Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2396,7 +2396,9 @@ public sealed record AnnotationsUpdatedAction
///
/// This side-effect request leaves optimistic catalogue state unchanged. The
/// host validates trigger ids and configuration, normalizes event-trigger
/// titles and descriptions, persists the definition, then publishes the
/// titles and descriptions, captures any
/// {@link AutomationSessionTemplate.customizations | session customizations}
/// from the dispatching client, persists the definition, then publishes the
/// authoritative result with {@link AutomationSetAction | `automation/set`}.
/// Rejections leave the catalogue unchanged.</summary>
public sealed record AutomationCreateRequestedAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ public sealed record AutomationCapabilities
/// implementation-defined.</summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public long? RunHistoryLimit { get; init; }

/// <summary>Present when {@link AutomationSessionTemplate.customizations} may contain
/// client plugins for the host to capture.</summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public AutomationCustomizationsCapability? Customizations { get; init; }
}

/// <summary>Presence capability for {@link AutomationCreateRequestedAction |
Expand Down Expand Up @@ -333,6 +338,15 @@ public sealed record AutomationRunCancellationCapability
{
}

/// <summary>Presence capability for
/// {@link AutomationSessionTemplate.customizations | automation customizations}.
///
/// The empty object means "supported"; fields are reserved for future
/// capture options and limits.</summary>
public sealed record AutomationCustomizationsCapability
{
}

/// <summary>Re-establishes a dropped connection. The server replays missed actions or
/// provides fresh snapshots.</summary>
public sealed record ReconnectParams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace Microsoft.AgentHostProtocol;
[JsonSerializable(typeof(AutomationCompletedRunLifecycle))]
[JsonSerializable(typeof(AutomationCreateCapability))]
[JsonSerializable(typeof(AutomationCreateRequestedAction))]
[JsonSerializable(typeof(AutomationCustomizationsCapability))]
[JsonSerializable(typeof(AutomationDefinition))]
[JsonSerializable(typeof(AutomationDefinitionPatch))]
[JsonSerializable(typeof(AutomationEntry))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5228,6 +5228,32 @@ public sealed record AutomationSessionTemplate
/// {@link ResolveSessionConfigResult.values}.</summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Dictionary<string, JsonElement>? Config { get; init; }

/// <summary>Client plugins to make available in every run session, in the same
/// published shape as
/// {@link SessionActiveClient.customizations | `activeClients[].customizations`}.
/// Entries are keyed by `id`.
///
/// Runs usually start when no client is connected, so the host does not
/// resolve these URIs at run time. Instead, when it accepts a
/// {@link AutomationCreateRequestedAction | `automation/createRequested`} or
/// {@link AutomationUpdateRequestedAction | `automation/updateRequested`}
/// that adds an entry or changes an entry's `uri` or `nonce`, the host
/// captures a host-owned copy of the plugin. For client-served URIs such as
/// `virtual://…`, it reads the contents from the dispatching client with
/// server→client `resource*` requests. If a capture fails, the host rejects
/// the whole action. Entries whose `id`, `uri`, and `nonce` are unchanged keep
/// their existing copy, so any client can re-submit a template it received
/// without being able to serve the plugin itself. The resulting copies are
/// reported in {@link AutomationEntry.customizations}.
///
/// The host MAY share one stored copy between entries with equal `uri` and
/// `nonce`, including across automations; this is not observable to clients.
///
/// Clients MUST NOT set this field unless the host advertises
/// {@link AutomationCapabilities.customizations}.</summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<ClientPluginCustomization>? Customizations { get; init; }
}

/// <summary>Durable, client-editable definition of an automation.
Expand Down Expand Up @@ -5277,7 +5303,9 @@ public sealed record AutomationDefinitionPatch
public Message? Message { get; init; }

