agents 0.26.0 → 0.28.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/abortable-C1SpfVoi.js +21 -0
- package/dist/abortable-C1SpfVoi.js.map +1 -0
- package/dist/{agent-routing-0DR0Tk2v.d.ts → agent-routing-QDcchcQP.d.ts} +16 -16
- 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-DHL2XI7u.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/ai-ahruGw7e.d.ts +239 -0
- package/dist/ai-sdk-Bdsf6mSA.js +2444 -0
- package/dist/ai-sdk-Bdsf6mSA.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.d.ts +8 -227
- package/dist/browser/ai.js +259 -1
- package/dist/browser/ai.js.map +1 -0
- package/dist/browser/index.d.ts +56 -46
- package/dist/browser/index.js +4 -361
- package/dist/browser/{ai-sdk.d.ts → tools/ai-sdk.d.ts} +7 -7
- package/dist/browser/{ai-sdk.js → tools/ai-sdk.js} +6 -5
- package/dist/browser/tools/ai-sdk.js.map +1 -0
- package/dist/browser/tools/pi.d.ts +111 -0
- package/dist/browser/tools/pi.js +119 -0
- package/dist/browser/tools/pi.js.map +1 -0
- package/dist/browser/{tanstack-ai.d.ts → tools/tanstack-ai.d.ts} +39 -37
- package/dist/browser/{tanstack-ai.js → tools/tanstack-ai.js} +73 -59
- package/dist/browser/tools/tanstack-ai.js.map +1 -0
- package/dist/browser-CEdNlsaD.js +481 -0
- package/dist/browser-CEdNlsaD.js.map +1 -0
- package/dist/{browser-DE3d-RLk.d.ts → browser-D30VlpcA.d.ts} +63 -37
- package/dist/{browser-tool-CQ10e6Kj.js → browser-tool-4iomavs_.js} +198 -62
- package/dist/browser-tool-4iomavs_.js.map +1 -0
- package/dist/{browser-tool-DuNdlwZ9.d.ts → browser-tool-vtrPOV8e.d.ts} +25 -6
- package/dist/{capability-B4WbF81e.js → capability-DBAKc6UZ.js} +1 -3
- package/dist/capability-DBAKc6UZ.js.map +1 -0
- package/dist/{capability-runner-DBAnGr6L.d.ts → capability-runner-BiVUtjqC.d.ts} +9 -7
- 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-je3koD9Z.d.ts → client-BGIQKJhX.d.ts} +2 -2
- package/dist/{client-fyQrLGkD.js → client-BnYbNT3z.js} +29 -5
- package/dist/client-BnYbNT3z.js.map +1 -0
- package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
- package/dist/client.d.ts +1 -1
- package/dist/{connector-58XDGvc3.js → connector-CtZylXdk.js} +3 -603
- package/dist/connector-CtZylXdk.js.map +1 -0
- package/dist/{connector-Cl-VqPmA.d.ts → connector-DEXzVoaY.d.ts} +9 -374
- package/dist/conversations-FjHDRZyD.d.ts +192 -0
- package/dist/{current-agent-vAk_5JMt.d.ts → current-agent-CKgT5d1O.d.ts} +3 -5
- package/dist/current-agent-DhoDkSnH.js.map +1 -1
- 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-DOI_bzCH.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-BFO6vRDn.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/harness/pi/index.d.ts +3 -2
- package/dist/harness/pi/index.js +3 -3
- 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 +2721 -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-BEL3ZV-s.d.ts} +2 -6
- package/dist/index-CBt8oRJt.d.ts +198 -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-BQykTEp_.js +20 -0
- package/dist/input-schema-BQykTEp_.js.map +1 -0
- package/dist/input-schema-D2QAtHZH.js +23 -0
- package/dist/input-schema-D2QAtHZH.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/lifecycle/index.js +2 -2
- package/dist/{lifecycle-CFu6OV03.js → lifecycle-DGorpAmA.js} +2 -4
- package/dist/lifecycle-DGorpAmA.js.map +1 -0
- 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 +9 -7
- package/dist/models/pi-ai/index.js +2 -1
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/options-CiIsJHXR.d.ts +130 -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/queue/index.js +1 -1
- package/dist/{queue-BB-zfIYF.js → queue-CcIjVYTE.js} +2 -2
- package/dist/{queue-BB-zfIYF.js.map → queue-CcIjVYTE.js.map} +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +2 -2
- package/dist/routing/index.js +1 -1
- package/dist/{scheduler-RdACNXDP.d.ts → scheduler-BCLESHSC.d.ts} +2 -12
- package/dist/{scheduler-DZ3xQfeK.js → scheduler-FIHv2-kJ.js} +2 -4
- package/dist/scheduler-FIHv2-kJ.js.map +1 -0
- package/dist/schedules/index.d.ts +1 -1
- package/dist/schedules/index.js +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/session-store-Do4xkDcf.js +606 -0
- package/dist/session-store-Do4xkDcf.js.map +1 -0
- package/dist/session-store-DoPY12xM.d.ts +383 -0
- package/dist/sessions/index.d.ts +11 -434
- package/dist/sessions/index.js +1 -2271
- package/dist/sessions-_vN5BEZX.js +2272 -0
- package/dist/sessions-_vN5BEZX.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-CQxJFv4l.js} +8 -8
- package/dist/src-CQxJFv4l.js.map +1 -0
- 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/state/index.js +1 -3
- package/dist/state/index.js.map +1 -1
- package/dist/store-BKM4Xm9M.d.ts +332 -0
- package/dist/store-CslVzfN7.js +458 -0
- package/dist/store-CslVzfN7.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-lsHMJhRW.js} +17 -4
- package/dist/streams-lsHMJhRW.js.map +1 -0
- package/dist/{streams-Cmkj9QfW.d.ts → streams-vrCtbUIn.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-BN_5AWqI.js} +3 -2
- package/dist/tasks-BN_5AWqI.js.map +1 -0
- package/dist/{tasks-9YxYtByh.d.ts → tasks-E89KdwkS.d.ts} +2 -2
- package/dist/tool-CTp72Jb_.d.ts +278 -0
- package/dist/tool-CxKsvxjm.js +1126 -0
- package/dist/tool-CxKsvxjm.js.map +1 -0
- package/dist/tool-DoVberpN.d.ts +301 -0
- package/dist/tool-cQRkwSZZ.js +410 -0
- package/dist/tool-cQRkwSZZ.js.map +1 -0
- package/dist/tool-helpers-O5BDVEAY.js +58 -0
- package/dist/tool-helpers-O5BDVEAY.js.map +1 -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/web/fetch/index.d.ts +89 -0
- package/dist/web/fetch/index.js +20 -0
- package/dist/web/fetch/index.js.map +1 -0
- package/dist/web/fetch/tools/ai-sdk.d.ts +80 -0
- package/dist/web/fetch/tools/ai-sdk.js +47 -0
- package/dist/web/fetch/tools/ai-sdk.js.map +1 -0
- package/dist/web/fetch/tools/pi.d.ts +84 -0
- package/dist/web/fetch/tools/pi.js +88 -0
- package/dist/web/fetch/tools/pi.js.map +1 -0
- package/dist/web/fetch/tools/tanstack-ai.d.ts +78 -0
- package/dist/web/fetch/tools/tanstack-ai.js +45 -0
- package/dist/web/fetch/tools/tanstack-ai.js.map +1 -0
- package/dist/web/search/index.d.ts +58 -0
- package/dist/web/search/index.js +2 -0
- package/dist/web/search/tools/ai-sdk.d.ts +77 -0
- package/dist/web/search/tools/ai-sdk.js +46 -0
- package/dist/web/search/tools/ai-sdk.js.map +1 -0
- package/dist/web/search/tools/pi.d.ts +82 -0
- package/dist/web/search/tools/pi.js +89 -0
- package/dist/web/search/tools/pi.js.map +1 -0
- package/dist/web/search/tools/tanstack-ai.d.ts +71 -0
- package/dist/web/search/tools/tanstack-ai.js +46 -0
- package/dist/web/search/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-C3zy8YR0.js} +20 -8
- package/dist/websockets-C3zy8YR0.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 +29 -1
- package/docs/fetch-the-web.md +276 -0
- package/docs/harnesses/pi.md +25 -0
- package/docs/harnesses/think.md +215 -0
- package/docs/index.md +99 -75
- package/docs/lifecycle.md +42 -3
- package/docs/queue.md +2 -3
- package/docs/scheduling.md +2 -6
- package/docs/search-the-web.md +135 -0
- package/package.json +148 -44
- package/dist/ai-fm7xx1BK.js +0 -312
- package/dist/ai-fm7xx1BK.js.map +0 -1
- package/dist/browser/ai-sdk.js.map +0 -1
- package/dist/browser/index.js.map +0 -1
- package/dist/browser/tanstack-ai.js.map +0 -1
- package/dist/browser-tool-CQ10e6Kj.js.map +0 -1
- package/dist/capability-B4WbF81e.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/client-fyQrLGkD.js.map +0 -1
- package/dist/connector-58XDGvc3.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/lifecycle-CFu6OV03.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/scheduler-DZ3xQfeK.js.map +0 -1
- package/dist/sessions/index.js.map +0 -1
- package/dist/src-BZeu-SCD.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,386 @@
|
|
|
1
|
+
//#region src/experimental/channels/surface.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A JSON value safe to persist across Worker and Durable Object boundaries.
|
|
4
|
+
*
|
|
5
|
+
* The recursive arms are interfaces rather than inline type literals so that
|
|
6
|
+
* TypeScript defers resolving them. Workers RPC checks a return type with
|
|
7
|
+
* `R extends Rpc.Serializable<R>`, which eagerly expands a self-referential
|
|
8
|
+
* type alias and fails with "Type instantiation is excessively deep". Deferred
|
|
9
|
+
* arms let a surface be returned from a Durable Object method.
|
|
10
|
+
*/
|
|
11
|
+
type ChannelSurfaceValue =
|
|
12
|
+
| null
|
|
13
|
+
| boolean
|
|
14
|
+
| number
|
|
15
|
+
| string
|
|
16
|
+
| ChannelSurfaceArray
|
|
17
|
+
| ChannelSurfaceObject;
|
|
18
|
+
interface ChannelSurfaceArray extends ReadonlyArray<ChannelSurfaceValue> {}
|
|
19
|
+
interface ChannelSurfaceObject {
|
|
20
|
+
readonly [key: string]: ChannelSurfaceValue;
|
|
21
|
+
}
|
|
22
|
+
/** A durable configured destination for one outbound message attempt. */
|
|
23
|
+
type ChannelMessageSurface<
|
|
24
|
+
TChannelKey extends string = string,
|
|
25
|
+
TAddress extends ChannelSurfaceValue = ChannelSurfaceValue
|
|
26
|
+
> = Readonly<{
|
|
27
|
+
channelKey: TChannelKey;
|
|
28
|
+
version: 1;
|
|
29
|
+
address: TAddress /** Human-readable destination text captured when the surface is created. */;
|
|
30
|
+
label: string;
|
|
31
|
+
}>;
|
|
32
|
+
/** A Channel-produced destination before its Host stamps the configured key. */
|
|
33
|
+
type ChannelMessageSurfaceInput<
|
|
34
|
+
TAddress extends ChannelSurfaceValue = ChannelSurfaceValue
|
|
35
|
+
> = Readonly<{
|
|
36
|
+
version: 1;
|
|
37
|
+
address: TAddress;
|
|
38
|
+
label: string;
|
|
39
|
+
}>;
|
|
40
|
+
/** Validate the common envelope before provider-specific address parsing. */
|
|
41
|
+
declare function isChannelMessageSurface(
|
|
42
|
+
value: unknown
|
|
43
|
+
): value is ChannelMessageSurface;
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/experimental/channels/protocol.d.ts
|
|
46
|
+
type Json = null | boolean | number | string | JsonArray | JsonObject;
|
|
47
|
+
interface JsonArray extends ReadonlyArray<Json> {}
|
|
48
|
+
interface JsonObject {
|
|
49
|
+
readonly [key: string]: Json;
|
|
50
|
+
}
|
|
51
|
+
type Participant = Readonly<{
|
|
52
|
+
/** Stable within the conversation. What the agent compares for ownership. */ id: string;
|
|
53
|
+
name?: string;
|
|
54
|
+
}>;
|
|
55
|
+
type TranscriptMessage = {
|
|
56
|
+
id: string;
|
|
57
|
+
role: "system" | "user" | "assistant";
|
|
58
|
+
parts: MessagePart[];
|
|
59
|
+
metadata?: JsonObject;
|
|
60
|
+
};
|
|
61
|
+
type MessagePart =
|
|
62
|
+
| {
|
|
63
|
+
type: "text";
|
|
64
|
+
text: string;
|
|
65
|
+
providerMetadata?: JsonObject;
|
|
66
|
+
}
|
|
67
|
+
| {
|
|
68
|
+
type: "reasoning";
|
|
69
|
+
text: string;
|
|
70
|
+
providerMetadata?: JsonObject;
|
|
71
|
+
}
|
|
72
|
+
| {
|
|
73
|
+
type: "file";
|
|
74
|
+
mediaType: string;
|
|
75
|
+
url: string;
|
|
76
|
+
filename?: string;
|
|
77
|
+
providerMetadata?: JsonObject;
|
|
78
|
+
}
|
|
79
|
+
| {
|
|
80
|
+
type: "source-url";
|
|
81
|
+
sourceId: string;
|
|
82
|
+
url: string;
|
|
83
|
+
title?: string;
|
|
84
|
+
providerMetadata?: JsonObject;
|
|
85
|
+
}
|
|
86
|
+
| {
|
|
87
|
+
type: "source-document";
|
|
88
|
+
sourceId: string;
|
|
89
|
+
mediaType: string;
|
|
90
|
+
title: string;
|
|
91
|
+
filename?: string;
|
|
92
|
+
providerMetadata?: JsonObject;
|
|
93
|
+
}
|
|
94
|
+
| {
|
|
95
|
+
type: "data";
|
|
96
|
+
name: string;
|
|
97
|
+
id?: string;
|
|
98
|
+
data: Json;
|
|
99
|
+
}
|
|
100
|
+
| ToolPart;
|
|
101
|
+
type ToolState =
|
|
102
|
+
| "input-streaming"
|
|
103
|
+
| "input-available"
|
|
104
|
+
| "approval-requested"
|
|
105
|
+
| "approval-responded"
|
|
106
|
+
| "output-available"
|
|
107
|
+
| "output-error"
|
|
108
|
+
| "output-denied";
|
|
109
|
+
type ToolPart = {
|
|
110
|
+
type: "tool";
|
|
111
|
+
toolCallId: string;
|
|
112
|
+
toolName: string;
|
|
113
|
+
state: ToolState;
|
|
114
|
+
input?: Json;
|
|
115
|
+
output?: Json;
|
|
116
|
+
errorText?: string /** Output so far; a later output replaces it. */;
|
|
117
|
+
preliminary?: boolean;
|
|
118
|
+
approval?: {
|
|
119
|
+
id: string;
|
|
120
|
+
approved?: boolean;
|
|
121
|
+
reason?: string;
|
|
122
|
+
} /** Id of the participant who may run this client tool call. Absent for server tools. */;
|
|
123
|
+
owner?: string;
|
|
124
|
+
providerExecuted?: boolean;
|
|
125
|
+
dynamic?: boolean;
|
|
126
|
+
title?: string;
|
|
127
|
+
providerMetadata?: JsonObject;
|
|
128
|
+
};
|
|
129
|
+
type ResponseChunk =
|
|
130
|
+
| {
|
|
131
|
+
type: "text-start";
|
|
132
|
+
id: string;
|
|
133
|
+
providerMetadata?: JsonObject;
|
|
134
|
+
}
|
|
135
|
+
| {
|
|
136
|
+
type: "text-delta";
|
|
137
|
+
id: string;
|
|
138
|
+
delta: string;
|
|
139
|
+
}
|
|
140
|
+
| {
|
|
141
|
+
type: "text-end";
|
|
142
|
+
id: string;
|
|
143
|
+
providerMetadata?: JsonObject;
|
|
144
|
+
}
|
|
145
|
+
| {
|
|
146
|
+
type: "reasoning-start";
|
|
147
|
+
id: string;
|
|
148
|
+
providerMetadata?: JsonObject;
|
|
149
|
+
}
|
|
150
|
+
| {
|
|
151
|
+
type: "reasoning-delta";
|
|
152
|
+
id: string;
|
|
153
|
+
delta: string;
|
|
154
|
+
}
|
|
155
|
+
| {
|
|
156
|
+
type: "reasoning-end";
|
|
157
|
+
id: string;
|
|
158
|
+
providerMetadata?: JsonObject;
|
|
159
|
+
}
|
|
160
|
+
| {
|
|
161
|
+
type: "tool-input-start";
|
|
162
|
+
toolCallId: string;
|
|
163
|
+
toolName: string;
|
|
164
|
+
owner?: string;
|
|
165
|
+
providerExecuted?: boolean;
|
|
166
|
+
dynamic?: boolean;
|
|
167
|
+
title?: string;
|
|
168
|
+
}
|
|
169
|
+
| {
|
|
170
|
+
type: "tool-input-delta";
|
|
171
|
+
toolCallId: string;
|
|
172
|
+
delta: string;
|
|
173
|
+
}
|
|
174
|
+
| {
|
|
175
|
+
type: "tool-input-available";
|
|
176
|
+
toolCallId: string;
|
|
177
|
+
toolName: string;
|
|
178
|
+
input: Json;
|
|
179
|
+
owner?: string;
|
|
180
|
+
providerExecuted?: boolean;
|
|
181
|
+
dynamic?: boolean;
|
|
182
|
+
title?: string;
|
|
183
|
+
providerMetadata?: JsonObject;
|
|
184
|
+
}
|
|
185
|
+
| {
|
|
186
|
+
type: "tool-input-error";
|
|
187
|
+
toolCallId: string;
|
|
188
|
+
toolName: string;
|
|
189
|
+
input: Json;
|
|
190
|
+
errorText: string;
|
|
191
|
+
providerExecuted?: boolean;
|
|
192
|
+
dynamic?: boolean;
|
|
193
|
+
title?: string;
|
|
194
|
+
}
|
|
195
|
+
| {
|
|
196
|
+
type: "tool-approval-request";
|
|
197
|
+
toolCallId: string;
|
|
198
|
+
approvalId: string;
|
|
199
|
+
}
|
|
200
|
+
| {
|
|
201
|
+
type: "tool-output-available";
|
|
202
|
+
toolCallId: string;
|
|
203
|
+
output: Json;
|
|
204
|
+
preliminary?: boolean;
|
|
205
|
+
providerExecuted?: boolean;
|
|
206
|
+
}
|
|
207
|
+
| {
|
|
208
|
+
type: "tool-output-error";
|
|
209
|
+
toolCallId: string;
|
|
210
|
+
errorText: string;
|
|
211
|
+
providerExecuted?: boolean;
|
|
212
|
+
}
|
|
213
|
+
| {
|
|
214
|
+
type: "tool-output-denied";
|
|
215
|
+
toolCallId: string;
|
|
216
|
+
}
|
|
217
|
+
| Extract<
|
|
218
|
+
MessagePart,
|
|
219
|
+
{
|
|
220
|
+
type: "file" | "source-url" | "source-document";
|
|
221
|
+
}
|
|
222
|
+
>
|
|
223
|
+
| {
|
|
224
|
+
type: "data";
|
|
225
|
+
name: string;
|
|
226
|
+
id?: string;
|
|
227
|
+
data: Json;
|
|
228
|
+
transient?: boolean;
|
|
229
|
+
} /** Merged into the metadata of the message this response builds. */
|
|
230
|
+
| {
|
|
231
|
+
type: "metadata";
|
|
232
|
+
metadata: JsonObject;
|
|
233
|
+
};
|
|
234
|
+
type TurnOutcome = "completed" | "failed" | "aborted" | "awaiting-input";
|
|
235
|
+
type TurnStatusBase = {
|
|
236
|
+
turnId: string /** Event id of the inbound message that started the turn. */;
|
|
237
|
+
startedBy: string;
|
|
238
|
+
};
|
|
239
|
+
type TurnStatus = TurnStatusBase &
|
|
240
|
+
(
|
|
241
|
+
| {
|
|
242
|
+
status: "queued";
|
|
243
|
+
}
|
|
244
|
+
| {
|
|
245
|
+
status: "running";
|
|
246
|
+
responseId: string /** Saved assistant message the response continues. */;
|
|
247
|
+
extends?: string;
|
|
248
|
+
}
|
|
249
|
+
| {
|
|
250
|
+
status: "settled";
|
|
251
|
+
outcome: Exclude<TurnOutcome, "failed">;
|
|
252
|
+
messageIds: string[];
|
|
253
|
+
}
|
|
254
|
+
| {
|
|
255
|
+
status: "settled";
|
|
256
|
+
outcome: "failed";
|
|
257
|
+
messageIds: string[] /** Shown to participants. Channels sends a generic message when absent. */;
|
|
258
|
+
error?: string;
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
type ConversationSnapshot = {
|
|
262
|
+
messages: TranscriptMessage[] /** Every turn that is queued, running or awaiting input. */;
|
|
263
|
+
turns: TurnStatus[];
|
|
264
|
+
};
|
|
265
|
+
/** Tool a participant's client can run, advertised with an inbound event. */
|
|
266
|
+
type ClientTool = {
|
|
267
|
+
name: string;
|
|
268
|
+
description?: string;
|
|
269
|
+
inputSchema?: JsonObject;
|
|
270
|
+
};
|
|
271
|
+
/** What an interface sends. */
|
|
272
|
+
type InboundEvent = {
|
|
273
|
+
/** Stable across redelivery of the same event. */ eventId: string;
|
|
274
|
+
} & (
|
|
275
|
+
| {
|
|
276
|
+
type: "message" /** Save it under this id. */;
|
|
277
|
+
message: TranscriptMessage & {
|
|
278
|
+
role: "user";
|
|
279
|
+
};
|
|
280
|
+
clientTools?: ClientTool[];
|
|
281
|
+
}
|
|
282
|
+
| {
|
|
283
|
+
type: "tool-result";
|
|
284
|
+
turnId: string;
|
|
285
|
+
toolCallId: string;
|
|
286
|
+
result:
|
|
287
|
+
| {
|
|
288
|
+
ok: true;
|
|
289
|
+
output: Json;
|
|
290
|
+
}
|
|
291
|
+
| {
|
|
292
|
+
ok: false;
|
|
293
|
+
errorText?: string;
|
|
294
|
+
};
|
|
295
|
+
clientTools?: ClientTool[];
|
|
296
|
+
}
|
|
297
|
+
| {
|
|
298
|
+
type: "approval-response";
|
|
299
|
+
turnId: string;
|
|
300
|
+
approvalId: string;
|
|
301
|
+
approved: boolean;
|
|
302
|
+
reason?: string;
|
|
303
|
+
}
|
|
304
|
+
| {
|
|
305
|
+
type: "cancel";
|
|
306
|
+
turnId: string;
|
|
307
|
+
} /** Start a new, empty conversation. The sending surface follows it. */
|
|
308
|
+
| {
|
|
309
|
+
type: "conversation-create";
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Start a new conversation with this one's transcript so far. The sending
|
|
313
|
+
* surface follows it; other surfaces stay.
|
|
314
|
+
*/
|
|
315
|
+
| {
|
|
316
|
+
type: "conversation-fork";
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Start this conversation over, keeping its id. The agent may carry a
|
|
320
|
+
* handoff note into the new context.
|
|
321
|
+
*/
|
|
322
|
+
| {
|
|
323
|
+
type: "conversation-reset";
|
|
324
|
+
handoff?: string;
|
|
325
|
+
}
|
|
326
|
+
);
|
|
327
|
+
/** Inbound events that act on a conversation rather than in it. */
|
|
328
|
+
type ConversationOperation = Extract<
|
|
329
|
+
InboundEvent["type"],
|
|
330
|
+
"conversation-create" | "conversation-fork" | "conversation-reset"
|
|
331
|
+
>;
|
|
332
|
+
/** One of an agent's conversations, as a client lists them. */
|
|
333
|
+
type ConversationInfo = {
|
|
334
|
+
id: string /** The conversation this one was forked from. */;
|
|
335
|
+
parent?: string /** True while a turn is running or queued. */;
|
|
336
|
+
busy: boolean;
|
|
337
|
+
};
|
|
338
|
+
/** What an accepted inbound event produced, for the surface that sent it. */
|
|
339
|
+
type DispatchResult = {
|
|
340
|
+
/** The conversation a create or fork started; the sender follows it. */ conversationId?: string;
|
|
341
|
+
};
|
|
342
|
+
/** Where an inbound event came from, stamped by Channels, never by the client. */
|
|
343
|
+
type EventOrigin = {
|
|
344
|
+
conversationId: string;
|
|
345
|
+
participant: Participant;
|
|
346
|
+
surface: ChannelMessageSurface;
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* Where an inbound event came from, as the gateway knows it: the route that
|
|
350
|
+
* picked the agent, and the conversation when the route named one. Channels
|
|
351
|
+
* resolves an unnamed conversation to the agent's default: the route itself,
|
|
352
|
+
* or a harness's default session.
|
|
353
|
+
*/
|
|
354
|
+
type GatewayOrigin = Omit<EventOrigin, "conversationId"> & {
|
|
355
|
+
route: string;
|
|
356
|
+
conversationId?: string;
|
|
357
|
+
};
|
|
358
|
+
//#endregion
|
|
359
|
+
export {
|
|
360
|
+
ChannelSurfaceObject as C,
|
|
361
|
+
ChannelSurfaceArray as S,
|
|
362
|
+
isChannelMessageSurface as T,
|
|
363
|
+
TranscriptMessage as _,
|
|
364
|
+
DispatchResult as a,
|
|
365
|
+
ChannelMessageSurface as b,
|
|
366
|
+
InboundEvent as c,
|
|
367
|
+
JsonObject as d,
|
|
368
|
+
MessagePart as f,
|
|
369
|
+
ToolState as g,
|
|
370
|
+
ToolPart as h,
|
|
371
|
+
ConversationSnapshot as i,
|
|
372
|
+
Json as l,
|
|
373
|
+
ResponseChunk as m,
|
|
374
|
+
ConversationInfo as n,
|
|
375
|
+
EventOrigin as o,
|
|
376
|
+
Participant as p,
|
|
377
|
+
ConversationOperation as r,
|
|
378
|
+
GatewayOrigin as s,
|
|
379
|
+
ClientTool as t,
|
|
380
|
+
JsonArray as u,
|
|
381
|
+
TurnOutcome as v,
|
|
382
|
+
ChannelSurfaceValue as w,
|
|
383
|
+
ChannelMessageSurfaceInput as x,
|
|
384
|
+
TurnStatus as y
|
|
385
|
+
};
|
|
386
|
+
//# sourceMappingURL=protocol-CukuI73M.d.ts.map
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
//#region src/harness/container/protocol.ts
|
|
2
|
+
/**
|
|
3
|
+
* The wire between `ContainerHarness` (in a Durable Object) and the harness
|
|
4
|
+
* daemon (in the container). Isomorphic and dependency-free: the daemon
|
|
5
|
+
* imports it in Node, the harness in Workers.
|
|
6
|
+
*
|
|
7
|
+
* One WebSocket per session, dialled by the object through
|
|
8
|
+
* `ctx.container.getTcpPort(port)` at `/sessions/<id>`. The daemon speaks
|
|
9
|
+
* first with `hello`; the object answers with `open` (when the daemon does
|
|
10
|
+
* not hold the session yet) and `replay`, then delivers `prompt`s.
|
|
11
|
+
*
|
|
12
|
+
* Everything the daemon produces for a session is a numbered `frame`. The
|
|
13
|
+
* numbers start at 1 for each session in each container, so a frame is
|
|
14
|
+
* addressed by `(runtimeId, seq)`. The daemon keeps frames until they are
|
|
15
|
+
* acknowledged, so an object that lost its socket (evicted, redeployed)
|
|
16
|
+
* replays what it missed from its cursor. A different `runtimeId` in
|
|
17
|
+
* `hello` means a different container: its numbering starts again, and
|
|
18
|
+
* whatever the old container was doing is gone.
|
|
19
|
+
*
|
|
20
|
+
* @experimental The wire may change before it stabilizes. The object and the image are
|
|
21
|
+
* a matched pair; a version mismatch is reported in `hello`.
|
|
22
|
+
*/
|
|
23
|
+
/** Bumped on any incompatible change. */
|
|
24
|
+
const CONTAINER_PROTOCOL_VERSION = 1;
|
|
25
|
+
/** The daemon answers `200` here once it accepts connections. */
|
|
26
|
+
const CONTAINER_HEALTH_PATH = "/healthz";
|
|
27
|
+
/** The session socket: `/sessions/<encoded session id>`. */
|
|
28
|
+
const CONTAINER_SESSION_PATH = "/sessions/";
|
|
29
|
+
/** The shared secret the object passes on every request. */
|
|
30
|
+
const CONTAINER_TOKEN_HEADER = "x-cf-harness-token";
|
|
31
|
+
/** The environment variables the object starts the container with. */
|
|
32
|
+
const CONTAINER_ENV = {
|
|
33
|
+
/** Shared secret for `CONTAINER_TOKEN_HEADER`. */
|
|
34
|
+
token: "CF_HARNESS_TOKEN",
|
|
35
|
+
/** This container's id. Echoed in `hello`. */
|
|
36
|
+
runtimeId: "CF_HARNESS_RUNTIME_ID",
|
|
37
|
+
/** The port the daemon listens on. */
|
|
38
|
+
port: "CF_HARNESS_PORT"
|
|
39
|
+
};
|
|
40
|
+
/** WebSocket close code: a newer connection for the session replaced this one. */
|
|
41
|
+
const CLOSE_REPLACED = 4001;
|
|
42
|
+
/** WebSocket close code: the request was not authorized. */
|
|
43
|
+
const CLOSE_UNAUTHORIZED = 4003;
|
|
44
|
+
/**
|
|
45
|
+
* Most JSON characters the object puts in one `restore` message, and the
|
|
46
|
+
* daemon in one `persist` frame (a single larger entry travels alone).
|
|
47
|
+
* Keeps every message well inside WebSocket message limits.
|
|
48
|
+
*/
|
|
49
|
+
const MAX_CHUNK_CHARS = 256 * 1024;
|
|
50
|
+
function isFields(value) {
|
|
51
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
function isString(value) {
|
|
54
|
+
return typeof value === "string";
|
|
55
|
+
}
|
|
56
|
+
function isCount(value) {
|
|
57
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
58
|
+
}
|
|
59
|
+
function isJson(value) {
|
|
60
|
+
if (value === null) return true;
|
|
61
|
+
switch (typeof value) {
|
|
62
|
+
case "string":
|
|
63
|
+
case "boolean": return true;
|
|
64
|
+
case "number": return Number.isFinite(value);
|
|
65
|
+
case "object":
|
|
66
|
+
if (Array.isArray(value)) return value.every(isJson);
|
|
67
|
+
return Object.values(value).every(isJson);
|
|
68
|
+
default: return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isOutcome(value) {
|
|
72
|
+
if (!isFields(value)) return false;
|
|
73
|
+
if (value.status === "done") return isString(value.text);
|
|
74
|
+
return value.status === "unanswered" && isString(value.reason);
|
|
75
|
+
}
|
|
76
|
+
function isEvent(value) {
|
|
77
|
+
if (!isFields(value) || !isString(value.type) || !isJson(value)) return false;
|
|
78
|
+
switch (value.type) {
|
|
79
|
+
case "text-delta":
|
|
80
|
+
case "reasoning-delta": return isString(value.messageId) && isString(value.delta);
|
|
81
|
+
case "message": return isFields(value.message) && isString(value.message.id) && (value.message.role === "user" || value.message.role === "assistant") && Array.isArray(value.message.parts);
|
|
82
|
+
case "usage": return true;
|
|
83
|
+
case "log": return isString(value.message);
|
|
84
|
+
case "raw": return "value" in value;
|
|
85
|
+
default: return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function isFrame(value) {
|
|
89
|
+
if (!isFields(value)) return false;
|
|
90
|
+
switch (value.kind) {
|
|
91
|
+
case "start": return isString(value.operationId);
|
|
92
|
+
case "event": return (value.operationId === null || isString(value.operationId)) && isEvent(value.event);
|
|
93
|
+
case "persist": return Array.isArray(value.entries) && value.entries.every(isJson);
|
|
94
|
+
case "settle": return isString(value.operationId) && isOutcome(value.outcome);
|
|
95
|
+
default: return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function isDaemonOperation(value) {
|
|
99
|
+
if (!isFields(value) || !isString(value.operationId)) return false;
|
|
100
|
+
if (value.status === "queued" || value.status === "running") return true;
|
|
101
|
+
return value.status === "settled" && isOutcome(value.outcome);
|
|
102
|
+
}
|
|
103
|
+
function isInput(value) {
|
|
104
|
+
if (isString(value)) return true;
|
|
105
|
+
return Array.isArray(value) && value.every((part) => isFields(part) && (part.type === "text" && isString(part.text) || part.type === "image" && isString(part.mediaType) && isString(part.data)));
|
|
106
|
+
}
|
|
107
|
+
function isSettings(value) {
|
|
108
|
+
return isFields(value) && (value.model === void 0 || isString(value.model)) && (value.options === void 0 || isJson(value.options));
|
|
109
|
+
}
|
|
110
|
+
function decode(text) {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(text);
|
|
113
|
+
} catch {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Parse one message from the daemon.
|
|
119
|
+
*
|
|
120
|
+
* @param text - The raw WebSocket message.
|
|
121
|
+
* @returns The message, or `undefined` when it is not one.
|
|
122
|
+
*/
|
|
123
|
+
function parseDaemonMessage(text) {
|
|
124
|
+
const value = decode(text);
|
|
125
|
+
if (!isFields(value)) return void 0;
|
|
126
|
+
switch (value.type) {
|
|
127
|
+
case "hello":
|
|
128
|
+
if (isCount(value.protocol) && isString(value.runtimeId) && isString(value.session) && isFields(value.adapter) && isString(value.adapter.id) && isString(value.adapter.version) && Array.isArray(value.adapter.capabilities) && value.adapter.capabilities.every(isString) && (value.open === null || isCount(value.open)) && isCount(value.lastSeq) && Array.isArray(value.operations) && value.operations.every(isDaemonOperation)) return value;
|
|
129
|
+
return;
|
|
130
|
+
case "frame": return isCount(value.seq) && isFrame(value.frame) ? value : void 0;
|
|
131
|
+
case "caught-up": return isCount(value.lastSeq) ? {
|
|
132
|
+
type: "caught-up",
|
|
133
|
+
lastSeq: value.lastSeq
|
|
134
|
+
} : void 0;
|
|
135
|
+
case "error": return isString(value.message) ? {
|
|
136
|
+
type: "error",
|
|
137
|
+
message: value.message
|
|
138
|
+
} : void 0;
|
|
139
|
+
default: return;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Parse one message from the object.
|
|
144
|
+
*
|
|
145
|
+
* @param text - The raw WebSocket message.
|
|
146
|
+
* @returns The message, or `undefined` when it is not one.
|
|
147
|
+
*/
|
|
148
|
+
function parseHostMessage(text) {
|
|
149
|
+
const value = decode(text);
|
|
150
|
+
if (!isFields(value)) return void 0;
|
|
151
|
+
switch (value.type) {
|
|
152
|
+
case "restore": return isCount(value.generation) && Array.isArray(value.entries) && value.entries.every(isJson) ? {
|
|
153
|
+
type: "restore",
|
|
154
|
+
generation: value.generation,
|
|
155
|
+
entries: value.entries
|
|
156
|
+
} : void 0;
|
|
157
|
+
case "open": return isCount(value.generation) && isSettings(value.settings) && Array.isArray(value.restore) && value.restore.every(isJson) ? {
|
|
158
|
+
type: "open",
|
|
159
|
+
generation: value.generation,
|
|
160
|
+
settings: value.settings,
|
|
161
|
+
restore: value.restore
|
|
162
|
+
} : void 0;
|
|
163
|
+
case "replay": return isCount(value.after) ? {
|
|
164
|
+
type: "replay",
|
|
165
|
+
after: value.after
|
|
166
|
+
} : void 0;
|
|
167
|
+
case "prompt": return isString(value.operationId) && isInput(value.input) && (value.whenBusy === "followUp" || value.whenBusy === "steer") ? {
|
|
168
|
+
type: "prompt",
|
|
169
|
+
operationId: value.operationId,
|
|
170
|
+
input: value.input,
|
|
171
|
+
whenBusy: value.whenBusy
|
|
172
|
+
} : void 0;
|
|
173
|
+
case "abort":
|
|
174
|
+
if (value.operationId === void 0) return { type: "abort" };
|
|
175
|
+
return isString(value.operationId) ? {
|
|
176
|
+
type: "abort",
|
|
177
|
+
operationId: value.operationId
|
|
178
|
+
} : void 0;
|
|
179
|
+
case "configure": return isSettings(value.settings) ? {
|
|
180
|
+
type: "configure",
|
|
181
|
+
settings: value.settings
|
|
182
|
+
} : void 0;
|
|
183
|
+
case "ack": return isCount(value.seq) ? {
|
|
184
|
+
type: "ack",
|
|
185
|
+
seq: value.seq
|
|
186
|
+
} : void 0;
|
|
187
|
+
default: return;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* The text of an input, with image parts left out.
|
|
192
|
+
*
|
|
193
|
+
* @param input - A prompt's input.
|
|
194
|
+
* @returns Its text.
|
|
195
|
+
*/
|
|
196
|
+
function inputText(input) {
|
|
197
|
+
if (typeof input === "string") return input;
|
|
198
|
+
return input.map((part) => part.type === "text" ? part.text : "").join("\n");
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Split entries into groups whose JSON stays under `MAX_CHUNK_CHARS`. An
|
|
202
|
+
* entry larger than that is a group of its own.
|
|
203
|
+
*
|
|
204
|
+
* @param entries - The entries, in order.
|
|
205
|
+
* @returns The groups, in order. Empty for no entries.
|
|
206
|
+
*/
|
|
207
|
+
function chunkEntries(entries) {
|
|
208
|
+
const groups = [];
|
|
209
|
+
let group = [];
|
|
210
|
+
let size = 0;
|
|
211
|
+
for (const entry of entries) {
|
|
212
|
+
const length = JSON.stringify(entry).length;
|
|
213
|
+
if (group.length > 0 && size + length > 262144) {
|
|
214
|
+
groups.push(group);
|
|
215
|
+
group = [];
|
|
216
|
+
size = 0;
|
|
217
|
+
}
|
|
218
|
+
group.push(entry);
|
|
219
|
+
size += length;
|
|
220
|
+
}
|
|
221
|
+
if (group.length > 0) groups.push(group);
|
|
222
|
+
return groups;
|
|
223
|
+
}
|
|
224
|
+
//#endregion
|
|
225
|
+
export { CONTAINER_PROTOCOL_VERSION as a, MAX_CHUNK_CHARS as c, parseDaemonMessage as d, parseHostMessage as f, CONTAINER_HEALTH_PATH as i, chunkEntries as l, CLOSE_UNAUTHORIZED as n, CONTAINER_SESSION_PATH as o, CONTAINER_ENV as r, CONTAINER_TOKEN_HEADER as s, CLOSE_REPLACED as t, inputText as u };
|
|
226
|
+
|
|
227
|
+
//# sourceMappingURL=protocol-cOklVBBD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol-cOklVBBD.js","names":[],"sources":["../src/harness/container/protocol.ts"],"sourcesContent":["/**\n * The wire between `ContainerHarness` (in a Durable Object) and the harness\n * daemon (in the container). Isomorphic and dependency-free: the daemon\n * imports it in Node, the harness in Workers.\n *\n * One WebSocket per session, dialled by the object through\n * `ctx.container.getTcpPort(port)` at `/sessions/<id>`. The daemon speaks\n * first with `hello`; the object answers with `open` (when the daemon does\n * not hold the session yet) and `replay`, then delivers `prompt`s.\n *\n * Everything the daemon produces for a session is a numbered `frame`. The\n * numbers start at 1 for each session in each container, so a frame is\n * addressed by `(runtimeId, seq)`. The daemon keeps frames until they are\n * acknowledged, so an object that lost its socket (evicted, redeployed)\n * replays what it missed from its cursor. A different `runtimeId` in\n * `hello` means a different container: its numbering starts again, and\n * whatever the old container was doing is gone.\n *\n * @experimental The wire may change before it stabilizes. The object and the image are\n * a matched pair; a version mismatch is reported in `hello`.\n */\n\n/** Bumped on any incompatible change. */\nexport const CONTAINER_PROTOCOL_VERSION = 1;\n\n/** The daemon answers `200` here once it accepts connections. */\nexport const CONTAINER_HEALTH_PATH = \"/healthz\";\n\n/** The session socket: `/sessions/<encoded session id>`. */\nexport const CONTAINER_SESSION_PATH = \"/sessions/\";\n\n/** The shared secret the object passes on every request. */\nexport const CONTAINER_TOKEN_HEADER = \"x-cf-harness-token\";\n\n/** The environment variables the object starts the container with. */\nexport const CONTAINER_ENV = {\n /** Shared secret for `CONTAINER_TOKEN_HEADER`. */\n token: \"CF_HARNESS_TOKEN\",\n /** This container's id. Echoed in `hello`. */\n runtimeId: \"CF_HARNESS_RUNTIME_ID\",\n /** The port the daemon listens on. */\n port: \"CF_HARNESS_PORT\"\n} as const;\n\n/** WebSocket close code: a newer connection for the session replaced this one. */\nexport const CLOSE_REPLACED = 4001;\n\n/** WebSocket close code: the request was not authorized. */\nexport const CLOSE_UNAUTHORIZED = 4003;\n\n/** A JSON value on the wire. */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | readonly JsonValue[]\n | { readonly [key: string]: JsonValue };\n\n/** One part of a prompt. */\nexport type ContainerInputPart =\n | { readonly type: \"text\"; readonly text: string }\n | {\n readonly type: \"image\";\n /** IANA media type, such as `image/png`. */\n readonly mediaType: string;\n /** Base64 bytes. */\n readonly data: string;\n };\n\n/** What a prompt carries: plain text, or parts. */\nexport type ContainerInput = string | readonly ContainerInputPart[];\n\n/** What a submission does when the session is already running. */\nexport type ContainerWhenBusy = \"followUp\" | \"steer\";\n\n/**\n * Per-session settings the object sends the adapter. `model` is the\n * adapter's own model name; `options` is opaque to everything but the\n * adapter.\n */\nexport type ContainerSettings = {\n readonly model?: string;\n readonly options?: JsonValue;\n};\n\n/** One part of a transcript message. */\nexport type ContainerPart =\n | { readonly type: \"text\"; readonly text: string }\n | { readonly type: \"reasoning\"; readonly text: string }\n | {\n readonly type: \"image\";\n readonly mediaType: string;\n readonly data: string;\n }\n | {\n readonly type: \"tool\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly input: JsonValue;\n readonly state: \"running\" | \"done\" | \"error\";\n readonly output?: JsonValue;\n };\n\n/**\n * A transcript message, in the one format every container adapter\n * produces. An adapter emits a message again, under the same id, to update\n * it (a tool result arriving, for example).\n */\nexport type ContainerMessage = {\n readonly id: string;\n readonly role: \"user\" | \"assistant\";\n readonly parts: readonly ContainerPart[];\n /** The operation the message belongs to. */\n readonly operationId?: string;\n readonly createdAt: number;\n};\n\n/** What an adapter reports while it runs. */\nexport type ContainerEvent =\n /** Live text for an assistant message that is still being written. */\n | {\n readonly type: \"text-delta\";\n readonly messageId: string;\n readonly delta: string;\n }\n /** Live reasoning for an assistant message that is still being written. */\n | {\n readonly type: \"reasoning-delta\";\n readonly messageId: string;\n readonly delta: string;\n }\n /** A finished or updated transcript message. Stored. */\n | { readonly type: \"message\"; readonly message: ContainerMessage }\n /** Token and cost figures the adapter reports, as the adapter counts them. */\n | {\n readonly type: \"usage\";\n readonly inputTokens?: number;\n readonly outputTokens?: number;\n readonly costUsd?: number;\n }\n /** A diagnostic line. */\n | {\n readonly type: \"log\";\n readonly level: \"info\" | \"warn\" | \"error\";\n readonly message: string;\n }\n /** Anything adapter-specific, passed through untouched. */\n | { readonly type: \"raw\"; readonly value: JsonValue };\n\n/** How an operation ended, as the daemon reports it. */\nexport type ContainerOutcome =\n | { readonly status: \"done\"; readonly text: string }\n | { readonly status: \"unanswered\"; readonly reason: string };\n\n/** What the daemon knows about one operation it was given. */\nexport type DaemonOperation =\n | {\n readonly operationId: string;\n readonly status: \"queued\" | \"running\";\n }\n | {\n readonly operationId: string;\n readonly status: \"settled\";\n readonly outcome: ContainerOutcome;\n };\n\n/** One numbered thing the daemon produced for a session. */\nexport type DaemonFrame =\n | { readonly kind: \"start\"; readonly operationId: string }\n | {\n readonly kind: \"event\";\n readonly operationId: string | null;\n readonly event: ContainerEvent;\n }\n /**\n * Adapter resume state to keep. The object stores these entries in order\n * and hands all of them back in `open` on a new container.\n */\n | { readonly kind: \"persist\"; readonly entries: readonly JsonValue[] }\n | {\n readonly kind: \"settle\";\n readonly operationId: string;\n readonly outcome: ContainerOutcome;\n };\n\n/** The adapter running in the container. */\nexport type AdapterInfo = {\n readonly id: string;\n readonly version: string;\n readonly capabilities: readonly string[];\n};\n\n/** Daemon → object. */\nexport type DaemonMessage =\n | {\n readonly type: \"hello\";\n readonly protocol: number;\n readonly runtimeId: string;\n readonly session: string;\n readonly adapter: AdapterInfo;\n /** The generation of the open adapter session, or null if none is open. */\n readonly open: number | null;\n /** The newest frame number for this session in this container. */\n readonly lastSeq: number;\n /** Every operation this container was given for the session. */\n readonly operations: readonly DaemonOperation[];\n }\n | {\n readonly type: \"frame\";\n readonly seq: number;\n readonly frame: DaemonFrame;\n }\n /** Every kept frame after the `replay` cursor has been sent. */\n | { readonly type: \"caught-up\"; readonly lastSeq: number }\n | { readonly type: \"error\"; readonly message: string };\n\n/**\n * Most JSON characters the object puts in one `restore` message, and the\n * daemon in one `persist` frame (a single larger entry travels alone).\n * Keeps every message well inside WebSocket message limits.\n */\nexport const MAX_CHUNK_CHARS = 256 * 1024;\n\n/** Object → daemon. */\nexport type HostMessage =\n /**\n * Part of the resume state for the next `open` of `generation`. Sent\n * before that `open`, in order, so no single message grows with the\n * session's history.\n */\n | {\n readonly type: \"restore\";\n readonly generation: number;\n readonly entries: readonly JsonValue[];\n }\n /**\n * Open the adapter session. Ignored when the same generation is already\n * open; a different generation closes the open one first.\n */\n | {\n readonly type: \"open\";\n readonly generation: number;\n readonly settings: ContainerSettings;\n /**\n * The last of the entries the adapter persisted for this session,\n * after any sent in `restore` messages for this generation.\n */\n readonly restore: readonly JsonValue[];\n }\n /** Send every kept frame after `after`, then live frames. */\n | { readonly type: \"replay\"; readonly after: number }\n /** Queue an operation. Idempotent on `operationId`. */\n | {\n readonly type: \"prompt\";\n readonly operationId: string;\n readonly input: ContainerInput;\n readonly whenBusy: ContainerWhenBusy;\n }\n /** Stop one operation, or every operation of the session. */\n | { readonly type: \"abort\"; readonly operationId?: string }\n | { readonly type: \"configure\"; readonly settings: ContainerSettings }\n /** Frames up to `seq` are stored; the daemon may forget them. */\n | { readonly type: \"ack\"; readonly seq: number };\n\n// ── Parsing ─────────────────────────────────────────────────────────────────\n//\n// Frames cross a process boundary, so each side parses what it receives.\n// The parsers check the envelope and the fields the receiver acts on;\n// payloads that are opaque to the receiver (events, persisted entries) are\n// passed through as JSON.\n\ntype Fields = { readonly [key: string]: unknown };\n\nfunction isFields(value: unknown): value is Fields {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\nfunction isCount(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction isJson(value: unknown): value is JsonValue {\n if (value === null) return true;\n switch (typeof value) {\n case \"string\":\n case \"boolean\":\n return true;\n case \"number\":\n return Number.isFinite(value);\n case \"object\":\n if (Array.isArray(value)) return value.every(isJson);\n return Object.values(value).every(isJson);\n default:\n return false;\n }\n}\n\nfunction isOutcome(value: unknown): value is ContainerOutcome {\n if (!isFields(value)) return false;\n if (value.status === \"done\") return isString(value.text);\n return value.status === \"unanswered\" && isString(value.reason);\n}\n\nfunction isEvent(value: unknown): value is ContainerEvent {\n if (!isFields(value) || !isString(value.type) || !isJson(value)) return false;\n switch (value.type) {\n case \"text-delta\":\n case \"reasoning-delta\":\n return isString(value.messageId) && isString(value.delta);\n case \"message\":\n return (\n isFields(value.message) &&\n isString(value.message.id) &&\n (value.message.role === \"user\" || value.message.role === \"assistant\") &&\n Array.isArray(value.message.parts)\n );\n case \"usage\":\n return true;\n case \"log\":\n return isString(value.message);\n case \"raw\":\n return \"value\" in value;\n default:\n return false;\n }\n}\n\nfunction isFrame(value: unknown): value is DaemonFrame {\n if (!isFields(value)) return false;\n switch (value.kind) {\n case \"start\":\n return isString(value.operationId);\n case \"event\":\n return (\n (value.operationId === null || isString(value.operationId)) &&\n isEvent(value.event)\n );\n case \"persist\":\n return Array.isArray(value.entries) && value.entries.every(isJson);\n case \"settle\":\n return isString(value.operationId) && isOutcome(value.outcome);\n default:\n return false;\n }\n}\n\nfunction isDaemonOperation(value: unknown): value is DaemonOperation {\n if (!isFields(value) || !isString(value.operationId)) return false;\n if (value.status === \"queued\" || value.status === \"running\") return true;\n return value.status === \"settled\" && isOutcome(value.outcome);\n}\n\nfunction isInput(value: unknown): value is ContainerInput {\n if (isString(value)) return true;\n return (\n Array.isArray(value) &&\n value.every(\n (part) =>\n isFields(part) &&\n ((part.type === \"text\" && isString(part.text)) ||\n (part.type === \"image\" &&\n isString(part.mediaType) &&\n isString(part.data)))\n )\n );\n}\n\nfunction isSettings(value: unknown): value is ContainerSettings {\n return (\n isFields(value) &&\n (value.model === undefined || isString(value.model)) &&\n (value.options === undefined || isJson(value.options))\n );\n}\n\nfunction decode(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Parse one message from the daemon.\n *\n * @param text - The raw WebSocket message.\n * @returns The message, or `undefined` when it is not one.\n */\nexport function parseDaemonMessage(text: string): DaemonMessage | undefined {\n const value = decode(text);\n if (!isFields(value)) return undefined;\n switch (value.type) {\n case \"hello\":\n if (\n isCount(value.protocol) &&\n isString(value.runtimeId) &&\n isString(value.session) &&\n isFields(value.adapter) &&\n isString(value.adapter.id) &&\n isString(value.adapter.version) &&\n Array.isArray(value.adapter.capabilities) &&\n value.adapter.capabilities.every(isString) &&\n (value.open === null || isCount(value.open)) &&\n isCount(value.lastSeq) &&\n Array.isArray(value.operations) &&\n value.operations.every(isDaemonOperation)\n ) {\n // SAFETY: every field the type names was checked above.\n return value as DaemonMessage;\n }\n return undefined;\n case \"frame\":\n // SAFETY: seq and frame were checked; the type is exactly these fields.\n return isCount(value.seq) && isFrame(value.frame)\n ? (value as DaemonMessage)\n : undefined;\n case \"caught-up\":\n return isCount(value.lastSeq)\n ? { type: \"caught-up\", lastSeq: value.lastSeq }\n : undefined;\n case \"error\":\n return isString(value.message)\n ? { type: \"error\", message: value.message }\n : undefined;\n default:\n return undefined;\n }\n}\n\n/**\n * Parse one message from the object.\n *\n * @param text - The raw WebSocket message.\n * @returns The message, or `undefined` when it is not one.\n */\nexport function parseHostMessage(text: string): HostMessage | undefined {\n const value = decode(text);\n if (!isFields(value)) return undefined;\n switch (value.type) {\n case \"restore\":\n return isCount(value.generation) &&\n Array.isArray(value.entries) &&\n value.entries.every(isJson)\n ? {\n type: \"restore\",\n generation: value.generation,\n entries: value.entries\n }\n : undefined;\n case \"open\":\n return isCount(value.generation) &&\n isSettings(value.settings) &&\n Array.isArray(value.restore) &&\n value.restore.every(isJson)\n ? {\n type: \"open\",\n generation: value.generation,\n settings: value.settings,\n restore: value.restore\n }\n : undefined;\n case \"replay\":\n return isCount(value.after)\n ? { type: \"replay\", after: value.after }\n : undefined;\n case \"prompt\":\n return isString(value.operationId) &&\n isInput(value.input) &&\n (value.whenBusy === \"followUp\" || value.whenBusy === \"steer\")\n ? {\n type: \"prompt\",\n operationId: value.operationId,\n input: value.input,\n whenBusy: value.whenBusy\n }\n : undefined;\n case \"abort\":\n if (value.operationId === undefined) return { type: \"abort\" };\n return isString(value.operationId)\n ? { type: \"abort\", operationId: value.operationId }\n : undefined;\n case \"configure\":\n return isSettings(value.settings)\n ? { type: \"configure\", settings: value.settings }\n : undefined;\n case \"ack\":\n return isCount(value.seq) ? { type: \"ack\", seq: value.seq } : undefined;\n default:\n return undefined;\n }\n}\n\n/**\n * The text of an input, with image parts left out.\n *\n * @param input - A prompt's input.\n * @returns Its text.\n */\nexport function inputText(input: ContainerInput): string {\n if (typeof input === \"string\") return input;\n return input\n .map((part) => (part.type === \"text\" ? part.text : \"\"))\n .join(\"\\n\");\n}\n\n/**\n * Split entries into groups whose JSON stays under `MAX_CHUNK_CHARS`. An\n * entry larger than that is a group of its own.\n *\n * @param entries - The entries, in order.\n * @returns The groups, in order. Empty for no entries.\n */\nexport function chunkEntries(entries: readonly JsonValue[]): JsonValue[][] {\n const groups: JsonValue[][] = [];\n let group: JsonValue[] = [];\n let size = 0;\n for (const entry of entries) {\n const length = JSON.stringify(entry).length;\n if (group.length > 0 && size + length > MAX_CHUNK_CHARS) {\n groups.push(group);\n group = [];\n size = 0;\n }\n group.push(entry);\n size += length;\n }\n if (group.length > 0) groups.push(group);\n return groups;\n}\n"],"mappings":"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"}
|