From db9600054c4cd7f50a5dd820073bf950f426034e Mon Sep 17 00:00:00 2001 From: aikiata <116858811+aikiata@users.noreply.github.com> Date: Sun, 6 Sep 2026 23:20:17 +0700 Subject: [PATCH] fix(providers): iterate tool-call accumulators by map, not index ChatStream parsed the tool-call accumulator map with a positional loop (for i := 0; i < len(accumulators); i++ { acc := accumulators[i] }), assuming OpenAI-compatible providers always emit contiguous zero-based tc.Index values in streamed delta.tool_calls. Some OpenAI-compatible gateways (observed with a self-hosted point-p1 proxy) emit non-contiguous or non-zero-based indices. When that happens accumulators[i] misses a populated key and returns a nil *toolCallAccumulator, and the next line dereferences acc.rawArgs on that nil pointer, causing a SIGSEGV panic. The panic kills the in-flight chat run's goroutine; the gateway's tracing safety-net logs 'finalizing orphan trace' and the user's message goes unanswered. Fix: range over the accumulators map directly instead of indexing by position, and skip nil entries defensively. Verified: built a full backend image (make build-full equivalent, CGO_ENABLED=0 go build -tags embedui) from this branch, deployed it against a real point-p1-backed agent, and confirmed multiple multi-tool-call turns (use_skill, read_file, exec x3) that previously triggered the panic now complete via v3.run.completed with no panic and no safety-net trace. --- internal/providers/openai_chat.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/providers/openai_chat.go b/internal/providers/openai_chat.go index 084c1a8c..30cc4803 100644 --- a/internal/providers/openai_chat.go +++ b/internal/providers/openai_chat.go @@ -195,9 +195,15 @@ func (p *OpenAIProvider) ChatStream(ctx context.Context, req ChatRequest, onChun return result, fmt.Errorf("%s: stream read error: %w", p.name, err) } - // Parse accumulated tool call arguments - for i := 0; i < len(accumulators); i++ { - acc := accumulators[i] + // Parse accumulated tool call arguments. + // Iterate the map directly (not 0..len(accumulators)-1): providers are not + // guaranteed to emit contiguous zero-based tc.Index values in delta.ToolCalls, + // so indexing by position can miss populated slots and hit a nil accumulator, + // causing a nil-pointer panic (observed with the point-p1/9router provider). + for _, acc := range accumulators { + if acc == nil { + continue + } args := make(map[string]any) if err := json.Unmarshal([]byte(acc.rawArgs), &args); err != nil && acc.rawArgs != "" { slog.Warn("openai_stream: failed to parse tool call arguments",