Files
ironclaw/crates
firat.sertgoz 141435eb0b feat(gateway): expose engine v2 threads in chat history and sidebar (#2532)
* feat(gateway): expose engine v2 threads in chat history and sidebar

Engine v2 threads weren't appearing in the gateway sidebar and
deep-linking to one by id (`#/chat/<engine-thread-id>`) returned an
empty history because the v1 `assistant` flow dual-writes into the
single assistant conversation id, not the engine thread id.

Three coordinated fixes:

- `chat_history_handler`: extend the ownership check with an engine v2
  lookup so an engine thread id is recognized, then fall back to
  loading messages via `bridge::get_engine_thread` when the v1
  conversation table has nothing.
- `chat_threads_handler`: merge engine threads from
  `bridge::list_engine_threads` into the sidebar, label them with
  their goal, and re-sort by `updated_at`. Bump the v1 conversation
  cap from 50 to 500 so older threads stop silently aging off the
  sidebar.
- Gateway frontend (`app.js`): when restoring from `#/chat/<id>` on
  load, switch even if the id is not in the loaded sidebar list — the
  history endpoint resolves it via the DB. Log a warning instead of
  silently dropping the URL.

Cherry-picked from 8df22ab2 (feat/skills-engine-fixes), adapted to
staging where chat_history_handler and chat_threads_handler still live
in both server.rs and handlers/chat.rs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(gateway): address v2 history review comments

* test(gateway): caller-level coverage for v2 thread ownership + history

Adds tests exercising chat_history_handler through the three ownership
branches the PR introduces, and two HTTP-driven e2e scenarios against
an ENGINE_V2=true server. Fills the caller-level coverage gap flagged
in review.

- Rust caller-level tests on chat_history_handler:
  - v2-owned: engine thread owned by user returns synthesized history
  - cross-user: alice can't read bob's engine thread (404)
  - session-only: in-memory session-owned thread returns 200 without DB
- Playwright e2e under ENGINE_V2=true:
  - engine-only thread appears in sidebar with channel=engine
  - deep-link by engine thread id returns synthesized turns

Exposes a minimal bridge::test_support module (ThreadTestStore,
install_engine_state_with_threads, clear_engine_state, shared test
lock) so cross-module tests can seed ENGINE_STATE without the weight
of the bridge's own full-featured TestStore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(ci): align with staging EngineState fields and clippy rules

- `EngineState` on staging now has `extension_manager` and `project_root`
  fields (added in #2549 and the attachments flow). Update the test-only
  `install_engine_state_with_threads` helper to populate them.
- Rewrite the `let Some(...) else { return None }` in
  `engine_history_entry_to_message` as a `?` — clippy::question_mark is
  denied on staging's all-features CI.
- Add missing `AuthenticatedUser` + `Query` imports to the server.rs
  test module for the `history_request` helper.
- `cargo fmt` on the 500-error test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Illia Polosukhin <ilblackdragon@gmail.com>
2026-04-20 12:57:27 +09:00
..