mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
feat: subagent feature wip
This commit is contained in:
@@ -122,9 +122,9 @@ Slash commands provide meta-level control over the CLI itself.
|
|||||||
- **`create`**:
|
- **`create`**:
|
||||||
- **Description:** Launch an interactive wizard to create a new subagent. The wizard guides you through location selection, AI-powered prompt generation, tool selection, and visual customization.
|
- **Description:** Launch an interactive wizard to create a new subagent. The wizard guides you through location selection, AI-powered prompt generation, tool selection, and visual customization.
|
||||||
- **Usage:** `/agents create`
|
- **Usage:** `/agents create`
|
||||||
- **`list`**:
|
- **`manage`**:
|
||||||
- **Description:** Open an interactive management dialog to view, edit, and delete existing subagents. Shows both project-level and user-level agents.
|
- **Description:** Open an interactive management dialog to view, edit, and delete existing subagents. Shows both project-level and user-level agents.
|
||||||
- **Usage:** `/agents list`
|
- **Usage:** `/agents manage`
|
||||||
- **Storage Locations:**
|
- **Storage Locations:**
|
||||||
- **Project-level:** `.qwen/agents/` (shared with team, takes precedence)
|
- **Project-level:** `.qwen/agents/` (shared with team, takes precedence)
|
||||||
- **User-level:** `~/.qwen/agents/` (personal agents, available across projects)
|
- **User-level:** `~/.qwen/agents/` (personal agents, available across projects)
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ Subagents are independent AI assistants that:
|
|||||||
|
|
||||||
Follow the guided wizard to create a specialized agent.
|
Follow the guided wizard to create a specialized agent.
|
||||||
|
|
||||||
2. **List existing agents**:
|
2. **Manage existing agents**:
|
||||||
|
|
||||||
```
|
```
|
||||||
/agents list
|
/agents manage
|
||||||
```
|
```
|
||||||
|
|
||||||
View and manage your configured subagents.
|
View and manage your configured subagents.
|
||||||
@@ -77,14 +77,14 @@ Creates a new subagent through a guided step wizard.
|
|||||||
/agents create
|
/agents create
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `/agents list`
|
#### `/agents manage`
|
||||||
|
|
||||||
Opens an interactive management dialog for viewing and managing existing subagents.
|
Opens an interactive management dialog for viewing and managing existing subagents.
|
||||||
|
|
||||||
**Usage:**
|
**Usage:**
|
||||||
|
|
||||||
```
|
```
|
||||||
/agents list
|
/agents manage
|
||||||
```
|
```
|
||||||
|
|
||||||
### Storage Locations
|
### Storage Locations
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const agentsCommand: SlashCommand = {
|
|||||||
kind: CommandKind.BUILT_IN,
|
kind: CommandKind.BUILT_IN,
|
||||||
subCommands: [
|
subCommands: [
|
||||||
{
|
{
|
||||||
name: 'list',
|
name: 'manage',
|
||||||
description: 'Manage existing subagents (view, edit, delete).',
|
description: 'Manage existing subagents (view, edit, delete).',
|
||||||
kind: CommandKind.BUILT_IN,
|
kind: CommandKind.BUILT_IN,
|
||||||
action: (): OpenDialogActionReturn => ({
|
action: (): OpenDialogActionReturn => ({
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ export function CreationSummary({
|
|||||||
state.location,
|
state.location,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const toolsDisplay = Array.isArray(state.selectedTools)
|
// If no tools explicitly selected, it means "all tools" for this agent
|
||||||
? state.selectedTools.join(', ')
|
const toolsDisplay =
|
||||||
: '*';
|
state.selectedTools.length === 0 ? '*' : state.selectedTools.join(', ');
|
||||||
|
|
||||||
// Common method to save subagent configuration
|
// Common method to save subagent configuration
|
||||||
const saveSubagent = useCallback(async (): Promise<SubagentManager> => {
|
const saveSubagent = useCallback(async (): Promise<SubagentManager> => {
|
||||||
@@ -225,12 +225,14 @@ export function CreationSummary({
|
|||||||
<Box flexDirection="column" gap={1}>
|
<Box flexDirection="column" gap={1}>
|
||||||
<Box flexDirection="column">
|
<Box flexDirection="column">
|
||||||
<Box>
|
<Box>
|
||||||
<Text bold>Name: </Text>
|
<Text color={theme.text.primary}>Name: </Text>
|
||||||
<Text>{state.generatedName}</Text>
|
<Text color={getColorForDisplay(state.color)}>
|
||||||
|
{state.generatedName}
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text bold>Location: </Text>
|
<Text color={theme.text.primary}>Location: </Text>
|
||||||
<Text>
|
<Text>
|
||||||
{state.location === 'project'
|
{state.location === 'project'
|
||||||
? 'Project Level (.qwen/agents/)'
|
? 'Project Level (.qwen/agents/)'
|
||||||
@@ -239,21 +241,19 @@ export function CreationSummary({
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text bold>Tools: </Text>
|
<Text color={theme.text.primary}>Tools: </Text>
|
||||||
<Text>{toolsDisplay}</Text>
|
<Text>{toolsDisplay}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{shouldShowColor(state.color) && (
|
{shouldShowColor(state.color) && (
|
||||||
<Box>
|
<Box>
|
||||||
<Text bold>Color: </Text>
|
<Text color={theme.text.primary}>Color: </Text>
|
||||||
<Text
|
<Text color={getColorForDisplay(state.color)}>{state.color}</Text>
|
||||||
color={getColorForDisplay(state.color)}
|
|
||||||
>{` ${state.generatedName} `}</Text>
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box marginTop={1}>
|
<Box marginTop={1}>
|
||||||
<Text bold>Description:</Text>
|
<Text color={theme.text.primary}>Description:</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box padding={1} paddingBottom={0}>
|
<Box padding={1} paddingBottom={0}>
|
||||||
<Text wrap="wrap">
|
<Text wrap="wrap">
|
||||||
@@ -262,7 +262,7 @@ export function CreationSummary({
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box marginTop={1}>
|
<Box marginTop={1}>
|
||||||
<Text bold>System Prompt:</Text>
|
<Text color={theme.text.primary}>System Prompt:</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box padding={1} paddingBottom={0}>
|
<Box padding={1} paddingBottom={0}>
|
||||||
<Text wrap="wrap">
|
<Text wrap="wrap">
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { useState, useCallback, useRef } from 'react';
|
import { useState, useCallback, useRef } from 'react';
|
||||||
import { Box, Text } from 'ink';
|
import { Box, Text } from 'ink';
|
||||||
|
import Spinner from 'ink-spinner';
|
||||||
import { WizardStepProps, WizardAction } from '../types.js';
|
import { WizardStepProps, WizardAction } from '../types.js';
|
||||||
import { sanitizeInput } from '../utils.js';
|
import { sanitizeInput } from '../utils.js';
|
||||||
import { Config, subagentGenerator } from '@qwen-code/qwen-code-core';
|
import { Config, subagentGenerator } from '@qwen-code/qwen-code-core';
|
||||||
@@ -239,8 +240,11 @@ export function DescriptionInput({
|
|||||||
|
|
||||||
{state.isGenerating ? (
|
{state.isGenerating ? (
|
||||||
<Box>
|
<Box>
|
||||||
|
<Box marginRight={1}>
|
||||||
|
<Spinner />
|
||||||
|
</Box>
|
||||||
<Text color={theme.text.accent}>
|
<Text color={theme.text.accent}>
|
||||||
⏳ Generating subagent configuration...
|
Generating subagent configuration...
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -30,33 +30,31 @@ export const AgentViewerStep = ({ selectedAgent }: AgentViewerStepProps) => {
|
|||||||
<Box flexDirection="column" gap={1}>
|
<Box flexDirection="column" gap={1}>
|
||||||
<Box flexDirection="column">
|
<Box flexDirection="column">
|
||||||
<Box>
|
<Box>
|
||||||
<Text bold>File Path: </Text>
|
<Text color={theme.text.primary}>File Path: </Text>
|
||||||
<Text>{agent.filePath}</Text>
|
<Text>{agent.filePath}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text bold>Tools: </Text>
|
<Text color={theme.text.primary}>Tools: </Text>
|
||||||
<Text>{toolsDisplay}</Text>
|
<Text>{toolsDisplay}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{shouldShowColor(agent.color) && (
|
{shouldShowColor(agent.color) && (
|
||||||
<Box>
|
<Box>
|
||||||
<Text bold>Color: </Text>
|
<Text color={theme.text.primary}>Color: </Text>
|
||||||
<Text
|
<Text color={getColorForDisplay(agent.color)}>{agent.color}</Text>
|
||||||
color={getColorForDisplay(agent.color)}
|
|
||||||
>{` ${agent.name} `}</Text>
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box marginTop={1}>
|
<Box marginTop={1}>
|
||||||
<Text bold>Description:</Text>
|
<Text color={theme.text.primary}>Description:</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box padding={1} paddingBottom={0}>
|
<Box padding={1} paddingBottom={0}>
|
||||||
<Text wrap="wrap">{agent.description}</Text>
|
<Text wrap="wrap">{agent.description}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box marginTop={1}>
|
<Box marginTop={1}>
|
||||||
<Text bold>System Prompt:</Text>
|
<Text color={theme.text.primary}>System Prompt:</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box padding={1} paddingBottom={0}>
|
<Box padding={1} paddingBottom={0}>
|
||||||
<Text wrap="wrap">{agent.systemPrompt}</Text>
|
<Text wrap="wrap">{agent.systemPrompt}</Text>
|
||||||
@@ -16,6 +16,7 @@ import { ColorSelector } from '../create/ColorSelector.js';
|
|||||||
import { MANAGEMENT_STEPS } from '../types.js';
|
import { MANAGEMENT_STEPS } from '../types.js';
|
||||||
import { Colors } from '../../../colors.js';
|
import { Colors } from '../../../colors.js';
|
||||||
import { theme } from '../../../semantic-colors.js';
|
import { theme } from '../../../semantic-colors.js';
|
||||||
|
import { getColorForDisplay, shouldShowColor } from '../utils.js';
|
||||||
import { Config, SubagentConfig } from '@qwen-code/qwen-code-core';
|
import { Config, SubagentConfig } from '@qwen-code/qwen-code-core';
|
||||||
|
|
||||||
interface AgentsManagerDialogProps {
|
interface AgentsManagerDialogProps {
|
||||||
@@ -166,9 +167,19 @@ export function AgentsManagerDialog({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Use agent color for the Agent Viewer header
|
||||||
|
const headerColor =
|
||||||
|
currentStep === MANAGEMENT_STEPS.AGENT_VIEWER &&
|
||||||
|
selectedAgent &&
|
||||||
|
shouldShowColor(selectedAgent.color)
|
||||||
|
? getColorForDisplay(selectedAgent.color)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Text bold>{getStepHeaderText()}</Text>
|
<Text bold color={headerColor}>
|
||||||
|
{getStepHeaderText()}
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}, [getCurrentStep, selectedAgent]);
|
}, [getCurrentStep, selectedAgent]);
|
||||||
@@ -171,7 +171,10 @@ const TaskPromptSection: React.FC<{
|
|||||||
<Box flexDirection="row">
|
<Box flexDirection="row">
|
||||||
<Text color={theme.text.primary}>Task Detail: </Text>
|
<Text color={theme.text.primary}>Task Detail: </Text>
|
||||||
{shouldTruncate && displayMode === 'default' && (
|
{shouldTruncate && displayMode === 'default' && (
|
||||||
<Text color={Colors.Gray}> Showing the first 10 lines.</Text>
|
<Text color={Colors.Gray}>
|
||||||
|
{' '}
|
||||||
|
Showing the first {MAX_TASK_PROMPT_LINES} lines.
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box paddingLeft={1}>
|
<Box paddingLeft={1}>
|
||||||
|
|||||||
@@ -16,8 +16,7 @@
|
|||||||
* - Runtime conversion functions integrated into the manager
|
* - Runtime conversion functions integrated into the manager
|
||||||
* - Manager class for CRUD operations on subagent files
|
* - Manager class for CRUD operations on subagent files
|
||||||
*
|
*
|
||||||
* The implementation follows the Markdown + YAML frontmatter format specified
|
* The implementation follows the Markdown + YAML frontmatter format , with storage at both project and user levels.
|
||||||
* in the Claude Code product manual, with storage at both project and user levels.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Core types and interfaces
|
// Core types and interfaces
|
||||||
|
|||||||
Reference in New Issue
Block a user