diff --git a/packages/cli/src/ui/components/agent-view/AgentComposer.test.tsx b/packages/cli/src/ui/components/agent-view/AgentComposer.test.tsx
new file mode 100644
index 00000000000..5b746e0559c
--- /dev/null
+++ b/packages/cli/src/ui/components/agent-view/AgentComposer.test.tsx
@@ -0,0 +1,102 @@
+/**
+ * @license
+ * Copyright 2026 Qwen Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { render } from 'ink-testing-library';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { AgentStatus } from '@qwen-code/qwen-code-core';
+import {
+ useAgentViewActions,
+ useAgentViewState,
+} from '../../contexts/AgentViewContext.js';
+import { useConfig } from '../../contexts/ConfigContext.js';
+import { useAgentStreamingState } from '../../hooks/useAgentStreamingState.js';
+import { useKeypress } from '../../hooks/useKeypress.js';
+import { usePreferredEditor } from '../../hooks/usePreferredEditor.js';
+import { useTerminalSize } from '../../hooks/useTerminalSize.js';
+import { StreamingState } from '../../types.js';
+import { useTextBuffer } from '../shared/text-buffer.js';
+import { AgentComposer } from './AgentComposer.js';
+
+vi.mock('../../contexts/AgentViewContext.js');
+vi.mock('../../contexts/ConfigContext.js');
+vi.mock('../../hooks/useAgentStreamingState.js');
+vi.mock('../../hooks/useKeypress.js');
+vi.mock('../../hooks/usePreferredEditor.js');
+vi.mock('../../hooks/useTerminalSize.js');
+vi.mock('../shared/text-buffer.js');
+vi.mock('../BaseTextInput.js', () => ({ BaseTextInput: () => null }));
+vi.mock('../LoadingIndicator.js', () => ({ LoadingIndicator: () => null }));
+vi.mock('../QueuedMessageDisplay.js', () => ({
+ QueuedMessageDisplay: () => null,
+}));
+vi.mock('./AgentFooter.js', () => ({ AgentFooter: () => null }));
+
+describe('AgentComposer', () => {
+ const setAgentInputBufferText = vi.fn();
+ const setAgentTabBarFocused = vi.fn();
+ const setAgentApprovalMode = vi.fn();
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+
+ vi.mocked(useAgentViewState).mockReturnValue({
+ activeView: 'agent-1',
+ agents: new Map([
+ [
+ 'agent-1',
+ {
+ modelId: 'qwen',
+ color: 'cyan',
+ interactiveAgent: {
+ cancelCurrentRound: vi.fn(),
+ enqueueMessage: vi.fn(),
+ getError: vi.fn(),
+ getLastRoundError: vi.fn(),
+ },
+ },
+ ],
+ ]),
+ agentShellFocused: false,
+ agentInputBufferText: '',
+ agentTabBarFocused: false,
+ agentApprovalModes: new Map(),
+ } as never);
+ vi.mocked(useAgentViewActions).mockReturnValue({
+ setAgentInputBufferText,
+ setAgentTabBarFocused,
+ setAgentApprovalMode,
+ } as never);
+ vi.mocked(useConfig).mockReturnValue({
+ getContentGeneratorConfig: () => undefined,
+ } as never);
+ vi.mocked(usePreferredEditor).mockReturnValue(undefined);
+ vi.mocked(useTerminalSize).mockReturnValue({ columns: 80, rows: 24 });
+ vi.mocked(useKeypress).mockImplementation(() => {});
+ vi.mocked(useAgentStreamingState).mockReturnValue({
+ status: AgentStatus.IDLE,
+ streamingState: StreamingState.Idle,
+ isInputActive: true,
+ elapsedTime: 0,
+ lastPromptTokenCount: 0,
+ } as never);
+ vi.mocked(useTextBuffer).mockReturnValue({
+ text: 'draft',
+ allVisualLines: ['draft'],
+ visualCursor: [0, 5],
+ } as never);
+ });
+
+ it('does not reset the parent input-buffer state during unmount', () => {
+ const { unmount } = render();
+
+ expect(setAgentInputBufferText).toHaveBeenCalledWith('draft');
+ setAgentInputBufferText.mockClear();
+
+ unmount();
+
+ expect(setAgentInputBufferText).not.toHaveBeenCalled();
+ });
+});
diff --git a/packages/cli/src/ui/components/agent-view/AgentComposer.tsx b/packages/cli/src/ui/components/agent-view/AgentComposer.tsx
index a2f6ac0536c..ed0557a03c0 100644
--- a/packages/cli/src/ui/components/agent-view/AgentComposer.tsx
+++ b/packages/cli/src/ui/components/agent-view/AgentComposer.tsx
@@ -133,10 +133,9 @@ export const AgentComposer: React.FC = ({ agentId }) => {
preferredEditor,
});
- // Sync agent buffer text to context so AgentTabBar can guard tab switching
+ // Sync the active agent buffer text to context.
useEffect(() => {
setAgentInputBufferText(buffer.text);
- return () => setAgentInputBufferText('');
}, [buffer.text, setAgentInputBufferText]);
// When agent input is not active (agent running, completed, etc.),
diff --git a/packages/cli/src/ui/contexts/AgentViewContext.tsx b/packages/cli/src/ui/contexts/AgentViewContext.tsx
index f414db5d892..49437b283a7 100644
--- a/packages/cli/src/ui/contexts/AgentViewContext.tsx
+++ b/packages/cli/src/ui/contexts/AgentViewContext.tsx
@@ -48,7 +48,7 @@ export interface AgentViewState {
agents: ReadonlyMap;
/** Whether any agent tab's embedded shell currently has input focus. */
agentShellFocused: boolean;
- /** Current text in the active agent tab's input buffer (empty when on main). */
+ /** Last synced text from the active agent tab's input buffer. */
agentInputBufferText: string;
/** Whether the tab bar has keyboard focus (vs the agent input). */
agentTabBarFocused: boolean;