From 79ec2d87c7ef441f3e50c977c1367ee82ede7112 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Fri, 21 Aug 2026 12:47:38 -0600 Subject: [PATCH] fix: support tab completions for graph-based agents with variables as well as standard agents --- src/config/agent.rs | 65 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/src/config/agent.rs b/src/config/agent.rs index dce814c..9a6b83f 100644 --- a/src/config/agent.rs +++ b/src/config/agent.rs @@ -1131,6 +1131,12 @@ struct AgentMetadataStub { description: String, } +#[derive(Deserialize)] +struct AgentVariablesStub { + #[serde(default)] + variables: Vec, +} + fn load_agent_description(name: &str) -> String { if let Ok(config) = AgentConfig::load(&paths::agent_config_file(name)) { return config.description; @@ -1145,16 +1151,22 @@ fn load_agent_description(name: &str) -> String { String::new() } -pub fn complete_agent_variables(agent_name: &str) -> Vec<(String, Option)> { - let config_path = paths::agent_config_file(agent_name); - if !config_path.exists() { - return vec![]; +fn load_agent_variables(name: &str) -> Vec { + if let Ok(config) = AgentConfig::load(&paths::agent_config_file(name)) { + return config.variables; } - let Ok(config) = AgentConfig::load(&config_path) else { - return vec![]; - }; - config - .variables + + if let Ok(contents) = read_to_string(paths::agent_graph_file(name)) + && let Ok(stub) = serde_yaml::from_str::(&contents) + { + return stub.variables; + } + + Vec::new() +} + +pub fn complete_agent_variables(agent_name: &str) -> Vec<(String, Option)> { + load_agent_variables(agent_name) .iter() .map(|v| { let description = match &v.default { @@ -1399,6 +1411,41 @@ version: "1.0" assert_eq!(meta.description, ""); } + #[test] + fn agent_variables_stub_extracts_variables_from_graph_yaml() { + let yaml = r#" +name: coder +description: Implementation agent. +version: "1.0" +variables: + - name: task + description: The task to implement + - name: scope + description: Directory scope + default: src/ +start: plan +nodes: {} +"#; + + let stub: AgentVariablesStub = serde_yaml::from_str(yaml).unwrap(); + + assert_eq!(stub.variables.len(), 2); + assert_eq!(stub.variables[0].name, "task"); + assert_eq!(stub.variables[0].description, "The task to implement"); + assert_eq!(stub.variables[0].default, None); + assert_eq!(stub.variables[1].name, "scope"); + assert_eq!(stub.variables[1].default.as_deref(), Some("src/")); + } + + #[test] + fn agent_variables_stub_defaults_when_variables_missing() { + let yaml = "name: coder\nversion: \"1.0\"\nstart: plan\nnodes: {}\n"; + + let stub: AgentVariablesStub = serde_yaml::from_str(yaml).unwrap(); + + assert!(stub.variables.is_empty()); + } + #[test] fn rag_init_config_forwards_an_explicit_driver() { let node: RagNode =