diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-23 08:33:07 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-23 08:33:07 +0200 |
| commit | 56c2c4f64ba1712f7cab28a8dc92a3c14b20eb1d (patch) | |
| tree | 4088f6ceddbfdea3877cd7c7343397a8b0e78d36 /internal/llm | |
| parent | 3ea11bc5d671d962d01b57fa0fba0bda611025fe (diff) | |
refactor: split oversized functions, fix double logging, add %w wrapping
- lsp/handlers_completion.go: extract buildNativeCompletionCacheKey and
postProcessNativeCompletion; track collectFirstCompletion in inflight;
remove redundant logLLMStats("") on error path
- lsp/handlers.go: extract checkTriggerFromContext and
checkTriggerFromCursorChar; isTriggerEvent reduced from 63→10 lines
- lsp/transport.go: use %w for error wrapping in Content-Length parse
- llm/ollama.go: extract parseOllamaStream; ChatStream reduced to ~35 lines
- appconfig/config_load.go: extract decodeModelEntryFromMap; rename 'any'
to 'found'; decodeModelEntry reduced to ~18 lines
- llm/provider.go: document why providerRegistry is package-level
- integrationtests/ask_test.go: add //go:build integration; move repoRoot
init from init() to TestMain with diagnostic message
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/llm')
| -rw-r--r-- | internal/llm/ollama.go | 52 |
1 files changed, 31 insertions, 21 deletions
diff --git a/internal/llm/ollama.go b/internal/llm/ollama.go index be93ab0..e212466 100644 --- a/internal/llm/ollama.go +++ b/internal/llm/ollama.go @@ -133,7 +133,35 @@ func (c ollamaClient) Chat(ctx context.Context, messages []Message, opts ...Requ func (c ollamaClient) Name() string { return "ollama" } func (c ollamaClient) DefaultModel() string { return c.defaultModel } -// Streaming support (optional) +// parseOllamaStream reads NDJSON streaming events from dec, calling onDelta for each +// non-empty content delta. Returns an error if decoding fails or the server signals +// an error event; returns nil when the done flag is received or the stream ends. +func parseOllamaStream(dec *json.Decoder, start time.Time, onDelta func(string)) error { + for { + var ev ollamaChatResponse + if err := dec.Decode(&ev); err != nil { + if errors.Is(err, io.EOF) { + break + } + logging.Logf("llm/ollama ", "%sdecode stream error after %s: %v%s", logging.AnsiRed, time.Since(start), err, logging.AnsiBase) + return err + } + if strings.TrimSpace(ev.Error) != "" { + logging.Logf("llm/ollama ", "%sstream event error: %s%s", logging.AnsiRed, ev.Error, logging.AnsiBase) + return fmt.Errorf("ollama stream error: %s", ev.Error) + } + if s := ev.Message.Content; strings.TrimSpace(s) != "" { + onDelta(s) + } + if ev.Done { + break + } + } + return nil +} + +// ChatStream sends a streaming chat request to Ollama, calling onDelta for each +// received content delta. It blocks until the stream ends or an error occurs. func (c ollamaClient) ChatStream(ctx context.Context, messages []Message, onDelta func(string), opts ...RequestOption) error { o := Options{Model: c.defaultModel} for _, opt := range opts { @@ -167,26 +195,8 @@ func (c ollamaClient) ChatStream(ctx context.Context, messages []Message, onDelt return err } - dec := json.NewDecoder(resp.Body) - for { - var ev ollamaChatResponse - if err := dec.Decode(&ev); err != nil { - if errors.Is(err, io.EOF) { - break - } - logging.Logf("llm/ollama ", "%sdecode stream error after %s: %v%s", logging.AnsiRed, time.Since(start), err, logging.AnsiBase) - return err - } - if strings.TrimSpace(ev.Error) != "" { - logging.Logf("llm/ollama ", "%sstream event error: %s%s", logging.AnsiRed, ev.Error, logging.AnsiBase) - return fmt.Errorf("ollama stream error: %s", ev.Error) - } - if s := ev.Message.Content; strings.TrimSpace(s) != "" { - onDelta(s) - } - if ev.Done { - break - } + if err := parseOllamaStream(json.NewDecoder(resp.Body), start, onDelta); err != nil { + return err } logging.Logf("llm/ollama ", "stream end duration=%s", time.Since(start)) return nil |
