diff options
| author | akbash <akbash@herdr.dev> | 2026-08-14 01:22:46 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-14 01:22:46 +0300 |
| commit | 9351b058f34973016a5d5973297d0567513e67a4 (patch) | |
| tree | 6b31e2700258170685297e08c03084e21d459e44 /src/app/api | |
| parent | 2075de5db083f1d1f4a9c67f6b36a8eeb250754e (diff) | |
fix: reject prompts to blocked agents (#2790)
* fix: reject prompts to blocked agents
refs #2788
* docs: clarify agent prompt timing
refs #2788
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Diffstat (limited to 'src/app/api')
| -rw-r--r-- | src/app/api/agents.rs | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/app/api/agents.rs b/src/app/api/agents.rs index e5e5525f..1ed13efc 100644 --- a/src/app/api/agents.rs +++ b/src/app/api/agents.rs @@ -79,6 +79,16 @@ impl App { let Some(terminal) = self.state.terminals.get(&terminal_id) else { return agent_not_found(id, ¶ms.target); }; + if terminal.state == crate::detect::AgentState::Blocked { + return encode_error( + id, + "agent_blocked", + format!( + "agent {} is blocked and requires interactive input", + params.target + ), + ); + } let Some(expected_agent) = terminal.effective_known_agent() else { return agent_not_ready(id, ¶ms.target); }; @@ -407,6 +417,41 @@ mod tests { } #[tokio::test] + async fn agent_prompt_rejects_blocked_agent_without_writing() { + let mut app = app_with_agent(); + let pane_id = app.state.workspaces[0].tabs[0].root_pane; + let terminal_id = app.state.workspaces[0].tabs[0].panes[&pane_id] + .attached_terminal_id + .clone(); + let terminal = app.state.terminals.get_mut(&terminal_id).unwrap(); + terminal.set_agent_name("reviewer".into()); + terminal.set_detected_state(Some(Agent::GithubCopilot), AgentState::Blocked); + let (runtime, mut rx) = crate::terminal::TerminalRuntime::test_with_channel(80, 24); + app.state.insert_test_runtime(pane_id, runtime); + + let response = app.handle_agent_prompt( + "req".into(), + AgentPromptParams { + target: "reviewer".into(), + text: "unrelated prompt".into(), + wait: None, + }, + ); + + let error: crate::api::schema::ErrorResponse = serde_json::from_str(&response).unwrap(); + assert_eq!(error.error.code, "agent_blocked"); + assert!( + tokio::time::timeout( + AGENT_PROMPT_SUBMIT_DELAY + Duration::from_millis(100), + rx.recv() + ) + .await + .is_err(), + "blocked prompt wrote or scheduled terminal input" + ); + } + + #[tokio::test] async fn agent_prompt_focuses_copilot_before_submitting() { let mut app = app_with_agent(); let pane_id = app.state.workspaces[0].tabs[0].root_pane; |
