Skip to content

feat(agent_panel): unified agent panel 2c — composer routing + live daemon source#210

Merged
BunsDev merged 5 commits into
mainfrom
feat/unified-agent-panel-2c
Jul 18, 2026
Merged

feat(agent_panel): unified agent panel 2c — composer routing + live daemon source#210
BunsDev merged 5 commits into
mainfrom
feat/unified-agent-panel-2c

Conversation

@BunsDev

@BunsDev BunsDev commented Jul 18, 2026

Copy link
Copy Markdown
Member

Description

What: Implements sub-phase 2c of the unified agent panel (plan in #207) — the composer now routes by conversation backend, and live Coven-daemon sessions populate the merged list. Builds on 2a (#205) + 2b (#209, merged).

Why: 2b gave the unified panel a working shell with the CLI composer. 2c makes the daemon side live: selecting a daemon conversation lets you send to it, and the reply streams back into the same agent_transcript transcript.

How:

  • ConversationBinding::LiveDaemon — a daemon conversation selected for input (no terminal; sends go through cast_agent). OpenChatSession routes by backend: daemon → bind_daemon, CLI → bind_past.
  • ChatModel::append_entry — a direct entry-append path (daemon events aren't CLIAgentEvents, so they can't go through apply_event), assigning sequence, persisting, and emitting.
  • ChatModel::refresh_daemon_conversations — upsert a Daemon conversation per live CovenSession; seeded at panel construction from ::ai::cast_agent::sessions() (alongside 2a's migrated history).
  • Composer routing — new WorkspaceAction::SubmitAgentPrompt (the unified composer now dispatches this): a live CLI binding → terminal PTY; a LiveDaemon binding → append the user prompt, then AgentPanelView::start_daemon_turn launches stream_agent_events and a 100ms UI poll drains events → daemon_event_to_entryappend_entry. Mirrors the shipped ai_assistant panel's spawn/buffer/poll pattern. Composer is enabled for LiveDaemon only when the runtime is reachable (composer_is_active_for).

Prompt delivery (resolved): stream_agent_events carries the prompt in the POST /api/v1/sessions launch body (launchMode:"stream") — no stdin user-frame. Each submit is one launch (session-per-turn); multi-turn daemon context continuity is out of scope.

Gating: the daemon streaming is cfg(all(feature = "cast-agent", unix)) (the daemon transport is a unix socket).

Linked Issue

Implements the 2c plan (#207). Continues the reconciliation roadmap (design #204; 2a #205; 2b #209; Phase 1 #201).

Testing

  • cargo nextest run -p warp-app --features cast-agent46 pass: new unit tests for LiveDaemon binding, append_entry sequencing + unknown-conversation no-op, refresh_daemon_conversations idempotency, daemon_turn message-build + event→entry mapping, and the composer_is_active_for predicate — plus the full pre-existing cli_chat/agent_panel/agent_transcript suites unchanged.
  • cargo check -p warp-app --bin cast-codes --features gui,cast-agent links.
  • cargo clippy -p warp-app --features cast-agent --all-targets -- -D warnings clean; cargo fmt -- --check clean.
  • ./script/check_cli_chat_boundary, ./script/check_ai_attribution, ./script/check_rebrand pass.
  • Live daemon end-to-end not run here — the streaming consumer mirrors the shipped ai_assistant path and is exercised by crates/cast_agent's in-process daemon stub; a live coven-code turn wants manual verification with ./script/run + a running daemon.

Agent Mode

@BunsDev
BunsDev marked this pull request as ready for review July 18, 2026 08:33
Copilot AI review requested due to automatic review settings July 18, 2026 08:33

Copilot AI 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.

Pull request overview

Implements unified agent panel sub-phase 2c by routing the composer based on the selected conversation backend and wiring live Coven-daemon sessions into the merged conversation list + transcript pipeline, so daemon turns stream back into the shared agent_transcript model.

Changes:

  • Add ConversationBinding::LiveDaemon and route OpenChatSession + unified composer submits by backend (CLI → terminal PTY, daemon → cast_agent stream).
  • Extend ChatModel with a direct append_entry path and daemon-session upsert (refresh_daemon_conversations) to support non-CLI event sources.
  • Implement daemon turn plumbing (daemon_turn) plus an async spawn/buffer/100ms UI-poll drain loop in AgentPanelView.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
app/src/workspace/view.rs Routes OpenChatSession and adds SubmitAgentPrompt handling for CLI PTY vs daemon streaming.
app/src/workspace/action.rs Adds WorkspaceAction::SubmitAgentPrompt and marks it non-background.
app/src/cli_chat/view/transcript.rs Allows transcript rendering for LiveDaemon bindings.
app/src/cli_chat/view/model_picker.rs Allows model label resolution for LiveDaemon bindings.
app/src/cli_chat/model.rs Adds daemon binding + direct entry append + live-daemon conversation refresh helpers.
app/src/cli_chat/model_tests.rs Adds unit tests for daemon binding, append sequencing/no-op, and refresh idempotency.
app/src/cli_chat/conversation.rs Introduces ConversationBinding::LiveDaemon.
app/src/agent_panel/view/transcript.rs Allows transcript rendering for LiveDaemon bindings.
app/src/agent_panel/view/header.rs Allows header label resolution for LiveDaemon bindings.
app/src/agent_panel/view/composer.rs Enables composer for LiveDaemon only when cast_agent is available.
app/src/agent_panel/view_tests.rs Adds unit test for the composer-active predicate.
app/src/agent_panel/mod.rs Seeds live daemon sessions; adds buffered daemon stream plumbing + polling drain into the model; composer dispatches SubmitAgentPrompt.
app/src/agent_panel/daemon_turn.rs New helper for building daemon messages and mapping daemon events into transcript entries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 7 to 11
//! 2b builds the view shell (merged list + transcript + composer shell). It
//! reuses the `cli_chat` model layer and the shared `agent_transcript`
//! renderer; per-backend composer routing + the live daemon source arrive in
//! 2c. The composer submits via the shared `WorkspaceAction::SubmitChatPrompt`
//! (live CLI only in 2b).
Comment thread app/src/workspace/view.rs
Comment on lines +20903 to +20926
let session_id = session_id.clone();
let text = text.clone();
// Show the user's prompt immediately, then stream the reply.
let sid = session_id.clone();
let prompt = text.clone();
crate::cli_chat::model::ChatModel::handle(ctx).update(ctx, |model, ctx| {
model.append_entry(
&sid,
crate::agent_transcript::entry::ChatEntry {
sequence: 0,
created_at: chrono::Utc::now(),
kind: crate::agent_transcript::entry::ChatEntryKind::UserPrompt {
text: prompt,
},
},
ctx,
);
});
if let Some(view) = &self.agent_panel_view {
view.update(ctx, |panel, ctx| {
panel.start_daemon_turn(session_id, text, ctx);
});
}
}
Comment on lines +191 to +197
Err(err) => {
log::info!("agent_panel: stream_agent_events failed: {err}");
}
}
let mut state = task_buffer.lock().unwrap_or_else(|p| p.into_inner());
state.in_flight = false;
});
Comment on lines +140 to +144
/// Launch a daemon turn for `conversation_id` and stream its events into the
/// transcript. Mirrors `ai_assistant::panel`'s spawn-on-runtime + shared
/// buffer + 100ms UI-poll pattern. Unix-only (the daemon transport is a unix
/// socket); a no-op elsewhere.
#[cfg(all(feature = "cast-agent", unix))]
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.

2 participants