Skip to content

test(llm, anthropic): Add tests for thinking block resend behavior#608

Merged
JeanMertz merged 7 commits into
mainfrom
prr176
May 6, 2026
Merged

test(llm, anthropic): Add tests for thinking block resend behavior#608
JeanMertz merged 7 commits into
mainfrom
prr176

Conversation

@JeanMertz
Copy link
Copy Markdown
Collaborator

Three new tests cover how prior reasoning events are re-serialized into Anthropic API requests during multi-turn conversations:

  • Signed thinking blocks are resent as native thinking content blocks with their original signature intact.
  • Redacted thinking blocks (carrying an REDACTED_THINKING_KEY payload) are resent as redacted_thinking content blocks.
  • Reasoning events without a signature fall back to wrapping the content in <think> tags inside a plain text block.

JeanMertz added 6 commits May 6, 2026 11:29
Three related rendering bugs are addressed in `TurnView` and the
`TurnCoordinator`:

1. **Unclosed structured fences.** A conversation ending on a
   `ChatResponse::Structured` would print an opening ` ```json ` with no
   matching close. `flush()` only drained the chat sub-renderer; the
   structured renderer was left open. Content boundaries (`begin_turn`,
   `render_user_request`, `render_chat_response`, `enter_tool_call`,
   `reconfigure`) now each call `structured.flush()` before proceeding,
   and the top-level `flush()` (formerly `flush_all()`) closes both
   renderers. The old `flush()` (chat-only) is removed; `flush_all()` is
   renamed to `flush()`.

2. **Missing assistant header after Continue-before-first-chunk.**
   `reset_for_continuation` unconditionally set
   `assistant_header_rendered = true`, so if the user interrupted before
   any chunk arrived the flag was forced on and the resumed output had
   no `── jp …` boundary. The flag is now left as-is; if no header had
   been emitted yet it stays `false` and the next assistant event
   renders one normally.

3. **Missing user header on Reply interrupt (live vs replay gap).** When
   the user replied mid-stream, the new `ChatRequest` was pushed to the
   conversation but never rendered in live mode, so the terminal showed
   no `── alice …` boundary. `coordinator.rs` now calls
   `view.render_user_request()` before pushing the event, matching what
   replay emits.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
When `build_execution_plan` encountered a `ToolCallRequest` with no
matching pending entry, it pushed the request into `orphaned` as a bare
`ToolCallRequest`. The caller in `turn_loop` then synthesized an error
response and assigned it an index of `approved.len() +
pre_resolved.len()` — effectively appending it at the end regardless of
where the request appeared in the stream.

Because `commit_tool_responses` sorts responses by index before
persisting them, this caused any orphaned response to land after all
non-orphaned responses, breaking document order in the stored
conversation.

The fix threads the document-order index through the orphaned path:
`orphaned` is now `Vec<(usize, ToolCallRequest)>` and
`build_execution_plan` populates the index from the same loop counter
used for `PlanItem`. The `turn_loop` destructs the pair and uses the
carried index directly when building the `pre_resolved` entry, removing
the incorrect append-to-end calculation entirely.

Also removes two stale references to internal Bear notes from code
comments.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
The Bear note attachment handler previously required the full
`bear://get/NOTE_ID` URI form. This adds support for the opaque
shorthand `bear:NOTE_ID`, where no authority (`//`) is present and the
note ID is taken directly from the path.

This mirrors the shorthand pattern already used by the GitHub attachment
handler, and makes it quicker to attach a note when you have the ID at
hand:

    jp attachment add "bear:2356A6D7-49D7-4818-8E37-3E02D1B95146"

Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
`detect_default_user_name` previously ran `git config --get user.name`
without a scope flag, meaning a repo-local override could be picked up
and written into the user-global JP config, where it would then be
inherited by every future workspace — leaking an unrelated identity.

The cascade now tries `git config --global --get user.name` first, then
falls back to the unscoped lookup for users who only have a repo-local
identity, and finally falls through to the `$USER`/`$USERNAME`
environment variable as before.

The name prompt also switches from `with_default()` to
`with_initial_value()`, so the detected name is pre-filled and editable
rather than silently substituted on empty submission. This lets users
clear the field and submit empty to skip attribution, which the previous
behaviour made impossible without typing a space first.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
AsciiDoctor-generated pages (notably git's manpages on git-scm.com) use
`<dl><dt>/<dd>` definition lists for glossary-style content rather than
headings. Each `<dt>` carries an anchor ID — sometimes on the element
itself, sometimes via a child `<a id="...">` — making it a valid
navigation target.

The HTML section fetcher previously only treated headings as section
roots. Anchor extraction would either fall through to a heading ancestor
(losing the specific term) or return nothing at all.

This change extends both `list_section_headers` and
`extract_section_html_from_doc` to handle `<dt>` elements. Terms are
listed one level below their enclosing heading, and anchor extraction
returns just the `<dt>` plus its associated `<dd>` siblings wrapped in a
fresh `<dl>`.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
Three new tests cover how prior reasoning events are re-serialized into
Anthropic API requests during multi-turn conversations:

- Signed thinking blocks are resent as native `thinking` content blocks
  with their original signature intact.
- Redacted thinking blocks (carrying an `REDACTED_THINKING_KEY` payload)
  are resent as `redacted_thinking` content blocks.
- Reasoning events without a signature fall back to wrapping the content
  in `<think>` tags inside a plain text block.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
@JeanMertz JeanMertz changed the base branch from prr175 to main May 6, 2026 13:19
@JeanMertz JeanMertz merged commit 86a76eb into main May 6, 2026
13 checks passed
@JeanMertz JeanMertz deleted the prr176 branch May 6, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant