fix: show tool error fallback for tool-only replies
This commit is contained in:
@@ -23,6 +23,8 @@ Docs: https://docs.clawd.bot
|
||||
### Fixes
|
||||
- Gateway: compare Linux process start time to avoid PID recycling lock loops; keep locks unless stale. (#1572) Thanks @steipete.
|
||||
- Skills: gate bird Homebrew install to macOS. (#1569) Thanks @bradleypriest.
|
||||
- Slack: honor open groupPolicy for unlisted channels in message + slash gating. (#1563) Thanks @itsjaydesu.
|
||||
- Agents: show tool error fallback when the last assistant turn only invoked tools (prevents silent stops).
|
||||
- Agents: ignore IDENTITY.md template placeholders when parsing identity to avoid placeholder replies. (#1556)
|
||||
- Agents: drop orphaned OpenAI Responses reasoning blocks on model switches. (#1562) Thanks @roshanasingh4.
|
||||
- Docker: update gateway command in docker-compose and Hetzner guide. (#1514)
|
||||
|
||||
@@ -148,6 +148,35 @@ describe("buildEmbeddedRunPayloads", () => {
|
||||
expect(payloads[0]?.text).toBe("All good");
|
||||
});
|
||||
|
||||
it("adds tool error fallback when the assistant only invoked tools", () => {
|
||||
const payloads = buildEmbeddedRunPayloads({
|
||||
assistantTexts: [],
|
||||
toolMetas: [],
|
||||
lastAssistant: {
|
||||
stopReason: "toolUse",
|
||||
content: [
|
||||
{
|
||||
type: "toolCall",
|
||||
id: "toolu_01",
|
||||
name: "exec",
|
||||
arguments: { command: "echo hi" },
|
||||
},
|
||||
],
|
||||
} as AssistantMessage,
|
||||
lastToolError: { toolName: "exec", error: "Command exited with code 1" },
|
||||
sessionKey: "session:telegram",
|
||||
inlineToolResultsAllowed: false,
|
||||
verboseLevel: "off",
|
||||
reasoningLevel: "off",
|
||||
toolResultFormat: "plain",
|
||||
});
|
||||
|
||||
expect(payloads).toHaveLength(1);
|
||||
expect(payloads[0]?.isError).toBe(true);
|
||||
expect(payloads[0]?.text).toContain("Exec");
|
||||
expect(payloads[0]?.text).toContain("code 1");
|
||||
});
|
||||
|
||||
it("suppresses recoverable tool errors containing 'required'", () => {
|
||||
const payloads = buildEmbeddedRunPayloads({
|
||||
assistantTexts: [],
|
||||
|
||||
@@ -169,7 +169,16 @@ export function buildEmbeddedRunPayloads(params: {
|
||||
}
|
||||
|
||||
if (params.lastToolError) {
|
||||
const hasUserFacingReply = replyItems.length > 0;
|
||||
const lastAssistantHasToolCalls =
|
||||
Array.isArray(params.lastAssistant?.content) &&
|
||||
params.lastAssistant?.content.some((block) =>
|
||||
block && typeof block === "object"
|
||||
? (block as { type?: unknown }).type === "toolCall"
|
||||
: false,
|
||||
);
|
||||
const lastAssistantWasToolUse = params.lastAssistant?.stopReason === "toolUse";
|
||||
const hasUserFacingReply =
|
||||
replyItems.length > 0 && !lastAssistantHasToolCalls && !lastAssistantWasToolUse;
|
||||
// Check if this is a recoverable/internal tool error that shouldn't be shown to users
|
||||
// when there's already a user-facing reply (the model should have retried).
|
||||
const errorLower = (params.lastToolError.error ?? "").toLowerCase();
|
||||
|
||||
Reference in New Issue
Block a user