(
tool: Tool,
messages: Message[],
tools: readonly { name: string }[],
)
| 576 | * model to re-load the tool; this hint does. Null if the schema was sent. |
| 577 | */ |
| 578 | export function buildSchemaNotSentHint( |
| 579 | tool: Tool, |
| 580 | messages: Message[], |
| 581 | tools: readonly { name: string }[], |
| 582 | ): string | null { |
| 583 | // Optimistic gating — reconstructing claude.ts's full useToolSearch |
| 584 | // computation is fragile. These two gates prevent pointing at a ToolSearch |
| 585 | // that isn't callable; occasional misfires (Haiku, tst-auto below threshold) |
| 586 | // cost one extra round-trip on an already-failing path. |
| 587 | if (!isToolSearchEnabledOptimistic()) return null |
| 588 | if (!isToolSearchToolAvailable(tools)) return null |
| 589 | if (!isDeferredTool(tool)) return null |
| 590 | const discovered = extractDiscoveredToolNames(messages) |
| 591 | if (discovered.has(tool.name)) return null |
| 592 | return ( |
| 593 | `\n\nThis tool's schema was not sent to the API — it was not in the discovered-tool set derived from message history. ` + |
| 594 | `Without the schema in your prompt, typed parameters (arrays, numbers, booleans) get emitted as strings and the client-side parser rejects them. ` + |
| 595 | `Load the tool first: call ${TOOL_SEARCH_TOOL_NAME} with query "select:${tool.name}", then retry this call.` |
| 596 | ) |
| 597 | } |
| 598 | |
| 599 | async function checkPermissionsAndCallTool( |
| 600 | tool: Tool, |
no test coverage detected