From 08fa81eca443c2752df20b2e24560b8da32fa62d Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Tue, 7 Jul 2026 05:58:32 -0500 Subject: [PATCH] Add optional _meta slot to SystemNotificationResponsePart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SystemNotificationResponsePart previously conveyed a harness event as human-readable `content` only, so a client could not categorize, icon, group, filter, or localize these parts without string-matching prose. Add the standard `_meta?: Record` escape hatch — consistent with the MCP `_meta` convention already used across AHP state carriers (Message, ChatState, SessionState, RootState, ToolDefinition, etc.) and with the doctrine's explicit-escape-hatch principle. Purely additive and optional: minimal clients ignore it and still render from `content`; hosts that omit it stay compliant. Regenerate the schema and all five client mirrors, document the part (previously missing) in the Response Parts section of the state model guide, and add the entry to the spec and per-client CHANGELOGs. Closes #307 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 4 ++++ clients/go/CHANGELOG.md | 3 +++ clients/go/ahptypes/state.generated.go | 8 ++++++++ clients/kotlin/CHANGELOG.md | 3 +++ .../generated/State.generated.kt | 13 ++++++++++++- clients/rust/CHANGELOG.md | 3 +++ clients/rust/crates/ahp-types/src/state.rs | 9 +++++++++ .../Generated/State.generated.swift | 18 +++++++++++++++++- clients/swift/CHANGELOG.md | 3 +++ clients/typescript/CHANGELOG.md | 3 +++ docs/guide/state-model.md | 10 ++++++++++ schema/actions.schema.json | 5 +++++ schema/commands.schema.json | 5 +++++ schema/errors.schema.json | 5 +++++ schema/notifications.schema.json | 5 +++++ schema/state.schema.json | 5 +++++ types/channels-chat/state.ts | 10 ++++++++++ 17 files changed, 110 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cd99323..97c17627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,10 @@ Spec version: `0.5.2` - `disableUserInvocation` on `SkillCustomization`, plus `disableModelInvocation` and `disableUserInvocation` on `AgentCustomization`, giving custom agents and skills a symmetric user/model invocation matrix. +- Optional `_meta` slot on `SystemNotificationResponsePart`, following the MCP + `_meta` convention. A host MAY attach a machine-readable descriptor of what + triggered the notification so clients can categorize, icon, group, filter, or + localize it without parsing `content`. ### Changed diff --git a/clients/go/CHANGELOG.md b/clients/go/CHANGELOG.md index 75f985ac..7c869515 100644 --- a/clients/go/CHANGELOG.md +++ b/clients/go/CHANGELOG.md @@ -25,6 +25,9 @@ Implements AHP 0.5.2. `RuleCustomization`, `HookCustomization`). - `DisableUserInvocation` on `SkillCustomization`, plus `DisableModelInvocation` and `DisableUserInvocation` on `AgentCustomization`. +- `SystemNotificationResponsePart.Meta` (wire `_meta`) — optional + provider-specific metadata bag (`map[string]json.RawMessage`) carrying a + machine-readable descriptor of what triggered the notification. ### Changed diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index 878c7787..9b79a7fc 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -1643,6 +1643,14 @@ type SystemNotificationResponsePart struct { Kind ResponsePartKind `json:"kind"` // The text of the system notification Content StringOrMarkdown `json:"content"` + // Additional provider-specific metadata for this notification. + // + // A host MAY attach a machine-readable descriptor of what triggered the + // notification so clients can categorize, icon, group, filter, or localize + // it without parsing `content`. Clients MAY look for well-known keys here to + // provide enhanced UI, and MUST render coherently from `content` alone when + // `_meta` is absent or unrecognized. + Meta map[string]json.RawMessage `json:"_meta,omitempty"` } // Tool execution result details, available after execution completes. diff --git a/clients/kotlin/CHANGELOG.md b/clients/kotlin/CHANGELOG.md index c58f26c6..09ec35a1 100644 --- a/clients/kotlin/CHANGELOG.md +++ b/clients/kotlin/CHANGELOG.md @@ -26,6 +26,9 @@ Implements AHP 0.5.2. `RuleCustomization`, `HookCustomization`). - `disableUserInvocation` on `SkillCustomization`, plus `disableModelInvocation` and `disableUserInvocation` on `AgentCustomization`. +- `SystemNotificationResponsePart.meta` (serialized as `_meta`) — optional + provider-specific metadata bag (`Map?`) carrying a + machine-readable descriptor of what triggered the notification. ### Changed diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt index dd5fd328..6d88c2b4 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt @@ -2285,7 +2285,18 @@ data class SystemNotificationResponsePart( /** * The text of the system notification */ - val content: StringOrMarkdown + val content: StringOrMarkdown, + /** + * Additional provider-specific metadata for this notification. + * + * A host MAY attach a machine-readable descriptor of what triggered the + * notification so clients can categorize, icon, group, filter, or localize + * it without parsing `content`. Clients MAY look for well-known keys here to + * provide enhanced UI, and MUST render coherently from `content` alone when + * `_meta` is absent or unrecognized. + */ + @SerialName("_meta") + val meta: Map? = null ) @Serializable diff --git a/clients/rust/CHANGELOG.md b/clients/rust/CHANGELOG.md index 2dc2620e..2bb57a44 100644 --- a/clients/rust/CHANGELOG.md +++ b/clients/rust/CHANGELOG.md @@ -27,6 +27,9 @@ Implements AHP 0.5.2. - `disable_user_invocation` on `SkillCustomization`, plus `disable_model_invocation` and `disable_user_invocation` on `AgentCustomization`. +- `SystemNotificationResponsePart.meta` (`_meta` on the wire) — optional + provider-specific metadata bag (`Option`) carrying a + machine-readable descriptor of what triggered the notification. ### Changed diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index 98a07dcf..2505b967 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -2058,6 +2058,15 @@ pub struct ReasoningResponsePart { pub struct SystemNotificationResponsePart { /// The text of the system notification pub content: StringOrMarkdown, + /// Additional provider-specific metadata for this notification. + /// + /// A host MAY attach a machine-readable descriptor of what triggered the + /// notification so clients can categorize, icon, group, filter, or localize + /// it without parsing `content`. Clients MAY look for well-known keys here to + /// provide enhanced UI, and MUST render coherently from `content` alone when + /// `_meta` is absent or unrecognized. + #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] + pub meta: Option, } /// Tool execution result details, available after execution completes. diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index 8c516563..1d2d2f2a 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -2289,13 +2289,29 @@ public struct SystemNotificationResponsePart: Codable, Sendable { public var kind: ResponsePartKind /// The text of the system notification public var content: StringOrMarkdown + /// Additional provider-specific metadata for this notification. + /// + /// A host MAY attach a machine-readable descriptor of what triggered the + /// notification so clients can categorize, icon, group, filter, or localize + /// it without parsing `content`. Clients MAY look for well-known keys here to + /// provide enhanced UI, and MUST render coherently from `content` alone when + /// `_meta` is absent or unrecognized. + public var meta: [String: AnyCodable]? + + enum CodingKeys: String, CodingKey { + case kind + case content + case meta = "_meta" + } public init( kind: ResponsePartKind, - content: StringOrMarkdown + content: StringOrMarkdown, + meta: [String: AnyCodable]? = nil ) { self.kind = kind self.content = content + self.meta = meta } } diff --git a/clients/swift/CHANGELOG.md b/clients/swift/CHANGELOG.md index 78aa42b2..ad6cc24a 100644 --- a/clients/swift/CHANGELOG.md +++ b/clients/swift/CHANGELOG.md @@ -28,6 +28,9 @@ Implements AHP 0.5.2. `RuleCustomization`, `HookCustomization`). - `disableUserInvocation` on `SkillCustomization`, plus `disableModelInvocation` and `disableUserInvocation` on `AgentCustomization`. +- `SystemNotificationResponsePart.meta` (serialized as `_meta`) — optional + provider-specific metadata bag (`[String: AnyCodable]?`) carrying a + machine-readable descriptor of what triggered the notification. ### Changed diff --git a/clients/typescript/CHANGELOG.md b/clients/typescript/CHANGELOG.md index f1774f66..eed15acc 100644 --- a/clients/typescript/CHANGELOG.md +++ b/clients/typescript/CHANGELOG.md @@ -31,6 +31,9 @@ Implements AHP 0.5.2. `RuleCustomization`, `HookCustomization`). - `disableUserInvocation` on `SkillCustomization`, plus `disableModelInvocation` and `disableUserInvocation` on `AgentCustomization`. +- `SystemNotificationResponsePart._meta?: Record` — optional + provider-specific metadata bag carrying a machine-readable descriptor of what + triggered the notification, following the existing `_meta` convention. ### Changed diff --git a/docs/guide/state-model.md b/docs/guide/state-model.md index b3dd56ae..3ca026e1 100644 --- a/docs/guide/state-model.md +++ b/docs/guide/state-model.md @@ -290,8 +290,18 @@ ContentRef { sizeHint?: number mimeType?: string } + +// A system notification surfaced in the response stream — an out-of-band +// harness event (e.g. "background subagent completed", "task cancelled") +SystemNotificationResponsePart { + kind: 'systemNotification' + content: StringOrMarkdown // human-readable notification text + _meta?: Record // machine-readable trigger metadata; see below +} ``` +`SystemNotificationResponsePart._meta` carries provider-specific metadata describing what triggered the notification. A host MAY attach a machine-readable descriptor so clients can categorize, icon, group, filter, or localize the notification without parsing `content`. Clients MAY inspect well-known keys for enhanced UI, and MUST render coherently from `content` alone when `_meta` is absent or unrecognized. + Text content uses a **create-then-append** pattern: the server first emits a `session/responsePart` action to create a new markdown (or reasoning) part with an `id`, then streams text into it via `session/delta` (or `session/reasoning`) actions targeting that `partId`. This pattern is extensible to future streaming content types. Clients fetch `ContentRef` content separately via the `resourceRead(uri)` command. This keeps the state tree small and serializable. diff --git a/schema/actions.schema.json b/schema/actions.schema.json index 54030ef2..451534b7 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -5078,6 +5078,11 @@ "content": { "$ref": "#/$defs/StringOrMarkdown", "description": "The text of the system notification" + }, + "_meta": { + "type": "object", + "additionalProperties": {}, + "description": "Additional provider-specific metadata for this notification.\n\nA host MAY attach a machine-readable descriptor of what triggered the\nnotification so clients can categorize, icon, group, filter, or localize\nit without parsing `content`. Clients MAY look for well-known keys here to\nprovide enhanced UI, and MUST render coherently from `content` alone when\n`_meta` is absent or unrecognized." } }, "required": [ diff --git a/schema/commands.schema.json b/schema/commands.schema.json index f260b622..3c17cf05 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -4390,6 +4390,11 @@ "content": { "$ref": "#/$defs/StringOrMarkdown", "description": "The text of the system notification" + }, + "_meta": { + "type": "object", + "additionalProperties": {}, + "description": "Additional provider-specific metadata for this notification.\n\nA host MAY attach a machine-readable descriptor of what triggered the\nnotification so clients can categorize, icon, group, filter, or localize\nit without parsing `content`. Clients MAY look for well-known keys here to\nprovide enhanced UI, and MUST render coherently from `content` alone when\n`_meta` is absent or unrecognized." } }, "required": [ diff --git a/schema/errors.schema.json b/schema/errors.schema.json index 53234985..bab8863a 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -3214,6 +3214,11 @@ "content": { "$ref": "#/$defs/StringOrMarkdown", "description": "The text of the system notification" + }, + "_meta": { + "type": "object", + "additionalProperties": {}, + "description": "Additional provider-specific metadata for this notification.\n\nA host MAY attach a machine-readable descriptor of what triggered the\nnotification so clients can categorize, icon, group, filter, or localize\nit without parsing `content`. Clients MAY look for well-known keys here to\nprovide enhanced UI, and MUST render coherently from `content` alone when\n`_meta` is absent or unrecognized." } }, "required": [ diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index f553faab..e31db9fc 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -3374,6 +3374,11 @@ "content": { "$ref": "#/$defs/StringOrMarkdown", "description": "The text of the system notification" + }, + "_meta": { + "type": "object", + "additionalProperties": {}, + "description": "Additional provider-specific metadata for this notification.\n\nA host MAY attach a machine-readable descriptor of what triggered the\nnotification so clients can categorize, icon, group, filter, or localize\nit without parsing `content`. Clients MAY look for well-known keys here to\nprovide enhanced UI, and MUST render coherently from `content` alone when\n`_meta` is absent or unrecognized." } }, "required": [ diff --git a/schema/state.schema.json b/schema/state.schema.json index 7f0e638a..eb4058da 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -3125,6 +3125,11 @@ "content": { "$ref": "#/$defs/StringOrMarkdown", "description": "The text of the system notification" + }, + "_meta": { + "type": "object", + "additionalProperties": {}, + "description": "Additional provider-specific metadata for this notification.\n\nA host MAY attach a machine-readable descriptor of what triggered the\nnotification so clients can categorize, icon, group, filter, or localize\nit without parsing `content`. Clients MAY look for well-known keys here to\nprovide enhanced UI, and MUST render coherently from `content` alone when\n`_meta` is absent or unrecognized." } }, "required": [ diff --git a/types/channels-chat/state.ts b/types/channels-chat/state.ts index 79d9ca7f..16e5a878 100644 --- a/types/channels-chat/state.ts +++ b/types/channels-chat/state.ts @@ -853,6 +853,16 @@ export interface SystemNotificationResponsePart { kind: ResponsePartKind.SystemNotification; /** The text of the system notification */ content: StringOrMarkdown; + /** + * Additional provider-specific metadata for this notification. + * + * A host MAY attach a machine-readable descriptor of what triggered the + * notification so clients can categorize, icon, group, filter, or localize + * it without parsing `content`. Clients MAY look for well-known keys here to + * provide enhanced UI, and MUST render coherently from `content` alone when + * `_meta` is absent or unrecognized. + */ + _meta?: Record; }