mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 20:20:57 +00:00
feat: subagent runtime & CLI display - wip
This commit is contained in:
parent
1f8ea7ab7a
commit
4985bfc000
31 changed files with 2664 additions and 390 deletions
|
|
@ -39,6 +39,19 @@ vi.mock('../../utils/MarkdownDisplay.js', () => ({
|
|||
return <Text>MockMarkdown:{text}</Text>;
|
||||
},
|
||||
}));
|
||||
vi.mock('../subagents/index.js', () => ({
|
||||
SubagentExecutionDisplay: function MockSubagentExecutionDisplay({
|
||||
data,
|
||||
}: {
|
||||
data: { subagentName: string; taskDescription: string };
|
||||
}) {
|
||||
return (
|
||||
<Text>
|
||||
🤖 {data.subagentName} • Task: {data.taskDescription}
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
// Helper to render with context
|
||||
const renderWithContext = (
|
||||
|
|
@ -180,4 +193,33 @@ describe('<ToolMessage />', () => {
|
|||
// We can at least ensure it doesn't have the high emphasis indicator.
|
||||
expect(lowEmphasisFrame()).not.toContain('←');
|
||||
});
|
||||
|
||||
it('shows subagent execution display for task tool with proper result display', () => {
|
||||
const subagentResultDisplay = {
|
||||
type: 'subagent_execution' as const,
|
||||
subagentName: 'file-search',
|
||||
taskDescription: 'Search for files matching pattern',
|
||||
status: 'running' as const,
|
||||
};
|
||||
|
||||
const props: ToolMessageProps = {
|
||||
name: 'task',
|
||||
description: 'Delegate task to subagent',
|
||||
resultDisplay: subagentResultDisplay,
|
||||
status: ToolCallStatus.Executing,
|
||||
terminalWidth: 80,
|
||||
callId: 'test-call-id-2',
|
||||
confirmationDetails: undefined,
|
||||
};
|
||||
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage {...props} />,
|
||||
StreamingState.Responding,
|
||||
);
|
||||
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('🤖'); // Subagent execution display should show
|
||||
expect(output).toContain('file-search'); // Actual subagent name
|
||||
expect(output).toContain('Search for files matching pattern'); // Actual task description
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@ import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
|
|||
import { GeminiRespondingSpinner } from '../GeminiRespondingSpinner.js';
|
||||
import { MaxSizedBox } from '../shared/MaxSizedBox.js';
|
||||
import { TodoDisplay } from '../TodoDisplay.js';
|
||||
import { TodoResultDisplay } from '@qwen-code/qwen-code-core';
|
||||
import {
|
||||
TodoResultDisplay,
|
||||
TaskResultDisplay,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
import { SubagentExecutionDisplay } from '../subagents/index.js';
|
||||
|
||||
const STATIC_HEIGHT = 1;
|
||||
const RESERVED_LINE_COUNT = 5; // for tool name, status, padding etc.
|
||||
|
|
@ -29,7 +33,8 @@ type DisplayRendererResult =
|
|||
| { type: 'none' }
|
||||
| { type: 'todo'; data: TodoResultDisplay }
|
||||
| { type: 'string'; data: string }
|
||||
| { type: 'diff'; data: { fileDiff: string; fileName: string } };
|
||||
| { type: 'diff'; data: { fileDiff: string; fileName: string } }
|
||||
| { type: 'subagent_execution'; data: TaskResultDisplay };
|
||||
|
||||
/**
|
||||
* Custom hook to determine the type of result display and return appropriate rendering info
|
||||
|
|
@ -55,6 +60,19 @@ const useResultDisplayRenderer = (
|
|||
};
|
||||
}
|
||||
|
||||
// Check for SubagentExecutionResultDisplay (for non-task tools)
|
||||
if (
|
||||
typeof resultDisplay === 'object' &&
|
||||
resultDisplay !== null &&
|
||||
'type' in resultDisplay &&
|
||||
resultDisplay.type === 'subagent_execution'
|
||||
) {
|
||||
return {
|
||||
type: 'subagent_execution',
|
||||
data: resultDisplay as TaskResultDisplay,
|
||||
};
|
||||
}
|
||||
|
||||
// Check for FileDiff
|
||||
if (
|
||||
typeof resultDisplay === 'object' &&
|
||||
|
|
@ -81,6 +99,15 @@ const TodoResultRenderer: React.FC<{ data: TodoResultDisplay }> = ({
|
|||
data,
|
||||
}) => <TodoDisplay todos={data.todos} />;
|
||||
|
||||
/**
|
||||
* Component to render subagent execution results
|
||||
*/
|
||||
const SubagentExecutionRenderer: React.FC<{
|
||||
data: TaskResultDisplay;
|
||||
availableHeight?: number;
|
||||
childWidth: number;
|
||||
}> = ({ data }) => <SubagentExecutionDisplay data={data} />;
|
||||
|
||||
/**
|
||||
* Component to render string results (markdown or plain text)
|
||||
*/
|
||||
|
|
@ -189,6 +216,13 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
|
|||
{displayRenderer.type === 'todo' && (
|
||||
<TodoResultRenderer data={displayRenderer.data} />
|
||||
)}
|
||||
{displayRenderer.type === 'subagent_execution' && (
|
||||
<SubagentExecutionRenderer
|
||||
data={displayRenderer.data}
|
||||
availableHeight={availableHeight}
|
||||
childWidth={childWidth}
|
||||
/>
|
||||
)}
|
||||
{displayRenderer.type === 'string' && (
|
||||
<StringResultRenderer
|
||||
data={displayRenderer.data}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue