hack to return tool call errors back to model

This commit is contained in:
Dax Raad
2025-08-04 11:59:42 -04:00
parent b05decc572
commit 0a42068fbb
4 changed files with 41 additions and 0 deletions

View File

@@ -13,6 +13,7 @@ import {
type ModelMessage, type ModelMessage,
stepCountIs, stepCountIs,
type StreamTextResult, type StreamTextResult,
InvalidToolInputError,
} from "ai" } from "ai"
import PROMPT_INITIALIZE from "../session/prompt/initialize.txt" import PROMPT_INITIALIZE from "../session/prompt/initialize.txt"
@@ -869,7 +870,21 @@ export namespace Session {
messages, messages,
} }
}, },
async experimental_repairToolCall(input) {
if (InvalidToolInputError.isInstance(input.error)) {
return {
...input.toolCall,
input: JSON.stringify({
tool: input.toolCall.toolName,
error: input.error.message,
}),
toolName: "invalid",
}
}
return null
},
maxRetries: 3, maxRetries: 3,
activeTools: Object.keys(tools).filter((x) => x !== "invalid"),
maxOutputTokens: outputLimit, maxOutputTokens: outputLimit,
abortSignal: abort.signal, abortSignal: abort.signal,
stopWhen: stepCountIs(1000), stopWhen: stepCountIs(1000),
@@ -962,6 +977,7 @@ export namespace Session {
if (match) { if (match) {
const part = await updatePart({ const part = await updatePart({
...match, ...match,
tool: value.toolName,
state: { state: {
status: "running", status: "running",
input: value.input, input: value.input,

View File

@@ -0,0 +1,17 @@
import { z } from "zod"
import { Tool } from "./tool"
export const InvalidTool = Tool.define("invalid", {
description: "Do not use",
parameters: z.object({
tool: z.string(),
error: z.string(),
}),
async execute(params) {
return {
title: "Invalid Tool",
output: `The arguments provided to the tool are invalid: ${params.error}`,
metadata: {},
}
},
})

View File

@@ -10,9 +10,11 @@ import { TaskTool } from "./task"
import { TodoWriteTool, TodoReadTool } from "./todo" import { TodoWriteTool, TodoReadTool } from "./todo"
import { WebFetchTool } from "./webfetch" import { WebFetchTool } from "./webfetch"
import { WriteTool } from "./write" import { WriteTool } from "./write"
import { InvalidTool } from "./invalid"
export namespace ToolRegistry { export namespace ToolRegistry {
const ALL = [ const ALL = [
InvalidTool,
BashTool, BashTool,
EditTool, EditTool,
WebFetchTool, WebFetchTool,

View File

@@ -555,6 +555,8 @@ func renderToolName(name string) string {
switch name { switch name {
case "webfetch": case "webfetch":
return "Fetch" return "Fetch"
case "invalid":
return "Invalid"
default: default:
normalizedName := name normalizedName := name
if after, ok := strings.CutPrefix(name, "opencode_"); ok { if after, ok := strings.CutPrefix(name, "opencode_"); ok {
@@ -657,6 +659,10 @@ func renderToolTitle(
title = getTodoTitle(toolCall) title = getTodoTitle(toolCall)
case "todoread": case "todoread":
return "Plan" return "Plan"
case "invalid":
if actualTool, ok := toolArgsMap["tool"].(string); ok {
title = renderToolName(actualTool)
}
default: default:
toolName := renderToolName(toolCall.Tool) toolName := renderToolName(toolCall.Tool)
title = fmt.Sprintf("%s %s", toolName, toolArgs) title = fmt.Sprintf("%s %s", toolName, toolArgs)