use bytes::Bytes; use crate::api::schema::{ AgentRenameParams, AgentSendParams, AgentStartParams, AgentTarget, PaneReadResult, ReadFormat, ReadSource, ResponseResult, }; use crate::app::App; use super::responses::{encode_error, encode_error_body, encode_success}; impl App { pub(super) fn handle_agent_list(&mut self, id: String) -> String { encode_success( id, ResponseResult::AgentList { agents: self.collect_agent_infos(), }, ) } pub(super) fn handle_agent_get(&mut self, id: String, target: AgentTarget) -> String { let agent = match self.agent_info_for_target(&target.target) { Ok(agent) => agent, Err(err) => return encode_error_body(id, self.agent_target_error_body(err)), }; encode_success(id, ResponseResult::AgentInfo { agent }) } pub(super) fn handle_agent_focus(&mut self, id: String, target: AgentTarget) -> String { let agent = match self.focus_agent_target(&target.target) { Ok(agent) => agent, Err(err) => return encode_error_body(id, self.agent_target_error_body(err)), }; encode_success(id, ResponseResult::AgentInfo { agent }) } pub(super) fn handle_agent_rename(&mut self, id: String, params: AgentRenameParams) -> String { let agent = match self.rename_agent_target(¶ms.target, params.name) { Ok(agent) => agent, Err(err) => return encode_error_body(id, self.agent_rename_error_body(err)), }; encode_success(id, ResponseResult::AgentInfo { agent }) } pub(super) fn handle_agent_start(&mut self, id: String, params: AgentStartParams) -> String { let extra_env = match super::env::normalize_launch_env(params.env.clone()) { Ok(env) => env, Err((code, message)) => return encode_error(id, &code, message), }; let (agent, argv) = match self.start_agent(params, extra_env) { Ok(started) => started, Err(err) => return encode_error_body(id, self.agent_start_error_body(err)), }; encode_success(id, ResponseResult::AgentStarted { agent, argv }) } pub(super) fn handle_agent_read( &mut self, id: String, params: crate::api::schema::AgentReadParams, ) -> String { let resolved = match self.resolve_terminal_target(¶ms.target) { Ok(resolved) => resolved, Err(err) => return encode_error_body(id, self.agent_target_error_body(err)), }; let Some((pane, workspace_id)) = self.lookup_runtime(resolved.ws_idx, resolved.pane_id) else { return agent_not_found(id, ¶ms.target); }; let requested_lines = params.lines.unwrap_or(80).min(1000) as usize; let text = match params.format { ReadFormat::Text => match params.source { ReadSource::Visible => pane.visible_text(), ReadSource::Recent => pane.recent_text(requested_lines), ReadSource::RecentUnwrapped => pane.recent_unwrapped_text(requested_lines), ReadSource::Detection => pane.detection_text(), }, ReadFormat::Ansi => match params.source { ReadSource::Visible => pane.visible_ansi(), ReadSource::Recent => pane.recent_ansi(requested_lines), ReadSource::RecentUnwrapped => pane.recent_unwrapped_ansi(requested_lines), ReadSource::Detection => pane.detection_text(), }, }; encode_success( id, ResponseResult::PaneRead { read: PaneReadResult { pane_id: self .public_pane_id(resolved.ws_idx, resolved.pane_id) .unwrap_or_else(|| params.target.clone()), workspace_id, tab_id: self .public_tab_id(resolved.ws_idx, resolved.tab_idx) .unwrap(), source: params.source, format: params.format, text, revision: 0, truncated: false, }, }, ) } pub(super) fn handle_agent_explain(&mut self, id: String, target: AgentTarget) -> String { let resolved = match self.resolve_terminal_target(&target.target) { Ok(resolved) => resolved, Err(err) => return encode_error_body(id, self.agent_target_error_body(err)), }; let Some((pane, _workspace_id)) = self.lookup_runtime(resolved.ws_idx, resolved.pane_id) else { return agent_not_found(id, &target.target); }; let Some(terminal_id) = self .state .workspaces .get(resolved.ws_idx) .and_then(|workspace| workspace.terminal_id(resolved.pane_id)) else { return agent_not_found(id, &target.target); }; let Some(terminal) = self.state.terminals.get(terminal_id) else { return agent_not_found(id, &target.target); }; if terminal.full_lifecycle_hook_authority_active() { let explain = serde_json::json!({ "agent": terminal.effective_agent_label().unwrap_or("unknown"), "state": crate::detect::manifest::agent_state_label(terminal.state), "manifest_source": null, "manifest_version": null, "cached_remote_version": null, "local_override_shadowing_remote": false, "remote_update_status": null, "remote_update_error": null, "matched_rule": null, "visible_idle": false, "visible_blocker": false, "visible_working": false, "screen_detection_skipped": true, "screen_detection_skip_reason": "full_lifecycle_hook_authority", "skip_state_update": false, "skipped_update_reason": null, "fallback_reason": null, "warning": null, "evaluated_rules": [], }); return encode_success(id, ResponseResult::AgentExplain { explain }); } let Some(agent) = terminal.effective_known_agent().or(terminal.detected_agent) else { return encode_error( id, "agent_explain_unavailable", format!( "agent target {} does not have a detected agent label", target.target ), ); }; let screen = pane.detection_text(); let osc_title = pane.agent_osc_title(); let osc_progress = pane.agent_osc_progress(); let explain = crate::detect::manifest::explain_with_input( agent, crate::detect::manifest::DetectionInput { screen: &screen, osc_title: &osc_title, osc_progress: &osc_progress, }, ); let value = crate::detect::manifest::explain_to_json_value(&explain); encode_success(id, ResponseResult::AgentExplain { explain: value }) } pub(super) fn handle_agent_send(&mut self, id: String, params: AgentSendParams) -> String { let resolved = match self.resolve_terminal_target(¶ms.target) { Ok(resolved) => resolved, Err(err) => return encode_error_body(id, self.agent_target_error_body(err)), }; let Some(runtime) = self.lookup_runtime_sender(resolved.ws_idx, resolved.pane_id) else { return agent_not_found(id, ¶ms.target); }; if let Err(err) = runtime.try_send_bytes(Bytes::from(params.text)) { return encode_error(id, "agent_send_failed", err.to_string()); } encode_success(id, ResponseResult::Ok {}) } } fn agent_not_found(id: String, target: &str) -> String { encode_error( id, "agent_not_found", format!("agent target {target} not found"), ) }