You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently in the protocol, we have notifications, methods, and states that can be subscribed to. Looking in the future, we are potentially able to multiplex other protocols, and also have subscribable data that is per-client and not stateful. (Currently in the protocol we only subscribe to state.) There are lots of cases for this...
Logging (streaming, subscribable, but not state)
File watching
Port forwarding
MCP (soon! kind of, it's complex, but...)
Tasks/MCP Tasks
LSP
TURN/STUN negotation
I want to clean things up a bit by introducing the notion of 'channels'. This largely serves to give us a cohesive way to talk about these multiplexed protocols and pubsub-type mechanics.
Internals
A channel is identified by a URI, like state today. A channel MAY have a state associated with it. Inside the channel are notifications and method calls. The scheme of the channel identifies what type of data is it. For example:
ahp-root:// - canonical root state
ahp-session://... - session state
ahp-log://<level> - logging stream
lsp://... - LSP communication
Clients MUST NOT subscribe to any protocols they don't recognize. Methods and notifications in the protocol should be prefixed with a namespace like lsp/message and contain a channel: URI field.
For state subscriptions, this is mostly the same as what we do today.
sequenceDiagram
participant C as Client
participant S as Server
C->>S: subscribe { resource: "ahp-session:/abc" }
S-->>C: result { state: <snapshot>, fromSeq: 42 }
S-->>C: session/action { envelope, serverSeq: 43 }
C->>S: session/dispatch { clientSeq, action }
S-->>C: session/action { envelope, serverSeq: 44, origin: { clientSeq } }
C->>S: unsubscribe { resource: "ahp-session:/abc" }
Loading
For consumers who want logs, they can subscribe to the ahp-log://<level> channel of the appropriate type. This channel has no associated state, but just emits log information.
sequenceDiagram
participant C as Client
participant S as Server
C->>S: subscribe { resource: "ahp-log://warn" }
S-->>C: result { resource: "ahp-log://warn" }
S-->>C: log/message { resource, message: { level: "warn", msg: "..." } }
S-->>C: log/message { resource, message: { level: "error", msg: "..." } }
C->>S: unsubscribe { resource: "ahp-log://warn" }
Loading
For things like LSP communication, we can be more opaque. An LSP can be advertised or created in some way (that's for another proposal) and then the agent host can directly forward traffic over the lsp:// channel back and forth.
sequenceDiagram
participant App as Client app
participant C as AHP Client
participant S as AHP Server
participant L as LSP server (in host)
App->>C: open LSP for "typescript"
C->>S: subscribe { resource: "lsp://typescript" }
S->>L: spawn / attach
S-->>C: result { resource: "lsp://typescript" }
App->>C: LSP initialize
C->>S: lsp/message { resource, message: <LSP initialize> }
S->>L: <LSP initialize>
L-->>S: <LSP initialize result>
S-->>C: lsp/message { resource, message: <LSP initialize result> }
C-->>App: deliver
Note over App,L: bidirectional traffic continues until unsubscribe
C->>S: unsubscribe { resource: "lsp://typescript" }
S->>L: shutdown
Currently in the protocol, we have notifications, methods, and states that can be subscribed to. Looking in the future, we are potentially able to multiplex other protocols, and also have subscribable data that is per-client and not stateful. (Currently in the protocol we only subscribe to state.) There are lots of cases for this...
I want to clean things up a bit by introducing the notion of 'channels'. This largely serves to give us a cohesive way to talk about these multiplexed protocols and pubsub-type mechanics.
Internals
A channel is identified by a URI, like state today. A channel MAY have a state associated with it. Inside the channel are notifications and method calls. The scheme of the channel identifies what type of data is it. For example:
ahp-root://- canonical root stateahp-session://...- session stateahp-log://<level>- logging streamlsp://...- LSP communicationClients MUST NOT subscribe to any protocols they don't recognize. Methods and notifications in the protocol should be prefixed with a namespace like
lsp/messageand contain achannel: URIfield.For state subscriptions, this is mostly the same as what we do today.
sequenceDiagram participant C as Client participant S as Server C->>S: subscribe { resource: "ahp-session:/abc" } S-->>C: result { state: <snapshot>, fromSeq: 42 } S-->>C: session/action { envelope, serverSeq: 43 } C->>S: session/dispatch { clientSeq, action } S-->>C: session/action { envelope, serverSeq: 44, origin: { clientSeq } } C->>S: unsubscribe { resource: "ahp-session:/abc" }For consumers who want logs, they can subscribe to the
ahp-log://<level>channel of the appropriate type. This channel has no associated state, but just emits log information.sequenceDiagram participant C as Client participant S as Server C->>S: subscribe { resource: "ahp-log://warn" } S-->>C: result { resource: "ahp-log://warn" } S-->>C: log/message { resource, message: { level: "warn", msg: "..." } } S-->>C: log/message { resource, message: { level: "error", msg: "..." } } C->>S: unsubscribe { resource: "ahp-log://warn" }For things like LSP communication, we can be more opaque. An LSP can be advertised or created in some way (that's for another proposal) and then the agent host can directly forward traffic over the
lsp://channel back and forth.sequenceDiagram participant App as Client app participant C as AHP Client participant S as AHP Server participant L as LSP server (in host) App->>C: open LSP for "typescript" C->>S: subscribe { resource: "lsp://typescript" } S->>L: spawn / attach S-->>C: result { resource: "lsp://typescript" } App->>C: LSP initialize C->>S: lsp/message { resource, message: <LSP initialize> } S->>L: <LSP initialize> L-->>S: <LSP initialize result> S-->>C: lsp/message { resource, message: <LSP initialize result> } C-->>App: deliver Note over App,L: bidirectional traffic continues until unsubscribe C->>S: unsubscribe { resource: "lsp://typescript" } S->>L: shutdown