microsoft / microsoft/agent-host-protocol
Kotlin client: no `AhpClient`, transport, or `MultiHostClient` — is this planned internally?
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 348
- Forks
- 122
- Avg merge
- 14h 12m
- Merged PRs (30d)
- 22
Description
Summary
The Kotlin client currently ships wire types + reducers only. It is the only
client in the repo with no connection layer at all, so a JVM/Android consumer
today has to hand-roll JSON-RPC framing, request correlation, and subscription
fan-out before it can talk to a host.
Before I invest in this, I'd like to check whether an Android/JVM client is
already being built internally — if so I'm happy to close this.
Current parity
| Client | types | reducers | Client | WS transport | MultiHost |
|---|---|---|---|---|---|
| Rust | ✓ | ✓ | ahp::Client |
ahp-ws |
✓ |
| Go | ✓ | ✓ | ahp.Client |
ahpws |
✓ |
| TypeScript | ✓ | ✓ | AhpClient |
src/ws |
✓ |
| Swift | ✓ | ✓ | AgentHostProtocolClient |
URLSession / NWConnection | ✓ |
| Kotlin | ✓ | ✓ | — | — | — |
clients/kotlin/src/main/kotlin/.../Ahp.kt is a single object exposing a
pre-configured Json; there is no transport package and no MultiHost* symbol
anywhere under clients/kotlin/.
What codegen already provides and a client can build on:
Actions/Commands/Errors/Messages/Notifications/State/Version.generated.kt
(~9.6k lines total)Reducers.kt(1730 lines), fixture-verified byFixtureDrivenReducerTestAhpCommandstyped request factories for every methodPROTOCOL_VERSION/SUPPORTED_PROTOCOL_VERSIONS
So this is purely hand-written client surface — no generator work required.
One design question worth settling first
The other clients decode an inbound frame of unknown shape through a single sum
type (Go: ahptypes.JsonRpcMessage with Request / Notification /
SuccessResponse / ErrorResponse). Kotlin has no equivalent — its JSON-RPC
types in Messages.generated.kt are generic over the params/result type
(JsonRpcRequest<P>, JsonRpcSuccessResponse<R>, JsonRpcNotification<P>),
which cannot be deserialized without knowing P up front.
Two options:
- Untyped inbound path (hand-written, no codegen change). Decode to
JsonElement, branch on the presence ofid/method/result/
error, then decodeparamsper method. Keeps generated code untouched. - Emit a
JsonRpcMessagesealed interface from codegen, mirroring Go and
Rust, so all clients share the same inbound model.
I lean towards (1) for the first PR to keep the change contained, but (2) is
the more consistent long-term shape. Happy to follow whichever you prefer.
Proposed sequence
Three reviewable PRs rather than one large one:
Transportinterface +AhpClientcore. Coroutine/Flow-based
equivalent ofahp.Client: request correlation,Flow<SubscriptionEvent>
fan-out per channel URI, server-initiated request handling
(resourceRead/resourceWrite/… +createResourceWatch),dispatchAction
with client-assignedclientSeq, graceful shutdown. Plus an in-memory
transport for tests, as Swift has (InMemoryTransport).- WebSocket transport. OkHttp or Ktor — see note below.
MultiHostClient. Port of thehostsmodule (host registry, per-host
client handles, client-id store, multi-host state mirror), matching the API
described indocs/guide/clients-multi-host.
Questions
- Is an Android/JVM AHP client already in progress internally?
- Preference between the two inbound-decoding options above?
- Transport dependency: OkHttp (ubiquitous on Android, but a new
non-kotlinxdependency) or Ktor client (multiplatform-friendly, aligns
with a possible future KMP target)? The current library is dependency-light
(kotlinx-serialization-jsononly, Java 8 bytecode, no Android SDK
dependency per the README), so I'd keep the WS transport in a separate
artifact the way Rust splitsahp/ahp-wsand Go splitsahp/
ahpws— leaving the core artifact dependency-light. Does that match how
you'd want the Maven coordinates laid out? - Should the coroutines dependency (
kotlinx-coroutines-core) land in the
core artifact, or would you rather the core stay callback-based to preserve
the current Java 8 / no-extra-deps posture?
I'm happy to start with PR 1 once the direction is confirmed.
Side note (separate, tiny)
Messages.generated.kt inlines the root channel URI as a literal:
fun ping(id: Long): JsonRpcRequest<JsonObject> =
JsonRpcRequest(id = id, method = "ping",
params = JsonObject(mapOf("channel" to JsonPrimitive("ahp-root://"))))
This is the same gap flagged in
clients/swift/.../AgentHostProtocolClient.swift:
TODO(codegen): Source this from `AgentHostProtocol` once codegen exposes a
shared constant (TypeScript/Rust/Swift would all benefit).
Kotlin would benefit too. I can send that as an independent PR if it's wanted —
say the word and I'll open a separate issue rather than mixing it in here.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with clients/kotlin/src/main/kotlin/.../Ahp.kt, Messages.generated.kt, and Reducers.kt, then compare the client and transport entry points in the Rust, Go, TypeScript, and Swift implementations. Resolve the inbound decoding and dependency choices before scoping the first PR. Done means an agreed, reviewable direction for the Kotlin client core rather than an implementation assembled from this issue alone.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin
- Domain
- api
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100