@robota-sdk/agent-transport 3.0.0-beta.82 → 3.0.0-beta.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +795 -0
- package/README.md +80 -118
- package/dist/browser/client.d.ts +2 -2
- package/dist/browser/client.js +1 -1
- package/dist/browser/index.d.ts +87 -13
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/observer-messages-CEeisRaF.js +2 -0
- package/dist/browser/observer-messages-CEeisRaF.js.map +1 -0
- package/dist/browser/observer-messages-Dnff2Tdb.d.ts +471 -0
- package/dist/browser/observer-messages-Dnff2Tdb.d.ts.map +1 -0
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +308 -16
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.ts +308 -16
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +1 -1
- package/dist/node/node.cjs +1 -1
- package/dist/node/node.d.cts +69 -1
- package/dist/node/node.d.cts.map +1 -1
- package/dist/node/node.d.ts +70 -2
- package/dist/node/node.d.ts.map +1 -1
- package/dist/node/node.js +1 -1
- package/dist/node/node.js.map +1 -1
- package/package.json +17 -14
- package/src/__tests__/bearer-resource-gate.test.ts +120 -0
- package/src/__tests__/history-attached-budget.test.ts +216 -0
- package/src/__tests__/message-decoders.test.ts +496 -6
- package/src/__tests__/project-read-messages.test.ts +118 -0
- package/src/__tests__/session-detail-loop-status.test.ts +169 -0
- package/src/__tests__/session-directory-messages.test.ts +322 -0
- package/src/__tests__/session-error-classification.test.ts +113 -0
- package/src/__tests__/session-history-wire.test.ts +342 -0
- package/src/__tests__/session-message-handler-observe.test.ts +217 -0
- package/src/__tests__/session-message-handler.test.ts +139 -4
- package/src/__tests__/settings-messages.test.ts +193 -0
- package/src/__tests__/ws-broadcast-events.test.ts +10 -0
- package/src/client.ts +9 -1
- package/src/index.ts +18 -2
- package/src/loop-control-messages.ts +34 -0
- package/src/message-decoders.ts +238 -6
- package/src/node/bearer-resource-gate.ts +291 -0
- package/src/node/index.ts +13 -0
- package/src/observer-messages.ts +47 -0
- package/src/open-prompts.ts +76 -0
- package/src/outbound-delivery.ts +11 -2
- package/src/project-read-messages.ts +74 -0
- package/src/protocol-session.ts +23 -1
- package/src/session-directory-messages.ts +162 -0
- package/src/session-error-classification.ts +91 -0
- package/src/session-events.ts +100 -19
- package/src/session-message-handler.ts +110 -15
- package/src/session-query-messages.ts +123 -5
- package/src/session-resume-bridge.ts +8 -0
- package/src/settings-messages.ts +103 -0
- package/src/wire-messages.ts +238 -11
- package/dist/browser/message-decoders-BB8n-H2X.d.ts +0 -252
- package/dist/browser/message-decoders-BB8n-H2X.d.ts.map +0 -1
- package/dist/browser/message-decoders-CDmDoZPR.js +0 -2
- package/dist/browser/message-decoders-CDmDoZPR.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,42 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @robota-sdk/agent-transport
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
`@robota-sdk/agent-transport/node` no longer exports `buildHandoffManifest`,
|
|
11
|
-
`IBuildManifestInput`, `ISourceRuntimeState`, or `TManifestResult`. Handoff readiness and inventory
|
|
12
|
-
classification belong to `@robota-sdk/agent-interface-session-mobility`. A host composing a handoff
|
|
13
|
-
should check readiness before serializing, then pass the integrity of those exact bytes to the
|
|
14
|
-
mobility offer policy:
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
import {
|
|
18
|
-
assessHandoffReadiness,
|
|
19
|
-
prepareHandoffOffer,
|
|
20
|
-
type IPrepareHandoffOfferInput,
|
|
21
|
-
} from '@robota-sdk/agent-interface-session-mobility';
|
|
22
|
-
import { sealHandoffRecord } from '@robota-sdk/agent-transport/node';
|
|
23
|
-
|
|
24
|
-
function buildOffer(request: Omit<IPrepareHandoffOfferInput, 'integrity'>) {
|
|
25
|
-
const readiness = assessHandoffReadiness(request.runtime);
|
|
26
|
-
if (!readiness.ready) return readiness;
|
|
27
|
-
|
|
28
|
-
const { serialized, integrity } = sealHandoffRecord(request.record);
|
|
29
|
-
const offer = prepareHandoffOffer({ ...request, integrity });
|
|
30
|
-
if (!offer.built) return offer;
|
|
31
|
-
|
|
32
|
-
// Send serialized unchanged: offer.manifest.integrity describes these exact bytes.
|
|
33
|
-
return { manifest: offer.manifest, serialized };
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
For types, use `ISourceRuntimeState`, `IPrepareHandoffOfferInput`, and `THandoffOfferResult` from
|
|
38
|
-
session mobility. `IPrepareHandoffOfferInput` includes the integrity metadata produced by
|
|
39
|
-
`sealHandoffRecord`; the serialized payload remains a separate transport value.
|
|
3
|
+
The shared protocol layer under every Robota transport. It defines the transport-neutral wire messages
|
|
4
|
+
(`TClientMessage` / `TServerMessage`), the session bridge that turns those messages into calls on a live
|
|
5
|
+
session, and the delivery helpers a carrier needs (backpressure, resumable delivery, channel framing,
|
|
6
|
+
handoff payload chunking). The WebSocket and WebRTC transports carry its wire protocol, and the HTTP and
|
|
7
|
+
MCP transports use its admission and token-verification helpers. It opens no socket or listener of its
|
|
8
|
+
own.
|
|
40
9
|
|
|
41
10
|
## Installation
|
|
42
11
|
|
|
@@ -44,115 +13,108 @@ session mobility. `IPrepareHandoffOfferInput` includes the integrity metadata pr
|
|
|
44
13
|
npm install @robota-sdk/agent-transport
|
|
45
14
|
```
|
|
46
15
|
|
|
47
|
-
|
|
16
|
+
Requires Node.js 22.12 or later. The root and `./client` entry points also run in the browser.
|
|
48
17
|
|
|
49
|
-
|
|
50
|
-
transport packages.
|
|
18
|
+
## Entry points
|
|
51
19
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
| MCP | `@robota-sdk/agent-transport-mcp` | Model Context Protocol server adapter |
|
|
58
|
-
| WebRTC | `@robota-sdk/agent-transport-webrtc` | Peer-to-peer data-channel adapter |
|
|
20
|
+
| Import path | Environment | What it contains |
|
|
21
|
+
| ------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
22
|
+
| `@robota-sdk/agent-transport` | browser and Node | Wire message types, runtime decoders, `createSessionMessageHandler`, `createOutboundDelivery`, `SessionResumeBridge`, channel frame codec, peer-message ledger, handoff chunking |
|
|
23
|
+
| `@robota-sdk/agent-transport/client` | browser and Node | Only the wire message types and the runtime decoders (`decodeServerMessage`, `decodeClientMessage`, `decodeFrame`) |
|
|
24
|
+
| `@robota-sdk/agent-transport/node` | Node only | Transport admission (`resolveAdmission`, `mintTransportToken`, `credentialMatches`), OAuth access-token verification (`createAccessTokenVerifier`), the bearer resource-server gate, file transfer, handoff integrity (`sealHandoffRecord`, `verifyHandoffPayload`) |
|
|
59
25
|
|
|
60
|
-
|
|
61
|
-
|
|
26
|
+
Anything that needs `node:crypto` or the network lives under `./node`, so a browser bundle that imports
|
|
27
|
+
the root or `./client` never pulls in a Node built-in.
|
|
62
28
|
|
|
63
|
-
|
|
64
|
-
`TWorkspaceProjectAccess` decision through `projectAccess`; omitting it creates a Restricted session
|
|
65
|
-
that does not load project contributions.
|
|
29
|
+
## Usage: bridging a connection to a session
|
|
66
30
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
### Headless
|
|
31
|
+
A carrier (your socket, data channel, or stream) turns each connection into three things: an outbound
|
|
32
|
+
sink, a failure policy, and a feed of inbound text frames. The package does the rest.
|
|
70
33
|
|
|
71
34
|
```typescript
|
|
72
|
-
import {
|
|
35
|
+
import { createOutboundDelivery, createSessionMessageHandler } from '@robota-sdk/agent-transport';
|
|
36
|
+
import type { IProtocolSession, TServerMessage } from '@robota-sdk/agent-transport';
|
|
73
37
|
|
|
74
|
-
const
|
|
75
|
-
|
|
38
|
+
declare const session: IProtocolSession; // e.g. an InteractiveSession from @robota-sdk/agent-framework
|
|
39
|
+
declare const socket: { send(text: string): void; close(): void }; // one client connection
|
|
76
40
|
|
|
77
|
-
|
|
41
|
+
// Outbound: every frame to this connection goes through one delivery boundary. A failed send, or a
|
|
42
|
+
// peer that stops reading, calls the error handler once; the carrier then closes the connection.
|
|
43
|
+
const deliver = createOutboundDelivery(
|
|
44
|
+
(message: TServerMessage) => socket.send(JSON.stringify(message)),
|
|
45
|
+
() => socket.close(),
|
|
46
|
+
);
|
|
78
47
|
|
|
79
|
-
|
|
80
|
-
import { WsTransport } from '@robota-sdk/agent-transport-ws';
|
|
48
|
+
const handler = createSessionMessageHandler({ session, deliver });
|
|
81
49
|
|
|
82
|
-
|
|
50
|
+
// Inbound: pass each raw text frame from the client; call cleanup when the connection closes.
|
|
51
|
+
handler.onMessage(JSON.stringify({ type: 'submit', prompt: 'Hello' }));
|
|
52
|
+
handler.cleanup();
|
|
83
53
|
```
|
|
84
54
|
|
|
85
|
-
|
|
55
|
+
`onMessage` decodes and validates the frame itself; malformed input is answered with a protocol error,
|
|
56
|
+
not thrown. Pass `role: 'observe'` for a read-only connection: it can read the session's conversation
|
|
57
|
+
and state but cannot submit, answer prompts or control the session.
|
|
86
58
|
|
|
87
|
-
|
|
88
|
-
import { createHttpTransport } from '@robota-sdk/agent-transport-http';
|
|
89
|
-
|
|
90
|
-
const transport = createHttpTransport({ basePath: '/agent' }); // mount on your own server
|
|
91
|
-
```
|
|
59
|
+
## Composing a handoff offer
|
|
92
60
|
|
|
93
|
-
|
|
61
|
+
Moving a session to another device is split between two packages. Readiness and the offer policy
|
|
62
|
+
belong to `@robota-sdk/agent-interface-session-mobility`; this package seals the serialized record so
|
|
63
|
+
the receiver can verify it arrived intact. Check readiness first, then pass the integrity of those
|
|
64
|
+
exact bytes to the offer:
|
|
94
65
|
|
|
95
66
|
```typescript
|
|
96
|
-
import {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
67
|
+
import {
|
|
68
|
+
assessHandoffReadiness,
|
|
69
|
+
prepareHandoffOffer,
|
|
70
|
+
type IPrepareHandoffOfferInput,
|
|
71
|
+
} from '@robota-sdk/agent-interface-session-mobility';
|
|
72
|
+
import { sealHandoffRecord } from '@robota-sdk/agent-transport/node';
|
|
100
73
|
|
|
101
|
-
|
|
74
|
+
function buildOffer(request: Omit<IPrepareHandoffOfferInput, 'integrity'>) {
|
|
75
|
+
const readiness = assessHandoffReadiness(request.runtime);
|
|
76
|
+
if (!readiness.ready) return readiness;
|
|
102
77
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
78
|
+
const { serialized, integrity } = sealHandoffRecord(request.record);
|
|
79
|
+
const offer = prepareHandoffOffer({ ...request, integrity });
|
|
80
|
+
if (!offer.built) return offer;
|
|
106
81
|
|
|
107
|
-
|
|
108
|
-
|
|
82
|
+
// Send serialized unchanged: offer.manifest.integrity describes these exact bytes.
|
|
83
|
+
return { manifest: offer.manifest, serialized };
|
|
84
|
+
}
|
|
109
85
|
```
|
|
110
86
|
|
|
111
|
-
|
|
112
|
-
|
|
87
|
+
The receiver checks the bytes against `offer.manifest.integrity` with `verifyHandoffPayload` before
|
|
88
|
+
parsing them. A payload too large for one frame can be split with `chunkHandoffPayload` and reassembled
|
|
89
|
+
with `HandoffChunkAssembler`.
|
|
113
90
|
|
|
114
|
-
##
|
|
91
|
+
## Transport packages
|
|
115
92
|
|
|
116
|
-
|
|
93
|
+
Each carrier is its own package, so an application installs only the protocol dependencies it uses.
|
|
117
94
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
import { renderApp } from '@robota-sdk/agent-ui-terminal';
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
The framework root owns headless and programmatic surfaces plus `TransportRegistry`. The transport
|
|
128
|
-
root owns transport-neutral wire messages, session bridging, channel codecs, and delivery helpers;
|
|
129
|
-
browser decoders are also available from `@robota-sdk/agent-transport/client`, while Node-only
|
|
130
|
-
admission and handoff integrity helpers live under `@robota-sdk/agent-transport/node`.
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
import { createHeadlessTransport } from '@robota-sdk/agent-framework';
|
|
134
|
-
```
|
|
95
|
+
| Transport | Package | What it does |
|
|
96
|
+
| --------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
97
|
+
| WebSocket | [`@robota-sdk/agent-transport-ws`](../agent-transport-ws/README.md) | Serves a session on a loopback WebSocket server (token-authenticated by default) |
|
|
98
|
+
| HTTP | [`@robota-sdk/agent-transport-http`](../agent-transport-http/README.md) | Hono routes for submitting prompts and reading session state over HTTP + SSE |
|
|
99
|
+
| MCP | [`@robota-sdk/agent-transport-mcp`](../agent-transport-mcp/README.md) | Exposes a session as an MCP server over stdio or Streamable HTTP |
|
|
100
|
+
| WebRTC | [`@robota-sdk/agent-transport-webrtc`](../agent-transport-webrtc/README.md) | Carries a session peer-to-peer over a pairing-gated data channel (Node host side) |
|
|
135
101
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
`abandoned` records on stop or rollback.
|
|
102
|
+
The headless (non-interactive text / JSON / stream-JSON) transport and `TransportRegistry`, which
|
|
103
|
+
starts and stops a set of transports together, live in `@robota-sdk/agent-framework`. The terminal UI is
|
|
104
|
+
`@robota-sdk/agent-ui-terminal`; this package has no React or Ink dependency.
|
|
140
105
|
|
|
141
106
|
## Dependencies
|
|
142
107
|
|
|
143
|
-
- `@robota-sdk/agent-
|
|
144
|
-
- `@robota-sdk/agent-interface-command
|
|
145
|
-
|
|
146
|
-
-
|
|
147
|
-
- `@robota-sdk/agent-interface-session-mobility`
|
|
148
|
-
- `@robota-sdk/agent-interface-transport`
|
|
108
|
+
- `@robota-sdk/agent-core`
|
|
109
|
+
- `@robota-sdk/agent-interface-analytics`, `-command`, `-execution`, `-session`, `-session-mobility`,
|
|
110
|
+
`-transport` (contract packages)
|
|
111
|
+
- `jose` (access-token signature verification under `./node`)
|
|
149
112
|
|
|
150
|
-
The
|
|
151
|
-
|
|
152
|
-
(`@robota-sdk/agent-transport-{http,ws,mcp}`) and presentation packages
|
|
153
|
-
(`@robota-sdk/agent-ui-{terminal,web}`).
|
|
113
|
+
The protocol libraries (`ws`, `hono`, `@modelcontextprotocol/sdk`, `node-datachannel`) are
|
|
114
|
+
dependencies of the individual transport packages, not of this one.
|
|
154
115
|
|
|
155
|
-
##
|
|
116
|
+
## Documentation
|
|
156
117
|
|
|
157
|
-
- [
|
|
158
|
-
- [
|
|
118
|
+
- [docs/SPEC.md](./docs/SPEC.md) — package contract and boundaries
|
|
119
|
+
- [npm](https://www.npmjs.com/package/@robota-sdk/agent-transport) ·
|
|
120
|
+
[GitHub](https://github.com/woojubb/robota)
|
package/dist/browser/client.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { MAX_INBOUND_FRAME_BYTES, type TClientMessage, type TMessageDecodeResult, type TSeqServerMessage, type TServerMessage, decodeClientMessage, decodeFrame, decodeServerMessage };
|
|
1
|
+
import { a as decodeFrame, c as IWireHistoryEntry, d as TServerMessage, f as TWireExecutionResult, i as decodeClientMessage, l as TClientMessage, n as MAX_INBOUND_FRAME_BYTES, o as decodeServerMessage, r as TMessageDecodeResult, t as isObserverMessageType, u as TSeqServerMessage } from "./observer-messages-Dnff2Tdb.js";
|
|
2
|
+
export { type IWireHistoryEntry, MAX_INBOUND_FRAME_BYTES, type TClientMessage, type TMessageDecodeResult, type TSeqServerMessage, type TServerMessage, type TWireExecutionResult, decodeClientMessage, decodeFrame, decodeServerMessage, isObserverMessageType };
|
package/dist/browser/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{a as e,i as t,n,r,t as i}from"./observer-messages-CEeisRaF.js";export{n as MAX_INBOUND_FRAME_BYTES,r as decodeClientMessage,t as decodeFrame,e as decodeServerMessage,i as isObserverMessageType};
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as decodeFrame, c as IWireHistoryEntry, d as TServerMessage, f as TWireExecutionResult, i as decodeClientMessage, l as TClientMessage, n as MAX_INBOUND_FRAME_BYTES, o as decodeServerMessage, r as TMessageDecodeResult, s as IWireAgentDefinitionSummary, t as isObserverMessageType, u as TSeqServerMessage } from "./observer-messages-Dnff2Tdb.js";
|
|
2
|
+
import { ISessionAgentJobs, ISessionBackgroundGroups, ISessionBackgroundTasks, ISessionCommands, ISessionConversationRead, ISessionDirectory, ISessionDriverAttribution, ISessionEvents, ISessionExecutionDetail, ISessionExecutionState, ISessionExecutionWorkspace, ISessionProjectRead, ISessionPromptResolution, ISessionSelfPacedLoopControl, ISessionStatusRead, ISessionTurnControl, ISessionTurnSubmission, ISettingsSnapshot, TDriverId, TSettingsPatch } from "@robota-sdk/agent-interface-session";
|
|
2
3
|
import { IPersonalUsageReport, IPersonalUsageRequest, IUsageBySourceReport, TUsageSurface } from "@robota-sdk/agent-interface-analytics";
|
|
3
|
-
import {
|
|
4
|
+
import { TCommandSurfaceLocality } from "@robota-sdk/agent-interface-command";
|
|
4
5
|
import { IBinaryFrame, IChannelEventFrame, TChannelReceiveResult } from "@robota-sdk/agent-interface-transport";
|
|
5
6
|
import { IHandoffIntegrity, IPeerMessage, IPeerMessageAck, TPeerDeliveryState } from "@robota-sdk/agent-interface-session-mobility";
|
|
6
7
|
//#region src/outbound-delivery.d.ts
|
|
@@ -33,14 +34,22 @@ type TOutboundDeliver = ((message: TServerMessage) => void) & {
|
|
|
33
34
|
};
|
|
34
35
|
/**
|
|
35
36
|
* Observe THIS connection's first outbound delivery failure. `event` is the `type` of the frame that
|
|
36
|
-
* could not be delivered — a session event
|
|
37
|
-
* reply's type for a reply (`command_result`, `protocol_error`, …).
|
|
37
|
+
* could not be delivered — for the fan-out, the frame a session event was forwarded as (usually, not
|
|
38
|
+
* always, the event's own name), and the reply's type for a reply (`command_result`, `protocol_error`, …).
|
|
38
39
|
*
|
|
39
40
|
* Required, never optional: a carrier that could opt out of observing its own delivery failures is the
|
|
40
41
|
* silent-failure shape this boundary exists to remove.
|
|
41
42
|
*/
|
|
42
43
|
type TDeliveryErrorHandler = (error: Error, event: TServerMessage['type']) => void;
|
|
43
44
|
declare const DEFAULT_MAX_PENDING_BYTES: number;
|
|
45
|
+
/**
|
|
46
|
+
* Backpressure budget for a terminal attached to a session on the same host, in either role.
|
|
47
|
+
*
|
|
48
|
+
* 1 MiB, tighter than the default: an attached terminal reads a local socket, so a backlog this large
|
|
49
|
+
* means it stopped reading rather than that a network is slow. Exceeding it closes that connection
|
|
50
|
+
* only; the session never waits for a reader, so other surfaces keep streaming.
|
|
51
|
+
*/
|
|
52
|
+
declare const ATTACHED_SURFACE_MAX_PENDING_BYTES: number;
|
|
44
53
|
/**
|
|
45
54
|
* Is this carrier holding more than the budget allows?
|
|
46
55
|
*
|
|
@@ -86,7 +95,48 @@ declare function createOutboundDelivery(send: (message: TServerMessage) => void,
|
|
|
86
95
|
//#endregion
|
|
87
96
|
//#region src/protocol-session.d.ts
|
|
88
97
|
/** Session roles required by the shared WebSocket/WebRTC protocol. */
|
|
89
|
-
interface IProtocolSession extends ISessionTurnSubmission, ISessionTurnControl, ISessionCommands, ISessionEvents, ISessionPromptResolution, ISessionConversationRead, ISessionExecutionState, ISessionDriverAttribution, ISessionBackgroundTasks, ISessionBackgroundGroups, ISessionExecutionWorkspace {}
|
|
98
|
+
interface IProtocolSession extends ISessionTurnSubmission, ISessionTurnControl, ISessionCommands, ISessionStatusRead, ISessionEvents, ISessionPromptResolution, ISessionConversationRead, ISessionExecutionState, ISessionDriverAttribution, ISessionBackgroundTasks, ISessionBackgroundGroups, ISessionExecutionWorkspace, ISessionExecutionDetail, ISessionSelfPacedLoopControl, ISessionAgentJobs {}
|
|
99
|
+
/**
|
|
100
|
+
* #3282 §4c: a protocol session that ALSO answers the Project panel's reads. `Partial` (not a fourth
|
|
101
|
+
* mandatory role on {@link IProtocolSession} itself) deliberately: every existing test double and
|
|
102
|
+
* every other host that builds an `IProtocolSession` keeps type-checking unchanged, and the panel's
|
|
103
|
+
* three methods are runtime-probed (`typeof session.readProjectStatus === 'function'`) rather than
|
|
104
|
+
* assumed — `InteractiveSession` (the one production implementation) provides all three, satisfying
|
|
105
|
+
* this type with no further wiring.
|
|
106
|
+
*/
|
|
107
|
+
type TProjectReadCapableSession = IProtocolSession & Partial<ISessionProjectRead>;
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/settings-messages.d.ts
|
|
110
|
+
type TSettingsMessage = Extract<TClientMessage, {
|
|
111
|
+
type: 'get-settings' | 'update-settings';
|
|
112
|
+
}>;
|
|
113
|
+
declare function isSettingsMessage(msg: TClientMessage): msg is TSettingsMessage;
|
|
114
|
+
/** What applying a patch did: the fresh snapshot, or why nothing was written. */
|
|
115
|
+
type TSettingsUpdateOutcome = {
|
|
116
|
+
readonly ok: true;
|
|
117
|
+
readonly settings: ISettingsSnapshot;
|
|
118
|
+
} | {
|
|
119
|
+
readonly ok: false;
|
|
120
|
+
readonly code: 'not_available' | 'invalid' | 'refused' | 'update_failed';
|
|
121
|
+
readonly message: string;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* #3282 §4a: host-owned read/write for the Settings screen, supplied by the composition root the
|
|
125
|
+
* same way `IUsageQueryReporters` supplies usage reads — this package only correlates the request
|
|
126
|
+
* and carries the result. `updateSettings` applies through the SAME function the matching slash
|
|
127
|
+
* command uses (issue #3282 §4: "one code path, so the behavior matches the TUI"), so whatever a
|
|
128
|
+
* command would refuse on this surface is refused here too.
|
|
129
|
+
*/
|
|
130
|
+
interface ISettingsReporter {
|
|
131
|
+
getSettings(session: IProtocolSession, locality?: TCommandSurfaceLocality): ISettingsSnapshot | Promise<ISettingsSnapshot>;
|
|
132
|
+
/**
|
|
133
|
+
* Applies through the SAME function the matching slash command uses. `locality` (#3282 §4 part
|
|
134
|
+
* b-2) is forwarded to that command exactly as the transport received it, so a command that
|
|
135
|
+
* refuses a remote surface (installing a plugin) refuses identically here.
|
|
136
|
+
*/
|
|
137
|
+
updateSettings(session: IProtocolSession, patch: TSettingsPatch, locality?: TCommandSurfaceLocality): TSettingsUpdateOutcome | Promise<TSettingsUpdateOutcome>;
|
|
138
|
+
}
|
|
139
|
+
declare function handleSettingsMessage(session: IProtocolSession, deliver: TOutboundDeliver, msg: TSettingsMessage, reporter: ISettingsReporter | undefined, locality?: TCommandSurfaceLocality): void;
|
|
90
140
|
//#endregion
|
|
91
141
|
//#region src/usage-messages.d.ts
|
|
92
142
|
interface IUsageQueryReporters {
|
|
@@ -105,17 +155,17 @@ declare const PROTOCOL_SESSION_EVENT_CLASSIFICATION: {
|
|
|
105
155
|
readonly thinking: "forwarded";
|
|
106
156
|
readonly complete: "forwarded";
|
|
107
157
|
readonly error: "forwarded";
|
|
108
|
-
readonly context_update: "
|
|
109
|
-
readonly compact: "
|
|
158
|
+
readonly context_update: "forwarded";
|
|
159
|
+
readonly compact: "forwarded";
|
|
110
160
|
readonly interrupted: "forwarded";
|
|
111
|
-
readonly skill_activation: "
|
|
161
|
+
readonly skill_activation: "forwarded";
|
|
112
162
|
readonly background_task_event: "forwarded";
|
|
113
163
|
readonly background_job_group_event: "forwarded";
|
|
114
164
|
readonly execution_workspace_event: "forwarded";
|
|
115
165
|
readonly user_message: "forwarded";
|
|
116
|
-
readonly turn_source: "
|
|
166
|
+
readonly turn_source: "forwarded";
|
|
117
167
|
readonly context_file_refreshed: "forwarded";
|
|
118
|
-
readonly memory_event: "
|
|
168
|
+
readonly memory_event: "forwarded";
|
|
119
169
|
readonly goal_event: "non-surface";
|
|
120
170
|
readonly plan_event: "forwarded";
|
|
121
171
|
readonly branch_event: "forwarded";
|
|
@@ -125,12 +175,20 @@ declare const PROTOCOL_SESSION_EVENT_CLASSIFICATION: {
|
|
|
125
175
|
readonly ui_intent: "requester-routed";
|
|
126
176
|
readonly session_renamed: "forwarded";
|
|
127
177
|
readonly history_cleared: "forwarded";
|
|
178
|
+
readonly session_switched: "forwarded";
|
|
179
|
+
readonly status_changed: "forwarded";
|
|
128
180
|
};
|
|
129
181
|
//#endregion
|
|
130
182
|
//#region src/session-message-handler.d.ts
|
|
183
|
+
/**
|
|
184
|
+
* What a connected surface may do. `drive` sends prompts, answers questions and controls the session.
|
|
185
|
+
* `observe` is read-only: it follows this session's conversation and state, but never submits, answers,
|
|
186
|
+
* controls, or reads another session's records, and it never counts as a surface that can answer.
|
|
187
|
+
*/
|
|
188
|
+
type TSessionSurfaceRole = 'drive' | 'observe';
|
|
131
189
|
interface ISessionMessageHandlerOptions {
|
|
132
|
-
/** IProtocolSession to expose. */
|
|
133
|
-
session:
|
|
190
|
+
/** IProtocolSession to expose — `Partial<ISessionProjectRead>` is probed, not assumed (#3282 §4c). */
|
|
191
|
+
session: TProjectReadCapableSession;
|
|
134
192
|
/**
|
|
135
193
|
* ARCH-030: the CARRIER's connection-scoped outbound delivery boundary — not a raw `send`, and not a
|
|
136
194
|
* `send` plus an error callback for this handler to assemble into one. The carrier owns both the sink
|
|
@@ -147,12 +205,25 @@ interface ISessionMessageHandlerOptions {
|
|
|
147
205
|
driverId?: TDriverId;
|
|
148
206
|
/** Trusted carrier-owned product surface, kept separate from driver identity. */
|
|
149
207
|
surface?: TUsageSurface;
|
|
208
|
+
/** Carrier-decided role of this connection; defaults to `drive`. The client never chooses it here. */
|
|
209
|
+
role?: TSessionSurfaceRole;
|
|
150
210
|
/** Host-owned cross-session read model. The protocol only correlates and carries its result. */
|
|
151
211
|
personalUsageReporter?: NonNullable<IUsageQueryReporters['personalUsageReporter']>;
|
|
152
212
|
/** Host-owned current-session trace/cost producer for the pre-existing message family. */
|
|
153
213
|
usageReporter?: NonNullable<IUsageQueryReporters['usageReporter']>;
|
|
154
214
|
/** Host-owned stored-session producer used by cross-session drill-down. */
|
|
155
215
|
storedSessionUsageReporter?: NonNullable<IUsageQueryReporters['storedSessionUsageReporter']>;
|
|
216
|
+
/** Host-owned session directory (#3189): list, start and switch the host's sessions. */
|
|
217
|
+
sessionDirectory?: ISessionDirectory;
|
|
218
|
+
/** #3282 §4a: host-owned read/write for the GUI Settings screen. */
|
|
219
|
+
settingsReporter?: ISettingsReporter;
|
|
220
|
+
/**
|
|
221
|
+
* #3282 §4 part b-2: carrier-decided, like `role` — whether THIS carrier's connections are
|
|
222
|
+
* provably on this machine. The loopback WS carrier is `'local'`; the device-mesh/WebRTC carrier
|
|
223
|
+
* sets `'remote'`. Absent → `'local'`, forwarded to `executeCommand` and the settings reporter so a
|
|
224
|
+
* command that runs code from outside the session (installing a plugin) can refuse a remote device.
|
|
225
|
+
*/
|
|
226
|
+
commandSurfaceLocality?: TCommandSurfaceLocality;
|
|
156
227
|
}
|
|
157
228
|
/**
|
|
158
229
|
* Create a carrier-neutral message handler for an IProtocolSession.
|
|
@@ -282,6 +353,8 @@ interface ISessionResumeBridgeOptions {
|
|
|
282
353
|
readonly personalUsageReporter?: IUsageQueryReporters['personalUsageReporter'];
|
|
283
354
|
readonly usageReporter?: IUsageQueryReporters['usageReporter'];
|
|
284
355
|
readonly storedSessionUsageReporter?: IUsageQueryReporters['storedSessionUsageReporter'];
|
|
356
|
+
/** #3282 §4 part b-2: this bridge is the reconnectable WebRTC path, so it is always `'remote'`. */
|
|
357
|
+
readonly commandSurfaceLocality?: TCommandSurfaceLocality;
|
|
285
358
|
}
|
|
286
359
|
declare class SessionResumeBridge {
|
|
287
360
|
private readonly session;
|
|
@@ -289,6 +362,7 @@ declare class SessionResumeBridge {
|
|
|
289
362
|
private driverId?;
|
|
290
363
|
private readonly reporters;
|
|
291
364
|
private readonly surface?;
|
|
365
|
+
private readonly commandSurfaceLocality?;
|
|
292
366
|
private readonly unsubscribe;
|
|
293
367
|
private onDeliveryError?;
|
|
294
368
|
/**
|
|
@@ -516,5 +590,5 @@ declare class HandoffChunkAssembler {
|
|
|
516
590
|
*/
|
|
517
591
|
declare function chunkCountFor(integrity: IHandoffIntegrity, maxChunkBytes?: number): number;
|
|
518
592
|
//#endregion
|
|
519
|
-
export { CHANNEL_FRAME_MAGIC, CHANNEL_FRAME_VERSION, DEFAULT_MAX_CHUNK_BYTES, DEFAULT_MAX_PENDING_BYTES, DEFAULT_MAX_PENDING_MS, HandoffChunkAssembler, type IAttachOptions, type IBufferedFrame, type IChunkResult, type IHandoffChunk, type IPeerMessageLedger, type IPeerMessageRejection, type IPeerMessageVerdict, type IPendingStallClock, type IProtocolSession, type IResumeBufferOptions, type ISessionMessageHandlerOptions, type ISessionResumeBridgeOptions, MAX_INBOUND_FRAME_BYTES, PROTOCOL_SESSION_EVENT_CLASSIFICATION, ResumeBuffer, SessionResumeBridge, type TChunkOutcome, type TChunkRejection, type TClientMessage, type TDeliveryErrorHandler, type TMessageDecodeResult, type TOutboundDeliver, type TProtocolSessionEventClassification, type TResumeSink, type TResumeTail, type TSeqServerMessage, type TServerMessage, acknowledgePeerMessage, admitPeerMessage, chunkCountFor, chunkHandoffPayload, createOutboundDelivery, createPeerMessageLedger, createPendingStallClock, createSessionMessageHandler, decodeChannelFrame, decodeClientMessage, decodeFrame, decodeServerMessage, encodeBinaryFrame, encodeChannelEventFrame, forgetPeerOrigin, isChannelFrame, isOverPendingBudget };
|
|
593
|
+
export { ATTACHED_SURFACE_MAX_PENDING_BYTES, CHANNEL_FRAME_MAGIC, CHANNEL_FRAME_VERSION, DEFAULT_MAX_CHUNK_BYTES, DEFAULT_MAX_PENDING_BYTES, DEFAULT_MAX_PENDING_MS, HandoffChunkAssembler, type IAttachOptions, type IBufferedFrame, type IChunkResult, type IHandoffChunk, type IPeerMessageLedger, type IPeerMessageRejection, type IPeerMessageVerdict, type IPendingStallClock, type IProtocolSession, type IResumeBufferOptions, type ISessionMessageHandlerOptions, type ISessionResumeBridgeOptions, type ISettingsReporter, type IWireAgentDefinitionSummary, type IWireHistoryEntry, MAX_INBOUND_FRAME_BYTES, PROTOCOL_SESSION_EVENT_CLASSIFICATION, ResumeBuffer, SessionResumeBridge, type TChunkOutcome, type TChunkRejection, type TClientMessage, type TDeliveryErrorHandler, type TMessageDecodeResult, type TOutboundDeliver, type TProtocolSessionEventClassification, type TResumeSink, type TResumeTail, type TSeqServerMessage, type TServerMessage, type TSessionSurfaceRole, type TSettingsUpdateOutcome, type TWireExecutionResult, acknowledgePeerMessage, admitPeerMessage, chunkCountFor, chunkHandoffPayload, createOutboundDelivery, createPeerMessageLedger, createPendingStallClock, createSessionMessageHandler, decodeChannelFrame, decodeClientMessage, decodeFrame, decodeServerMessage, encodeBinaryFrame, encodeChannelEventFrame, forgetPeerOrigin, handleSettingsMessage, isChannelFrame, isObserverMessageType, isOverPendingBudget, isSettingsMessage };
|
|
520
594
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/outbound-delivery.ts","../../src/protocol-session.ts","../../src/usage-messages.ts","../../src/session-events.ts","../../src/session-message-handler.ts","../../src/resume-buffer.ts","../../src/channel-frames.ts","../../src/session-resume-bridge.ts","../../src/peer-message-ledger.ts","../../src/handoff-chunking.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/outbound-delivery.ts","../../src/protocol-session.ts","../../src/settings-messages.ts","../../src/usage-messages.ts","../../src/session-events.ts","../../src/session-message-handler.ts","../../src/resume-buffer.ts","../../src/channel-frames.ts","../../src/session-resume-bridge.ts","../../src/peer-message-ledger.ts","../../src/handoff-chunking.ts"],"mappings":";;;;;;;cAkCc;;;;;;;;;KAUF,qBAAqB,SAAS;YAC9B;;;;;;;;;;;;;;;WAgBD;;;;;;;;;;KAWC,yBAAyB,OAAO,OAAO,OAAO;cA0B7C;;;;;;;;cASA;;;;;;;;;;;;iBAaG,oBACd,6BACA;;;;;;;;;;;;;cAiBW;;;;;;;UAQI;WACN;;;;;;EAMT,UAAU;;iBAGI,wBACd,uBACA,qBACC;iBAkBa,uBACd,OAAO,SAAS,yBAChB,iBAAiB,uBACjB,yCACA,0BACA,aAAY,qBACX;;;;UCpKc,yBAEb,wBACA,qBACA,kBACA,oBACA,gBACA,0BACA,0BACA,wBACA,2BACA,yBACA,0BACA,4BACA,yBACA,8BAIA;;;;;;;;;KAUQ,6BAA6B,mBAAmB,QAAQ;;;KC3C/D,mBAAmB,QAAQ;EAAkB;;iBAElC,kBAAkB,KAAK,iBAAiB,OAAO;;KAKnD;WACG;WAAmB,UAAU;;WAE7B;WACA;WACA;;;;;;;;;UAUE;EACf,YACE,SAAS,kBACT,WAAW,0BACV,oBAAoB,QAAQ;;;;;;EAM/B,eACE,SAAS,kBACT,OAAO,gBACP,WAAW,0BACV,yBAAyB,QAAQ;;iBAGtB,sBACd,SAAS,kBACT,SAAS,kBACT,KAAK,kBACL,UAAU,+BACV,WAAW;;;UCpCI;WACN,yBACH,SAAS,0BAA0B,uBAAuB,QAAQ;WAE/D,iBACH,SAAS,qBAAqB,uBAAuB,QAAQ;WAE1D,8BACL,sBAAsB,uBAAuB,QAAQ;;;;KCiB/C;;cAGC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KCaD;UAEK;;EAEf,SAAS;;;;;;;;EAQT,SAAS;;;;;;EAMT,WAAW;;EAEX,UAAU;;EAEV,OAAO;;EAEP,wBAAwB,YAAY;;EAEpC,gBAAgB,YAAY;;EAE5B,6BAA6B,YAAY;;EAEzC,mBAAmB;;EAEnB,mBAAmB;;;;;;;EAOnB,yBAAyB;;;;;;;;;;;;;;;;;;;;;iBAsBX,4BAA4B,SAAS;EACnD,YAAY;EACZ;;;;;UCxGe;WACN;WACA,SAAS;;;KAIR;WACG;WAAuB,iBAAiB;;WACxC;;UAEE;;WAEN;;WAEA;;WAEA,UAAU,SAAS;;;;;;cAUjB;mBACM;mBACA;UACT;UACA;mBAES;mBACA;mBACA;EAEE,YAAA,UAAS;;EAOrB,OAAO,SAAS;;EAYhB,WAAW;;;;;;EAWX,UAAU,kBAAkB;;MAWxB;;MAKA;UAIH;;UAeA;;;;;cC3EG,qBAAqB;;cAGrB;;iBAwCG,kBAAkB,OAAO,eAAe;;iBASxC,wBAAwB,OAAO,qBAAqB;;iBAUpD,eAAe,OAAO;;;;;;iBAsCtB,mBAAmB,OAAO,aAAa;;;;KCzG3C,eAAe;;UAGV;;;;;;;;WAQN;;WAEA,kBAAkB,OAAO,OAAO;;;;;;;;WAQhC;;UAGM;WACN,SAAS;WACT,SAAS;;WAET,WAAW;WACX,UAAU;WACV,wBAAwB;WACxB,gBAAgB;WAChB,6BAA6B;;WAE7B,yBAAyB;;cAGvB;mBACM;mBACA;UACT;mBACS;mBACA;mBACA;mBACA;UACT;;;;;;;UAOA;;;;;;;;;;;;;;mBAcS;UACT;;UAEA;EAEW,YAAA,SAAS;;EA+BrB,OAAO,MAAM,aAAa,SAAS;;EAanC;;;;;EASA,YAAY,UAAU;;EAKtB,gBAAgB;;EA4BhB;;MAUI;;;;;;;;UAWH;;;;;;;;;;UAgBA;;UAgBA;;UAKA;;;;;;;;;;;;;;;;;;UC1MO;;EAEf;;EAEA,WAAW;;EAEX,QAAQ,YAAY;;;UAIL;WACN,SAAS,YAAY;;iBAGhB,2BAA2B;;UAK1B;WACN,OAAO,QAAQ;WACf;;UAGM;WACN,KAAK;;;;;;;;WAQL;;;;;;;WAOA;;;;;;;;;iBAUK,iBACd,QAAQ,oBACR,SAAS,cACT,YAAY,wBACX;;;;;;;;iBAyEa,uBACd,QAAQ,oBACR,yBACA,aACC;;iBAWa,iBAAiB,QAAQ,oBAAoB;;;;;;;;;;UCvJ5C;WACN;;WAEA;;WAEA;;WAEA;;;;;;;;;cAUE;;;;;;;;iBASG,oBACd,mBACA,oBACA,kCACU;;KAqBA;;;;;;;;;KAUA;;;;;;;UASK;WACN,SAAS;WACT,YAAY;;WAEZ;;WAEA;;WAEA;;;;;;;;;;cAWE;mBAIkB;mBAHZ;UACT;EAEqB,YAAA;MAEzB;MAIA;;EAKJ,OAAO,OAAO,gBAAgB;;EAmD9B;;EAQA;UAKQ;;;;;;;;iBAsBM,cACd,WAAW,mBACX"}
|
package/dist/browser/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e,n as t,r as n,t as r}from"./message-decoders-CDmDoZPR.js";function i(e,t,n){if(n.type===`get-background-tasks`){t({type:`background_tasks`,tasks:e.listBackgroundTasks(n.filter)});return}if(n.type===`get-background-task`){o(e,t,n);return}if(n.type===`get-background-job-groups`){t({type:`background_job_groups`,groups:e.listBackgroundJobGroups()});return}if(n.type===`get-background-job-group`){c(e,t,n);return}if(n.type===`wait-background-job-group`){l(e,t,n);return}s(e,t,n)}function a(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}if(n.type===`cancel-background-task`){d(t,`cancel`,n.taskId,e.cancelBackgroundTask(n.taskId,n.reason));return}if(n.type===`close-background-task`){d(t,`close`,n.taskId,e.closeBackgroundTask(n.taskId));return}u(e,t,n)}function o(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}t({type:`background_task`,taskId:n.taskId,task:e.getBackgroundTask(n.taskId)??null})}function s(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}e.readBackgroundTaskLog(n.taskId,n.cursor).then(e=>t({type:`background_task_log`,taskId:n.taskId,page:e}),e=>t({type:`protocol_error`,message:e.message}))}function c(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}t({type:`background_job_group`,groupId:n.groupId,group:e.getBackgroundJobGroup(n.groupId)??null})}function l(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}e.waitBackgroundJobGroup(n.groupId).then(e=>t({type:`background_job_group`,groupId:n.groupId,group:e}),e=>t({type:`protocol_error`,message:e.message}))}function u(e,t,n){if(!n.input){t({type:`protocol_error`,message:`input is required`});return}d(t,`send`,n.taskId,e.sendBackgroundTask(n.taskId,n.input))}function d(e,t,n,r){r.then(()=>e({type:`background_task_control_result`,action:t,taskId:n,success:!0}),r=>e({type:`background_task_control_result`,action:t,taskId:n,success:!1,message:r.message}))}function f(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function p(e){return typeof e==`string`&&e.length>0?e:void 0}function m(e){if(!(new TextEncoder().encode(e).byteLength>4194304))try{let t=JSON.parse(e);if(!f(t))return;let n=p(t.requestId);if(!n)return;if(t.type===`get-personal-usage-report`)return{type:`personal`,requestId:n};let r=p(t.sessionId);return t.type===`get-stored-session-usage-report`&&r?{type:`stored-session`,requestId:n,sessionId:r}:void 0}catch{return}}function h(e,t,n,r){return n.type===`get-personal-usage-report`?(y(t,n,r.personalUsageReporter),!0):n.type===`get-stored-session-usage-report`?(_(t,n,r.storedSessionUsageReporter),!0):n.type===`get-usage-report`?(g(e,t,r.usageReporter),!0):!1}function g(e,t,n){if(!n){t({type:`protocol_error`,message:`Per-session usage reporting is not available on this host.`});return}try{Promise.resolve(n(e)).then(e=>t({type:`usage_report`,report:e}),e=>t({type:`protocol_error`,message:x(e)}))}catch(e){t({type:`protocol_error`,message:x(e instanceof Error?e:String(e))})}}function _(e,t,n){if(!n){v(e,t,`not_available`,`Stored-session usage reporting is not available on this host.`);return}try{Promise.resolve(n(t.sessionId)).then(n=>e({type:`stored_session_usage_report`,requestId:t.requestId,sessionId:t.sessionId,report:n}),n=>v(e,t,`report_failed`,x(n)))}catch(n){v(e,t,`report_failed`,x(n instanceof Error?n:String(n)))}}function v(e,t,n,r){e({type:`stored_session_usage_report_error`,requestId:t.requestId,sessionId:t.sessionId,code:n,message:r})}function y(e,t,n){if(!n){b(e,t.requestId,`not_available`,`Personal usage reporting is not available on this host.`);return}try{Promise.resolve(n({period:t.period,timezone:t.timezone})).then(n=>e({type:`personal_usage_report`,requestId:t.requestId,report:n}),n=>b(e,t.requestId,`report_failed`,x(n)))}catch(n){b(e,t.requestId,`report_failed`,x(n instanceof Error?n:String(n)))}}function b(e,t,n,r){e({type:`personal_usage_report_error`,requestId:t,code:n,message:r})}function x(e){return e instanceof Error?e.message:String(e)}function S(e,r){let i=n(e,t);if(i.ok)return i.message;let a=m(e);return a?.type===`personal`?(r({type:`personal_usage_report_error`,requestId:a.requestId,code:`report_failed`,message:`Invalid personal usage report request.`}),null):a?.type===`stored-session`?(r({type:`stored_session_usage_report_error`,requestId:a.requestId,sessionId:a.sessionId,code:`report_failed`,message:`Invalid stored-session usage report request.`}),null):(r({type:`protocol_error`,message:i.reason}),null)}const C={text_delta:`forwarded`,tool_start:`forwarded`,tool_end:`forwarded`,thinking:`forwarded`,complete:`forwarded`,error:`forwarded`,context_update:`non-surface`,compact:`non-surface`,interrupted:`forwarded`,skill_activation:`non-surface`,background_task_event:`forwarded`,background_job_group_event:`forwarded`,execution_workspace_event:`forwarded`,user_message:`forwarded`,turn_source:`non-surface`,context_file_refreshed:`forwarded`,memory_event:`non-surface`,goal_event:`non-surface`,plan_event:`forwarded`,branch_event:`forwarded`,permission_request:`forwarded`,ask_request:`forwarded`,prompt_resolved:`forwarded`,ui_intent:`requester-routed`,session_renamed:`forwarded`,history_cleared:`forwarded`};function w(e,t,n={}){let r=()=>{let t=e.getActiveDriverId();return t?{driverId:t}:{}},i=e=>t({type:`user_message`,content:e,...r()}),a=e=>t({type:`text_delta`,delta:e,...r()}),o=e=>t({type:`tool_start`,state:e,...r()}),s=e=>t({type:`tool_end`,state:e,...r()}),c=e=>t({type:`thinking`,isThinking:e,...r()}),l=e=>t({type:`complete`,result:e,...r()}),u=e=>t({type:`interrupted`,result:e,...r()}),d=e=>t({type:`error`,message:e.message,...r()}),f=e=>t({type:`background_task_event`,event:e}),p=e=>t({type:`background_job_group_event`,event:e}),m=e=>t({type:`execution_workspace_event`,snapshot:e.snapshot}),h=e=>t({type:`plan_event`,event:e}),g=e=>t({type:`context_file_refreshed`,event:e}),_=e=>t({type:`branch_event`,event:e}),v=e=>t({type:`permission_request`,event:e}),y=e=>t({type:`ask_request`,event:e}),b=e=>t({type:`prompt_resolved`,event:e}),x=e=>{(e.requesterDriverId===void 0||e.requesterDriverId===n.getSurfaceDriverId?.())&&t({type:`ui_intent`,event:e})},S=e=>t({type:`session_renamed`,event:e}),C=()=>t({type:`history_cleared`});return e.on(`user_message`,i),e.on(`text_delta`,a),e.on(`tool_start`,o),e.on(`tool_end`,s),e.on(`thinking`,c),e.on(`complete`,l),e.on(`interrupted`,u),e.on(`error`,d),e.on(`background_task_event`,f),e.on(`background_job_group_event`,p),e.on(`execution_workspace_event`,m),e.on(`plan_event`,h),e.on(`context_file_refreshed`,g),e.on(`branch_event`,_),e.on(`permission_request`,v),e.on(`ask_request`,y),e.on(`prompt_resolved`,b),e.on(`ui_intent`,x),e.on(`session_renamed`,S),e.on(`history_cleared`,C),()=>{e.off(`user_message`,i),e.off(`text_delta`,a),e.off(`tool_start`,o),e.off(`tool_end`,s),e.off(`thinking`,c),e.off(`complete`,l),e.off(`interrupted`,u),e.off(`error`,d),e.off(`background_task_event`,f),e.off(`background_job_group_event`,p),e.off(`execution_workspace_event`,m),e.off(`plan_event`,h),e.off(`context_file_refreshed`,g),e.off(`branch_event`,_),e.off(`permission_request`,v),e.off(`ask_request`,y),e.off(`prompt_resolved`,b),e.off(`ui_intent`,x),e.off(`session_renamed`,S),e.off(`history_cleared`,C)}}function T(e){return e.type===`get-messages`||e.type===`get-context`||e.type===`get-executing`||e.type===`get-pending`||e.type===`get-execution-workspace`}function ee(e,t,n){n.type===`get-messages`?t({type:`messages`,messages:e.getMessages()}):n.type===`get-context`?t({type:`context`,state:e.getContextState()}):n.type===`get-executing`?t({type:`executing`,executing:e.isExecuting()}):n.type===`get-execution-workspace`?t({type:`execution_workspace_event`,snapshot:e.getExecutionWorkspaceSnapshot()}):t({type:`pending`,pending:e.getPendingPrompt()})}function E(e){let t=w(e.session,e.deliver,{getSurfaceDriverId:()=>e.driverId});return{onMessage:D(e.session,e.deliver,e.driverId,{personalUsageReporter:e.personalUsageReporter,usageReporter:e.usageReporter,storedSessionUsageReporter:e.storedSessionUsageReporter},e.surface),cleanup:t}}function D(e,t,n,r=O,i){return a=>{let o=S(a,t);o&&k(e,t,o,n,r,i)}}const O={personalUsageReporter:void 0,usageReporter:void 0,storedSessionUsageReporter:void 0};function k(e,t,n,r,o=O,s){if(h(e,t,n,o))return;if(te(n)){P(e,t,n,r,s);return}if(T(n)){ee(e,t,n);return}if(A(n)){i(e,t,n);return}if(j(n)){a(e,t,n);return}if(M(n)){N(e,n,r);return}let c=n.type;t({type:`protocol_error`,message:`Unknown message type: ${c}`})}function te(e){return e.type===`submit`||e.type===`command`||e.type===`abort`||e.type===`cancel-queue`}function A(e){return e.type===`get-background-tasks`||e.type===`get-background-task`||e.type===`read-background-task-log`||e.type===`get-background-job-groups`||e.type===`get-background-job-group`||e.type===`wait-background-job-group`}function j(e){return e.type===`cancel-background-task`||e.type===`close-background-task`||e.type===`send-background-task`}function M(e){return e.type===`permission-response`||e.type===`ask-response`}function N(e,t,n){t.type===`permission-response`?e.resolvePermission(t.id,t.result,n):e.resolveAsk(t.id,t.response,n)}function P(e,t,n,r,i){if(n.type===`submit`){if(typeof n.prompt!=`string`||n.prompt.length===0){t({type:`protocol_error`,message:`prompt must be a non-empty string`});return}let a={...r?{driverId:r}:{},...i?{surface:i}:{}};e.submit(n.prompt,void 0,void 0,Object.keys(a).length>0?a:void 0).catch(e=>{t({type:`protocol_error`,message:e.message})})}else if(n.type===`command`){if(!n.name){t({type:`protocol_error`,message:`name is required`});return}e.executeCommand(n.name,n.args??``,`remote`,r).then(e=>{t({type:`command_result`,name:n.name,message:e?.message??`Unknown command: ${n.name}`,success:e?.success??!1,data:e?.data})},e=>{t({type:`protocol_error`,message:e.message})})}else n.type===`abort`?e.abort():e.cancelQueue()}const F=8*1048576;function I(e,t=F){return e!==void 0&&e>t}const L=120*1e3;function R(e=L,t=Date.now){let n;return{maxPendingMs:e,observe(r){if(r===void 0)return;if(r===0){n=void 0;return}let i=t();n??=i;let a=i-n;return a>e?a:void 0}}}function z(e,t,n,r=F,i=R()){let a=!1,o=t=>{if(a)return;let o=n?.();if(I(o,r)){a=!0,s(Error(`outbound backpressure budget exceeded: ${o} byte(s) pending, limit ${r}. The peer has accepted frames it is not reading.`),t.type);return}let c=i.observe(o);if(c!==void 0){a=!0,s(Error(`outbound drain budget exceeded: ${o} byte(s) pending for ${c} ms, limit ${i.maxPendingMs} ms. The peer is reading too slowly to ever drain what it accepted.`),t.type);return}try{e(t)}catch(e){a=!0,s(e instanceof Error?e:Error(String(e)),t.type)}};function s(e,n){try{t(e,n)}catch{}}return Object.assign(o,{pendingBytes:()=>n?.()})}var B=class{frames=[];sizes=[];nextSeq=1;bytes=0;maxFrames;maxBytes;sizeOf;constructor(e={}){this.maxFrames=e.maxFrames??512,this.maxBytes=e.maxBytes??4194304,this.sizeOf=e.sizeOf??(e=>JSON.stringify(e).length)}append(e){let t=this.nextSeq;this.nextSeq+=1;let n=this.sizeOf(e);return this.frames.push({seq:t,message:e}),this.sizes.push(n),this.bytes+=n,this.evict(),t}ackThrough(e){let t=0;for(;t<this.frames.length&&this.frames[t].seq<=e;)t+=1;this.removeOldest(t)}tailAfter(e){return this.frames.length===0?e>=this.nextSeq-1?{kind:`tail`,frames:[]}:{kind:`overrun`}:e<this.frames[0].seq-1?{kind:`overrun`}:{kind:`tail`,frames:this.frames.filter(t=>t.seq>e)}}get lastSeq(){return this.nextSeq-1}get size(){return this.frames.length}evict(){let e=0,t=this.bytes;for(;this.frames.length-e>this.maxFrames||t>this.maxBytes&&this.frames.length-e>1;)t-=this.sizes[e],e+=1;this.removeOldest(e)}removeOldest(e){if(!(e<=0)){for(let t=0;t<e;t+=1)this.bytes-=this.sizes[t]??0;this.frames.splice(0,e),this.sizes.splice(0,e),this.frames.length===0&&(this.bytes=0)}}};const V=new TextEncoder,H=new TextDecoder,U=V.encode(`RBF`),W=1,G=4294967295;function K(e,t){let n=V.encode(e);if(n.byteLength===0||n.byteLength>255)throw Error(`channel name must be 1..255 UTF-8 bytes (got ${n.byteLength})`);if(!Number.isInteger(t)||t<0||t>G)throw Error(`seq must be an integer in 0..${G} (got ${t})`);return n}function q(e,t,n,r){e.set(U,0),e[3]=1,e[4]=t,e[5]=n.byteLength,e.set(n,6);let i=6+n.byteLength;return new DataView(e.buffer,e.byteOffset,e.byteLength).setUint32(i,r,!1),i+4}function J(e){let t=K(e.channel,e.seq),n=new Uint8Array(6+t.byteLength+4+e.payload.byteLength),r=q(n,1,t,e.seq);return n.set(e.payload,r),n}function Y(e){let t=K(e.channel,e.seq),n=V.encode(JSON.stringify({event:e.event,payload:e.payload})),r=new Uint8Array(6+t.byteLength+4+n.byteLength),i=q(r,2,t,e.seq);return r.set(n,i),r}function X(e){return e.byteLength<U.length?!1:U.every((t,n)=>e[n]===t)}function Z(e){let t=H.decode(e),n;try{n=JSON.parse(t)}catch{return{ok:!1,error:`channel frame: malformed JSON body`}}if(typeof n!=`object`||!n||Array.isArray(n))return{ok:!1,error:`channel frame: event body must be a JSON object`};let{event:r,payload:i}=n;return typeof r!=`string`||r.length===0?{ok:!1,error:"channel frame: event body is missing a non-empty `event` name"}:{ok:!0,event:r,payload:i??null}}function ne(e){if(!X(e))return{ok:!1,error:`channel frame: bad magic (not a channel frame)`};if(e.byteLength<6)return{ok:!1,error:`channel frame: truncated header`};if(e[3]!==1)return{ok:!1,error:`channel frame: unsupported version ${String(e[3])}`};let t=e[4],n=e[5]??0;if(n===0)return{ok:!1,error:`channel frame: empty channel name`};let r=6+n,i=r+4;if(e.byteLength<i)return{ok:!1,error:`channel frame: truncated (header longer than the frame)`};let a=H.decode(e.subarray(6,r)),o=new DataView(e.buffer,e.byteOffset,e.byteLength).getUint32(r,!1),s=e.subarray(i);if(t===1)return{ok:!0,frame:{kind:`binary`,channel:a,seq:o,payload:Uint8Array.from(s)}};if(t===2){let e=Z(s);return e.ok?{ok:!0,frame:{kind:`event`,channel:a,seq:o,event:e.event,payload:e.payload}}:{ok:!1,error:e.error}}return{ok:!1,error:`channel frame: unknown kind ${String(t)}`}}var re=class{session;buffer;driverId;reporters;surface;unsubscribe;onDeliveryError;outbound;emitBoundary;disposed=!1;holding=!1;constructor(e){this.session=e.session,this.buffer=new B(e.buffer),this.driverId=e.driverId,this.surface=e.surface,this.reporters={personalUsageReporter:e.personalUsageReporter,usageReporter:e.usageReporter,storedSessionUsageReporter:e.storedSessionUsageReporter},this.emitBoundary=z(e=>this.emit(e),(e,t)=>this.reportDeliveryError(e,t)),this.unsubscribe=w(this.session,this.emitBoundary,{getSurfaceDriverId:()=>this.driverId})}attach(e,t){this.disposed||(this.onDeliveryError=t.onDeliveryError,this.outbound=z(t=>e(JSON.stringify(t)),(e,t)=>this.reportDeliveryError(e,t),t.pendingBytes),this.holding=t.awaitResume===!0)}detach(){this.outbound=void 0,this.onDeliveryError=void 0}setDriverId(e){this.driverId=e}onClientMessage(e){if(this.disposed)return;let t=S(e,this.emitBoundary);if(t){if(t.type===`resume`){this.replay(t.lastSeq);return}if(t.type===`ack`){this.buffer.ackThrough(t.seq);return}k(this.session,this.emitBoundary,t,this.driverId,this.reporters,this.surface)}}dispose(){this.disposed||(this.disposed=!0,this.detach(),this.unsubscribe())}get lastSeq(){return this.buffer.lastSeq}emit(e){if(this.disposed)return;let t=this.buffer.append(e);this.holding||this.deliverFrame({...e,seq:t})}replay(e){let t=this.buffer.tailAfter(e);if(t.kind===`overrun`){this.deliverFrame({type:`resume_gap`}),this.holding=!1;return}for(let e of t.frames)this.deliverFrame({...e.message,seq:e.seq});this.holding=!1}deliverFrame(e){this.outbound?.(e)}reportDeliveryError(e,t){let n=this.onDeliveryError;this.detach();try{n?.(e,t)}catch{}}};function ie(){return{origins:new Map}}function ae(e,t,n){let r=t.origin.sessionId,i=e.origins.get(r);i===void 0&&(i={highestSequence:0,delivered:new Set,issued:new Map},e.origins.set(r,i));let a=i.issued.get(t.id);if(a!==void 0)return{ack:{...a,state:`duplicate`},deliver:!1};if(n!==void 0){let e={id:t.id,sequence:t.sequence,state:n.state,reason:n.reason};return i.issued.set(t.id,e),{ack:e,deliver:!1}}if(i.delivered.has(t.sequence)){let e={id:t.id,sequence:t.sequence,state:`refused`,reason:`sequence ${t.sequence} was already delivered by this origin under a different message id. A retry must repeat its id; a new id on a delivered sequence cannot be ordered against what the receiver already has.`};return i.issued.set(t.id,e),{ack:e,deliver:!1}}let o=i.highestSequence+1,s=t.sequence>o?o:void 0,c={id:t.id,sequence:t.sequence,state:`delivered`};return i.issued.set(t.id,c),i.delivered.add(t.sequence),i.highestSequence=Math.max(i.highestSequence,t.sequence),s===void 0?{ack:c,deliver:!0}:{ack:c,deliver:!0,gapBefore:s}}function oe(e,t,n){let r=e.origins.get(t),i=r?.issued.get(n);if(r===void 0||i===void 0||i.state!==`delivered`)return;let a={...i,state:`acknowledged`};return r.issued.set(n,a),a}function se(e,t){e.origins.delete(t)}const Q=16*1024;function ce(e,t,n=Q){if(!Number.isInteger(n)||n<1)throw Error(`handoff chunking: maxChunkBytes must be a positive integer, got ${n}. A zero or negative budget produces an infinite sequence of empty chunks, which presents as a hang rather than as the configuration error it is.`);let r=Buffer.from(t,`utf8`),i=Math.max(1,Math.ceil(r.byteLength/n)),a=[];for(let t=0;t<i;t+=1){let o=r.subarray(t*n,(t+1)*n);a.push({handoffId:e,index:t,total:i,data:o.toString(`base64`)})}return a}var le=class{handoffId;chunks=new Map;declaredTotal;constructor(e){this.handoffId=e}get received(){return this.chunks.size}get expected(){return this.declaredTotal}accept(e){let t=e=>({outcome:`refused`,rejection:e,received:this.chunks.size,...this.declaredTotal===void 0?{}:{expected:this.declaredTotal}});if(e.handoffId!==this.handoffId)return t(`wrong-handoff`);if(!Number.isInteger(e.total)||e.total<1||this.declaredTotal!==void 0&&e.total!==this.declaredTotal)return t(`inconsistent-total`);if(!Number.isInteger(e.index)||e.index<0||e.index>=e.total)return t(`out-of-range`);let n=Buffer.from(e.data,`base64`);if(n.toString(`base64`)!==e.data)return t(`undecodable`);this.declaredTotal=e.total;let r=this.chunks.get(e.index);return r===void 0?(this.chunks.set(e.index,n),this.chunks.size<e.total?{outcome:`accepted`,received:this.chunks.size,expected:e.total}:{outcome:`complete`,serialized:this.reassemble(e.total),received:this.chunks.size,expected:e.total}):r.equals(n)?{outcome:`duplicate`,received:this.chunks.size,expected:e.total}:t(`inconsistent-total`)}missing(){if(this.declaredTotal===void 0)return[];let e=[];for(let t=0;t<this.declaredTotal;t+=1)this.chunks.has(t)||e.push(t);return e}discard(){this.chunks.clear(),this.declaredTotal=void 0}reassemble(e){let t=[];for(let n=0;n<e;n+=1){let r=this.chunks.get(n);if(r===void 0)throw Error(`handoff chunking: chunk ${n} of ${e} is missing at reassembly.`);t.push(r)}return Buffer.concat(t).toString(`utf8`)}};function $(e,t=Q){return Math.max(1,Math.ceil(e.byteLength/t))}export{U as CHANNEL_FRAME_MAGIC,W as CHANNEL_FRAME_VERSION,Q as DEFAULT_MAX_CHUNK_BYTES,F as DEFAULT_MAX_PENDING_BYTES,L as DEFAULT_MAX_PENDING_MS,le as HandoffChunkAssembler,r as MAX_INBOUND_FRAME_BYTES,C as PROTOCOL_SESSION_EVENT_CLASSIFICATION,B as ResumeBuffer,re as SessionResumeBridge,oe as acknowledgePeerMessage,ae as admitPeerMessage,$ as chunkCountFor,ce as chunkHandoffPayload,z as createOutboundDelivery,ie as createPeerMessageLedger,R as createPendingStallClock,E as createSessionMessageHandler,ne as decodeChannelFrame,t as decodeClientMessage,n as decodeFrame,e as decodeServerMessage,J as encodeBinaryFrame,Y as encodeChannelEventFrame,se as forgetPeerOrigin,X as isChannelFrame,I as isOverPendingBudget};
|
|
1
|
+
import{a as e,i as t,n,r,t as i}from"./observer-messages-CEeisRaF.js";import{isSessionChangeRefusal as a,isSessionDeleteRefusal as o}from"@robota-sdk/agent-interface-session";import{AuthenticationError as s,ModelNotAvailableError as c,NetworkError as l,ProviderError as u,RateLimitError as d}from"@robota-sdk/agent-core";function f(e,t,n){if(n.type===`get-background-tasks`){t({type:`background_tasks`,tasks:e.listBackgroundTasks(n.filter)});return}if(n.type===`get-background-task`){m(e,t,n);return}if(n.type===`get-background-job-groups`){t({type:`background_job_groups`,groups:e.listBackgroundJobGroups()});return}if(n.type===`get-background-job-group`){g(e,t,n);return}if(n.type===`wait-background-job-group`){_(e,t,n);return}h(e,t,n)}function p(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}if(n.type===`cancel-background-task`){y(t,`cancel`,n.taskId,e.cancelBackgroundTask(n.taskId,n.reason));return}if(n.type===`close-background-task`){y(t,`close`,n.taskId,e.closeBackgroundTask(n.taskId));return}v(e,t,n)}function m(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}t({type:`background_task`,taskId:n.taskId,task:e.getBackgroundTask(n.taskId)??null})}function h(e,t,n){if(!n.taskId){t({type:`protocol_error`,message:`taskId is required`});return}e.readBackgroundTaskLog(n.taskId,n.cursor).then(e=>t({type:`background_task_log`,taskId:n.taskId,page:e}),e=>t({type:`protocol_error`,message:e.message}))}function g(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}t({type:`background_job_group`,groupId:n.groupId,group:e.getBackgroundJobGroup(n.groupId)??null})}function _(e,t,n){if(!n.groupId){t({type:`protocol_error`,message:`groupId is required`});return}e.waitBackgroundJobGroup(n.groupId).then(e=>t({type:`background_job_group`,groupId:n.groupId,group:e}),e=>t({type:`protocol_error`,message:e.message}))}function v(e,t,n){if(!n.input){t({type:`protocol_error`,message:`input is required`});return}y(t,`send`,n.taskId,e.sendBackgroundTask(n.taskId,n.input))}function y(e,t,n,r){r.then(()=>e({type:`background_task_control_result`,action:t,taskId:n,success:!0}),r=>e({type:`background_task_control_result`,action:t,taskId:n,success:!1,message:r.message}))}function b(e){return e.type===`stop-waiting-loop`}function x(e,t,n){let{requestId:r}=n;e.stopWaitingSelfPacedLoop().then(e=>t({type:`waiting_loop_stop`,requestId:r,outcome:e}),e=>t({type:`waiting_loop_stop`,requestId:r,outcome:{kind:`failed`,message:S(e)}}))}function S(e){return e instanceof Error?e.message:String(e)}function C(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function w(e){return typeof e==`string`&&e.length>0?e:void 0}function T(e){if(!(new TextEncoder().encode(e).byteLength>4194304))try{let t=JSON.parse(e);if(!C(t))return;let n=w(t.requestId);if(!n)return;if(t.type===`get-personal-usage-report`)return{type:`personal`,requestId:n};let r=w(t.sessionId);return t.type===`get-stored-session-usage-report`&&r?{type:`stored-session`,requestId:n,sessionId:r}:void 0}catch{return}}function E(e,t,n,r){return n.type===`get-personal-usage-report`?(A(t,n,r.personalUsageReporter),!0):n.type===`get-stored-session-usage-report`?(O(t,n,r.storedSessionUsageReporter),!0):n.type===`get-usage-report`?(D(e,t,r.usageReporter),!0):!1}function D(e,t,n){if(!n){t({type:`protocol_error`,message:`Per-session usage reporting is not available on this host.`});return}try{Promise.resolve(n(e)).then(e=>t({type:`usage_report`,report:e}),e=>t({type:`protocol_error`,message:M(e)}))}catch(e){t({type:`protocol_error`,message:M(e instanceof Error?e:String(e))})}}function O(e,t,n){if(!n){k(e,t,`not_available`,`Stored-session usage reporting is not available on this host.`);return}try{Promise.resolve(n(t.sessionId)).then(n=>e({type:`stored_session_usage_report`,requestId:t.requestId,sessionId:t.sessionId,report:n}),n=>k(e,t,`report_failed`,M(n)))}catch(n){k(e,t,`report_failed`,M(n instanceof Error?n:String(n)))}}function k(e,t,n,r){e({type:`stored_session_usage_report_error`,requestId:t.requestId,sessionId:t.sessionId,code:n,message:r})}function A(e,t,n){if(!n){j(e,t.requestId,`not_available`,`Personal usage reporting is not available on this host.`);return}try{Promise.resolve(n({period:t.period,timezone:t.timezone})).then(n=>e({type:`personal_usage_report`,requestId:t.requestId,report:n}),n=>j(e,t.requestId,`report_failed`,M(n)))}catch(n){j(e,t.requestId,`report_failed`,M(n instanceof Error?n:String(n)))}}function j(e,t,n,r){e({type:`personal_usage_report_error`,requestId:t,code:n,message:r})}function M(e){return e instanceof Error?e.message:String(e)}function ee(e,n){let i=t(e,r);if(i.ok)return i.message;let a=T(e);return a?.type===`personal`?(n({type:`personal_usage_report_error`,requestId:a.requestId,code:`report_failed`,message:`Invalid personal usage report request.`}),null):a?.type===`stored-session`?(n({type:`stored_session_usage_report_error`,requestId:a.requestId,sessionId:a.sessionId,code:`report_failed`,message:`Invalid stored-session usage report request.`}),null):(n({type:`protocol_error`,message:i.reason}),null)}function te(e){return e.type===`project-status`||e.type===`project-diff`||e.type===`project-memory`}function N(e,t){e({type:`protocol_error`,message:`This host does not support the Project panel.`,requestId:t})}function ne(e,t,n){let{requestId:r}=n;if(n.type===`project-status`){if(!e.readProjectStatus)return N(t,r);e.readProjectStatus().then(e=>t({type:`project_status`,requestId:r,result:e}),e=>t({type:`project_status`,requestId:r,result:{kind:`failed`,message:e instanceof Error?e.message:String(e)}}))}else if(n.type===`project-diff`){if(!e.readProjectDiff)return N(t,r);e.readProjectDiff(n.path).then(e=>t({type:`project_diff`,requestId:r,result:e}),e=>t({type:`project_diff`,requestId:r,result:{kind:`failed`,message:e instanceof Error?e.message:String(e)}}))}else{if(!e.readProjectMemory)return N(t,r);e.readProjectMemory().then(e=>t({type:`project_memory`,requestId:r,result:e}),e=>t({type:`project_memory`,requestId:r,result:{kind:`unavailable`,message:e instanceof Error?e.message:String(e)}}))}}function re(e){return e.type===`list-sessions`||e.type===`new-session`||e.type===`switch-session`}function ie(e){return e.type===`rename-session`}function ae(e){return e.type===`delete-session`}function oe(e,t,n){if(t.type===`list-sessions`){se(e,t.requestId,n);return}let r=t.requestId===void 0?{}:{requestId:t.requestId};if(!n){e({type:`session_change_failed`,code:`not_available`,message:`Sessions cannot be switched on this host.`,...r});return}Promise.resolve().then(()=>t.type===`new-session`?n.newSession():n.switchSession(t.sessionId)).catch(t=>e({type:`session_change_failed`,code:a(t)?t.code:`failed`,message:P(t),...r}))}function se(e,t,n){if(!n){e({type:`sessions_error`,requestId:t,code:`not_available`,message:`Session listing is not available on this host.`});return}try{e({type:`sessions`,requestId:t,listing:n.listSessions()})}catch(n){e({type:`sessions_error`,requestId:t,code:`list_failed`,message:P(n instanceof Error?n:String(n))})}}function P(e){return e instanceof Error?e.message:String(e)}function ce(e,t,n){if(!n){e({type:`session_rename_failed`,requestId:t.requestId,message:`Sessions cannot be renamed on this host.`});return}n.renameSession(t.sessionId,t.name).then(()=>e({type:`session_renamed_in_list`,requestId:t.requestId,sessionId:t.sessionId,name:t.name}),n=>e({type:`session_rename_failed`,requestId:t.requestId,message:P(n)}))}function le(e,t,n){if(!n){e({type:`session_delete_failed`,requestId:t.requestId,code:`not_available`,message:`Sessions cannot be deleted on this host.`});return}n.deleteSession(t.sessionId).then(()=>e({type:`session_deleted`,requestId:t.requestId,sessionId:t.sessionId}),n=>e({type:`session_delete_failed`,requestId:t.requestId,code:o(n)?n.code:`failed`,message:P(n)}))}const F=new WeakMap;function ue(e){let t=F.get(e);t===void 0&&(t={frames:new Map,holders:0},F.set(e,t));let n=t;n.holders+=1;let r=!1;return{record:e=>{r||n.frames.set(e.event.id,e)},forget:e=>{n.frames.delete(e)},clear:()=>{n.frames.clear()},release:()=>{r||(r=!0,--n.holders,n.holders===0&&F.get(e)===n&&F.delete(e))}}}function de(e){return[...F.get(e)?.frames.values()??[]]}function fe(e){let t=[],n=new Set,r=[e];for(let e=0;e<=8&&r.length>0;e++){let e=[];for(let i of r)if(!(i==null||n.has(i))&&(n.add(i),t.push(i),typeof i==`object`)){let t=i;e.push(t.originalError,t.cause)}r=e}return t}function pe(e){let t;for(let n of fe(e)){if(n instanceof s)return{code:`auth`,...n.provider!==void 0&&{provider:n.provider}};if(n instanceof d)return{code:`rate_limit`,...n.provider!==void 0&&{provider:n.provider},...n.retryAfter!==void 0&&{retryAfterSeconds:n.retryAfter}};if(n instanceof c)return{code:`model_unavailable`,provider:n.provider,...n.model!==void 0&&{model:n.model}};if(n instanceof l)return{code:`network`,...n.provider!==void 0&&{provider:n.provider}};t===void 0&&n instanceof u&&(t={code:`provider`,provider:n.provider})}return t??{}}const me={text_delta:`forwarded`,tool_start:`forwarded`,tool_end:`forwarded`,thinking:`forwarded`,complete:`forwarded`,error:`forwarded`,context_update:`forwarded`,compact:`forwarded`,interrupted:`forwarded`,skill_activation:`forwarded`,background_task_event:`forwarded`,background_job_group_event:`forwarded`,execution_workspace_event:`forwarded`,user_message:`forwarded`,turn_source:`forwarded`,context_file_refreshed:`forwarded`,memory_event:`forwarded`,goal_event:`non-surface`,plan_event:`forwarded`,branch_event:`forwarded`,permission_request:`forwarded`,ask_request:`forwarded`,prompt_resolved:`forwarded`,ui_intent:`requester-routed`,session_renamed:`forwarded`,history_cleared:`forwarded`,session_switched:`forwarded`,status_changed:`forwarded`};function he(e,t,n={}){let r=()=>{let t=e.getActiveDriverId();return t?{driverId:t}:{}},i=e=>t({type:`user_message`,content:e,...r()}),a=e=>t({type:`text_delta`,delta:e,...r()}),o=e=>t({type:`tool_start`,state:e,...r()}),s=e=>t({type:`tool_end`,state:e,...r()}),c=e=>t({type:`thinking`,isThinking:e,...r()}),l=e=>t({type:`complete`,result:I(e),...r()}),u=e=>t({type:`interrupted`,result:I(e),...r()}),d=e=>t({type:`error`,message:e.message,...pe(e),...r()}),f=e=>t({type:`background_task_event`,event:e}),p=e=>t({type:`background_job_group_event`,event:e}),m=e=>t({type:`execution_workspace_event`,snapshot:e.snapshot}),h=e=>t({type:`plan_event`,event:e}),g=e=>t({type:`context_file_refreshed`,event:e}),_=e=>t({type:`branch_event`,event:e}),v=n.receivePrompts??!0,y=v?ue(e):void 0,b=e=>{let n={type:`permission_request`,event:e};y?.record(n),t(n)},x=e=>{let n={type:`ask_request`,event:e};y?.record(n),t(n)},S=e=>{y?.forget(e.id),t({type:`prompt_resolved`,event:e})},C=e=>{(e.requesterDriverId===void 0||e.requesterDriverId===n.getSurfaceDriverId?.())&&t({type:`ui_intent`,event:e})},w=e=>t({type:`session_renamed`,event:e}),T=()=>t({type:`history_cleared`}),E=e=>{y?.clear(),t({type:`session_switched`,event:e})},D=e=>t({type:`context`,state:e}),O=()=>t({type:`history_changed`}),k=e=>t({type:`turn_source`,source:e}),A=e=>t({type:`session_status`,status:e});return e.on(`user_message`,i),e.on(`text_delta`,a),e.on(`tool_start`,o),e.on(`tool_end`,s),e.on(`thinking`,c),e.on(`complete`,l),e.on(`interrupted`,u),e.on(`error`,d),e.on(`background_task_event`,f),e.on(`background_job_group_event`,p),e.on(`execution_workspace_event`,m),e.on(`plan_event`,h),e.on(`context_file_refreshed`,g),e.on(`branch_event`,_),v&&(e.on(`permission_request`,b),e.on(`ask_request`,x)),e.on(`prompt_resolved`,S),e.on(`ui_intent`,C),e.on(`session_renamed`,w),e.on(`history_cleared`,T),e.on(`session_switched`,E),e.on(`context_update`,D),e.on(`compact`,O),e.on(`skill_activation`,O),e.on(`memory_event`,O),e.on(`turn_source`,k),e.on(`status_changed`,A),()=>{e.off(`user_message`,i),e.off(`text_delta`,a),e.off(`tool_start`,o),e.off(`tool_end`,s),e.off(`thinking`,c),e.off(`complete`,l),e.off(`interrupted`,u),e.off(`error`,d),e.off(`background_task_event`,f),e.off(`background_job_group_event`,p),e.off(`execution_workspace_event`,m),e.off(`plan_event`,h),e.off(`context_file_refreshed`,g),e.off(`branch_event`,_),v&&(e.off(`permission_request`,b),e.off(`ask_request`,x)),e.off(`prompt_resolved`,S),e.off(`ui_intent`,C),e.off(`session_renamed`,w),e.off(`history_cleared`,T),e.off(`session_switched`,E),e.off(`context_update`,D),e.off(`compact`,O),e.off(`skill_activation`,O),e.off(`memory_event`,O),e.off(`turn_source`,k),e.off(`status_changed`,A),y?.release()}}function I(e){let{history:t,...n}=e;return n}const ge=new TextEncoder;function _e(e){return e.type===`get-messages`||e.type===`get-history`||e.type===`get-prompts`||e.type===`get-context`||e.type===`get-commands`||e.type===`get-status`||e.type===`list-models`||e.type===`get-agent-definitions`||e.type===`get-executing`||e.type===`get-pending`||e.type===`get-execution-workspace`||e.type===`read-execution-detail`}function ve(e,t,n){if(n.type===`get-messages`)t({type:`messages`,messages:e.getMessages(),display:e.getMessagesDisplay()});else if(n.type===`get-history`)t(be(e,n.fromIndex??0));else if(n.type===`get-prompts`)for(let n of de(e))t(n);else if(n.type===`get-context`)t({type:`context`,state:e.getContextState()});else if(n.type===`get-commands`)t({type:`commands`,commands:e.listCommands(),skills:e.listSkills()});else if(n.type===`get-status`)t({type:`session_status`,status:e.getStatusSnapshot()});else if(n.type===`list-models`){let r=e.listModels();t({type:`model_list`,requestId:n.requestId,...r})}else n.type===`get-agent-definitions`?t({type:`agent_definitions`,requestId:n.requestId,agents:e.listAgentDefinitions(),current:e.getDefaultAgentType()}):n.type===`get-executing`?t({type:`executing`,executing:e.isExecuting()}):n.type===`get-execution-workspace`?t({type:`execution_workspace_event`,snapshot:e.getExecutionWorkspaceSnapshot()}):n.type===`read-execution-detail`?ye(e,t,n):t(L(e))}function ye(e,t,n){let{requestId:r}=n;e.readExecutionWorkspaceDetail(n.entryId,n.cursor).then(e=>t({type:`execution_detail`,requestId:r,page:e}),e=>t({type:`execution_detail_error`,requestId:r,message:e instanceof Error?e.message:String(e)}))}function L(e){return{type:`pending`,pending:e.getPendingPrompt(),pendingCount:e.getPendingCount()}}function be(e,t){let n=e.getFullHistory(),r=n.length,i=Math.min(t,r),a=[],o=0;for(let e=i;e<r;e+=1){let t=xe(n[e]),r=ge.encode(JSON.stringify(t)).byteLength;if(a.length>0&&o+r>262144)break;a.push(t),o+=r}return{type:`history`,startIndex:i,total:r,entries:a}}function xe(e){return{...e,timestamp:Se(e.timestamp)}}function Se(e){return typeof e==`string`?e:e.toISOString()}function R(e){return e.type===`get-settings`||e.type===`update-settings`}function z(e,t,n,r,i){if(!r){B(t,n.requestId,`not_available`,`Settings are not available on this host.`);return}try{if(n.type===`get-settings`){Promise.resolve(r.getSettings(e,i)).then(e=>t({type:`settings`,requestId:n.requestId,settings:e}),e=>B(t,n.requestId,`update_failed`,V(e)));return}Promise.resolve(r.updateSettings(e,n.patch,i)).then(e=>{e.ok?t({type:`settings`,requestId:n.requestId,settings:e.settings}):B(t,n.requestId,e.code,e.message)},e=>B(t,n.requestId,`update_failed`,V(e)))}catch(e){B(t,n.requestId,`update_failed`,V(e instanceof Error?e:String(e)))}}function B(e,t,n,r){e({type:`settings_error`,requestId:t,code:n,message:r})}function V(e){return e instanceof Error?e.message:String(e)}function Ce(e){let t=e.role??`drive`,n=he(e.session,e.deliver,{getSurfaceDriverId:()=>e.driverId,receivePrompts:t===`drive`});return{onMessage:we(e.session,e.deliver,e.driverId,{personalUsageReporter:e.personalUsageReporter,usageReporter:e.usageReporter,storedSessionUsageReporter:e.storedSessionUsageReporter},e.surface,t,e.sessionDirectory,e.settingsReporter,e.commandSurfaceLocality),cleanup:n}}function we(e,t,n,r=Te,a,o=`drive`,s,c,l){return u=>{let d=ee(u,t);if(d){if(o===`observe`&&!i(d.type)){t({type:`protocol_error`,message:`Not permitted for an observer: ${d.type}`});return}H(e,t,d,n,r,a,s,c,l)}}}const Te={personalUsageReporter:void 0,usageReporter:void 0,storedSessionUsageReporter:void 0};function H(e,t,n,r,i=Te,a,o,s,c){if(E(e,t,n,i))return;if(re(n)){oe(t,n,o);return}if(R(n)){z(e,t,n,s,c);return}if(ie(n)){ce(t,n,o);return}if(ae(n)){le(t,n,o);return}if(Ee(n)){je(e,t,n,r,a,c);return}if(b(n)){x(e,t,n);return}if(_e(n)){ve(e,t,n);return}if(te(n)){ne(e,t,n);return}if(De(n)){f(e,t,n);return}if(Oe(n)){p(e,t,n);return}if(ke(n)){Ae(e,n,r);return}let l=n.type;t({type:`protocol_error`,message:`Unknown message type: ${l}`})}function Ee(e){return e.type===`submit`||e.type===`command`||e.type===`abort`||e.type===`cancel-queue`}function De(e){return e.type===`get-background-tasks`||e.type===`get-background-task`||e.type===`read-background-task-log`||e.type===`get-background-job-groups`||e.type===`get-background-job-group`||e.type===`wait-background-job-group`}function Oe(e){return e.type===`cancel-background-task`||e.type===`close-background-task`||e.type===`send-background-task`}function ke(e){return e.type===`permission-response`||e.type===`ask-response`}function Ae(e,t,n){t.type===`permission-response`?e.resolvePermission(t.id,t.result,n):e.resolveAsk(t.id,t.response,n)}function je(e,t,n,r,i,a){if(n.type===`submit`){if(typeof n.prompt!=`string`||n.prompt.length===0){t({type:`protocol_error`,message:`prompt must be a non-empty string`});return}let a={...r?{driverId:r}:{},...i?{surface:i}:{}};e.submit(n.prompt,void 0,void 0,Object.keys(a).length>0?a:void 0).then(()=>t(L(e)),e=>t({type:`protocol_error`,message:e.message}))}else if(n.type===`command`){let i=n.requestId===void 0?{}:{requestId:n.requestId};if(!n.name){t({type:`protocol_error`,message:`name is required`,...i});return}e.executeCommand(n.name,n.args??``,`remote`,r,a).then(e=>{t({type:`command_result`,name:n.name,message:e?.message??`Unknown command: ${n.name}`,success:e?.success??!1,data:e?.data,...i})},e=>{t({type:`protocol_error`,message:e.message,...i})})}else n.type===`abort`?e.abort():e.cancelQueue()}const U=1024*1024,W=8*U,Me=U;function G(e,t=W){return e!==void 0&&e>t}const K=120*1e3;function q(e=K,t=Date.now){let n;return{maxPendingMs:e,observe(r){if(r===void 0)return;if(r===0){n=void 0;return}let i=t();n??=i;let a=i-n;return a>e?a:void 0}}}function J(e,t,n,r=W,i=q()){let a=!1,o=t=>{if(a)return;let o=n?.();if(G(o,r)){a=!0,s(Error(`outbound backpressure budget exceeded: ${o} byte(s) pending, limit ${r}. The peer has accepted frames it is not reading.`),t.type);return}let c=i.observe(o);if(c!==void 0){a=!0,s(Error(`outbound drain budget exceeded: ${o} byte(s) pending for ${c} ms, limit ${i.maxPendingMs} ms. The peer is reading too slowly to ever drain what it accepted.`),t.type);return}try{e(t)}catch(e){a=!0,s(e instanceof Error?e:Error(String(e)),t.type)}};function s(e,n){try{t(e,n)}catch{}}return Object.assign(o,{pendingBytes:()=>n?.()})}var Y=class{frames=[];sizes=[];nextSeq=1;bytes=0;maxFrames;maxBytes;sizeOf;constructor(e={}){this.maxFrames=e.maxFrames??512,this.maxBytes=e.maxBytes??4194304,this.sizeOf=e.sizeOf??(e=>JSON.stringify(e).length)}append(e){let t=this.nextSeq;this.nextSeq+=1;let n=this.sizeOf(e);return this.frames.push({seq:t,message:e}),this.sizes.push(n),this.bytes+=n,this.evict(),t}ackThrough(e){let t=0;for(;t<this.frames.length&&this.frames[t].seq<=e;)t+=1;this.removeOldest(t)}tailAfter(e){return this.frames.length===0?e>=this.nextSeq-1?{kind:`tail`,frames:[]}:{kind:`overrun`}:e<this.frames[0].seq-1?{kind:`overrun`}:{kind:`tail`,frames:this.frames.filter(t=>t.seq>e)}}get lastSeq(){return this.nextSeq-1}get size(){return this.frames.length}evict(){let e=0,t=this.bytes;for(;this.frames.length-e>this.maxFrames||t>this.maxBytes&&this.frames.length-e>1;)t-=this.sizes[e],e+=1;this.removeOldest(e)}removeOldest(e){if(!(e<=0)){for(let t=0;t<e;t+=1)this.bytes-=this.sizes[t]??0;this.frames.splice(0,e),this.sizes.splice(0,e),this.frames.length===0&&(this.bytes=0)}}};const X=new TextEncoder,Z=new TextDecoder,Q=X.encode(`RBF`),Ne=1,Pe=4294967295;function Fe(e,t){let n=X.encode(e);if(n.byteLength===0||n.byteLength>255)throw Error(`channel name must be 1..255 UTF-8 bytes (got ${n.byteLength})`);if(!Number.isInteger(t)||t<0||t>Pe)throw Error(`seq must be an integer in 0..${Pe} (got ${t})`);return n}function Ie(e,t,n,r){e.set(Q,0),e[3]=1,e[4]=t,e[5]=n.byteLength,e.set(n,6);let i=6+n.byteLength;return new DataView(e.buffer,e.byteOffset,e.byteLength).setUint32(i,r,!1),i+4}function Le(e){let t=Fe(e.channel,e.seq),n=new Uint8Array(6+t.byteLength+4+e.payload.byteLength),r=Ie(n,1,t,e.seq);return n.set(e.payload,r),n}function Re(e){let t=Fe(e.channel,e.seq),n=X.encode(JSON.stringify({event:e.event,payload:e.payload})),r=new Uint8Array(6+t.byteLength+4+n.byteLength),i=Ie(r,2,t,e.seq);return r.set(n,i),r}function ze(e){return e.byteLength<Q.length?!1:Q.every((t,n)=>e[n]===t)}function Be(e){let t=Z.decode(e),n;try{n=JSON.parse(t)}catch{return{ok:!1,error:`channel frame: malformed JSON body`}}if(typeof n!=`object`||!n||Array.isArray(n))return{ok:!1,error:`channel frame: event body must be a JSON object`};let{event:r,payload:i}=n;return typeof r!=`string`||r.length===0?{ok:!1,error:"channel frame: event body is missing a non-empty `event` name"}:{ok:!0,event:r,payload:i??null}}function Ve(e){if(!ze(e))return{ok:!1,error:`channel frame: bad magic (not a channel frame)`};if(e.byteLength<6)return{ok:!1,error:`channel frame: truncated header`};if(e[3]!==1)return{ok:!1,error:`channel frame: unsupported version ${String(e[3])}`};let t=e[4],n=e[5]??0;if(n===0)return{ok:!1,error:`channel frame: empty channel name`};let r=6+n,i=r+4;if(e.byteLength<i)return{ok:!1,error:`channel frame: truncated (header longer than the frame)`};let a=Z.decode(e.subarray(6,r)),o=new DataView(e.buffer,e.byteOffset,e.byteLength).getUint32(r,!1),s=e.subarray(i);if(t===1)return{ok:!0,frame:{kind:`binary`,channel:a,seq:o,payload:Uint8Array.from(s)}};if(t===2){let e=Be(s);return e.ok?{ok:!0,frame:{kind:`event`,channel:a,seq:o,event:e.event,payload:e.payload}}:{ok:!1,error:e.error}}return{ok:!1,error:`channel frame: unknown kind ${String(t)}`}}var He=class{session;buffer;driverId;reporters;surface;commandSurfaceLocality;unsubscribe;onDeliveryError;outbound;emitBoundary;disposed=!1;holding=!1;constructor(e){this.session=e.session,this.buffer=new Y(e.buffer),this.driverId=e.driverId,this.surface=e.surface,this.commandSurfaceLocality=e.commandSurfaceLocality,this.reporters={personalUsageReporter:e.personalUsageReporter,usageReporter:e.usageReporter,storedSessionUsageReporter:e.storedSessionUsageReporter},this.emitBoundary=J(e=>this.emit(e),(e,t)=>this.reportDeliveryError(e,t)),this.unsubscribe=he(this.session,this.emitBoundary,{getSurfaceDriverId:()=>this.driverId})}attach(e,t){this.disposed||(this.onDeliveryError=t.onDeliveryError,this.outbound=J(t=>e(JSON.stringify(t)),(e,t)=>this.reportDeliveryError(e,t),t.pendingBytes),this.holding=t.awaitResume===!0)}detach(){this.outbound=void 0,this.onDeliveryError=void 0}setDriverId(e){this.driverId=e}onClientMessage(e){if(this.disposed)return;let t=ee(e,this.emitBoundary);if(t){if(t.type===`resume`){this.replay(t.lastSeq);return}if(t.type===`ack`){this.buffer.ackThrough(t.seq);return}H(this.session,this.emitBoundary,t,this.driverId,this.reporters,this.surface,void 0,void 0,this.commandSurfaceLocality)}}dispose(){this.disposed||(this.disposed=!0,this.detach(),this.unsubscribe())}get lastSeq(){return this.buffer.lastSeq}emit(e){if(this.disposed)return;let t=this.buffer.append(e);this.holding||this.deliverFrame({...e,seq:t})}replay(e){let t=this.buffer.tailAfter(e);if(t.kind===`overrun`){this.deliverFrame({type:`resume_gap`}),this.holding=!1;return}for(let e of t.frames)this.deliverFrame({...e.message,seq:e.seq});this.holding=!1}deliverFrame(e){this.outbound?.(e)}reportDeliveryError(e,t){let n=this.onDeliveryError;this.detach();try{n?.(e,t)}catch{}}};function Ue(){return{origins:new Map}}function We(e,t,n){let r=t.origin.sessionId,i=e.origins.get(r);i===void 0&&(i={highestSequence:0,delivered:new Set,issued:new Map},e.origins.set(r,i));let a=i.issued.get(t.id);if(a!==void 0)return{ack:{...a,state:`duplicate`},deliver:!1};if(n!==void 0){let e={id:t.id,sequence:t.sequence,state:n.state,reason:n.reason};return i.issued.set(t.id,e),{ack:e,deliver:!1}}if(i.delivered.has(t.sequence)){let e={id:t.id,sequence:t.sequence,state:`refused`,reason:`sequence ${t.sequence} was already delivered by this origin under a different message id. A retry must repeat its id; a new id on a delivered sequence cannot be ordered against what the receiver already has.`};return i.issued.set(t.id,e),{ack:e,deliver:!1}}let o=i.highestSequence+1,s=t.sequence>o?o:void 0,c={id:t.id,sequence:t.sequence,state:`delivered`};return i.issued.set(t.id,c),i.delivered.add(t.sequence),i.highestSequence=Math.max(i.highestSequence,t.sequence),s===void 0?{ack:c,deliver:!0}:{ack:c,deliver:!0,gapBefore:s}}function Ge(e,t,n){let r=e.origins.get(t),i=r?.issued.get(n);if(r===void 0||i===void 0||i.state!==`delivered`)return;let a={...i,state:`acknowledged`};return r.issued.set(n,a),a}function Ke(e,t){e.origins.delete(t)}const $=16*1024;function qe(e,t,n=$){if(!Number.isInteger(n)||n<1)throw Error(`handoff chunking: maxChunkBytes must be a positive integer, got ${n}. A zero or negative budget produces an infinite sequence of empty chunks, which presents as a hang rather than as the configuration error it is.`);let r=Buffer.from(t,`utf8`),i=Math.max(1,Math.ceil(r.byteLength/n)),a=[];for(let t=0;t<i;t+=1){let o=r.subarray(t*n,(t+1)*n);a.push({handoffId:e,index:t,total:i,data:o.toString(`base64`)})}return a}var Je=class{handoffId;chunks=new Map;declaredTotal;constructor(e){this.handoffId=e}get received(){return this.chunks.size}get expected(){return this.declaredTotal}accept(e){let t=e=>({outcome:`refused`,rejection:e,received:this.chunks.size,...this.declaredTotal===void 0?{}:{expected:this.declaredTotal}});if(e.handoffId!==this.handoffId)return t(`wrong-handoff`);if(!Number.isInteger(e.total)||e.total<1||this.declaredTotal!==void 0&&e.total!==this.declaredTotal)return t(`inconsistent-total`);if(!Number.isInteger(e.index)||e.index<0||e.index>=e.total)return t(`out-of-range`);let n=Buffer.from(e.data,`base64`);if(n.toString(`base64`)!==e.data)return t(`undecodable`);this.declaredTotal=e.total;let r=this.chunks.get(e.index);return r===void 0?(this.chunks.set(e.index,n),this.chunks.size<e.total?{outcome:`accepted`,received:this.chunks.size,expected:e.total}:{outcome:`complete`,serialized:this.reassemble(e.total),received:this.chunks.size,expected:e.total}):r.equals(n)?{outcome:`duplicate`,received:this.chunks.size,expected:e.total}:t(`inconsistent-total`)}missing(){if(this.declaredTotal===void 0)return[];let e=[];for(let t=0;t<this.declaredTotal;t+=1)this.chunks.has(t)||e.push(t);return e}discard(){this.chunks.clear(),this.declaredTotal=void 0}reassemble(e){let t=[];for(let n=0;n<e;n+=1){let r=this.chunks.get(n);if(r===void 0)throw Error(`handoff chunking: chunk ${n} of ${e} is missing at reassembly.`);t.push(r)}return Buffer.concat(t).toString(`utf8`)}};function Ye(e,t=$){return Math.max(1,Math.ceil(e.byteLength/t))}export{Me as ATTACHED_SURFACE_MAX_PENDING_BYTES,Q as CHANNEL_FRAME_MAGIC,Ne as CHANNEL_FRAME_VERSION,$ as DEFAULT_MAX_CHUNK_BYTES,W as DEFAULT_MAX_PENDING_BYTES,K as DEFAULT_MAX_PENDING_MS,Je as HandoffChunkAssembler,n as MAX_INBOUND_FRAME_BYTES,me as PROTOCOL_SESSION_EVENT_CLASSIFICATION,Y as ResumeBuffer,He as SessionResumeBridge,Ge as acknowledgePeerMessage,We as admitPeerMessage,Ye as chunkCountFor,qe as chunkHandoffPayload,J as createOutboundDelivery,Ue as createPeerMessageLedger,q as createPendingStallClock,Ce as createSessionMessageHandler,Ve as decodeChannelFrame,r as decodeClientMessage,t as decodeFrame,e as decodeServerMessage,Le as encodeBinaryFrame,Re as encodeChannelEventFrame,Ke as forgetPeerOrigin,z as handleSettingsMessage,ze as isChannelFrame,i as isObserverMessageType,G as isOverPendingBudget,R as isSettingsMessage};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|