Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/types/src/experiment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import type { Keys, Equals, AssertEqual } from "./type-fu.js"
* ExperimentId
*/

export const experimentIds = ["preventFocusDisruption", "imageGeneration", "runSlashCommand", "customTools"] as const
export const experimentIds = [
"preventFocusDisruption",
"imageGeneration",
"runSlashCommand",
"customTools",
"subagent",
] as const

export const experimentIdsSchema = z.enum(experimentIds)

Expand All @@ -21,6 +27,7 @@ export const experimentsSchema = z.object({
imageGeneration: z.boolean().optional(),
runSlashCommand: z.boolean().optional(),
customTools: z.boolean().optional(),
subagent: z.boolean().optional(),
})

export type Experiments = z.infer<typeof experimentsSchema>
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export type ClineSay = z.infer<typeof clineSaySchema>
export const toolProgressStatusSchema = z.object({
icon: z.string().optional(),
text: z.string().optional(),
spin: z.boolean().optional(),
})

export type ToolProgressStatus = z.infer<typeof toolProgressStatusSchema>
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const toolNames = [
"skill",
"generate_image",
"custom_tool",
"subagent",
] as const

export const toolNamesSchema = z.enum(toolNames)
Expand Down
9 changes: 9 additions & 0 deletions packages/types/src/vscode-extension-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,8 @@ export interface ClineSayTool {
| "runSlashCommand"
| "updateTodoList"
| "skill"
| "subagentRunning"
| "subagentCompleted"
path?: string
// For readCommandOutput
readStart?: number
Expand Down Expand Up @@ -839,6 +841,13 @@ export interface ClineSayTool {
description?: string
// Properties for skill tool
skill?: string
// Properties for subagent tool (subagentRunning / subagentCompleted)
currentTask?: string
result?: string
error?: string
/** When set (e.g. CANCELLED), webview shows t(messageKey) instead of result/error. */
resultCode?: string
messageKey?: string
}

export interface ClineAskUseMcpServer {
Expand Down
29 changes: 29 additions & 0 deletions src/core/assistant-message/NativeToolCallParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,20 @@ export class NativeToolCallParser {
}
break

case "subagent":
if (
partialArgs.description !== undefined ||
partialArgs.prompt !== undefined ||
partialArgs.subagent_type !== undefined
) {
nativeArgs = {
description: partialArgs.description,
prompt: partialArgs.prompt,
subagent_type: partialArgs.subagent_type,
}
}
break

default:
break
}
Expand Down Expand Up @@ -911,6 +925,21 @@ export class NativeToolCallParser {
}
break

case "subagent":
if (
args.description !== undefined &&
args.prompt !== undefined &&
args.subagent_type !== undefined &&
(args.subagent_type === "general" || args.subagent_type === "explore")
) {
nativeArgs = {
description: args.description,
prompt: args.prompt,
subagent_type: args.subagent_type,
} as NativeArgsFor<TName>
}
break

case "use_mcp_tool":
if (args.server_name !== undefined && args.tool_name !== undefined) {
nativeArgs = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,56 @@ describe("NativeToolCallParser", () => {
})
})
})

describe("subagent tool", () => {
it("should parse description, prompt, and subagent_type into nativeArgs", () => {
const toolCall = {
id: "toolu_subagent_1",
name: "subagent" as const,
arguments: JSON.stringify({
description: "Explore codebase",
prompt: "List all exports from src/index.ts",
subagent_type: "explore",
}),
}

const result = NativeToolCallParser.parseToolCall(toolCall)

expect(result).not.toBeNull()
expect(result?.type).toBe("tool_use")
if (result?.type === "tool_use") {
expect(result.nativeArgs).toBeDefined()
const nativeArgs = result.nativeArgs as {
description: string
prompt: string
subagent_type: "general" | "explore"
}
expect(nativeArgs.description).toBe("Explore codebase")
expect(nativeArgs.prompt).toBe("List all exports from src/index.ts")
expect(nativeArgs.subagent_type).toBe("explore")
}
})

it("should parse general subagent_type", () => {
const toolCall = {
id: "toolu_subagent_2",
name: "subagent" as const,
arguments: JSON.stringify({
description: "Fix bug",
prompt: "Fix the null check in utils.ts",
subagent_type: "general",
}),
}

const result = NativeToolCallParser.parseToolCall(toolCall)

expect(result).not.toBeNull()
if (result?.type === "tool_use" && result.nativeArgs) {
const nativeArgs = result.nativeArgs as { subagent_type: string }
expect(nativeArgs.subagent_type).toBe("general")
}
})
})
})

describe("processStreamingChunk", () => {
Expand Down
Loading
Loading