Summary
On the final permitted iteration, the function-invocation loop removes local function declarations. If the provider nevertheless emits a local call or approval, TypeScript returns content it will neither execute nor remove, despite the public contract promising a final answer with no unanswered local tool calls.
Python hardened this behavior with per-update filtering and the deterministic fallback text:
Function invocation limit reached before a final answer could be produced.
Required implementation
- On the final request, remove local function declarations and send
toolChoice: "none".
- Treat only actionable local
function_call content and local function_approval_request content as unexecutable. Use the existing hosted-approval predicate; hosted approvals are provider-owned and survive.
- In streaming mode, filter each update before accumulation/yield. Do not add a full-final-round gate: retained updates continue flowing as they arrive.
- Preserve text, reasoning, metadata, raw representation, hosted/informational content, and provider-executed
informationalOnly call/result pairs.
- If removing local content leaves a metadata-bearing update, retain it. Omit only a truly empty update.
- Append the exact fallback only when finalization leaves no non-blank user-visible answer and no hosted approval. Do not replace retained content to make room for it.
Acceptance criteria
Summary
On the final permitted iteration, the function-invocation loop removes local function declarations. If the provider nevertheless emits a local call or approval, TypeScript returns content it will neither execute nor remove, despite the public contract promising a final answer with no unanswered local tool calls.
Python hardened this behavior with per-update filtering and the deterministic fallback text:
Required implementation
toolChoice: "none".function_callcontent and localfunction_approval_requestcontent as unexecutable. Use the existing hosted-approval predicate; hosted approvals are provider-owned and survive.informationalOnlycall/result pairs.Acceptance criteria
toolChoice: "none".informationalOnlycall/result pairs and hosted approvals survive unchanged in awaited and streamed modes.