Skip to content

Conversation streaming for the TUI#13057

Open
harryalbert wants to merge 20 commits into
masterfrom
harry/conversation-streaming-for-tui
Open

Conversation streaming for the TUI#13057
harryalbert wants to merge 20 commits into
masterfrom
harry/conversation-streaming-for-tui

Conversation

@harryalbert

@harryalbert harryalbert commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Description

This PR changes it so that the main cluster of conversation models (i.e. the BlocklistAIContextModel, BlocklistAIInputModel, BlocklistAIController, and BlocklistAIHistoryModel) necessary for conversation streaming and basic conversation management can be re-used by the TUI w/ no TUI or GUI specific code within said models (i.e. the models are not concerned w/ whether they are associated with a TUI or GUI surface).

Luckily enough, there's actually not much that needs to be changed within these models to get them working for the TUI and GUI in a surface-agnostic way. The major things that change are:

  • the models stop referencing a terminal_view_id: EntityId, replaced with terminal_surface_id: EntityId. This is where the majority of the LOC changed come from in this PR, and it should be a behavior no-op. Just want to make sure we're clear on our naming here.
  • the shared models no longer hold an AgentViewController, as this controller is GUI specific. What makes this a little tricky is that the AgentViewController was doing several jobs: it was telling the models whether an agent view was open or not, telling the models what conversation was currently selected, and emitting presentation lifecycle events consumed by the shared models. To handle these jobs, this PR adds an object-safe ConversationSelection abstraction that each surface implements and passes to the shared models behind a ConversationSelectionHandle. For GUI surfaces, AgentViewConversationSelection delegates presentation operations to AgentViewController and translates Agent View lifecycle events into events consumed by shared models. For TUI surfaces, TuiConversationSelection owns the pending conversation selection directly.

The history model also now distinguishes between transferring a conversation to a new terminal surface and simply marking an already-owned conversation as the active streaming target. This ensures automatic follow-ups don't accidentally transfer conversations between surfaces, while explicit transfers still clean up the previous renderer and selection.

Finally, this PR adds a one-shot --prompt runtime path to warp_tui, which streams a response directly back as output. I would just delete this as "testing code", but I actually think it's worthwhile to keep given our long-term plan of replacing the portion of the Oz CLI responsible for handling prompt submission with the TUI. The reusable conversation coordination lives in TuiConversationModel, while the one-shot stdout behavior lives in PromptStreamSurface.

This PR also adds a --conversation-id flag so that you can continue an existing conversation. This flag accepts a server conversation token, allowing the TUI to restore the corresponding conversation and test that follow-ups are WAI.

The TUI now uses the normal backing terminal server. To prevent this from recursively starting more TUI frontends, worker invocations are dispatched before TUI frontend arguments are parsed.

Reviewing this PR

A lot of this PR is no-op field name changes or simple call structure changes that aren't worth reading. The files worth digging into are:

  1. The tech spec for an over-arching tech implementation guide
    specs/conversation-streaming-for-tui/TECH.md

  2. The new ConversationSelection abstraction and its GUI/TUI implementations
    app/src/ai/blocklist/conversation_selection.rs
    app/src/ai/blocklist/agent_view/conversation_selection.rs
    crates/warp_tui/src/conversation_selection.rs

  3. The existing models migrated onto that abstraction. These are skim-able IMO but worth looking at just to see how the abstractions introduced in this PR are used in action.
    app/src/ai/blocklist/context_model.rs
    app/src/ai/blocklist/input_model.rs
    app/src/ai/blocklist/controller.rs

  4. The history-model behavioral portions (again, skim-able)
    app/src/ai/blocklist/history_model.rs
    ◦ Do not read all of the changed lines sequentially; most are renames. Focus on:
    set_active_conversation_id
    mark_active_conversation_id
    restore_conversations
    ▪ clear/remove/delete behavior
    terminal_surface_id_for_conversation
    ConversationTransferredBetweenTerminalSurfaces
    BlocklistAIHistoryEvent::terminal_surface_id
    ◦ The important behavior is conversation transfer between surfaces and ensuring the previous renderer/selection is cleaned up.

  5. The TUI conversation model
    crates/warp_tui/src/conversation_model.rs

  6. The TUI presentation streaming adapter
    crates/warp_tui/src/prompt_stream.rs
    ◦ Focus on:
    ▪ model cluster construction
    ▪ retained surface/manager lifetimes
    ▪ stdout snapshot behavior
    ▪ tool-action failure behavior
    ▪ final-status and error termination

  7. The bug fix around preventing a fork bomb while allowing us to spin up a backing terminal server
    app/src/lib.rs
    app/src/tui.rs
    crates/warp_tui/src/lib.rs
    crates/warp_cli/src/lib.rsis_worker_invocation
    crates/warp_tui/tests/worker_dispatch.rs

