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
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
k as ChannelIngress,
|
|
2
|
+
D as ChannelIngress,
|
|
3
|
+
c as ChannelRoute,
|
|
5
4
|
n as Channel,
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
o as ChannelMessage,
|
|
6
|
+
s as ChannelParticipant
|
|
7
|
+
} from "../../../channel-Bak_6zDP.js";
|
|
8
|
+
import { b as ChannelMessageSurface } from "../../../protocol-CukuI73M.js";
|
|
8
9
|
|
|
9
|
-
//#region src/channels/
|
|
10
|
+
//#region src/experimental/channels/telegram/index.d.ts
|
|
10
11
|
type TelegramUser = {
|
|
11
12
|
id: number;
|
|
12
13
|
is_bot: boolean;
|
|
@@ -65,7 +66,16 @@ type TelegramChannelOptions = {
|
|
|
65
66
|
* Smallest gap between `sendMessageDraft` previews. Snapshots produced
|
|
66
67
|
* inside one interval are replaced rather than sent. @default 500
|
|
67
68
|
*/
|
|
68
|
-
streamIntervalMs?: number
|
|
69
|
+
streamIntervalMs?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Who sent a verified Telegram update, such as your user linked to
|
|
72
|
+
* `event.actor`. Return null to drop the update. Required with `webhook`.
|
|
73
|
+
*/
|
|
74
|
+
participant?: ChannelParticipant<TelegramUpdate>;
|
|
75
|
+
/**
|
|
76
|
+
* Pick the agent object an update reaches. Default: a room of the
|
|
77
|
+
* participant's own, so a group chat is not shared by accident.
|
|
78
|
+
*/
|
|
69
79
|
route?: ChannelRoute<TelegramUpdate> /** Add secret-verified Telegram webhook ingress to the returned Channel. */;
|
|
70
80
|
webhook?: {
|
|
71
81
|
secretToken: string /** Exact webhook pathname accepted by this ingress. @default "/webhooks/telegram" */;
|
|
@@ -87,7 +97,7 @@ type TelegramWebhookOptions = {
|
|
|
87
97
|
declare function telegramWebhook(
|
|
88
98
|
options: TelegramWebhookOptions
|
|
89
99
|
): ChannelIngress<TelegramUpdate>;
|
|
90
|
-
/** Create a configured Telegram
|
|
100
|
+
/** Create a configured Telegram ingress Channel. */
|
|
91
101
|
declare function telegram(
|
|
92
102
|
options: TelegramChannelOptions
|
|
93
103
|
): Channel<TelegramUpdate>;
|
|
@@ -103,4 +113,4 @@ export {
|
|
|
103
113
|
telegram,
|
|
104
114
|
telegramWebhook
|
|
105
115
|
};
|
|
106
|
-
//# sourceMappingURL=
|
|
116
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { t as emptyIngressResponse } from "../../../internal-kmw70xwR.js";
|
|
2
|
+
import { t as matchesPath } from "../../../ingress-EFbrS547.js";
|
|
3
|
+
//#region src/experimental/channels/telegram/index.ts
|
|
4
|
+
const DEFAULT_TELEGRAM_WEBHOOK_PATH = "/webhooks/telegram";
|
|
5
|
+
const INTERACTION_FOOTER = /\n\nReply YES to approve or NO to reject\.\n\n\[channel-interaction:v1:([A-Za-z0-9_-]+)\]$/;
|
|
6
|
+
function channelIdentity(chatId) {
|
|
7
|
+
return `telegram:chat:${chatId}`;
|
|
8
|
+
}
|
|
9
|
+
function userIdentity(userId) {
|
|
10
|
+
return `telegram:user:${userId}`;
|
|
11
|
+
}
|
|
12
|
+
function messageIdentity(chatId, messageId) {
|
|
13
|
+
return `${channelIdentity(chatId)}:message:${messageId}`;
|
|
14
|
+
}
|
|
15
|
+
function updateIdentity(chatId, updateId) {
|
|
16
|
+
return `${channelIdentity(chatId)}:update:${updateId}`;
|
|
17
|
+
}
|
|
18
|
+
function decodeApprovalId(value) {
|
|
19
|
+
try {
|
|
20
|
+
const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
21
|
+
const padding = "=".repeat((4 - base64.length % 4) % 4);
|
|
22
|
+
const binary = atob(base64 + padding);
|
|
23
|
+
const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
24
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes) || void 0;
|
|
25
|
+
} catch {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function asTelegramMessage(value) {
|
|
30
|
+
return value !== null && typeof value === "object" ? value : void 0;
|
|
31
|
+
}
|
|
32
|
+
function telegramActor(message) {
|
|
33
|
+
const sender = message.from;
|
|
34
|
+
if (sender) {
|
|
35
|
+
const fullName = [sender.first_name, sender.last_name].filter(Boolean).join(" ");
|
|
36
|
+
return {
|
|
37
|
+
id: userIdentity(sender.id),
|
|
38
|
+
identity: { subject: `user:${sender.id}` },
|
|
39
|
+
...sender.username && { username: sender.username },
|
|
40
|
+
...fullName && { fullName },
|
|
41
|
+
isBot: sender.is_bot
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const senderChat = message.sender_chat;
|
|
45
|
+
if (!senderChat) return void 0;
|
|
46
|
+
const fullName = senderChat.title ?? [senderChat.first_name, senderChat.last_name].filter(Boolean).join(" ");
|
|
47
|
+
return {
|
|
48
|
+
id: channelIdentity(senderChat.id),
|
|
49
|
+
identity: { subject: `chat:${senderChat.id}` },
|
|
50
|
+
...senderChat.username && { username: senderChat.username },
|
|
51
|
+
...fullName && { fullName },
|
|
52
|
+
isBot: "unknown"
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function chatLabel(chat) {
|
|
56
|
+
return `Telegram · ${(chat.title ?? (chat.username ? `@${chat.username}` : void 0) ?? [chat.first_name, chat.last_name].filter(Boolean).join(" ") ?? String(chat.id)) || chat.id}`;
|
|
57
|
+
}
|
|
58
|
+
function eventContext(message, eventId, botUserId) {
|
|
59
|
+
const actor = telegramActor(message);
|
|
60
|
+
const channelId = channelIdentity(message.chat.id);
|
|
61
|
+
return {
|
|
62
|
+
eventId,
|
|
63
|
+
thread: {
|
|
64
|
+
id: typeof message.message_thread_id === "number" ? `${channelId}:topic:${message.message_thread_id}` : channelId,
|
|
65
|
+
isDirectMessage: message.chat.type === "private" ? true : message.chat.type === "group" || message.chat.type === "supergroup" || message.chat.type === "channel" ? false : "unknown"
|
|
66
|
+
},
|
|
67
|
+
replySurface: {
|
|
68
|
+
version: 1,
|
|
69
|
+
address: {
|
|
70
|
+
chatId: String(message.chat.id),
|
|
71
|
+
...botUserId && { botUserId },
|
|
72
|
+
...typeof message.message_thread_id === "number" && { messageThreadId: message.message_thread_id },
|
|
73
|
+
replyToMessageId: message.message_id
|
|
74
|
+
},
|
|
75
|
+
label: chatLabel(message.chat)
|
|
76
|
+
},
|
|
77
|
+
...actor && { actor }
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function telegramTimestamp(value) {
|
|
81
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
|
|
82
|
+
const date = /* @__PURE__ */ new Date(value * 1e3);
|
|
83
|
+
return Number.isFinite(date.getTime()) ? date.toISOString() : void 0;
|
|
84
|
+
}
|
|
85
|
+
function normalizedMessage(message, eventId, edited, botUserId) {
|
|
86
|
+
const reply = asTelegramMessage(message.reply_to_message);
|
|
87
|
+
const sentAt = telegramTimestamp(message.date);
|
|
88
|
+
const editedAt = telegramTimestamp(message.edit_date);
|
|
89
|
+
return {
|
|
90
|
+
type: "message",
|
|
91
|
+
...eventContext(message, eventId, botUserId),
|
|
92
|
+
message: {
|
|
93
|
+
id: messageIdentity(message.chat.id, message.message_id),
|
|
94
|
+
text: message.text,
|
|
95
|
+
...typeof reply?.message_id === "number" && { reply: {
|
|
96
|
+
id: messageIdentity(message.chat.id, reply.message_id),
|
|
97
|
+
...typeof reply.text === "string" && { text: reply.text }
|
|
98
|
+
} },
|
|
99
|
+
...(sentAt || edited || editedAt) && { metadata: {
|
|
100
|
+
...sentAt && { sentAt },
|
|
101
|
+
...edited && { edited: true },
|
|
102
|
+
...editedAt && { editedAt }
|
|
103
|
+
} }
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function approvalResponse(message, eventId, botUserId) {
|
|
108
|
+
if (botUserId === void 0) return void 0;
|
|
109
|
+
if (message.text !== "YES" && message.text !== "NO") return void 0;
|
|
110
|
+
const reply = asTelegramMessage(message.reply_to_message);
|
|
111
|
+
if (typeof reply?.message_id !== "number") return void 0;
|
|
112
|
+
const author = reply.from;
|
|
113
|
+
if (author?.is_bot !== true || author.id !== botUserId) return void 0;
|
|
114
|
+
const encodedApprovalId = typeof reply.text === "string" ? reply.text.match(INTERACTION_FOOTER)?.[1] : void 0;
|
|
115
|
+
const approvalId = encodedApprovalId ? decodeApprovalId(encodedApprovalId) : void 0;
|
|
116
|
+
if (!approvalId) return void 0;
|
|
117
|
+
return {
|
|
118
|
+
type: "approval-response",
|
|
119
|
+
...eventContext(message, eventId, botUserId),
|
|
120
|
+
approvalId,
|
|
121
|
+
decision: message.text === "YES" ? "approve" : "reject",
|
|
122
|
+
reference: messageIdentity(message.chat.id, message.message_id)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function inboundEvent(update, botUserId) {
|
|
126
|
+
const edited = update.edited_message !== void 0;
|
|
127
|
+
const message = asTelegramMessage(edited ? update.edited_message : update.message);
|
|
128
|
+
if (typeof update.update_id !== "number" || typeof message?.message_id !== "number" || typeof message.text !== "string" || typeof message.chat?.id !== "number") return;
|
|
129
|
+
const eventId = updateIdentity(message.chat.id, update.update_id);
|
|
130
|
+
return approvalResponse(message, eventId, botUserId) ?? normalizedMessage(message, eventId, edited, botUserId);
|
|
131
|
+
}
|
|
132
|
+
/** Recover this bot's numeric user id from its BotFather token prefix. */
|
|
133
|
+
function telegramBotUserId(botToken) {
|
|
134
|
+
const prefix = botToken.match(/^(\d+):/)?.[1];
|
|
135
|
+
if (!prefix) return void 0;
|
|
136
|
+
const botUserId = Number(prefix);
|
|
137
|
+
return Number.isSafeInteger(botUserId) && botUserId > 0 ? botUserId : void 0;
|
|
138
|
+
}
|
|
139
|
+
/** Create dependency-free Telegram webhook ingress for a destination chat. */
|
|
140
|
+
function telegramWebhook(options) {
|
|
141
|
+
if (!options.secretToken.trim()) throw new Error("secretToken is required to create Telegram webhook ingress");
|
|
142
|
+
if (options.botUserId !== void 0 && (!Number.isSafeInteger(options.botUserId) || options.botUserId <= 0)) throw new Error("botUserId must be a positive Telegram user id");
|
|
143
|
+
const botUserId = options.botUserId;
|
|
144
|
+
const path = options.path ?? DEFAULT_TELEGRAM_WEBHOOK_PATH;
|
|
145
|
+
return { async receive(request) {
|
|
146
|
+
if (!matchesPath(request, path)) return null;
|
|
147
|
+
if (request.method !== "POST") return emptyIngressResponse(405);
|
|
148
|
+
if (request.headers.get("x-telegram-bot-api-secret-token") !== options.secretToken) return emptyIngressResponse(401);
|
|
149
|
+
let update;
|
|
150
|
+
try {
|
|
151
|
+
update = await request.json();
|
|
152
|
+
} catch {
|
|
153
|
+
return emptyIngressResponse(400);
|
|
154
|
+
}
|
|
155
|
+
if (update === null || typeof update !== "object") return emptyIngressResponse(400);
|
|
156
|
+
const raw = update;
|
|
157
|
+
const event = inboundEvent(raw, botUserId);
|
|
158
|
+
return {
|
|
159
|
+
events: event ? [{
|
|
160
|
+
event,
|
|
161
|
+
raw
|
|
162
|
+
}] : [],
|
|
163
|
+
response: new Response(null, { status: 200 })
|
|
164
|
+
};
|
|
165
|
+
} };
|
|
166
|
+
}
|
|
167
|
+
/** Create a configured Telegram ingress Channel. */
|
|
168
|
+
function telegram(options) {
|
|
169
|
+
if (!options.botToken.trim()) throw new Error("botToken is required to create a Telegram channel");
|
|
170
|
+
if (options.webhook && !options.participant) throw new Error("participant is required with a Telegram webhook");
|
|
171
|
+
const botUserId = telegramBotUserId(options.botToken);
|
|
172
|
+
const ingress = options.webhook ? telegramWebhook({
|
|
173
|
+
...options.webhook,
|
|
174
|
+
botUserId
|
|
175
|
+
}) : void 0;
|
|
176
|
+
return {
|
|
177
|
+
...options.participant && { participant: options.participant },
|
|
178
|
+
...options.route && { route: options.route },
|
|
179
|
+
...ingress && { ingress },
|
|
180
|
+
contactSurface(identity) {
|
|
181
|
+
if ((identity.scope ?? "default") !== "default") return null;
|
|
182
|
+
const match = identity.subject.match(/^(user|chat):(-?\d+)$/);
|
|
183
|
+
if (!match) return null;
|
|
184
|
+
return {
|
|
185
|
+
version: 1,
|
|
186
|
+
address: {
|
|
187
|
+
chatId: match[2],
|
|
188
|
+
...botUserId && { botUserId }
|
|
189
|
+
},
|
|
190
|
+
label: `Telegram · ${match[1]} ${match[2]}`
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
export { telegram, telegramWebhook };
|
|
197
|
+
|
|
198
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/experimental/channels/telegram/index.ts"],"sourcesContent":["import type {\n Channel,\n ChannelMessage,\n ChannelParticipant,\n ChannelRoute\n} from \"../channel\";\nimport type { ChannelIdentity } from \"../identity\";\nimport type { ChannelMessageSurface } from \"../surface\";\nimport {\n matchesPath,\n type ChannelApprovalResponseInput,\n type ChannelEventContextInput,\n type ChannelInboundMessageInput,\n type ChannelIngress,\n type ChannelIngressEventInput\n} from \"../ingress\";\nimport { emptyIngressResponse } from \"../internal\";\n\nexport type TelegramUser = {\n id: number;\n is_bot: boolean;\n first_name: string;\n last_name?: string;\n username?: string;\n [key: string]: unknown;\n};\n\nexport type TelegramChat = {\n id: number;\n type: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n title?: string;\n username?: string;\n first_name?: string;\n last_name?: string;\n [key: string]: unknown;\n};\n\nexport type TelegramMessage = {\n message_id: number;\n date: number;\n chat: TelegramChat;\n message_thread_id?: number;\n from?: TelegramUser;\n sender_chat?: TelegramChat;\n text?: string;\n edit_date?: number;\n reply_to_message?: TelegramMessage;\n [key: string]: unknown;\n};\n\n/** Authenticated JSON body delivered by a Telegram webhook. */\nexport type TelegramUpdate = {\n update_id: number;\n message?: TelegramMessage;\n edited_message?: TelegramMessage;\n [key: string]: unknown;\n};\n\nexport type TelegramMessageSurface = ChannelMessageSurface<\n string,\n {\n chatId: string;\n botUserId?: number;\n messageThreadId?: number;\n replyToMessageId?: number;\n }\n>;\n\n/** Configuration for a Telegram Channel. */\nexport type TelegramChannelOptions = {\n /** Bot token issued by BotFather. */\n botToken: string;\n /** Telegram Bot API origin. @default \"https://api.telegram.org\" */\n apiBaseUrl?: string;\n /** Maximum text length accepted by this route. @default 4096 */\n maxLength?: number;\n /** Project the canonical message into Telegram text. */\n toText?: (message: ChannelMessage) => string;\n /** Parse mode for caller-formatted delivery text. */\n parseMode?: \"HTML\" | \"MarkdownV2\";\n /**\n * Smallest gap between `sendMessageDraft` previews. Snapshots produced\n * inside one interval are replaced rather than sent. @default 500\n */\n streamIntervalMs?: number;\n /**\n * Who sent a verified Telegram update, such as your user linked to\n * `event.actor`. Return null to drop the update. Required with `webhook`.\n */\n participant?: ChannelParticipant<TelegramUpdate>;\n /**\n * Pick the agent object an update reaches. Default: a room of the\n * participant's own, so a group chat is not shared by accident.\n */\n route?: ChannelRoute<TelegramUpdate>;\n /** Add secret-verified Telegram webhook ingress to the returned Channel. */\n webhook?: {\n secretToken: string;\n /** Exact webhook pathname accepted by this ingress. @default \"/webhooks/telegram\" */\n path?: string;\n };\n /** Override fetch for testing or custom network routing. */\n fetch?: typeof globalThis.fetch;\n};\n\nconst DEFAULT_TELEGRAM_WEBHOOK_PATH = \"/webhooks/telegram\";\nconst INTERACTION_FOOTER =\n /\\n\\nReply YES to approve or NO to reject\\.\\n\\n\\[channel-interaction:v1:([A-Za-z0-9_-]+)\\]$/;\n\nfunction channelIdentity(chatId: number): string {\n return `telegram:chat:${chatId}`;\n}\n\nfunction userIdentity(userId: number): string {\n return `telegram:user:${userId}`;\n}\n\nfunction messageIdentity(chatId: number, messageId: number): string {\n return `${channelIdentity(chatId)}:message:${messageId}`;\n}\n\nfunction updateIdentity(chatId: number, updateId: number): string {\n return `${channelIdentity(chatId)}:update:${updateId}`;\n}\n\nfunction decodeApprovalId(value: string): string | undefined {\n try {\n const base64 = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padding = \"=\".repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(base64 + padding);\n const bytes = Uint8Array.from(binary, (character) =>\n character.charCodeAt(0)\n );\n const approvalId = new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n return approvalId || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport type TelegramWebhookOptions = {\n /** Telegram webhook secret configured through setWebhook. */\n secretToken: string;\n /** Exact webhook pathname accepted by this ingress. @default \"/webhooks/telegram\" */\n path?: string;\n /**\n * Numeric user id of this bot, used to prove that an approval reply answers\n * a message this bot sent. Without it, marker replies stay ordinary\n * messages because their provenance cannot be established.\n */\n botUserId?: number;\n};\n\nfunction asTelegramMessage(value: unknown): TelegramMessage | undefined {\n return value !== null && typeof value === \"object\"\n ? (value as TelegramMessage)\n : undefined;\n}\n\nfunction telegramActor(message: TelegramMessage) {\n const sender = message.from;\n if (sender) {\n const fullName = [sender.first_name, sender.last_name]\n .filter(Boolean)\n .join(\" \");\n return {\n id: userIdentity(sender.id),\n identity: {\n subject: `user:${sender.id}`\n },\n ...(sender.username && { username: sender.username }),\n ...(fullName && { fullName }),\n isBot: sender.is_bot\n };\n }\n\n const senderChat = message.sender_chat;\n if (!senderChat) return undefined;\n const fullName =\n senderChat.title ??\n [senderChat.first_name, senderChat.last_name].filter(Boolean).join(\" \");\n return {\n id: channelIdentity(senderChat.id),\n identity: {\n subject: `chat:${senderChat.id}`\n },\n ...(senderChat.username && { username: senderChat.username }),\n ...(fullName && { fullName }),\n isBot: \"unknown\" as const\n };\n}\n\nfunction chatLabel(chat: TelegramChat): string {\n const name =\n chat.title ??\n (chat.username ? `@${chat.username}` : undefined) ??\n [chat.first_name, chat.last_name].filter(Boolean).join(\" \") ??\n String(chat.id);\n return `Telegram · ${name || chat.id}`;\n}\n\nfunction eventContext(\n message: TelegramMessage,\n eventId: string,\n botUserId: number | undefined\n): ChannelEventContextInput {\n const actor = telegramActor(message);\n const channelId = channelIdentity(message.chat.id);\n const threadId =\n typeof message.message_thread_id === \"number\"\n ? `${channelId}:topic:${message.message_thread_id}`\n : channelId;\n const isDirectMessage =\n message.chat.type === \"private\"\n ? true\n : message.chat.type === \"group\" ||\n message.chat.type === \"supergroup\" ||\n message.chat.type === \"channel\"\n ? false\n : (\"unknown\" as const);\n return {\n eventId,\n thread: { id: threadId, isDirectMessage },\n replySurface: {\n version: 1,\n address: {\n chatId: String(message.chat.id),\n ...(botUserId && { botUserId }),\n ...(typeof message.message_thread_id === \"number\" && {\n messageThreadId: message.message_thread_id\n }),\n replyToMessageId: message.message_id\n },\n label: chatLabel(message.chat)\n },\n ...(actor && { actor })\n };\n}\n\nfunction telegramTimestamp(value: unknown): string | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return undefined;\n const date = new Date(value * 1000);\n return Number.isFinite(date.getTime()) ? date.toISOString() : undefined;\n}\n\nfunction normalizedMessage(\n message: TelegramMessage,\n eventId: string,\n edited: boolean,\n botUserId: number | undefined\n): ChannelInboundMessageInput {\n const reply = asTelegramMessage(message.reply_to_message);\n const sentAt = telegramTimestamp(message.date);\n const editedAt = telegramTimestamp(message.edit_date);\n\n return {\n type: \"message\",\n ...eventContext(message, eventId, botUserId),\n message: {\n id: messageIdentity(message.chat.id, message.message_id),\n text: message.text as string,\n ...(typeof reply?.message_id === \"number\" && {\n reply: {\n id: messageIdentity(message.chat.id, reply.message_id),\n ...(typeof reply.text === \"string\" && { text: reply.text })\n }\n }),\n ...((sentAt || edited || editedAt) && {\n metadata: {\n ...(sentAt && { sentAt }),\n ...(edited && { edited: true }),\n ...(editedAt && { editedAt })\n }\n })\n }\n };\n}\n\nfunction approvalResponse(\n message: TelegramMessage,\n eventId: string,\n botUserId: number | undefined\n): ChannelApprovalResponseInput | undefined {\n if (botUserId === undefined) return undefined;\n if (message.text !== \"YES\" && message.text !== \"NO\") return undefined;\n\n const reply = asTelegramMessage(message.reply_to_message);\n if (typeof reply?.message_id !== \"number\") return undefined;\n\n // An interaction marker only authorizes a decision when this bot authored\n // the replied-to message; otherwise any chat member could forge one.\n const author = reply.from;\n if (author?.is_bot !== true || author.id !== botUserId) return undefined;\n\n const encodedApprovalId =\n typeof reply.text === \"string\"\n ? reply.text.match(INTERACTION_FOOTER)?.[1]\n : undefined;\n const approvalId = encodedApprovalId\n ? decodeApprovalId(encodedApprovalId)\n : undefined;\n if (!approvalId) return undefined;\n\n return {\n type: \"approval-response\",\n ...eventContext(message, eventId, botUserId),\n approvalId,\n decision: message.text === \"YES\" ? \"approve\" : \"reject\",\n reference: messageIdentity(message.chat.id, message.message_id)\n };\n}\n\nfunction inboundEvent(\n update: TelegramUpdate,\n botUserId: number | undefined\n): ChannelIngressEventInput | undefined {\n const edited = update.edited_message !== undefined;\n const message = asTelegramMessage(\n edited ? update.edited_message : update.message\n );\n if (\n typeof update.update_id !== \"number\" ||\n typeof message?.message_id !== \"number\" ||\n typeof message.text !== \"string\" ||\n typeof message.chat?.id !== \"number\"\n ) {\n return undefined;\n }\n\n const eventId = updateIdentity(message.chat.id, update.update_id);\n return (\n approvalResponse(message, eventId, botUserId) ??\n normalizedMessage(message, eventId, edited, botUserId)\n );\n}\n\n/** Recover this bot's numeric user id from its BotFather token prefix. */\nfunction telegramBotUserId(botToken: string): number | undefined {\n const prefix = botToken.match(/^(\\d+):/)?.[1];\n if (!prefix) return undefined;\n const botUserId = Number(prefix);\n return Number.isSafeInteger(botUserId) && botUserId > 0\n ? botUserId\n : undefined;\n}\n\n/** Create dependency-free Telegram webhook ingress for a destination chat. */\nexport function telegramWebhook(\n options: TelegramWebhookOptions\n): ChannelIngress<TelegramUpdate> {\n if (!options.secretToken.trim()) {\n throw new Error(\n \"secretToken is required to create Telegram webhook ingress\"\n );\n }\n if (\n options.botUserId !== undefined &&\n (!Number.isSafeInteger(options.botUserId) || options.botUserId <= 0)\n ) {\n throw new Error(\"botUserId must be a positive Telegram user id\");\n }\n\n const botUserId = options.botUserId;\n const path = options.path ?? DEFAULT_TELEGRAM_WEBHOOK_PATH;\n return {\n async receive(request) {\n if (!matchesPath(request, path)) return null;\n if (request.method !== \"POST\") return emptyIngressResponse(405);\n if (\n request.headers.get(\"x-telegram-bot-api-secret-token\") !==\n options.secretToken\n ) {\n return emptyIngressResponse(401);\n }\n\n let update: unknown;\n try {\n update = await request.json();\n } catch {\n return emptyIngressResponse(400);\n }\n if (update === null || typeof update !== \"object\") {\n return emptyIngressResponse(400);\n }\n\n const raw = update as TelegramUpdate;\n const event = inboundEvent(raw, botUserId);\n return {\n events: event ? [{ event, raw }] : [],\n response: new Response(null, { status: 200 })\n };\n }\n };\n}\n\n/** Create a configured Telegram ingress Channel. */\nexport function telegram(\n options: TelegramChannelOptions\n): Channel<TelegramUpdate> {\n if (!options.botToken.trim()) {\n throw new Error(\"botToken is required to create a Telegram channel\");\n }\n if (options.webhook && !options.participant) {\n throw new Error(\"participant is required with a Telegram webhook\");\n }\n const botUserId = telegramBotUserId(options.botToken);\n const ingress = options.webhook\n ? telegramWebhook({ ...options.webhook, botUserId })\n : undefined;\n\n return {\n ...(options.participant && { participant: options.participant }),\n ...(options.route && { route: options.route }),\n ...(ingress && { ingress }),\n contactSurface(identity: ChannelIdentity) {\n if ((identity.scope ?? \"default\") !== \"default\") return null;\n const match = identity.subject.match(/^(user|chat):(-?\\d+)$/);\n if (!match) return null;\n return {\n version: 1,\n address: {\n chatId: match[2],\n ...(botUserId && { botUserId })\n },\n label: `Telegram · ${match[1]} ${match[2]}`\n };\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { l as Json } from "../../../protocol-CukuI73M.js";
|
|
2
|
+
import { WebChannelClient } from "./client.js";
|
|
3
|
+
import { ChatTransport, UIMessage, UIMessageChunk } from "ai";
|
|
4
|
+
|
|
5
|
+
//#region src/experimental/channels/web/ai-sdk.d.ts
|
|
6
|
+
type WebChannelChatTransportOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* Client tools the transport runs itself when the agent gives this
|
|
9
|
+
* participant a call. Without them, answer calls with `addToolOutput`.
|
|
10
|
+
*/
|
|
11
|
+
tools?: Record<string, (input: Json) => Json | Promise<Json>>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* What the transport reads from `sendMessages`. Kept structural so the
|
|
15
|
+
* transport also fits the `ChatTransport` of a newer `ai` release, such as
|
|
16
|
+
* the one `@ai-sdk/tui` brings.
|
|
17
|
+
*/
|
|
18
|
+
type WebChannelSendOptions = {
|
|
19
|
+
trigger: "submit-message" | "regenerate-message";
|
|
20
|
+
messages: readonly {
|
|
21
|
+
id: string;
|
|
22
|
+
role: UIMessage["role"];
|
|
23
|
+
parts: readonly object[];
|
|
24
|
+
}[];
|
|
25
|
+
abortSignal?: AbortSignal;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* An AI SDK `ChatTransport` over a Web Channel connection, for `useChat`
|
|
29
|
+
* and `@ai-sdk/tui`. Each call streams one turn until it settles, or until
|
|
30
|
+
* it waits for input the transport cannot give.
|
|
31
|
+
*
|
|
32
|
+
* The agent owns the transcript, so only the newest user message or the
|
|
33
|
+
* newest answers to pending tool calls are sent; the rest of `messages` is
|
|
34
|
+
* ignored. Regenerating a message is not supported.
|
|
35
|
+
*/
|
|
36
|
+
declare class WebChannelChatTransport implements ChatTransport<UIMessage> {
|
|
37
|
+
#private;
|
|
38
|
+
constructor(
|
|
39
|
+
client: WebChannelClient,
|
|
40
|
+
options?: WebChannelChatTransportOptions
|
|
41
|
+
);
|
|
42
|
+
sendMessages({
|
|
43
|
+
trigger,
|
|
44
|
+
messages,
|
|
45
|
+
abortSignal
|
|
46
|
+
}: WebChannelSendOptions): Promise<ReadableStream<UIMessageChunk>>;
|
|
47
|
+
reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null>;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export {
|
|
51
|
+
WebChannelChatTransport,
|
|
52
|
+
WebChannelChatTransportOptions,
|
|
53
|
+
WebChannelSendOptions
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=ai-sdk.d.ts.map
|
|
@@ -0,0 +1,266 @@
|
|
|
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 toTranscriptMessage, s as toUIMessageChunk } from "../../../turns-DCV3ycDl.js";
|
|
4
|
+
//#region src/experimental/channels/web/ai-sdk.ts
|
|
5
|
+
var _client = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
var _tools = /* @__PURE__ */ new WeakMap();
|
|
7
|
+
var _WebChannelChatTransport_brand = /* @__PURE__ */ new WeakSet();
|
|
8
|
+
/**
|
|
9
|
+
* An AI SDK `ChatTransport` over a Web Channel connection, for `useChat`
|
|
10
|
+
* and `@ai-sdk/tui`. Each call streams one turn until it settles, or until
|
|
11
|
+
* it waits for input the transport cannot give.
|
|
12
|
+
*
|
|
13
|
+
* The agent owns the transcript, so only the newest user message or the
|
|
14
|
+
* newest answers to pending tool calls are sent; the rest of `messages` is
|
|
15
|
+
* ignored. Regenerating a message is not supported.
|
|
16
|
+
*/
|
|
17
|
+
var WebChannelChatTransport = class {
|
|
18
|
+
constructor(client, options = {}) {
|
|
19
|
+
_classPrivateMethodInitSpec(this, _WebChannelChatTransport_brand);
|
|
20
|
+
_classPrivateFieldInitSpec(this, _client, void 0);
|
|
21
|
+
_classPrivateFieldInitSpec(this, _tools, void 0);
|
|
22
|
+
_classPrivateFieldSet2(_client, this, client);
|
|
23
|
+
_classPrivateFieldSet2(_tools, this, options.tools);
|
|
24
|
+
}
|
|
25
|
+
async sendMessages({ trigger, messages, abortSignal }) {
|
|
26
|
+
if (trigger === "regenerate-message") throw new Error("Channels cannot regenerate a message. Send a new message instead.");
|
|
27
|
+
await _assertClassBrand(_WebChannelChatTransport_brand, this, _connected).call(this);
|
|
28
|
+
const last = messages.at(-1);
|
|
29
|
+
if (last?.role === "user") {
|
|
30
|
+
const id = crypto.randomUUID();
|
|
31
|
+
const message = {
|
|
32
|
+
...toTranscriptMessage(last),
|
|
33
|
+
id,
|
|
34
|
+
role: "user"
|
|
35
|
+
};
|
|
36
|
+
return _assertClassBrand(_WebChannelChatTransport_brand, this, _follow).call(this, {
|
|
37
|
+
startedBy: id,
|
|
38
|
+
events: [{
|
|
39
|
+
type: "message",
|
|
40
|
+
eventId: id,
|
|
41
|
+
message,
|
|
42
|
+
..._assertClassBrand(_WebChannelChatTransport_brand, this, _clientTools).call(this)
|
|
43
|
+
}],
|
|
44
|
+
signal: abortSignal
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const answers = last ? _assertClassBrand(_WebChannelChatTransport_brand, this, _answers).call(this, last) : [];
|
|
48
|
+
if (answers.length === 0) throw new Error("Nothing to send: the last message is neither a user message nor an answer to a pending tool call.");
|
|
49
|
+
return _assertClassBrand(_WebChannelChatTransport_brand, this, _follow).call(this, {
|
|
50
|
+
turnId: answers[0].turnId,
|
|
51
|
+
events: answers,
|
|
52
|
+
signal: abortSignal
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async reconnectToStream() {
|
|
56
|
+
await _assertClassBrand(_WebChannelChatTransport_brand, this, _connected).call(this);
|
|
57
|
+
const running = _classPrivateFieldGet2(_client, this).state.turns.find((turn) => turn.status === "running");
|
|
58
|
+
if (running?.status !== "running") return null;
|
|
59
|
+
return _assertClassBrand(_WebChannelChatTransport_brand, this, _follow).call(this, {
|
|
60
|
+
turnId: running.turnId,
|
|
61
|
+
responseId: running.responseId,
|
|
62
|
+
events: []
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
function _connected() {
|
|
67
|
+
if (_classPrivateFieldGet2(_client, this).state.connected) return Promise.resolve();
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
const off = _classPrivateFieldGet2(_client, this).subscribe((state) => {
|
|
70
|
+
if (!state.connected) return;
|
|
71
|
+
off();
|
|
72
|
+
resolve();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function _clientTools() {
|
|
77
|
+
return _classPrivateFieldGet2(_tools, this) ? { clientTools: Object.keys(_classPrivateFieldGet2(_tools, this)).map((name) => ({ name })) } : {};
|
|
78
|
+
}
|
|
79
|
+
/** Answers in the message to tool calls the agent is waiting on. */
|
|
80
|
+
function _answers(message) {
|
|
81
|
+
const answers = [];
|
|
82
|
+
for (const part of toTranscriptMessage(message).parts) {
|
|
83
|
+
if (part.type !== "tool") continue;
|
|
84
|
+
const pending = _assertClassBrand(_WebChannelChatTransport_brand, this, _pending).call(this, part.toolCallId);
|
|
85
|
+
if (!pending) continue;
|
|
86
|
+
const { turnId, call } = pending;
|
|
87
|
+
if (call.state === "approval-requested" && call.approval && part.state === "approval-responded" && part.approval?.approved !== void 0) answers.push({
|
|
88
|
+
type: "approval-response",
|
|
89
|
+
turnId,
|
|
90
|
+
approvalId: call.approval.id,
|
|
91
|
+
approved: part.approval.approved,
|
|
92
|
+
...part.approval.reason !== void 0 && { reason: part.approval.reason }
|
|
93
|
+
});
|
|
94
|
+
else if (call.state === "input-available" && (part.state === "output-available" || part.state === "output-error")) answers.push({
|
|
95
|
+
type: "tool-result",
|
|
96
|
+
turnId,
|
|
97
|
+
toolCallId: part.toolCallId,
|
|
98
|
+
result: part.state === "output-available" ? {
|
|
99
|
+
ok: true,
|
|
100
|
+
output: part.output ?? null
|
|
101
|
+
} : {
|
|
102
|
+
ok: false,
|
|
103
|
+
errorText: part.errorText
|
|
104
|
+
},
|
|
105
|
+
..._assertClassBrand(_WebChannelChatTransport_brand, this, _clientTools).call(this)
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return answers;
|
|
109
|
+
}
|
|
110
|
+
/** A tool call waiting for input, and the turn waiting on it. */
|
|
111
|
+
function _pending(toolCallId) {
|
|
112
|
+
const { messages, turns } = _classPrivateFieldGet2(_client, this).state;
|
|
113
|
+
for (const message of messages) {
|
|
114
|
+
const call = message.parts.find((part) => part.type === "tool" && part.toolCallId === toolCallId);
|
|
115
|
+
if (!call) continue;
|
|
116
|
+
const turn = turns.find((t) => t.status === "settled" && t.outcome === "awaiting-input" && t.messageIds.includes(message.id));
|
|
117
|
+
return turn && {
|
|
118
|
+
turnId: turn.turnId,
|
|
119
|
+
call
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** Calls in a settled turn that this transport can run for its participant. */
|
|
124
|
+
function _runnable(turn) {
|
|
125
|
+
const { messages, you } = _classPrivateFieldGet2(_client, this).state;
|
|
126
|
+
if (turn.status !== "settled" || !_classPrivateFieldGet2(_tools, this) || !you) return [];
|
|
127
|
+
return messages.filter((message) => turn.messageIds.includes(message.id)).flatMap((message) => message.parts).filter((part) => part.type === "tool" && part.state === "input-available" && part.owner === you.id && Object.hasOwn(_classPrivateFieldGet2(_tools, this) ?? {}, part.toolName));
|
|
128
|
+
}
|
|
129
|
+
function _follow(follow) {
|
|
130
|
+
const client = _classPrivateFieldGet2(_client, this);
|
|
131
|
+
let { turnId, responseId } = follow;
|
|
132
|
+
let responseEnded = responseId === void 0;
|
|
133
|
+
let settled;
|
|
134
|
+
let answering = false;
|
|
135
|
+
let offline = false;
|
|
136
|
+
let done = false;
|
|
137
|
+
const cleanup = [];
|
|
138
|
+
return new ReadableStream({
|
|
139
|
+
start: (controller) => {
|
|
140
|
+
const enqueue = (chunk) => {
|
|
141
|
+
if (!done) controller.enqueue(chunk);
|
|
142
|
+
};
|
|
143
|
+
const finish = (...last) => {
|
|
144
|
+
if (done) return;
|
|
145
|
+
for (const chunk of last) controller.enqueue(chunk);
|
|
146
|
+
done = true;
|
|
147
|
+
for (const off of cleanup) off();
|
|
148
|
+
controller.close();
|
|
149
|
+
};
|
|
150
|
+
const fail = (error) => finish({
|
|
151
|
+
type: "error",
|
|
152
|
+
errorText: error instanceof Error ? error.message : String(error)
|
|
153
|
+
});
|
|
154
|
+
const send = (event) => client.send(event).catch((error) => fail(error));
|
|
155
|
+
const answer = async (calls) => {
|
|
156
|
+
answering = true;
|
|
157
|
+
settled = void 0;
|
|
158
|
+
for (const call of calls) {
|
|
159
|
+
const run = _classPrivateFieldGet2(_tools, this)?.[call.toolName];
|
|
160
|
+
let result;
|
|
161
|
+
try {
|
|
162
|
+
result = {
|
|
163
|
+
ok: true,
|
|
164
|
+
output: await run?.(call.input ?? null) ?? null
|
|
165
|
+
};
|
|
166
|
+
enqueue({
|
|
167
|
+
type: "tool-output-available",
|
|
168
|
+
toolCallId: call.toolCallId,
|
|
169
|
+
output: result.output
|
|
170
|
+
});
|
|
171
|
+
} catch (error) {
|
|
172
|
+
result = {
|
|
173
|
+
ok: false,
|
|
174
|
+
errorText: String(error)
|
|
175
|
+
};
|
|
176
|
+
enqueue({
|
|
177
|
+
type: "tool-output-error",
|
|
178
|
+
toolCallId: call.toolCallId,
|
|
179
|
+
errorText: result.errorText
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (!turnId) return;
|
|
183
|
+
await send({
|
|
184
|
+
type: "tool-result",
|
|
185
|
+
turnId,
|
|
186
|
+
toolCallId: call.toolCallId,
|
|
187
|
+
result,
|
|
188
|
+
..._assertClassBrand(_WebChannelChatTransport_brand, this, _clientTools).call(this)
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
answering = false;
|
|
192
|
+
};
|
|
193
|
+
const settle = () => {
|
|
194
|
+
if (!settled || settled.status !== "settled") return;
|
|
195
|
+
if (!responseEnded || answering) return;
|
|
196
|
+
switch (settled.outcome) {
|
|
197
|
+
case "awaiting-input": {
|
|
198
|
+
const calls = _assertClassBrand(_WebChannelChatTransport_brand, this, _runnable).call(this, settled);
|
|
199
|
+
if (calls.length > 0) {
|
|
200
|
+
answer(calls);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
return finish({ type: "finish" });
|
|
204
|
+
}
|
|
205
|
+
case "completed": return finish({ type: "finish" });
|
|
206
|
+
case "aborted": return finish({ type: "abort" });
|
|
207
|
+
case "failed": return finish({
|
|
208
|
+
type: "error",
|
|
209
|
+
errorText: settled.error ?? "The turn failed."
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
enqueue(follow.startedBy ? {
|
|
214
|
+
type: "start",
|
|
215
|
+
messageId: crypto.randomUUID()
|
|
216
|
+
} : { type: "start" });
|
|
217
|
+
if (responseId) for (const chunk of client.chunksOf(responseId) ?? []) enqueue(toUIMessageChunk(chunk));
|
|
218
|
+
cleanup.push(client.onActivity((activity) => {
|
|
219
|
+
if (activity.type === "turn") {
|
|
220
|
+
const turn = activity.turn;
|
|
221
|
+
if (!turnId && turn.startedBy === follow.startedBy) turnId = turn.turnId;
|
|
222
|
+
if (turn.turnId !== turnId) return;
|
|
223
|
+
if (turn.status === "running" && turn.responseId !== responseId) {
|
|
224
|
+
responseId = turn.responseId;
|
|
225
|
+
responseEnded = false;
|
|
226
|
+
}
|
|
227
|
+
settled = turn.status === "settled" ? turn : void 0;
|
|
228
|
+
return settle();
|
|
229
|
+
}
|
|
230
|
+
if (activity.responseId !== responseId) return;
|
|
231
|
+
if (activity.type === "chunks") for (const chunk of activity.chunks) enqueue(toUIMessageChunk(chunk));
|
|
232
|
+
else {
|
|
233
|
+
responseEnded = true;
|
|
234
|
+
settle();
|
|
235
|
+
}
|
|
236
|
+
}), client.subscribe((state) => {
|
|
237
|
+
if (!state.connected) {
|
|
238
|
+
offline = true;
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (!offline) return;
|
|
242
|
+
offline = false;
|
|
243
|
+
if (turnId && !state.turns.some((t) => t.turnId === turnId)) finish({ type: "finish" });
|
|
244
|
+
}));
|
|
245
|
+
const abort = () => {
|
|
246
|
+
if (turnId) client.send({
|
|
247
|
+
type: "cancel",
|
|
248
|
+
turnId
|
|
249
|
+
}).catch(() => {});
|
|
250
|
+
finish();
|
|
251
|
+
};
|
|
252
|
+
if (follow.signal?.aborted) return abort();
|
|
253
|
+
follow.signal?.addEventListener("abort", abort, { once: true });
|
|
254
|
+
cleanup.push(() => follow.signal?.removeEventListener("abort", abort));
|
|
255
|
+
for (const event of follow.events) send(event);
|
|
256
|
+
},
|
|
257
|
+
cancel: () => {
|
|
258
|
+
done = true;
|
|
259
|
+
for (const off of cleanup) off();
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
264
|
+
export { WebChannelChatTransport };
|
|
265
|
+
|
|
266
|
+
//# sourceMappingURL=ai-sdk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sdk.js","names":[],"sources":["../../../../src/experimental/channels/web/ai-sdk.ts"],"sourcesContent":["import type { ChatTransport, UIMessage, UIMessageChunk } from \"ai\";\nimport {\n toTranscriptMessage,\n toUIMessageChunk\n} from \"../../../harness/ai-sdk/turns\";\nimport type { Json, ToolPart, TurnStatus } from \"../protocol\";\nimport type { ClientEvent, WebChannelClient } from \"./client\";\n\nexport type WebChannelChatTransportOptions = {\n /**\n * Client tools the transport runs itself when the agent gives this\n * participant a call. Without them, answer calls with `addToolOutput`.\n */\n tools?: Record<string, (input: Json) => Json | Promise<Json>>;\n};\n\n/**\n * What the transport reads from `sendMessages`. Kept structural so the\n * transport also fits the `ChatTransport` of a newer `ai` release, such as\n * the one `@ai-sdk/tui` brings.\n */\nexport type WebChannelSendOptions = {\n trigger: \"submit-message\" | \"regenerate-message\";\n messages: readonly {\n id: string;\n role: UIMessage[\"role\"];\n parts: readonly object[];\n }[];\n abortSignal?: AbortSignal;\n};\n\ntype Follow = {\n /** The turn to follow; for a new message, the turn the message starts. */\n turnId?: string;\n startedBy?: string;\n responseId?: string;\n events: ClientEvent[];\n signal?: AbortSignal;\n};\n\n/**\n * An AI SDK `ChatTransport` over a Web Channel connection, for `useChat`\n * and `@ai-sdk/tui`. Each call streams one turn until it settles, or until\n * it waits for input the transport cannot give.\n *\n * The agent owns the transcript, so only the newest user message or the\n * newest answers to pending tool calls are sent; the rest of `messages` is\n * ignored. Regenerating a message is not supported.\n */\nexport class WebChannelChatTransport implements ChatTransport<UIMessage> {\n readonly #client: WebChannelClient;\n readonly #tools: WebChannelChatTransportOptions[\"tools\"];\n\n constructor(\n client: WebChannelClient,\n options: WebChannelChatTransportOptions = {}\n ) {\n this.#client = client;\n this.#tools = options.tools;\n }\n\n async sendMessages({\n trigger,\n messages,\n abortSignal\n }: WebChannelSendOptions): Promise<ReadableStream<UIMessageChunk>> {\n if (trigger === \"regenerate-message\") {\n throw new Error(\n \"Channels cannot regenerate a message. Send a new message instead.\"\n );\n }\n await this.#connected();\n // SAFETY: every AI SDK 7 release shares these UI message shapes.\n const last = messages.at(-1) as UIMessage | undefined;\n if (last?.role === \"user\") {\n const id = crypto.randomUUID();\n const message = {\n ...toTranscriptMessage(last),\n id,\n role: \"user\" as const\n };\n return this.#follow({\n startedBy: id,\n events: [\n {\n type: \"message\",\n eventId: id,\n message,\n ...this.#clientTools()\n }\n ],\n signal: abortSignal\n });\n }\n const answers = last ? this.#answers(last) : [];\n if (answers.length === 0) {\n throw new Error(\n \"Nothing to send: the last message is neither a user message nor an answer to a pending tool call.\"\n );\n }\n return this.#follow({\n turnId: answers[0].turnId,\n events: answers,\n signal: abortSignal\n });\n }\n\n async reconnectToStream(): Promise<ReadableStream<UIMessageChunk> | null> {\n await this.#connected();\n const running = this.#client.state.turns.find(\n (turn) => turn.status === \"running\"\n );\n if (running?.status !== \"running\") return null;\n return this.#follow({\n turnId: running.turnId,\n responseId: running.responseId,\n events: []\n });\n }\n\n #connected(): Promise<void> {\n if (this.#client.state.connected) return Promise.resolve();\n return new Promise((resolve) => {\n const off = this.#client.subscribe((state) => {\n if (!state.connected) return;\n off();\n resolve();\n });\n });\n }\n\n #clientTools() {\n return this.#tools\n ? { clientTools: Object.keys(this.#tools).map((name) => ({ name })) }\n : {};\n }\n\n /** Answers in the message to tool calls the agent is waiting on. */\n #answers(message: UIMessage) {\n const answers: (ClientEvent & { turnId: string })[] = [];\n for (const part of toTranscriptMessage(message).parts) {\n if (part.type !== \"tool\") continue;\n const pending = this.#pending(part.toolCallId);\n if (!pending) continue;\n const { turnId, call } = pending;\n if (\n call.state === \"approval-requested\" &&\n call.approval &&\n part.state === \"approval-responded\" &&\n part.approval?.approved !== undefined\n ) {\n answers.push({\n type: \"approval-response\",\n turnId,\n approvalId: call.approval.id,\n approved: part.approval.approved,\n ...(part.approval.reason !== undefined && {\n reason: part.approval.reason\n })\n });\n } else if (\n call.state === \"input-available\" &&\n (part.state === \"output-available\" || part.state === \"output-error\")\n ) {\n answers.push({\n type: \"tool-result\",\n turnId,\n toolCallId: part.toolCallId,\n result:\n part.state === \"output-available\"\n ? { ok: true, output: part.output ?? null }\n : { ok: false, errorText: part.errorText },\n ...this.#clientTools()\n });\n }\n }\n return answers;\n }\n\n /** A tool call waiting for input, and the turn waiting on it. */\n #pending(toolCallId: string): { turnId: string; call: ToolPart } | undefined {\n const { messages, turns } = this.#client.state;\n for (const message of messages) {\n const call = message.parts.find(\n (part): part is ToolPart =>\n part.type === \"tool\" && part.toolCallId === toolCallId\n );\n if (!call) continue;\n const turn = turns.find(\n (t) =>\n t.status === \"settled\" &&\n t.outcome === \"awaiting-input\" &&\n t.messageIds.includes(message.id)\n );\n return turn && { turnId: turn.turnId, call };\n }\n return undefined;\n }\n\n /** Calls in a settled turn that this transport can run for its participant. */\n #runnable(turn: TurnStatus): ToolPart[] {\n const { messages, you } = this.#client.state;\n if (turn.status !== \"settled\" || !this.#tools || !you) return [];\n return messages\n .filter((message) => turn.messageIds.includes(message.id))\n .flatMap((message) => message.parts)\n .filter(\n (part): part is ToolPart =>\n part.type === \"tool\" &&\n part.state === \"input-available\" &&\n part.owner === you.id &&\n Object.hasOwn(this.#tools ?? {}, part.toolName)\n );\n }\n\n #follow(follow: Follow): ReadableStream<UIMessageChunk> {\n const client = this.#client;\n let { turnId, responseId } = follow;\n let responseEnded = responseId === undefined;\n let settled: TurnStatus | undefined;\n let answering = false;\n let offline = false;\n let done = false;\n const cleanup: (() => void)[] = [];\n\n return new ReadableStream<UIMessageChunk>({\n start: (controller) => {\n const enqueue = (chunk: UIMessageChunk) => {\n if (!done) controller.enqueue(chunk);\n };\n const finish = (...last: UIMessageChunk[]) => {\n if (done) return;\n for (const chunk of last) controller.enqueue(chunk);\n done = true;\n for (const off of cleanup) off();\n controller.close();\n };\n const fail = (error: unknown) =>\n finish({\n type: \"error\",\n errorText: error instanceof Error ? error.message : String(error)\n });\n\n const send = (event: ClientEvent) =>\n client.send(event).catch((error: unknown) => fail(error));\n\n const answer = async (calls: ToolPart[]) => {\n answering = true;\n settled = undefined;\n for (const call of calls) {\n const run = this.#tools?.[call.toolName];\n let result:\n | { ok: true; output: Json }\n | { ok: false; errorText: string };\n try {\n result = {\n ok: true,\n output: (await run?.(call.input ?? null)) ?? null\n };\n enqueue({\n type: \"tool-output-available\",\n toolCallId: call.toolCallId,\n output: result.output\n });\n } catch (error) {\n result = { ok: false, errorText: String(error) };\n enqueue({\n type: \"tool-output-error\",\n toolCallId: call.toolCallId,\n errorText: result.errorText\n });\n }\n if (!turnId) return;\n await send({\n type: \"tool-result\",\n turnId,\n toolCallId: call.toolCallId,\n result,\n ...this.#clientTools()\n });\n }\n answering = false;\n };\n\n const settle = () => {\n if (!settled || settled.status !== \"settled\") return;\n if (!responseEnded || answering) return;\n switch (settled.outcome) {\n case \"awaiting-input\": {\n const calls = this.#runnable(settled);\n if (calls.length > 0) {\n void answer(calls);\n return;\n }\n return finish({ type: \"finish\" });\n }\n case \"completed\":\n return finish({ type: \"finish\" });\n case \"aborted\":\n return finish({ type: \"abort\" });\n case \"failed\":\n return finish({\n type: \"error\",\n errorText: settled.error ?? \"The turn failed.\"\n });\n }\n };\n\n // A new turn builds a new message; the AI SDK keys messages by id,\n // so without one each reply would replace the last. A continuation\n // keeps the id the caller already has.\n enqueue(\n follow.startedBy\n ? { type: \"start\", messageId: crypto.randomUUID() }\n : { type: \"start\" }\n );\n if (responseId) {\n for (const chunk of client.chunksOf(responseId) ?? []) {\n enqueue(toUIMessageChunk(chunk));\n }\n }\n\n cleanup.push(\n client.onActivity((activity) => {\n if (activity.type === \"turn\") {\n const turn = activity.turn;\n if (!turnId && turn.startedBy === follow.startedBy) {\n turnId = turn.turnId;\n }\n if (turn.turnId !== turnId) return;\n if (turn.status === \"running\" && turn.responseId !== responseId) {\n responseId = turn.responseId;\n responseEnded = false;\n }\n settled = turn.status === \"settled\" ? turn : undefined;\n return settle();\n }\n if (activity.responseId !== responseId) return;\n if (activity.type === \"chunks\") {\n for (const chunk of activity.chunks) {\n enqueue(toUIMessageChunk(chunk));\n }\n } else {\n responseEnded = true;\n settle();\n }\n }),\n client.subscribe((state) => {\n if (!state.connected) {\n offline = true;\n return;\n }\n if (!offline) return;\n offline = false;\n // The turn settled while this client was away.\n if (turnId && !state.turns.some((t) => t.turnId === turnId)) {\n finish({ type: \"finish\" });\n }\n })\n );\n\n const abort = () => {\n if (turnId)\n void client.send({ type: \"cancel\", turnId }).catch(() => {});\n finish();\n };\n if (follow.signal?.aborted) return abort();\n follow.signal?.addEventListener(\"abort\", abort, { once: true });\n cleanup.push(() => follow.signal?.removeEventListener(\"abort\", abort));\n\n for (const event of follow.events) void send(event);\n },\n cancel: () => {\n done = true;\n for (const off of cleanup) off();\n }\n });\n }\n}\n"],"mappings":"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"}
|