feat(cli): Add agent tab navigation and live tool output for in-process arena mode

Add AgentViewContext, AgentTabBar, and AgentChatView components for tab-based
agent switching. Add useArenaInProcess hook bridging ArenaManager events to
React state. Add agentHistoryAdapter converting AgentMessage[] to HistoryItem[].

Core support changes:
- Replace stream buffers with ROUND_TEXT events (complete round text)
- Add TOOL_OUTPUT_UPDATE events for live tool output streaming
- Add pendingApprovals/liveOutputs/shellPids state to AgentInteractive
- Fix missing ROUND_END emission for final text rounds

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
tanzhenxin 2026-02-23 13:21:16 +08:00
parent d4cfb18f79
commit 5d07c495f1
27 changed files with 2086 additions and 314 deletions

View file

@ -97,6 +97,8 @@ import {
} from './hooks/useExtensionUpdates.js';
import { useCodingPlanUpdates } from './hooks/useCodingPlanUpdates.js';
import { ShellFocusContext } from './contexts/ShellFocusContext.js';
import { useAgentViewState } from './contexts/AgentViewContext.js';
import { useArenaInProcess } from './hooks/useArenaInProcess.js';
import { t } from '../i18n/index.js';
import { useWelcomeBack } from './hooks/useWelcomeBack.js';
import { useDialogClose } from './hooks/useDialogClose.js';
@ -710,6 +712,8 @@ export const AppContainer = (props: AppContainerProps) => {
shouldBlockTab: () => hasSuggestionsVisible,
});
const agentViewState = useAgentViewState();
const { messageQueue, addMessage, clearQueue, getQueuedMessagesText } =
useMessageQueue({
isConfigInitialized,
@ -720,9 +724,17 @@ export const AppContainer = (props: AppContainerProps) => {
// Callback for handling final submit (must be after addMessage from useMessageQueue)
const handleFinalSubmit = useCallback(
(submittedValue: string) => {
// Route to active in-process agent if viewing a sub-agent tab.
if (agentViewState.activeView !== 'main') {
const agent = agentViewState.agents.get(agentViewState.activeView);
if (agent) {
agent.interactiveAgent.enqueueMessage(submittedValue.trim());
return;
}
}
addMessage(submittedValue);
},
[addMessage],
[addMessage, agentViewState],
);
const handleArenaModelsSelected = useCallback(
@ -807,10 +819,17 @@ export const AppContainer = (props: AppContainerProps) => {
}
}, [buffer, terminalWidth, terminalHeight]);
// Compute available terminal height based on controls measurement
// agentViewState is declared earlier (before handleFinalSubmit) so it
// is available for input routing. Referenced here for layout computation.
// Compute available terminal height based on controls measurement.
// When in-process agents are present the AgentTabBar renders an extra
// row at the top of the layout; subtract it so downstream consumers
// (shell, transcript, etc.) don't overestimate available space.
const tabBarHeight = agentViewState.agents.size > 0 ? 1 : 0;
const availableTerminalHeight = Math.max(
0,
terminalHeight - controlsHeight - staticExtraHeight - 2,
terminalHeight - controlsHeight - staticExtraHeight - 2 - tabBarHeight,
);
config.setShellExecutionConfig({
@ -826,6 +845,9 @@ export const AppContainer = (props: AppContainerProps) => {
const isFocused = useFocus();
useBracketedPaste();
// Bridge arena in-process events to AgentViewContext
useArenaInProcess(config);
// Context file names computation
const contextFileNames = useMemo(() => {
const fromSettings = settings.merged.context?.fileName;