fix: ensure tools are always in same order (#26370)

This commit is contained in:
Aiden Cline
2026-05-08 10:59:41 -05:00
committed by GitHub
parent fc46cef5fd
commit 83bb216486

View File

@@ -225,6 +225,7 @@ const live: Layer.Layer<
execute: async () => ({ output: "", title: "", metadata: {} }), execute: async () => ({ output: "", title: "", metadata: {} }),
}) })
} }
const sortedTools = Object.fromEntries(Object.entries(tools).toSorted(([a], [b]) => a.localeCompare(b)))
// Wire up toolExecutor for DWS workflow models so that tool calls // Wire up toolExecutor for DWS workflow models so that tool calls
// from the workflow service are executed via opencode's tool system // from the workflow service are executed via opencode's tool system
@@ -238,7 +239,7 @@ const live: Layer.Layer<
workflowModel.sessionID = input.sessionID workflowModel.sessionID = input.sessionID
workflowModel.systemPrompt = system.join("\n") workflowModel.systemPrompt = system.join("\n")
workflowModel.toolExecutor = async (toolName, argsJson, _requestID) => { workflowModel.toolExecutor = async (toolName, argsJson, _requestID) => {
const t = tools[toolName] const t = sortedTools[toolName]
if (!t || !t.execute) { if (!t || !t.execute) {
return { result: "", error: `Unknown tool: ${toolName}` } return { result: "", error: `Unknown tool: ${toolName}` }
} }
@@ -260,7 +261,7 @@ const live: Layer.Layer<
} }
const ruleset = Permission.merge(input.agent.permission ?? [], input.permission ?? []) const ruleset = Permission.merge(input.agent.permission ?? [], input.permission ?? [])
workflowModel.sessionPreapprovedTools = Object.keys(tools).filter((name) => { workflowModel.sessionPreapprovedTools = Object.keys(sortedTools).filter((name) => {
const match = ruleset.findLast((rule) => Wildcard.match(name, rule.permission)) const match = ruleset.findLast((rule) => Wildcard.match(name, rule.permission))
return !match || match.action !== "ask" return !match || match.action !== "ask"
}) })
@@ -341,7 +342,7 @@ const live: Layer.Layer<
}, },
async experimental_repairToolCall(failed) { async experimental_repairToolCall(failed) {
const lower = failed.toolCall.toolName.toLowerCase() const lower = failed.toolCall.toolName.toLowerCase()
if (lower !== failed.toolCall.toolName && tools[lower]) { if (lower !== failed.toolCall.toolName && sortedTools[lower]) {
l.info("repairing tool call", { l.info("repairing tool call", {
tool: failed.toolCall.toolName, tool: failed.toolCall.toolName,
repaired: lower, repaired: lower,
@@ -364,8 +365,8 @@ const live: Layer.Layer<
topP: params.topP, topP: params.topP,
topK: params.topK, topK: params.topK,
providerOptions: ProviderTransform.providerOptions(input.model, params.options), providerOptions: ProviderTransform.providerOptions(input.model, params.options),
activeTools: Object.keys(tools).filter((x) => x !== "invalid"), activeTools: Object.keys(sortedTools).filter((x) => x !== "invalid"),
tools, tools: sortedTools,
toolChoice: input.toolChoice, toolChoice: input.toolChoice,
maxOutputTokens: params.maxOutputTokens, maxOutputTokens: params.maxOutputTokens,
abortSignal: input.abort, abortSignal: input.abort,