@@ -6755,6 +6971,65 @@ pub enum FusionPattern {
Unknown,
}
+/// HydraFusion phase kind.
+///
+///
+///
+/// **Experimental.** This type is part of an experimental wire-protocol surface
+/// and may change or be removed in future SDK or CLI releases.
+///
+///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum FusionPhaseKind {
+ /// Primary solver phase.
+ #[serde(rename = "primary")]
+ Primary,
+ /// Read-only cascade judge phase.
+ #[serde(rename = "judge")]
+ Judge,
+ /// Cascade repair phase.
+ #[serde(rename = "repair")]
+ Repair,
+ /// Initial critique-pattern draft phase.
+ #[serde(rename = "draft")]
+ Draft,
+ /// Read-only critique phase.
+ #[serde(rename = "critic")]
+ Critic,
+ /// Critique-pattern revision phase.
+ #[serde(rename = "revision")]
+ Revision,
+ /// Follow-up phase continuing from the resolved model.
+ #[serde(rename = "follow_up")]
+ FollowUp,
+ /// Unknown variant for forward compatibility.
+ #[default]
+ #[serde(other)]
+ Unknown,
+}
+
+/// Conversation scope in which a HydraFusion phase executes.
+///
+///
+///
+/// **Experimental.** This type is part of an experimental wire-protocol surface
+/// and may change or be removed in future SDK or CLI releases.
+///
+///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum FusionConversationScope {
+ /// Canonical root conversation history.
+ #[serde(rename = "root")]
+ Root,
+ /// Isolated read-only review history that does not enter the root conversation.
+ #[serde(rename = "review")]
+ Review,
+ /// Unknown variant for forward compatibility.
+ #[default]
+ #[serde(other)]
+ Unknown,
+}
+
/// The agent mode that was active when this message was sent
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum UserMessageAgentMode {
@@ -6845,7 +7120,7 @@ pub enum ModelCallFailureTransport {
Unknown,
}
-/// Conversation scope in which a HydraFusion phase executes.
+/// Content-safe activity observed while a HydraFusion phase is running.
///
///
///
@@ -6854,50 +7129,16 @@ pub enum ModelCallFailureTransport {
///
///
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
-pub enum FusionConversationScope {
- /// Canonical root conversation history.
- #[serde(rename = "root")]
- Root,
- /// Isolated read-only review history that does not enter the root conversation.
- #[serde(rename = "review")]
- Review,
- /// Unknown variant for forward compatibility.
- #[default]
- #[serde(other)]
- Unknown,
-}
-
-/// HydraFusion phase kind.
-///
-///
-///
-/// **Experimental.** This type is part of an experimental wire-protocol surface
-/// and may change or be removed in future SDK or CLI releases.
-///
-///
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
-pub enum FusionPhaseKind {
- /// Primary solver phase.
- #[serde(rename = "primary")]
- Primary,
- /// Read-only cascade judge phase.
- #[serde(rename = "judge")]
- Judge,
- /// Cascade repair phase.
- #[serde(rename = "repair")]
- Repair,
- /// Initial critique-pattern draft phase.
- #[serde(rename = "draft")]
- Draft,
- /// Read-only critique phase.
- #[serde(rename = "critic")]
- Critic,
- /// Critique-pattern revision phase.
- #[serde(rename = "revision")]
- Revision,
- /// Follow-up phase continuing from the resolved model.
- #[serde(rename = "follow_up")]
- FollowUp,
+pub enum FusionPhaseActivityKind {
+ /// The provider produced additional private output bytes.
+ #[serde(rename = "model_output")]
+ ModelOutput,
+ /// A tool began executing inside the phase.
+ #[serde(rename = "tool_started")]
+ ToolStarted,
+ /// A tool finished executing inside the phase.
+ #[serde(rename = "tool_completed")]
+ ToolCompleted,
/// Unknown variant for forward compatibility.
#[default]
#[serde(other)]
@@ -8302,6 +8543,21 @@ pub enum SkillSource {
Unknown,
}
+/// Whether configured models are advisory preferences or required constraints
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum AgentModelPolicy {
+ /// Treat the authored models as advisory preferences that callers may override.
+ #[serde(rename = "preferred")]
+ Preferred,
+ /// Require subagent execution to use one of the authored models.
+ #[serde(rename = "required")]
+ Required,
+ /// Unknown variant for forward compatibility.
+ #[default]
+ #[serde(other)]
+ Unknown,
+}
+
/// Configuration source: user, workspace, plugin, or builtin
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum McpServerSource {
diff --git a/rust/tests/api_types_test.rs b/rust/tests/api_types_test.rs
index 8ed40e7c76..194457c273 100644
--- a/rust/tests/api_types_test.rs
+++ b/rust/tests/api_types_test.rs
@@ -5,8 +5,9 @@
use github_copilot_sdk::AutoTier;
use github_copilot_sdk::rpc::{
- Extension, ExtensionList, ExtensionSource, ExtensionStatus, ExtensionsDisableRequest,
- ExtensionsEnableRequest, FleetStartRequest, FleetStartResult, TasksStartAgentRequest,
+ CatalogCandidate, CatalogCandidateSource, CatalogSearchResult, Extension, ExtensionList,
+ ExtensionSource, ExtensionStatus, ExtensionsDisableRequest, ExtensionsEnableRequest,
+ FleetStartRequest, FleetStartResult, TasksStartAgentRequest,
};
use github_copilot_sdk::session_events::{
PermissionRequest, PermissionRequestedData, SessionEventData, TypedSessionEvent,
@@ -146,6 +147,83 @@ fn permission_event_exposes_managed_approval_required() {
assert_eq!(request.managed_approval_required, Some(true));
}
+#[test]
+fn catalog_search_deserializes_typed_candidates_handles_and_refusals() {
+ let result: CatalogSearchResult = serde_json::from_value(serde_json::json!({
+ "kind": "succeeded",
+ "searchId": "search-1",
+ "candidates": [
+ {
+ "kind": "mcp-server",
+ "handle": "mcp-handle",
+ "handleExpiresAt": "2026-09-02T12:00:00Z",
+ "mediaType": "application/mcp-server-card+json",
+ "installability": "installable",
+ "displayName": "Example MCP",
+ "source": {"kind": "url", "url": "https://example.com/mcp.json"},
+ "provenance": {
+ "authority": "example.com",
+ "observedAt": "2026-09-02T11:00:00Z",
+ "mediaType": "application/mcp-server-card+json"
+ }
+ },
+ {
+ "kind": "ai-skill",
+ "handle": "skill-handle",
+ "handleExpiresAt": "2026-09-02T12:00:00Z",
+ "mediaType": "application/ai-skill",
+ "installability": "not-installable-kind",
+ "displayName": "Example skill",
+ "source": {"kind": "embedded"},
+ "provenance": {
+ "authority": "example.com",
+ "observedAt": "2026-09-02T11:00:00Z",
+ "mediaType": "application/ai-skill"
+ }
+ }
+ ],
+ "truncated": false,
+ "negotiated": {
+ "runtimeProtocolVersion": 1,
+ "grantedCapabilities": ["mcp-server-card", "ai-skill-discovery"]
+ }
+ }))
+ .unwrap();
+
+ let CatalogSearchResult::Succeeded(success) = result else {
+ panic!("expected successful catalogue search");
+ };
+ let CatalogCandidate::McpServer(mcp_candidate) = &success.candidates[0] else {
+ panic!("expected MCP server candidate");
+ };
+ assert_eq!(mcp_candidate.handle, "mcp-handle");
+ assert!(matches!(
+ mcp_candidate.source,
+ CatalogCandidateSource::Url(_)
+ ));
+ let CatalogCandidate::AiSkill(skill_candidate) = &success.candidates[1] else {
+ panic!("expected AI skill candidate");
+ };
+ assert_eq!(skill_candidate.handle, "skill-handle");
+ assert!(matches!(
+ skill_candidate.source,
+ CatalogCandidateSource::Embedded(_)
+ ));
+ assert_eq!(
+ serde_json::to_value(&skill_candidate.source).unwrap(),
+ serde_json::json!({"kind": "embedded"})
+ );
+
+ let refusal: CatalogSearchResult = serde_json::from_value(serde_json::json!({
+ "kind": "unsupported-kind",
+ "message": "AI skills are unavailable",
+ "requestedKinds": ["ai-skill"],
+ "supportedKinds": ["mcp-server"]
+ }))
+ .unwrap();
+ assert!(matches!(refusal, CatalogSearchResult::UnsupportedKind(_)));
+}
+
fn running_extension(id: &str, name: &str) -> Extension {
Extension {
id: id.to_string(),
diff --git a/rust/tests/cli_resolution_test.rs b/rust/tests/cli_resolution_test.rs
index 75773a0c0d..4d19aedf78 100644
--- a/rust/tests/cli_resolution_test.rs
+++ b/rust/tests/cli_resolution_test.rs
@@ -250,7 +250,12 @@ fn pin_file_when_present_is_well_formed() {
}
}
assert!(saw_version, "{filename} missing `version=` line");
- assert_eq!(package_count, 6);
+ let expected_package_count = if cfg!(feature = "bundled-in-process") {
+ 8
+ } else {
+ 6
+ };
+ assert_eq!(package_count, expected_package_count);
}
/// With `bundled-cli` on AND a supported target, `install_bundled_cli`
diff --git a/rust/tests/e2e/rpc_session_state_extras.rs b/rust/tests/e2e/rpc_session_state_extras.rs
index 81901d06ae..d89f2c8d72 100644
--- a/rust/tests/e2e/rpc_session_state_extras.rs
+++ b/rust/tests/e2e/rpc_session_state_extras.rs
@@ -495,6 +495,7 @@ async fn should_update_and_clear_live_subagent_settings() {
),
effort_level: Some("low".to_string()),
model: Some("gpt-5-mini".to_string()),
+ model_policy: None,
},
)])),
disabled_subagents: Some(vec!["legacy-agent".to_string()]),
diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts
index d4be520fe7..f53a61aed1 100644
--- a/scripts/codegen/python.ts
+++ b/scripts/codegen/python.ts
@@ -413,6 +413,7 @@ function postProcessRefBasedDiscriminatedUnionsForPython(
const acronymCandidates = (name: string): string[] => {
const substitutions: Array<[RegExp, string]> = [
[/Api/g, "API"],
+ [/Ai/g, "AI"],
[/Mcp/g, "MCP"],
[/Url/g, "URL"],
[/Json/g, "JSON"],
diff --git a/scripts/codegen/rust.ts b/scripts/codegen/rust.ts
index 0feec5e98a..a14be1a5cf 100644
--- a/scripts/codegen/rust.ts
+++ b/scripts/codegen/rust.ts
@@ -377,11 +377,7 @@ function tryEmitRustUnion(
}
const lines: string[] = [];
- if (schema.description) {
- for (const line of schema.description.split(/\r?\n/)) {
- lines.push(`/// ${line}`);
- }
- }
+ pushRustDoc(lines, schema.description);
pushRustExperimentalDocs(lines, isSchemaExperimental(schema) || ctx.experimentalTypeNames.has(enumName));
lines.push("#[derive(Debug, Clone, Serialize, Deserialize)]");
lines.push("#[serde(untagged)]");
@@ -468,7 +464,13 @@ function pushRustExperimentalDocs(
function pushRustDoc(lines: string[], text: string | undefined, indent = ""): void {
if (!text) return;
- for (const paragraph of text.trim().split(/\r?\n/)) {
+ const escaped = text
+ .split(/(`[^`]*`)/g)
+ .map((segment, index) => index % 2 === 0
+ ? segment.replace(/\[([^\]]+)\](?!\()/g, "\\[$1\\]")
+ : segment)
+ .join("");
+ for (const paragraph of escaped.trim().split(/\r?\n/)) {
if (paragraph.trim().length === 0) {
lines.push(`${indent}///`);
} else {
@@ -923,11 +925,7 @@ function emitRustStruct(
const required = new Set(schema.required || []);
const lines: string[] = [];
const desc = description || schema.description;
- if (desc) {
- for (const line of desc.split(/\r?\n/)) {
- lines.push(`/// ${line}`);
- }
- }
+ pushRustDoc(lines, desc);
pushRustExperimentalDocs(lines, isSchemaExperimental(schema) || ctx.experimentalTypeNames.has(typeName));
if (isSchemaDeprecated(schema)) {
lines.push(...rustDeprecatedAttributes());
@@ -970,11 +968,7 @@ function emitRustStruct(
lines.push(`${structVis} struct ${typeName} {`);
for (const { propName, prop, isReq, rustField, rustType } of fields) {
- if (prop.description) {
- for (const line of prop.description.split(/\r?\n/)) {
- lines.push(` /// ${line}`);
- }
- }
+ pushRustDoc(lines, prop.description, " ");
pushRustExperimentalDocs(lines, isSchemaExperimental(prop), " ");
const propIsInternal = isSchemaInternal(prop);
if (propIsInternal) {
@@ -1029,11 +1023,7 @@ function emitRustStringEnum(
ctx.generatedNames.add(enumName);
const lines: string[] = [];
- if (description) {
- for (const line of description.split(/\r?\n/)) {
- lines.push(`/// ${line}`);
- }
- }
+ pushRustDoc(lines, description);
pushRustExperimentalDocs(lines, experimental || ctx.experimentalTypeNames.has(enumName));
lines.push(
"#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]",
@@ -1078,11 +1068,7 @@ function emitRustConstStringEnum(
ctx.generatedNames.add(enumName);
const lines: string[] = [];
- if (description) {
- for (const line of description.split(/\r?\n/)) {
- lines.push(`/// ${line}`);
- }
- }
+ pushRustDoc(lines, description);
lines.push(
"#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]",
);
diff --git a/test/harness/package-lock.json b/test/harness/package-lock.json
index 274e70f675..bfd6b558ed 100644
--- a/test/harness/package-lock.json
+++ b/test/harness/package-lock.json
@@ -9,7 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
- "@github/copilot": "^1.0.83-1",
+ "@github/copilot": "^1.0.83-2",
"@modelcontextprotocol/sdk": "^1.26.0",
"@types/node": "^25.3.3",
"@types/node-forge": "^1.3.14",
@@ -472,8 +472,8 @@
}
},
"node_modules/@github/copilot": {
- "version": "1.0.83-1",
- "integrity": "sha512-7rhgbgSx7IgfFYXrTx2/2+qowv6MZjC6BN0mhba37RuGQxsca9Zk2ucAeIX3GbQTp91AhvnN0aHCxabX36xADQ==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-ntRvwGdZbZJjOvdV3LVBQ7z69W19DO4MWe/dh6pP8kYeumbzC4udVj7mCtoSwBOs0hwXirhXY+BZwqSJUp5FLQ==",
"dev": true,
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
@@ -483,19 +483,19 @@
"copilot": "npm-loader.js"
},
"optionalDependencies": {
- "@github/copilot-darwin-arm64": "1.0.83-1",
- "@github/copilot-darwin-x64": "1.0.83-1",
- "@github/copilot-linux-arm64": "1.0.83-1",
- "@github/copilot-linux-x64": "1.0.83-1",
- "@github/copilot-linuxmusl-arm64": "1.0.83-1",
- "@github/copilot-linuxmusl-x64": "1.0.83-1",
- "@github/copilot-win32-arm64": "1.0.83-1",
- "@github/copilot-win32-x64": "1.0.83-1"
+ "@github/copilot-darwin-arm64": "1.0.83-2",
+ "@github/copilot-darwin-x64": "1.0.83-2",
+ "@github/copilot-linux-arm64": "1.0.83-2",
+ "@github/copilot-linux-x64": "1.0.83-2",
+ "@github/copilot-linuxmusl-arm64": "1.0.83-2",
+ "@github/copilot-linuxmusl-x64": "1.0.83-2",
+ "@github/copilot-win32-arm64": "1.0.83-2",
+ "@github/copilot-win32-x64": "1.0.83-2"
}
},
"node_modules/@github/copilot-darwin-arm64": {
- "version": "1.0.83-1",
- "integrity": "sha512-gxYJEd4yoIBIQHRmJw6ZegSkR6VuNm7AJVdAdARcU0SS68VZjtZFT29luThAp75Pxp37S5w+3A/jQNtxGyHizw==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-RBjF/zTJe+gp9PsthYtIHF36+y3A3Zv3w/2FAa9nHF6ople1+lYoQ0OC1z6tWQSpBx3n/fSkNt0ebMmfhWlQyw==",
"cpu": [
"arm64"
],
@@ -510,8 +510,8 @@
}
},
"node_modules/@github/copilot-darwin-x64": {
- "version": "1.0.83-1",
- "integrity": "sha512-PL63+Ib1RH+Bpu2UYJ9E8tmD4NZD/YlhD25F1Q9Rb86AdgLEoRYlxjNxXXF9P9dMmJ/u5zm0rUtWIRxv/FRbPg==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-GzaarluCiHUA4yrYxWIFEklwPLTYjxGvLyYjI0wW5IPseT7GLFjN7AkDGRU4Ny/mxTj1MbUEsJAWVtiNy5EUHg==",
"cpu": [
"x64"
],
@@ -526,12 +526,15 @@
}
},
"node_modules/@github/copilot-linux-arm64": {
- "version": "1.0.83-1",
- "integrity": "sha512-7c4RVEuXQu9zepAWoXwkizpESztUbWUR1hLPl+o+19L+D8fXm+5XQRH5E22Ia7P7/xHW3Ml2o2x5cXFq0k7/7w==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-iGD5Pc7vnzrAjqTK/BrI8MDtMqXyxUe7P6u8TiGt+4DzKe3v2myT6eFQ+z/JJOHNpiu6LUpTDzwS8WttZqqJpA==",
"cpu": [
"arm64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
@@ -542,12 +545,15 @@
}
},
"node_modules/@github/copilot-linux-x64": {
- "version": "1.0.83-1",
- "integrity": "sha512-Be0zUVysLYV66pnOPhMxpShQ8Ox5V07qcsSOoNzG7iwpzkfZuf70U9CHk/fnI//mWwmZR+caPUfVM9BpwrdNnA==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-jOQwz075vRWat+RJiMNtD+7vm4DQ83Dvw4iakpNkLfqWMPXlliVr/tqL+SffeSo87LnhOKobZOJOjELS27drdg==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
@@ -558,12 +564,15 @@
}
},
"node_modules/@github/copilot-linuxmusl-arm64": {
- "version": "1.0.83-1",
- "integrity": "sha512-PZNP8vZZJU8yIc3dNjGUBUCFPNjqZs8FPZLDxvL6XdHM7Ep4cLBa+QdbRsw+nZONIaG0GtQf26eqk5ymYYpUPA==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-6/+ByEBEV/vDofrCymaKrEZ5/p+TVHQfgWu8ywvWEPALfxj/iHpAF3grM2bj7uED4C19LTSarHNCkCqdrAUzIQ==",
"cpu": [
"arm64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
@@ -574,12 +583,15 @@
}
},
"node_modules/@github/copilot-linuxmusl-x64": {
- "version": "1.0.83-1",
- "integrity": "sha512-uKMhGtg5K07nA5/pxDSq8S5F/I+sMgVhUXg90Y4BI9trOidgxpXpCVyh4TeRNj2ENNugPvATdfGc6eFPsjmlgQ==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-8dbiPUHaDemDibLfKXDe5xublJxt6fOht4yYDk/ikmOGAVezBUwRVO27PchXQBwGjP2PVNAASkv2WB4Ubw72lA==",
"cpu": [
"x64"
],
"dev": true,
+ "libc": [
+ "musl"
+ ],
"license": "SEE LICENSE IN LICENSE.md",
"optional": true,
"os": [
@@ -590,8 +602,8 @@
}
},
"node_modules/@github/copilot-win32-arm64": {
- "version": "1.0.83-1",
- "integrity": "sha512-vMxHTmv3SotBuNI4LKcIFckd+n0OvhTik27qjsqOnVqFpvmHDghSsa8YPxySyxUQIE35z5pJaivVBK3dfEAY7w==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-ZE1iUXlJSnNIH+VoRG96emy2e7jMJm85/pcKCrgLvqhDAcQSqiqLVv3OJp2VX2IcDxToOpiaGccU8Ab9zHQqkQ==",
"cpu": [
"arm64"
],
@@ -606,8 +618,8 @@
}
},
"node_modules/@github/copilot-win32-x64": {
- "version": "1.0.83-1",
- "integrity": "sha512-2l0VVTazW3/+p94ZQ5sAPCj1iH7KWxJAYh4yXWfvpsB/1JEEmyVgpLei1MeaMFVdtp/hi9bGprZ9+zWNlHh5hQ==",
+ "version": "1.0.83-2",
+ "integrity": "sha512-qfturLon+1oaWqSaXCISL6BEf5K+ijJFl0m/OZwstWYSlIlaE2+iOz5LcRukoxm25OG1JZDHQFp1k2PY2A+LbA==",
"cpu": [
"x64"
],
diff --git a/test/harness/package.json b/test/harness/package.json
index e293910938..91aaff849a 100644
--- a/test/harness/package.json
+++ b/test/harness/package.json
@@ -14,7 +14,7 @@
"node": "^20.19.0 || >=22.12.0"
},
"devDependencies": {
- "@github/copilot": "^1.0.83-1",
+ "@github/copilot": "^1.0.83-2",
"@modelcontextprotocol/sdk": "^1.26.0",
"@types/node": "^25.3.3",
"@types/node-forge": "^1.3.14",