fix: use Promise.allSettled to prevent missing ToolMessage responses
When LLM sends multiple parallel tool_calls but one throws unexpectedly, Promise.all loses all results causing 400 error from OpenAI. Promise.allSettled ensures every tool_call_id gets a response. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
e3147231a6
commit
9cf6293198
@@ -144,8 +144,22 @@ export async function toolExecutorNode(
|
||||
}
|
||||
});
|
||||
|
||||
const results = await Promise.all(executions);
|
||||
toolMessages.push(...results);
|
||||
const settled = await Promise.allSettled(executions);
|
||||
for (let i = 0; i < settled.length; i++) {
|
||||
const result = settled[i];
|
||||
if (result.status === "fulfilled") {
|
||||
toolMessages.push(result.value);
|
||||
} else {
|
||||
const tc = toolCalls[i];
|
||||
const errMsg = result.reason instanceof Error ? result.reason.message : String(result.reason);
|
||||
console.error(`[tool-executor] Unhandled rejection for ${tc.name}:`, result.reason);
|
||||
toolMessages.push({
|
||||
role: "tool" as const,
|
||||
tool_call_id: tc.id ?? "",
|
||||
content: JSON.stringify({ ok: false, tool: tc.name, error: errMsg }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
messages: toolMessages,
|
||||
|
||||
@@ -1033,8 +1033,22 @@ export async function toolExecutorNode(
|
||||
}
|
||||
});
|
||||
|
||||
const results = await Promise.all(executions);
|
||||
toolMessages.push(...results);
|
||||
const settled = await Promise.allSettled(executions);
|
||||
for (let i = 0; i < settled.length; i++) {
|
||||
const result = settled[i];
|
||||
if (result.status === "fulfilled") {
|
||||
toolMessages.push(result.value);
|
||||
} else {
|
||||
const tc = toolCalls[i];
|
||||
const errMsg = result.reason instanceof Error ? result.reason.message : String(result.reason);
|
||||
console.error(`[tool-executor] Unhandled rejection for ${tc.name}:`, result.reason);
|
||||
toolMessages.push({
|
||||
role: "tool" as const,
|
||||
tool_call_id: tc.id ?? "",
|
||||
content: JSON.stringify({ ok: false, tool: tc.name, error: errMsg }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Push next-actions card based on successful tool results
|
||||
const successfulTools = statusList.filter(
|
||||
|
||||
@@ -375,8 +375,24 @@ export async function toolExecutorNode(
|
||||
}
|
||||
});
|
||||
|
||||
const results = await Promise.all(executions);
|
||||
toolMessages.push(...results);
|
||||
const settled = await Promise.allSettled(executions);
|
||||
for (let i = 0; i < settled.length; i++) {
|
||||
const result = settled[i];
|
||||
if (result.status === "fulfilled") {
|
||||
toolMessages.push(result.value);
|
||||
} else {
|
||||
// Ensure every tool_call_id gets a response even if execution threw unexpectedly
|
||||
const tc = toolCalls[i];
|
||||
const errMsg = result.reason instanceof Error ? result.reason.message : String(result.reason);
|
||||
console.error(`[tool-executor] Unhandled rejection for ${tc.name}:`, result.reason);
|
||||
toolMessages.push({
|
||||
role: "tool" as const,
|
||||
tool_call_id: tc.id ?? "",
|
||||
content: JSON.stringify({ ok: false, tool: tc.name, error: errMsg }),
|
||||
});
|
||||
statusList.push({ tool: tc.name ?? "unknown", status: "error", message: errMsg });
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
messages: toolMessages,
|
||||
|
||||
Reference in New Issue
Block a user