Testing

  • I have manually tested my changes locally with ./script/run

Screenshots / Videos

https://www.loom.com/share/2ecdc7fa6ee54bcab0b4183a237d12af

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

@cla-bot cla-bot Bot added the cla-signed label Jun 25, 2026

harryalbert commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@harryalbert harryalbert force-pushed the harry/conversation-streaming-for-tui branch from 3cb8802 to 44f7640 Compare June 26, 2026 02:13
@harryalbert harryalbert force-pushed the harry/conversation-streaming-for-tui branch from 44f7640 to 9f5a53d Compare June 26, 2026 13:23
@harryalbert harryalbert force-pushed the harry/conversation-streaming-for-tui branch from 863eeae to 5953228 Compare June 26, 2026 14:43
@harryalbert harryalbert force-pushed the harry/conversation-streaming-for-tui branch from 5953228 to d9b26c6 Compare June 26, 2026 14:46
@harryalbert harryalbert marked this pull request as ready for review June 26, 2026 14:46
@harryalbert harryalbert requested a review from kevinyang372 June 26, 2026 14:46
@oz-for-oss

oz-for-oss Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

@harryalbert

I'm starting a first review of this pull request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@harryalbert harryalbert changed the title add tech spec Conversation streaming for the TUI Jun 26, 2026

@oz-for-oss oz-for-oss Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR refactors the Blocklist AI conversation models around terminal-surface-scoped selection/history, adds a TUI conversation coordinator, and introduces one-shot warp_tui --prompt streaming with worker-dispatch support.

Concerns

  • The TUI prompt stream treats every status other than InProgress as terminal success, which can prematurely stop transient recovery, waiting, blocked, error, and cancellation states while returning a successful CLI exit.
  • This is a user-facing TUI behavior change, but the PR description does not include screenshots or a screen recording. For this user-facing change, please include screenshots or a screen recording demonstrating it working end to end.

Verdict

Found: 0 critical, 2 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread crates/warp_tui/src/prompt_stream.rs Outdated
update: ConversationStatusUpdate::Changed { .. },
} => {
self.print_stream_snapshot(*conversation_id, ctx);
if !status.is_in_progress() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] !status.is_in_progress() treats TransientError, WaitingForEvents, and Blocked as final and terminates with None, so retries/waits/tool-blocked/error states can be cut off while the CLI exits successfully; gate completion on terminal statuses and surface non-success statuses as errors.

Comment thread crates/warp_tui/src/conversation_model.rs
Comment thread app/src/ai/blocklist/conversation_selection_model.rs Outdated
@harryalbert harryalbert requested a review from kevinyang372 June 26, 2026 20:22
@harryalbert harryalbert mentioned this pull request Jun 26, 2026
4 tasks
Comment thread app/src/ai/blocklist/conversation_selection.rs Outdated
Comment thread app/src/ai/blocklist/conversation_selection.rs Outdated
Comment thread app/src/ai/blocklist/conversation_selection.rs Outdated
Comment thread app/src/ai/blocklist/agent_view/conversation_selection.rs Outdated
Comment thread app/src/ai/blocklist/conversation_selection.rs Outdated
Comment thread crates/warp_tui/src/conversation_selection.rs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants