v0.4.0
microsoft/agent-host-protocolv0.4.0Jun 19, 2026by github-actions[bot]
Upgrading?
Release notes summary
This release implements AHP 0.4.0, introducing a dedicated chat channel (ahp-chat:), robust state reducers for changesets and resource watches, and improved type safety for message origins. It also enhances metadata handling across the protocol and fixes critical encoding bugs in AnyCodable.
Key Highlights
- Introduction of the ahp-chat: channel with full chat lifecycle management (createChat, disposeChat).
- Implementation of missing state reducers (changesetReducer, resourceWatchReducer, annotationsReducer) for state mirroring.
- Type-safe MessageOrigin and MessageKind replacing untyped AnyCodable.
- Enhanced metadata support via the _meta field on various actions and state roots.
- Fixes for AnyCodable encoding corruption of numeric types and unsigned integers.
Breaking Changes
- SessionStatus is now an OptionSet (UInt32) instead of an Int.
- ChangesetOperationTarget range targets now use a nested TextRange struct instead of flat integers.
- ChatState structure flattened; 'summary' removed from state, moved to ChatSummary catalog entry.
- ChatSummary.modifiedAt and ChatState.modifiedAt changed from numeric timestamps to ISO 8601 strings.
- SessionChatsChangedAction removed, replaced by SessionChatAddedAction, SessionChatRemovedAction, and SessionChatUpdatedAction.
New Features
- MessageOrigin struct and MessageKind enum for message origins.
- ConfigPropertySchema.additionalProperties for dynamic object schemas.
- ChangesetContentChangedAction for snapshot operations.
- ChangesetOperation.group and ChangesetOperationStatus.disabled.
- _meta field on per-turn chat actions for provider context.
- SnapshotState.resourceWatch for seeding resource watch descriptors.
- AnnotationsUpdatedAction for partial annotation updates.
- ChatSummary.workingDirectory and interactivity flags.
- ErrorInfo.meta for provider-specific error metadata.
- RootState.meta for implementation-defined host metadata.
Full Release Notes
## [0.4.0] — 2026-06-19
Implements AHP 0.4.0.
### Added
- `MessageOrigin` struct and `MessageKind` enum now type `Message.origin`
(previously an untyped `AnyCodable`); `MessageKind` covers `user`, `agent`,
`tool`, and `systemNotification`, adding faithful agent- and tool-initiated
origins.
- `ConfigPropertySchema.additionalProperties` — optional field describing the
schema for object-typed config properties beyond those in `properties`.
- `ChangesetContentChangedAction` for full-replacement changeset file
snapshots with optional operations and error details.
- `ChangesetOperationStatus.disabled` — new case for changeset operations
that are currently unavailable and cannot be invoked.
- `ChangesetOperation.group` — optional identifier for grouping related
changeset operations together in the UI.
- `_meta` (`meta`) field on the per-turn chat actions (`chat/turnStarted`,
`chat/delta`, `chat/responsePart`, `chat/reasoning`, `chat/usage`,
`chat/turnComplete`, `chat/turnCancelled`, `chat/error`) — optional
provider-specific metadata so hosts can carry portable per-event context,
such as attributing an event to a specific agent (e.g. a sub-agent acting
within the turn).
### Changed
- `ToolResultSubagentContent.resource` is now specified as the spawned worker
**chat** URI (`ahp-chat:/<cid>`), not a session URI — a tool-spawned
sub-agent is a chat. Its doc now describes the correspondence with the worker
chat's `ChatOrigin.tool` record (matching `toolCallId`), which remains the
canonical representation of the spawn relationship.
- **BREAKING:** `SessionStatus` is now an `OptionSet` with a `UInt32` rawValue
(was `Int`), an unsigned 32-bit bitset that preserves combined and unknown
forward-compat bits. Combine flags with set-union (`∪` / `union`) and test
membership with `contains(_:)`.
- **BREAKING:** `ChangesetOperationTarget`'s range target now carries a nested
`TextRange` (`{start: {line, character}, end: {line, character}}`) instead of
a flat `{start, end}` integer pair.
### Added
- `SnapshotState.resourceWatch` case and matching
`MultiHostStateMirror.resourceWatches` slot, so `applySnapshot(host:snapshot:)`
can seed an `ahp-resource-watch:` channel's descriptor (root URI, recursive
flag, optional includes/excludes) alongside the existing root / session /
terminal / changeset / annotations slots. `reset(host:)` / `reset()` clear
the new slot.
### Fixed
- `AnyCodable.encode` no longer corrupts `NSNumber`-backed `Int`/`Double` values to `Bool`/`Int`. `NSNumber` is now special-cased before the generic Swift type arms, using `CFBooleanGetTypeID()` to distinguish boolean from numeric `NSNumber` instances.
- `AnyCodable.encode(to:)` now preserves unsigned integers above `Int64.max` (encoding `NSNumber` values whose `objCType` is unsigned via `uint64Value` instead of the signed `int64Value` fallback), and the `AnyCodable.swift` template in `scripts/generate-swift.ts` reproduces the full encode/equality logic so regenerating the scaffold no longer reintroduces the bug.
- `MultiHostClient`/host runtime now advertises the generated `SUPPORTED_PROTOCOL_VERSIONS` on `initialize` instead of a stale hard-coded `"0.2.0"`.
- Session reducers now apply `_meta` (`meta`) updates from every
tool-call-scoped action, not only `session/toolCallStart`.
### Added
- `annotationsReducer` implemented; annotations conformance fixtures (210–219) now pass.
- `AnnotationsUpdatedAction` (`annotations/updated`) — partially updates an
existing annotation's `turnId` / `resource` / `range` / `resolved` without
resending its entries. Handled by the annotations reducer (no-op on unknown
id).
- `ahp-chat:` channel for per-chat conversation state; `SessionState.chats[]` catalog; `SessionState.defaultChat?` input-routing hint; `ChatOrigin` provenance union; `createChat` / `disposeChat` commands.
- `SessionChatAddedAction`, `SessionChatRemovedAction`, and `SessionChatUpdatedAction` handling for incremental chat catalog updates.
- `ChatSummary.workingDirectory` — optional per-chat working directory. Falls back to the session's `workingDirectory` when absent.
- `SessionDefaultChatChangedAction` (`session/defaultChatChanged`) — updates `SessionState.defaultChat` to steer new input to the designated chat; absent value clears the hint.
- `ErrorInfo.meta: [String: AnyCodable]?` — optional provider-specific metadata bag on error payloads (serialized as `_meta`), mirroring the existing `meta` field on `UsageInfo` and other protocol types. Clients MAY inspect well-known keys here for richer, localised error UI.
- `RootState` now exposes an optional `_meta` property bag (`meta: [String:
AnyCodable]?`) for implementation-defined agent-host metadata, such as a
well-known `hostBuild` key carrying the host's build version/commit/date.
- `changesetReducer` and `resourceWatchReducer` — the two state reducers
that were missing from the Swift client are now implemented, mirroring the
canonical TypeScript reducers (and the Kotlin/.NET clients). `changesetReducer`
folds `changeset/*` actions into `ChangesetState`; `resourceWatchReducer`
treats `resourceWatch/changed` as a documented event pass-through. The
fixture-driven reducer test no longer silently skips the terminal, changeset,
and resourceWatch fixture families — they now decode and assert, with the
remaining gaps (unknown-discriminant response part; the not-yet-implemented
annotations channel) pinned by an explicit drift tripwire.
### Changed
- `ChatState` is now flat — the previous embedded `summary` has been replaced with inlined `resource` / `title` / `status` / `activity` / `modifiedAt` / `model` / `agent` / `origin` / `workingDirectory` properties. `ChatSummary` remains as the standalone catalog entry on `SessionState.chats`.
- `ChatSummary.modifiedAt` and `ChatState.modifiedAt` are now ISO 8601 `String` values instead of `Int64`/`UInt64` milliseconds.
### Added
- `ChatSummary.interactivity` / `ChatState.interactivity` (`"full" | "read-only" | "hidden"`) indicating how the user can interact with a chat. Absent defaults to `"full"`.
### Removed
- `SessionChatsChangedAction` (replaced by the three discrete chat-catalog actions above).
### Fixed
- Encode-fidelity: an unknown `StateAction` variant no longer re-encodes to
`{}` (dropping its `type` discriminant and extra fields); the raw payload is
preserved on decode and re-emitted verbatim.
- Forward-compatibility: unknown discriminants on wire-decoded discriminated
unions (`ResponsePart`, `ToolCallState`, `TerminalClaim`,
`TerminalContentPart`, `Customization`, and other evolvable unions) now decode
to a raw passthrough and re-encode verbatim instead of throwing
`DecodingError`, so a snapshot carrying an unknown variant still decodes and
subsequent actions fold correctly.
- `ChangesetOperationResourceTarget` / `…RangeTarget` now encode their `kind`
discriminant (previously a computed property excluded from `CodingKeys`, so it
was dropped on encode).
Related Repositories
The AI that really does things. Any OS. Any Platform. The lobster way. 🦞
Reverse engineer anything with agents, from app behavior down to native binaries.
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
The open source coding agent.
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.