{"record":{"id":"470edccce291ec4d","repo":"siyuan-note/siyuan","slug":"streamed-function-call-id-does-not-match-the-termi","errorCode":null,"errorMessage":"streamed function call ID does not match the terminal response","messagePattern":"streamed function call ID does not match the terminal response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/openai_completion.go","lineNumber":521,"sourceCode":"\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\n\t\t}\n\t\tcurrent := stream.responseToolCalls[index]\n\t\tif current.ID != \"\" && item.CallID != \"\" && current.ID != item.CallID {\n\t\t\treturn errors.New(\"streamed function call ID does not match the terminal response\")\n\t\t}\n\t\tif current.Function.Name != \"\" && item.Name != \"\" && current.Function.Name != item.Name {\n\t\t\treturn errors.New(\"streamed function name does not match the terminal response\")\n\t\t}\n\t\tif current.Function.Arguments != item.Arguments &&\n\t\t\t!strings.HasPrefix(item.Arguments, current.Function.Arguments) {\n\t\t\treturn errors.New(\"streamed function arguments do not match the terminal response\")\n\t\t}\n\t\tdelta := openai.ToolCall{Type: openai.ToolTypeFunction}\n\t\tdeltaIndex := index\n\t\tdelta.Index = &deltaIndex\n\t\tchanged := false\n\t\tif current.ID == \"\" && item.CallID != \"\" {\n\t\t\tdelta.ID = item.CallID\n\t\t\tchanged = true\n\t\t}\n\t\tif current.Function.Name == \"\" && item.Name != \"\" {\n\t\t\tdelta.Function.Name = item.Name","sourceCodeStart":503,"sourceCodeEnd":539,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/util/openai_completion.go#L503-L539","documentation":"For every terminal function_call item, the adapter cross-checks the call ID accumulated from deltas (current.ID) against item.CallID whenever both are non-empty. A mismatch means the stream and the final response describe different calls — typically a provider regeneration or index swap — and executing either blindly could invoke the wrong function, so the adapter refuses.","triggerScenarios":"Gateways regenerating call IDs between streaming and final assembly; parallel tool calls with indices swapped server-side; event translation layers rewriting item identifiers mid-stream.","commonSituations":"Third-party gateways stitching Responses events from multiple upstream attempts; failover mid-stream; non-compliant Responses-API reimplementations.","solutions":["Retry the request once — transient assembly inconsistencies often clear.","Reproduce against the official OpenAI endpoint to confirm provider fault; upgrade or switch the gateway.","Disable streaming for tool calls on the affected provider.","Report with a captured SSE trace showing both the streamed ID and the terminal item."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"Discard accumulated tool calls and re-issue the request with backoff; if the same index keeps mismatching, permanently switch that provider to non-streaming tool calls.","preventionTips":["Prefer official or fully compliant endpoints for tool calling","Capture SSE traces when integrating new gateways","Alert on repeated stream-versus-terminal mismatches per provider"],"tags":["streaming","tool-calls","openai","responses-api","id-mismatch"],"backgroundTag":"stream-state-mismatch","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}