Skip to content

feat(tui): read-only Next Research page over session search and fetch (#414) - #434

Open
BunsDev wants to merge 4 commits into
feat/413-work-viewfrom
feat/414-research-view
Open

BunsDev wants to merge 4 commits into
feat/413-work-viewfrom
feat/414-research-view

Conversation

@BunsDev

@BunsDev BunsDev commented Nov 1, 2026

Copy link
Copy Markdown
Member

Context

Implementation

  • Projection (crates/tui/src/application/research.rs): pairs each assistant WebSearch/WebFetch call with its result by tool-use id, in call order. It takes one linear pass over the results.
    • The outcome is one of five:
      • returned
      • failed, with the HTTP status when the error has one
      • pending, only while the call is in the newest message
      • interrupted
      • no result recorded, when a later message exists. The engine never adds a result for a call that never finished.
    • URLs are shown without user info, query or fragment, for any scheme. A backslash ends the host, as it does for the HTTP client. Failed-fetch errors have every scheme:// token redacted the same way, and they are redacted before they are shortened.
    • Search hits are parsed only from the numbered N. **title** / URL: form, and every hit is labelled "parsed, unverified". A returned search with no parsed hits, such as DuckDuckGo's format or "No results found.", says "none parsed (output format not recognised)".
    • All source text is terminal-safe, with newlines removed. Fetch bodies are never copied.
  • Inspector: a Research page between Work and Views. Its header always shows "tool calls: not a research job" and "unavailable: research jobs ([TUI v2][P1] T7: add a native research workbench with source provenance, citations, and resumable artifacts #414)". Each row shows its reference. It also shows "Retrieved: unknown time, final URL and content hash (WebFetch: stale cache returned after a live fetch, UTF-8 slicing panics, and missing fetch restrictions #433)" and, for a returned fetch, "may be cached or model-extracted (WebFetch: stale cache returned after a live fetch, UTF-8 slicing panics, and missing fetch restrictions #433)". The Views entry for Research now reads "local only".
  • User-visible behavior: Next only. Alt+I, then Tab to Research. Classic is unchanged.
  • Compatibility notes: no storage, protocol or command changes.

Verification

  • cargo fmt --all --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace: 2898 passed, 0 failed, 52 ignored
  • n/a python3 scripts/check-secrets.py: this repository has no such script. The diff adds no credentials, tokens or private paths.
  • Additional manual checks: every new test was seen failing first. Coverage:
    • projection: 12 tests
    • Next render: 12 tests, at 80x50, 80x24, 120x50, 160x30, 40x12, 20x6 and 1x1
    • next_shell: 18 tests, still passing

Independent review

A fresh reviewer read c9dc1c2. Verdict: ready after fixes. Resolved in ef93e74:

Finding Resolution
High: a failed fetch's error showed the raw URL with credentials and query Every URL in error text is shown in display form, redacted before it is shortened, so a cut can't land inside the user info. Unit and render tests added.
A backslash in the authority could spoof the shown host A backslash ends the host
An unfinished call read "pending" forever once the next turn started New "no result recorded" state when a later message exists
A search in an unparsed format looked like an empty search "none parsed (output format not recognised)"
Non-http schemes showed credentials User info and query are stripped for every scheme
Every fetch body was cloned each frame Results are borrowed; only search text and errors are read
At 40x12 the header hid every row Scope notes are shortened to fit 40 columns, with a content test
"Cannot add a hit" and "one row" overclaimed Doc wording corrected; hits stay labelled unverified
A tool use in a user message was listed Assistant messages only

Risk and Rollback

  • Risk level: low. The change is display only, behind the Next renderer, and computed only while the Research page is open.
  • Rollback plan: revert this PR. No data or format migrates.

…#414)

The first T7 slice. The engine has no research job, source store or
citation producer, so this shows this session's WebSearch and WebFetch
calls from the transcript and claims nothing beyond them.

- application::research pairs each search or fetch tool call with its
  result by tool-use id, indexing results once so long transcripts stay
  linear. A call is returned, failed (one row, with the HTTP status a
  fetch error reports), pending, or interrupted (from the loop's
  interrupted tools).
- Search hits are parsed only from the numbered "N. **title**" line
  directly followed by "URL:"; any other URL line, including one inside
  a snippet, is not a hit. Hits are labeled "parsed, unverified", and
  duplicates are kept.
- URLs are displayed without credentials, query or fragment, which can
  carry secrets. All source text is terminal-safe, kept to one row, and
  never interpreted.
- The inspector gains a Research page after Work. Its header says the
  rows are tool activity, not a research job, and that jobs, citations
  and export need a research producer. Each row shows retrieval time,
  final URL and content hash as unknown, and a returned fetch as
  possibly cached or model-extracted, pointing at #433. The Views entry
  for Research reads "local only".

Tests (seen failing first against a stub): projection unit tests for
pairing and order, hit parsing, failure, pending and interrupted
states, URL redaction, hostile text and fake URL lines; Next render
tests for content, redaction, scope notes under scrolling, no
"verified" claim, empty and interrupted states, the Views entry and
40x12, 20x6 and 1x1 rendering.
…nding (#414)

- Failed fetch errors carry the raw URL; every scheme:// token is now shown
  in display form, redacted before the text is shortened.
- A backslash ends the host, as it does for the HTTP client.
- Credentials and query are stripped for every scheme, not only http(s).
- A call with no result and a later message reads "no result recorded".
- A returned search with no parsed hits says the format was not recognised.
- Only assistant tool uses are listed; fetch bodies are no longer copied.
- Scope notes fit 40 columns so rows stay visible at 40x12.
@vercel

vercel Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Nov 2, 2026 6:51am UTC

Request Review

This branch was successfully deployed

1 active deployment
Preview — ddfc627c Deployed Nov 2, 2026 by vercel[bot]
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