@@ -71,6 +71,8 @@ use crate::util::{
7171 directories,
7272} ;
7373
74+ pub const DEFAULT_AGENT_NAME : & str = "q_cli_default" ;
75+
7476#[ derive( Debug , Error ) ]
7577pub enum AgentConfigError {
7678 #[ error( "Json supplied at {} is invalid: {}" , path. display( ) , error) ]
@@ -86,8 +88,6 @@ pub enum AgentConfigError {
8688 Directories ( #[ from] util:: directories:: DirectoryError ) ,
8789 #[ error( "Encountered io error: {0}" ) ]
8890 Io ( #[ from] std:: io:: Error ) ,
89- #[ error( "Agent path missing file name" ) ]
90- MissingFilename ,
9191 #[ error( "Failed to parse legacy mcp config: {0}" ) ]
9292 BadLegacyMcpConfig ( #[ from] eyre:: Report ) ,
9393}
@@ -120,14 +120,14 @@ pub enum AgentConfigError {
120120#[ serde( rename_all = "camelCase" , deny_unknown_fields) ]
121121#[ schemars( description = "An Agent is a declarative way of configuring a given instance of q chat." ) ]
122122pub struct Agent {
123- /// Agent names are derived from the file name. Thus they are skipped for
124- /// serializing
125- # [ serde ( skip ) ]
123+ # [ serde ( rename = "$schema" , default = "default_schema" ) ]
124+ pub schema : String ,
125+ /// Name of the agent
126126 pub name : String ,
127127 /// This field is not model facing and is mostly here for users to discern between agents
128128 #[ serde( default ) ]
129129 pub description : Option < String > ,
130- /// (NOT YET IMPLEMENTED) The intention for this field is to provide high level context to the
130+ /// The intention for this field is to provide high level context to the
131131 /// agent. This should be seen as the same category of context as a system prompt.
132132 #[ serde( default ) ]
133133 pub prompt : Option < String > ,
@@ -168,7 +168,8 @@ pub struct Agent {
168168impl Default for Agent {
169169 fn default ( ) -> Self {
170170 Self {
171- name : "default" . to_string ( ) ,
171+ schema : default_schema ( ) ,
172+ name : DEFAULT_AGENT_NAME . to_string ( ) ,
172173 description : Some ( "Default agent" . to_string ( ) ) ,
173174 prompt : Default :: default ( ) ,
174175 mcp_servers : Default :: default ( ) ,
@@ -206,18 +207,10 @@ impl Agent {
206207
207208 /// This function mutates the agent to a state that is usable for runtime.
208209 /// Practically this means to convert some of the fields value to their usable counterpart.
209- /// For example, we populate the agent with its file name, convert the mcp array to actual
210- /// mcp config and populate the agent file path.
210+ /// For example, converting the mcp array to actual mcp config and populate the agent file path.
211211 fn thaw ( & mut self , path : & Path , global_mcp_config : Option < & McpServerConfig > ) -> Result < ( ) , AgentConfigError > {
212212 let Self { mcp_servers, .. } = self ;
213213
214- let name = path
215- . file_stem ( )
216- . ok_or ( AgentConfigError :: MissingFilename ) ?
217- . to_string_lossy ( )
218- . to_string ( ) ;
219-
220- self . name = name. clone ( ) ;
221214 self . path = Some ( path. to_path_buf ( ) ) ;
222215
223216 if let ( true , Some ( global_mcp_config) ) = ( self . use_legacy_mcp_json , global_mcp_config) {
@@ -259,7 +252,7 @@ impl Agent {
259252 pub async fn get_agent_by_name ( os : & Os , agent_name : & str ) -> eyre:: Result < ( Agent , PathBuf ) > {
260253 let config_path: Result < PathBuf , PathBuf > = ' config: {
261254 // local first, and then fall back to looking at global
262- let local_config_dir = directories:: chat_local_agent_dir ( ) ?. join ( format ! ( "{agent_name}.json" ) ) ;
255+ let local_config_dir = directories:: chat_local_agent_dir ( os ) ?. join ( format ! ( "{agent_name}.json" ) ) ;
263256 if os. fs . exists ( & local_config_dir) {
264257 break ' config Ok ( local_config_dir) ;
265258 }
@@ -397,7 +390,7 @@ impl Agents {
397390 } ;
398391
399392 let new_agents = if !skip_migration {
400- match legacy:: migrate ( os) . await {
393+ match legacy:: migrate ( os, false ) . await {
401394 Ok ( Some ( new_agents) ) => {
402395 let migrated_count = new_agents. len ( ) ;
403396 info ! ( migrated_count, "Profile migration successful" ) ;
@@ -431,7 +424,7 @@ impl Agents {
431424 } ,
432425 }
433426
434- let Ok ( path) = directories:: chat_local_agent_dir ( ) else {
427+ let Ok ( path) = directories:: chat_local_agent_dir ( os ) else {
435428 break ' local Vec :: < Agent > :: new ( ) ;
436429 } ;
437430 let Ok ( files) = os. fs . read_dir ( path) . await else {
@@ -641,7 +634,7 @@ impl Agents {
641634 agent
642635 } ) ;
643636
644- "default" . to_string ( )
637+ DEFAULT_AGENT_NAME . to_string ( )
645638 } ;
646639
647640 let _ = output. flush ( ) ;
@@ -707,7 +700,7 @@ impl Agents {
707700 // Here the tool names can take the following forms:
708701 // - @{server_name}{delimiter}{tool_name}
709702 // - native_tool_name
710- name == tool_name
703+ name == tool_name && matches ! ( origin , & ToolOrigin :: Native )
711704 || name. strip_prefix ( "@" ) . is_some_and ( |remainder| {
712705 remainder
713706 . split_once ( MCP_SERVER_TOOL_DELIMITER )
@@ -776,6 +769,10 @@ async fn load_agents_from_entries(
776769 res
777770}
778771
772+ fn default_schema ( ) -> String {
773+ "https://raw.githubusercontent.com/aws/amazon-q-developer-cli/refs/heads/main/schemas/agent-v1.json" . into ( )
774+ }
775+
779776#[ cfg( test) ]
780777fn validate_agent_name ( name : & str ) -> eyre:: Result < ( ) > {
781778 // Check if name is empty
@@ -800,6 +797,7 @@ mod tests {
800797
801798 const INPUT : & str = r#"
802799 {
800+ "name": "some_agent",
803801 "description": "My developer agent is used for small development tasks like solving open issues.",
804802 "prompt": "You are a principal developer who uses multiple agents to accomplish difficult engineering tasks",
805803 "mcpServers": {
@@ -841,11 +839,12 @@ mod tests {
841839 assert ! ( collection. get_active( ) . is_none( ) ) ;
842840
843841 let agent = Agent :: default ( ) ;
844- collection. agents . insert ( "default" . to_string ( ) , agent) ;
845- collection. active_idx = "default" . to_string ( ) ;
842+ let agent_name = agent. name . clone ( ) ;
843+ collection. agents . insert ( agent_name. clone ( ) , agent) ;
844+ collection. active_idx = agent_name. clone ( ) ;
846845
847846 assert ! ( collection. get_active( ) . is_some( ) ) ;
848- assert_eq ! ( collection. get_active( ) . unwrap( ) . name, "default" ) ;
847+ assert_eq ! ( collection. get_active( ) . unwrap( ) . name, agent_name ) ;
849848 }
850849
851850 #[ test]
0 commit comments