diff --git a/.claude/skills/system-prompts/SKILL.md b/.claude/skills/system-prompts/SKILL.md index d9c7ad67f..4377be59d 100644 --- a/.claude/skills/system-prompts/SKILL.md +++ b/.claude/skills/system-prompts/SKILL.md @@ -183,7 +183,7 @@ READ-ONLY if applicable — list prohibited actions explicitly. What to return. Schema requirements. -Call `complete` with findings when done. +Call `submit_result` with findings when done. @@ -541,11 +541,11 @@ READ-ONLY. You are STRICTLY PROHIBITED from: 2. Read key sections (not entire files) 3. Identify types, interfaces, key functions 4. Note dependencies between files -5. Call `complete` with findings +5. Call `submit_result` with findings -Read-only. Call `complete` when done. This matters. +Read-only. Call `submit_result` when done. This matters. ``` diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index c4039fb63..b775c8f83 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -5,6 +5,9 @@ ### Added - Added `/fork` command to create a new session with the exact same state (entries and artifacts) as the current session +### Changed +- Renamed the `complete` tool to `submit_result` for subagent result submission + ## [8.6.0] - 2026-01-27 ### Added diff --git a/packages/coding-agent/DEVELOPMENT.md b/packages/coding-agent/DEVELOPMENT.md index 1456963c2..9481166e9 100644 --- a/packages/coding-agent/DEVELOPMENT.md +++ b/packages/coding-agent/DEVELOPMENT.md @@ -268,7 +268,7 @@ src/ │ ├── bash.ts # Bash command execution │ ├── bash-interceptor.ts # Bash command interception │ ├── calculator.ts # Calculator tool -│ ├── complete.ts # Completion tool +│ ├── submit-result.ts # Submit result tool │ ├── context.ts # Tool context utilities │ ├── fetch.ts # URL content fetching │ ├── find.ts # File search by glob diff --git a/packages/coding-agent/src/commit/agentic/prompts/analyze-file.md b/packages/coding-agent/src/commit/agentic/prompts/analyze-file.md index ddbcf00bc..dfa37d4dc 100644 --- a/packages/coding-agent/src/commit/agentic/prompts/analyze-file.md +++ b/packages/coding-agent/src/commit/agentic/prompts/analyze-file.md @@ -19,4 +19,4 @@ Return a concise JSON object with: Consider how this file's changes relate to the above files. {{/if}} -Call the complete tool with the JSON payload. \ No newline at end of file +Call the submit_result tool with the JSON payload. \ No newline at end of file diff --git a/packages/coding-agent/src/prompts/agents/explore.md b/packages/coding-agent/src/prompts/agents/explore.md index ef9ebff63..4d85032d4 100644 --- a/packages/coding-agent/src/prompts/agents/explore.md +++ b/packages/coding-agent/src/prompts/agents/explore.md @@ -117,5 +117,5 @@ Infer from task, default medium: -Read-only; no file modifications. Call `complete` with your findings when done. +Read-only; no file modifications. Call `submit_result` with your findings when done. \ No newline at end of file diff --git a/packages/coding-agent/src/prompts/agents/reviewer.md b/packages/coding-agent/src/prompts/agents/reviewer.md index 32a24a3e9..5d544f3c3 100644 --- a/packages/coding-agent/src/prompts/agents/reviewer.md +++ b/packages/coding-agent/src/prompts/agents/reviewer.md @@ -61,7 +61,7 @@ output: 2. Read modified files for full context 3. For large changes, spawn parallel `task` agents (one per module/concern) 4. Call `report_finding` for each issue -5. Call `complete` with your verdict — **review is incomplete until `complete` is called** +5. Call `submit_result` with your verdict — **review is incomplete until `submit_result` is called** Bash is read-only here: `git diff`, `git log`, `git show`, `gh pr diff`. No file modifications or builds. @@ -109,17 +109,17 @@ Each `report_finding` requires: - `file_path`: Absolute path - `line_start`, `line_end`: Range ≤10 lines, must overlap the diff -Final `complete` call (payload goes under `data`): +Final `submit_result` call (payload goes under `data`): - `data.overall_correctness`: "correct" (no bugs/blockers) or "incorrect" - `data.explanation`: Plain text, 1-3 sentences summarizing your verdict. Do NOT include JSON, do NOT repeat findings here (they're already captured via `report_finding`). - `data.confidence`: 0.0-1.0 - `data.findings`: Optional; MUST omit (it is populated from `report_finding` calls) -Do not output JSON or code blocks. You must call the `complete` tool. +Do not output JSON or code blocks. You must call the `submit_result` tool. Correctness judgment ignores non-blocking issues (style, docs, nits). -Every finding must be anchored to the patch and evidence-backed. Before submitting, verify each finding is not speculative. Then call `complete`. +Every finding must be anchored to the patch and evidence-backed. Before submitting, verify each finding is not speculative. Then call `submit_result`. \ No newline at end of file diff --git a/packages/coding-agent/src/prompts/review-request.md b/packages/coding-agent/src/prompts/review-request.md index 2707e6e88..86b16149b 100644 --- a/packages/coding-agent/src/prompts/review-request.md +++ b/packages/coding-agent/src/prompts/review-request.md @@ -41,7 +41,7 @@ Each reviewer agent should: 2. {{#if skipDiff}}Run `git diff` or `git show` to get the diff for assigned files{{else}}Use the diff hunks provided below (don't re-run git diff){{/if}} 3. Read full file context as needed via the `read` tool 4. Call `report_finding` for each issue found -5. Call `complete` with verdict when done +5. Call `submit_result` with verdict when done {{#if skipDiff}} ### Diff Previews diff --git a/packages/coding-agent/src/prompts/tools/task.md b/packages/coding-agent/src/prompts/tools/task.md index b1001ed6b..79a1c275c 100644 --- a/packages/coding-agent/src/prompts/tools/task.md +++ b/packages/coding-agent/src/prompts/tools/task.md @@ -2,6 +2,21 @@ Launch a new agent to handle complex, multi-step tasks autonomously. Each agent type has specific capabilities and tools available to it. + +This matters. Get it right. + +Subagents have NO access to conversation history. They only see: +1. Their agent-specific system prompt +2. The `context` string you provide +3. The `task` string you provide + +Use a single Task call with multiple `tasks` entries when parallelizing. Multiple concurrent Task calls bypass coordination. + +For code changes, have subagents write files directly with Edit/Write. Do not ask them to return patches for you to apply. + +Agents with `output="structured"` enforce their own schema; the `output` parameter is ignored for those agents. + + {{#list agents join="\n"}} @@ -9,20 +24,17 @@ Launch a new agent to handle complex, multi-step tasks autonomously. Each agent {{default (join tools ", ") "All tools"}} {{/list}} - -Agents with `output="structured"` have a fixed schema enforced via frontmatter; your `output` parameter will be ignored for these agents. -- Always include a short description of the task in the task parameter -- **Plan-then-execute**: Put shared constraints in `context`, keep each task focused, specify acceptance criteria; **always provide an `output` schema unless the task explicitly does not require structured output** -- **Minimize tool chatter**: Avoid repeating large context; use `read agent://` for full logs -- **Parallelize**: Launch multiple agents whenever possible. You MUST use a single Task call with multiple entries in the `tasks` array to do this. -- **Isolate file scopes**: Assign each task distinct files or directories so agents don't conflict -- **Results are intermediate data**: Agent findings provide context for YOU to perform actual work. Do not treat agent reports as "task complete" signals. -- **Trust outputs**: Agent results should generally be trusted -- **Clarify intent**: Tell the agent whether you expect code changes or just research (search, file reads, web fetches) -- **Proactive use**: If an agent description says to use it proactively, do so without waiting for explicit user request +This matters. Be thorough. + +1. Plan before acting. Define the goal, acceptance criteria, and scope per task. +2. Put shared constraints and decisions in `context`; keep each task request short and unambiguous. +3. State whether each task is research-only or should modify files. +4. Provide an `output` schema whenever possible. Do not repeat the schema in `context`; the agent does not need it there. +5. Assign distinct file scopes per task to avoid conflicts. +6. Trust the returned data, then verify with tools when correctness matters. @@ -34,7 +46,7 @@ Agents with `output="structured"` have a fixed schema enforced via frontmatter; - `description`: Short human-readable description of what the task does - `args`: Object with keys matching `\{{placeholders}}` in context (always include this, even if empty) - `skills`: (optional) Array of skill names to preload into this task's system prompt. When set, the skills index section is omitted and the full SKILL.md contents are embedded. -- `output`: (optional) JTD schema for structured subagent output (used by the complete tool) +- `output`: (optional) JTD schema for structured subagent output (used by the submit_result tool). Do not duplicate this schema in `context`. @@ -46,17 +58,6 @@ Returns task results for each spawned agent: Results are keyed by task `id` (e.g., "AuthProvider", "AuthApi"). - -**Subagents have NO access to conversation history.** They only see: -1. Their agent-specific system prompt -2. The `context` string you provide -3. The `task` string you provide - -If you discussed requirements, plans, schemas, or decisions with the user, you MUST include that information in `context`. Subagents cannot see prior messages—they start fresh with only what you explicitly pass them. -**Never call Task multiple times in parallel.** Use a single Task call with multiple entries in the `tasks` array. Parallel Task calls waste resources and bypass coordination. -**For code changes, subagents write files directly.** Never ask an agent to "return the changes" for you to apply—they have Edit and Write tools. Their context window holds the work; asking them to report back wastes it. - - user: "Looks good, execute the plan" assistant: I'll execute the refactoring plan. @@ -80,10 +81,10 @@ assistant: Uses the Task tool: -- Confirmation bias: avoid yes/no exploration prompts; ask for factual discovery instead +- Confirmation bias: ask for factual discovery instead of yes/no exploration prompts - Reading a specific file path → Use Read tool instead - Finding files by pattern/name → Use Find tool instead - Searching for a specific class/function definition → Use Grep tool instead - Searching code within 2-3 specific files → Use Read tool instead - Tasks unrelated to the agent descriptions above - \ No newline at end of file + diff --git a/packages/coding-agent/src/sdk.ts b/packages/coding-agent/src/sdk.ts index e7cbbc94c..097a6ad0f 100644 --- a/packages/coding-agent/src/sdk.ts +++ b/packages/coding-agent/src/sdk.ts @@ -178,8 +178,8 @@ export interface CreateAgentSessionOptions { /** Output schema for structured completion (subagents) */ outputSchema?: unknown; - /** Whether to include the complete tool by default */ - requireCompleteTool?: boolean; + /** Whether to include the submit_result tool by default */ + requireSubmitResultTool?: boolean; /** Session manager. Default: SessionManager.create(cwd) */ sessionManager?: SessionManager; @@ -746,7 +746,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} skills, eventBus, outputSchema: options.outputSchema, - requireCompleteTool: options.requireCompleteTool, + requireSubmitResultTool: options.requireSubmitResultTool, getSessionFile: () => sessionManager.getSessionFile() ?? null, getSessionId: () => sessionManager.getSessionId?.() ?? null, getSessionSpawns: () => options.spawns ?? "*", diff --git a/packages/coding-agent/src/task/executor.ts b/packages/coding-agent/src/task/executor.ts index 73abad597..a3074e7a9 100644 --- a/packages/coding-agent/src/task/executor.ts +++ b/packages/coding-agent/src/task/executor.ts @@ -155,7 +155,7 @@ function resolveModelOverride( return {}; } -function buildCompleteToolChoice(model?: Model): ToolChoice | undefined { +function buildSubmitResultToolChoice(model?: Model): ToolChoice | undefined { if (!model) return undefined; if ( model.api === "openai-codex-responses" || @@ -163,10 +163,10 @@ function buildCompleteToolChoice(model?: Model): ToolChoice | undefined { model.api === "openai-completions" || model.api === "azure-openai-responses" ) { - return { type: "function", name: "complete" }; + return { type: "function", name: "submit_result" }; } if (model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") { - return { type: "tool", name: "complete" }; + return { type: "tool", name: "submit_result" }; } return undefined; } @@ -545,7 +545,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise void) | null = null; - let completeCalled = false; + let submitResultCalled = false; // Accumulate usage incrementally from message_end events (no memory for streaming events) const accumulatedUsage = { @@ -921,7 +921,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise { - if (event.type === "tool_execution_end" && event.toolName === "complete") { - completeCalled = true; + if (event.type === "tool_execution_end" && event.toolName === "submit_result") { + submitResultCalled = true; } if (isAgentEvent(event)) { try { @@ -1046,28 +1046,28 @@ export async function runSubprocess(options: ExecutorOptions): Promise -CRITICAL: You stopped without calling the complete tool. This is reminder ${retryCount} of ${MAX_COMPLETE_RETRIES}. +CRITICAL: You stopped without calling the submit_result tool. This is reminder ${retryCount} of ${MAX_SUBMIT_RESULT_RETRIES}. -You MUST call the complete tool to finish your task. Options: -1. Call complete with your result data if you have completed the task -2. Call complete with status="aborted" and an error message if you cannot complete the task +You MUST call the submit_result tool to finish your task. Options: +1. Call submit_result with your result data if you have completed the task +2. Call submit_result with status="aborted" and an error message if you cannot complete the task -Failure to call complete after ${MAX_COMPLETE_RETRIES} reminders will result in task failure. +Failure to call submit_result after ${MAX_SUBMIT_RESULT_RETRIES} reminders will result in task failure. -Call complete now.`; +Call submit_result now.`; await session.prompt(reminder, reminderToolChoice ? { toolChoice: reminderToolChoice } : undefined); } @@ -1137,32 +1137,32 @@ Call complete now.`; // Use final output if available, otherwise accumulated output let rawOutput = finalOutputChunks.length > 0 ? finalOutputChunks.join("") : outputChunks.join(""); - let abortedViaComplete = false; - const completeItems = progress.extractedToolData?.complete as + let abortedViaSubmitResult = false; + const submitResultItems = progress.extractedToolData?.submit_result as | Array<{ data?: unknown; status?: "success" | "aborted"; error?: string }> | undefined; const reportFindings = progress.extractedToolData?.report_finding as ReviewFinding[] | undefined; - const hasComplete = Array.isArray(completeItems) && completeItems.length > 0; - if (hasComplete) { - const lastComplete = completeItems[completeItems.length - 1]; - if (lastComplete?.status === "aborted") { - // Agent explicitly aborted via complete tool - clean exit with error info - abortedViaComplete = true; + const hasSubmitResult = Array.isArray(submitResultItems) && submitResultItems.length > 0; + if (hasSubmitResult) { + const lastSubmitResult = submitResultItems[submitResultItems.length - 1]; + if (lastSubmitResult?.status === "aborted") { + // Agent explicitly aborted via submit_result tool - clean exit with error info + abortedViaSubmitResult = true; exitCode = 0; - stderr = lastComplete.error || "Subagent aborted task"; + stderr = lastSubmitResult.error || "Subagent aborted task"; try { - rawOutput = JSON.stringify({ aborted: true, error: lastComplete.error }, null, 2); + rawOutput = JSON.stringify({ aborted: true, error: lastSubmitResult.error }, null, 2); } catch { - rawOutput = `{"aborted":true,"error":"${lastComplete.error || "Unknown error"}"}`; + rawOutput = `{"aborted":true,"error":"${lastSubmitResult.error || "Unknown error"}"}`; } } else { // Normal successful completion - const completeData = normalizeCompleteData(lastComplete?.data ?? null, reportFindings); + const completeData = normalizeCompleteData(lastSubmitResult?.data ?? null, reportFindings); try { rawOutput = JSON.stringify(completeData, null, 2) ?? "null"; } catch (err) { const errorMessage = err instanceof Error ? err.message : String(err); - rawOutput = `{"error":"Failed to serialize complete data: ${errorMessage}"}`; + rawOutput = `{"error":"Failed to serialize submit_result data: ${errorMessage}"}`; } exitCode = 0; stderr = ""; @@ -1186,7 +1186,7 @@ Call complete now.`; exitCode = 0; stderr = ""; } else { - const warning = "SYSTEM WARNING: Subagent exited without calling complete tool after 3 reminders."; + const warning = "SYSTEM WARNING: Subagent exited without calling submit_result tool after 3 reminders."; rawOutput = rawOutput ? `${warning}\n\n${rawOutput}` : warning; } } @@ -1210,7 +1210,7 @@ Call complete now.`; } // Update final progress - const wasAborted = abortedViaComplete || (!hasComplete && (done.aborted || signal?.aborted || false)); + const wasAborted = abortedViaSubmitResult || (!hasSubmitResult && (done.aborted || signal?.aborted || false)); progress.status = wasAborted ? "aborted" : exitCode === 0 ? "completed" : "failed"; scheduleProgress(true); diff --git a/packages/coding-agent/src/task/render.ts b/packages/coding-agent/src/task/render.ts index 43510530a..52121fd57 100644 --- a/packages/coding-agent/src/task/render.ts +++ b/packages/coding-agent/src/task/render.ts @@ -77,12 +77,12 @@ function formatJsonScalar(value: unknown, theme: Theme): string { return ""; } -const MISSING_COMPLETE_WARNING_PREFIX = "SYSTEM WARNING: Subagent exited without calling complete tool"; +const MISSING_SUBMIT_RESULT_WARNING_PREFIX = "SYSTEM WARNING: Subagent exited without calling submit_result tool"; -function extractMissingCompleteWarning(output: string): { warning?: string; rest: string } { +function extractMissingSubmitResultWarning(output: string): { warning?: string; rest: string } { const lines = output.split("\n"); const firstLine = lines[0]?.trim() ?? ""; - if (!firstLine.startsWith(MISSING_COMPLETE_WARNING_PREFIX)) { + if (!firstLine.startsWith(MISSING_SUBMIT_RESULT_WARNING_PREFIX)) { return { rest: output }; } const rest = lines @@ -574,9 +574,9 @@ function renderAgentProgress( // Render extracted tool data inline (e.g., review findings) if (progress.extractedToolData) { - // For completed tasks, check for review verdict from complete tool + // For completed tasks, check for review verdict from submit_result tool if (progress.status === "completed") { - const completeData = progress.extractedToolData.complete as Array<{ data: unknown }> | undefined; + const completeData = progress.extractedToolData.submit_result as Array<{ data: unknown }> | undefined; const reportFindingData = progress.extractedToolData.report_finding as ReportFindingDetails[] | undefined; const reviewData = completeData ?.map(c => c.data as SubmitReviewDetails) @@ -732,7 +732,8 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool const prefix = isLast ? theme.fg("dim", theme.tree.last) : theme.fg("dim", theme.tree.branch); const continuePrefix = isLast ? " " : `${theme.fg("dim", theme.tree.vertical)} `; - const { warning: missingCompleteWarning, rest: outputWithoutWarning } = extractMissingCompleteWarning(result.output); + const { warning: missingCompleteWarning, rest: outputWithoutWarning } = + extractMissingSubmitResultWarning(result.output); const aborted = result.aborted ?? false; const success = !aborted && result.exitCode === 0; const needsWarning = Boolean(missingCompleteWarning) && success; @@ -766,11 +767,11 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool lines.push(statusLine); lines.push(...renderArgsSection(result.args, continuePrefix, expanded, theme)); - // Check for review result (complete with review schema + report_finding) - const completeData = result.extractedToolData?.complete as Array<{ data: unknown }> | undefined; + // Check for review result (submit_result with review schema + report_finding) + const completeData = result.extractedToolData?.submit_result as Array<{ data: unknown }> | undefined; const reportFindingData = result.extractedToolData?.report_finding as ReportFindingDetails[] | undefined; - // Extract review verdict from complete tool's data field if it matches SubmitReviewDetails + // Extract review verdict from submit_result tool's data field if it matches SubmitReviewDetails const reviewData = completeData ?.map(c => c.data as SubmitReviewDetails) .filter(d => d && typeof d === "object" && "overall_correctness" in d); @@ -787,7 +788,7 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool const hasCompleteData = completeData && completeData.length > 0; const message = hasCompleteData ? "Review verdict missing expected fields" - : "Review incomplete (complete not called)"; + : "Review incomplete (submit_result not called)"; lines.push(`${continuePrefix}${theme.fg("warning", theme.status.warning)} ${theme.fg("dim", message)}`); lines.push(`${continuePrefix}${formatFindingSummary(reportFindingData, theme)}`); lines.push(...renderFindings(reportFindingData, continuePrefix, expanded, theme)); @@ -799,7 +800,7 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool if (result.extractedToolData) { for (const [toolName, dataArray] of Object.entries(result.extractedToolData)) { // Skip review tools - handled above - if (toolName === "complete" || toolName === "report_finding") continue; + if (toolName === "submit_result" || toolName === "report_finding") continue; const handler = subprocessToolRegistry.getHandler(toolName); if (handler?.renderFinal && (dataArray as unknown[]).length > 0) { diff --git a/packages/coding-agent/src/tools/index.ts b/packages/coding-agent/src/tools/index.ts index a844d9802..d0ba2ca08 100644 --- a/packages/coding-agent/src/tools/index.ts +++ b/packages/coding-agent/src/tools/index.ts @@ -19,7 +19,7 @@ import { WebSearchTool } from "../web/search"; import { AskTool } from "./ask"; import { BashTool } from "./bash"; import { CalculatorTool } from "./calculator"; -import { CompleteTool } from "./complete"; +import { SubmitResultTool } from "./submit-result"; import { ExitPlanModeTool } from "./exit-plan-mode"; import { FetchTool } from "./fetch"; import { FindTool } from "./find"; @@ -72,7 +72,7 @@ export { export { AskTool, type AskToolDetails } from "./ask"; export { BashTool, type BashToolDetails, type BashToolOptions } from "./bash"; export { CalculatorTool, type CalculatorToolDetails } from "./calculator"; -export { CompleteTool } from "./complete"; +export { SubmitResultTool } from "./submit-result"; export { type ExitPlanModeDetails, ExitPlanModeTool } from "./exit-plan-mode"; export { FetchTool, type FetchToolDetails } from "./fetch"; export { type FindOperations, FindTool, type FindToolDetails, type FindToolOptions } from "./find"; @@ -126,8 +126,8 @@ export interface ToolSession { eventBus?: EventBus; /** Output schema for structured completion (subagents) */ outputSchema?: unknown; - /** Whether to include the complete tool by default */ - requireCompleteTool?: boolean; + /** Whether to include the submit_result tool by default */ + requireSubmitResultTool?: boolean; /** Get session file */ getSessionFile: () => string | null; /** Get session ID */ @@ -198,7 +198,7 @@ export const BUILTIN_TOOLS: Record = { }; export const HIDDEN_TOOLS: Record = { - complete: s => new CompleteTool(s), + submit_result: s => new SubmitResultTool(s), report_finding: () => reportFindingTool, exit_plan_mode: s => new ExitPlanModeTool(s), }; @@ -240,7 +240,7 @@ function getPythonModeFromEnv(): PythonToolMode | null { */ export async function createTools(session: ToolSession, toolNames?: string[]): Promise { time("createTools:start"); - const includeComplete = session.requireCompleteTool === true; + const includeSubmitResult = session.requireSubmitResultTool === true; const enableLsp = session.enableLsp ?? true; const requestedTools = toolNames && toolNames.length > 0 ? [...new Set(toolNames)] : undefined; if (requestedTools && !requestedTools.includes("exit_plan_mode")) { @@ -296,8 +296,8 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P if (name === "python") return allowPython; return true; }; - if (includeComplete && requestedTools && !requestedTools.includes("complete")) { - requestedTools.push("complete"); + if (includeSubmitResult && requestedTools && !requestedTools.includes("submit_result")) { + requestedTools.push("submit_result"); } const filteredRequestedTools = requestedTools?.filter(name => name in allTools && isToolAllowed(name)); @@ -307,7 +307,7 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P ? filteredRequestedTools.map(name => [name, allTools[name]] as const) : [ ...Object.entries(BUILTIN_TOOLS).filter(([name]) => isToolAllowed(name)), - ...(includeComplete ? ([["complete", HIDDEN_TOOLS.complete]] as const) : []), + ...(includeSubmitResult ? ([["submit_result", HIDDEN_TOOLS.submit_result]] as const) : []), ...([["exit_plan_mode", HIDDEN_TOOLS.exit_plan_mode]] as const), ]; time("createTools:beforeFactories"); diff --git a/packages/coding-agent/src/tools/review.ts b/packages/coding-agent/src/tools/review.ts index f0f6068cc..66e977b3e 100644 --- a/packages/coding-agent/src/tools/review.ts +++ b/packages/coding-agent/src/tools/review.ts @@ -3,7 +3,7 @@ * * Used by the reviewer agent to report findings in a structured way. * Hidden by default - only enabled when explicitly listed in agent's tools. - * Reviewers finish via `complete` tool with SubmitReviewDetails schema. + * Reviewers finish via `submit_result` tool with SubmitReviewDetails schema. */ // ───────────────────────────────────────────────────────────────────────────── // Subprocess tool handlers - registered for extraction/rendering in task tool @@ -85,7 +85,7 @@ interface ReportFindingDetails { export const reportFindingTool: AgentTool = { name: "report_finding", label: "Report Finding", - description: "Report a code review finding. Use this for each issue found. Call complete when done.", + description: "Report a code review finding. Use this for each issue found. Call submit_result when done.", parameters: ReportFindingParams, async execute(_toolCallId, params, _signal, _onUpdate, _ctx) { const { title, body, priority, confidence, file_path, line_start, line_end } = params; @@ -140,7 +140,7 @@ export const reportFindingTool: AgentTool { - public readonly name = "complete"; - public readonly label = "Complete"; +export class SubmitResultTool implements AgentTool { + public readonly name = "submit_result"; + public readonly label = "Submit Result"; public readonly description = "Finish the task with structured JSON output. Call exactly once at the end of the task.\n\n" + "If you cannot complete the task, call with status='aborted' and an error message."; @@ -106,9 +106,9 @@ export class CompleteTool implements AgentTool { _toolCallId: string, params: Static, _signal?: AbortSignal, - _onUpdate?: AgentToolUpdateCallback, + _onUpdate?: AgentToolUpdateCallback, _context?: AgentToolContext, - ): Promise> { + ): Promise> { const status = (params.status ?? "success") as "success" | "aborted"; // Skip validation when aborting - data is optional for aborts @@ -125,7 +125,7 @@ export class CompleteTool implements AgentTool { } const responseText = - status === "aborted" ? `Task aborted: ${params.error || "No reason provided"}` : "Completion recorded."; + status === "aborted" ? `Task aborted: ${params.error || "No reason provided"}` : "Result submitted."; return { content: [{ type: "text", text: responseText }], @@ -135,7 +135,7 @@ export class CompleteTool implements AgentTool { } // Register subprocess tool handler for extraction + termination. -subprocessToolRegistry.register("complete", { - extractData: event => event.result?.details as CompleteDetails | undefined, +subprocessToolRegistry.register("submit_result", { + extractData: event => event.result?.details as SubmitResultDetails | undefined, shouldTerminate: () => true, }); diff --git a/packages/coding-agent/test/tools/index.test.ts b/packages/coding-agent/test/tools/index.test.ts index d6b10c684..33b76f751 100644 --- a/packages/coding-agent/test/tools/index.test.ts +++ b/packages/coding-agent/test/tools/index.test.ts @@ -112,12 +112,12 @@ describe("createTools", () => { expect(names).toEqual(["report_finding", "exit_plan_mode"]); }); - it("includes complete tool when required", async () => { - const session = createTestSession({ requireCompleteTool: true }); + it("includes submit_result tool when required", async () => { + const session = createTestSession({ requireSubmitResultTool: true }); const tools = await createTools(session); const names = tools.map(t => t.name); - expect(names).toContain("complete"); + expect(names).toContain("submit_result"); }); it("excludes ask tool when hasUI is false", async () => { @@ -166,6 +166,6 @@ describe("createTools", () => { }); it("HIDDEN_TOOLS contains review tools", () => { - expect(Object.keys(HIDDEN_TOOLS).sort()).toEqual(["complete", "exit_plan_mode", "report_finding"]); + expect(Object.keys(HIDDEN_TOOLS).sort()).toEqual(["exit_plan_mode", "report_finding", "submit_result"]); }); });