agents 0.25.0 → 0.27.0
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/README.md +8 -9
- package/dist/{agent-routing-0DR0Tk2v.d.ts → agent-routing-Bhdbvf7s.d.ts} +13 -8
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-YrATZJu2.d.ts → agent-tools-bJZwBMfq.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/ai-sdk-OoGkFy3s.js +2444 -0
- package/dist/ai-sdk-OoGkFy3s.js.map +1 -0
- package/dist/apply-chunks-1FheRb9W.js +99 -0
- package/dist/apply-chunks-1FheRb9W.js.map +1 -0
- package/dist/broadcast-state-CEyI4uAK.js +69 -0
- package/dist/broadcast-state-CEyI4uAK.js.map +1 -0
- package/dist/browser/ai-sdk.d.ts +1 -1
- package/dist/browser/ai-sdk.js +2 -2
- package/dist/browser/ai-sdk.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/tanstack-ai.d.ts +1 -1
- package/dist/browser/tanstack-ai.js +1 -1
- package/dist/{browser-DE3d-RLk.d.ts → browser-tmkcAAI3.d.ts} +2 -2
- package/dist/{browser-tool-DuNdlwZ9.d.ts → browser-tool-Bn-nzJQI.d.ts} +3 -3
- package/dist/{browser-tool-CQ10e6Kj.js → browser-tool-CBqs6hqa.js} +58 -18
- package/dist/browser-tool-CBqs6hqa.js.map +1 -0
- package/dist/capability-B4WbF81e.js.map +1 -1
- package/dist/{capability-runner-DBAnGr6L.d.ts → capability-runner-O5VbQzqg.d.ts} +9 -1
- package/dist/channel-Bak_6zDP.d.ts +333 -0
- package/dist/chat/index.d.ts +11 -9
- package/dist/chat/index.js +5 -194
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +2 -4
- package/dist/chat/react.js +3 -1
- package/dist/chat/react.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/cli.js +144 -0
- package/dist/{client-fyQrLGkD.js → client-1tEQ1Oqz.js} +27 -2
- package/dist/{client-fyQrLGkD.js.map → client-1tEQ1Oqz.js.map} +1 -1
- package/dist/{client-je3koD9Z.d.ts → client-DS3Dz9l0.d.ts} +2 -2
- package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
- package/dist/client.d.ts +1 -1
- package/dist/conversations-DH0ut_8n.d.ts +192 -0
- package/dist/{current-agent-vAk_5JMt.d.ts → current-agent-C07C5o5Y.d.ts} +3 -3
- package/dist/daemon-core-Buubj-y1.js +481 -0
- package/dist/daemon-core-Buubj-y1.js.map +1 -0
- package/dist/daemon-core-CbohVPAu.d.ts +132 -0
- package/dist/{do-oauth-client-provider-Tmf1vgKz.d.ts → do-oauth-client-provider-DfsUcpc3.d.ts} +7 -1
- package/dist/{durable-object-lifecycle-HhgOMWq9.d.ts → durable-object-lifecycle-DRqp475_.d.ts} +2 -2
- package/dist/{channels/email.d.ts → experimental/channels/email/index.d.ts} +25 -12
- package/dist/{channels/email.js → experimental/channels/email/index.js} +13 -35
- package/dist/experimental/channels/email/index.js.map +1 -0
- package/dist/experimental/channels/index.d.ts +270 -0
- package/dist/experimental/channels/index.js +1186 -0
- package/dist/experimental/channels/index.js.map +1 -0
- package/dist/{channels/slack.d.ts → experimental/channels/slack/index.d.ts} +19 -9
- package/dist/experimental/channels/slack/index.js +267 -0
- package/dist/experimental/channels/slack/index.js.map +1 -0
- package/dist/{channels/telegram.d.ts → experimental/channels/telegram/index.d.ts} +19 -9
- package/dist/experimental/channels/telegram/index.js +198 -0
- package/dist/experimental/channels/telegram/index.js.map +1 -0
- package/dist/experimental/channels/web/ai-sdk.d.ts +55 -0
- package/dist/experimental/channels/web/ai-sdk.js +266 -0
- package/dist/experimental/channels/web/ai-sdk.js.map +1 -0
- package/dist/experimental/channels/web/client.d.ts +97 -0
- package/dist/experimental/channels/web/client.js +349 -0
- package/dist/experimental/channels/web/client.js.map +1 -0
- package/dist/experimental/channels/web/index.d.ts +189 -0
- package/dist/experimental/channels/web/index.js +332 -0
- package/dist/experimental/channels/web/index.js.map +1 -0
- package/dist/gateway-BDC07gYO.d.ts +100 -0
- package/dist/handle-zAzh0UW2.d.ts +460 -0
- package/dist/harness/ai-sdk/index.d.ts +175 -0
- package/dist/harness/ai-sdk/index.js +605 -0
- package/dist/harness/ai-sdk/index.js.map +1 -0
- package/dist/harness/container/daemon/index.d.ts +76 -0
- package/dist/harness/container/daemon/index.js +3 -0
- package/dist/harness/container/index.d.ts +740 -0
- package/dist/harness/container/index.js +2152 -0
- package/dist/harness/container/index.js.map +1 -0
- package/dist/harness/container/runtime/index.d.ts +144 -0
- package/dist/harness/container/runtime/index.js +1082 -0
- package/dist/harness/container/runtime/index.js.map +1 -0
- package/dist/harness/opencode/index.d.ts +369 -0
- package/dist/harness/opencode/index.js +1072 -0
- package/dist/harness/opencode/index.js.map +1 -0
- package/dist/{harnesses → harness}/pi/index.d.ts +85 -88
- package/dist/{harnesses → harness}/pi/index.js +196 -77
- package/dist/harness/pi/index.js.map +1 -0
- package/dist/harness/store/index.d.ts +24 -0
- package/dist/harness/store/index.js +2 -0
- package/dist/harness/think/index.d.ts +821 -0
- package/dist/harness/think/index.js +2529 -0
- package/dist/harness/think/index.js.map +1 -0
- package/dist/harness-B6B9S3rb.d.ts +203 -0
- package/dist/{images-iiTDSyRu.js → images-Ce9SCu3X.js} +2 -248
- package/dist/images-Ce9SCu3X.js.map +1 -0
- package/dist/{index-BreL0YrQ.d.ts → index-D0A5tbWu.d.ts} +2 -2
- package/dist/index-Ib_4dwOo.d.ts +200 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/ingress-EFbrS547.js +9 -0
- package/dist/ingress-EFbrS547.js.map +1 -0
- package/dist/input-schema-DNrpTu49.js +23 -0
- package/dist/input-schema-DNrpTu49.js.map +1 -0
- package/dist/internal-kmw70xwR.js +46 -0
- package/dist/internal-kmw70xwR.js.map +1 -0
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +3 -3
- package/dist/mcp/client/do-oauth-client-provider.d.ts +1 -1
- package/dist/mcp/client/do-oauth-client-provider.js +9 -0
- package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/client/x402.d.ts +35 -4
- package/dist/mcp/client/x402.js +24 -3
- package/dist/mcp/client/x402.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/models/ai-sdk/index.d.ts +16 -14
- package/dist/models/ai-sdk/index.js +1 -2442
- package/dist/models/opencode/index.d.ts +65 -0
- package/dist/models/opencode/index.js +285 -0
- package/dist/models/opencode/index.js.map +1 -0
- package/dist/models/pi-ai/index.d.ts +23 -21
- package/dist/models/pi-ai/index.js +7 -6
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/options-pwTNq9z6.d.ts +134 -0
- package/dist/protocol-BEgrJYC5.d.ts +331 -0
- package/dist/protocol-CukuI73M.d.ts +386 -0
- package/dist/protocol-cOklVBBD.js +227 -0
- package/dist/protocol-cOklVBBD.js.map +1 -0
- package/dist/{protocol-kHsr-f0X.js → protocol-eXeJxhgu.js} +2 -67
- package/dist/protocol-eXeJxhgu.js.map +1 -0
- package/dist/protocol-y2sSY584.js +148 -0
- package/dist/protocol-y2sSY584.js.map +1 -0
- package/dist/queue/index.d.ts +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +2 -2
- package/dist/{scheduler-RdACNXDP.d.ts → scheduler-CrFCnv_J.d.ts} +2 -2
- package/dist/schedules/index.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sessions/index.d.ts +11 -434
- package/dist/sessions/index.js +1 -2271
- package/dist/sessions-B9pNuxdT.js +2272 -0
- package/dist/sessions-B9pNuxdT.js.map +1 -0
- package/dist/settings-C45hDliX.js +253 -0
- package/dist/settings-C45hDliX.js.map +1 -0
- package/dist/{transport-PfFnt-Ld.d.ts → settings-NgGwF7Qt.d.ts} +14 -208
- package/dist/{src-BZeu-SCD.js → src-DgCbZtIR.js} +4 -4
- package/dist/{src-BZeu-SCD.js.map → src-DgCbZtIR.js.map} +1 -1
- package/dist/stall-watchdog-BpRF2uwG.js +195 -0
- package/dist/stall-watchdog-BpRF2uwG.js.map +1 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/store-DLeqKuj3.d.ts +310 -0
- package/dist/store-vgcPYo8K.js +432 -0
- package/dist/store-vgcPYo8K.js.map +1 -0
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/{streams-DW-UCOUc.js → streams-CITClVer.js} +16 -3
- package/dist/streams-CITClVer.js.map +1 -0
- package/dist/{streams-Cmkj9QfW.d.ts → streams-fbG61qM8.d.ts} +2 -2
- package/dist/sub-routing.d.ts +1 -1
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/{tasks-68DESxf0.js → tasks-CkTZNaV1.js} +2 -1
- package/dist/tasks-CkTZNaV1.js.map +1 -0
- package/dist/{tasks-9YxYtByh.d.ts → tasks-PtlB4Uyn.d.ts} +2 -2
- package/dist/tool-3PA8xjB_.js +421 -0
- package/dist/tool-3PA8xjB_.js.map +1 -0
- package/dist/tool-BPJEbwaX.d.ts +278 -0
- package/dist/transport-k2mFrtL8.d.ts +200 -0
- package/dist/turns-DCV3ycDl.js +317 -0
- package/dist/turns-DCV3ycDl.js.map +1 -0
- package/dist/voice/client.js +1 -1
- package/dist/voice/index.d.ts +2 -2
- package/dist/voice/index.js +1 -1
- package/dist/websearch/index.d.ts +58 -0
- package/dist/websearch/index.js +2 -0
- package/dist/websearch/tools/ai-sdk.d.ts +77 -0
- package/dist/websearch/tools/ai-sdk.js +46 -0
- package/dist/websearch/tools/ai-sdk.js.map +1 -0
- package/dist/websearch/tools/pi.d.ts +82 -0
- package/dist/websearch/tools/pi.js +89 -0
- package/dist/websearch/tools/pi.js.map +1 -0
- package/dist/websearch/tools/tanstack-ai.d.ts +71 -0
- package/dist/websearch/tools/tanstack-ai.js +46 -0
- package/dist/websearch/tools/tanstack-ai.js.map +1 -0
- package/dist/websockets/index.d.ts +12 -296
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-Ci-LZFHH.js → websockets-CmENGb-Z.js} +18 -4
- package/dist/websockets-CmENGb-Z.js.map +1 -0
- package/dist/{wire-types-CrjKvDyi.d.ts → wire-types-Cv0iwjk5.d.ts} +3 -51
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +1 -1
- package/docs/browse-the-web.md +3 -0
- package/docs/harnesses/pi.md +114 -32
- package/docs/harnesses/think.md +215 -0
- package/docs/index.md +4 -3
- package/docs/lifecycle.md +40 -0
- package/docs/models-pi-ai.md +5 -5
- package/docs/search-the-web.md +133 -0
- package/package.json +126 -47
- package/dist/browser-tool-CQ10e6Kj.js.map +0 -1
- package/dist/channel-Bnm4S7T2.d.ts +0 -491
- package/dist/channels/ai-sdk.d.ts +0 -46
- package/dist/channels/ai-sdk.js +0 -120
- package/dist/channels/ai-sdk.js.map +0 -1
- package/dist/channels/email.js.map +0 -1
- package/dist/channels/index.d.ts +0 -233
- package/dist/channels/index.js +0 -608
- package/dist/channels/index.js.map +0 -1
- package/dist/channels/slack.js +0 -614
- package/dist/channels/slack.js.map +0 -1
- package/dist/channels/tanstack-ai.d.ts +0 -39
- package/dist/channels/tanstack-ai.js +0 -17
- package/dist/channels/tanstack-ai.js.map +0 -1
- package/dist/channels/telegram.js +0 -427
- package/dist/channels/telegram.js.map +0 -1
- package/dist/channels/voice.d.ts +0 -45
- package/dist/channels/voice.js +0 -122
- package/dist/channels/voice.js.map +0 -1
- package/dist/harnesses/pi/index.js.map +0 -1
- package/dist/images-iiTDSyRu.js.map +0 -1
- package/dist/index-BB0kqhIz.d.ts +0 -101
- package/dist/ingress-BfetZbMO.js +0 -83
- package/dist/ingress-BfetZbMO.js.map +0 -1
- package/dist/internal-CYlgHl1l.js +0 -59
- package/dist/internal-CYlgHl1l.js.map +0 -1
- package/dist/models/ai-sdk/index.js.map +0 -1
- package/dist/protocol-kHsr-f0X.js.map +0 -1
- package/dist/sessions/index.js.map +0 -1
- package/dist/streams-DW-UCOUc.js.map +0 -1
- package/dist/surface-bZZJqBka.js +0 -17
- package/dist/surface-bZZJqBka.js.map +0 -1
- package/dist/tasks-68DESxf0.js.map +0 -1
- package/dist/tool-schema-CBjGPrsQ.js +0 -31
- package/dist/tool-schema-CBjGPrsQ.js.map +0 -1
- package/dist/websockets-Ci-LZFHH.js.map +0 -1
- package/docs/channels.md +0 -323
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import {
|
|
2
|
+
d as ChannelUpgradeMatch,
|
|
3
|
+
m as ParticipantResult,
|
|
4
|
+
n as Channel,
|
|
5
|
+
t as Awaitable
|
|
6
|
+
} from "../../../channel-Bak_6zDP.js";
|
|
7
|
+
import {
|
|
8
|
+
_ as TranscriptMessage,
|
|
9
|
+
c as InboundEvent,
|
|
10
|
+
i as ConversationSnapshot,
|
|
11
|
+
m as ResponseChunk,
|
|
12
|
+
n as ConversationInfo,
|
|
13
|
+
p as Participant,
|
|
14
|
+
r as ConversationOperation,
|
|
15
|
+
y as TurnStatus
|
|
16
|
+
} from "../../../protocol-CukuI73M.js";
|
|
17
|
+
import { i as WebSockets } from "../../../index-Ib_4dwOo.js";
|
|
18
|
+
import {
|
|
19
|
+
a as ConversationChannel,
|
|
20
|
+
o as ConversationUpdate,
|
|
21
|
+
r as ChannelsHost
|
|
22
|
+
} from "../../../conversations-DH0ut_8n.js";
|
|
23
|
+
|
|
24
|
+
//#region src/experimental/channels/web/channel.d.ts
|
|
25
|
+
type WebChannelOptions = {
|
|
26
|
+
/**
|
|
27
|
+
* The connections to serve conversations on, for an agent sharing its own.
|
|
28
|
+
* Default: the WebSockets Channels shares, created on first use.
|
|
29
|
+
*/
|
|
30
|
+
websockets?: WebSockets;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Serves conversations over the agent's WebSockets connections, to clients
|
|
34
|
+
* the gateway has resolved. Frames are
|
|
35
|
+
* namespaced `channels:`, so a connection can carry other protocols too.
|
|
36
|
+
*/
|
|
37
|
+
declare class WebChannel implements ConversationChannel {
|
|
38
|
+
#private;
|
|
39
|
+
constructor(options?: WebChannelOptions);
|
|
40
|
+
mount(host: ChannelsHost): void;
|
|
41
|
+
publish(conversationId: string, update: ConversationUpdate): void;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/experimental/channels/web/ingress.d.ts
|
|
45
|
+
/** How the gateway takes the Web Channel's WebSocket upgrades. */
|
|
46
|
+
type WebIngressOptions = {
|
|
47
|
+
/**
|
|
48
|
+
* Who is connecting, from request data you can verify, such as a session
|
|
49
|
+
* cookie or an Access JWT. Return null to refuse the upgrade.
|
|
50
|
+
*/
|
|
51
|
+
participant(request: Request): Awaitable<ParticipantResult>;
|
|
52
|
+
/**
|
|
53
|
+
* The agent object the participant reaches, or null to refuse them. That
|
|
54
|
+
* object is the authorization boundary: whoever reaches it may use every
|
|
55
|
+
* conversation in it. Default: an agent object of the participant's own.
|
|
56
|
+
*/
|
|
57
|
+
route?(request: Request, participant: Participant): Awaitable<string | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Which upgrades are for the Web Channel, and the conversation each
|
|
60
|
+
* follows. Return undefined for one that is not. Default: `/channels`,
|
|
61
|
+
* or `/channels/<conversation>`.
|
|
62
|
+
*/
|
|
63
|
+
match?(request: Request): ChannelUpgradeMatch | undefined;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The Web Channel's side in the gateway: it resolves each WebSocket upgrade
|
|
67
|
+
* and forwards it to the agent, whose `WebChannel` serves the connection.
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* new ChannelGateway({
|
|
71
|
+
* agent: (route) => env.SupportAgent.getByName(route),
|
|
72
|
+
* channels: {
|
|
73
|
+
* web: web({
|
|
74
|
+
* participant: async (request) =>
|
|
75
|
+
* (await verifySession(request, env))?.id ?? null
|
|
76
|
+
* })
|
|
77
|
+
* }
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare function web(options: WebIngressOptions): Channel;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/experimental/channels/web/protocol.d.ts
|
|
84
|
+
/** Who a connection is: set by the gateway, read by the Web Channel. */
|
|
85
|
+
type WebIdentity = {
|
|
86
|
+
/** The route that picked the agent. */ route: string /** The conversation to follow. Default: the agent's default for the route. */;
|
|
87
|
+
conversationId?: string;
|
|
88
|
+
participant: Participant;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The header carrying a connection's WebIdentity from the gateway to the
|
|
92
|
+
* agent. The gateway always sets it, so a client cannot supply its own; an
|
|
93
|
+
* agent must not take WebSocket upgrades from any other route.
|
|
94
|
+
*/
|
|
95
|
+
declare const WEB_IDENTITY_HEADER = "x-channels-identity";
|
|
96
|
+
type ClientFrame =
|
|
97
|
+
| {
|
|
98
|
+
type: "channels:event";
|
|
99
|
+
event: InboundEvent;
|
|
100
|
+
}
|
|
101
|
+
| {
|
|
102
|
+
type: "channels:subscribe";
|
|
103
|
+
responseId: string;
|
|
104
|
+
from?: number;
|
|
105
|
+
} /** Ask for the agent's conversations; answered by `channels:conversations`. */
|
|
106
|
+
| {
|
|
107
|
+
type: "channels:list-conversations";
|
|
108
|
+
requestId: string;
|
|
109
|
+
};
|
|
110
|
+
type ServerFrame = {
|
|
111
|
+
conversationId: string;
|
|
112
|
+
} &
|
|
113
|
+
/**
|
|
114
|
+
* On connect, after a reset (empty), and when the connection follows
|
|
115
|
+
* another conversation. `you` is this connection's participant;
|
|
116
|
+
* `operations` are the conversation operations it may send.
|
|
117
|
+
*/
|
|
118
|
+
(
|
|
119
|
+
| ({
|
|
120
|
+
type: "channels:snapshot";
|
|
121
|
+
you: Participant;
|
|
122
|
+
operations: ConversationOperation[];
|
|
123
|
+
} & ConversationSnapshot)
|
|
124
|
+
| {
|
|
125
|
+
type: "channels:turn";
|
|
126
|
+
turn: TurnStatus;
|
|
127
|
+
} /** Upserts by id; an unknown id appends. */
|
|
128
|
+
| {
|
|
129
|
+
type: "channels:messages";
|
|
130
|
+
messages: TranscriptMessage[];
|
|
131
|
+
}
|
|
132
|
+
| {
|
|
133
|
+
type: "channels:chunks";
|
|
134
|
+
responseId: string /** Seq of the first chunk. */;
|
|
135
|
+
from: number;
|
|
136
|
+
chunks: ResponseChunk[];
|
|
137
|
+
} /** Everything before this was replay; what follows is live. */
|
|
138
|
+
| {
|
|
139
|
+
type: "channels:caught-up";
|
|
140
|
+
responseId: string;
|
|
141
|
+
cursor: number;
|
|
142
|
+
}
|
|
143
|
+
| {
|
|
144
|
+
type: "channels:end";
|
|
145
|
+
responseId: string;
|
|
146
|
+
state: "ended" | "interrupted" | "not-found";
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The agent's conversations: the answer to a list request, carrying its
|
|
150
|
+
* `requestId`, or pushed when one is created or forked.
|
|
151
|
+
*/
|
|
152
|
+
| {
|
|
153
|
+
type: "channels:conversations";
|
|
154
|
+
requestId?: string;
|
|
155
|
+
conversations?: ConversationInfo[];
|
|
156
|
+
error?: string;
|
|
157
|
+
} /** `conversationId` is the one a create or fork started, when it did. */
|
|
158
|
+
| {
|
|
159
|
+
type: "channels:ack";
|
|
160
|
+
eventId: string;
|
|
161
|
+
error?: string;
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
/** A frame that names a Channels type but is malformed. */
|
|
165
|
+
type InvalidClientFrame = {
|
|
166
|
+
invalid: string;
|
|
167
|
+
eventId?: string;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Parse a text frame. Returns undefined for anything that is not a Channels
|
|
171
|
+
* frame, so the socket's other protocols keep working.
|
|
172
|
+
*/
|
|
173
|
+
declare function parseClientFrame(
|
|
174
|
+
text: string
|
|
175
|
+
): ClientFrame | InvalidClientFrame | undefined;
|
|
176
|
+
//#endregion
|
|
177
|
+
export {
|
|
178
|
+
ClientFrame,
|
|
179
|
+
InvalidClientFrame,
|
|
180
|
+
ServerFrame,
|
|
181
|
+
WEB_IDENTITY_HEADER,
|
|
182
|
+
WebChannel,
|
|
183
|
+
WebChannelOptions,
|
|
184
|
+
WebIdentity,
|
|
185
|
+
WebIngressOptions,
|
|
186
|
+
parseClientFrame,
|
|
187
|
+
web
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../../../classPrivateFieldGet2-DZBYAB34.js";
|
|
2
|
+
import { t as _classPrivateMethodInitSpec } from "../../../classPrivateMethodInitSpec-qMjJ6sHQ.js";
|
|
3
|
+
import { a as getConnectionFlag, l as registerInternalConnectionKeys, t as WebSockets, u as setConnectionFlag } from "../../../websockets-CmENGb-Z.js";
|
|
4
|
+
import { i as participantRoute } from "../../../internal-kmw70xwR.js";
|
|
5
|
+
import { n as parseClientFrame, t as WEB_IDENTITY_HEADER } from "../../../protocol-y2sSY584.js";
|
|
6
|
+
//#region src/experimental/channels/web/channel.ts
|
|
7
|
+
/** Where a Channels connection's identity lives in its connection state. */
|
|
8
|
+
const IDENTITY_KEY = "_cf_channels";
|
|
9
|
+
registerInternalConnectionKeys(IDENTITY_KEY);
|
|
10
|
+
var _options = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
var _websockets = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
var _host = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
var _pending = /* @__PURE__ */ new WeakMap();
|
|
14
|
+
var _reads = /* @__PURE__ */ new WeakMap();
|
|
15
|
+
var _WebChannel_brand = /* @__PURE__ */ new WeakSet();
|
|
16
|
+
/**
|
|
17
|
+
* Serves conversations over the agent's WebSockets connections, to clients
|
|
18
|
+
* the gateway has resolved. Frames are
|
|
19
|
+
* namespaced `channels:`, so a connection can carry other protocols too.
|
|
20
|
+
*/
|
|
21
|
+
var WebChannel = class {
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
_classPrivateMethodInitSpec(this, _WebChannel_brand);
|
|
24
|
+
_classPrivateFieldInitSpec(this, _options, void 0);
|
|
25
|
+
_classPrivateFieldInitSpec(this, _websockets, void 0);
|
|
26
|
+
_classPrivateFieldInitSpec(this, _host, void 0);
|
|
27
|
+
_classPrivateFieldInitSpec(this, _pending, /* @__PURE__ */ new Map());
|
|
28
|
+
_classPrivateFieldInitSpec(this, _reads, /* @__PURE__ */ new Map());
|
|
29
|
+
_classPrivateFieldSet2(_options, this, options);
|
|
30
|
+
}
|
|
31
|
+
mount(host) {
|
|
32
|
+
if (_classPrivateFieldGet2(_host, this)) throw new Error("A WebChannel can be mounted only once");
|
|
33
|
+
_classPrivateFieldSet2(_host, this, host);
|
|
34
|
+
_classPrivateFieldSet2(_websockets, this, _classPrivateFieldGet2(_options, this).websockets ?? host.websockets(() => new WebSockets()));
|
|
35
|
+
_classPrivateFieldGet2(_websockets, this).use({
|
|
36
|
+
onConnect: (connection, ctx) => _assertClassBrand(_WebChannel_brand, this, _connect).call(this, connection, ctx),
|
|
37
|
+
onMessage: (connection, message) => _assertClassBrand(_WebChannel_brand, this, _message).call(this, connection, message),
|
|
38
|
+
onClose: (connection) => _assertClassBrand(_WebChannel_brand, this, _close).call(this, connection)
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
publish(conversationId, update) {
|
|
42
|
+
for (const [connection, identity] of _assertClassBrand(_WebChannel_brand, this, _connections).call(this)) {
|
|
43
|
+
if (identity.conversationId !== conversationId) continue;
|
|
44
|
+
if (update.type === "messages" && _assertClassBrand(_WebChannel_brand, this, _sentBy).call(this, update, connection)) continue;
|
|
45
|
+
if (update.type === "reset") _assertClassBrand(_WebChannel_brand, this, _stopReads).call(this, connection.id);
|
|
46
|
+
const frame = toFrame(update, conversationId, identity.participant, _assertClassBrand(_WebChannel_brand, this, _mounted).call(this).operations);
|
|
47
|
+
const pending = _classPrivateFieldGet2(_pending, this).get(connection.id);
|
|
48
|
+
if (pending) pending.push(frame);
|
|
49
|
+
else send(connection, frame);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
async function _connect(connection, { request }) {
|
|
54
|
+
const header = request.headers.get(WEB_IDENTITY_HEADER);
|
|
55
|
+
if (header === null) return;
|
|
56
|
+
const resolved = JSON.parse(header);
|
|
57
|
+
const host = _assertClassBrand(_WebChannel_brand, this, _mounted).call(this);
|
|
58
|
+
const identity = {
|
|
59
|
+
...resolved,
|
|
60
|
+
conversationId: resolved.conversationId ?? host.defaultConversation(),
|
|
61
|
+
channelKey: host.channelKey
|
|
62
|
+
};
|
|
63
|
+
setConnectionFlag(connection, IDENTITY_KEY, identity);
|
|
64
|
+
_classPrivateFieldGet2(_pending, this).set(connection.id, []);
|
|
65
|
+
await _assertClassBrand(_WebChannel_brand, this, _sendSnapshot).call(this, connection, identity);
|
|
66
|
+
}
|
|
67
|
+
async function _message(connection, message) {
|
|
68
|
+
const identity = _assertClassBrand(_WebChannel_brand, this, _identityOf).call(this, connection);
|
|
69
|
+
if (!identity || typeof message !== "string") return false;
|
|
70
|
+
const frame = parseClientFrame(message);
|
|
71
|
+
if (!frame) return false;
|
|
72
|
+
if ("invalid" in frame) {
|
|
73
|
+
send(connection, {
|
|
74
|
+
type: "channels:ack",
|
|
75
|
+
conversationId: identity.conversationId,
|
|
76
|
+
eventId: frame.eventId ?? "",
|
|
77
|
+
error: `Invalid frame: ${frame.invalid}`
|
|
78
|
+
});
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
if (frame.type === "channels:list-conversations") {
|
|
82
|
+
await _assertClassBrand(_WebChannel_brand, this, _list).call(this, connection, identity, frame.requestId);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
if (frame.type === "channels:subscribe") {
|
|
86
|
+
_assertClassBrand(_WebChannel_brand, this, _subscribe).call(this, connection, identity, frame.responseId, frame.from);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
const { eventId } = frame.event;
|
|
90
|
+
let result;
|
|
91
|
+
try {
|
|
92
|
+
result = await _assertClassBrand(_WebChannel_brand, this, _mounted).call(this).dispatch(frame.event, origin(identity, connection.id));
|
|
93
|
+
} catch {
|
|
94
|
+
send(connection, {
|
|
95
|
+
type: "channels:ack",
|
|
96
|
+
conversationId: identity.conversationId,
|
|
97
|
+
eventId,
|
|
98
|
+
error: "Event rejected"
|
|
99
|
+
});
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
const followed = result.conversationId;
|
|
103
|
+
send(connection, {
|
|
104
|
+
type: "channels:ack",
|
|
105
|
+
conversationId: followed ?? identity.conversationId,
|
|
106
|
+
eventId
|
|
107
|
+
});
|
|
108
|
+
if (followed !== void 0 && followed !== identity.conversationId) await _assertClassBrand(_WebChannel_brand, this, _follow).call(this, connection, {
|
|
109
|
+
...identity,
|
|
110
|
+
conversationId: followed
|
|
111
|
+
});
|
|
112
|
+
if (followed !== void 0) await _assertClassBrand(_WebChannel_brand, this, _pushConversations).call(this);
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
async function _list(connection, identity, requestId) {
|
|
116
|
+
const frame = {
|
|
117
|
+
type: "channels:conversations",
|
|
118
|
+
conversationId: identity.conversationId,
|
|
119
|
+
requestId
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
const conversations = await _assertClassBrand(_WebChannel_brand, this, _mounted).call(this).listConversations();
|
|
123
|
+
send(connection, {
|
|
124
|
+
...frame,
|
|
125
|
+
conversations
|
|
126
|
+
});
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error("Failed to list conversations", error);
|
|
129
|
+
send(connection, {
|
|
130
|
+
...frame,
|
|
131
|
+
error: "Failed to list conversations"
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** Tell every connection the agent's conversations changed. */
|
|
136
|
+
async function _pushConversations() {
|
|
137
|
+
let conversations;
|
|
138
|
+
try {
|
|
139
|
+
conversations = await _assertClassBrand(_WebChannel_brand, this, _mounted).call(this).listConversations();
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("Failed to list conversations", error);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
for (const [connection, identity] of _assertClassBrand(_WebChannel_brand, this, _connections).call(this)) {
|
|
145
|
+
const frame = {
|
|
146
|
+
type: "channels:conversations",
|
|
147
|
+
conversationId: identity.conversationId,
|
|
148
|
+
conversations
|
|
149
|
+
};
|
|
150
|
+
const pending = _classPrivateFieldGet2(_pending, this).get(connection.id);
|
|
151
|
+
if (pending) pending.push(frame);
|
|
152
|
+
else send(connection, frame);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** Move a connection to another conversation, starting from its snapshot. */
|
|
156
|
+
async function _follow(connection, identity) {
|
|
157
|
+
_assertClassBrand(_WebChannel_brand, this, _stopReads).call(this, connection.id);
|
|
158
|
+
setConnectionFlag(connection, IDENTITY_KEY, identity);
|
|
159
|
+
_classPrivateFieldGet2(_pending, this).set(connection.id, []);
|
|
160
|
+
await _assertClassBrand(_WebChannel_brand, this, _sendSnapshot).call(this, connection, identity);
|
|
161
|
+
}
|
|
162
|
+
function _close(connection) {
|
|
163
|
+
_assertClassBrand(_WebChannel_brand, this, _stopReads).call(this, connection.id);
|
|
164
|
+
_classPrivateFieldGet2(_pending, this).delete(connection.id);
|
|
165
|
+
}
|
|
166
|
+
function _sentBy(update, connection) {
|
|
167
|
+
const surface = update.origin?.surface;
|
|
168
|
+
return surface !== void 0 && surface.channelKey === _classPrivateFieldGet2(_host, this)?.channelKey && connectionIdOf(surface.address) === connection.id;
|
|
169
|
+
}
|
|
170
|
+
async function _sendSnapshot(connection, identity) {
|
|
171
|
+
try {
|
|
172
|
+
const snapshot = await _assertClassBrand(_WebChannel_brand, this, _mounted).call(this).snapshot(identity.conversationId);
|
|
173
|
+
send(connection, {
|
|
174
|
+
type: "channels:snapshot",
|
|
175
|
+
conversationId: identity.conversationId,
|
|
176
|
+
you: identity.participant,
|
|
177
|
+
operations: [..._assertClassBrand(_WebChannel_brand, this, _mounted).call(this).operations],
|
|
178
|
+
...snapshot
|
|
179
|
+
});
|
|
180
|
+
for (const frame of _classPrivateFieldGet2(_pending, this).get(connection.id) ?? []) send(connection, frame);
|
|
181
|
+
_classPrivateFieldGet2(_pending, this).delete(connection.id);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error("Failed to read the conversation snapshot", error);
|
|
184
|
+
_classPrivateFieldGet2(_pending, this).delete(connection.id);
|
|
185
|
+
connection.close(1011, "Snapshot failed");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/** One read per response per connection; a repeated subscribe joins it. */
|
|
189
|
+
function _subscribe(connection, identity, responseId, from) {
|
|
190
|
+
let reads = _classPrivateFieldGet2(_reads, this).get(connection.id);
|
|
191
|
+
if (!reads) _classPrivateFieldGet2(_reads, this).set(connection.id, reads = /* @__PURE__ */ new Map());
|
|
192
|
+
if (reads.has(responseId)) return;
|
|
193
|
+
const controller = new AbortController();
|
|
194
|
+
reads.set(responseId, controller);
|
|
195
|
+
const { conversationId } = identity;
|
|
196
|
+
_assertClassBrand(_WebChannel_brand, this, _mounted).call(this).readResponse(conversationId, responseId, {
|
|
197
|
+
from,
|
|
198
|
+
signal: controller.signal,
|
|
199
|
+
onChunks: (first, chunks) => send(connection, {
|
|
200
|
+
type: "channels:chunks",
|
|
201
|
+
conversationId,
|
|
202
|
+
responseId,
|
|
203
|
+
from: first,
|
|
204
|
+
chunks
|
|
205
|
+
}),
|
|
206
|
+
onCaughtUp: (cursor) => send(connection, {
|
|
207
|
+
type: "channels:caught-up",
|
|
208
|
+
conversationId,
|
|
209
|
+
responseId,
|
|
210
|
+
cursor
|
|
211
|
+
})
|
|
212
|
+
}).then((ending) => send(connection, {
|
|
213
|
+
type: "channels:end",
|
|
214
|
+
conversationId,
|
|
215
|
+
responseId,
|
|
216
|
+
state: ending
|
|
217
|
+
}), (error) => {
|
|
218
|
+
if (controller.signal.aborted) return;
|
|
219
|
+
console.error(`Failed to read response "${responseId}"`, error);
|
|
220
|
+
send(connection, {
|
|
221
|
+
type: "channels:end",
|
|
222
|
+
conversationId,
|
|
223
|
+
responseId,
|
|
224
|
+
state: "interrupted"
|
|
225
|
+
});
|
|
226
|
+
}).finally(() => reads.delete(responseId));
|
|
227
|
+
}
|
|
228
|
+
function _stopReads(connectionId) {
|
|
229
|
+
for (const controller of _classPrivateFieldGet2(_reads, this).get(connectionId)?.values() ?? []) controller.abort();
|
|
230
|
+
_classPrivateFieldGet2(_reads, this).delete(connectionId);
|
|
231
|
+
}
|
|
232
|
+
function* _connections() {
|
|
233
|
+
for (const connection of _classPrivateFieldGet2(_websockets, this)?.getConnections() ?? []) {
|
|
234
|
+
const identity = _assertClassBrand(_WebChannel_brand, this, _identityOf).call(this, connection);
|
|
235
|
+
if (identity) yield [connection, identity];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function _identityOf(connection) {
|
|
239
|
+
const identity = getConnectionFlag(connection, IDENTITY_KEY);
|
|
240
|
+
return identity?.channelKey === _classPrivateFieldGet2(_host, this)?.channelKey ? identity : void 0;
|
|
241
|
+
}
|
|
242
|
+
function _mounted() {
|
|
243
|
+
if (!_classPrivateFieldGet2(_host, this)) throw new Error("WebChannel is not mounted");
|
|
244
|
+
return _classPrivateFieldGet2(_host, this);
|
|
245
|
+
}
|
|
246
|
+
function origin(identity, connectionId) {
|
|
247
|
+
return {
|
|
248
|
+
conversationId: identity.conversationId,
|
|
249
|
+
participant: identity.participant,
|
|
250
|
+
surface: {
|
|
251
|
+
channelKey: identity.channelKey,
|
|
252
|
+
version: 1,
|
|
253
|
+
address: {
|
|
254
|
+
conversationId: identity.conversationId,
|
|
255
|
+
connectionId
|
|
256
|
+
},
|
|
257
|
+
label: "Web"
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function connectionIdOf(address) {
|
|
262
|
+
return typeof address === "object" && address !== null && "connectionId" in address && typeof address.connectionId === "string" ? address.connectionId : void 0;
|
|
263
|
+
}
|
|
264
|
+
function toFrame(update, conversationId, you, operations) {
|
|
265
|
+
switch (update.type) {
|
|
266
|
+
case "turn": return {
|
|
267
|
+
type: "channels:turn",
|
|
268
|
+
conversationId,
|
|
269
|
+
turn: update.turn
|
|
270
|
+
};
|
|
271
|
+
case "messages": return {
|
|
272
|
+
type: "channels:messages",
|
|
273
|
+
conversationId,
|
|
274
|
+
messages: update.messages
|
|
275
|
+
};
|
|
276
|
+
case "reset": return {
|
|
277
|
+
type: "channels:snapshot",
|
|
278
|
+
conversationId,
|
|
279
|
+
you,
|
|
280
|
+
operations: [...operations],
|
|
281
|
+
messages: [],
|
|
282
|
+
turns: []
|
|
283
|
+
};
|
|
284
|
+
case "response-end": return {
|
|
285
|
+
type: "channels:end",
|
|
286
|
+
conversationId,
|
|
287
|
+
responseId: update.responseId,
|
|
288
|
+
state: update.ending
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/** A failed send to one stale socket must not stop delivery to the rest. */
|
|
293
|
+
function send(connection, frame) {
|
|
294
|
+
try {
|
|
295
|
+
connection.send(JSON.stringify(frame));
|
|
296
|
+
} catch {}
|
|
297
|
+
}
|
|
298
|
+
//#endregion
|
|
299
|
+
//#region src/experimental/channels/web/ingress.ts
|
|
300
|
+
/**
|
|
301
|
+
* The Web Channel's side in the gateway: it resolves each WebSocket upgrade
|
|
302
|
+
* and forwards it to the agent, whose `WebChannel` serves the connection.
|
|
303
|
+
*
|
|
304
|
+
* ```ts
|
|
305
|
+
* new ChannelGateway({
|
|
306
|
+
* agent: (route) => env.SupportAgent.getByName(route),
|
|
307
|
+
* channels: {
|
|
308
|
+
* web: web({
|
|
309
|
+
* participant: async (request) =>
|
|
310
|
+
* (await verifySession(request, env))?.id ?? null
|
|
311
|
+
* })
|
|
312
|
+
* }
|
|
313
|
+
* });
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
function web(options) {
|
|
317
|
+
const route = options.route;
|
|
318
|
+
return { upgrade: {
|
|
319
|
+
match: options.match ?? matchChannelsPath,
|
|
320
|
+
participant: (request) => options.participant(request),
|
|
321
|
+
route: (request, participant) => route ? route(request, participant) : participantRoute(participant)
|
|
322
|
+
} };
|
|
323
|
+
}
|
|
324
|
+
function matchChannelsPath(request) {
|
|
325
|
+
const match = /^\/channels(?:\/([^/]+))?$/.exec(new URL(request.url).pathname);
|
|
326
|
+
if (!match) return void 0;
|
|
327
|
+
return match[1] === void 0 ? {} : { conversationId: decodeURIComponent(match[1]) };
|
|
328
|
+
}
|
|
329
|
+
//#endregion
|
|
330
|
+
export { WEB_IDENTITY_HEADER, WebChannel, parseClientFrame, web };
|
|
331
|
+
|
|
332
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/experimental/channels/web/channel.ts","../../../../src/experimental/channels/web/ingress.ts"],"sourcesContent":["import type {\n Connection,\n ConnectionContext,\n WSMessage\n} from \"../../../lifecycle\";\nimport {\n getConnectionFlag,\n registerInternalConnectionKeys,\n setConnectionFlag\n} from \"../../../websockets/connection-flags\";\nimport { WebSockets } from \"../../../websockets\";\nimport type {\n ChannelsHost,\n ConversationChannel,\n ConversationUpdate\n} from \"../conversations\";\nimport type {\n ConversationOperation,\n EventOrigin,\n Participant\n} from \"../protocol\";\nimport {\n parseClientFrame,\n WEB_IDENTITY_HEADER,\n type ServerFrame,\n type WebIdentity\n} from \"./protocol\";\n\n/** Where a Channels connection's identity lives in its connection state. */\nconst IDENTITY_KEY = \"_cf_channels\";\nregisterInternalConnectionKeys(IDENTITY_KEY);\n\nexport type WebChannelOptions = {\n /**\n * The connections to serve conversations on, for an agent sharing its own.\n * Default: the WebSockets Channels shares, created on first use.\n */\n websockets?: WebSockets;\n};\n\ntype Identity = Omit<WebIdentity, \"conversationId\"> & {\n conversationId: string;\n channelKey: string;\n};\n\n/**\n * Serves conversations over the agent's WebSockets connections, to clients\n * the gateway has resolved. Frames are\n * namespaced `channels:`, so a connection can carry other protocols too.\n */\nexport class WebChannel implements ConversationChannel {\n readonly #options: WebChannelOptions;\n #websockets: WebSockets | undefined;\n #host: ChannelsHost | undefined;\n /** Frames held back until a connection has its snapshot. */\n readonly #pending = new Map<string, ServerFrame[]>();\n /** Active response reads, by connection, then response. */\n readonly #reads = new Map<string, Map<string, AbortController>>();\n\n constructor(options: WebChannelOptions = {}) {\n this.#options = options;\n }\n\n mount(host: ChannelsHost): void {\n if (this.#host) throw new Error(\"A WebChannel can be mounted only once\");\n this.#host = host;\n this.#websockets =\n this.#options.websockets ?? host.websockets(() => new WebSockets());\n this.#websockets.use({\n onConnect: (connection, ctx) => this.#connect(connection, ctx),\n onMessage: (connection, message) => this.#message(connection, message),\n onClose: (connection) => this.#close(connection)\n });\n }\n\n publish(conversationId: string, update: ConversationUpdate): void {\n for (const [connection, identity] of this.#connections()) {\n if (identity.conversationId !== conversationId) continue;\n // The sender adds its own message once the agent accepts it.\n if (update.type === \"messages\" && this.#sentBy(update, connection)) {\n continue;\n }\n if (update.type === \"reset\") this.#stopReads(connection.id);\n const frame = toFrame(\n update,\n conversationId,\n identity.participant,\n this.#mounted().operations\n );\n const pending = this.#pending.get(connection.id);\n if (pending) pending.push(frame);\n else send(connection, frame);\n }\n }\n\n async #connect(\n connection: Connection,\n { request }: ConnectionContext\n ): Promise<void> {\n const header = request.headers.get(WEB_IDENTITY_HEADER);\n if (header === null) return;\n // The gateway is the trust boundary: it resolves who is connecting and\n // sets this header. The agent must only be reachable through the\n // gateway, or a caller could forge the header and join as anyone.\n // There is no further authorization here: the agent object is the\n // boundary, so a connection may use every conversation in it.\n // SAFETY: only the gateway sets this header, with a WebIdentity.\n const resolved = JSON.parse(header) as WebIdentity;\n const host = this.#mounted();\n const identity: Identity = {\n ...resolved,\n conversationId: resolved.conversationId ?? host.defaultConversation(),\n channelKey: host.channelKey\n };\n setConnectionFlag(connection, IDENTITY_KEY, identity);\n // Listen for pushes before reading the snapshot, so none are lost.\n this.#pending.set(connection.id, []);\n await this.#sendSnapshot(connection, identity);\n }\n\n async #message(connection: Connection, message: WSMessage): Promise<boolean> {\n const identity = this.#identityOf(connection);\n if (!identity || typeof message !== \"string\") return false;\n const frame = parseClientFrame(message);\n if (!frame) return false;\n\n if (\"invalid\" in frame) {\n send(connection, {\n type: \"channels:ack\",\n conversationId: identity.conversationId,\n eventId: frame.eventId ?? \"\",\n error: `Invalid frame: ${frame.invalid}`\n });\n return true;\n }\n if (frame.type === \"channels:list-conversations\") {\n await this.#list(connection, identity, frame.requestId);\n return true;\n }\n if (frame.type === \"channels:subscribe\") {\n this.#subscribe(connection, identity, frame.responseId, frame.from);\n return true;\n }\n\n const { eventId } = frame.event;\n let result;\n try {\n result = await this.#mounted().dispatch(\n frame.event,\n origin(identity, connection.id)\n );\n } catch {\n send(connection, {\n type: \"channels:ack\",\n conversationId: identity.conversationId,\n eventId,\n error: \"Event rejected\"\n });\n return true;\n }\n // The sender follows a conversation it created or forked; other\n // connections stay where they are. Acknowledge first: a client resends\n // unacknowledged events on every snapshot, and the new conversation's\n // snapshot would otherwise carry the create or fork into it again.\n const followed = result.conversationId;\n send(connection, {\n type: \"channels:ack\",\n conversationId: followed ?? identity.conversationId,\n eventId\n });\n if (followed !== undefined && followed !== identity.conversationId) {\n await this.#follow(connection, { ...identity, conversationId: followed });\n }\n if (followed !== undefined) await this.#pushConversations();\n return true;\n }\n\n async #list(\n connection: Connection,\n identity: Identity,\n requestId: string\n ): Promise<void> {\n // The agent object is the authorization boundary, so every connection\n // may list every conversation in it.\n const frame = {\n type: \"channels:conversations\" as const,\n conversationId: identity.conversationId,\n requestId\n };\n try {\n const conversations = await this.#mounted().listConversations();\n send(connection, { ...frame, conversations });\n } catch (error) {\n console.error(\"Failed to list conversations\", error);\n send(connection, { ...frame, error: \"Failed to list conversations\" });\n }\n }\n\n /** Tell every connection the agent's conversations changed. */\n async #pushConversations(): Promise<void> {\n let conversations;\n try {\n conversations = await this.#mounted().listConversations();\n } catch (error) {\n console.error(\"Failed to list conversations\", error);\n return;\n }\n for (const [connection, identity] of this.#connections()) {\n const frame: ServerFrame = {\n type: \"channels:conversations\",\n conversationId: identity.conversationId,\n conversations\n };\n const pending = this.#pending.get(connection.id);\n if (pending) pending.push(frame);\n else send(connection, frame);\n }\n }\n\n /** Move a connection to another conversation, starting from its snapshot. */\n async #follow(connection: Connection, identity: Identity): Promise<void> {\n this.#stopReads(connection.id);\n setConnectionFlag(connection, IDENTITY_KEY, identity);\n this.#pending.set(connection.id, []);\n await this.#sendSnapshot(connection, identity);\n }\n\n #close(connection: Connection): void {\n this.#stopReads(connection.id);\n this.#pending.delete(connection.id);\n }\n\n #sentBy(\n update: Extract<ConversationUpdate, { type: \"messages\" }>,\n connection: Connection\n ): boolean {\n const surface = update.origin?.surface;\n return (\n surface !== undefined &&\n surface.channelKey === this.#host?.channelKey &&\n connectionIdOf(surface.address) === connection.id\n );\n }\n\n async #sendSnapshot(\n connection: Connection,\n identity: Identity\n ): Promise<void> {\n try {\n const snapshot = await this.#mounted().snapshot(identity.conversationId);\n send(connection, {\n type: \"channels:snapshot\",\n conversationId: identity.conversationId,\n you: identity.participant,\n operations: [...this.#mounted().operations],\n ...snapshot\n });\n for (const frame of this.#pending.get(connection.id) ?? []) {\n send(connection, frame);\n }\n this.#pending.delete(connection.id);\n } catch (error) {\n console.error(\"Failed to read the conversation snapshot\", error);\n this.#pending.delete(connection.id);\n connection.close(1011, \"Snapshot failed\");\n }\n }\n\n /** One read per response per connection; a repeated subscribe joins it. */\n #subscribe(\n connection: Connection,\n identity: Identity,\n responseId: string,\n from: number | undefined\n ): void {\n let reads = this.#reads.get(connection.id);\n if (!reads) this.#reads.set(connection.id, (reads = new Map()));\n if (reads.has(responseId)) return;\n const controller = new AbortController();\n reads.set(responseId, controller);\n\n const { conversationId } = identity;\n this.#mounted()\n .readResponse(conversationId, responseId, {\n from,\n signal: controller.signal,\n onChunks: (first, chunks) =>\n send(connection, {\n type: \"channels:chunks\",\n conversationId,\n responseId,\n from: first,\n chunks\n }),\n onCaughtUp: (cursor) =>\n send(connection, {\n type: \"channels:caught-up\",\n conversationId,\n responseId,\n cursor\n })\n })\n .then(\n (ending) =>\n send(connection, {\n type: \"channels:end\",\n conversationId,\n responseId,\n state: ending\n }),\n (error) => {\n if (controller.signal.aborted) return;\n console.error(`Failed to read response \"${responseId}\"`, error);\n // Tell the client the read is over, so it does not wait forever.\n send(connection, {\n type: \"channels:end\",\n conversationId,\n responseId,\n state: \"interrupted\"\n });\n }\n )\n .finally(() => reads.delete(responseId));\n }\n\n #stopReads(connectionId: string): void {\n for (const controller of this.#reads.get(connectionId)?.values() ?? []) {\n controller.abort();\n }\n this.#reads.delete(connectionId);\n }\n\n *#connections(): Iterable<[Connection, Identity]> {\n for (const connection of this.#websockets?.getConnections() ?? []) {\n const identity = this.#identityOf(connection);\n if (identity) yield [connection, identity];\n }\n }\n\n #identityOf(connection: Connection): Identity | undefined {\n // SAFETY: only #connect writes this key, with an Identity.\n const identity = getConnectionFlag(connection, IDENTITY_KEY) as\n | Identity\n | undefined;\n return identity?.channelKey === this.#host?.channelKey\n ? identity\n : undefined;\n }\n\n #mounted(): ChannelsHost {\n if (!this.#host) throw new Error(\"WebChannel is not mounted\");\n return this.#host;\n }\n}\n\nfunction origin(identity: Identity, connectionId: string): EventOrigin {\n return {\n conversationId: identity.conversationId,\n participant: identity.participant,\n surface: {\n channelKey: identity.channelKey,\n version: 1,\n address: { conversationId: identity.conversationId, connectionId },\n label: \"Web\"\n }\n };\n}\n\nfunction connectionIdOf(address: unknown): string | undefined {\n return typeof address === \"object\" &&\n address !== null &&\n \"connectionId\" in address &&\n typeof address.connectionId === \"string\"\n ? address.connectionId\n : undefined;\n}\n\nfunction toFrame(\n update: ConversationUpdate,\n conversationId: string,\n you: Participant,\n operations: readonly ConversationOperation[]\n): ServerFrame {\n switch (update.type) {\n case \"turn\":\n return { type: \"channels:turn\", conversationId, turn: update.turn };\n case \"messages\":\n return {\n type: \"channels:messages\",\n conversationId,\n messages: update.messages\n };\n case \"reset\":\n return {\n type: \"channels:snapshot\",\n conversationId,\n you,\n operations: [...operations],\n messages: [],\n turns: []\n };\n case \"response-end\":\n return {\n type: \"channels:end\",\n conversationId,\n responseId: update.responseId,\n state: update.ending\n };\n }\n}\n\n/** A failed send to one stale socket must not stop delivery to the rest. */\nfunction send(connection: Connection, frame: ServerFrame): void {\n try {\n connection.send(JSON.stringify(frame));\n } catch {\n // The socket is closing; its close handler cleans up.\n }\n}\n","import type {\n Awaitable,\n Channel,\n ChannelUpgradeMatch,\n ParticipantResult\n} from \"../channel\";\nimport { participantRoute } from \"../internal\";\nimport type { Participant } from \"../protocol\";\n\n/** How the gateway takes the Web Channel's WebSocket upgrades. */\nexport type WebIngressOptions = {\n /**\n * Who is connecting, from request data you can verify, such as a session\n * cookie or an Access JWT. Return null to refuse the upgrade.\n */\n participant(request: Request): Awaitable<ParticipantResult>;\n /**\n * The agent object the participant reaches, or null to refuse them. That\n * object is the authorization boundary: whoever reaches it may use every\n * conversation in it. Default: an agent object of the participant's own.\n */\n route?(request: Request, participant: Participant): Awaitable<string | null>;\n /**\n * Which upgrades are for the Web Channel, and the conversation each\n * follows. Return undefined for one that is not. Default: `/channels`,\n * or `/channels/<conversation>`.\n */\n match?(request: Request): ChannelUpgradeMatch | undefined;\n};\n\n/**\n * The Web Channel's side in the gateway: it resolves each WebSocket upgrade\n * and forwards it to the agent, whose `WebChannel` serves the connection.\n *\n * ```ts\n * new ChannelGateway({\n * agent: (route) => env.SupportAgent.getByName(route),\n * channels: {\n * web: web({\n * participant: async (request) =>\n * (await verifySession(request, env))?.id ?? null\n * })\n * }\n * });\n * ```\n */\nexport function web(options: WebIngressOptions): Channel {\n const route = options.route;\n return {\n upgrade: {\n match: options.match ?? matchChannelsPath,\n participant: (request) => options.participant(request),\n route: (request, participant) =>\n route ? route(request, participant) : participantRoute(participant)\n }\n };\n}\n\nfunction matchChannelsPath(request: Request): ChannelUpgradeMatch | undefined {\n const match = /^\\/channels(?:\\/([^/]+))?$/.exec(\n new URL(request.url).pathname\n );\n if (!match) return undefined;\n return match[1] === undefined\n ? {}\n : { conversationId: decodeURIComponent(match[1]) };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
N as ChannelIdentity,
|
|
3
|
+
S as ChannelEmailInput,
|
|
4
|
+
a as ChannelDeliveryOptions,
|
|
5
|
+
k as ChannelIngressEvent,
|
|
6
|
+
l as ChannelStreamOptions,
|
|
7
|
+
n as Channel,
|
|
8
|
+
o as ChannelMessage,
|
|
9
|
+
p as DeliveryResult,
|
|
10
|
+
r as ChannelChunkSource
|
|
11
|
+
} from "./channel-Bak_6zDP.js";
|
|
12
|
+
import {
|
|
13
|
+
b as ChannelMessageSurface,
|
|
14
|
+
p as Participant,
|
|
15
|
+
s as GatewayOrigin
|
|
16
|
+
} from "./protocol-CukuI73M.js";
|
|
17
|
+
import { c as GatewayEvent } from "./conversations-DH0ut_8n.js";
|
|
18
|
+
|
|
19
|
+
//#region src/experimental/channels/gateway.d.ts
|
|
20
|
+
type ChannelRouteEvent = {
|
|
21
|
+
channelKey: string;
|
|
22
|
+
event: ChannelIngressEvent /** Who the Channel resolved the sender as; null when it refused them. */;
|
|
23
|
+
participant: Participant | null /** The agent object the event reaches; null when it is ignored or refused. */;
|
|
24
|
+
route:
|
|
25
|
+
| string
|
|
26
|
+
| null /** Stable identity derived only from the configured Channel and eventId. */;
|
|
27
|
+
dispatchId: string;
|
|
28
|
+
};
|
|
29
|
+
/** The agent object a route names, as the gateway reaches it. */
|
|
30
|
+
type GatewayAgent = {
|
|
31
|
+
/** Hand the agent an inbound event; Channels' `receive` serves it. */ receive(
|
|
32
|
+
event: GatewayEvent,
|
|
33
|
+
origin: GatewayOrigin
|
|
34
|
+
): Promise<unknown>;
|
|
35
|
+
fetch(request: Request): Promise<Response>;
|
|
36
|
+
};
|
|
37
|
+
type ChannelGatewayOptions = {
|
|
38
|
+
/**
|
|
39
|
+
* The Channels this Worker serves. Each one that takes ingress says who
|
|
40
|
+
* its senders are (`participant`) and which agent object they reach
|
|
41
|
+
* (`route`).
|
|
42
|
+
*/
|
|
43
|
+
channels: Record<string, Channel> /** The agent object a route names. */;
|
|
44
|
+
agent(
|
|
45
|
+
route: string
|
|
46
|
+
): GatewayAgent /** Observes every valid route outcome before it is sent to the agent. */;
|
|
47
|
+
onRoute?(event: ChannelRouteEvent): void | Promise<void>;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The Worker's entry point for Channels. Authenticates and normalizes
|
|
51
|
+
* webhooks, resolves WebSocket upgrades, routes each to the agent object
|
|
52
|
+
* its route names, and sends to surfaces.
|
|
53
|
+
*
|
|
54
|
+
* The gateway is the trust boundary. It alone decides who a sender is and
|
|
55
|
+
* tells the agent, so an agent serving Channels must be reachable only
|
|
56
|
+
* through it: an app that forwards an upgrade to the agent some other way
|
|
57
|
+
* (another fetch handler, `routeAgentRequest`, RPC) lets the caller pick
|
|
58
|
+
* its own participant and conversation.
|
|
59
|
+
*
|
|
60
|
+
* The agent object is the authorization boundary. Whoever a Channel routes
|
|
61
|
+
* to an object may list, join, create, fork and reset every conversation in
|
|
62
|
+
* it. To keep people apart, route them to different objects; by default
|
|
63
|
+
* each participant gets an object of their own.
|
|
64
|
+
*/
|
|
65
|
+
declare class ChannelGateway {
|
|
66
|
+
#private;
|
|
67
|
+
constructor(options: ChannelGatewayOptions);
|
|
68
|
+
/** Serve a request if it is for Channels, or return undefined. */
|
|
69
|
+
fetch(request: Request): Promise<Response | undefined>;
|
|
70
|
+
handleEmail(email: ChannelEmailInput): Promise<boolean>;
|
|
71
|
+
/** Deliver through the configured Channel named by the surface. */
|
|
72
|
+
deliver(
|
|
73
|
+
surface: ChannelMessageSurface,
|
|
74
|
+
message: ChannelMessage,
|
|
75
|
+
options?: ChannelDeliveryOptions
|
|
76
|
+
): Promise<DeliveryResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Deliver a progressively generated answer to the Channel
|
|
79
|
+
* named by the surface.
|
|
80
|
+
*
|
|
81
|
+
* A Channel that can stream consumes the stream itself. A Channel that
|
|
82
|
+
* cannot never learns it was a stream, because the Host collects the answer
|
|
83
|
+
* and calls `deliver` once.
|
|
84
|
+
*/
|
|
85
|
+
stream(
|
|
86
|
+
surface: ChannelMessageSurface,
|
|
87
|
+
chunks: ChannelChunkSource,
|
|
88
|
+
options?: ChannelStreamOptions
|
|
89
|
+
): Promise<DeliveryResult>;
|
|
90
|
+
/** Return the identity's configured Channel destination, when supported. */
|
|
91
|
+
contactSurface(identity: ChannelIdentity): ChannelMessageSurface | null;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export {
|
|
95
|
+
GatewayAgent as i,
|
|
96
|
+
ChannelGatewayOptions as n,
|
|
97
|
+
ChannelRouteEvent as r,
|
|
98
|
+
ChannelGateway as t
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=gateway-BDC07gYO.d.ts.map
|