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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ Spec version: `0.5.2`
- `disableUserInvocation` on `SkillCustomization`, plus `disableModelInvocation`
and `disableUserInvocation` on `AgentCustomization`, giving custom agents and
skills a symmetric user/model invocation matrix.
- Optional `serverInfo` on `InitializeResult` and `clientInfo` on
`InitializeParams`, each an `Implementation` (`name`, optional `version`,
optional `title`), so either side of the handshake can identify its
implementation and build. Informational only — mirrors LSP/MCP and MUST NOT
be used for feature detection.

### Changed

Expand Down
5 changes: 5 additions & 0 deletions clients/go/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ Implements AHP 0.5.2.
`RuleCustomization`, `HookCustomization`).
- `DisableUserInvocation` on `SkillCustomization`, plus `DisableModelInvocation`
and `DisableUserInvocation` on `AgentCustomization`.
- Optional `ServerInfo` on `InitializeResult` and `ClientInfo` on
`InitializeParams`, each an `Implementation` struct (`Name`, optional
`Version`, optional `Title`), identifying the implementation and build behind
either side of the handshake. Informational only — MUST NOT be used for
feature detection.

### Changed

Expand Down
36 changes: 36 additions & 0 deletions clients/go/ahptypes/commands.generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ type InitializeParams struct {
ProtocolVersions []string `json:"protocolVersions"`
// Unique client identifier
ClientId string `json:"clientId"`
// Optional identity of the client implementation (name and version).
// Informational only — see {@link Implementation} for how it may and may not
// be used. Distinct from {@link InitializeParams.clientId | `clientId`},
// which is an opaque per-connection identifier used for reconnection, not a
// human-readable implementation name.
ClientInfo *Implementation `json:"clientInfo,omitempty"`
// URIs to subscribe to during handshake
InitialSubscriptions []URI `json:"initialSubscriptions,omitempty"`
// IETF BCP 47 language tag indicating the client's preferred locale
Expand Down Expand Up @@ -122,6 +128,12 @@ type InitializeResult struct {
ProtocolVersion string `json:"protocolVersion"`
// Current server sequence number
ServerSeq int64 `json:"serverSeq"`
// Optional identity of the server implementation (name and version).
// Informational only — see {@link Implementation} for how it may and may not
// be used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}
// identifies the negotiated protocol, `serverInfo` identifies the host
// software behind it.
ServerInfo *Implementation `json:"serverInfo,omitempty"`
// Snapshots for each `initialSubscriptions` URI
Snapshots []Snapshot `json:"snapshots"`
// Suggested default directory for remote filesystem browsing
Expand Down Expand Up @@ -159,6 +171,30 @@ type ClientCapabilities struct {
McpApps map[string]json.RawMessage `json:"mcpApps,omitempty"`
}

// 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
// client side and {@link InitializeResult.serverInfo | `serverInfo`} on the
// server side, mirroring LSP's `clientInfo`/`serverInfo` and MCP's
// `Implementation`.
//
// This is **informational only**: it exists for logging, telemetry, an
// about/status affordance, and — as a last resort — a known-issue workaround
// for a specific buggy build. It is **not** a feature-detection mechanism.
// Feature availability stays with the capability model
// ({@link ClientCapabilities} and the various `*.capabilities` declarations);
// implementations SHOULD NOT gate protocol behaviour on parsing
// {@link Implementation.version | `version`}.
type Implementation struct {
// Implementation name, e.g. a product or package identifier.
Name string `json:"name"`
// Implementation version. A [SemVer](https://semver.org) string is
// recommended but not required.
Version *string `json:"version,omitempty"`
// Optional human-readable display name.
Title *string `json:"title,omitempty"`
}

// Re-establishes a dropped connection. The server replays missed actions or
// provides fresh snapshots.
type ReconnectParams struct {
Expand Down
4 changes: 4 additions & 0 deletions clients/go/ahptypes/roundtrip_fixture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ func decodeAndReencode(t *testing.T, name, typ, inputJSON string) string {
var v PartialSessionSummary
dec(&v)
return enc(&v)
case "Implementation":
var v Implementation
dec(&v)
return enc(&v)
default:
t.Fatalf("%s: round-trip fixture: unknown wire type %q. Add a decode entry to decodeAndReencode.", name, typ)
return ""
Expand Down
4 changes: 4 additions & 0 deletions clients/kotlin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ Implements AHP 0.5.2.
`RuleCustomization`, `HookCustomization`).
- `disableUserInvocation` on `SkillCustomization`, plus `disableModelInvocation`
and `disableUserInvocation` on `AgentCustomization`.
- Optional `serverInfo` on `InitializeResult` and `clientInfo` on
`InitializeParams`, each an `Implementation` (`name`, optional `version`,
optional `title`), identifying the implementation and build behind either side
of the handshake. Informational only — MUST NOT be used for feature detection.

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ data class InitializeParams(
* Unique client identifier
*/
val clientId: String,
/**
* Optional identity of the client implementation (name and version).
* Informational only — see {@link Implementation} for how it may and may not
* be used. Distinct from {@link InitializeParams.clientId | `clientId`},
* which is an opaque per-connection identifier used for reconnection, not a
* human-readable implementation name.
*/
val clientInfo: Implementation? = null,
/**
* URIs to subscribe to during handshake
*/
Expand Down Expand Up @@ -155,6 +163,14 @@ data class InitializeResult(
* Current server sequence number
*/
val serverSeq: Long,
/**
* Optional identity of the server implementation (name and version).
* Informational only — see {@link Implementation} for how it may and may not
* be used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}
* identifies the negotiated protocol, `serverInfo` identifies the host
* software behind it.
*/
val serverInfo: Implementation? = null,
/**
* Snapshots for each `initialSubscriptions` URI
*/
Expand Down Expand Up @@ -198,6 +214,23 @@ data class ClientCapabilities(
val mcpApps: Map<String, JsonElement>? = null
)

@Serializable
data class Implementation(
/**
* Implementation name, e.g. a product or package identifier.
*/
val name: String,
/**
* Implementation version. A [SemVer](https://semver.org) string is
* recommended but not required.
*/
val version: String? = null,
/**
* Optional human-readable display name.
*/
val title: String? = null
)

@Serializable
data class ReconnectParams(
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ package com.microsoft.agenthostprotocol
import com.microsoft.agenthostprotocol.generated.ActionEnvelope
import com.microsoft.agenthostprotocol.generated.ChangesetOperationTarget
import com.microsoft.agenthostprotocol.generated.Customization
import com.microsoft.agenthostprotocol.generated.Implementation
import com.microsoft.agenthostprotocol.generated.JsonRpcErrorResponse
import com.microsoft.agenthostprotocol.generated.JsonRpcNotification
import com.microsoft.agenthostprotocol.generated.JsonRpcRequest
Expand Down Expand Up @@ -247,6 +248,7 @@ class RoundTripCorpusTest {
"SessionSummary" -> rt(SessionSummary.serializer())
"SessionAddedParams" -> rt(SessionAddedParams.serializer())
"PartialSessionSummary" -> rt(PartialSessionSummary.serializer())
"Implementation" -> rt(Implementation.serializer())
else -> fail(
"$file: unknown wire type \"$typeName\". " +
"Add a decode entry to decodeAndReencode.",
Expand Down
5 changes: 5 additions & 0 deletions clients/rust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ Implements AHP 0.5.2.
- `disable_user_invocation` on `SkillCustomization`, plus
`disable_model_invocation` and `disable_user_invocation` on
`AgentCustomization`.
- Optional `server_info` on `InitializeResult` and `client_info` on
`InitializeParams`, each an `Implementation` struct (`name`, optional
`version`, optional `title`), identifying the implementation and build behind
either side of the handshake. Informational only — MUST NOT be used for
feature detection.

### Changed

Expand Down
42 changes: 42 additions & 0 deletions clients/rust/crates/ahp-types/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ pub struct InitializeParams {
pub protocol_versions: Vec<String>,
/// Unique client identifier
pub client_id: String,
/// Optional identity of the client implementation (name and version).
/// Informational only — see {@link Implementation} for how it may and may not
/// be used. Distinct from {@link InitializeParams.clientId | `clientId`},
/// which is an opaque per-connection identifier used for reconnection, not a
/// human-readable implementation name.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub client_info: Option<Implementation>,
/// URIs to subscribe to during handshake
#[serde(default, skip_serializing_if = "Option::is_none")]
pub initial_subscriptions: Option<Vec<Uri>>,
Expand Down Expand Up @@ -142,6 +149,13 @@ pub struct InitializeResult {
pub protocol_version: String,
/// Current server sequence number
pub server_seq: i64,
/// Optional identity of the server implementation (name and version).
/// Informational only — see {@link Implementation} for how it may and may not
/// be used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}
/// identifies the negotiated protocol, `serverInfo` identifies the host
/// software behind it.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub server_info: Option<Implementation>,
/// Snapshots for each `initialSubscriptions` URI
pub snapshots: Vec<Snapshot>,
/// Suggested default directory for remote filesystem browsing
Expand Down Expand Up @@ -185,6 +199,34 @@ pub struct ClientCapabilities {
pub mcp_apps: Option<JsonObject>,
}

/// 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
/// client side and {@link InitializeResult.serverInfo | `serverInfo`} on the
/// server side, mirroring LSP's `clientInfo`/`serverInfo` and MCP's
/// `Implementation`.
///
/// This is **informational only**: it exists for logging, telemetry, an
/// about/status affordance, and — as a last resort — a known-issue workaround
/// for a specific buggy build. It is **not** a feature-detection mechanism.
/// Feature availability stays with the capability model
/// ({@link ClientCapabilities} and the various `*.capabilities` declarations);
/// implementations SHOULD NOT gate protocol behaviour on parsing
/// {@link Implementation.version | `version`}.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Implementation {
/// Implementation name, e.g. a product or package identifier.
pub name: String,
/// Implementation version. A [SemVer](https://semver.org) string is
/// recommended but not required.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
/// Optional human-readable display name.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}

/// Re-establishes a dropped connection. The server replays missed actions or
/// provides fresh snapshots.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
Expand Down
7 changes: 6 additions & 1 deletion clients/rust/crates/ahp-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
//! ## Build an `initialize` request
//!
//! ```
//! use ahp_types::commands::InitializeParams;
//! use ahp_types::commands::{Implementation, InitializeParams};
//! use ahp_types::messages::{JsonRpcMessage, JsonRpcRequest, JsonRpcVersion};
//! use ahp_types::common::AnyValue;
//!
Expand All @@ -68,6 +68,11 @@
//! initial_subscriptions: Some(vec!["ahp-root://".into()]),
//! locale: Some("en".into()),
//! capabilities: None,
//! client_info: Some(Implementation {
//! name: "my-host".into(),
//! version: Some("1.0.0".into()),
//! title: Some("My Host".into()),
//! }),
//! };
//!
//! let req = JsonRpcMessage::Request(JsonRpcRequest {
Expand Down
3 changes: 2 additions & 1 deletion clients/rust/crates/ahp-types/tests/roundtrip_corpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

use ahp_types::{
actions::{ActionEnvelope, StateAction},
commands::ChangesetOperationTarget,
commands::{ChangesetOperationTarget, Implementation},
common::StringOrMarkdown,
messages::JsonRpcMessage,
notifications::{PartialSessionSummary, SessionAddedParams},
Expand Down Expand Up @@ -219,6 +219,7 @@ fn decode_and_reencode(file: &str, type_name: &str, input_json: &str) -> Result<
"SessionSummary" => round_trip!(SessionSummary),
"SessionAddedParams" => round_trip!(SessionAddedParams),
"PartialSessionSummary" => round_trip!(PartialSessionSummary),
"Implementation" => round_trip!(Implementation),
other => Err(format!(
"{}: unknown wire type {:?}. Add a decode entry to decode_and_reencode.",
file, other
Expand Down
1 change: 1 addition & 0 deletions clients/rust/crates/ahp/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ impl Client {
},
locale: None,
capabilities: None,
client_info: None,
};
self.request("initialize", params).await
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ public struct InitializeParams: Codable, Sendable {
public var protocolVersions: [String]
/// Unique client identifier
public var clientId: String
/// Optional identity of the client implementation (name and version).
/// Informational only — see {@link Implementation} for how it may and may not
/// be used. Distinct from {@link InitializeParams.clientId | `clientId`},
/// which is an opaque per-connection identifier used for reconnection, not a
/// human-readable implementation name.
public var clientInfo: Implementation?
/// URIs to subscribe to during handshake
public var initialSubscriptions: [String]?
/// IETF BCP 47 language tag indicating the client's preferred locale
Expand All @@ -88,13 +94,15 @@ public struct InitializeParams: Codable, Sendable {
channel: String,
protocolVersions: [String],
clientId: String,
clientInfo: Implementation? = nil,
initialSubscriptions: [String]? = nil,
locale: String? = nil,
capabilities: ClientCapabilities? = nil
) {
self.channel = channel
self.protocolVersions = protocolVersions
self.clientId = clientId
self.clientInfo = clientInfo
self.initialSubscriptions = initialSubscriptions
self.locale = locale
self.capabilities = capabilities
Expand All @@ -108,6 +116,12 @@ public struct InitializeResult: Codable, Sendable {
public var protocolVersion: String
/// Current server sequence number
public var serverSeq: Int
/// Optional identity of the server implementation (name and version).
/// Informational only — see {@link Implementation} for how it may and may not
/// be used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}
/// identifies the negotiated protocol, `serverInfo` identifies the host
/// software behind it.
public var serverInfo: Implementation?
/// Snapshots for each `initialSubscriptions` URI
public var snapshots: [Snapshot]
/// Suggested default directory for remote filesystem browsing
Expand All @@ -127,13 +141,15 @@ public struct InitializeResult: Codable, Sendable {
public init(
protocolVersion: String,
serverSeq: Int,
serverInfo: Implementation? = nil,
snapshots: [Snapshot],
defaultDirectory: String? = nil,
completionTriggerCharacters: [String]? = nil,
telemetry: TelemetryCapabilities? = nil
) {
self.protocolVersion = protocolVersion
self.serverSeq = serverSeq
self.serverInfo = serverInfo
self.snapshots = snapshots
self.defaultDirectory = defaultDirectory
self.completionTriggerCharacters = completionTriggerCharacters
Expand Down Expand Up @@ -162,6 +178,26 @@ public struct ClientCapabilities: Codable, Sendable {
}
}

public struct Implementation: Codable, Sendable {
/// Implementation name, e.g. a product or package identifier.
public var name: String
/// Implementation version. A [SemVer](https://semver.org) string is
/// recommended but not required.
public var version: String?
/// Optional human-readable display name.
public var title: String?

public init(
name: String,
version: String? = nil,
title: String? = nil
) {
self.name = name
self.version = version
self.title = title
}
}

public struct ReconnectParams: Codable, Sendable {
/// Channel URI this command targets.
public var channel: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ final class TypesRoundTripFixtureTests: XCTestCase {
return try reencode(dec.decode(SessionAddedParams.self, from: inputData))
case "PartialSessionSummary":
return try reencode(dec.decode(PartialSessionSummary.self, from: inputData))
case "Implementation":
return try reencode(dec.decode(Implementation.self, from: inputData))
default:
throw FixtureError.message(
"round-trip fixture: unknown wire type \"\(type)\". Add a decode entry to decodeAndReencode.")
Expand Down
4 changes: 4 additions & 0 deletions clients/swift/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ Implements AHP 0.5.2.
`RuleCustomization`, `HookCustomization`).
- `disableUserInvocation` on `SkillCustomization`, plus `disableModelInvocation`
and `disableUserInvocation` on `AgentCustomization`.
- Optional `serverInfo` on `InitializeResult` and `clientInfo` on
`InitializeParams`, each an `Implementation` (`name`, optional `version`,
optional `title`), identifying the implementation and build behind either side
of the handshake. Informational only — MUST NOT be used for feature detection.

### Changed

Expand Down
Loading
Loading