{"record":{"id":"50ad6e17bd02025c","repo":"siyuan-note/siyuan","slug":"response-ended-with-an-incomplete-function-call","errorCode":null,"errorMessage":"response ended with an incomplete function call","messagePattern":"response ended with an incomplete function call","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/openai_completion.go","lineNumber":557,"sourceCode":"\t\t\treturn openai.ChatCompletionStreamResponse{}, responseEventError(event, \"response stream failed\")\n\t\t}\n\t\treturn response, nil\n\t}\n}\n\nfunc (stream *OpenAICompletionStream) queueResponseTerminal(response openai.CreateResponseResponse) error {\n\tif err := responseResultError(response); err != nil {\n\t\treturn err\n\t}\n\tterminalToolCalls := map[int]struct{}{}\n\tfor index, raw := range response.Output {\n\t\titem, ok := responseOutputItem(raw)\n\t\tif !ok || item.Type != \"function_call\" {\n\t\t\tcontinue\n\t\t}\n\t\tif item.Status == \"incomplete\" || item.Status == \"in_progress\" ||\n\t\t\t(response.Status == openai.ResponseStatusIncomplete && item.Status != \"completed\") {\n\t\t\treturn errors.New(\"response ended with an incomplete function call\")\n\t\t}\n\t\tterminalToolCalls[index] = struct{}{}\n\t}\n\tfor index := range stream.responseToolCalls {\n\t\tif _, ok := terminalToolCalls[index]; !ok {\n\t\t\treturn errors.New(\"streamed function call is missing from the terminal response\")\n\t\t}\n\t}\n\toutput, err := MarshalOpenAIResponseOutput(response.Output)\n\tif err != nil {\n\t\treturn err\n\t}\n\tstream.responseOutput = output\n\n\tfor index, raw := range response.Output {\n\t\titem, ok := responseOutputItem(raw)\n\t\tif !ok || item.Type != \"function_call\" {\n\t\t\tcontinue","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/openai_completion.go#L539-L575","documentation":"This is a consistency check in the OpenAI Responses-API-to-Chat-Completions streaming adapter (kernel/util/openai_completion.go). When the terminal event (response.completed / response.incomplete) arrives, queueResponseTerminal inspects every function_call item in the final response output; if a function call is still 'incomplete', 'in_progress', or the overall response status is 'incomplete' with a non-completed function call, it aborts the stream instead of emitting a truncated tool call that the agent might execute. It protects the agent runtime from running half-formed tool invocations.","triggerScenarios":"Streaming via OpenAICompletionStream.Recv() over the Responses API when the response terminates with status 'incomplete' (e.g. max_output_tokens hit, content filter) while a function_call output item is present and not marked 'completed'.","commonSituations":"Model hits the max_output_tokens limit mid-way through emitting tool call arguments; provider truncates the response; content filter cuts off the turn while the model was calling a tool; a proxy returns a non-standard function_call item status.","solutions":["Increase the model's max output token budget so the function call can complete (set a higher MaxTokens/MaxCompletionTokens on the request).","Retry the request; transient provider truncation is often resolved on a subsequent call.","Reduce prompt/tool-schema size so fewer tokens are spent before the tool call completes.","Handle the error in the agent loop by treating the turn as failed and re-prompting, rather than parsing the partial tool call."],"exampleFix":"// before\nresp, err := client.Chat.Completions.Create(...) // MaxTokens: 512\n// after\nresp, err := client.Chat.Completions.Create(...) // MaxTokens: 4096 (room for full tool call arguments)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"resp, err := stream.Recv()\nif err != nil {\n    if strings.Contains(err.Error(), \"incomplete function call\") {\n        // treat turn as failed; re-issue request with a larger token budget\n        return retryWithLargerBudget(ctx)\n    }\n    return err\n}","preventionTips":["Set generous max output tokens when tool calling is enabled","Keep tool argument schemas compact","Retry truncated streaming turns instead of parsing partial tool calls","Monitor finish reasons / incomplete statuses in provider metrics"],"tags":["openai","streaming","tool-calls","truncated-response"],"backgroundTag":"unexpected-response-shape","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}