// tools/control.rs — Agent control tools // // Tools that affect agent control flow rather than performing work. // These return Result to maintain consistency with other // tools that can fail. The dispatch function handles error wrapping. use anyhow::{Context, Result}; use super::ToolOutput; use crate::agent::types::ToolDef; pub(super) fn pause(_args: &serde_json::Value) -> Result { Ok(ToolOutput { text: "Pausing autonomous behavior. Only user input will wake you.".to_string(), is_yield: true, images: Vec::new(), model_switch: None, dmn_pause: true, }) } pub(super) fn switch_model(args: &serde_json::Value) -> Result { let model = args .get("model") .and_then(|v| v.as_str()) .context("'model' parameter is required")?; if model.is_empty() { anyhow::bail!("'model' parameter cannot be empty"); } Ok(ToolOutput { text: format!("Switching to model '{}' after this turn.", model), is_yield: false, images: Vec::new(), model_switch: Some(model.to_string()), dmn_pause: false, }) } pub(super) fn yield_to_user(args: &serde_json::Value) -> Result { let msg = args .get("message") .and_then(|v| v.as_str()) .unwrap_or("Waiting for input."); Ok(ToolOutput { text: format!("Yielding. {}", msg), is_yield: true, images: Vec::new(), model_switch: None, dmn_pause: false, }) } pub(super) fn definitions() -> Vec { vec![ ToolDef::new( "switch_model", "Switch to a different LLM model mid-conversation. The switch \ takes effect after the current turn completes. Use this when \ a task would benefit from a different model's strengths. \ Your memories and conversation history carry over.", serde_json::json!({ "type": "object", "properties": { "model": { "type": "string", "description": "Name of the model to switch to (configured in config.json5)" } }, "required": ["model"] }), ), ToolDef::new( "pause", "Pause all autonomous behavior (DMN). You will only run when \ the user types something. Use this as a safety valve when \ you're stuck in a loop, confused, or want to fully stop. \ NOTE: only the user can unpause (Ctrl+P or /wake) — you \ cannot undo this yourself.", serde_json::json!({ "type": "object", "properties": {} }), ), ToolDef::new( "yield_to_user", "Signal that you want to wait for user input before continuing. \ Call this when you have a question for the user, when you've \ completed their request and want feedback, or when you genuinely \ want to pause. This is the ONLY way to enter a waiting state — \ without calling this tool, the agent loop will keep prompting you \ after a brief interval.", serde_json::json!({ "type": "object", "properties": { "message": { "type": "string", "description": "Optional status message (e.g., 'Waiting for your thoughts on the design')" } } }), ), ] }