/// <summary>Replacement {@link AutomationDefinition.session}. The host revalidates
/// affected event triggers when their discovery context changes.</summary>
/// affected event triggers when their discovery context changes, and
/// captures {@link AutomationSessionTemplate.customizations} entries that
/// are new or whose `uri` or `nonce` changed.</summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public AutomationSessionTemplate? Session { get; init; }

Expand Down Expand Up @@ -5325,6 +5353,22 @@ public sealed class AutomationEntry
/// <summary>Operations currently permitted for this automation.</summary>
public required List<AutomationOperation> Operations { get; set; }

/// <summary>Host-owned copies of the plugins in
/// {@link AutomationSessionTemplate.customizations}, one per template entry
/// with the same `id`. Absent when the template has no customizations.
///
/// Each copy's `uri` identifies the captured contents, which clients can
/// browse with `resourceRead`. `children` and `load` report what the host
/// found in that copy, independent of whether the originating client is
/// connected. `clientId` is absent because the copy no longer depends on a
/// client.
///
/// Every run session receives these plugins in
/// {@link SessionState.customizations}, with the enablement from the
/// matching template entry.</summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<PluginCustomization>? Customizations { get; set; }

/// <summary>Creation timestamp in ISO 8601 format.</summary>
public required string CreatedAt { get; set; }

