Repository navigation
Conversation
mattt
left a comment
There was a problem hiding this comment.
Thanks, @foxterm. Streaming the reasoning as it arrives makes sense, and it should come in before the answer. A few things before we can merge this:
swift format lintfails in CI onOllamaLanguageModel.swift(a missing line break at line 324, and line 332 is too long). Runningswift format --in-placeon the file should fix both.- Since reasoning now goes into
state.entriesbeforetoolRounds.record(completed:), aToolRoundLimitExceedederror would include the reasoning from the round that was rejected, which the error's documentation says it leaves out. I'd expectOllamaReasoningReplayTeststo catch this once CI gets past lint.AnthropicLanguageModelhandles this by savingstate.entriesat the start of each round and passing that copy torecord. .reasoning(.ollama(thinking))creates a new entry, with new IDs, for each chunk. Transcript entries should keep the same ID as they update, so that UIs can track them. Could you update the existing entry's text in place instead, and add a test with a few thinking chunks that checks for one entry with the same ID across snapshots?AnthropicReasoningTestshas a similar check.
…h unclosed on finalize
|
Thanks for the updates, @foxterm. This PR now does a few different things, so let's split it up to make each part easier to review. Could you bring this PR back to streaming Ollama reasoning? Two things from my earlier review are still open there: reasoning goes into The tool guidance message is something we can't take in the library. It changes what every Ollama request with tools sends, in one language, and apps can already add that kind of guidance in their own instructions. The llama.cpp thinking spans and the context size changes would be good as a separate PR. Those change defaults and add public API, so it'd help to have the reasoning for them in the PR description. What do you think? |
- Add LlamaPerformanceSnapshot with model size, parameter count, KV cache estimate, process footprint, available memory, tokens/s and GPU offload layers via llama_model_size/n_params/n_ctx/n_layer/n_embd - Measure process CPU via proc_pidinfo: host_cpu_load_info idle ticks never advance on Apple Silicon so it always reported 100% - Tighten runtime memory guard to max(estimate/4, 1GB) to prevent system memory compression stalls - Record tokens-per-second per generation under statsLock
Summary
OllamaLanguageModel.streamResponsebuffered the model'sthinkingchunks in a localvariable and only appended a
.reasoningtranscript entry after the chunk streamended. Snapshots were also only yielded for
content/usagechunks, so nothing wasemitted during the reasoning phase at all.
Consumers that render
snapshot.transcriptEntries(e.g. chat UIs showing the thinkingblock) therefore saw the answer stream in first, and the full reasoning text appear all
at once in the final snapshot — reasoning always arrived last, out of order.
Changes
thinkingpiece is accumulated into a singlecumulative
.reasoningentry per round, replaced as new pieces come in. This keeps thetranscript compact and preserves the original thinking text when replaying to Ollama.
thinkingchunks too, so reasoning streams progressively,before the answer.
path and the tool-round path).
Behavior
Responseis unchanged: reasoning still lands intranscriptEntriesbeforethe response / tool calls, and
collect()reaches the same end state.toOllamaMessages()replay is unchanged: one cumulative entry means the thinking textsent back to the model is exactly as before.
Testing
Built a downstream Swift package that depends on AnyLanguageModel via SPM
(Debug, macOS) — compiles cleanly.