fix(cli, llm, serve-web): Join split reasoning into one region - #919
Merged
Conversation
Anthropic interrupts a `thinking` block with an opaque `redacted_thinking` block and resumes the thinking in a third block, splitting one region of reasoning mid-word across three items. Each `thinking` block carries its own signature, and a `ConversationEvent` holds one signature field, so the three items cannot be merged upstream without dropping a signature and failing the next request's signature validation. Rendering previously treated every `ChatResponse` boundary as a block boundary, which broke this text apart on screen, in `jp c print` replay, and in the web viewer. Text-bearing responses (`Message`, `Reasoning`) now concatenate across consecutive events of the same kind, and the visual break between segments comes from blank lines in the stored content instead of from the response boundary. Discrete responses (`Structured`) are unaffected: each one still closes its `json` fence at the response boundary, since a JSON value cannot encode its own framing. Reasoning events are now persisted even when their text is empty, because the attached metadata (a redacted-thinking payload or a thinking signature) can be the only reason the event exists; dropping whitespace-only reasoning would lose that metadata. The web viewer's `render_events` gained a small buffer that accumulates consecutive text events of one kind before parsing them as markdown, so it stays consistent with the CLI's rendering. `jp_llm`'s `MultiProviderMetadata` now derives its `Map` conversion from `Serialize` instead of building the map by hand, since the struct fields already match the metadata keys one for one. Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
5 tasks
Signed-off-by: Jean Mertz <git@jeanmertz.com>
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.
Anthropic interrupts a
thinkingblock with an opaqueredacted_thinkingblock and resumes the thinking in a third block, splitting one region of reasoning mid-word across three items. Eachthinkingblock carries its own signature, and aConversationEventholds one signature field, so the three items cannot be merged upstream without dropping a signature and failing the next request's signature validation.Rendering previously treated every
ChatResponseboundary as a block boundary, which broke this text apart on screen, injp c printreplay, and in the web viewer. Text-bearing responses (Message,Reasoning) now concatenate across consecutive events of the same kind, and the visual break between segments comes from blank lines in the stored content instead of from the response boundary. Discrete responses (Structured) are unaffected: each one still closes itsjsonfence at the response boundary, since a JSON value cannot encode its own framing.Reasoning events are now persisted even when their text is empty, because the attached metadata (a redacted-thinking payload or a thinking signature) can be the only reason the event exists; dropping whitespace-only reasoning would lose that metadata. The web viewer's
render_eventsgained a small buffer that accumulates consecutive text events of one kind before parsing them as markdown, so it stays consistent with the CLI's rendering.jp_llm'sMultiProviderMetadatanow derives itsMapconversion fromSerializeinstead of building the map by hand, since the struct fields already match the metadata keys one for one.