Details and log output for this agent run.
{"query": "DisallowUnknownFields", "max_results": 50}
/project/internal/llm/streamer.go:70: decoder.DisallowUnknownFields() /project/internal/llm/types.go:210:// the streamer decodes with DisallowUnknownFields, so this must match
{"end_line": 80, "path": "internal/llm/streamer.go", "start_line": 60}
{"path":"internal/llm/streamer.go","content":"\r\n\tif bytes.Equal(buf, []byte(\"[DONE]\")) {\r\n\t\ts.resp.Body.Close()\r\n\t\ts.eof = true\r\n\t\treturn nil, io.EOF\r\n\t}\r\n\r\n\tvar completion ChatCompletion\r\n\r\n\tdecoder := json.NewDecoder(bytes.NewReader(buf))\r\n\tdecoder.DisallowUnknownFields()\r\n\r\n\tif err := decoder.Decode(\u0026completion); err != nil {\r\n\t\treturn nil, fmt.Errorf(\"decode completion chunk: %w: %s\", err, buf)\r\n\t}\r\n\r\n\ts.completion.Merge(\u0026completion)\r\n\r\n\treturn \u0026s.completion, nil\r\n}\r","start_line":60,"end_line":79,"total_lines":79,"truncated":false}
{"end_line": 220, "path": "internal/llm/types.go", "start_line": 200}
{"path":"internal/llm/types.go","content":"\tif next.FinishReason != \"\" {\r\n\t\tc.FinishReason = next.FinishReason\r\n\t}\r\n\r\n\tif next.Role != \"\" {\r\n\t\tc.Role = next.Role\r\n\t}\r\n}\r\n\r\n// Timings mirrors llama.cpp's /chat/completions timing block exactly;\r\n// the streamer decodes with DisallowUnknownFields, so this must match\r\n// the server's JSON shape field-for-field.\r\ntype Timings struct {\r\n\tCacheN int `json:\"cache_n\"`\r\n\tDraftN int `json:\"draft_n\"`\r\n\tDraftNAccepted int `json:\"draft_n_accepted\"`\r\n\tPromptN int `json:\"prompt_n\"`\r\n\tPromptMs float64 `json:\"prompt_ms\"`\r\n\tPromptPerTokenMs float64 `json:\"prompt_per_token_ms\"`\r\n\tPromptPerSecond float64 `json:\"prompt_per_second\"`\r\n\tPredictedN int `json:\"predicted_n\"`\r","start_line":200,"end_line":220,"total_lines":267,"truncated":true}
{"end_line": 79, "path": "internal/llm/streamer.go", "start_line": 1}
{"path":"internal/llm/streamer.go","content":"package llm\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"bytes\"\r\n\t\"encoding/json\"\r\n\t\"fmt\"\r\n\t\"io\"\r\n\t\"net/http\"\r\n)\r\n\r\ntype Streamer struct {\r\n\tcompletion ChatCompletion\r\n\tresp *http.Response\r\n\tscanner *bufio.Scanner\r\n\teof bool\r\n}\r\n\r\nfunc NewStreamer(resp *http.Response) (*Streamer, error) {\r\n\tif resp.StatusCode != http.StatusOK {\r\n\t\tbody, _ := io.ReadAll(resp.Body)\r\n\t\tresp.Body.Close()\r\n\t\treturn nil, fmt.Errorf(\"status: %d: %s\", resp.StatusCode, body)\r\n\t}\r\n\r\n\treturn \u0026Streamer{\r\n\t\tresp: resp,\r\n\t\tscanner: bufio.NewScanner(resp.Body),\r\n\t}, nil\r\n}\r\n\r\n// Get returns the accumulated completion after merging in the next SSE\r\n// chunk. Callers should keep calling Get until it returns io.EOF.\r\nfunc (s *Streamer) Get() (*ChatCompletion, error) {\r\n\tif s.eof {\r\n\t\treturn nil, io.EOF\r\n\t}\r\n\r\n\tprefix := []byte(\"data: \")\r\n\r\n\tvar buf []byte\r\n\r\n\tfor s.scanner.Scan() {\r\n\t\tif err := s.scanner.Err(); err != nil {\r\n\t\t\treturn nil, err\r\n\t\t}\r\n\r\n\t\tbuf = bytes.TrimSpace(s.scanner.Bytes())\r\n\r\n\t\tif len(buf) == 0 {\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tif bytes.HasPrefix(buf, prefix) {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\r\n\tbuf = bytes.TrimPrefix(buf, prefix)\r\n\r\n\tif bytes.Equal(buf, []byte(\"[DONE]\")) {\r\n\t\ts.resp.Body.Close()\r\n\t\ts.eof = true\r\n\t\treturn nil, io.EOF\r\n\t}\r\n\r\n\tvar completion ChatCompletion\r\n\r\n\tdecoder := json.NewDecoder(bytes.NewReader(buf))\r\n\tdecoder.DisallowUnknownFields()\r\n\r\n\tif err := decoder.Decode(\u0026completion); err != nil {\r\n\t\treturn nil, fmt.Errorf(\"decode completion chunk: %w: %s\", err, buf)\r\n\t}\r\n\r\n\ts.completion.Merge(\u0026completion)\r\n\r\n\treturn \u0026s.completion, nil\r\n}\r","start_line":1,"end_line":79,"total_lines":79,"truncated":false}
{"agent": "greg"}
Assigned to greg
{"body": "Assigned to **greg** (Senior Developer & Architect) since this is a code change task requiring technical expertise. The task involves removing `DisallowUnknownFields()` from the JSON decoder in `internal/llm/streamer.go` to improve compatibility with different LLM providers."}
Comment posted