@@ -77,51 +77,37 @@ impl MultiAgentWorkflowExecutor {
7777 // Check if there's a global LLM config section
7878 let default_role_name = "Default" . into ( ) ;
7979 if let Some ( default_role) = config. roles . get ( & default_role_name) {
80- if let Some ( provider) = default_role. extra . get ( "llm_provider" ) {
81- if let Some ( provider_str) = provider. as_str ( ) {
82- resolved. llm_provider = Some ( provider_str. to_string ( ) ) ;
83- }
80+ if let Some ( s) = Self :: get_role_extra_str ( & default_role. extra , "llm_provider" ) {
81+ resolved. llm_provider = Some ( s. to_string ( ) ) ;
8482 }
85- if let Some ( model) = default_role. extra . get ( "llm_model" ) {
86- if let Some ( model_str) = model. as_str ( ) {
87- resolved. llm_model = Some ( model_str. to_string ( ) ) ;
88- }
83+ if let Some ( s) = Self :: get_role_extra_str ( & default_role. extra , "llm_model" ) {
84+ resolved. llm_model = Some ( s. to_string ( ) ) ;
8985 }
90- if let Some ( base_url) = default_role. extra . get ( "llm_base_url" ) {
91- if let Some ( base_url_str) = base_url. as_str ( ) {
92- resolved. llm_base_url = Some ( base_url_str. to_string ( ) ) ;
93- }
86+ if let Some ( s) = Self :: get_role_extra_str ( & default_role. extra , "llm_base_url" ) {
87+ resolved. llm_base_url = Some ( s. to_string ( ) ) ;
9488 }
9589 }
9690
9791 // Check role-specific config
9892 let role_name_key = role_name. into ( ) ;
9993 if let Some ( role) = config. roles . get ( & role_name_key) {
100- if let Some ( provider) = role. extra . get ( "llm_provider" ) {
101- if let Some ( provider_str) = provider. as_str ( ) {
102- resolved. llm_provider = Some ( provider_str. to_string ( ) ) ;
103- }
94+ if let Some ( s) = Self :: get_role_extra_str ( & role. extra , "llm_provider" ) {
95+ resolved. llm_provider = Some ( s. to_string ( ) ) ;
10496 }
105- if let Some ( model) = role. extra . get ( "llm_model" ) {
106- if let Some ( model_str) = model. as_str ( ) {
107- resolved. llm_model = Some ( model_str. to_string ( ) ) ;
108- }
97+ if let Some ( s) = Self :: get_role_extra_str ( & role. extra , "llm_model" ) {
98+ resolved. llm_model = Some ( s. to_string ( ) ) ;
10999 }
110- if let Some ( base_url) = role. extra . get ( "llm_base_url" ) {
111- if let Some ( base_url_str) = base_url. as_str ( ) {
112- resolved. llm_base_url = Some ( base_url_str. to_string ( ) ) ;
113- }
100+ if let Some ( s) = Self :: get_role_extra_str ( & role. extra , "llm_base_url" ) {
101+ resolved. llm_base_url = Some ( s. to_string ( ) ) ;
114102 }
115- if let Some ( temp) = role. extra . get ( "llm_temperature" ) {
116- if let Some ( temp_val) = temp. as_f64 ( ) {
117- resolved. llm_temperature = Some ( temp_val) ;
118- }
103+ if let Some ( v) = Self :: get_role_extra_f64 ( & role. extra , "llm_temperature" ) {
104+ resolved. llm_temperature = Some ( v) ;
119105 }
120106 }
121107 }
122108 }
123109
124- // Override with request-level config (highest priority)
110+ // Override with request-level config if provided
125111 if let Some ( req_config) = request_config {
126112 if let Some ( provider) = & req_config. llm_provider {
127113 resolved. llm_provider = Some ( provider. clone ( ) ) ;
@@ -149,6 +135,32 @@ impl MultiAgentWorkflowExecutor {
149135 resolved
150136 }
151137
138+ /// Get a string value from Role.extra, checking both flat and nested paths.
139+ ///
140+ /// Due to `#[serde(flatten)]` on `Role.extra`, config JSON with `"extra": {"key": "val"}`
141+ /// results in `extra["extra"]["key"]` rather than `extra["key"]`.
142+ fn get_role_extra_str < ' a > (
143+ extra : & ' a AHashMap < String , serde_json:: Value > ,
144+ key : & str ,
145+ ) -> Option < & ' a str > {
146+ extra. get ( key) . and_then ( |v| v. as_str ( ) ) . or_else ( || {
147+ extra
148+ . get ( "extra" )
149+ . and_then ( |v| v. get ( key) )
150+ . and_then ( |v| v. as_str ( ) )
151+ } )
152+ }
153+
154+ /// Get an f64 value from Role.extra, checking both flat and nested paths.
155+ fn get_role_extra_f64 ( extra : & AHashMap < String , serde_json:: Value > , key : & str ) -> Option < f64 > {
156+ extra. get ( key) . and_then ( |v| v. as_f64 ( ) ) . or_else ( || {
157+ extra
158+ . get ( "extra" )
159+ . and_then ( |v| v. get ( key) )
160+ . and_then ( |v| v. as_f64 ( ) )
161+ } )
162+ }
163+
152164 /// Execute prompt chaining workflow with actual TerraphimAgent
153165 #[ allow( clippy:: too_many_arguments) ]
154166 pub async fn execute_prompt_chain (
0 commit comments