Files
zerogravity/docs/panel-stream-investigation.md
Nikketryhard 940786c57f docs: update standalone LS, MITM, and panel stream investigation
- Add panel-stream-investigation.md documenting dead end
- Update KNOWN_ISSUES: move polling and panel stream to resolved
- Update GEMINI.md with standalone LS section and new MITM setup
- Fix standalone-ls-todo to reflect default mode
2026-02-14 21:40:35 -06:00

3.0 KiB

Panel Stream Investigation — Dead End

Summary

Investigated StreamCascadePanelReactiveUpdates RPC as a potential source for progressive thinking text. Result: dead end. The panel state only contains UI metadata (plan_status, user_settings), not thinking content.

What We Tried

1. Subscribe with Cascade ID

Attempted to subscribe to StreamCascadePanelReactiveUpdates using the cascade ID as the reactive component identifier:

{ "protocolVersion": 1, "id": "<cascade-id>" }

Result: "reactive component <cascade-id> not found"

2. Retry with Delays

Added retry logic (3 attempts, 500ms/1s/1.5s delays) to handle the possibility that the panel state is created asynchronously after cascade start.

Result: Same error on all attempts. The panel state uses a different identifier than the cascade ID.

3. InitializeCascadePanelState Analysis

Examined the RPC that creates panel state:

await this.client.initializeCascadePanelState({ metadata: e, userStatus: t });

Takes workspace metadata + user status, not cascade ID. Panel state is workspace-scoped, not cascade-scoped.

CascadePanelState Proto Definition

exa.cortex_pb.CascadePanelState:
  field 1: plan_status  (PlanStatus)
  field 2: user_settings (UserSettings)

Only 2 fields — neither contains thinking text.

Where Thinking Text Actually Lives

Thinking text flows through StreamCascadeReactiveUpdates (the cascade reactive diffs that we already subscribe to):

CascadeState (jetski_cortex_pb)
  └─ field 2: trajectory (gemini_coder.Trajectory)
       └─ field 2: steps[] (gemini_coder.Step)
            └─ field 20: planner_response (CortexStepPlannerResponse)
                 ├─ field 1: response (string — streams progressively)
                 ├─ field 3: thinking (string — raw thinking text)
                 ├─ field 8: modified_response (string)
                 └─ field 11: thinking_duration (Duration)

Observed Behavior (gemini-3-flash)

  • Thinking text arrives as a single atomic diff (341 chars, one shot)
  • Response text streams progressively across many diffs (26 → 1796 chars)
  • Total diffs per request: ~20

Current Proxy Approach

The proxy already captures thinking text correctly through polling GetCascadeTrajectory + extract_thinking_content(). No reactive diff parsing needed for current functionality.

Future: Progressive Thinking for Extended-Thinking Models

For Opus models with extended thinking, the thinking text might arrive progressively across multiple reactive diffs. If needed:

  1. Parse reactive diff JSON for field 3 changes within field 20
  2. Diff the thinking text between updates for incremental deltas
  3. Emit response.reasoning_summary_text.delta events as thinking grows

Cleanup

  • Removed stream_cascade_panel_updates() from backend.rs
  • Removed panel stream subscription + retry code from responses.rs
  • StreamCascadeReactiveUpdates (cascade diffs) is still used for real-time notification of state changes (with polling as fallback)