Skip to content

Session Channel

A session channel carries session-level state and acts as the coordination scope for one or more chats. The session tracks lifecycle, model/agent defaults, customizations, per-session configuration, changesets, and the catalog of chats that belong to the session. The per-conversation state — turns, streaming responses, tool calls, pending messages, and input requests — lives on the chat channel.

URI

ahp-session:/<uuid>

The path is a server-unique identifier (typically a UUID) chosen by the client at creation time. The session's provider (e.g. "copilot") is not encoded in the URI scheme — it is carried on SessionSummary.provider. This decoupling lets the same scheme address sessions backed by any agent.

Multiple session channels may be active simultaneously. Clients subscribe to each one whose state they want to track.

State

Subscribers receive a SessionState snapshot containing the session summary, lifecycle phase, the catalog of chats belonging to this session, the optional defaultChat routing hint, model and active-client state, customizations, changesets, and per-session configuration. Per-conversation state (turns, streaming, tool calls, pending messages, input requests) lives on the chat channel. Refer to the State Model guide for a structural overview.

Lifecycle

1. Client picks a session URI (e.g. ahp-session:/<new-uuid>)
2. Client sends createSession(uri, config) command
3. Client sends subscribe(uri) — MAY be batched with the command
4. Server creates session with lifecycle: 'creating', returns the snapshot
5. Server asynchronously initialises the agent backend
6. On success: server dispatches session/ready
7. On failure: server dispatches session/creationFailed
8. Server broadcasts root/sessionAdded to clients subscribed to ahp-root://

Creation

createSession is a JSON-RPC request. The client picks the URI; the server allocates session state and begins backend initialisation. If the URI is already in use the server returns SessionAlreadyExists (-32003).

Active session

Once a session reaches lifecycle: 'ready', clients may create chats on it with createChat. Each chat is independently subscribable at its own ahp-chat:/<cid> URI; see the Chat Channel specification for the per-chat lifecycle, turn flow, tool calls, and input request handling.

Session-scoped actions dispatched on this channel are limited to:

  • Catalog mutations — session/chatAdded, session/chatRemoved, session/chatUpdated, and session/defaultChatChanged.
  • Session-wide configuration — model and agent defaults, active-client tracking, customizations, changesets, lifecycle transitions.

All actions dispatched on this channel travel on ActionEnvelopes whose channel is the session URI. Action payloads do NOT carry their own session URI — the channel comes from the envelope.

Chat catalog mutations

Three discrete actions keep SessionState.chats in sync as chats come and go. Sessions with a single chat trivially round-trip a session/chatAdded once at creation; multi-chat sessions exercise all three:

ActionPayloadReducer behavior
session/chatAddedsummary: ChatSummaryUpsert by summary.resource. Appends when no entry has the same URI; otherwise replaces the existing entry. Mirrors root/sessionAdded.
session/chatRemovedchat: URIRemoves the matching entry. No-op when no entry matches. If state.defaultChat referenced the removed URI, the reducer clears it. Mirrors root/sessionRemoved.
session/chatUpdatedchat: URI, changes: Partial<ChatSummary>Merges the non-identity fields of changes onto the matching entry. No-op when no entry matches; clients SHOULD then wait for a session/chatAdded. Identity fields (resource) MUST NOT be carried in changes. Mirrors root/sessionSummaryChanged.

The producer of the chat's own ChatState is responsible for emitting matching session/chatUpdated actions so the catalog and the per-chat channel stay consistent.

Chat aggregation

SessionSummary carries session-wide identity (resource, provider, createdAt, workingDirectory) but several of its mutable fields are aggregates derived from the session's chats. Producers SHOULD apply these rules so clients that only consume the session summary (a session list, for example) still see meaningful state:

FieldDerivation rule
statusTake the activity bits (Idle / InProgress / InputNeeded / Error) from the defaultChat when set, else from the most recently modified chat. Promote InputNeeded if any chat needs input. Promote Error if any chat is in an error state. The orthogonal IsRead / IsArchived flags remain session-scoped and pass through unchanged.
activityMirror the activity string of the chat that contributes the activity bits — usually the default chat, but the chat that raised InputNeeded / Error when a non-default chat wins the promotion.
modifiedAtThe maximum of every chat's modifiedAt.
model / agentThe session-level selection. Per-chat overrides are surfaced on individual ChatSummary entries; do not aggregate them up.
workingDirectoryThe session-level default. Individual chats MAY override via ChatSummary.workingDirectory; aggregating per-chat overrides up is meaningless and SHOULD NOT be attempted.
changesOptional roll-up. Producers MAY sum per-chat changeset stats or report the most expensive chat's stats — whichever is cheaper to compute.

Sessions with a single chat satisfy all of the above trivially (the chat's values pass through). The rules only matter once a session carries multiple chats.

Disposal

jsonc
// Client → Server (request)
{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "disposeSession",
  "params": { "channel": "ahp-session:/<uuid>" },
}

The server tears down the session backend, drops associated subscriptions, and broadcasts root/sessionRemoved to clients subscribed to ahp-root://.

Methods and events on this channel

This section lists wire methods that are interpreted in the context of a session URI (ahp-session:/<uuid>).

Commands (params.channel = "ahp-session:/<uuid>")

MethodKindPurpose
createSessionrequestCreate a session at the chosen URI.
disposeSessionrequestDispose this session and its backend resources (cascades to every chat in the session's catalog).

Notifications (params.channel = "ahp-session:/<uuid>")

MethodKindMeaning
actionserver → client notificationSession action envelope (session/* action payloads — catalog updates, lifecycle, model/agent, customizations, changesets).
dispatchActionclient → server notificationDispatch client actions on this session (session/modelChanged, session/defaultChatChanged, ...).
unsubscribeclient → server notificationStop receiving messages for this session channel.

auth/required may also target a session URI when auth is required for an operation scoped to that session; see Authentication.

Server Validation of Client Actions

When the server receives a client-dispatched action on this channel, it MUST validate it before applying. Invalid actions MUST be echoed back with a rejectionReason on the ActionEnvelope. The following validation rules apply:

ActionConditionServer Behavior
Any action referencing a non-existent sessionChannel URI not foundServer MUST silently ignore the action (no echo)
session/modelChangedA turn is currently active in any chat in this sessionServer MUST defer the model change until every active turn completes, then apply it for next turns
session/agentChangedA turn is currently active in any chat in this sessionServer MUST defer the agent change until every active turn completes, then apply it for next turns
session/defaultChatChangeddefaultChat URI does not match an entry in the session's chat catalogServer MUST reject the action

Turn-, tool-call-, input-request-, and pending-message-level validation lives on the Chat Channel.

Actions

Refer to the Session Channel Reference for the full per-action reference. All session-scoped action envelopes carry channel: "ahp-session:/<uuid>".

Catalogue Notifications

Session catalogue events (creation, disposal, summary mutations) are emitted on the Root Channel, not on the session channel itself. This lets clients track the session list without subscribing to every session.

Released under the MIT License.