feat: /sessions expand subcommand with context window (F4 UX, Task 2.6.4) #15

Open
opened 2026-04-24 11:07:14 +02:00 by product-owner · 0 comments

Problem Statement

The session-search spec UX example (F4 Interactive Mode) shows:

> /sessions expand 1 --context 5
[Expands session 1 with 5 messages of context]

Today SessionsSubcommand has Show { session_id } which dumps the full session, but no Expand variant that:

  1. Accepts a rank index from the last search (1) or a session-id
  2. Takes --context N to show N surrounding messages around the match
  3. Formats the match itself with highlighting

This is the canonical AI-agent flow after a robot-mode search: "show me result #1 with surrounding context". Without it, agents must re-fetch the full session and slice it themselves, defeating the purpose of a tight token budget.

Upstream: spec section "User Experience / Interactive Mode", Phase 2 Task 2.6.4.

Acceptance Criteria

  • Add SessionsSubcommand::Expand { target: String, context: Option<usize>, highlight: bool }
    • target accepts either a UUID, a short hash prefix, or a #N rank from the last search
    • context defaults to 3, max 20
  • Track last search results in ReplState (ring buffer of last N search responses keyed by rank index)
  • In robot mode, produce RobotResponse { data: { session_id, matches: [{ message_id, role, content, timestamp, is_match }], context_before: N, context_after: N } }
  • In interactive mode, print a bordered block with the match message highlighted and context messages dimmed
  • Error: #N with no prior search returns ExitCode::ERROR_USAGE; unknown id returns ExitCode::ERROR_NOT_FOUND
  • Unit tests for target resolution (uuid / prefix / rank)
  • Integration test exercising search then expand
  • cargo test -p terraphim_agent --features repl-sessions passes
  • cargo clippy -p terraphim_agent --features repl-sessions -- -D warnings passes

Proposed Approach

  • Crates touched: terraphim_agent only (commands.rs, handler.rs, repl state)
  • Extend search handler to record last search hits in a bounded ring buffer bound to the REPL session
  • Add a lookup helper resolve_expand_target(&self, target: &str) returning (SessionId, Option<MessageId>)
  • Reuse existing SessionService::get_session and Session::messages

Dependencies

  • Blocks none directly, but is a sibling of #12 (/sessions path) for shared "last results" memory
  • No hard dependencies; can ship independently of Tantivy (#5)

Verification

cargo test -p terraphim_agent --features repl-sessions expand
cargo clippy -p terraphim_agent --features repl-sessions -- -D warnings
./target/debug/terraphim-agent --robot sessions search "async database" --max-results 3
./target/debug/terraphim-agent --robot sessions expand 1 --context 5

Scope

Single PR. ~250-350 lines across parser + handler + state + tests.

## Problem Statement The session-search spec UX example (F4 Interactive Mode) shows: ``` > /sessions expand 1 --context 5 [Expands session 1 with 5 messages of context] ``` Today `SessionsSubcommand` has `Show { session_id }` which dumps the full session, but no `Expand` variant that: 1. Accepts a **rank index from the last search** (`1`) or a session-id 2. Takes `--context N` to show N surrounding messages around the match 3. Formats the match itself with highlighting This is the canonical AI-agent flow after a robot-mode search: "show me result #1 with surrounding context". Without it, agents must re-fetch the full session and slice it themselves, defeating the purpose of a tight token budget. Upstream: spec section "User Experience / Interactive Mode", Phase 2 Task 2.6.4. ## Acceptance Criteria - [ ] Add `SessionsSubcommand::Expand { target: String, context: Option<usize>, highlight: bool }` - `target` accepts either a UUID, a short hash prefix, or a `#N` rank from the last search - `context` defaults to 3, max 20 - [ ] Track last search results in `ReplState` (ring buffer of last N search responses keyed by rank index) - [ ] In robot mode, produce `RobotResponse { data: { session_id, matches: [{ message_id, role, content, timestamp, is_match }], context_before: N, context_after: N } }` - [ ] In interactive mode, print a bordered block with the match message highlighted and context messages dimmed - [ ] Error: `#N` with no prior search returns `ExitCode::ERROR_USAGE`; unknown id returns `ExitCode::ERROR_NOT_FOUND` - [ ] Unit tests for target resolution (uuid / prefix / rank) - [ ] Integration test exercising search then expand - [ ] `cargo test -p terraphim_agent --features repl-sessions` passes - [ ] `cargo clippy -p terraphim_agent --features repl-sessions -- -D warnings` passes ## Proposed Approach - Crates touched: `terraphim_agent` only (commands.rs, handler.rs, repl state) - Extend search handler to record last search hits in a bounded ring buffer bound to the REPL session - Add a lookup helper `resolve_expand_target(&self, target: &str)` returning `(SessionId, Option<MessageId>)` - Reuse existing `SessionService::get_session` and `Session::messages` ## Dependencies - Blocks none directly, but is a sibling of #12 (/sessions path) for shared "last results" memory - No hard dependencies; can ship independently of Tantivy (#5) ## Verification ``` cargo test -p terraphim_agent --features repl-sessions expand cargo clippy -p terraphim_agent --features repl-sessions -- -D warnings ./target/debug/terraphim-agent --robot sessions search "async database" --max-results 3 ./target/debug/terraphim-agent --robot sessions expand 1 --context 5 ``` ## Scope Single PR. ~250-350 lines across parser + handler + state + tests.
Sign in to join this conversation.