fix(tui): enable tool access in fullscreen mode via NativeAgent

Fullscreen TUI was calling modelClient directly, bypassing the NativeAgent
tool loop entirely. Pass the agent through FullscreenTuiConfig → App and
use agent.process() for message handling, which enables the full tool
registry and executor.
This commit is contained in:
William Valentin
2026-02-10 13:21:22 -08:00
parent f892bbe6ca
commit e46e8740a1
3 changed files with 29 additions and 7 deletions
+2
View File
@@ -216,6 +216,7 @@ export function registerTuiCommand(program: Command): void {
modelRouter,
systemPrompt,
model: config.models.default.model,
agent,
onExit: cleanup,
});
} else {
@@ -259,6 +260,7 @@ export function registerTuiCommand(program: Command): void {
modelRouter,
systemPrompt,
model: config.models.default.model,
agent,
onExit: cleanup,
});
return;
+24 -7
View File
@@ -7,6 +7,7 @@ import { parseCommand, getHelpText, resolveModelAlias, getCommandCompletions } f
import type { Message, ModelClient, TokenUsage } from '../../../models/types.js';
import type { ModelRouter } from '../../../models/router.js';
import type { ManagedSession } from '../../../session/index.js';
import type { NativeAgent } from '../../../backends/native/agent.js';
export interface AppProps {
session: ManagedSession;
@@ -14,6 +15,7 @@ export interface AppProps {
modelRouter?: ModelRouter;
systemPrompt: string;
model: string;
agent?: NativeAgent;
onExit?: () => void;
}
@@ -23,6 +25,7 @@ export function App({
modelRouter,
systemPrompt,
model,
agent,
onExit,
}: AppProps): React.ReactElement {
const { exit } = useApp();
@@ -156,19 +159,33 @@ export function App({
if (command.type !== 'message' || isStreaming) return;
// Add user message
// Add user message to UI (and session if no agent — agent adds it internally)
const userMessage: Message = { role: 'user', content: command.content };
const messageWithTimestamp = session.addMessage(userMessage);
setMessages(prev => [...prev, messageWithTimestamp]);
if (!agent) {
const messageWithTimestamp = session.addMessage(userMessage);
setMessages(prev => [...prev, messageWithTimestamp]);
} else {
setMessages(prev => [...prev, { ...userMessage, timestamp: Date.now() }]);
}
setScrollOffset(0); // Auto-scroll to bottom
// Stream response
// Process response
setIsStreaming(true);
setStreamingContent('');
abortRef.current = false;
try {
if (modelClient.chatStream) {
if (agent) {
// agent.process() handles session history internally
const response = await agent.process(command.content);
const usage = agent.getUsage();
setTokenUsage({ inputTokens: usage.inputTokens, outputTokens: usage.outputTokens });
// Sync UI with session history (agent already added messages to session)
setMessages(session.getHistory());
} else if (modelClient.chatStream) {
// Fallback: direct streaming without tools
let fullContent = '';
for await (const event of modelClient.chatStream({
@@ -199,7 +216,7 @@ export function App({
const assistantWithTimestamp = session.addMessage(assistantMessage);
setMessages(prev => [...prev, assistantWithTimestamp]);
} else {
// Fallback to non-streaming
// Fallback: non-streaming without tools
const response = await modelClient.chat({
messages: session.getHistory(),
system: systemPrompt,
@@ -225,7 +242,7 @@ export function App({
setIsStreaming(false);
setStreamingContent('');
}
}, [isStreaming, session, modelClient, modelRouter, systemPrompt, exit, onExit, messages.length, tokenUsage]);
}, [isStreaming, session, agent, modelClient, modelRouter, systemPrompt, exit, onExit, messages.length, tokenUsage]);
return (
<Box flexDirection="column" height="100%">
+3
View File
@@ -4,6 +4,7 @@ import { App } from './components/index.js';
import type { ManagedSession } from '../../session/index.js';
import type { ModelClient } from '../../models/types.js';
import type { ModelRouter } from '../../models/router.js';
import type { NativeAgent } from '../../backends/native/agent.js';
export interface FullscreenTuiConfig {
session: ManagedSession;
@@ -11,6 +12,7 @@ export interface FullscreenTuiConfig {
modelRouter?: ModelRouter;
systemPrompt: string;
model: string;
agent?: NativeAgent;
onExit?: () => void;
}
@@ -27,6 +29,7 @@ export async function startFullscreenTui(config: FullscreenTuiConfig): Promise<v
modelRouter: config.modelRouter,
systemPrompt: config.systemPrompt,
model: config.model,
agent: config.agent,
onExit: config.onExit,
})
);