Repository navigation
feat(json): assemble a streamed chat completion into the non-streaming answer - #595
Merged
Merged
Conversation
…g answer json.ChatStreamAssembler turns an OpenAI streaming chat completion back into the answer of the same request without `stream`: from a Server-Sent Events body (parseStream / acceptLine) or from the chunk strings LlamaModel.streamChatCompletion hands its sink (acceptChunk). Per choice it joins content and reasoning_content, rebuilds the tool calls and keeps the last finish reason; of the stream it keeps the first id/created/model and the last usage and timings. A data line that is not JSON, an error chunk and a body without `data: [DONE]` throw InvalidStreamException instead of passing for a short answer. ToolCallDeltaAccumulator moves from `server` to `json` and becomes public, so the server's protocol translators and the assembler share one implementation. Tests: unit tests (PIT 50/50, added to the gate), the server's own SSE stream assembled against its non-streaming answer (FakeBackend, with and without heartbeats), and Qwen3-0.6B greedy: streamed and not streamed give the same text, reasoning, finish reason and token counts. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01DuAkLtHrCTx81vP5Mt4jad
|
bernardladenthin
added a commit
to bernardladenthin/srcmorph
that referenced
this pull request
Oct 29, 2026
…treamAssembler `OpenAiCompatibleProviderSupport.assembleStream` and its constants copy what java-llama.cpp ships as `json.ChatStreamAssembler` (bernardladenthin/java-llama.cpp#595), which is in no release yet. The new marker annotation `support.ReplaceWithLibrary` names the library class and the release expected to carry it. `ReplaceWithLibraryTest` fails as soon as that class is on the classpath, i.e. when net.ladenthin:llama is raised to that release, and lists the marked elements. It also fails once no marker is left, so the annotation and the test are deleted with the last copy. TODO.md describes the switch. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01DuAkLtHrCTx81vP5Mt4jad
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
json.ChatStreamAssembler. It turns an OpenAI streaming chat completion back into the answer the same request gives withoutstream.parseStream, or line by line withacceptLine) or the chunk stringsLlamaModel.streamChatCompletionhands its sink (acceptChunk).contentandreasoning_content, rebuilds the tool calls and keeps the last finish reason. From the stream as a whole it keeps the firstid/created/modeland the lastusageandtimings.ChatResponseParser(toResponse) or comes back as the non-streaming JSON (toCompletionJson).errorchunk, or a body withoutdata: [DONE]throwsInvalidStreamException. Heartbeat comments and the other SSE fields are skipped.ToolCallDeltaAccumulatormoves fromservertojsonand becomes public. The server's protocol translators (Ollama, Anthropic, Responses) and the assembler now share one implementation. The SpotBugs exclusion moves with it.Test plan
jllama.dll): 210 tests acrossChatStreamAssemblerTest(22),ToolCallDeltaAccumulatorTest,OpenAiCompatServerHttpTest,OllamaApiSupportTest, the two stream translators,LlamaArchitectureTestandOpenAiCompatServerIntegrationTest.FakeBackend, with and without heartbeats).aStreamedChatAssemblesIntoTheNonStreamedAnswer).ChatStreamAssembleradded to the gate, 50/50 mutations killed.mvn -pl llama verify -DskipTests: SpotBugs, Javadoc and the other static checks pass.Related issues / PRs
Refs bernardladenthin/srcmorph#257. srcmorph can switch to this class once a jllama release contains it.
Checklist
CONTRIBUTING.mdandCODE_OF_CONDUCT.mdSECURITY.md)🤖 Generated with Claude Code
https://claude.ai/code/session_01DuAkLtHrCTx81vP5Mt4jad
Summary by CodeRabbit