fix: invalid tool call ID recovery and system-reminder tag centralization (#627)
Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
@@ -6,6 +6,11 @@ import { APPROVAL_RECOVERY_PROMPT } from "./promptAssets";
|
||||
const APPROVAL_RECOVERY_DETAIL_FRAGMENT =
|
||||
"no tool call is currently awaiting approval";
|
||||
|
||||
// Error when approval tool call IDs don't match what server expects
|
||||
// Format: "Invalid tool call IDs: Expected [...], got [...]"
|
||||
// This is a specific subtype of desync - server HAS approvals but with different IDs
|
||||
const INVALID_TOOL_CALL_IDS_FRAGMENT = "invalid tool call ids";
|
||||
|
||||
// Error when trying to SEND message but server has pending approval waiting
|
||||
// This is the CONFLICT error - opposite of desync
|
||||
const APPROVAL_PENDING_DETAIL_FRAGMENT = "cannot send a new message";
|
||||
@@ -27,7 +32,27 @@ type RunErrorMetadata =
|
||||
|
||||
export function isApprovalStateDesyncError(detail: unknown): boolean {
|
||||
if (typeof detail !== "string") return false;
|
||||
return detail.toLowerCase().includes(APPROVAL_RECOVERY_DETAIL_FRAGMENT);
|
||||
const lower = detail.toLowerCase();
|
||||
return (
|
||||
lower.includes(APPROVAL_RECOVERY_DETAIL_FRAGMENT) ||
|
||||
lower.includes(INVALID_TOOL_CALL_IDS_FRAGMENT)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if error specifically indicates tool call ID mismatch.
|
||||
* This is a subtype of desync where the server HAS pending approvals,
|
||||
* but they have different IDs than what the client sent.
|
||||
*
|
||||
* Unlike "no tool call is currently awaiting approval" (server has nothing),
|
||||
* this error means we need to FETCH the actual pending approvals to resync.
|
||||
*
|
||||
* Error format:
|
||||
* { detail: "Invalid tool call IDs: Expected ['tc_abc'], got ['tc_xyz']" }
|
||||
*/
|
||||
export function isInvalidToolCallIdsError(detail: unknown): boolean {
|
||||
if (typeof detail !== "string") return false;
|
||||
return detail.toLowerCase().includes(INVALID_TOOL_CALL_IDS_FRAGMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,11 @@ import {
|
||||
addToolCall,
|
||||
updateSubagent,
|
||||
} from "../../cli/helpers/subagentState.js";
|
||||
import { INTERRUPTED_BY_USER } from "../../constants";
|
||||
import {
|
||||
INTERRUPTED_BY_USER,
|
||||
SYSTEM_REMINDER_CLOSE,
|
||||
SYSTEM_REMINDER_OPEN,
|
||||
} from "../../constants";
|
||||
import { cliPermissions } from "../../permissions/cli";
|
||||
import { permissionMode } from "../../permissions/mode";
|
||||
import { sessionPermissions } from "../../permissions/session";
|
||||
@@ -643,11 +647,11 @@ function buildDeploySystemReminder(
|
||||
? "read-only tools (Read, Glob, Grep)"
|
||||
: "local tools (Bash, Read, Write, Edit, etc.)";
|
||||
|
||||
return `<system-reminder>
|
||||
return `${SYSTEM_REMINDER_OPEN}
|
||||
This task is from "${senderAgentName}" (agent ID: ${senderAgentId}), which deployed you as a subagent inside the Letta Code CLI (docs.letta.com/letta-code).
|
||||
You have access to ${toolDescription} in their codebase.
|
||||
Your final message will be returned to the caller.
|
||||
</system-reminder>
|
||||
${SYSTEM_REMINDER_CLOSE}
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user