- Rust 98.1%
- Shell 0.7%
- Python 0.5%
- Objective-C 0.2%
- PowerShell 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
## Description Required for the conversation-steering interrupt e2e (warp-server warpdotdev/warp-server#16958, session-sharing warpdotdev/session-sharing#517, follows warpdotdev/warp-internal#27914). ### Staging evidence With the sharer bypass from #27914, a steering interrupt reaches the sharer as `ControlActionRequested { action: CancelConversation { server_conversation_token } }` and the turn is cancelled (no further LLM requests; `TOOL_RESULT cancel: cancelled` is carried with the next request). But the agent's in-flight tool command kept running to natural completion: `echo step-one; sleep 12; echo done-one` finished its full 12 s after the interrupt (`CommandExecutionFinished` ~12–13 s after start in every run). Product decision: an interrupt must terminate the running command as well as cancel the turn. ### Local stop vs. shared-session cancel (before this PR) * **Local stop kills the command.** The pill-bar Stop/Kill (`pane_group/pane/terminal_pane.rs`) and the second Ctrl-C after a Stop takeover (`view.rs` `ctrl_c_to_active_block`) both go through `TerminalView::stop_local_agent_conversation`, which calls `cancel_conversation_progress(ManuallyCancelled)`, releases an agent-controlled block via `set_user_control_for_teardown()`, and writes Ctrl-C (ETX) to the PTY. Rewind does the same. * **Shared-session cancel did not.** `terminal_view_adaptor.rs` → `BlocklistAIController::handle_shared_session_cancel_action` → `cancel_conversation_progress` only. For a running `RequestCommandOutput`, `ShellCommandExecutor::cancel_execution` just drops the block-finished / force-refresh oneshot senders so the action resolves `Cancelled`; nothing touches the PTY, so the child process runs to completion. ### Change * `NetworkEvent::ControlActionRequested { CancelConversation }` now calls a new `TerminalView::handle_shared_session_cancel_action(token)`, which resolves the token to the live conversation and then calls the existing `stop_local_agent_conversation`. Viewer-initiated stop and server-side steering both arrive through this handler, so both get the same behaviour. The local stop primitive is unchanged. * `BlocklistAIController::handle_shared_session_cancel_action` becomes `conversation_for_shared_session_cancel_action`: a pure resolver returning the live, **not-yet-finished** conversation bound to the token. This is a small deliberate tightening: a late/duplicate cancel for a conversation that already reached `Success`/`Error`/`Cancelled` is now a no-op (previously it only reset the sharer's input mode) instead of being able to flip the terminal status to `Cancelled` via the stop primitive. Expected result on staging: the command block finishes within ~1 s of the interrupt (exit 130) rather than at natural completion, and the tool result reports cancellation promptly. ## Linked Issue - [ ] The linked issue is labeled `ready-to-spec` or `ready-to-implement`. - [ ] Where appropriate, screenshots or a short video of the implementation are included below (especially for user-visible or UI changes). ## Testing New unit tests in `app/src/terminal/view_tests.rs`: * `shared_session_cancel_action_interrupts_running_agent_command` — agent-requested command running in the active block; cancel writes exactly one ETX to the PTY and the conversation ends `Cancelled`. * `shared_session_cancel_action_releases_agent_controlled_command_before_interrupting` — CLI-subagent-controlled block (which would otherwise swallow the Ctrl-C in `write_user_bytes_to_pty`) is handed to the user for teardown, ETX is written, no auto-resume. * `shared_session_cancel_action_ignores_unknown_and_finished_conversations` — unknown token and already-`Success` conversation: no PTY write, status preserved. Commands run: * `./script/format` then `./script/format --check` — pass * `cargo clippy -p warp --all-targets --tests -- -D warnings` — pass * `cargo nextest run -p warp -E 'test(shared_session_cancel_action) | test(ctrl_c_after_stop_takeover) | test(ctrl_c_after_transfer_takeover) | test(completed_user_controlled_lrc)'` — 7/7 pass - [ ] I have manually tested my changes locally with `./script/run` (not run; needs the steering e2e on staging — see evidence above for the pre-change baseline) ## Follow-up: run state after interrupt (proposal, not implemented) Today `LocalAgentTaskSyncModel::map_conversation_status` (`app/src/ai/blocklist/local_agent_task_sync_model.rs`) maps `ConversationStatus::Cancelled` → `(AgentTaskState::Cancelled, "Cancelled by user")` and pushes it to warp-server, which runs `TransitionTaskToCancelled` (cancels a bound Factory task, notifies GitHub/Linear/Jira/lifecycle, expires queued follow-ups; the run becomes non-resumable once the session idles out). For a shared-session-originated cancel (steering interrupt or viewer stop) the desired run state is the idle shape a completed turn leaves: report `AgentTaskState::Succeeded` with status message `"Turn interrupted"`, while the transcript still shows the exchange as cancelled. **Why the reason isn't available to the sync model today.** The only place a `CancellationReason` is recorded is on the exchange, in `FinishedAIAgentOutput::Cancelled { reason }`, and only when an in-flight *stream* is cancelled (`AIConversation::mark_request_cancelled`). In the interrupt case there is no stream: the turn is mid-tool-call, so the conversation is moved to `Cancelled` by the controller's `FinishedAction` handler (`controller.rs`, the "mixed results → Cancelled" branch) and by `stop_local_agent_conversation`'s direct `update_conversation_status(Cancelled)` — neither carries a reason. So the exchange is not a reliable place to look. **Proposal.** 1. `app/src/ai/agent/mod.rs`: add `CancellationReason::SharedSessionControl`. `conversation_outcome()` → `CancellationOutcome::Cancelled`; `Display` → `"shared session control action"`. (Only these two matches are exhaustive over the enum.) 2. `app/src/ai/agent/conversation.rs`: mirror the existing `status_error: Option<RenderableAIError>` pattern with `status_cancellation_reason: Option<CancellationReason>`, set by a new `update_status_with_cancellation_reason(status, reason, ...)` (cleared when the status is not `Cancelled`), exposed via `status_cancellation_reason()`; `BlocklistAIHistoryModel` gets the matching `update_conversation_status_with_cancellation_reason`. Persist it alongside `status_error` if that is persisted (check `conversation_yaml` / the persisted conversation state; a restart mid-interrupt is an edge case, not a blocker). 3. Plumb the reason: `TerminalView::stop_local_agent_conversation(conversation_id, reason, ctx)` takes the `CancellationReason` (local callers pass `ManuallyCancelled`, the new `handle_shared_session_cancel_action` passes `SharedSessionControl`) and forwards it to `cancel_conversation_progress`, to its direct `Cancelled` status write, and — via `BlocklistAIActionEvent::FinishedAction { cancellation_reason }` — the controller's `FinishedAction` handler records it when it writes `Cancelled`. `mark_request_cancelled` already has the reason and should record it too, so the stream-cancel path is covered for free. 4. `local_agent_task_sync_model.rs`: in `map_conversation_status`, `ConversationStatus::Cancelled` matches on `conversation.status_cancellation_reason()`: `Some(SharedSessionControl)` → `(AgentTaskState::Succeeded, Some(TaskStatusUpdate::message("Turn interrupted")))`; anything else keeps `(Cancelled, "Cancelled by user")`. The reason is available where the update is computed because `on_conversation_status_updated` runs off `BlocklistAIHistoryEvent::UpdatedConversationStatus` and reads the conversation from the history model synchronously, after the status (and reason) have been written. 5. Tests: `local_agent_task_sync_model_tests.rs` — `map_conversation_status` with `Cancelled` + `SharedSessionControl` → `Succeeded`/"Turn interrupted", and `Cancelled` + `ManuallyCancelled`/`None` → unchanged; `view_tests.rs` — `handle_shared_session_cancel_action` records `SharedSessionControl` on the conversation while a local Ctrl-C stop records `ManuallyCancelled`. Caveat to confirm with the server side: reporting `Succeeded` for an interrupted turn means the run shows as succeeded in lists until the next turn; if a distinct state is preferred the mapping in step 4 is the single place to change. ## Agent Mode - [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode CHANGELOG-BUG-FIX: Stopping a shared Agent Mode conversation from a viewer or via conversation steering now interrupts the agent's running command instead of letting it run to completion. --- Conversation: https://staging.warp.dev/conversation/8eaf5a4f-d303-465a-8498-f6267e0a0347 Run: https://platform.staging.warp.dev/runs/01a084d0-cfc8-7b67-b960-97c4e2622c47 |
||
| .agents | ||
| .cargo | ||
| .claude | ||
| .config | ||
| .github | ||
| .vscode | ||
| .warp | ||
| agents/specs | ||
| app | ||
| command-signatures-v2/js | ||
| crates | ||
| docker | ||
| images | ||
| resources | ||
| script | ||
| specs | ||
| .clippy.toml | ||
| .dockerignore | ||
| .gitattributes | ||
| .gitignore | ||
| .mcp.json | ||
| .PSScriptAnalyzerSettings.psd1 | ||
| .rustfmt.toml | ||
| .warpindexingignore | ||
| about.hbs | ||
| about.toml | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| deny.toml | ||
| diesel.toml | ||
| FAQ.md | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE-AGPL | ||
| LICENSE-MIT | ||
| PSScriptAnalyzerCustomRules.psm1 | ||
| README.md | ||
| rust-toolchain.toml | ||
| SECURITY.md | ||
| skills-lock.json | ||
Website · Code · Agents · Terminal · Drive · Docs · How Warp Works
Note
OpenAI is the founding sponsor of the new, open-source Warp repository, and the new agentic management workflows are powered by GPT models.
About
Warp is an agentic development environment, born out of the terminal. Use Warp's built-in coding agent, or bring your own CLI agent (Claude Code, Codex, Gemini CLI, and others).
Installation
You can download Warp and read our docs for platform-specific instructions.
Warp Contributions Overview Dashboard
Explore build.warp.dev to:
- Watch thousands of Warp Factory agents triage issues, write specs, implement changes, and review PRs
- View top contributors and in-flight features
- Track your own issues with GitHub sign-in
- Click into active agent sessions in a web-compiled Warp terminal
Automate development with Warp Factories
This repository is driven by Warp Factories: open, flexible infrastructure for teams to build cloud software factories of their own.
Warp Factories are defined in code and easy to deploy on any model or harness, with evals, benchmarks, and self-improvement built in. Request early access.
Licensing
Warp's UI framework (the warpui_core and warpui crates) are licensed under the MIT license.
The rest of the code in this repository is licensed under the AGPL v3.
Open Source & Contributing
Warp's client codebase is open source and lives in this repository. We welcome community contributions and have designed a lightweight workflow to help new contributors get started. For the full contribution flow, read our CONTRIBUTING.md guide.
Tip
Chat with contributors and the Warp team in the
#oss-contributorsSlack channel — a good place for ad-hoc questions, design discussion, and pairing with maintainers. New here? Join the Warp Slack community first, then jump into#oss-contributors.
Issue to PR
Before filing, search existing issues for your bug or feature request. If nothing exists, file an issue using our templates. Security vulnerabilities should be reported privately as described in CONTRIBUTING.md.
Once filed, a Warp maintainer reviews the issue and may apply a readiness label: ready-to-spec signals the design is open for contributors to spec out, and ready-to-implement signals the design is settled and code PRs are welcome. Anyone can pick up a labeled issue — mention @oss-maintainers on an issue if you'd like it considered for a readiness label.
Building the Repo Locally
To build and run Warp from source:
./script/bootstrap # platform-specific setup
./script/run # build and run Warp
./script/presubmit # fmt, clippy, and tests
See AGENTS.md for the full engineering guide, including coding style, testing, and platform-specific notes.
Joining the Team
Interested in joining the team? See our open roles.
Support and Questions
- See our docs for a comprehensive guide to Warp's features.
- Join our Slack Community to connect with other users and get help from the Warp team — contributors hang out in
#oss-contributors. - Try our Preview build to test the latest experimental features.
- Mention @oss-maintainers on any issue to escalate to the team — for example, if you encounter problems with the automated agents.
Code of Conduct
We ask everyone to be respectful and empathetic. Warp follows the Code of Conduct. To report violations, email warp-coc at warp.dev.
Open Source Dependencies
We'd like to call out a few of the open source dependencies that have helped Warp to get off the ground: