Source multi-agent instructions from the model catalog (#38619)

## What changed

- Add model-catalog messages for root and subagent roles, explicit delegation, and delegation hints.
- Resolve role instructions in config, catalog, then bundled-default order, while preserving empty values as an explicit way to suppress fallback text.
- Refresh catalog-provided role and mode instructions when the model changes, and give full-history forks the selected child model's subagent role without retaining the parent's role guidance.
- Keep existing config overrides and reasoning-effort behavior, including proactive delegation for ultra reasoning effort.

## Testing

- Cover message deserialization and preservation through model overrides.
- Cover precedence, empty overrides, model switches, resumed sessions, and full-history subagent forks.

GitOrigin-RevId: 4625cf7c6a5490176adddfaa0fb99100707daea9
This commit is contained in:
rhan-oai authored and copyberry committed 2026-08-14 18:26:20 +00:00
1 parent 14a6813fa8
commit 395723b238
30 files changed
+734 -231

No files matched your search

+52
View File
@@ -531,6 +531,7 @@ pub struct ModelMessages {
pub collaboration_modes: Option<CollaborationModeMessages>,
pub auto_review: Option<AutoReviewMessages>,
pub permissions: Option<PermissionMessages>,
pub multi_agent: Option<MultiAgentMessages>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub token_budget: Option<ModelTokenBudgetConfig>,
}
@@ -572,6 +573,24 @@ pub struct PermissionMessages {
pub read_only: Option<String>,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, TS, JsonSchema)]
pub struct MultiAgentMessages {
pub role: Option<MultiAgentRoleMessages>,
pub mode: Option<MultiAgentModeMessages>,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, TS, JsonSchema)]
pub struct MultiAgentRoleMessages {
pub root: Option<String>,
pub subagent: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, TS, JsonSchema)]
pub struct MultiAgentModeMessages {
pub explicit: Option<String>,
pub hint_text: Option<String>,
}
impl ModelMessages {
fn has_personality_placeholder(&self) -> bool {
self.instructions_template
@@ -737,6 +756,7 @@ where
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
});
messages.instructions_template = Some(base_instructions);
@@ -925,6 +945,7 @@ mod tests {
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
}
);
@@ -1018,6 +1039,28 @@ mod tests {
);
}
#[test]
fn multi_agent_messages_preserve_missing_and_empty_values() {
let messages: ModelMessages = from_str(
r#"{"instructions_template":null,"instructions_variables":null,"multi_agent":{"role":{"root":"","subagent":"subagent base"},"mode":{"explicit":"explicit mode","hint_text":""}}}"#,
)
.expect("multi-agent messages should deserialize");
assert_eq!(
messages.multi_agent,
Some(MultiAgentMessages {
role: Some(MultiAgentRoleMessages {
root: Some(String::new()),
subagent: Some("subagent base".to_string()),
}),
mode: Some(MultiAgentModeMessages {
explicit: Some("explicit mode".to_string()),
hint_text: Some(String::new()),
}),
})
);
}
#[test]
fn collaboration_mode_messages_preserve_missing_and_empty_values() {
let messages: ModelMessages = from_str(
@@ -1043,6 +1086,7 @@ mod tests {
}),
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
}
);
@@ -1123,6 +1167,7 @@ mod tests {
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
}));
@@ -1144,6 +1189,7 @@ mod tests {
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
}));
assert_eq!(
@@ -1166,6 +1212,7 @@ mod tests {
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
}));
assert_eq!(
@@ -1199,6 +1246,7 @@ mod tests {
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
}));
@@ -1238,6 +1286,7 @@ mod tests {
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
})
);
@@ -1288,6 +1337,7 @@ mod tests {
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
}))],
};
@@ -1324,6 +1374,7 @@ mod tests {
workspace_write: Some("workspace".to_string()),
read_only: None,
}),
multi_agent: None,
token_budget: None,
};
let mut value = serde_json::to_value(ModelsResponse {
@@ -1345,6 +1396,7 @@ mod tests {
collaboration_modes: None,
auto_review: None,
permissions: None,
multi_agent: None,
token_budget: None,
};
let mut value = serde_json::to_value(ModelsResponse {