From 4ad17803d8b198107218b79bdc709b7cf67c4d06 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 28 Aug 2026 12:51:00 -0700 Subject: [PATCH 1/2] automation: align catalog state naming Rename individual automation state values to AutomationEntry, make AutomationState the channel-level collection with entries, and regenerate all client mirrors. Finalize the coordinated spec and client changelogs and metadata for the 0.9.0 release. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 30 ++++++++++- clients/dotnet/CHANGELOG.md | 7 +-- clients/dotnet/release-metadata.json | 2 +- .../Generated/Actions.generated.cs | 16 +++--- .../Generated/Commands.generated.cs | 12 ++--- .../JsonSerializerContext.generated.cs | 2 +- .../Generated/State.generated.cs | 29 +++++------ .../Generated/Version.generated.cs | 4 +- .../dotnet/src/AgentHostProtocol/Reducers.cs | 12 ++--- .../FixtureDrivenReducerTests.cs | 2 +- clients/go/CHANGELOG.md | 5 +- clients/go/ahp/multi_host_state_mirror.go | 16 +++--- .../go/ahp/multi_host_state_mirror_test.go | 12 ++--- clients/go/ahp/reducers.go | 16 +++--- clients/go/ahp/reducers_fixture_test.go | 2 +- clients/go/ahptypes/actions.generated.go | 16 +++--- clients/go/ahptypes/commands.generated.go | 12 ++--- clients/go/ahptypes/state.generated.go | 43 ++++++++------- clients/go/ahptypes/version.generated.go | 4 +- clients/go/release-metadata.json | 2 +- clients/kotlin/CHANGELOG.md | 5 +- clients/kotlin/release-metadata.json | 2 +- .../microsoft/agenthostprotocol/Reducers.kt | 26 +++++----- .../generated/Actions.generated.kt | 10 ++-- .../generated/Commands.generated.kt | 10 ++-- .../generated/State.generated.kt | 28 +++++----- .../generated/Version.generated.kt | 4 +- .../FixtureDrivenReducerTest.kt | 4 +- clients/rust/CHANGELOG.md | 5 +- clients/rust/crates/ahp-types/src/actions.rs | 18 +++---- clients/rust/crates/ahp-types/src/commands.rs | 12 ++--- clients/rust/crates/ahp-types/src/state.rs | 23 ++++---- clients/rust/crates/ahp-types/src/version.rs | 4 +- .../crates/ahp/src/multi_host_state_mirror.rs | 16 +++--- clients/rust/crates/ahp/src/reducers.rs | 18 +++---- .../ahp/tests/multi_host_state_mirror.rs | 2 +- clients/rust/release-metadata.json | 2 +- .../Generated/Actions.generated.swift | 12 ++--- .../Generated/Commands.generated.swift | 10 ++-- .../Generated/State.generated.swift | 26 +++++----- .../Generated/Version.generated.swift | 4 +- .../Sources/AgentHostProtocol/Reducers.swift | 12 ++--- .../AHPStateMirror.swift | 10 ++-- .../MultiHostStateMirror.swift | 8 +-- .../AHPStateMirrorTests.swift | 12 ++--- .../MultiHostStateMirrorTests.swift | 6 +-- .../FixtureDrivenReducerTests.swift | 2 +- clients/swift/CHANGELOG.md | 5 +- clients/swift/release-metadata.json | 2 +- clients/typescript/CHANGELOG.md | 5 +- clients/typescript/release-metadata.json | 2 +- .../src/client/hosts/state-mirror.ts | 18 +++---- clients/typescript/src/client/state-mirror.ts | 20 +++---- clients/typescript/test/client.test.ts | 8 +-- .../.changes/20260805-shared-automations.json | 7 --- ...-error-response-parts-and-turn-resume.json | 7 --- docs/.changes/20260820-annotation-origin.json | 7 --- .../20260820-changeset-content-error.json | 7 --- ...260820-deterministic-chat-modified-at.json | 7 --- .../20260820-remove-session-fork.json | 7 --- .../20260820-session-lifecycle-failed.json | 7 --- .../20260820-terminal-claim-chat.json | 7 --- .../.changes/20260820-terminal-lifecycle.json | 7 --- .../.changes/20260821-enum-compatibility.json | 7 --- .../20260821-error-code-corrections.json | 7 --- .../20260821-running-tool-call-request.json | 7 --- .../20260826-initialize-result-meta.json | 7 --- docs/guide/automations.md | 10 ++-- docs/specification/automation-channel.md | 10 ++-- docs/specification/overview.md | 2 +- docs/specification/subscriptions.md | 2 +- package-lock.json | 4 +- package.json | 2 +- schema/actions.schema.json | 40 +++++++------- schema/commands.schema.json | 52 +++++++++---------- schema/errors.schema.json | 52 +++++++++---------- schema/notifications.schema.json | 26 +++++----- schema/state.schema.json | 26 +++++----- scripts/generate-csharp.ts | 10 ++-- scripts/generate-go.ts | 10 ++-- scripts/generate-kotlin.ts | 16 +++--- scripts/generate-rust.ts | 8 +-- scripts/generate-swift.ts | 8 +-- types/channels-automation-run/state.ts | 4 +- types/channels-automation/actions.ts | 18 +++---- types/channels-automation/commands.ts | 8 +-- types/channels-automation/reducer.ts | 22 ++++---- types/channels-automation/state.ts | 17 +++--- types/channels-session/state.ts | 4 +- types/common/commands.ts | 8 +-- types/common/state.ts | 4 +- types/reducers.test.ts | 6 +-- .../reducers/263-automation-set-appends.json | 4 +- .../reducers/264-automation-set-replaces.json | 4 +- .../267-automation-removed-removes.json | 4 +- .../reducers/269-automation-removed-noop.json | 4 +- .../270-automation-request-actions-noop.json | 4 +- .../041-automation-catalogue-snapshot.json | 4 +- types/version/registry.test.ts | 6 +-- types/version/registry.ts | 6 +-- 100 files changed, 514 insertions(+), 577 deletions(-) delete mode 100644 docs/.changes/20260805-shared-automations.json delete mode 100644 docs/.changes/20260811-error-response-parts-and-turn-resume.json delete mode 100644 docs/.changes/20260820-annotation-origin.json delete mode 100644 docs/.changes/20260820-changeset-content-error.json delete mode 100644 docs/.changes/20260820-deterministic-chat-modified-at.json delete mode 100644 docs/.changes/20260820-remove-session-fork.json delete mode 100644 docs/.changes/20260820-session-lifecycle-failed.json delete mode 100644 docs/.changes/20260820-terminal-claim-chat.json delete mode 100644 docs/.changes/20260820-terminal-lifecycle.json delete mode 100644 docs/.changes/20260821-enum-compatibility.json delete mode 100644 docs/.changes/20260821-error-code-corrections.json delete mode 100644 docs/.changes/20260821-running-tool-call-request.json delete mode 100644 docs/.changes/20260826-initialize-result-meta.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 2234d4420..c0687a6a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,9 +23,35 @@ changes accumulate. Track in-flight protocol changes via PRs touching `NOTIFICATION_INTRODUCED_IN` maps in [`types/version/registry.ts`](types/version/registry.ts). -## [1.0.0] — Unreleased +## [0.9.0] — 2026-08-28 -Spec version: `1.0.0` +Spec version: `0.9.0` + +### Added + +- Automation catalogue and automation-run channels, including self-contained host-defined event triggers and automation-origin messages, for shared trigger-based agent session workflows. +- Turn errors are durable response parts, and resumable errors can reopen the same turn through `chat/turnResume`. +- `InitializeResult._meta` for hosts to advertise implementation-specific extension capabilities in initialize responses. + +### Changed + +- Annotations now carry an `origin` with a required session URI and optional chat URI and turn ID. +- Renamed the failed session lifecycle value from `creationFailed` to `failed`. +- `TerminalSessionClaim` now requires the chat URI that owns the terminal. +- Terminal state now uses an explicit `running`/`exited` lifecycle that preserves exits without an exit code. +- Generated clients now preserve unknown values for nonexhaustive protocol enums and their discriminated unions. +- `SessionToolClientExecutionRequest.toolCall` is narrowed to a running tool-call state. +- Automation catalogue snapshots now use `AutomationState.entries`, whose items are named `AutomationEntry`. + +### Removed + +- Removed `error` from `changeset/contentChanged`; changeset failures are represented by `changeset/statusChanged`. +- Removed session-level forking from `createSession`; use chat forking instead. +- `ContentNotFound` is no longer an exported AHP error code; `-32006` remains reserved and unassigned. + +### Fixed + +- Chat reducers now derive `modifiedAt` from turn action data instead of local wall clocks. ## [0.8.0] — 2026-08-17 diff --git a/clients/dotnet/CHANGELOG.md b/clients/dotnet/CHANGELOG.md index 21d2d9b23..3752108c7 100644 --- a/clients/dotnet/CHANGELOG.md +++ b/clients/dotnet/CHANGELOG.md @@ -477,15 +477,15 @@ this release negotiates. receive buffer dropped a frame; the receive loop now grows the buffer after copying the previous frame rather than before. -## [0.9.0] — 2026-08-27 +## [0.9.0] — 2026-08-28 -Implements AHP 1.0.0. +Implements AHP 0.9.0. ### Added - Automation catalogue and automation-run channels, including self-contained host-defined event triggers and automation-origin messages, for shared trigger-based agent session workflows. - Turn errors are durable response parts, and resumable errors can reopen the same turn through `chat/turnResume`. -- First-party .NET client with generated AHP 1.0 wire types, reducers, JSON-RPC and multi-host clients, and an integrated WebSocket transport targeting `netstandard2.0` and `net8.0`. (#206, #214) +- First-party .NET client with generated AHP 0.9.0 wire types, reducers, JSON-RPC and multi-host clients, and an integrated WebSocket transport targeting `netstandard2.0` and `net8.0`. (#206, #214) - `ClientConfig.TimeProvider` enables deterministic request timeout, keep-alive, reconnect scheduling, and host timestamps. - `InitializeResult._meta` for hosts to advertise implementation-specific extension capabilities in initialize responses. @@ -499,6 +499,7 @@ Implements AHP 1.0.0. - Generated clients now preserve unknown values for nonexhaustive protocol enums and their discriminated unions. - `SessionToolClientExecutionRequest.toolCall` is narrowed to a running tool-call state. - The .NET client now ships as the signed `Microsoft.VisualStudioCode.AgentHostProtocol` and `Microsoft.VisualStudioCode.AgentHostProtocol.Abstractions` NuGet packages. +- Automation catalogue snapshots now use `AutomationState.entries`, whose items are named `AutomationEntry`. ### Removed diff --git a/clients/dotnet/release-metadata.json b/clients/dotnet/release-metadata.json index 6fbef298a..128ac239f 100644 --- a/clients/dotnet/release-metadata.json +++ b/clients/dotnet/release-metadata.json @@ -2,7 +2,7 @@ "client": "dotnet", "packageVersion": "0.9.0", "supportedProtocolVersions": [ - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Actions.generated.cs b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Actions.generated.cs index b120dce1e..01ee2af4a 100644 --- a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Actions.generated.cs +++ b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Actions.generated.cs @@ -2367,10 +2367,10 @@ public sealed record AutomationCreateRequestedAction { public ActionType Type { get; init; } - /// Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}. + /// Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}. public required string Resource { get; init; } - /// Complete initial {@link AutomationState.definition}. + /// Complete initial {@link AutomationEntry.definition}. public required AutomationDefinition Definition { get; init; } } @@ -2391,7 +2391,7 @@ public sealed record AutomationUpdateRequestedAction { public ActionType Type { get; init; } - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. public required string Resource { get; init; } /// Editable {@link AutomationDefinition} fields to replace. @@ -2399,19 +2399,19 @@ public sealed record AutomationUpdateRequestedAction } /// Add or replace one full automation state in -/// {@link AutomationCatalogState.automations}. +/// {@link AutomationState.entries}. /// -/// Existing entries are matched by {@link AutomationState.resource} and +/// Existing entries are matched by {@link AutomationEntry.resource} and /// replaced in place. A previously unseen resource is appended. public sealed record AutomationSetAction { public ActionType Type { get; init; } /// Full new or replacement automation state. - public required AutomationState Automation { get; init; } + public required AutomationEntry Automation { get; init; } } -/// Remove one automation from {@link AutomationCatalogState.automations}. +/// Remove one automation from {@link AutomationState.entries}. /// /// Clients may dispatch this action only while the target advertises /// {@link AutomationOperation.Remove}. The host revalidates that operation @@ -2423,7 +2423,7 @@ public sealed record AutomationRemovedAction { public ActionType Type { get; init; } - /// {@link AutomationState.resource} to remove. + /// {@link AutomationEntry.resource} to remove. public required string Resource { get; init; } } diff --git a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Commands.generated.cs b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Commands.generated.cs index 2b82c6027..1c69bf740 100644 --- a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Commands.generated.cs +++ b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Commands.generated.cs @@ -214,7 +214,7 @@ public sealed record InitializeResult public TelemetryCapabilities? Telemetry { get; init; } /// Host-owned automation support. Presence means clients may subscribe to - /// `ahp-automations://` for {@link AutomationCatalogState}; absence means the + /// `ahp-automations://` for {@link AutomationState}; absence means the /// host does not expose an automation catalogue or automation commands. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public AutomationCapabilities? Automations { get; init; } @@ -278,7 +278,7 @@ public sealed record ClientCapabilities /// restrictions. /// /// Capabilities describe implementation support. -/// {@link AutomationState.operations} remains authoritative for which +/// {@link AutomationEntry.operations} remains authoritative for which /// definition mutations are currently allowed on a particular automation. public sealed record AutomationCapabilities { @@ -295,7 +295,7 @@ public sealed record AutomationCapabilities [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public AutomationRunCancellationCapability? RunCancellation { get; init; } - /// Maximum terminal entries retained in {@link AutomationState.runs}. Active + /// Maximum terminal entries retained in {@link AutomationEntry.runs}. Active /// runs are not counted toward the limit. Absence means the retention limit is /// implementation-defined. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -1612,7 +1612,7 @@ public sealed record RunAutomationParams [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public Dictionary? Meta { get; init; } - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. public required string Automation { get; init; } /// Durable client-generated idempotency key. Retrying with the same key and @@ -1645,10 +1645,10 @@ public sealed record FetchAutomationRunsParams [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public Dictionary? Meta { get; init; } - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. public required string Automation { get; init; } - /// Cursor previously received as {@link AutomationState.runsNextCursor}. + /// Cursor previously received as {@link AutomationEntry.runsNextCursor}. /// Omit to request the first page not already included by the snapshot. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Cursor { get; init; } diff --git a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/JsonSerializerContext.generated.cs b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/JsonSerializerContext.generated.cs index 545e9b55d..9b1640215 100644 --- a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/JsonSerializerContext.generated.cs +++ b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/JsonSerializerContext.generated.cs @@ -33,12 +33,12 @@ namespace Microsoft.AgentHostProtocol; [JsonSerializable(typeof(AuthRequiredReason))] [JsonSerializable(typeof(AutomationCancelledRunLifecycle))] [JsonSerializable(typeof(AutomationCapabilities))] -[JsonSerializable(typeof(AutomationCatalogState))] [JsonSerializable(typeof(AutomationCompletedRunLifecycle))] [JsonSerializable(typeof(AutomationCreateCapability))] [JsonSerializable(typeof(AutomationCreateRequestedAction))] [JsonSerializable(typeof(AutomationDefinition))] [JsonSerializable(typeof(AutomationDefinitionPatch))] +[JsonSerializable(typeof(AutomationEntry))] [JsonSerializable(typeof(AutomationEventTrigger))] [JsonSerializable(typeof(AutomationFailedRunLifecycle))] [JsonSerializable(typeof(AutomationManualRunOrigin))] diff --git a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/State.generated.cs b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/State.generated.cs index 6f33169f3..5ead9d4cf 100644 --- a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/State.generated.cs +++ b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/State.generated.cs @@ -584,7 +584,7 @@ public enum ResourceChangeType /// Operations the host currently permits for an automation. /// -/// The list on {@link AutomationState.operations} is authoritative and may +/// The list on {@link AutomationEntry.operations} is authoritative and may /// change over time. Clients MUST NOT infer permission from capabilities alone: /// capabilities describe what the host implementation can support, while /// operations describe what is allowed for this particular automation now. @@ -4964,7 +4964,7 @@ public sealed record AutomationSessionOrigin { public SessionOriginKind Kind { get; init; } - /// Owning {@link AutomationState.resource}. + /// Owning {@link AutomationEntry.resource}. public required string Automation { get; init; } /// Owning {@link AutomationRunState.resource}. @@ -5155,7 +5155,7 @@ public sealed record AutomationSessionTemplate /// A definition combines the initial automation message, the session template /// used for each run, and zero or more automatic triggers. Run history, /// timestamps, and currently allowed operations live on -/// {@link AutomationState} rather than in the definition. +/// {@link AutomationEntry} rather than in the definition. public sealed record AutomationDefinition { /// Human-readable automation name. @@ -5216,13 +5216,12 @@ public sealed record AutomationDefinitionPatch public Dictionary? Meta { get; init; } } -/// Authoritative state of one automation in the -/// {@link AutomationCatalogState.automations} catalogue. +/// Authoritative state of one automation in {@link AutomationState.entries}. /// /// The host owns trigger evaluation, run claims, run retention, and operation /// availability. Clients render this state and submit actions or commands; they /// never run a fallback scheduler for a host-owned definition. -public sealed class AutomationState +public sealed class AutomationEntry { /// Stable `ahp-automation:/<id>` resource identifier. public required string Resource { get; set; } @@ -5236,7 +5235,7 @@ public sealed class AutomationState /// Newest-first retained run summaries. This is a bounded window; use /// {@link FetchAutomationRunsParams | fetchAutomationRuns} when - /// {@link AutomationState.runsNextCursor} is present. + /// {@link AutomationEntry.runsNextCursor} is present. public required List Runs { get; set; } /// Opaque cursor passed as {@link FetchAutomationRunsParams.cursor} for the next older run-history page. @@ -5265,10 +5264,10 @@ public sealed class AutomationState /// Subsequent {@link AutomationSetAction | `automation/set`} and /// {@link AutomationRemovedAction | `automation/removed`} actions keep the /// catalogue synchronized and participate in normal reconnect replay. -public sealed class AutomationCatalogState +public sealed class AutomationState { - /// Full automation states keyed by {@link AutomationState.resource}. - public required List Automations { get; set; } + /// Full automation entries keyed by {@link AutomationEntry.resource}. + public required List Entries { get; set; } /// Opaque host-defined catalogue metadata. [JsonPropertyName("_meta")] @@ -5434,7 +5433,7 @@ public sealed class AutomationRunState /// URI of this automation-run channel. public required string Resource { get; set; } - /// Owning `ahp-automation:` URI matching {@link AutomationState.resource}. + /// Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}. public required string Automation { get; set; } /// Immutable provenance describing how this run was created. @@ -6283,7 +6282,7 @@ public sealed class SnapshotState public AnnotationsState? Annotations { get; set; } /// Automation catalogue state variant, when populated. - public AutomationCatalogState? Automations { get; set; } + public AutomationState? Automations { get; set; } /// Automation run state variant, when populated. public AutomationRunState? AutomationRun { get; set; } @@ -6303,9 +6302,9 @@ public override SnapshotState Read(ref Utf8JsonReader reader, Type typeToConvert { result.AutomationRun = root.Deserialize(AhpJsonTypeInfo.Get(options)); } - else if (root.TryGetProperty("automations", out _)) + else if (root.TryGetProperty("entries", out _)) { - result.Automations = root.Deserialize(AhpJsonTypeInfo.Get(options)); + result.Automations = root.Deserialize(AhpJsonTypeInfo.Get(options)); } else if (root.TryGetProperty("turns", out _)) { @@ -6344,7 +6343,7 @@ public override SnapshotState Read(ref Utf8JsonReader reader, Type typeToConvert public override void Write(Utf8JsonWriter writer, SnapshotState value, JsonSerializerOptions options) { if (value.AutomationRun is not null) { JsonSerializer.Serialize(writer, value.AutomationRun, AhpJsonTypeInfo.Get(options)); return; } - if (value.Automations is not null) { JsonSerializer.Serialize(writer, value.Automations, AhpJsonTypeInfo.Get(options)); return; } + if (value.Automations is not null) { JsonSerializer.Serialize(writer, value.Automations, AhpJsonTypeInfo.Get(options)); return; } if (value.Chat is not null) { JsonSerializer.Serialize(writer, value.Chat, AhpJsonTypeInfo.Get(options)); return; } if (value.Session is not null) { JsonSerializer.Serialize(writer, value.Session, AhpJsonTypeInfo.Get(options)); return; } if (value.Terminal is not null) { JsonSerializer.Serialize(writer, value.Terminal, AhpJsonTypeInfo.Get(options)); return; } diff --git a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Version.generated.cs b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Version.generated.cs index 9d07e184a..1f8c3437d 100644 --- a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Version.generated.cs +++ b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Version.generated.cs @@ -14,11 +14,11 @@ public static class ProtocolVersion /// The current protocol version (SemVer MAJOR.MINOR.PATCH) this /// generated source speaks. /// - public const string Current = "1.0.0"; + public const string Current = "0.9.0"; private static readonly string[] s_supported = { - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/dotnet/src/AgentHostProtocol/Reducers.cs b/clients/dotnet/src/AgentHostProtocol/Reducers.cs index 8ad227254..f132f9d83 100644 --- a/clients/dotnet/src/AgentHostProtocol/Reducers.cs +++ b/clients/dotnet/src/AgentHostProtocol/Reducers.cs @@ -2350,7 +2350,7 @@ public static ReduceOutcome ApplyToAnnotations(AnnotationsState state, StateActi /// Applies an action to the automation catalogue in place. public static ReduceOutcome ApplyToAutomation( - AutomationCatalogState state, + AutomationState state, StateAction action) { Guard.ThrowIfNull(state, nameof(state)); @@ -2363,29 +2363,29 @@ public static ReduceOutcome ApplyToAutomation( return ReduceOutcome.NoOp; case AutomationSetAction set: { - int index = state.Automations.FindIndex( + int index = state.Entries.FindIndex( automation => automation.Resource == set.Automation.Resource); if (index < 0) { - state.Automations.Add(set.Automation); + state.Entries.Add(set.Automation); } else { - state.Automations[index] = set.Automation; + state.Entries[index] = set.Automation; } return ReduceOutcome.Applied; } case AutomationRemovedAction removed: { - int index = state.Automations.FindIndex( + int index = state.Entries.FindIndex( automation => automation.Resource == removed.Resource); if (index < 0) { return ReduceOutcome.NoOp; } - state.Automations.RemoveAt(index); + state.Entries.RemoveAt(index); return ReduceOutcome.Applied; } default: diff --git a/clients/dotnet/tests/AgentHostProtocol.Tests/FixtureDrivenReducerTests.cs b/clients/dotnet/tests/AgentHostProtocol.Tests/FixtureDrivenReducerTests.cs index 863b95ce3..4bf9390e4 100644 --- a/clients/dotnet/tests/AgentHostProtocol.Tests/FixtureDrivenReducerTests.cs +++ b/clients/dotnet/tests/AgentHostProtocol.Tests/FixtureDrivenReducerTests.cs @@ -79,7 +79,7 @@ public void ReducerMatchesFixture(string name, string path) RunFixture(initial, expected, actions, Reducers.ApplyToChat); break; case "automation": - RunFixture( + RunFixture( initial, expected, actions, diff --git a/clients/go/CHANGELOG.md b/clients/go/CHANGELOG.md index 06ce6c0a8..36cc79e49 100644 --- a/clients/go/CHANGELOG.md +++ b/clients/go/CHANGELOG.md @@ -14,9 +14,9 @@ tag whose matching `## [X.Y.Z]` heading is missing from this file. ## [Unreleased] -## [0.9.0] — 2026-08-27 +## [0.9.0] — 2026-08-28 -Implements AHP 1.0.0. +Implements AHP 0.9.0. ### Added @@ -32,6 +32,7 @@ Implements AHP 1.0.0. - Terminal state now uses an explicit `running`/`exited` lifecycle that preserves exits without an exit code. - Generated clients now preserve unknown values for nonexhaustive protocol enums and their discriminated unions. - `SessionToolClientExecutionRequest.toolCall` is narrowed to a running tool-call state. +- Automation catalogue snapshots now use `AutomationState.entries`, whose items are named `AutomationEntry`. ### Removed diff --git a/clients/go/ahp/multi_host_state_mirror.go b/clients/go/ahp/multi_host_state_mirror.go index 5810d21d9..a47bf441b 100644 --- a/clients/go/ahp/multi_host_state_mirror.go +++ b/clients/go/ahp/multi_host_state_mirror.go @@ -31,8 +31,8 @@ type MultiHostStateMirror struct { chat map[HostedResourceKey]ahptypes.ChatState term map[HostedResourceKey]ahptypes.TerminalState changes map[HostedResourceKey]ahptypes.ChangesetState - automationCat map[string]ahptypes.AutomationCatalogState - automation map[HostedResourceKey]ahptypes.AutomationState + automationCat map[string]ahptypes.AutomationState + automation map[HostedResourceKey]ahptypes.AutomationEntry automationRun map[HostedResourceKey]ahptypes.AutomationRunState } @@ -44,8 +44,8 @@ func NewMultiHostStateMirror() *MultiHostStateMirror { chat: make(map[HostedResourceKey]ahptypes.ChatState), term: make(map[HostedResourceKey]ahptypes.TerminalState), changes: make(map[HostedResourceKey]ahptypes.ChangesetState), - automationCat: make(map[string]ahptypes.AutomationCatalogState), - automation: make(map[HostedResourceKey]ahptypes.AutomationState), + automationCat: make(map[string]ahptypes.AutomationState), + automation: make(map[HostedResourceKey]ahptypes.AutomationEntry), automationRun: make(map[HostedResourceKey]ahptypes.AutomationRunState), } } @@ -132,7 +132,7 @@ func (m *MultiHostStateMirror) Changeset(hostID string, uri ahptypes.URI) (ahpty // PutAutomationCatalog stores a host's automation catalogue snapshot and // refreshes the per-automation lookup. -func (m *MultiHostStateMirror) PutAutomationCatalog(hostID string, catalog ahptypes.AutomationCatalogState) { +func (m *MultiHostStateMirror) PutAutomationCatalog(hostID string, catalog ahptypes.AutomationState) { m.mu.Lock() defer m.mu.Unlock() m.automationCat[hostID] = catalog @@ -141,13 +141,13 @@ func (m *MultiHostStateMirror) PutAutomationCatalog(hostID string, catalog ahpty delete(m.automation, key) } } - for _, automation := range catalog.Automations { + for _, automation := range catalog.Entries { m.automation[HostedResourceKey{hostID, automation.Resource}] = automation } } // AutomationCatalog returns the automation catalogue for hostID. -func (m *MultiHostStateMirror) AutomationCatalog(hostID string) (ahptypes.AutomationCatalogState, bool) { +func (m *MultiHostStateMirror) AutomationCatalog(hostID string) (ahptypes.AutomationState, bool) { m.mu.RLock() defer m.mu.RUnlock() v, ok := m.automationCat[hostID] @@ -155,7 +155,7 @@ func (m *MultiHostStateMirror) AutomationCatalog(hostID string) (ahptypes.Automa } // Automation returns the automation snapshot at (hostID, uri). -func (m *MultiHostStateMirror) Automation(hostID string, uri ahptypes.URI) (ahptypes.AutomationState, bool) { +func (m *MultiHostStateMirror) Automation(hostID string, uri ahptypes.URI) (ahptypes.AutomationEntry, bool) { m.mu.RLock() defer m.mu.RUnlock() v, ok := m.automation[HostedResourceKey{hostID, uri}] diff --git a/clients/go/ahp/multi_host_state_mirror_test.go b/clients/go/ahp/multi_host_state_mirror_test.go index 418dd93a7..160c8115a 100644 --- a/clients/go/ahp/multi_host_state_mirror_test.go +++ b/clients/go/ahp/multi_host_state_mirror_test.go @@ -11,12 +11,12 @@ func TestMultiHostStateMirrorDropHostWithoutChangesets(t *testing.T) { automationURI := ahptypes.URI("ahp-automation:/nightly") runURI := ahptypes.URI("ahp-automation-run:/nightly/1") - mirror.PutAutomationCatalog("removed", ahptypes.AutomationCatalogState{ - Automations: []ahptypes.AutomationState{{Resource: automationURI}}, + mirror.PutAutomationCatalog("removed", ahptypes.AutomationState{ + Entries: []ahptypes.AutomationEntry{{Resource: automationURI}}, }) mirror.PutAutomationRun("removed", runURI, ahptypes.AutomationRunState{Resource: runURI}) - mirror.PutAutomationCatalog("retained", ahptypes.AutomationCatalogState{ - Automations: []ahptypes.AutomationState{{Resource: automationURI}}, + mirror.PutAutomationCatalog("retained", ahptypes.AutomationState{ + Entries: []ahptypes.AutomationEntry{{Resource: automationURI}}, }) mirror.PutAutomationRun("retained", runURI, ahptypes.AutomationRunState{Resource: runURI}) @@ -44,8 +44,8 @@ func TestMultiHostStateMirrorDropResourceRemovesAutomationCatalogue(t *testing.T automationURI := ahptypes.URI("ahp-automation:/nightly") runURI := ahptypes.URI("ahp-automation-run:/nightly/1") - mirror.PutAutomationCatalog("host", ahptypes.AutomationCatalogState{ - Automations: []ahptypes.AutomationState{{Resource: automationURI}}, + mirror.PutAutomationCatalog("host", ahptypes.AutomationState{ + Entries: []ahptypes.AutomationEntry{{Resource: automationURI}}, }) mirror.PutAutomationRun("host", runURI, ahptypes.AutomationRunState{Resource: runURI}) diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index 445cdd355..6da0af869 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -1854,23 +1854,23 @@ func ApplyActionToResourceWatch(state *ahptypes.ResourceWatchState, action ahpty } // ApplyActionToAutomation applies an action to automation catalogue state. -func ApplyActionToAutomation(state *ahptypes.AutomationCatalogState, action ahptypes.StateAction) ReduceOutcome { +func ApplyActionToAutomation(state *ahptypes.AutomationState, action ahptypes.StateAction) ReduceOutcome { switch a := action.Value.(type) { case *ahptypes.AutomationCreateRequestedAction, *ahptypes.AutomationUpdateRequestedAction: return ReduceOutcomeNoOp case *ahptypes.AutomationSetAction: - for i := range state.Automations { - if state.Automations[i].Resource == a.Automation.Resource { - state.Automations[i] = a.Automation + for i := range state.Entries { + if state.Entries[i].Resource == a.Automation.Resource { + state.Entries[i] = a.Automation return ReduceOutcomeApplied } } - state.Automations = append(state.Automations, a.Automation) + state.Entries = append(state.Entries, a.Automation) return ReduceOutcomeApplied case *ahptypes.AutomationRemovedAction: - for i := range state.Automations { - if state.Automations[i].Resource == a.Resource { - state.Automations = append(state.Automations[:i], state.Automations[i+1:]...) + for i := range state.Entries { + if state.Entries[i].Resource == a.Resource { + state.Entries = append(state.Entries[:i], state.Entries[i+1:]...) return ReduceOutcomeApplied } } diff --git a/clients/go/ahp/reducers_fixture_test.go b/clients/go/ahp/reducers_fixture_test.go index 99c15a726..a1617d4b7 100644 --- a/clients/go/ahp/reducers_fixture_test.go +++ b/clients/go/ahp/reducers_fixture_test.go @@ -154,7 +154,7 @@ func TestFixtureDrivenReducerParity(t *testing.T) { case "resourceWatch": runFixture[ahptypes.ResourceWatchState](tt, fixture.Initial, fixture.Expected, actions, ApplyActionToResourceWatch) case "automation": - runFixture[ahptypes.AutomationCatalogState](tt, fixture.Initial, fixture.Expected, actions, ApplyActionToAutomation) + runFixture[ahptypes.AutomationState](tt, fixture.Initial, fixture.Expected, actions, ApplyActionToAutomation) case "automationRun": runFixture[ahptypes.AutomationRunState](tt, fixture.Initial, fixture.Expected, actions, ApplyActionToAutomationRun) default: diff --git a/clients/go/ahptypes/actions.generated.go b/clients/go/ahptypes/actions.generated.go index d5c8b412a..d940c8bda 100644 --- a/clients/go/ahptypes/actions.generated.go +++ b/clients/go/ahptypes/actions.generated.go @@ -1549,9 +1549,9 @@ type ResourceWatchChangedAction struct { // Rejections leave the catalogue unchanged. type AutomationCreateRequestedAction struct { Type ActionType `json:"type"` - // Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}. + // Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}. Resource URI `json:"resource"` - // Complete initial {@link AutomationState.definition}. + // Complete initial {@link AutomationEntry.definition}. Definition AutomationDefinition `json:"definition"` } @@ -1570,24 +1570,24 @@ type AutomationCreateRequestedAction struct { // server order wins. type AutomationUpdateRequestedAction struct { Type ActionType `json:"type"` - // Target {@link AutomationState.resource}. + // Target {@link AutomationEntry.resource}. Resource URI `json:"resource"` // Editable {@link AutomationDefinition} fields to replace. Changes AutomationDefinitionPatch `json:"changes"` } // Add or replace one full automation state in -// {@link AutomationCatalogState.automations}. +// {@link AutomationState.entries}. // -// Existing entries are matched by {@link AutomationState.resource} and +// Existing entries are matched by {@link AutomationEntry.resource} and // replaced in place. A previously unseen resource is appended. type AutomationSetAction struct { Type ActionType `json:"type"` // Full new or replacement automation state. - Automation AutomationState `json:"automation"` + Automation AutomationEntry `json:"automation"` } -// Remove one automation from {@link AutomationCatalogState.automations}. +// Remove one automation from {@link AutomationState.entries}. // // Clients may dispatch this action only while the target advertises // {@link AutomationOperation.Remove}. The host revalidates that operation @@ -1597,7 +1597,7 @@ type AutomationSetAction struct { // Removing an unknown resource is a no-op. type AutomationRemovedAction struct { Type ActionType `json:"type"` - // {@link AutomationState.resource} to remove. + // {@link AutomationEntry.resource} to remove. Resource URI `json:"resource"` } diff --git a/clients/go/ahptypes/commands.generated.go b/clients/go/ahptypes/commands.generated.go index 2fc55b110..9e7b6d9a4 100644 --- a/clients/go/ahptypes/commands.generated.go +++ b/clients/go/ahptypes/commands.generated.go @@ -177,7 +177,7 @@ type InitializeResult struct { // filtering). Clients MAY ignore signals they cannot process. Telemetry *TelemetryCapabilities `json:"telemetry,omitempty"` // Host-owned automation support. Presence means clients may subscribe to - // `ahp-automations://` for {@link AutomationCatalogState}; absence means the + // `ahp-automations://` for {@link AutomationState}; absence means the // host does not expose an automation catalogue or automation commands. Automations *AutomationCapabilities `json:"automations,omitempty"` } @@ -209,7 +209,7 @@ type ClientCapabilities struct { // restrictions. // // Capabilities describe implementation support. -// {@link AutomationState.operations} remains authoritative for which +// {@link AutomationEntry.operations} remains authoritative for which // definition mutations are currently allowed on a particular automation. type AutomationCapabilities struct { // Present when clients may dispatch {@link AutomationCreateRequestedAction}. @@ -219,7 +219,7 @@ type AutomationCapabilities struct { // Present when clients may request cancellation of `pending` or `running` // automation runs. RunCancellation *AutomationRunCancellationCapability `json:"runCancellation,omitempty"` - // Maximum terminal entries retained in {@link AutomationState.runs}. Active + // Maximum terminal entries retained in {@link AutomationEntry.runs}. Active // runs are not counted toward the limit. Absence means the retention limit is // implementation-defined. RunHistoryLimit *int64 `json:"runHistoryLimit,omitempty"` @@ -1265,7 +1265,7 @@ type RunAutomationParams struct { // Optional JSON-serializable metadata associated with this request. // Receivers MUST ignore keys they do not understand. Meta map[string]json.RawMessage `json:"_meta,omitempty"` - // Target {@link AutomationState.resource}. + // Target {@link AutomationEntry.resource}. Automation URI `json:"automation"` // Durable client-generated idempotency key. Retrying with the same key and // automation MUST return the original run URI rather than create another @@ -1291,9 +1291,9 @@ type FetchAutomationRunsParams struct { // Optional JSON-serializable metadata associated with this request. // Receivers MUST ignore keys they do not understand. Meta map[string]json.RawMessage `json:"_meta,omitempty"` - // Target {@link AutomationState.resource}. + // Target {@link AutomationEntry.resource}. Automation URI `json:"automation"` - // Cursor previously received as {@link AutomationState.runsNextCursor}. + // Cursor previously received as {@link AutomationEntry.runsNextCursor}. // Omit to request the first page not already included by the snapshot. Cursor *string `json:"cursor,omitempty"` } diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index 399c12475..269b50f54 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -473,7 +473,7 @@ const ( // Operations the host currently permits for an automation. // -// The list on {@link AutomationState.operations} is authoritative and may +// The list on {@link AutomationEntry.operations} is authoritative and may // change over time. Clients MUST NOT infer permission from capabilities alone: // capabilities describe what the host implementation can support, while // operations describe what is allowed for this particular automation now. @@ -3749,7 +3749,7 @@ type ResourceChange struct { // for this session's transcript, tools, confirmations, and changes. type AutomationSessionOrigin struct { Kind SessionOriginKind `json:"kind"` - // Owning {@link AutomationState.resource}. + // Owning {@link AutomationEntry.resource}. Automation URI `json:"automation"` // Owning {@link AutomationRunState.resource}. Run URI `json:"run"` @@ -3886,7 +3886,7 @@ type AutomationSessionTemplate struct { // A definition combines the initial automation message, the session template // used for each run, and zero or more automatic triggers. Run history, // timestamps, and currently allowed operations live on -// {@link AutomationState} rather than in the definition. +// {@link AutomationEntry} rather than in the definition. type AutomationDefinition struct { // Human-readable automation name. Title string `json:"title"` @@ -3926,13 +3926,12 @@ type AutomationDefinitionPatch struct { Meta *map[string]json.RawMessage `json:"_meta,omitempty"` } -// Authoritative state of one automation in the -// {@link AutomationCatalogState.automations} catalogue. +// Authoritative state of one automation in {@link AutomationState.entries}. // // The host owns trigger evaluation, run claims, run retention, and operation // availability. Clients render this state and submit actions or commands; they // never run a fallback scheduler for a host-owned definition. -type AutomationState struct { +type AutomationEntry struct { // Stable `ahp-automation:/` resource identifier. Resource URI `json:"resource"` // Current durable definition. @@ -3941,7 +3940,7 @@ type AutomationState struct { NextRunAt *string `json:"nextRunAt,omitempty"` // Newest-first retained run summaries. This is a bounded window; use // {@link FetchAutomationRunsParams | fetchAutomationRuns} when - // {@link AutomationState.runsNextCursor} is present. + // {@link AutomationEntry.runsNextCursor} is present. Runs []AutomationRunSummary `json:"runs"` // Opaque cursor passed as {@link FetchAutomationRunsParams.cursor} for the next older run-history page. RunsNextCursor *string `json:"runsNextCursor,omitempty"` @@ -3962,9 +3961,9 @@ type AutomationState struct { // Subsequent {@link AutomationSetAction | `automation/set`} and // {@link AutomationRemovedAction | `automation/removed`} actions keep the // catalogue synchronized and participate in normal reconnect replay. -type AutomationCatalogState struct { - // Full automation states keyed by {@link AutomationState.resource}. - Automations []AutomationState `json:"automations"` +type AutomationState struct { + // Full automation entries keyed by {@link AutomationEntry.resource}. + Entries []AutomationEntry `json:"entries"` // Opaque host-defined catalogue metadata. Meta map[string]json.RawMessage `json:"_meta,omitempty"` } @@ -4084,7 +4083,7 @@ type AutomationRunSummary struct { type AutomationRunState struct { // URI of this automation-run channel. Resource URI `json:"resource"` - // Owning `ahp-automation:` URI matching {@link AutomationState.resource}. + // Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}. Automation URI `json:"automation"` // Immutable provenance describing how this run was created. Origin AutomationRunOrigin `json:"origin"` @@ -5872,15 +5871,15 @@ func (o ChatOrigin) MarshalJSON() ([]byte, error) { // (automationRun → automations → session → chat → terminal → changeset → // resourceWatch → annotations → root). type SnapshotState struct { - Root *RootState `json:"-"` - Session *SessionState `json:"-"` - Chat *ChatState `json:"-"` - Terminal *TerminalState `json:"-"` - Changeset *ChangesetState `json:"-"` - ResourceWatch *ResourceWatchState `json:"-"` - Annotations *AnnotationsState `json:"-"` - Automations *AutomationCatalogState `json:"-"` - AutomationRun *AutomationRunState `json:"-"` + Root *RootState `json:"-"` + Session *SessionState `json:"-"` + Chat *ChatState `json:"-"` + Terminal *TerminalState `json:"-"` + Changeset *ChangesetState `json:"-"` + ResourceWatch *ResourceWatchState `json:"-"` + Annotations *AnnotationsState `json:"-"` + Automations *AutomationState `json:"-"` + AutomationRun *AutomationRunState `json:"-"` } // MarshalJSON encodes whichever variant is currently populated. @@ -5924,8 +5923,8 @@ func (s *SnapshotState) UnmarshalJSON(data []byte) error { return err } s.AutomationRun = &v - case containsAll(probe, "automations"): - var v AutomationCatalogState + case containsAll(probe, "entries"): + var v AutomationState if err := json.Unmarshal(data, &v); err != nil { return err } diff --git a/clients/go/ahptypes/version.generated.go b/clients/go/ahptypes/version.generated.go index 525967fe8..456d539c8 100644 --- a/clients/go/ahptypes/version.generated.go +++ b/clients/go/ahptypes/version.generated.go @@ -6,13 +6,13 @@ package ahptypes // ProtocolVersion is the current protocol version (SemVer // MAJOR.MINOR.PATCH) that this generated source speaks. -const ProtocolVersion = "1.0.0" +const ProtocolVersion = "0.9.0" // supportedProtocolVersions backs [SupportedProtocolVersions] — held // in an unexported slice so callers cannot accidentally mutate the // shared backing array. var supportedProtocolVersions = []string{ - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/go/release-metadata.json b/clients/go/release-metadata.json index 2534ebc6a..4faee915d 100644 --- a/clients/go/release-metadata.json +++ b/clients/go/release-metadata.json @@ -2,7 +2,7 @@ "client": "go", "packageVersion": "0.9.0", "supportedProtocolVersions": [ - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/kotlin/CHANGELOG.md b/clients/kotlin/CHANGELOG.md index 3413fd5c1..0631c7704 100644 --- a/clients/kotlin/CHANGELOG.md +++ b/clients/kotlin/CHANGELOG.md @@ -15,9 +15,9 @@ versions (`*-SNAPSHOT`) are explicitly rejected by the publish pipeline; bump ## [Unreleased] -## [0.9.0] — 2026-08-27 +## [0.9.0] — 2026-08-28 -Implements AHP 1.0.0. +Implements AHP 0.9.0. ### Added @@ -33,6 +33,7 @@ Implements AHP 1.0.0. - Terminal state now uses an explicit `running`/`exited` lifecycle that preserves exits without an exit code. - Generated clients now preserve unknown values for nonexhaustive protocol enums and their discriminated unions. - `SessionToolClientExecutionRequest.toolCall` is narrowed to a running tool-call state. +- Automation catalogue snapshots now use `AutomationState.entries`, whose items are named `AutomationEntry`. ### Removed diff --git a/clients/kotlin/release-metadata.json b/clients/kotlin/release-metadata.json index 1595b24b1..bdf2a4881 100644 --- a/clients/kotlin/release-metadata.json +++ b/clients/kotlin/release-metadata.json @@ -2,7 +2,7 @@ "client": "kotlin", "packageVersion": "0.9.0", "supportedProtocolVersions": [ - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt index 435e10b1b..87c7493fa 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt @@ -73,8 +73,8 @@ public object ResourceWatchReducer : Reducer { } /** Pure automation reducer as a [Reducer] instance. Delegates to [automationReducer]. */ -public object AutomationReducer : Reducer { - override fun reduce(state: AutomationCatalogState, action: StateAction): AutomationCatalogState = +public object AutomationReducer : Reducer { + override fun reduce(state: AutomationState, action: StateAction): AutomationState = automationReducer(state, action) } @@ -1848,32 +1848,32 @@ public fun resourceWatchReducer(state: ResourceWatchState, action: StateAction): // ─── Automation Reducer ───────────────────────────────────────────────────── -/** Pure reducer for [AutomationCatalogState]. Handles automation-channel action variants. */ -public fun automationReducer(state: AutomationCatalogState, action: StateAction): AutomationCatalogState = when (action) { +/** Pure reducer for [AutomationState]. Handles automation-channel action variants. */ +public fun automationReducer(state: AutomationState, action: StateAction): AutomationState = when (action) { is StateActionAutomationCreateRequested, is StateActionAutomationUpdateRequested, -> state is StateActionAutomationSet -> { val automation = action.value.automation - val index = state.automations.indexOfFirst { it.resource == automation.resource } + val index = state.entries.indexOfFirst { it.resource == automation.resource } if (index < 0) { - state.copy(automations = state.automations + automation) + state.copy(entries = state.entries + automation) } else { - val automations = state.automations.toMutableList() - automations[index] = automation - state.copy(automations = automations) + val entries = state.entries.toMutableList() + entries[index] = automation + state.copy(entries = entries) } } is StateActionAutomationRemoved -> { - val index = state.automations.indexOfFirst { it.resource == action.value.resource } + val index = state.entries.indexOfFirst { it.resource == action.value.resource } if (index < 0) { state } else { - val automations = state.automations.toMutableList() - automations.removeAt(index) - state.copy(automations = automations) + val entries = state.entries.toMutableList() + entries.removeAt(index) + state.copy(entries = entries) } } diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt index 84ae20747..e0326f283 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt @@ -1441,11 +1441,11 @@ data class ResourceWatchChangedAction( data class AutomationCreateRequestedAction( val type: ActionType, /** - * Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}. + * Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}. */ val resource: String, /** - * Complete initial {@link AutomationState.definition}. + * Complete initial {@link AutomationEntry.definition}. */ val definition: AutomationDefinition ) @@ -1454,7 +1454,7 @@ data class AutomationCreateRequestedAction( data class AutomationUpdateRequestedAction( val type: ActionType, /** - * Target {@link AutomationState.resource}. + * Target {@link AutomationEntry.resource}. */ val resource: String, /** @@ -1469,14 +1469,14 @@ data class AutomationSetAction( /** * Full new or replacement automation state. */ - val automation: AutomationState + val automation: AutomationEntry ) @Serializable data class AutomationRemovedAction( val type: ActionType, /** - * {@link AutomationState.resource} to remove. + * {@link AutomationEntry.resource} to remove. */ val resource: String ) diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Commands.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Commands.generated.kt index 14c8ff48c..ad5ac5270 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Commands.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Commands.generated.kt @@ -387,7 +387,7 @@ data class InitializeResult( val telemetry: TelemetryCapabilities? = null, /** * Host-owned automation support. Presence means clients may subscribe to - * `ahp-automations://` for {@link AutomationCatalogState}; absence means the + * `ahp-automations://` for {@link AutomationState}; absence means the * host does not expose an automation catalogue or automation commands. */ val automations: AutomationCapabilities? = null @@ -427,7 +427,7 @@ data class AutomationCapabilities( */ val runCancellation: AutomationRunCancellationCapability? = null, /** - * Maximum terminal entries retained in {@link AutomationState.runs}. Active + * Maximum terminal entries retained in {@link AutomationEntry.runs}. Active * runs are not counted toward the limit. Absence means the retention limit is * implementation-defined. */ @@ -1615,7 +1615,7 @@ data class RunAutomationParams( @SerialName("_meta") val meta: Map? = null, /** - * Target {@link AutomationState.resource}. + * Target {@link AutomationEntry.resource}. */ val automation: String, /** @@ -1647,11 +1647,11 @@ data class FetchAutomationRunsParams( @SerialName("_meta") val meta: Map? = null, /** - * Target {@link AutomationState.resource}. + * Target {@link AutomationEntry.resource}. */ val automation: String, /** - * Cursor previously received as {@link AutomationState.runsNextCursor}. + * Cursor previously received as {@link AutomationEntry.runsNextCursor}. * Omit to request the first page not already included by the snapshot. */ val cursor: String? = null 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 0a3f22707..9fee270bb 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 @@ -1007,7 +1007,7 @@ internal object SessionOriginKindSerializer : KSerializer { /** * Operations the host currently permits for an automation. * - * The list on {@link AutomationState.operations} is authoritative and may + * The list on {@link AutomationEntry.operations} is authoritative and may * change over time. Clients MUST NOT infer permission from capabilities alone: * capabilities describe what the host implementation can support, while * operations describe what is allowed for this particular automation now. @@ -5159,7 +5159,7 @@ data class ResourceChange( data class AutomationSessionOrigin( val kind: SessionOriginKind, /** - * Owning {@link AutomationState.resource}. + * Owning {@link AutomationEntry.resource}. */ val automation: String, /** @@ -5370,7 +5370,7 @@ data class AutomationDefinitionPatch( ) @Serializable -data class AutomationState( +data class AutomationEntry( /** * Stable `ahp-automation:/` resource identifier. */ @@ -5386,7 +5386,7 @@ data class AutomationState( /** * Newest-first retained run summaries. This is a bounded window; use * {@link FetchAutomationRunsParams | fetchAutomationRuns} when - * {@link AutomationState.runsNextCursor} is present. + * {@link AutomationEntry.runsNextCursor} is present. */ val runs: List, /** @@ -5413,11 +5413,11 @@ data class AutomationState( ) @Serializable -data class AutomationCatalogState( +data class AutomationState( /** - * Full automation states keyed by {@link AutomationState.resource}. + * Full automation entries keyed by {@link AutomationEntry.resource}. */ - val automations: List, + val entries: List, /** * Opaque host-defined catalogue metadata. */ @@ -5576,7 +5576,7 @@ data class AutomationRunState( */ val resource: String, /** - * Owning `ahp-automation:` URI matching {@link AutomationState.resource}. + * Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}. */ val automation: String, /** @@ -6964,7 +6964,7 @@ sealed interface SnapshotState { @JvmInline value class Changeset(val value: ChangesetState) : SnapshotState @JvmInline value class ResourceWatch(val value: ResourceWatchState) : SnapshotState @JvmInline value class Annotations(val value: AnnotationsState) : SnapshotState - @JvmInline value class Automations(val value: AutomationCatalogState) : SnapshotState + @JvmInline value class Automations(val value: AutomationState) : SnapshotState @JvmInline value class AutomationRun(val value: AutomationRunState) : SnapshotState } @@ -6979,8 +6979,8 @@ internal object SnapshotStateSerializer : KSerializer { val obj = element as? JsonObject ?: error("Expected JsonObject for SnapshotState") // Try the most distinctive shape first. AutomationRunState has required - // `automation`, `origin`, and `sessions`; AutomationCatalogState has - // required `automations`; SessionState has required + // `automation`, `origin`, and `sessions`; AutomationState has + // required `entries`; SessionState has required // `lifecycle`; ChatState has required `turns`; ChangesetState has // required `status` + `files`; ResourceWatchState has required // `root` + `recursive`; AnnotationsState has required `annotations` @@ -6990,8 +6990,8 @@ internal object SnapshotStateSerializer : KSerializer { return when { obj.containsKey("automation") && obj.containsKey("origin") && obj.containsKey("sessions") -> SnapshotState.AutomationRun(input.json.decodeFromJsonElement(AutomationRunState.serializer(), element)) - obj.containsKey("automations") -> - SnapshotState.Automations(input.json.decodeFromJsonElement(AutomationCatalogState.serializer(), element)) + obj.containsKey("entries") -> + SnapshotState.Automations(input.json.decodeFromJsonElement(AutomationState.serializer(), element)) obj.containsKey("lifecycle") -> SnapshotState.Session(input.json.decodeFromJsonElement(SessionState.serializer(), element)) obj.containsKey("turns") -> SnapshotState.Chat(input.json.decodeFromJsonElement(ChatState.serializer(), element)) obj.containsKey("status") && obj.containsKey("files") -> @@ -7017,7 +7017,7 @@ internal object SnapshotStateSerializer : KSerializer { is SnapshotState.Changeset -> output.json.encodeToJsonElement(ChangesetState.serializer(), value.value) is SnapshotState.ResourceWatch -> output.json.encodeToJsonElement(ResourceWatchState.serializer(), value.value) is SnapshotState.Annotations -> output.json.encodeToJsonElement(AnnotationsState.serializer(), value.value) - is SnapshotState.Automations -> output.json.encodeToJsonElement(AutomationCatalogState.serializer(), value.value) + is SnapshotState.Automations -> output.json.encodeToJsonElement(AutomationState.serializer(), value.value) is SnapshotState.AutomationRun -> output.json.encodeToJsonElement(AutomationRunState.serializer(), value.value) } output.encodeJsonElement(element) diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Version.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Version.generated.kt index c5ee648b7..31c2b348c 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Version.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Version.generated.kt @@ -5,7 +5,7 @@ package com.microsoft.agenthostprotocol.generated /** * Current protocol version (SemVer `MAJOR.MINOR.PATCH`). */ -public const val PROTOCOL_VERSION: String = "1.0.0" +public const val PROTOCOL_VERSION: String = "0.9.0" /** * Every protocol version this library is willing to negotiate, ordered @@ -16,7 +16,7 @@ public const val PROTOCOL_VERSION: String = "1.0.0" * protocol versions if the host doesn't accept the newest one. */ public val SUPPORTED_PROTOCOL_VERSIONS: List = listOf( - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/kotlin/src/test/kotlin/com/microsoft/agenthostprotocol/FixtureDrivenReducerTest.kt b/clients/kotlin/src/test/kotlin/com/microsoft/agenthostprotocol/FixtureDrivenReducerTest.kt index 33cc1053f..c3f4675eb 100644 --- a/clients/kotlin/src/test/kotlin/com/microsoft/agenthostprotocol/FixtureDrivenReducerTest.kt +++ b/clients/kotlin/src/test/kotlin/com/microsoft/agenthostprotocol/FixtureDrivenReducerTest.kt @@ -3,7 +3,7 @@ package com.microsoft.agenthostprotocol import com.microsoft.agenthostprotocol.generated.ChatState import com.microsoft.agenthostprotocol.generated.ChangesetState import com.microsoft.agenthostprotocol.generated.AnnotationsState -import com.microsoft.agenthostprotocol.generated.AutomationCatalogState +import com.microsoft.agenthostprotocol.generated.AutomationState import com.microsoft.agenthostprotocol.generated.AutomationRunState import com.microsoft.agenthostprotocol.generated.ResourceWatchState import com.microsoft.agenthostprotocol.generated.RootState @@ -204,7 +204,7 @@ class FixtureDrivenReducerTest { file = file, initial = initial, expected = expected, - serializer = AutomationCatalogState.serializer(), + serializer = AutomationState.serializer(), run = { state -> var s = state for (action in actions) s = automationReducer(s, action) diff --git a/clients/rust/CHANGELOG.md b/clients/rust/CHANGELOG.md index 356b62153..57980ce35 100644 --- a/clients/rust/CHANGELOG.md +++ b/clients/rust/CHANGELOG.md @@ -15,9 +15,9 @@ matching `## [X.Y.Z]` heading is missing from this file. ## [Unreleased] -## [0.9.0] — 2026-08-27 +## [0.9.0] — 2026-08-28 -Implements AHP 1.0.0. +Implements AHP 0.9.0. ### Added @@ -34,6 +34,7 @@ Implements AHP 1.0.0. - Terminal state now uses an explicit `running`/`exited` lifecycle that preserves exits without an exit code. - Generated clients now preserve unknown values for nonexhaustive protocol enums and their discriminated unions. - `SessionToolClientExecutionRequest.toolCall` is narrowed to a running tool-call state. +- Automation catalogue snapshots now use `AutomationState.entries`, whose items are named `AutomationEntry`. ### Removed diff --git a/clients/rust/crates/ahp-types/src/actions.rs b/clients/rust/crates/ahp-types/src/actions.rs index 4c0b67854..05dba2c2b 100644 --- a/clients/rust/crates/ahp-types/src/actions.rs +++ b/clients/rust/crates/ahp-types/src/actions.rs @@ -14,7 +14,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; #[allow(unused_imports)] use crate::state::{ AgentInfo, AgentSelection, Annotation, AnnotationEntry, AnnotationOrigin, AutomationDefinition, - AutomationDefinitionPatch, AutomationRunLifecycle, AutomationRunSummary, AutomationState, + AutomationDefinitionPatch, AutomationEntry, AutomationRunLifecycle, AutomationRunSummary, Changeset, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, ChangesetStatus, ChatInputAnswer, ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ChatSummary, ConfirmationOption, ContentRef, Customization, CustomizationEnablement, ErrorInfo, @@ -2036,9 +2036,9 @@ pub struct ResourceWatchChangedAction { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AutomationCreateRequestedAction { - /// Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}. + /// Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}. pub resource: Uri, - /// Complete initial {@link AutomationState.definition}. + /// Complete initial {@link AutomationEntry.definition}. pub definition: AutomationDefinition, } @@ -2058,25 +2058,25 @@ pub struct AutomationCreateRequestedAction { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AutomationUpdateRequestedAction { - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. pub resource: Uri, /// Editable {@link AutomationDefinition} fields to replace. pub changes: AutomationDefinitionPatch, } /// Add or replace one full automation state in -/// {@link AutomationCatalogState.automations}. +/// {@link AutomationState.entries}. /// -/// Existing entries are matched by {@link AutomationState.resource} and +/// Existing entries are matched by {@link AutomationEntry.resource} and /// replaced in place. A previously unseen resource is appended. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AutomationSetAction { /// Full new or replacement automation state. - pub automation: AutomationState, + pub automation: AutomationEntry, } -/// Remove one automation from {@link AutomationCatalogState.automations}. +/// Remove one automation from {@link AutomationState.entries}. /// /// Clients may dispatch this action only while the target advertises /// {@link AutomationOperation.Remove}. The host revalidates that operation @@ -2087,7 +2087,7 @@ pub struct AutomationSetAction { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AutomationRemovedAction { - /// {@link AutomationState.resource} to remove. + /// {@link AutomationEntry.resource} to remove. pub resource: Uri, } diff --git a/clients/rust/crates/ahp-types/src/commands.rs b/clients/rust/crates/ahp-types/src/commands.rs index dc8f02b93..37e3b642b 100644 --- a/clients/rust/crates/ahp-types/src/commands.rs +++ b/clients/rust/crates/ahp-types/src/commands.rs @@ -288,7 +288,7 @@ pub struct InitializeResult { #[serde(default, skip_serializing_if = "Option::is_none")] pub telemetry: Option, /// Host-owned automation support. Presence means clients may subscribe to - /// `ahp-automations://` for {@link AutomationCatalogState}; absence means the + /// `ahp-automations://` for {@link AutomationState}; absence means the /// host does not expose an automation catalogue or automation commands. #[serde(default, skip_serializing_if = "Option::is_none")] pub automations: Option, @@ -324,7 +324,7 @@ pub struct ClientCapabilities { /// restrictions. /// /// Capabilities describe implementation support. -/// {@link AutomationState.operations} remains authoritative for which +/// {@link AutomationEntry.operations} remains authoritative for which /// definition mutations are currently allowed on a particular automation. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] @@ -339,7 +339,7 @@ pub struct AutomationCapabilities { /// automation runs. #[serde(default, skip_serializing_if = "Option::is_none")] pub run_cancellation: Option, - /// Maximum terminal entries retained in {@link AutomationState.runs}. Active + /// Maximum terminal entries retained in {@link AutomationEntry.runs}. Active /// runs are not counted toward the limit. Absence means the retention limit is /// implementation-defined. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -1619,7 +1619,7 @@ pub struct RunAutomationParams { /// Receivers MUST ignore keys they do not understand. #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. pub automation: Uri, /// Durable client-generated idempotency key. Retrying with the same key and /// automation MUST return the original run URI rather than create another @@ -1650,9 +1650,9 @@ pub struct FetchAutomationRunsParams { /// Receivers MUST ignore keys they do not understand. #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. pub automation: Uri, - /// Cursor previously received as {@link AutomationState.runsNextCursor}. + /// Cursor previously received as {@link AutomationEntry.runsNextCursor}. /// Omit to request the first page not already included by the snapshot. #[serde(default, skip_serializing_if = "Option::is_none")] pub cursor: Option, diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index 05f70b1e8..6d7ff245a 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -1292,7 +1292,7 @@ impl<'de> serde::Deserialize<'de> for SessionOriginKind { /// Operations the host currently permits for an automation. /// -/// The list on {@link AutomationState.operations} is authoritative and may +/// The list on {@link AutomationEntry.operations} is authoritative and may /// change over time. Clients MUST NOT infer permission from capabilities alone: /// capabilities describe what the host implementation can support, while /// operations describe what is allowed for this particular automation now. @@ -5237,7 +5237,7 @@ pub struct ResourceChange { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AutomationSessionOrigin { - /// Owning {@link AutomationState.resource}. + /// Owning {@link AutomationEntry.resource}. pub automation: Uri, /// Owning {@link AutomationRunState.resource}. pub run: Uri, @@ -5395,7 +5395,7 @@ pub struct AutomationSessionTemplate { /// A definition combines the initial automation message, the session template /// used for each run, and zero or more automatic triggers. Run history, /// timestamps, and currently allowed operations live on -/// {@link AutomationState} rather than in the definition. +/// {@link AutomationEntry} rather than in the definition. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AutomationDefinition { @@ -5446,15 +5446,14 @@ pub struct AutomationDefinitionPatch { pub meta: Option, } -/// Authoritative state of one automation in the -/// {@link AutomationCatalogState.automations} catalogue. +/// Authoritative state of one automation in {@link AutomationState.entries}. /// /// The host owns trigger evaluation, run claims, run retention, and operation /// availability. Clients render this state and submit actions or commands; they /// never run a fallback scheduler for a host-owned definition. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct AutomationState { +pub struct AutomationEntry { /// Stable `ahp-automation:/` resource identifier. pub resource: Uri, /// Current durable definition. @@ -5464,7 +5463,7 @@ pub struct AutomationState { pub next_run_at: Option, /// Newest-first retained run summaries. This is a bounded window; use /// {@link FetchAutomationRunsParams | fetchAutomationRuns} when - /// {@link AutomationState.runsNextCursor} is present. + /// {@link AutomationEntry.runsNextCursor} is present. pub runs: Vec, /// Opaque cursor passed as {@link FetchAutomationRunsParams.cursor} for the next older run-history page. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -5489,9 +5488,9 @@ pub struct AutomationState { /// catalogue synchronized and participate in normal reconnect replay. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct AutomationCatalogState { - /// Full automation states keyed by {@link AutomationState.resource}. - pub automations: Vec, +pub struct AutomationState { + /// Full automation entries keyed by {@link AutomationEntry.resource}. + pub entries: Vec, /// Opaque host-defined catalogue metadata. #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, @@ -5630,7 +5629,7 @@ pub struct AutomationRunSummary { pub struct AutomationRunState { /// URI of this automation-run channel. pub resource: Uri, - /// Owning `ahp-automation:` URI matching {@link AutomationState.resource}. + /// Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}. pub automation: Uri, /// Immutable provenance describing how this run was created. pub origin: AutomationRunOrigin, @@ -6092,7 +6091,7 @@ pub enum SnapshotState { Changeset(Box), ResourceWatch(Box), Annotations(Box), - Automations(Box), + Automations(Box), AutomationRun(Box), Root(Box), } diff --git a/clients/rust/crates/ahp-types/src/version.rs b/clients/rust/crates/ahp-types/src/version.rs index 6bb261243..15cc81d3e 100644 --- a/clients/rust/crates/ahp-types/src/version.rs +++ b/clients/rust/crates/ahp-types/src/version.rs @@ -5,7 +5,7 @@ #![allow(missing_docs)] /// Current protocol version (SemVer `MAJOR.MINOR.PATCH`). -pub const PROTOCOL_VERSION: &str = "1.0.0"; +pub const PROTOCOL_VERSION: &str = "0.9.0"; /// Every protocol version this crate is willing to negotiate, ordered /// most-preferred-first. The first entry equals [`PROTOCOL_VERSION`]. @@ -14,4 +14,4 @@ pub const PROTOCOL_VERSION: &str = "1.0.0"; /// derived `Vec`) so the same client binary can fall back to /// older protocol versions if the host doesn't accept the newest one. pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = - &["1.0.0", "0.8.0", "0.7.0", "0.6.0", "0.5.2", "0.5.1"]; + &["0.9.0", "0.8.0", "0.7.0", "0.6.0", "0.5.2", "0.5.1"]; diff --git a/clients/rust/crates/ahp/src/multi_host_state_mirror.rs b/clients/rust/crates/ahp/src/multi_host_state_mirror.rs index a084de6d5..c581bd26d 100644 --- a/clients/rust/crates/ahp/src/multi_host_state_mirror.rs +++ b/clients/rust/crates/ahp/src/multi_host_state_mirror.rs @@ -39,7 +39,7 @@ use std::collections::HashMap; use ahp_types::actions::ActionEnvelope; use ahp_types::common::ROOT_RESOURCE_URI; use ahp_types::state::{ - AnnotationsState, AutomationCatalogState, AutomationRunState, AutomationState, ChangesetState, + AnnotationsState, AutomationEntry, AutomationRunState, AutomationState, ChangesetState, ChatState, ResourceWatchState, RootState, SessionState, SnapshotState, TerminalState, }; @@ -97,8 +97,8 @@ pub struct MultiHostStateMirror { changesets: HashMap, annotations: HashMap, resource_watches: HashMap, - automation_catalogs: HashMap, - automations: HashMap, + automation_catalogs: HashMap, + automations: HashMap, automation_runs: HashMap, } @@ -144,12 +144,12 @@ impl MultiHostStateMirror { } /// Borrow automation catalogue states keyed by host. - pub fn automation_catalogs(&self) -> &HashMap { + pub fn automation_catalogs(&self) -> &HashMap { &self.automation_catalogs } /// Borrow automation states keyed by `(host_id, uri)`. - pub fn automations(&self) -> &HashMap { + pub fn automations(&self) -> &HashMap { &self.automations } @@ -191,7 +191,7 @@ impl MultiHostStateMirror { if envelope.channel == AUTOMATIONS_RESOURCE_URI { let automations = self.automation_catalogs.get_mut(host).map(|catalog| { apply_action_to_automation(catalog, &envelope.action); - catalog.automations.clone() + catalog.entries.clone() }); if let Some(automations) = automations { self.replace_automations(host, automations); @@ -250,7 +250,7 @@ impl MultiHostStateMirror { } SnapshotState::Automations(state) => { let state = state.as_ref().clone(); - self.replace_automations(host, state.automations.clone()); + self.replace_automations(host, state.entries.clone()); self.automation_catalogs.insert(host.clone(), state); } SnapshotState::AutomationRun(state) => { @@ -289,7 +289,7 @@ impl MultiHostStateMirror { self.automation_runs.clear(); } - fn replace_automations(&mut self, host: &HostId, automations: Vec) { + fn replace_automations(&mut self, host: &HostId, automations: Vec) { self.automations.retain(|key, _| &key.host_id != host); for automation in automations { self.automations.insert( diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index 7abedffb4..0233ec089 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -57,7 +57,7 @@ use ahp_types::actions::{ ChatTurnStartedAction, StateAction, }; use ahp_types::state::{ - ActiveTurn, AnnotationsState, AutomationCatalogState, AutomationRunState, + ActiveTurn, AnnotationsState, AutomationRunState, AutomationState, ChangesetOperationStatus, ChangesetState, ChangesetStatus, ChatInputRequest, ChatState, ChildCustomization, ConfirmationOption, Customization, CustomizationEnablement, ErrorResponsePart, InputRequestResponsePart, McpServerStartingState, McpServerState, @@ -2068,9 +2068,9 @@ pub fn apply_action_to_resource_watch( } } -/// Apply a [`StateAction`] to an [`AutomationCatalogState`] in place. +/// Apply a [`StateAction`] to an [`AutomationState`] in place. pub fn apply_action_to_automation( - state: &mut AutomationCatalogState, + state: &mut AutomationState, action: &StateAction, ) -> ReduceOutcome { match action { @@ -2079,25 +2079,25 @@ pub fn apply_action_to_automation( } StateAction::AutomationSet(a) => { if let Some(index) = state - .automations + .entries .iter() .position(|automation| automation.resource == a.automation.resource) { - state.automations[index] = a.automation.clone(); + state.entries[index] = a.automation.clone(); } else { - state.automations.push(a.automation.clone()); + state.entries.push(a.automation.clone()); } ReduceOutcome::Applied } StateAction::AutomationRemoved(a) => { let Some(index) = state - .automations + .entries .iter() .position(|automation| automation.resource == a.resource) else { return ReduceOutcome::NoOp; }; - state.automations.remove(index); + state.entries.remove(index); ReduceOutcome::Applied } _ => ReduceOutcome::OutOfScope, @@ -2647,7 +2647,7 @@ mod tests { &file_name, description, ), - "automation" => run_fixture::( + "automation" => run_fixture::( initial, expected, &parsed_actions, diff --git a/clients/rust/crates/ahp/tests/multi_host_state_mirror.rs b/clients/rust/crates/ahp/tests/multi_host_state_mirror.rs index f6f60937b..4dd42c919 100644 --- a/clients/rust/crates/ahp/tests/multi_host_state_mirror.rs +++ b/clients/rust/crates/ahp/tests/multi_host_state_mirror.rs @@ -82,7 +82,7 @@ fn automation_snapshot() -> Snapshot { serde_json::from_value(serde_json::json!({ "resource": "ahp-automations://", "state": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "Old", diff --git a/clients/rust/release-metadata.json b/clients/rust/release-metadata.json index a5f778151..b93f3893f 100644 --- a/clients/rust/release-metadata.json +++ b/clients/rust/release-metadata.json @@ -2,7 +2,7 @@ "client": "rust", "packageVersion": "0.9.0", "supportedProtocolVersions": [ - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift index 410137ab1..3abc0a935 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift @@ -2216,9 +2216,9 @@ public struct ResourceWatchChangedAction: Codable, Sendable { public struct AutomationCreateRequestedAction: Codable, Sendable { public var type: ActionType - /// Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}. + /// Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}. public var resource: String - /// Complete initial {@link AutomationState.definition}. + /// Complete initial {@link AutomationEntry.definition}. public var definition: AutomationDefinition public init( @@ -2234,7 +2234,7 @@ public struct AutomationCreateRequestedAction: Codable, Sendable { public struct AutomationUpdateRequestedAction: Codable, Sendable { public var type: ActionType - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. public var resource: String /// Editable {@link AutomationDefinition} fields to replace. public var changes: AutomationDefinitionPatch @@ -2253,11 +2253,11 @@ public struct AutomationUpdateRequestedAction: Codable, Sendable { public struct AutomationSetAction: Codable, Sendable { public var type: ActionType /// Full new or replacement automation state. - public var automation: AutomationState + public var automation: AutomationEntry public init( type: ActionType, - automation: AutomationState + automation: AutomationEntry ) { self.type = type self.automation = automation @@ -2266,7 +2266,7 @@ public struct AutomationSetAction: Codable, Sendable { public struct AutomationRemovedAction: Codable, Sendable { public var type: ActionType - /// {@link AutomationState.resource} to remove. + /// {@link AutomationEntry.resource} to remove. public var resource: String public init( diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Commands.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Commands.generated.swift index 81b975601..bb6ee6827 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Commands.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Commands.generated.swift @@ -338,7 +338,7 @@ public struct InitializeResult: Codable, Sendable { /// filtering). Clients MAY ignore signals they cannot process. public var telemetry: TelemetryCapabilities? /// Host-owned automation support. Presence means clients may subscribe to - /// `ahp-automations://` for {@link AutomationCatalogState}; absence means the + /// `ahp-automations://` for {@link AutomationState}; absence means the /// host does not expose an automation catalogue or automation commands. public var automations: AutomationCapabilities? @@ -409,7 +409,7 @@ public struct AutomationCapabilities: Codable, Sendable { /// Present when clients may request cancellation of `pending` or `running` /// automation runs. public var runCancellation: AutomationRunCancellationCapability? - /// Maximum terminal entries retained in {@link AutomationState.runs}. Active + /// Maximum terminal entries retained in {@link AutomationEntry.runs}. Active /// runs are not counted toward the limit. Absence means the retention limit is /// implementation-defined. public var runHistoryLimit: Int? @@ -1997,7 +1997,7 @@ public struct RunAutomationParams: Codable, Sendable { /// Optional JSON-serializable metadata associated with this request. /// Receivers MUST ignore keys they do not understand. public var meta: [String: AnyCodable]? - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. public var automation: String /// Durable client-generated idempotency key. Retrying with the same key and /// automation MUST return the original run URI rather than create another @@ -2041,9 +2041,9 @@ public struct FetchAutomationRunsParams: Codable, Sendable { /// Optional JSON-serializable metadata associated with this request. /// Receivers MUST ignore keys they do not understand. public var meta: [String: AnyCodable]? - /// Target {@link AutomationState.resource}. + /// Target {@link AutomationEntry.resource}. public var automation: String - /// Cursor previously received as {@link AutomationState.runsNextCursor}. + /// Cursor previously received as {@link AutomationEntry.runsNextCursor}. /// Omit to request the first page not already included by the snapshot. public var cursor: String? diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index 606b399e0..313783d66 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -1000,7 +1000,7 @@ public enum SessionOriginKind: Codable, Sendable, Equatable { /// Operations the host currently permits for an automation. /// -/// The list on {@link AutomationState.operations} is authoritative and may +/// The list on {@link AutomationEntry.operations} is authoritative and may /// change over time. Clients MUST NOT infer permission from capabilities alone: /// capabilities describe what the host implementation can support, while /// operations describe what is allowed for this particular automation now. @@ -6051,7 +6051,7 @@ public struct ResourceChange: Codable, Sendable { public struct AutomationSessionOrigin: Codable, Sendable { public var kind: SessionOriginKind - /// Owning {@link AutomationState.resource}. + /// Owning {@link AutomationEntry.resource}. public var automation: String /// Owning {@link AutomationRunState.resource}. public var run: String @@ -6312,7 +6312,7 @@ public struct AutomationDefinitionPatch: Codable, Sendable { } } -public struct AutomationState: Codable, Sendable { +public struct AutomationEntry: Codable, Sendable { /// Stable `ahp-automation:/` resource identifier. public var resource: String /// Current durable definition. @@ -6321,7 +6321,7 @@ public struct AutomationState: Codable, Sendable { public var nextRunAt: String? /// Newest-first retained run summaries. This is a bounded window; use /// {@link FetchAutomationRunsParams | fetchAutomationRuns} when - /// {@link AutomationState.runsNextCursor} is present. + /// {@link AutomationEntry.runsNextCursor} is present. public var runs: [AutomationRunSummary] /// Opaque cursor passed as {@link FetchAutomationRunsParams.cursor} for the next older run-history page. public var runsNextCursor: String? @@ -6369,22 +6369,22 @@ public struct AutomationState: Codable, Sendable { } } -public struct AutomationCatalogState: Codable, Sendable { - /// Full automation states keyed by {@link AutomationState.resource}. - public var automations: [AutomationState] +public struct AutomationState: Codable, Sendable { + /// Full automation entries keyed by {@link AutomationEntry.resource}. + public var entries: [AutomationEntry] /// Opaque host-defined catalogue metadata. public var meta: [String: AnyCodable]? enum CodingKeys: String, CodingKey { - case automations + case entries case meta = "_meta" } public init( - automations: [AutomationState], + entries: [AutomationEntry], meta: [String: AnyCodable]? = nil ) { - self.automations = automations + self.entries = entries self.meta = meta } } @@ -6583,7 +6583,7 @@ public struct AutomationRunSummary: Codable, Sendable { public struct AutomationRunState: Codable, Sendable { /// URI of this automation-run channel. public var resource: String - /// Owning `ahp-automation:` URI matching {@link AutomationState.resource}. + /// Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}. public var automation: String /// Immutable provenance describing how this run was created. public var origin: AutomationRunOrigin @@ -7726,7 +7726,7 @@ public enum SnapshotState: Codable, Sendable { case changeset(ChangesetState) case resourceWatch(ResourceWatchState) case annotations(AnnotationsState) - case automations(AutomationCatalogState) + case automations(AutomationState) case automationRun(AutomationRunState) public init(from decoder: Decoder) throws { @@ -7746,7 +7746,7 @@ public enum SnapshotState: Codable, Sendable { self = .resourceWatch(resourceWatch) } else if let annotations = try? AnnotationsState(from: decoder) { self = .annotations(annotations) - } else if let automations = try? AutomationCatalogState(from: decoder) { + } else if let automations = try? AutomationState(from: decoder) { self = .automations(automations) } else if let automationRun = try? AutomationRunState(from: decoder) { self = .automationRun(automationRun) diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Version.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Version.generated.swift index 9d92647e4..b85278501 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Version.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Version.generated.swift @@ -3,7 +3,7 @@ import Foundation /// Current protocol version (SemVer `MAJOR.MINOR.PATCH`). -public let PROTOCOL_VERSION: String = "1.0.0" +public let PROTOCOL_VERSION: String = "0.9.0" /// Every protocol version this package is willing to negotiate, /// ordered most-preferred-first. The first entry equals @@ -13,7 +13,7 @@ public let PROTOCOL_VERSION: String = "1.0.0" /// `InitializeParams` so the same client binary can fall back to older /// protocol versions if the host doesn't accept the newest one. public let SUPPORTED_PROTOCOL_VERSIONS: [String] = [ - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift index b7c553842..0d5585cfa 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift @@ -1492,22 +1492,22 @@ public func resourceWatchReducer(state: ResourceWatchState, action: StateAction) } /// Pure reducer for automation catalogue state. -public func automationReducer(state: AutomationCatalogState, action: StateAction) -> AutomationCatalogState { +public func automationReducer(state: AutomationState, action: StateAction) -> AutomationState { var next = state switch action { case .automationCreateRequested, .automationUpdateRequested: return state case .automationSet(let value): - if let index = next.automations.firstIndex(where: { $0.resource == value.automation.resource }) { - next.automations[index] = value.automation + if let index = next.entries.firstIndex(where: { $0.resource == value.automation.resource }) { + next.entries[index] = value.automation } else { - next.automations.append(value.automation) + next.entries.append(value.automation) } case .automationRemoved(let value): - guard let index = next.automations.firstIndex(where: { $0.resource == value.resource }) else { + guard let index = next.entries.firstIndex(where: { $0.resource == value.resource }) else { return state } - next.automations.remove(at: index) + next.entries.remove(at: index) default: return state } diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocolClient/AHPStateMirror.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocolClient/AHPStateMirror.swift index ba09e27da..271684937 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocolClient/AHPStateMirror.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocolClient/AHPStateMirror.swift @@ -18,8 +18,8 @@ public actor AHPStateMirror { public private(set) var changesets: [String: ChangesetState] = [:] public private(set) var annotations: [String: AnnotationsState] = [:] public private(set) var resourceWatches: [String: ResourceWatchState] = [:] - public private(set) var automationCatalog = AutomationCatalogState(automations: []) - public private(set) var automations: [String: AutomationState] = [:] + public private(set) var automationCatalog = AutomationState(entries: []) + public private(set) var automations: [String: AutomationEntry] = [:] public private(set) var automationRuns: [String: AutomationRunState] = [:] public init() {} @@ -106,8 +106,8 @@ public actor AHPStateMirror { } private func rebuildAutomationIndex() { - var indexed: [String: AutomationState] = [:] - for automation in automationCatalog.automations { + var indexed: [String: AutomationEntry] = [:] + for automation in automationCatalog.entries { indexed[automation.resource] = automation } automations = indexed @@ -122,7 +122,7 @@ public actor AHPStateMirror { changesets.removeAll() annotations.removeAll() resourceWatches.removeAll() - automationCatalog = AutomationCatalogState(automations: []) + automationCatalog = AutomationState(entries: []) automations.removeAll() automationRuns.removeAll() } diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocolClient/MultiHostStateMirror.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocolClient/MultiHostStateMirror.swift index 6653d650b..e08fd4015 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocolClient/MultiHostStateMirror.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocolClient/MultiHostStateMirror.swift @@ -49,8 +49,8 @@ public actor MultiHostStateMirror { public private(set) var changesets: [HostedResourceKey: ChangesetState] = [:] public private(set) var annotations: [HostedResourceKey: AnnotationsState] = [:] public private(set) var resourceWatches: [HostedResourceKey: ResourceWatchState] = [:] - public private(set) var automationCatalogs: [HostId: AutomationCatalogState] = [:] - public private(set) var automations: [HostedResourceKey: AutomationState] = [:] + public private(set) var automationCatalogs: [HostId: AutomationState] = [:] + public private(set) var automations: [HostedResourceKey: AutomationEntry] = [:] public private(set) var automationRuns: [HostedResourceKey: AutomationRunState] = [:] public init() {} @@ -176,10 +176,10 @@ public actor MultiHostStateMirror { automationRuns.removeAll() } - private func setAutomationCatalog(host: HostId, catalog: AutomationCatalogState) { + private func setAutomationCatalog(host: HostId, catalog: AutomationState) { automationCatalogs[host] = catalog automations = automations.filter { $0.key.hostId != host } - for automation in catalog.automations { + for automation in catalog.entries { automations[HostedResourceKey(hostId: host, uri: automation.resource)] = automation } } diff --git a/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolClientTests/AHPStateMirrorTests.swift b/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolClientTests/AHPStateMirrorTests.swift index aa1be4a57..7c6d46aab 100644 --- a/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolClientTests/AHPStateMirrorTests.swift +++ b/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolClientTests/AHPStateMirrorTests.swift @@ -45,12 +45,12 @@ final class AHPStateMirrorTests: XCTestCase { func testAutomationIndexUsesLastDuplicateResourceAcrossSnapshotAndAction() async { let mirror = AHPStateMirror() let resource = "ahp-automation:/a1" - let first = makeAutomationState(resource: resource, title: "First") - let latest = makeAutomationState(resource: resource, title: "Latest") + let first = makeAutomationEntry(resource: resource, title: "First") + let latest = makeAutomationEntry(resource: resource, title: "Latest") await mirror.applySnapshot(Snapshot( resource: "ahp-automations://", - state: .automations(AutomationCatalogState(automations: [first, latest])), + state: .automations(AutomationState(entries: [first, latest])), fromSeq: 0 )) @@ -58,7 +58,7 @@ final class AHPStateMirrorTests: XCTestCase { XCTAssertEqual(automations.count, 1) XCTAssertEqual(automations[resource]?.definition.title, "Latest") - let added = makeAutomationState(resource: "ahp-automation:/a2", title: "Added") + let added = makeAutomationEntry(resource: "ahp-automation:/a2", title: "Added") await mirror.apply(ActionEnvelope( channel: "ahp-automations://", action: .automationSet(AutomationSetAction( @@ -137,8 +137,8 @@ final class AHPStateMirrorTests: XCTestCase { } } -private func makeAutomationState(resource: String, title: String) -> AutomationState { - AutomationState( +private func makeAutomationEntry(resource: String, title: String) -> AutomationEntry { + AutomationEntry( resource: resource, definition: AutomationDefinition( title: title, diff --git a/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolClientTests/MultiHostStateMirrorTests.swift b/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolClientTests/MultiHostStateMirrorTests.swift index aed7ee5c2..218f9adfc 100644 --- a/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolClientTests/MultiHostStateMirrorTests.swift +++ b/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolClientTests/MultiHostStateMirrorTests.swift @@ -133,8 +133,8 @@ final class MultiHostStateMirrorTests: XCTestCase { host: "alpha", snapshot: Snapshot( resource: "ahp-automations://", - state: .automations(AutomationCatalogState(automations: [ - AutomationState( + state: .automations(AutomationState(entries: [ + AutomationEntry( resource: automationResource, definition: initialDefinition, nextRunAt: "2026-08-06T12:00:00Z", @@ -168,7 +168,7 @@ final class MultiHostStateMirrorTests: XCTestCase { channel: "ahp-automations://", action: .automationSet(AutomationSetAction( type: .automationSet, - automation: AutomationState( + automation: AutomationEntry( resource: automationResource, definition: makeAutomationDefinition(title: "New"), runs: [], diff --git a/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolTests/FixtureDrivenReducerTests.swift b/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolTests/FixtureDrivenReducerTests.swift index f5eef714f..100ef243c 100644 --- a/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolTests/FixtureDrivenReducerTests.swift +++ b/clients/swift/AgentHostProtocol/Tests/AgentHostProtocolTests/FixtureDrivenReducerTests.swift @@ -197,7 +197,7 @@ final class FixtureDrivenReducerTests: XCTestCase { actions.reduce(state) { annotationsReducer(state: $0, action: $1) } } case "automation": - try compareFixture(file: file, fixture: fixture, stateType: AutomationCatalogState.self) { state in + try compareFixture(file: file, fixture: fixture, stateType: AutomationState.self) { state in actions.reduce(state) { automationReducer(state: $0, action: $1) } } case "automationRun": diff --git a/clients/swift/CHANGELOG.md b/clients/swift/CHANGELOG.md index 444b9144c..d3bd18a09 100644 --- a/clients/swift/CHANGELOG.md +++ b/clients/swift/CHANGELOG.md @@ -17,9 +17,9 @@ the tag matches the version pinned in [`VERSION`](VERSION). ## [Unreleased] -## [0.9.0] — 2026-08-27 +## [0.9.0] — 2026-08-28 -Implements AHP 1.0.0. +Implements AHP 0.9.0. ### Added @@ -35,6 +35,7 @@ Implements AHP 1.0.0. - Terminal state now uses an explicit `running`/`exited` lifecycle that preserves exits without an exit code. - Generated clients now preserve unknown values for nonexhaustive protocol enums and their discriminated unions. - `SessionToolClientExecutionRequest.toolCall` is narrowed to a running tool-call state. +- Automation catalogue snapshots now use `AutomationState.entries`, whose items are named `AutomationEntry`. ### Removed diff --git a/clients/swift/release-metadata.json b/clients/swift/release-metadata.json index 3cf5d06fd..e5693c0d4 100644 --- a/clients/swift/release-metadata.json +++ b/clients/swift/release-metadata.json @@ -2,7 +2,7 @@ "client": "swift", "packageVersion": "0.9.0", "supportedProtocolVersions": [ - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/typescript/CHANGELOG.md b/clients/typescript/CHANGELOG.md index 6bc225912..d8db7cdde 100644 --- a/clients/typescript/CHANGELOG.md +++ b/clients/typescript/CHANGELOG.md @@ -20,9 +20,9 @@ hotfix escape hatch. ## [Unreleased] -## [0.9.0] — 2026-08-27 +## [0.9.0] — 2026-08-28 -Implements AHP 1.0.0. +Implements AHP 0.9.0. ### Added @@ -38,6 +38,7 @@ Implements AHP 1.0.0. - Terminal state now uses an explicit `running`/`exited` lifecycle that preserves exits without an exit code. - Generated clients now preserve unknown values for nonexhaustive protocol enums and their discriminated unions. - `SessionToolClientExecutionRequest.toolCall` is narrowed to a running tool-call state. +- Automation catalogue snapshots now use `AutomationState.entries`, whose items are named `AutomationEntry`. ### Removed diff --git a/clients/typescript/release-metadata.json b/clients/typescript/release-metadata.json index dc05b7b71..1925c9293 100644 --- a/clients/typescript/release-metadata.json +++ b/clients/typescript/release-metadata.json @@ -2,7 +2,7 @@ "client": "typescript", "packageVersion": "0.9.0", "supportedProtocolVersions": [ - "1.0.0", + "0.9.0", "0.8.0", "0.7.0", "0.6.0", diff --git a/clients/typescript/src/client/hosts/state-mirror.ts b/clients/typescript/src/client/hosts/state-mirror.ts index 02bf371dd..50ff617bc 100644 --- a/clients/typescript/src/client/hosts/state-mirror.ts +++ b/clients/typescript/src/client/hosts/state-mirror.ts @@ -42,7 +42,7 @@ import type { ChangesetState } from '../../types/channels-changeset/state.js'; import type { RootState } from '../../types/channels-root/state.js'; import type { SessionState } from '../../types/channels-session/state.js'; import type { TerminalState } from '../../types/channels-terminal/state.js'; -import type { AutomationCatalogState, AutomationState } from '../../types/channels-automation/state.js'; +import type { AutomationEntry, AutomationState } from '../../types/channels-automation/state.js'; import type { AutomationRunState } from '../../types/channels-automation-run/state.js'; import { changesetReducer } from '../../types/channels-changeset/reducer.js'; import { rootReducer } from '../../types/channels-root/reducer.js'; @@ -105,8 +105,8 @@ export class MultiHostStateMirror { private readonly sessionsMap = new Map(); private readonly terminalsMap = new Map(); private readonly changesetsMap = new Map(); - private readonly automationCatalogsMap = new Map(); - private readonly automationsMap = new Map(); + private readonly automationCatalogsMap = new Map(); + private readonly automationsMap = new Map(); private readonly automationRunsMap = new Map(); /** All known root states keyed by host. */ @@ -130,12 +130,12 @@ export class MultiHostStateMirror { } /** Automation catalogue state keyed by host. */ - get automationCatalogs(): ReadonlyMap { + get automationCatalogs(): ReadonlyMap { return this.automationCatalogsMap; } /** Catalogued automations keyed by `hostedResourceKey(hostId, resource)`. */ - get automations(): ReadonlyMap { + get automations(): ReadonlyMap { return this.automationsMap; } @@ -165,7 +165,7 @@ export class MultiHostStateMirror { } /** Look up a catalogued automation by `(hostId, uri)`. */ - getAutomation(hostId: HostId, uri: URI): AutomationState | undefined { + getAutomation(hostId: HostId, uri: URI): AutomationEntry | undefined { return this.automationsMap.get(hostedResourceKey(hostId, uri)); } @@ -255,7 +255,7 @@ export class MultiHostStateMirror { return; } if (resource === AUTOMATIONS_URI) { - this.setAutomationCatalog(hostId, snapshot.state as AutomationCatalogState); + this.setAutomationCatalog(hostId, snapshot.state as AutomationState); return; } if (resource.startsWith('ahp-automation-run:')) { @@ -297,13 +297,13 @@ export class MultiHostStateMirror { this.automationRunsMap.clear(); } - private setAutomationCatalog(hostId: HostId, state: AutomationCatalogState): void { + private setAutomationCatalog(hostId: HostId, state: AutomationState): void { this.automationCatalogsMap.set(hostId, state); const prefix = hostedResourceKeyPrefix(hostId); for (const key of this.automationsMap.keys()) { if (key.startsWith(prefix)) this.automationsMap.delete(key); } - for (const automation of state.automations) { + for (const automation of state.entries) { this.automationsMap.set(hostedResourceKey(hostId, automation.resource), automation); } } diff --git a/clients/typescript/src/client/state-mirror.ts b/clients/typescript/src/client/state-mirror.ts index 043445cfa..59d07a34d 100644 --- a/clients/typescript/src/client/state-mirror.ts +++ b/clients/typescript/src/client/state-mirror.ts @@ -26,7 +26,7 @@ import type { ChangesetState } from '../types/channels-changeset/state.js'; import type { RootState } from '../types/channels-root/state.js'; import type { SessionState } from '../types/channels-session/state.js'; import type { TerminalState } from '../types/channels-terminal/state.js'; -import type { AutomationCatalogState, AutomationState } from '../types/channels-automation/state.js'; +import type { AutomationEntry, AutomationState } from '../types/channels-automation/state.js'; import type { AutomationRunState } from '../types/channels-automation-run/state.js'; import { changesetReducer } from '../types/channels-changeset/reducer.js'; import { rootReducer } from '../types/channels-root/reducer.js'; @@ -39,7 +39,7 @@ const ROOT_URI = 'ahp-root://' as const; const AUTOMATIONS_URI = 'ahp-automations://' as const; const INITIAL_ROOT: RootState = { agents: [] }; -const INITIAL_AUTOMATION_CATALOG: AutomationCatalogState = { automations: [] }; +const INITIAL_AUTOMATION_CATALOG: AutomationState = { entries: [] }; /** Reducer-driven state container synchronised with server events. */ export class AhpStateMirror { @@ -47,8 +47,8 @@ export class AhpStateMirror { private readonly sessionsMap = new Map(); private readonly terminalsMap = new Map(); private readonly changesetsMap = new Map(); - private automationCatalogState: AutomationCatalogState = INITIAL_AUTOMATION_CATALOG; - private readonly automationsMap = new Map(); + private automationCatalogState: AutomationState = INITIAL_AUTOMATION_CATALOG; + private readonly automationsMap = new Map(); private readonly automationRunsMap = new Map(); /** Current root state. */ @@ -72,12 +72,12 @@ export class AhpStateMirror { } /** Current automation catalogue state. */ - get automationCatalog(): AutomationCatalogState { + get automationCatalog(): AutomationState { return this.automationCatalogState; } /** All catalogued automations keyed by their stable resource URI. */ - get automations(): ReadonlyMap { + get automations(): ReadonlyMap { return this.automationsMap; } @@ -97,7 +97,7 @@ export class AhpStateMirror { } /** Look up a catalogued automation by URI. */ - getAutomation(uri: URI): AutomationState | undefined { + getAutomation(uri: URI): AutomationEntry | undefined { return this.automationsMap.get(uri); } @@ -124,7 +124,7 @@ export class AhpStateMirror { return; } if (resource === AUTOMATIONS_URI) { - this.setAutomationCatalog(snapshot.state as AutomationCatalogState); + this.setAutomationCatalog(snapshot.state as AutomationState); return; } if (resource.startsWith('ahp-automation-run:')) { @@ -179,10 +179,10 @@ export class AhpStateMirror { } } - private setAutomationCatalog(state: AutomationCatalogState): void { + private setAutomationCatalog(state: AutomationState): void { this.automationCatalogState = state; this.automationsMap.clear(); - for (const automation of state.automations) { + for (const automation of state.entries) { this.automationsMap.set(automation.resource, automation); } } diff --git a/clients/typescript/test/client.test.ts b/clients/typescript/test/client.test.ts index f6a6e43bf..6177c092f 100644 --- a/clients/typescript/test/client.test.ts +++ b/clients/typescript/test/client.test.ts @@ -40,7 +40,7 @@ import type { UnsubscribeParams, } from '../src/types/common/commands.js'; import { JsonRpcErrorCodes } from '../src/types/common/errors.js'; -import { AutomationOperation, type AutomationState } from '../src/types/channels-automation/state.js'; +import { AutomationOperation, type AutomationEntry } from '../src/types/channels-automation/state.js'; import { MessageKind } from '../src/types/channels-chat/state.js'; const ROOT = 'ahp-root://' as const; @@ -158,7 +158,7 @@ test('subscribe attaches before sending the request and fans out an action', asy test('state mirror applies automation catalogue snapshots and actions', () => { const mirror = new AhpStateMirror(); - const automation: AutomationState = { + const automation: AutomationEntry = { resource: 'ahp-automation:/a1', definition: { title: 'Daily triage', @@ -175,12 +175,12 @@ test('state mirror applies automation catalogue snapshots and actions', () => { mirror.applySnapshot({ resource: AUTOMATIONS, - state: { automations: [automation] }, + state: { entries: [automation] }, fromSeq: 0, }); assert.equal(mirror.getAutomation(automation.resource)?.definition.title, 'Daily triage'); - const updated: AutomationState = { + const updated: AutomationEntry = { ...automation, definition: { ...automation.definition, title: 'Updated triage' }, modifiedAt: '2026-08-02T00:00:00Z', diff --git a/docs/.changes/20260805-shared-automations.json b/docs/.changes/20260805-shared-automations.json deleted file mode 100644 index d02c0ac62..000000000 --- a/docs/.changes/20260805-shared-automations.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "added", - "message": "Automation catalogue and automation-run channels, including self-contained host-defined event triggers and automation-origin messages, for shared trigger-based agent session workflows.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260811-error-response-parts-and-turn-resume.json b/docs/.changes/20260811-error-response-parts-and-turn-resume.json deleted file mode 100644 index 65b15b7a5..000000000 --- a/docs/.changes/20260811-error-response-parts-and-turn-resume.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "added", - "message": "Turn errors are durable response parts, and resumable errors can reopen the same turn through `chat/turnResume`.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260820-annotation-origin.json b/docs/.changes/20260820-annotation-origin.json deleted file mode 100644 index 04333c2f1..000000000 --- a/docs/.changes/20260820-annotation-origin.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "changed", - "message": "Annotations now carry an `origin` with a required session URI and optional chat URI and turn ID.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260820-changeset-content-error.json b/docs/.changes/20260820-changeset-content-error.json deleted file mode 100644 index 3d1a5bdcc..000000000 --- a/docs/.changes/20260820-changeset-content-error.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "removed", - "message": "Removed `error` from `changeset/contentChanged`; changeset failures are represented by `changeset/statusChanged`.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260820-deterministic-chat-modified-at.json b/docs/.changes/20260820-deterministic-chat-modified-at.json deleted file mode 100644 index e037959a4..000000000 --- a/docs/.changes/20260820-deterministic-chat-modified-at.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "fixed", - "message": "Chat reducers now derive `modifiedAt` from turn action data instead of local wall clocks.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260820-remove-session-fork.json b/docs/.changes/20260820-remove-session-fork.json deleted file mode 100644 index 23083e6c6..000000000 --- a/docs/.changes/20260820-remove-session-fork.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "removed", - "message": "Removed session-level forking from `createSession`; use chat forking instead.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260820-session-lifecycle-failed.json b/docs/.changes/20260820-session-lifecycle-failed.json deleted file mode 100644 index 5a4032a2d..000000000 --- a/docs/.changes/20260820-session-lifecycle-failed.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "changed", - "message": "Renamed the failed session lifecycle value from `creationFailed` to `failed`.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260820-terminal-claim-chat.json b/docs/.changes/20260820-terminal-claim-chat.json deleted file mode 100644 index 073004ba0..000000000 --- a/docs/.changes/20260820-terminal-claim-chat.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "changed", - "message": "`TerminalSessionClaim` now requires the chat URI that owns the terminal.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260820-terminal-lifecycle.json b/docs/.changes/20260820-terminal-lifecycle.json deleted file mode 100644 index fdc0be4d0..000000000 --- a/docs/.changes/20260820-terminal-lifecycle.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "changed", - "message": "Terminal state now uses an explicit `running`/`exited` lifecycle that preserves exits without an exit code.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260821-enum-compatibility.json b/docs/.changes/20260821-enum-compatibility.json deleted file mode 100644 index ff39c63b5..000000000 --- a/docs/.changes/20260821-enum-compatibility.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "changed", - "message": "Generated clients now preserve unknown values for nonexhaustive protocol enums and their discriminated unions.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260821-error-code-corrections.json b/docs/.changes/20260821-error-code-corrections.json deleted file mode 100644 index 321e9417d..000000000 --- a/docs/.changes/20260821-error-code-corrections.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "removed", - "message": "`ContentNotFound` is no longer an exported AHP error code; `-32006` remains reserved and unassigned.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260821-running-tool-call-request.json b/docs/.changes/20260821-running-tool-call-request.json deleted file mode 100644 index 27fa95197..000000000 --- a/docs/.changes/20260821-running-tool-call-request.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "changed", - "message": "`SessionToolClientExecutionRequest.toolCall` is narrowed to a running tool-call state.", - "targets": [ - "spec" - ] -} diff --git a/docs/.changes/20260826-initialize-result-meta.json b/docs/.changes/20260826-initialize-result-meta.json deleted file mode 100644 index 4c3be37b0..000000000 --- a/docs/.changes/20260826-initialize-result-meta.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "added", - "message": "`InitializeResult._meta` for hosts to advertise implementation-specific extension capabilities in initialize responses.", - "targets": [ - "spec" - ] -} diff --git a/docs/guide/automations.md b/docs/guide/automations.md index e9d21db46..33cf71281 100644 --- a/docs/guide/automations.md +++ b/docs/guide/automations.md @@ -55,7 +55,7 @@ room for future feature-specific options without changing capability detection. ```mermaid flowchart TD R["ahp-root:// capabilities"] --> C["ahp-automations:// catalogue"] - C --> A["AutomationState identified by ahp-automation:/<id>"] + C --> A["AutomationEntry identified by ahp-automation:/<id>"] A --> RS["newest-first run summaries"] RS --> AR["ahp-automation-run:/<id>"] AR --> S1["ahp-session:/<id>"] @@ -78,8 +78,8 @@ When `InitializeResult.automations` is present, clients subscribe to `ahp-automations://`. The snapshot contains the complete catalogue: ```typescript -AutomationCatalogState { - automations: AutomationState[] +AutomationState { + entries: AutomationEntry[] } ``` @@ -89,7 +89,7 @@ The host keeps the catalogue synchronized with full-entry actions: | --- | --- | | `automation/createRequested` | Ask the host to persist a complete definition at a client-chosen resource. | | `automation/updateRequested` | Ask the host to apply a definition patch in action order. | -| `automation/set` | Add or replace one complete `AutomationState`, keyed by `resource`. | +| `automation/set` | Add or replace one complete `AutomationEntry`, keyed by `resource`. | | `automation/removed` | Permanently delete the entry identified by `resource`; clients may dispatch this while `remove` is advertised. | These are ordinary ordered AHP actions. After reconnect, the host either replays @@ -437,7 +437,7 @@ become `cancelled`, or it may complete or fail before cancellation takes effect. ## Run history and retention -`AutomationState.runs` is a newest-first, bounded window of +`AutomationEntry.runs` is a newest-first, bounded window of `AutomationRunSummary` values. If `runsNextCursor` is present, the client calls `fetchAutomationRuns`; the host then publishes the updated full state through `automation/set` so every catalogue subscriber applies the same reducer update. diff --git a/docs/specification/automation-channel.md b/docs/specification/automation-channel.md index 7aadf0c72..39c8183e9 100644 --- a/docs/specification/automation-channel.md +++ b/docs/specification/automation-channel.md @@ -12,7 +12,7 @@ or from host-owned triggers. ahp-automations:// ``` -Each `AutomationState.resource` is a stable `ahp-automation:/` identifier +Each `AutomationEntry.resource` is a stable `ahp-automation:/` identifier chosen by `automation/createRequested`. Those identifiers target commands, actions, and relationships but are not independently subscribable channels. The host owns persistence, action ordering, trigger evaluation, run claims, and run @@ -20,7 +20,7 @@ history. ## State -`AutomationCatalogState.automations` contains the full `AutomationState` for +`AutomationState.entries` contains the full `AutomationEntry` for every visible automation, keyed by `resource`. Each entry contains the complete definition, host-computed next scheduled run, a newest-first window of `AutomationRunSummary` entries, and allowed operations. @@ -38,7 +38,7 @@ creation. Hosts revalidate all selections when a run starts. When `InitializeResult.automations` is present, clients subscribe to `ahp-automations://`. The subscription returns the complete -`AutomationCatalogState` snapshot. Later catalogue changes use normal ordered +`AutomationState` snapshot. Later catalogue changes use normal ordered actions and therefore participate in reconnect replay. If replay is unavailable, the host returns a fresh catalogue snapshot. @@ -59,7 +59,7 @@ target entry's identifier as `automation`. at a client-chosen `resource` (client-dispatchable). - `automation/updateRequested` asks the host to apply a definition patch in action order (client-dispatchable). -- `automation/set` adds or replaces one full `AutomationState` by `resource` +- `automation/set` adds or replaces one full `AutomationEntry` by `resource` (server-only). - `automation/removed` permanently deletes one entry by `resource` (client-dispatchable or server-originated). @@ -68,7 +68,7 @@ The host sequences all actions on `ahp-automations://`. Create and update requests are side-effect-only: their reducers leave catalogue state unchanged. The host validates and persists the requested mutation, then -publishes the resulting full `AutomationState` through `automation/set`. A +publishes the resulting full `AutomationEntry` through `automation/set`. A rejected request carries `ActionEnvelope.rejectionReason` and produces no catalogue mutation. diff --git a/docs/specification/overview.md b/docs/specification/overview.md index 09ee051da..36eedcfff 100644 --- a/docs/specification/overview.md +++ b/docs/specification/overview.md @@ -94,7 +94,7 @@ The specification is organised around the **channels** that AHP exposes — each - **[Terminal Channel Reference](/reference/terminal)** — `TerminalState`, terminal actions, and terminal commands. - **[Changeset Channel Reference](/reference/changeset)** — `ChangesetState`, changeset actions, and changeset commands. - **[Annotations Channel Reference](/reference/annotations)** — `AnnotationsState` and annotations actions. -- **[Automation Catalogue Channel Reference](/reference/automation)** — `AutomationCatalogState`, automation actions, and automation commands. +- **[Automation Catalogue Channel Reference](/reference/automation)** — `AutomationState`, automation actions, and automation commands. - **[Automation Run Channel Reference](/reference/automation-run)** — `AutomationRunState` and automation-run actions. - **[Resource Watch Channel Reference](/reference/resource-watch)** — `ResourceWatchState`, resource-watch actions, and resource-watch commands. - **[Telemetry Channel Reference](/reference/otlp)** — OTLP capability types and notifications. diff --git a/docs/specification/subscriptions.md b/docs/specification/subscriptions.md index 22ff7ef24..389fd9861 100644 --- a/docs/specification/subscriptions.md +++ b/docs/specification/subscriptions.md @@ -25,7 +25,7 @@ The rest of this page details the URI scheme and the lifecycle of a subscription | URI | State type | Description | |---|---|---| | `ahp-root://` | `RootState` | Global state (agents, terminals, host config). Always present. | -| `ahp-automations://` | `AutomationCatalogState` | Full state for every visible automation. Present when `InitializeResult.automations` is advertised. | +| `ahp-automations://` | `AutomationState` | Full state for every visible automation. Present when `InitializeResult.automations` is advertised. | | `ahp-session:/` | `SessionState` | Per-session state (metadata plus the `chats` catalog). The session's provider is carried on `SessionSummary.provider`, not in the URI scheme. | | `ahp-chat:/` | `ChatState` | Per-chat conversation state (turns, streaming, tool calls, pending messages, input requests). A session starts with a default chat; multi-chat hosts add more via `createChat`. See [Chat Channel](/specification/chat-channel). | | `ahp-terminal:/` | `TerminalState` | Per-terminal state. Server-defined id. | diff --git a/package-lock.json b/package-lock.json index 9170b2252..6d8c0c100 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "agent-host-protocol", - "version": "1.0.0", + "version": "0.9.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "agent-host-protocol", - "version": "1.0.0", + "version": "0.9.0", "license": "MIT", "devDependencies": { "@types/node": "^25.5.0", diff --git a/package.json b/package.json index 0a90fdbbd..b0d2fa9b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agent-host-protocol", - "version": "1.0.0", + "version": "0.9.0", "description": "", "main": "index.js", "scripts": { diff --git a/schema/actions.schema.json b/schema/actions.schema.json index a62c111d6..70f7a2b5a 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -2168,11 +2168,11 @@ }, "resource": { "$ref": "#/$defs/URI", - "description": "Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}." + "description": "Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}." }, "definition": { "$ref": "#/$defs/AutomationDefinition", - "description": "Complete initial {@link AutomationState.definition}." + "description": "Complete initial {@link AutomationEntry.definition}." } }, "required": [ @@ -2190,7 +2190,7 @@ }, "resource": { "$ref": "#/$defs/URI", - "description": "Target {@link AutomationState.resource}." + "description": "Target {@link AutomationEntry.resource}." }, "changes": { "$ref": "#/$defs/AutomationDefinitionPatch", @@ -2205,13 +2205,13 @@ }, "AutomationSetAction": { "type": "object", - "description": "Add or replace one full automation state in\n{@link AutomationCatalogState.automations}.\n\nExisting entries are matched by {@link AutomationState.resource} and\nreplaced in place. A previously unseen resource is appended.", + "description": "Add or replace one full automation state in\n{@link AutomationState.entries}.\n\nExisting entries are matched by {@link AutomationEntry.resource} and\nreplaced in place. A previously unseen resource is appended.", "properties": { "type": { "const": "automation/set" }, "automation": { - "$ref": "#/$defs/AutomationState", + "$ref": "#/$defs/AutomationEntry", "description": "Full new or replacement automation state." } }, @@ -2222,14 +2222,14 @@ }, "AutomationRemovedAction": { "type": "object", - "description": "Remove one automation from {@link AutomationCatalogState.automations}.\n\nClients may dispatch this action only while the target advertises\n{@link AutomationOperation.Remove}. The host revalidates that operation\nbefore permanently deleting the automation. A rejected action leaves the\nauthoritative catalogue and durable definition unchanged.\n\nRemoving an unknown resource is a no-op.", + "description": "Remove one automation from {@link AutomationState.entries}.\n\nClients may dispatch this action only while the target advertises\n{@link AutomationOperation.Remove}. The host revalidates that operation\nbefore permanently deleting the automation. A rejected action leaves the\nauthoritative catalogue and durable definition unchanged.\n\nRemoving an unknown resource is a no-op.", "properties": { "type": { "const": "automation/removed" }, "resource": { "$ref": "#/$defs/URI", - "description": "{@link AutomationState.resource} to remove." + "description": "{@link AutomationEntry.resource} to remove." } }, "required": [ @@ -2836,7 +2836,7 @@ "$ref": "#/$defs/ChatState" }, { - "$ref": "#/$defs/AutomationCatalogState" + "$ref": "#/$defs/AutomationState" }, { "$ref": "#/$defs/AutomationRunState" @@ -3080,7 +3080,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning {@link AutomationState.resource}." + "description": "Owning {@link AutomationEntry.resource}." }, "run": { "$ref": "#/$defs/URI", @@ -7611,7 +7611,7 @@ }, "AutomationDefinition": { "type": "object", - "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationState} rather than in the definition.", + "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationEntry} rather than in the definition.", "properties": { "title": { "type": "string", @@ -7650,9 +7650,9 @@ "triggers" ] }, - "AutomationState": { + "AutomationEntry": { "type": "object", - "description": "Authoritative state of one automation in the\n{@link AutomationCatalogState.automations} catalogue.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", + "description": "Authoritative state of one automation in {@link AutomationState.entries}.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", "properties": { "resource": { "$ref": "#/$defs/URI", @@ -7671,7 +7671,7 @@ "items": { "$ref": "#/$defs/AutomationRunSummary" }, - "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationState.runsNextCursor} is present." + "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationEntry.runsNextCursor} is present." }, "runsNextCursor": { "type": "string", @@ -7707,16 +7707,16 @@ "modifiedAt" ] }, - "AutomationCatalogState": { + "AutomationState": { "type": "object", "description": "Authoritative automation catalogue exposed on the `ahp-automations://`\nchannel.\n\nA subscription snapshot contains every automation visible to the client.\nSubsequent {@link AutomationSetAction | `automation/set`} and\n{@link AutomationRemovedAction | `automation/removed`} actions keep the\ncatalogue synchronized and participate in normal reconnect replay.", "properties": { - "automations": { + "entries": { "type": "array", "items": { - "$ref": "#/$defs/AutomationState" + "$ref": "#/$defs/AutomationEntry" }, - "description": "Full automation states keyed by {@link AutomationState.resource}." + "description": "Full automation entries keyed by {@link AutomationEntry.resource}." }, "_meta": { "type": "object", @@ -7725,7 +7725,7 @@ } }, "required": [ - "automations" + "entries" ] }, "AutomationManualRunOrigin": { @@ -7949,7 +7949,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning `ahp-automation:` URI matching {@link AutomationState.resource}." + "description": "Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}." }, "origin": { "$ref": "#/$defs/AutomationRunOrigin", @@ -8999,7 +8999,7 @@ "run" ], "type": "string", - "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationState.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." + "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationEntry.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." } } } diff --git a/schema/commands.schema.json b/schema/commands.schema.json index dbda097a2..6b792f21b 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -180,7 +180,7 @@ }, "automations": { "$ref": "#/$defs/AutomationCapabilities", - "description": "Host-owned automation support. Presence means clients may subscribe to\n`ahp-automations://` for {@link AutomationCatalogState}; absence means the\nhost does not expose an automation catalogue or automation commands." + "description": "Host-owned automation support. Presence means clients may subscribe to\n`ahp-automations://` for {@link AutomationState}; absence means the\nhost does not expose an automation catalogue or automation commands." } }, "required": [ @@ -191,7 +191,7 @@ }, "AutomationCapabilities": { "type": "object", - "description": "Automation features supported by this host authority.\n\nThe presence of this object advertises the baseline `ahp-automations://`\ncatalogue. Optional fields describe additional host features and\nrestrictions.\n\nCapabilities describe implementation support.\n{@link AutomationState.operations} remains authoritative for which\ndefinition mutations are currently allowed on a particular automation.", + "description": "Automation features supported by this host authority.\n\nThe presence of this object advertises the baseline `ahp-automations://`\ncatalogue. Optional fields describe additional host features and\nrestrictions.\n\nCapabilities describe implementation support.\n{@link AutomationEntry.operations} remains authoritative for which\ndefinition mutations are currently allowed on a particular automation.", "properties": { "create": { "$ref": "#/$defs/AutomationCreateCapability", @@ -207,7 +207,7 @@ }, "runHistoryLimit": { "type": "number", - "description": "Maximum terminal entries retained in {@link AutomationState.runs}. Active\nruns are not counted toward the limit. Absence means the retention limit is\nimplementation-defined." + "description": "Maximum terminal entries retained in {@link AutomationEntry.runs}. Active\nruns are not counted toward the limit. Absence means the retention limit is\nimplementation-defined." } } }, @@ -1599,7 +1599,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Target {@link AutomationState.resource}." + "description": "Target {@link AutomationEntry.resource}." }, "requestId": { "type": "string", @@ -1643,11 +1643,11 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Target {@link AutomationState.resource}." + "description": "Target {@link AutomationEntry.resource}." }, "cursor": { "type": "string", - "description": "Cursor previously received as {@link AutomationState.runsNextCursor}.\nOmit to request the first page not already included by the snapshot." + "description": "Cursor previously received as {@link AutomationEntry.runsNextCursor}.\nOmit to request the first page not already included by the snapshot." } }, "required": [ @@ -2075,7 +2075,7 @@ "$ref": "#/$defs/ChatState" }, { - "$ref": "#/$defs/AutomationCatalogState" + "$ref": "#/$defs/AutomationState" }, { "$ref": "#/$defs/AutomationRunState" @@ -2319,7 +2319,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning {@link AutomationState.resource}." + "description": "Owning {@link AutomationEntry.resource}." }, "run": { "$ref": "#/$defs/URI", @@ -6850,7 +6850,7 @@ }, "AutomationDefinition": { "type": "object", - "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationState} rather than in the definition.", + "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationEntry} rather than in the definition.", "properties": { "title": { "type": "string", @@ -6889,9 +6889,9 @@ "triggers" ] }, - "AutomationState": { + "AutomationEntry": { "type": "object", - "description": "Authoritative state of one automation in the\n{@link AutomationCatalogState.automations} catalogue.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", + "description": "Authoritative state of one automation in {@link AutomationState.entries}.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", "properties": { "resource": { "$ref": "#/$defs/URI", @@ -6910,7 +6910,7 @@ "items": { "$ref": "#/$defs/AutomationRunSummary" }, - "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationState.runsNextCursor} is present." + "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationEntry.runsNextCursor} is present." }, "runsNextCursor": { "type": "string", @@ -6946,16 +6946,16 @@ "modifiedAt" ] }, - "AutomationCatalogState": { + "AutomationState": { "type": "object", "description": "Authoritative automation catalogue exposed on the `ahp-automations://`\nchannel.\n\nA subscription snapshot contains every automation visible to the client.\nSubsequent {@link AutomationSetAction | `automation/set`} and\n{@link AutomationRemovedAction | `automation/removed`} actions keep the\ncatalogue synchronized and participate in normal reconnect replay.", "properties": { - "automations": { + "entries": { "type": "array", "items": { - "$ref": "#/$defs/AutomationState" + "$ref": "#/$defs/AutomationEntry" }, - "description": "Full automation states keyed by {@link AutomationState.resource}." + "description": "Full automation entries keyed by {@link AutomationEntry.resource}." }, "_meta": { "type": "object", @@ -6964,7 +6964,7 @@ } }, "required": [ - "automations" + "entries" ] }, "AutomationManualRunOrigin": { @@ -7188,7 +7188,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning `ahp-automation:` URI matching {@link AutomationState.resource}." + "description": "Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}." }, "origin": { "$ref": "#/$defs/AutomationRunOrigin", @@ -9386,11 +9386,11 @@ }, "resource": { "$ref": "#/$defs/URI", - "description": "Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}." + "description": "Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}." }, "definition": { "$ref": "#/$defs/AutomationDefinition", - "description": "Complete initial {@link AutomationState.definition}." + "description": "Complete initial {@link AutomationEntry.definition}." } }, "required": [ @@ -9408,7 +9408,7 @@ }, "resource": { "$ref": "#/$defs/URI", - "description": "Target {@link AutomationState.resource}." + "description": "Target {@link AutomationEntry.resource}." }, "changes": { "$ref": "#/$defs/AutomationDefinitionPatch", @@ -9423,13 +9423,13 @@ }, "AutomationSetAction": { "type": "object", - "description": "Add or replace one full automation state in\n{@link AutomationCatalogState.automations}.\n\nExisting entries are matched by {@link AutomationState.resource} and\nreplaced in place. A previously unseen resource is appended.", + "description": "Add or replace one full automation state in\n{@link AutomationState.entries}.\n\nExisting entries are matched by {@link AutomationEntry.resource} and\nreplaced in place. A previously unseen resource is appended.", "properties": { "type": { "const": "automation/set" }, "automation": { - "$ref": "#/$defs/AutomationState", + "$ref": "#/$defs/AutomationEntry", "description": "Full new or replacement automation state." } }, @@ -9440,14 +9440,14 @@ }, "AutomationRemovedAction": { "type": "object", - "description": "Remove one automation from {@link AutomationCatalogState.automations}.\n\nClients may dispatch this action only while the target advertises\n{@link AutomationOperation.Remove}. The host revalidates that operation\nbefore permanently deleting the automation. A rejected action leaves the\nauthoritative catalogue and durable definition unchanged.\n\nRemoving an unknown resource is a no-op.", + "description": "Remove one automation from {@link AutomationState.entries}.\n\nClients may dispatch this action only while the target advertises\n{@link AutomationOperation.Remove}. The host revalidates that operation\nbefore permanently deleting the automation. A rejected action leaves the\nauthoritative catalogue and durable definition unchanged.\n\nRemoving an unknown resource is a no-op.", "properties": { "type": { "const": "automation/removed" }, "resource": { "$ref": "#/$defs/URI", - "description": "{@link AutomationState.resource} to remove." + "description": "{@link AutomationEntry.resource} to remove." } }, "required": [ @@ -10604,7 +10604,7 @@ "run" ], "type": "string", - "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationState.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." + "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationEntry.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." }, "AutomationRunOrigin": { "oneOf": [ diff --git a/schema/errors.schema.json b/schema/errors.schema.json index 0e2457bc6..46c000196 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -509,7 +509,7 @@ "$ref": "#/$defs/ChatState" }, { - "$ref": "#/$defs/AutomationCatalogState" + "$ref": "#/$defs/AutomationState" }, { "$ref": "#/$defs/AutomationRunState" @@ -753,7 +753,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning {@link AutomationState.resource}." + "description": "Owning {@link AutomationEntry.resource}." }, "run": { "$ref": "#/$defs/URI", @@ -5284,7 +5284,7 @@ }, "AutomationDefinition": { "type": "object", - "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationState} rather than in the definition.", + "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationEntry} rather than in the definition.", "properties": { "title": { "type": "string", @@ -5323,9 +5323,9 @@ "triggers" ] }, - "AutomationState": { + "AutomationEntry": { "type": "object", - "description": "Authoritative state of one automation in the\n{@link AutomationCatalogState.automations} catalogue.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", + "description": "Authoritative state of one automation in {@link AutomationState.entries}.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", "properties": { "resource": { "$ref": "#/$defs/URI", @@ -5344,7 +5344,7 @@ "items": { "$ref": "#/$defs/AutomationRunSummary" }, - "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationState.runsNextCursor} is present." + "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationEntry.runsNextCursor} is present." }, "runsNextCursor": { "type": "string", @@ -5380,16 +5380,16 @@ "modifiedAt" ] }, - "AutomationCatalogState": { + "AutomationState": { "type": "object", "description": "Authoritative automation catalogue exposed on the `ahp-automations://`\nchannel.\n\nA subscription snapshot contains every automation visible to the client.\nSubsequent {@link AutomationSetAction | `automation/set`} and\n{@link AutomationRemovedAction | `automation/removed`} actions keep the\ncatalogue synchronized and participate in normal reconnect replay.", "properties": { - "automations": { + "entries": { "type": "array", "items": { - "$ref": "#/$defs/AutomationState" + "$ref": "#/$defs/AutomationEntry" }, - "description": "Full automation states keyed by {@link AutomationState.resource}." + "description": "Full automation entries keyed by {@link AutomationEntry.resource}." }, "_meta": { "type": "object", @@ -5398,7 +5398,7 @@ } }, "required": [ - "automations" + "entries" ] }, "AutomationManualRunOrigin": { @@ -5622,7 +5622,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning `ahp-automation:` URI matching {@link AutomationState.resource}." + "description": "Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}." }, "origin": { "$ref": "#/$defs/AutomationRunOrigin", @@ -5832,7 +5832,7 @@ }, "automations": { "$ref": "#/$defs/AutomationCapabilities", - "description": "Host-owned automation support. Presence means clients may subscribe to\n`ahp-automations://` for {@link AutomationCatalogState}; absence means the\nhost does not expose an automation catalogue or automation commands." + "description": "Host-owned automation support. Presence means clients may subscribe to\n`ahp-automations://` for {@link AutomationState}; absence means the\nhost does not expose an automation catalogue or automation commands." } }, "required": [ @@ -5843,7 +5843,7 @@ }, "AutomationCapabilities": { "type": "object", - "description": "Automation features supported by this host authority.\n\nThe presence of this object advertises the baseline `ahp-automations://`\ncatalogue. Optional fields describe additional host features and\nrestrictions.\n\nCapabilities describe implementation support.\n{@link AutomationState.operations} remains authoritative for which\ndefinition mutations are currently allowed on a particular automation.", + "description": "Automation features supported by this host authority.\n\nThe presence of this object advertises the baseline `ahp-automations://`\ncatalogue. Optional fields describe additional host features and\nrestrictions.\n\nCapabilities describe implementation support.\n{@link AutomationEntry.operations} remains authoritative for which\ndefinition mutations are currently allowed on a particular automation.", "properties": { "create": { "$ref": "#/$defs/AutomationCreateCapability", @@ -5859,7 +5859,7 @@ }, "runHistoryLimit": { "type": "number", - "description": "Maximum terminal entries retained in {@link AutomationState.runs}. Active\nruns are not counted toward the limit. Absence means the retention limit is\nimplementation-defined." + "description": "Maximum terminal entries retained in {@link AutomationEntry.runs}. Active\nruns are not counted toward the limit. Absence means the retention limit is\nimplementation-defined." } } }, @@ -7251,7 +7251,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Target {@link AutomationState.resource}." + "description": "Target {@link AutomationEntry.resource}." }, "requestId": { "type": "string", @@ -7295,11 +7295,11 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Target {@link AutomationState.resource}." + "description": "Target {@link AutomationEntry.resource}." }, "cursor": { "type": "string", - "description": "Cursor previously received as {@link AutomationState.runsNextCursor}.\nOmit to request the first page not already included by the snapshot." + "description": "Cursor previously received as {@link AutomationEntry.runsNextCursor}.\nOmit to request the first page not already included by the snapshot." } }, "required": [ @@ -7992,7 +7992,7 @@ "run" ], "type": "string", - "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationState.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." + "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationEntry.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." }, "AutomationRunOrigin": { "oneOf": [ @@ -10433,11 +10433,11 @@ }, "resource": { "$ref": "#/$defs/URI", - "description": "Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}." + "description": "Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}." }, "definition": { "$ref": "#/$defs/AutomationDefinition", - "description": "Complete initial {@link AutomationState.definition}." + "description": "Complete initial {@link AutomationEntry.definition}." } }, "required": [ @@ -10455,7 +10455,7 @@ }, "resource": { "$ref": "#/$defs/URI", - "description": "Target {@link AutomationState.resource}." + "description": "Target {@link AutomationEntry.resource}." }, "changes": { "$ref": "#/$defs/AutomationDefinitionPatch", @@ -10470,13 +10470,13 @@ }, "AutomationSetAction": { "type": "object", - "description": "Add or replace one full automation state in\n{@link AutomationCatalogState.automations}.\n\nExisting entries are matched by {@link AutomationState.resource} and\nreplaced in place. A previously unseen resource is appended.", + "description": "Add or replace one full automation state in\n{@link AutomationState.entries}.\n\nExisting entries are matched by {@link AutomationEntry.resource} and\nreplaced in place. A previously unseen resource is appended.", "properties": { "type": { "const": "automation/set" }, "automation": { - "$ref": "#/$defs/AutomationState", + "$ref": "#/$defs/AutomationEntry", "description": "Full new or replacement automation state." } }, @@ -10487,14 +10487,14 @@ }, "AutomationRemovedAction": { "type": "object", - "description": "Remove one automation from {@link AutomationCatalogState.automations}.\n\nClients may dispatch this action only while the target advertises\n{@link AutomationOperation.Remove}. The host revalidates that operation\nbefore permanently deleting the automation. A rejected action leaves the\nauthoritative catalogue and durable definition unchanged.\n\nRemoving an unknown resource is a no-op.", + "description": "Remove one automation from {@link AutomationState.entries}.\n\nClients may dispatch this action only while the target advertises\n{@link AutomationOperation.Remove}. The host revalidates that operation\nbefore permanently deleting the automation. A rejected action leaves the\nauthoritative catalogue and durable definition unchanged.\n\nRemoving an unknown resource is a no-op.", "properties": { "type": { "const": "automation/removed" }, "resource": { "$ref": "#/$defs/URI", - "description": "{@link AutomationState.resource} to remove." + "description": "{@link AutomationEntry.resource} to remove." } }, "required": [ diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index 4acf66148..edf2ca344 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -676,7 +676,7 @@ "$ref": "#/$defs/ChatState" }, { - "$ref": "#/$defs/AutomationCatalogState" + "$ref": "#/$defs/AutomationState" }, { "$ref": "#/$defs/AutomationRunState" @@ -920,7 +920,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning {@link AutomationState.resource}." + "description": "Owning {@link AutomationEntry.resource}." }, "run": { "$ref": "#/$defs/URI", @@ -5451,7 +5451,7 @@ }, "AutomationDefinition": { "type": "object", - "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationState} rather than in the definition.", + "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationEntry} rather than in the definition.", "properties": { "title": { "type": "string", @@ -5490,9 +5490,9 @@ "triggers" ] }, - "AutomationState": { + "AutomationEntry": { "type": "object", - "description": "Authoritative state of one automation in the\n{@link AutomationCatalogState.automations} catalogue.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", + "description": "Authoritative state of one automation in {@link AutomationState.entries}.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", "properties": { "resource": { "$ref": "#/$defs/URI", @@ -5511,7 +5511,7 @@ "items": { "$ref": "#/$defs/AutomationRunSummary" }, - "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationState.runsNextCursor} is present." + "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationEntry.runsNextCursor} is present." }, "runsNextCursor": { "type": "string", @@ -5547,16 +5547,16 @@ "modifiedAt" ] }, - "AutomationCatalogState": { + "AutomationState": { "type": "object", "description": "Authoritative automation catalogue exposed on the `ahp-automations://`\nchannel.\n\nA subscription snapshot contains every automation visible to the client.\nSubsequent {@link AutomationSetAction | `automation/set`} and\n{@link AutomationRemovedAction | `automation/removed`} actions keep the\ncatalogue synchronized and participate in normal reconnect replay.", "properties": { - "automations": { + "entries": { "type": "array", "items": { - "$ref": "#/$defs/AutomationState" + "$ref": "#/$defs/AutomationEntry" }, - "description": "Full automation states keyed by {@link AutomationState.resource}." + "description": "Full automation entries keyed by {@link AutomationEntry.resource}." }, "_meta": { "type": "object", @@ -5565,7 +5565,7 @@ } }, "required": [ - "automations" + "entries" ] }, "AutomationManualRunOrigin": { @@ -5789,7 +5789,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning `ahp-automation:` URI matching {@link AutomationState.resource}." + "description": "Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}." }, "origin": { "$ref": "#/$defs/AutomationRunOrigin", @@ -6512,7 +6512,7 @@ "run" ], "type": "string", - "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationState.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." + "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationEntry.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." }, "AutomationRunOrigin": { "oneOf": [ diff --git a/schema/state.schema.json b/schema/state.schema.json index fb3623e33..097236dfa 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -420,7 +420,7 @@ "$ref": "#/$defs/ChatState" }, { - "$ref": "#/$defs/AutomationCatalogState" + "$ref": "#/$defs/AutomationState" }, { "$ref": "#/$defs/AutomationRunState" @@ -664,7 +664,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning {@link AutomationState.resource}." + "description": "Owning {@link AutomationEntry.resource}." }, "run": { "$ref": "#/$defs/URI", @@ -5195,7 +5195,7 @@ }, "AutomationDefinition": { "type": "object", - "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationState} rather than in the definition.", + "description": "Durable, client-editable definition of an automation.\n\nA definition combines the initial automation message, the session template\nused for each run, and zero or more automatic triggers. Run history,\ntimestamps, and currently allowed operations live on\n{@link AutomationEntry} rather than in the definition.", "properties": { "title": { "type": "string", @@ -5234,9 +5234,9 @@ "triggers" ] }, - "AutomationState": { + "AutomationEntry": { "type": "object", - "description": "Authoritative state of one automation in the\n{@link AutomationCatalogState.automations} catalogue.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", + "description": "Authoritative state of one automation in {@link AutomationState.entries}.\n\nThe host owns trigger evaluation, run claims, run retention, and operation\navailability. Clients render this state and submit actions or commands; they\nnever run a fallback scheduler for a host-owned definition.", "properties": { "resource": { "$ref": "#/$defs/URI", @@ -5255,7 +5255,7 @@ "items": { "$ref": "#/$defs/AutomationRunSummary" }, - "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationState.runsNextCursor} is present." + "description": "Newest-first retained run summaries. This is a bounded window; use\n{@link FetchAutomationRunsParams | fetchAutomationRuns} when\n{@link AutomationEntry.runsNextCursor} is present." }, "runsNextCursor": { "type": "string", @@ -5291,16 +5291,16 @@ "modifiedAt" ] }, - "AutomationCatalogState": { + "AutomationState": { "type": "object", "description": "Authoritative automation catalogue exposed on the `ahp-automations://`\nchannel.\n\nA subscription snapshot contains every automation visible to the client.\nSubsequent {@link AutomationSetAction | `automation/set`} and\n{@link AutomationRemovedAction | `automation/removed`} actions keep the\ncatalogue synchronized and participate in normal reconnect replay.", "properties": { - "automations": { + "entries": { "type": "array", "items": { - "$ref": "#/$defs/AutomationState" + "$ref": "#/$defs/AutomationEntry" }, - "description": "Full automation states keyed by {@link AutomationState.resource}." + "description": "Full automation entries keyed by {@link AutomationEntry.resource}." }, "_meta": { "type": "object", @@ -5309,7 +5309,7 @@ } }, "required": [ - "automations" + "entries" ] }, "AutomationManualRunOrigin": { @@ -5533,7 +5533,7 @@ }, "automation": { "$ref": "#/$defs/URI", - "description": "Owning `ahp-automation:` URI matching {@link AutomationState.resource}." + "description": "Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}." }, "origin": { "$ref": "#/$defs/AutomationRunOrigin", @@ -6279,7 +6279,7 @@ "run" ], "type": "string", - "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationState.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." + "description": "Operations the host currently permits for an automation.\n\nThe list on {@link AutomationEntry.operations} is authoritative and may\nchange over time. Clients MUST NOT infer permission from capabilities alone:\ncapabilities describe what the host implementation can support, while\noperations describe what is allowed for this particular automation now." } } } diff --git a/scripts/generate-csharp.ts b/scripts/generate-csharp.ts index cc6b433fd..207212210 100644 --- a/scripts/generate-csharp.ts +++ b/scripts/generate-csharp.ts @@ -792,8 +792,8 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; csName?: strin { name: 'AutomationSessionTemplate' }, { name: 'AutomationDefinition' }, { name: 'AutomationDefinitionPatch' }, + { name: 'AutomationEntry', mutable: true }, { name: 'AutomationState', mutable: true }, - { name: 'AutomationCatalogState', mutable: true }, { name: 'AutomationManualRunOrigin' }, { name: 'AutomationTriggeredRunOrigin' }, { name: 'AutomationPendingRunLifecycle' }, @@ -1278,7 +1278,7 @@ public sealed class SnapshotState public AnnotationsState? Annotations { get; set; } /// Automation catalogue state variant, when populated. - public AutomationCatalogState? Automations { get; set; } + public AutomationState? Automations { get; set; } /// Automation run state variant, when populated. public AutomationRunState? AutomationRun { get; set; } @@ -1298,9 +1298,9 @@ internal sealed class SnapshotStateConverter : JsonConverter { result.AutomationRun = root.Deserialize(AhpJsonTypeInfo.Get(options)); } - else if (root.TryGetProperty("automations", out _)) + else if (root.TryGetProperty("entries", out _)) { - result.Automations = root.Deserialize(AhpJsonTypeInfo.Get(options)); + result.Automations = root.Deserialize(AhpJsonTypeInfo.Get(options)); } else if (root.TryGetProperty("turns", out _)) { @@ -1339,7 +1339,7 @@ internal sealed class SnapshotStateConverter : JsonConverter public override void Write(Utf8JsonWriter writer, SnapshotState value, JsonSerializerOptions options) { if (value.AutomationRun is not null) { JsonSerializer.Serialize(writer, value.AutomationRun, AhpJsonTypeInfo.Get(options)); return; } - if (value.Automations is not null) { JsonSerializer.Serialize(writer, value.Automations, AhpJsonTypeInfo.Get(options)); return; } + if (value.Automations is not null) { JsonSerializer.Serialize(writer, value.Automations, AhpJsonTypeInfo.Get(options)); return; } if (value.Chat is not null) { JsonSerializer.Serialize(writer, value.Chat, AhpJsonTypeInfo.Get(options)); return; } if (value.Session is not null) { JsonSerializer.Serialize(writer, value.Session, AhpJsonTypeInfo.Get(options)); return; } if (value.Terminal is not null) { JsonSerializer.Serialize(writer, value.Terminal, AhpJsonTypeInfo.Get(options)); return; } diff --git a/scripts/generate-go.ts b/scripts/generate-go.ts index 9831f6748..71926ac2f 100644 --- a/scripts/generate-go.ts +++ b/scripts/generate-go.ts @@ -173,7 +173,7 @@ function mapType(tsType: string): string { tsType === 'RootState | SessionState | TerminalState | ChangesetState | AnnotationsState' || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState' || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState' || - tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationCatalogState | AutomationRunState' || + tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationState | AutomationRunState' || tsType === 'RootState | SessionState | ChatState | TerminalState | ChangesetState' || tsType === 'RootState | SessionState | ChatState | TerminalState | ChangesetState | AnnotationsState' ) { @@ -872,8 +872,8 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; goName?: strin { name: 'AutomationSessionTemplate' }, { name: 'AutomationDefinition' }, { name: 'AutomationDefinitionPatch' }, + { name: 'AutomationEntry' }, { name: 'AutomationState' }, - { name: 'AutomationCatalogState' }, { name: 'AutomationManualRunOrigin' }, { name: 'AutomationTriggeredRunOrigin' }, { name: 'AutomationPendingRunLifecycle' }, @@ -1279,7 +1279,7 @@ type SnapshotState struct { \tChangeset *ChangesetState \`json:"-"\` \tResourceWatch *ResourceWatchState \`json:"-"\` \tAnnotations *AnnotationsState \`json:"-"\` -\tAutomations *AutomationCatalogState \`json:"-"\` +\tAutomations *AutomationState \`json:"-"\` \tAutomationRun *AutomationRunState \`json:"-"\` } @@ -1324,8 +1324,8 @@ func (s *SnapshotState) UnmarshalJSON(data []byte) error { \t\t\treturn err \t\t} \t\ts.AutomationRun = &v -\tcase containsAll(probe, "automations"): -\t\tvar v AutomationCatalogState +\tcase containsAll(probe, "entries"): +\t\tvar v AutomationState \t\tif err := json.Unmarshal(data, &v); err != nil { \t\t\treturn err \t\t} diff --git a/scripts/generate-kotlin.ts b/scripts/generate-kotlin.ts index 47cf3827d..ea13b41e5 100644 --- a/scripts/generate-kotlin.ts +++ b/scripts/generate-kotlin.ts @@ -153,7 +153,7 @@ function mapType(tsType: string): string { tsType === 'RootState | SessionState | TerminalState | ChangesetState | AnnotationsState' || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState' || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState' || - tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationCatalogState | AutomationRunState' || + tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationState | AutomationRunState' || tsType === 'RootState | SessionState | ChatState' || tsType === 'RootState | SessionState | ChatState | TerminalState' || tsType === 'RootState | SessionState | ChatState | TerminalState | ChangesetState' || @@ -842,7 +842,7 @@ sealed interface SnapshotState { @JvmInline value class Changeset(val value: ChangesetState) : SnapshotState @JvmInline value class ResourceWatch(val value: ResourceWatchState) : SnapshotState @JvmInline value class Annotations(val value: AnnotationsState) : SnapshotState - @JvmInline value class Automations(val value: AutomationCatalogState) : SnapshotState + @JvmInline value class Automations(val value: AutomationState) : SnapshotState @JvmInline value class AutomationRun(val value: AutomationRunState) : SnapshotState } @@ -857,8 +857,8 @@ internal object SnapshotStateSerializer : KSerializer { val obj = element as? JsonObject ?: error("Expected JsonObject for SnapshotState") // Try the most distinctive shape first. AutomationRunState has required - // \`automation\`, \`origin\`, and \`sessions\`; AutomationCatalogState has - // required \`automations\`; SessionState has required + // \`automation\`, \`origin\`, and \`sessions\`; AutomationState has + // required \`entries\`; SessionState has required // \`lifecycle\`; ChatState has required \`turns\`; ChangesetState has // required \`status\` + \`files\`; ResourceWatchState has required // \`root\` + \`recursive\`; AnnotationsState has required \`annotations\` @@ -868,8 +868,8 @@ internal object SnapshotStateSerializer : KSerializer { return when { obj.containsKey("automation") && obj.containsKey("origin") && obj.containsKey("sessions") -> SnapshotState.AutomationRun(input.json.decodeFromJsonElement(AutomationRunState.serializer(), element)) - obj.containsKey("automations") -> - SnapshotState.Automations(input.json.decodeFromJsonElement(AutomationCatalogState.serializer(), element)) + obj.containsKey("entries") -> + SnapshotState.Automations(input.json.decodeFromJsonElement(AutomationState.serializer(), element)) obj.containsKey("lifecycle") -> SnapshotState.Session(input.json.decodeFromJsonElement(SessionState.serializer(), element)) obj.containsKey("turns") -> SnapshotState.Chat(input.json.decodeFromJsonElement(ChatState.serializer(), element)) obj.containsKey("status") && obj.containsKey("files") -> @@ -895,7 +895,7 @@ internal object SnapshotStateSerializer : KSerializer { is SnapshotState.Changeset -> output.json.encodeToJsonElement(ChangesetState.serializer(), value.value) is SnapshotState.ResourceWatch -> output.json.encodeToJsonElement(ResourceWatchState.serializer(), value.value) is SnapshotState.Annotations -> output.json.encodeToJsonElement(AnnotationsState.serializer(), value.value) - is SnapshotState.Automations -> output.json.encodeToJsonElement(AutomationCatalogState.serializer(), value.value) + is SnapshotState.Automations -> output.json.encodeToJsonElement(AutomationState.serializer(), value.value) is SnapshotState.AutomationRun -> output.json.encodeToJsonElement(AutomationRunState.serializer(), value.value) } output.encodeJsonElement(element) @@ -1042,7 +1042,7 @@ const STATE_STRUCTS = [ 'AutomationTriggerEventDefinition', 'AutomationTriggerDefinition', 'AutomationSessionTemplate', 'AutomationDefinition', 'AutomationDefinitionPatch', - 'AutomationState', 'AutomationCatalogState', + 'AutomationEntry', 'AutomationState', 'AutomationManualRunOrigin', 'AutomationTriggeredRunOrigin', 'AutomationPendingRunLifecycle', 'AutomationRunningRunLifecycle', 'AutomationCompletedRunLifecycle', diff --git a/scripts/generate-rust.ts b/scripts/generate-rust.ts index 0b40c2edf..4e999bbcf 100644 --- a/scripts/generate-rust.ts +++ b/scripts/generate-rust.ts @@ -163,7 +163,7 @@ function mapType(tsType: string, propName?: string, containerName?: string): str || tsType === 'RootState | SessionState | TerminalState | ChangesetState | AnnotationsState' || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState' || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState' - || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationCatalogState | AutomationRunState' + || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationState | AutomationRunState' || tsType === 'RootState | SessionState | ChatState' || tsType === 'RootState | SessionState | ChatState | TerminalState' || tsType === 'RootState | SessionState | ChatState | TerminalState | ChangesetState' @@ -933,8 +933,8 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; rustName?: str { name: 'AutomationSessionTemplate' }, { name: 'AutomationDefinition' }, { name: 'AutomationDefinitionPatch' }, + { name: 'AutomationEntry' }, { name: 'AutomationState' }, - { name: 'AutomationCatalogState' }, { name: 'AutomationManualRunOrigin', omitDiscriminants: true }, { name: 'AutomationTriggeredRunOrigin', omitDiscriminants: true }, { name: 'AutomationPendingRunLifecycle', omitDiscriminants: true }, @@ -1295,7 +1295,7 @@ pub enum SnapshotState { Changeset(Box), ResourceWatch(Box), Annotations(Box), - Automations(Box), + Automations(Box), AutomationRun(Box), Root(Box), }`; @@ -1590,7 +1590,7 @@ impl Serialize for ChatErrorAction { function generateActionsFile(project: Project): string { const lines: string[] = [GENERATED_HEADER]; lines.push('#[allow(unused_imports)]'); - lines.push('use crate::state::{AgentInfo, AgentSelection, Annotation, AnnotationEntry, AnnotationOrigin, AutomationDefinition, AutomationDefinitionPatch, AutomationRunLifecycle, AutomationRunSummary, AutomationState, ChatInputAnswer, ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ConfirmationOption, ContentRef, Customization, CustomizationEnablement, ErrorInfo, ErrorResponsePart, McpAuthRequirement, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, SideChatSelection, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, ToolCallConfirmationReason, ToolCallCancellationReason, ToolDefinition, ToolInput, ToolResultContent, UsageInfo, Message, PendingMessageKind, Turn, ChangesetStatus, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, Changeset, ChatSummary};'); + lines.push('use crate::state::{AgentInfo, AgentSelection, Annotation, AnnotationEntry, AnnotationOrigin, AutomationDefinition, AutomationDefinitionPatch, AutomationEntry, AutomationRunLifecycle, AutomationRunSummary, ChatInputAnswer, ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ConfirmationOption, ContentRef, Customization, CustomizationEnablement, ErrorInfo, ErrorResponsePart, McpAuthRequirement, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, SideChatSelection, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, ToolCallConfirmationReason, ToolCallCancellationReason, ToolDefinition, ToolInput, ToolResultContent, UsageInfo, Message, PendingMessageKind, Turn, ChangesetStatus, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, Changeset, ChatSummary};'); lines.push(''); // ActionType enum diff --git a/scripts/generate-swift.ts b/scripts/generate-swift.ts index 1a94c8c33..89fa9bcdf 100644 --- a/scripts/generate-swift.ts +++ b/scripts/generate-swift.ts @@ -119,7 +119,7 @@ function mapType(tsType: string, propName?: string, containerName?: string): str || tsType === 'RootState | SessionState | TerminalState | ChangesetState | AnnotationsState' || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState' || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState' - || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationCatalogState | AutomationRunState' + || tsType === 'RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationState | AutomationRunState' || tsType === 'RootState | SessionState | ChatState' || tsType === 'RootState | SessionState | ChatState | TerminalState' || tsType === 'RootState | SessionState | ChatState | TerminalState | ChangesetState' @@ -747,7 +747,7 @@ const STATE_STRUCTS = [ 'AutomationTriggerEventDefinition', 'AutomationTriggerDefinition', 'AutomationSessionTemplate', 'AutomationDefinition', 'AutomationDefinitionPatch', - 'AutomationState', 'AutomationCatalogState', + 'AutomationEntry', 'AutomationState', 'AutomationManualRunOrigin', 'AutomationTriggeredRunOrigin', 'AutomationPendingRunLifecycle', 'AutomationRunningRunLifecycle', 'AutomationCompletedRunLifecycle', @@ -1100,7 +1100,7 @@ public enum SnapshotState: Codable, Sendable { case changeset(ChangesetState) case resourceWatch(ResourceWatchState) case annotations(AnnotationsState) - case automations(AutomationCatalogState) + case automations(AutomationState) case automationRun(AutomationRunState) public init(from decoder: Decoder) throws { @@ -1120,7 +1120,7 @@ public enum SnapshotState: Codable, Sendable { self = .resourceWatch(resourceWatch) } else if let annotations = try? AnnotationsState(from: decoder) { self = .annotations(annotations) - } else if let automations = try? AutomationCatalogState(from: decoder) { + } else if let automations = try? AutomationState(from: decoder) { self = .automations(automations) } else if let automationRun = try? AutomationRunState(from: decoder) { self = .automationRun(automationRun) diff --git a/types/channels-automation-run/state.ts b/types/channels-automation-run/state.ts index 33da62c0e..c829762c7 100644 --- a/types/channels-automation-run/state.ts +++ b/types/channels-automation-run/state.ts @@ -11,7 +11,7 @@ import type { AutomationEventTrigger, AutomationMisfirePolicy, AutomationScheduleTrigger, - AutomationState, + AutomationEntry, } from '../channels-automation/state.js'; import type { RunAutomationParams } from '../channels-automation/commands.js'; import type { SessionState } from '../channels-session/state.js'; @@ -232,7 +232,7 @@ export interface AutomationRunSummary { export interface AutomationRunState { /** URI of this automation-run channel. */ resource: URI; - /** Owning `ahp-automation:` URI matching {@link AutomationState.resource}. */ + /** Owning `ahp-automation:` URI matching {@link AutomationEntry.resource}. */ automation: URI; /** Immutable provenance describing how this run was created. */ origin: AutomationRunOrigin; diff --git a/types/channels-automation/actions.ts b/types/channels-automation/actions.ts index 4f7a75ce0..7c48eeb33 100644 --- a/types/channels-automation/actions.ts +++ b/types/channels-automation/actions.ts @@ -9,8 +9,8 @@ import { ActionType } from '../common/actions.js'; import type { Message } from '../channels-chat/state.js'; import type { URI } from '../common/state.js'; import type { - AutomationCatalogState, AutomationDefinition, + AutomationEntry, AutomationOperation, AutomationSessionTemplate, AutomationState, @@ -66,9 +66,9 @@ export interface AutomationDefinitionPatch { */ export interface AutomationCreateRequestedAction { type: ActionType.AutomationCreateRequested; - /** Client-chosen `ahp-automation:` URI that becomes {@link AutomationState.resource}. */ + /** Client-chosen `ahp-automation:` URI that becomes {@link AutomationEntry.resource}. */ resource: URI; - /** Complete initial {@link AutomationState.definition}. */ + /** Complete initial {@link AutomationEntry.definition}. */ definition: AutomationDefinition; } @@ -93,7 +93,7 @@ export interface AutomationCreateRequestedAction { */ export interface AutomationUpdateRequestedAction { type: ActionType.AutomationUpdateRequested; - /** Target {@link AutomationState.resource}. */ + /** Target {@link AutomationEntry.resource}. */ resource: URI; /** Editable {@link AutomationDefinition} fields to replace. */ changes: AutomationDefinitionPatch; @@ -101,9 +101,9 @@ export interface AutomationUpdateRequestedAction { /** * Add or replace one full automation state in - * {@link AutomationCatalogState.automations}. + * {@link AutomationState.entries}. * - * Existing entries are matched by {@link AutomationState.resource} and + * Existing entries are matched by {@link AutomationEntry.resource} and * replaced in place. A previously unseen resource is appended. * * @category Automation Actions @@ -112,11 +112,11 @@ export interface AutomationUpdateRequestedAction { export interface AutomationSetAction { type: ActionType.AutomationSet; /** Full new or replacement automation state. */ - automation: AutomationState; + automation: AutomationEntry; } /** - * Remove one automation from {@link AutomationCatalogState.automations}. + * Remove one automation from {@link AutomationState.entries}. * * Clients may dispatch this action only while the target advertises * {@link AutomationOperation.Remove}. The host revalidates that operation @@ -131,6 +131,6 @@ export interface AutomationSetAction { */ export interface AutomationRemovedAction { type: ActionType.AutomationRemoved; - /** {@link AutomationState.resource} to remove. */ + /** {@link AutomationEntry.resource} to remove. */ resource: URI; } diff --git a/types/channels-automation/commands.ts b/types/channels-automation/commands.ts index ed720fef9..0975f4dac 100644 --- a/types/channels-automation/commands.ts +++ b/types/channels-automation/commands.ts @@ -12,8 +12,8 @@ import type { AgentInfo } from '../channels-root/state.js'; import type { AutomationSetAction } from './actions.js'; import type { AutomationDefinition, + AutomationEntry, AutomationSessionTemplate, - AutomationState, AutomationTriggerDefinition, } from './state.js'; @@ -68,7 +68,7 @@ export interface ListAutomationTriggerDefinitionsResult { export interface RunAutomationParams extends BaseParams { /** Manual runs are scoped to the catalogue channel. */ channel: 'ahp-automations://'; - /** Target {@link AutomationState.resource}. */ + /** Target {@link AutomationEntry.resource}. */ automation: URI; /** * Durable client-generated idempotency key. Retrying with the same key and @@ -105,10 +105,10 @@ export interface RunAutomationResult { export interface FetchAutomationRunsParams extends BaseParams { /** Run-history loading is scoped to the catalogue channel. */ channel: 'ahp-automations://'; - /** Target {@link AutomationState.resource}. */ + /** Target {@link AutomationEntry.resource}. */ automation: URI; /** - * Cursor previously received as {@link AutomationState.runsNextCursor}. + * Cursor previously received as {@link AutomationEntry.runsNextCursor}. * Omit to request the first page not already included by the snapshot. */ cursor?: string; diff --git a/types/channels-automation/reducer.ts b/types/channels-automation/reducer.ts index 5544d5088..86649fab9 100644 --- a/types/channels-automation/reducer.ts +++ b/types/channels-automation/reducer.ts @@ -7,36 +7,36 @@ import type { AutomationAction } from '../action-origin.generated.js'; import { ActionType } from '../common/actions.js'; import { softAssertNever } from '../common/reducer-helpers.js'; -import type { AutomationCatalogState } from './state.js'; +import type { AutomationState } from './state.js'; /** Pure reducer for automation catalogue state. */ -export function automationReducer(state: AutomationCatalogState, action: AutomationAction, log?: (msg: string) => void): AutomationCatalogState { +export function automationReducer(state: AutomationState, action: AutomationAction, log?: (msg: string) => void): AutomationState { switch (action.type) { case ActionType.AutomationCreateRequested: case ActionType.AutomationUpdateRequested: return state; case ActionType.AutomationSet: { - const idx = state.automations.findIndex(automation => automation.resource === action.automation.resource); + const idx = state.entries.findIndex(automation => automation.resource === action.automation.resource); if (idx < 0) { return { ...state, - automations: [...state.automations, action.automation], + entries: [...state.entries, action.automation], }; } - const automations = state.automations.slice(); - automations[idx] = action.automation; - return { ...state, automations }; + const entries = state.entries.slice(); + entries[idx] = action.automation; + return { ...state, entries }; } case ActionType.AutomationRemoved: { - const idx = state.automations.findIndex(automation => automation.resource === action.resource); + const idx = state.entries.findIndex(automation => automation.resource === action.resource); if (idx < 0) { return state; } - const automations = state.automations.slice(); - automations.splice(idx, 1); - return { ...state, automations }; + const entries = state.entries.slice(); + entries.splice(idx, 1); + return { ...state, entries }; } default: diff --git a/types/channels-automation/state.ts b/types/channels-automation/state.ts index ceae8d65b..d77912f15 100644 --- a/types/channels-automation/state.ts +++ b/types/channels-automation/state.ts @@ -30,7 +30,7 @@ import type { /** * Operations the host currently permits for an automation. * - * The list on {@link AutomationState.operations} is authoritative and may + * The list on {@link AutomationEntry.operations} is authoritative and may * change over time. Clients MUST NOT infer permission from capabilities alone: * capabilities describe what the host implementation can support, while * operations describe what is allowed for this particular automation now. @@ -266,7 +266,7 @@ export interface AutomationSessionTemplate { * A definition combines the initial automation message, the session template * used for each run, and zero or more automatic triggers. Run history, * timestamps, and currently allowed operations live on - * {@link AutomationState} rather than in the definition. + * {@link AutomationEntry} rather than in the definition. * * @category Automation State */ @@ -295,8 +295,7 @@ export interface AutomationDefinition { } /** - * Authoritative state of one automation in the - * {@link AutomationCatalogState.automations} catalogue. + * Authoritative state of one automation in {@link AutomationState.entries}. * * The host owns trigger evaluation, run claims, run retention, and operation * availability. Clients render this state and submit actions or commands; they @@ -304,7 +303,7 @@ export interface AutomationDefinition { * * @category Automation State */ -export interface AutomationState { +export interface AutomationEntry { /** Stable `ahp-automation:/` resource identifier. */ resource: URI; /** Current durable definition. */ @@ -314,7 +313,7 @@ export interface AutomationState { /** * Newest-first retained run summaries. This is a bounded window; use * {@link FetchAutomationRunsParams | fetchAutomationRuns} when - * {@link AutomationState.runsNextCursor} is present. + * {@link AutomationEntry.runsNextCursor} is present. */ runs: AutomationRunSummary[]; /** Opaque cursor passed as {@link FetchAutomationRunsParams.cursor} for the next older run-history page. */ @@ -340,9 +339,9 @@ export interface AutomationState { * * @category Automation State */ -export interface AutomationCatalogState { - /** Full automation states keyed by {@link AutomationState.resource}. */ - automations: AutomationState[]; +export interface AutomationState { + /** Full automation entries keyed by {@link AutomationEntry.resource}. */ + entries: AutomationEntry[]; /** Opaque host-defined catalogue metadata. */ _meta?: Record; } diff --git a/types/channels-session/state.ts b/types/channels-session/state.ts index 9448aa29d..78db10000 100644 --- a/types/channels-session/state.ts +++ b/types/channels-session/state.ts @@ -16,7 +16,7 @@ import type { ToolCallAuthRequiredState, } from '../channels-chat/state.js'; import type { AutomationRunState } from '../channels-automation-run/state.js'; -import type { AutomationState } from '../channels-automation/state.js'; +import type { AutomationEntry } from '../channels-automation/state.js'; import type { ConfigPropertySchema, ErrorInfo, @@ -87,7 +87,7 @@ export const enum SessionOriginKind { */ export interface AutomationSessionOrigin { kind: SessionOriginKind.Automation; - /** Owning {@link AutomationState.resource}. */ + /** Owning {@link AutomationEntry.resource}. */ automation: URI; /** Owning {@link AutomationRunState.resource}. */ run: URI; diff --git a/types/common/commands.ts b/types/common/commands.ts index ec93fc825..14d181445 100644 --- a/types/common/commands.ts +++ b/types/common/commands.ts @@ -14,7 +14,7 @@ import type { AutomationCreateRequestedAction } from '../channels-automation/act import type { AutomationSchedule, AutomationScheduleTrigger, - AutomationCatalogState, + AutomationEntry, AutomationState, } from '../channels-automation/state.js'; import type { TelemetryCapabilities } from '../channels-otlp/state.js'; @@ -287,7 +287,7 @@ export interface InitializeResult { telemetry?: TelemetryCapabilities; /** * Host-owned automation support. Presence means clients may subscribe to - * `ahp-automations://` for {@link AutomationCatalogState}; absence means the + * `ahp-automations://` for {@link AutomationState}; absence means the * host does not expose an automation catalogue or automation commands. * * @see {@link /guide/automations | Automations Guide} @@ -303,7 +303,7 @@ export interface InitializeResult { * restrictions. * * Capabilities describe implementation support. - * {@link AutomationState.operations} remains authoritative for which + * {@link AutomationEntry.operations} remains authoritative for which * definition mutations are currently allowed on a particular automation. * * @category Commands @@ -319,7 +319,7 @@ export interface AutomationCapabilities { */ runCancellation?: AutomationRunCancellationCapability; /** - * Maximum terminal entries retained in {@link AutomationState.runs}. Active + * Maximum terminal entries retained in {@link AutomationEntry.runs}. Active * runs are not counted toward the limit. Absence means the retention limit is * implementation-defined. */ diff --git a/types/common/state.ts b/types/common/state.ts index 14df4904c..b56048c6a 100644 --- a/types/common/state.ts +++ b/types/common/state.ts @@ -14,7 +14,7 @@ import type { ChangesetState } from '../channels-changeset/state.js'; import type { ResourceWatchState } from '../channels-resource-watch/state.js'; import type { AnnotationsState } from '../channels-annotations/state.js'; import type { ChatState } from '../channels-chat/state.js'; -import type { AutomationCatalogState } from '../channels-automation/state.js'; +import type { AutomationState } from '../channels-automation/state.js'; import type { AutomationRunState } from '../channels-automation-run/state.js'; // ─── Type Aliases ──────────────────────────────────────────────────────────── @@ -335,7 +335,7 @@ export interface Snapshot { /** The subscribed channel URI (e.g. `ahp-root://`, `ahp-session:/`, or `ahp-chat:/`) */ resource: URI; /** The current state of the resource */ - state: RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationCatalogState | AutomationRunState; + state: RootState | SessionState | TerminalState | ChangesetState | ResourceWatchState | AnnotationsState | ChatState | AutomationState | AutomationRunState; /** The `serverSeq` at which this snapshot was taken. Subsequent actions will have `serverSeq > fromSeq`. */ fromSeq: number; } diff --git a/types/reducers.test.ts b/types/reducers.test.ts index fe8a9c0ce..cc90200a3 100644 --- a/types/reducers.test.ts +++ b/types/reducers.test.ts @@ -31,7 +31,7 @@ import { } from './reducers.js'; import { IS_CLIENT_DISPATCHABLE } from './action-origin.generated.js'; import { ActionType } from './actions.js'; -import type { RootState, SessionState, ChatState, TerminalState, ChangesetState, AnnotationsState, ResourceWatchState, AutomationCatalogState, AutomationRunState } from './state.js'; +import type { RootState, SessionState, ChatState, TerminalState, ChangesetState, AnnotationsState, ResourceWatchState, AutomationState, AutomationRunState } from './state.js'; import { SessionStatus, TurnState, @@ -73,7 +73,7 @@ function readChannelSources(baseName: string): string { // ─── Fixture Loading ───────────────────────────────────────────────────────── -type FixtureState = RootState | SessionState | ChatState | TerminalState | ChangesetState | AnnotationsState | ResourceWatchState | AutomationCatalogState | AutomationRunState; +type FixtureState = RootState | SessionState | ChatState | TerminalState | ChangesetState | AnnotationsState | ResourceWatchState | AutomationState | AutomationRunState; interface Fixture { description: string; @@ -128,7 +128,7 @@ describe('reducer fixtures', () => { } else if (fixture.reducer === 'resourceWatch') { state = resourceWatchReducer(state as ResourceWatchState, action as any); } else if (fixture.reducer === 'automation') { - state = automationReducer(state as AutomationCatalogState, action as any); + state = automationReducer(state as AutomationState, action as any); } else if (fixture.reducer === 'automationRun') { state = automationRunReducer(state as AutomationRunState, action as any); } else { diff --git a/types/test-cases/reducers/263-automation-set-appends.json b/types/test-cases/reducers/263-automation-set-appends.json index 50e0a0e1e..ce599b9ce 100644 --- a/types/test-cases/reducers/263-automation-set-appends.json +++ b/types/test-cases/reducers/263-automation-set-appends.json @@ -2,7 +2,7 @@ "description": "automation set appends a new catalogue entry", "reducer": "automation", "initial": { - "automations": [] + "entries": [] }, "actions": [{ "type": "automation/set", @@ -22,7 +22,7 @@ } }], "expected": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "A", diff --git a/types/test-cases/reducers/264-automation-set-replaces.json b/types/test-cases/reducers/264-automation-set-replaces.json index 3738d9554..254663bf5 100644 --- a/types/test-cases/reducers/264-automation-set-replaces.json +++ b/types/test-cases/reducers/264-automation-set-replaces.json @@ -2,7 +2,7 @@ "description": "automation set replaces an existing catalogue entry in place", "reducer": "automation", "initial": { - "automations": [ + "entries": [ { "resource": "ahp-automation:/a1", "definition": { @@ -51,7 +51,7 @@ } }], "expected": { - "automations": [ + "entries": [ { "resource": "ahp-automation:/a1", "definition": { diff --git a/types/test-cases/reducers/267-automation-removed-removes.json b/types/test-cases/reducers/267-automation-removed-removes.json index 6d8e7c0b9..9debbb226 100644 --- a/types/test-cases/reducers/267-automation-removed-removes.json +++ b/types/test-cases/reducers/267-automation-removed-removes.json @@ -2,7 +2,7 @@ "description": "automation removed deletes an existing catalogue entry", "reducer": "automation", "initial": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "A", @@ -22,6 +22,6 @@ "resource": "ahp-automation:/a1" }], "expected": { - "automations": [] + "entries": [] } } diff --git a/types/test-cases/reducers/269-automation-removed-noop.json b/types/test-cases/reducers/269-automation-removed-noop.json index 2c9ecf9c5..dcd6c1a8a 100644 --- a/types/test-cases/reducers/269-automation-removed-noop.json +++ b/types/test-cases/reducers/269-automation-removed-noop.json @@ -2,7 +2,7 @@ "description": "automation removed is a no-op for an unknown resource", "reducer": "automation", "initial": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "A", @@ -22,7 +22,7 @@ "resource": "ahp-automation:/missing" }], "expected": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "A", diff --git a/types/test-cases/reducers/270-automation-request-actions-noop.json b/types/test-cases/reducers/270-automation-request-actions-noop.json index 0d06ff872..f4a483906 100644 --- a/types/test-cases/reducers/270-automation-request-actions-noop.json +++ b/types/test-cases/reducers/270-automation-request-actions-noop.json @@ -2,7 +2,7 @@ "description": "automation create and update requests leave authoritative catalogue state unchanged", "reducer": "automation", "initial": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "A", @@ -38,7 +38,7 @@ } ], "expected": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "A", diff --git a/types/test-cases/round-trips/041-automation-catalogue-snapshot.json b/types/test-cases/round-trips/041-automation-catalogue-snapshot.json index abd3aaffb..7938b68dc 100644 --- a/types/test-cases/round-trips/041-automation-catalogue-snapshot.json +++ b/types/test-cases/round-trips/041-automation-catalogue-snapshot.json @@ -6,7 +6,7 @@ "input": { "resource": "ahp-automations://", "state": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "Triage", @@ -56,7 +56,7 @@ "acceptableOutputs": [{ "resource": "ahp-automations://", "state": { - "automations": [{ + "entries": [{ "resource": "ahp-automation:/a1", "definition": { "title": "Triage", diff --git a/types/version/registry.test.ts b/types/version/registry.test.ts index 35d618d62..29862ed4b 100644 --- a/types/version/registry.test.ts +++ b/types/version/registry.test.ts @@ -60,15 +60,15 @@ test('SUPPORTED_PROTOCOL_VERSIONS has no duplicates', () => { assert.equal(set.size, SUPPORTED_PROTOCOL_VERSIONS.length); }); -test('chat/turnResume is available starting in protocol 1.0.0', () => { +test('chat/turnResume is available starting in protocol 0.9.0', () => { const action = { type: ActionType.ChatTurnResume, turnId: 'turn-1', } as const; - assert.equal(ACTION_INTRODUCED_IN[ActionType.ChatTurnResume], '1.0.0'); + assert.equal(ACTION_INTRODUCED_IN[ActionType.ChatTurnResume], '0.9.0'); assert.equal(isActionKnownToVersion(action, '0.8.0'), false); - assert.equal(isActionKnownToVersion(action, '1.0.0'), true); + assert.equal(isActionKnownToVersion(action, '0.9.0'), true); }); test('public package entry re-exports both protocol-version constants', async () => { diff --git a/types/version/registry.ts b/types/version/registry.ts index 7dd1f9cf9..ddddc86e5 100644 --- a/types/version/registry.ts +++ b/types/version/registry.ts @@ -15,7 +15,7 @@ import type { ServerNotificationMap } from '../messages.js'; * * Formatted as a [SemVer](https://semver.org) `MAJOR.MINOR.PATCH` string. */ -export const PROTOCOL_VERSION = '1.0.0'; +export const PROTOCOL_VERSION = '0.9.0'; /** * Every protocol version a client built from this source tree is willing @@ -34,7 +34,7 @@ export const PROTOCOL_VERSION = '1.0.0'; * `scripts/verify-release-metadata.ts`. */ export const SUPPORTED_PROTOCOL_VERSIONS: readonly string[] = Object.freeze([ - '1.0.0', + '0.9.0', '0.8.0', '0.7.0', '0.6.0', @@ -125,7 +125,7 @@ export const ACTION_INTRODUCED_IN: { readonly [K in StateAction['type']]: string [ActionType.ChatTurnComplete]: '0.4.0', [ActionType.ChatTurnCancelled]: '0.4.0', [ActionType.ChatError]: '0.4.0', - [ActionType.ChatTurnResume]: '1.0.0', + [ActionType.ChatTurnResume]: '0.9.0', [ActionType.ChatActivityChanged]: '0.5.0', [ActionType.ChatWorkingDirectorySet]: '0.7.0', [ActionType.ChatWorkingDirectoryRemoved]: '0.7.0', From 472129a1f7e7c7044f44eaf62db266f2422f9006 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 28 Aug 2026 12:55:43 -0700 Subject: [PATCH 2/2] rust: format automation reducer imports Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/rust/crates/ahp/src/reducers.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index 0233ec089..95b02ff4d 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -57,14 +57,14 @@ use ahp_types::actions::{ ChatTurnStartedAction, StateAction, }; use ahp_types::state::{ - ActiveTurn, AnnotationsState, AutomationRunState, AutomationState, - ChangesetOperationStatus, ChangesetState, ChangesetStatus, ChatInputRequest, ChatState, - ChildCustomization, ConfirmationOption, Customization, CustomizationEnablement, - ErrorResponsePart, InputRequestResponsePart, McpServerStartingState, McpServerState, - McpServerStoppedState, PendingMessage, PendingMessageKind, ResourceWatchState, ResponsePart, - RootState, SessionInputRequest, SessionLifecycle, SessionState, SessionStatus, - TerminalCommandPart, TerminalContentPart, TerminalExitedLifecycleState, TerminalLifecycleState, - TerminalState, TerminalUnclassifiedPart, ToolCallAuthRequiredState, ToolCallCancellationReason, + ActiveTurn, AnnotationsState, AutomationRunState, AutomationState, ChangesetOperationStatus, + ChangesetState, ChangesetStatus, ChatInputRequest, ChatState, ChildCustomization, + ConfirmationOption, Customization, CustomizationEnablement, ErrorResponsePart, + InputRequestResponsePart, McpServerStartingState, McpServerState, McpServerStoppedState, + PendingMessage, PendingMessageKind, ResourceWatchState, ResponsePart, RootState, + SessionInputRequest, SessionLifecycle, SessionState, SessionStatus, TerminalCommandPart, + TerminalContentPart, TerminalExitedLifecycleState, TerminalLifecycleState, TerminalState, + TerminalUnclassifiedPart, ToolCallAuthRequiredState, ToolCallCancellationReason, ToolCallCancelledState, ToolCallCompletedState, ToolCallConfirmationReason, ToolCallContributor, ToolCallPendingConfirmationState, ToolCallPendingResultConfirmationState, ToolCallResponsePart, ToolCallRunningState, ToolCallState, ToolCallStatus,