Expand Down
4 changes: 3 additions & 1 deletion clients/go/ahptypes/actions.generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -1573,7 +1573,9 @@ type ResourceWatchChangedAction struct {
//
// This side-effect request leaves optimistic catalogue state unchanged. The
// host validates trigger ids and configuration, normalizes event-trigger
// titles and descriptions, persists the definition, then publishes the
// titles and descriptions, captures any
// {@link AutomationSessionTemplate.customizations | session customizations}
// from the dispatching client, persists the definition, then publishes the
// authoritative result with {@link AutomationSetAction | `automation/set`}.
// Rejections leave the catalogue unchanged.
type AutomationCreateRequestedAction struct {
Expand Down
11 changes: 11 additions & 0 deletions clients/go/ahptypes/commands.generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ type AutomationCapabilities struct {
// runs are not counted toward the limit. Absence means the retention limit is
// implementation-defined.
RunHistoryLimit *int64 `json:"runHistoryLimit,omitempty"`
// Present when {@link AutomationSessionTemplate.customizations} may contain
// client plugins for the host to capture.
Customizations *AutomationCustomizationsCapability `json:"customizations,omitempty"`
}

// Presence capability for {@link AutomationCreateRequestedAction |
Expand Down Expand Up @@ -252,6 +255,14 @@ type AutomationScheduleCapabilities struct {
type AutomationRunCancellationCapability struct {
}

// Presence capability for
// {@link AutomationSessionTemplate.customizations | automation customizations}.
//
// The empty object means "supported"; fields are reserved for future
// capture options and limits.
type AutomationCustomizationsCapability struct {
}

// Identifies a protocol implementation — the software (and build) on one end
// of the connection, as distinct from the {@link AgentInfo | agent persona} it
// hosts. Carried as {@link InitializeParams.clientInfo | `clientInfo`} on the
Expand Down
42 changes: 41 additions & 1 deletion clients/go/ahptypes/state.generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -3939,6 +3939,30 @@ type AutomationSessionTemplate struct {
// {@link CreateSessionParams.config}, normally obtained from
// {@link ResolveSessionConfigResult.values}.
Config map[string]json.RawMessage `json:"config,omitempty"`
// Client plugins to make available in every run session, in the same
// published shape as
// {@link SessionActiveClient.customizations | `activeClients[].customizations`}.
// Entries are keyed by `id`.
//
// Runs usually start when no client is connected, so the host does not
// resolve these URIs at run time. Instead, when it accepts a
// {@link AutomationCreateRequestedAction | `automation/createRequested`} or
// {@link AutomationUpdateRequestedAction | `automation/updateRequested`}
// that adds an entry or changes an entry's `uri` or `nonce`, the host
// captures a host-owned copy of the plugin. For client-served URIs such as
// `virtual://…`, it reads the contents from the dispatching client with
// server→client `resource*` requests. If a capture fails, the host rejects
// the whole action. Entries whose `id`, `uri`, and `nonce` are unchanged keep
// their existing copy, so any client can re-submit a template it received
// without being able to serve the plugin itself. The resulting copies are
// reported in {@link AutomationEntry.customizations}.
//
// The host MAY share one stored copy between entries with equal `uri` and
// `nonce`, including across automations; this is not observable to clients.
//
// Clients MUST NOT set this field unless the host advertises
// {@link AutomationCapabilities.customizations}.
Customizations []ClientPluginCustomization `json:"customizations,omitempty"`
}

// Durable, client-editable definition of an automation.
Expand Down Expand Up @@ -3975,7 +3999,9 @@ type AutomationDefinitionPatch struct {
// Replacement {@link AutomationDefinition.message}.
Message *Message `json:"message,omitempty"`
// Replacement {@link AutomationDefinition.session}. The host revalidates
// affected event triggers when their discovery context changes.
// affected event triggers when their discovery context changes, and
// captures {@link AutomationSessionTemplate.customizations} entries that
// are new or whose `uri` or `nonce` changed.
Session *AutomationSessionTemplate `json:"session,omitempty"`
// Replacement {@link AutomationDefinition.enabled}.
Enabled *bool `json:"enabled,omitempty"`
Expand Down Expand Up @@ -4006,6 +4032,20 @@ type AutomationEntry struct {
RunsNextCursor *string `json:"runsNextCursor,omitempty"`
// Operations currently permitted for this automation.
Operations []AutomationOperation `json:"operations"`
// Host-owned copies of the plugins in
// {@link AutomationSessionTemplate.customizations}, one per template entry
// with the same `id`. Absent when the template has no customizations.
//
// Each copy's `uri` identifies the captured contents, which clients can
// browse with `resourceRead`. `children` and `load` report what the host
// found in that copy, independent of whether the originating client is
// connected. `clientId` is absent because the copy no longer depends on a
// client.
//
// Every run session receives these plugins in
// {@link SessionState.customizations}, with the enablement from the
// matching template entry.
Customizations []PluginCustomization `json:"customizations,omitempty"`
// Creation timestamp in ISO 8601 format.
CreatedAt string `json:"createdAt"`
// Last definition modification timestamp in ISO 8601 format.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,12 @@ data class AutomationCapabilities(
* runs are not counted toward the limit. Absence means the retention limit is
* implementation-defined.
*/
val runHistoryLimit: Long? = null
val runHistoryLimit: Long? = null,
/**
* Present when {@link AutomationSessionTemplate.customizations} may contain
* client plugins for the host to capture.
*/
val customizations: AutomationCustomizationsCapability? = null
)

@Serializable
Expand All @@ -450,6 +455,9 @@ data class AutomationScheduleCapabilities(
@Serializable
class AutomationRunCancellationCapability

@Serializable
class AutomationCustomizationsCapability

@Serializable
data class Implementation(
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5385,7 +5385,33 @@ data class AutomationSessionTemplate(
* {@link CreateSessionParams.config}, normally obtained from
* {@link ResolveSessionConfigResult.values}.
*/
val config: Map<String, JsonElement>? = null
val config: Map<String, JsonElement>? = null,
/**
* Client plugins to make available in every run session, in the same
* published shape as
* {@link SessionActiveClient.customizations | `activeClients[].customizations`}.
* Entries are keyed by `id`.
*
* Runs usually start when no client is connected, so the host does not
* resolve these URIs at run time. Instead, when it accepts a
* {@link AutomationCreateRequestedAction | `automation/createRequested`} or
* {@link AutomationUpdateRequestedAction | `automation/updateRequested`}
* that adds an entry or changes an entry's `uri` or `nonce`, the host
* captures a host-owned copy of the plugin. For client-served URIs such as
* `virtual://…`, it reads the contents from the dispatching client with
* server→client `resource*` requests. If a capture fails, the host rejects
* the whole action. Entries whose `id`, `uri`, and `nonce` are unchanged keep
* their existing copy, so any client can re-submit a template it received
* without being able to serve the plugin itself. The resulting copies are
* reported in {@link AutomationEntry.customizations}.
*
* The host MAY share one stored copy between entries with equal `uri` and
* `nonce`, including across automations; this is not observable to clients.
*
* Clients MUST NOT set this field unless the host advertises
* {@link AutomationCapabilities.customizations}.
*/
val customizations: List<ClientPluginCustomization>? = null
)

@Serializable
Expand Down Expand Up @@ -5432,7 +5458,9 @@ data class AutomationDefinitionPatch(
val message: Message? = null,
/**
* Replacement {@link AutomationDefinition.session}. The host revalidates
* affected event triggers when their discovery context changes.
* affected event triggers when their discovery context changes, and
* captures {@link AutomationSessionTemplate.customizations} entries that
* are new or whose `uri` or `nonce` changed.
*/
val session: AutomationSessionTemplate? = null,
/**
Expand Down Expand Up @@ -5479,6 +5507,22 @@ data class AutomationEntry(
* Operations currently permitted for this automation.
*/
val operations: List<AutomationOperation>,
/**
* Host-owned copies of the plugins in
* {@link AutomationSessionTemplate.customizations}, one per template entry
* with the same `id`. Absent when the template has no customizations.
*
* Each copy's `uri` identifies the captured contents, which clients can
* browse with `resourceRead`. `children` and `load` report what the host
* found in that copy, independent of whether the originating client is
* connected. `clientId` is absent because the copy no longer depends on a
* client.
*
* Every run session receives these plugins in
* {@link SessionState.customizations}, with the enablement from the
* matching template entry.
*/
val customizations: List<PluginCustomization>? = null,
/**
* Creation timestamp in ISO 8601 format.
*/
Expand Down
4 changes: 3 additions & 1 deletion clients/rust/crates/ahp-types/src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2066,7 +2066,9 @@ pub struct ResourceWatchChangedAction {
///
/// This side-effect request leaves optimistic catalogue state unchanged. The
/// host validates trigger ids and configuration, normalizes event-trigger
/// titles and descriptions, persists the definition, then publishes the
/// titles and descriptions, captures any
/// {@link AutomationSessionTemplate.customizations | session customizations}
/// from the dispatching client, persists the definition, then publishes the
/// authoritative result with {@link AutomationSetAction | `automation/set`}.
/// Rejections leave the catalogue unchanged.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
Expand Down
13 changes: 13 additions & 0 deletions clients/rust/crates/ahp-types/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,10 @@ pub struct AutomationCapabilities {
/// implementation-defined.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub run_history_limit: Option<i64>,
/// Present when {@link AutomationSessionTemplate.customizations} may contain
/// client plugins for the host to capture.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub customizations: Option<AutomationCustomizationsCapability>,
}

/// Presence capability for {@link AutomationCreateRequestedAction |
Expand Down Expand Up @@ -378,6 +382,15 @@ pub struct AutomationScheduleCapabilities {
#[serde(rename_all = "camelCase")]
pub struct AutomationRunCancellationCapability {}

/// Presence capability for
/// {@link AutomationSessionTemplate.customizations | automation customizations}.
///
/// The empty object means "supported"; fields are reserved for future
/// capture options and limits.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AutomationCustomizationsCapability {}

/// Identifies a protocol implementation — the software (and build) on one end
/// of the connection, as distinct from the {@link AgentInfo | agent persona} it
/// hosts. Carried as {@link InitializeParams.clientInfo | `clientInfo`} on the
Expand Down
Loading
Loading