agents 0.22.0 → 0.24.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 +20 -1
- package/dist/{agent-routing-CnkaHb-v.d.ts → agent-routing-B2XLNMxq.d.ts} +1094 -443
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +26 -26
- package/dist/{agent-tools-C0XJqWzB.d.ts → agent-tools-Dj5Mzlw7.d.ts} +7 -7
- package/dist/agent-tools.d.ts +21 -21
- package/dist/browser/ai.js +4 -1
- package/dist/browser/ai.js.map +1 -1
- package/dist/browser/tanstack-ai.js.map +1 -1
- package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
- package/dist/callable-decorator.d.ts +18 -0
- package/dist/callable-decorator.js +71 -0
- package/dist/callable-decorator.js.map +1 -0
- package/dist/{capability-BjSKYpzg.js → capability-B4WbF81e.js} +2 -1
- package/dist/capability-B4WbF81e.js.map +1 -0
- package/dist/capability-runner-BUBa6Ake.d.ts +484 -0
- package/dist/channel-Bnm4S7T2.d.ts +491 -0
- package/dist/channels/ai-sdk.d.ts +46 -0
- package/dist/channels/ai-sdk.js +120 -0
- package/dist/channels/ai-sdk.js.map +1 -0
- package/dist/channels/email.d.ts +95 -0
- package/dist/channels/email.js +323 -0
- package/dist/channels/email.js.map +1 -0
- package/dist/channels/index.d.ts +233 -0
- package/dist/channels/index.js +608 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/slack.d.ts +140 -0
- package/dist/channels/slack.js +614 -0
- package/dist/channels/slack.js.map +1 -0
- package/dist/channels/tanstack-ai.d.ts +39 -0
- package/dist/channels/tanstack-ai.js +17 -0
- package/dist/channels/tanstack-ai.js.map +1 -0
- package/dist/channels/telegram.d.ts +106 -0
- package/dist/channels/telegram.js +427 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/voice.d.ts +45 -0
- package/dist/channels/voice.js +122 -0
- package/dist/channels/voice.js.map +1 -0
- package/dist/chat/index.d.ts +2319 -2010
- package/dist/chat/index.js +892 -518
- package/dist/chat/index.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +7 -7
- package/dist/chat-sdk/index.js +1 -1
- package/dist/client-BxdkCuVy.d.ts +411 -0
- package/dist/client-C9DAjZIY.js +518 -0
- package/dist/client-C9DAjZIY.js.map +1 -0
- package/dist/{client-jagG8a9_.js → client-fyQrLGkD.js} +2 -2
- package/dist/{client-jagG8a9_.js.map → client-fyQrLGkD.js.map} +1 -1
- package/dist/client.d.ts +27 -283
- package/dist/client.js +2 -274
- package/dist/context/index.d.ts +216 -0
- package/dist/context/index.js +454 -0
- package/dist/context/index.js.map +1 -0
- package/dist/current-agent-C4w86kcN.d.ts +93 -0
- package/dist/current-agent-DhoDkSnH.js.map +1 -1
- package/dist/{diagnostics-CaBjfz4J.js → diagnostics-BzvaX2UT.js} +5 -1
- package/dist/diagnostics-BzvaX2UT.js.map +1 -0
- package/dist/diagnostics-C4jcz3VK.js +360 -0
- package/dist/diagnostics-C4jcz3VK.js.map +1 -0
- package/dist/durable-object-lifecycle-ei7M7lqB.d.ts +157 -0
- package/dist/index-BB0kqhIz.d.ts +101 -0
- package/dist/index-BVVgDSdq.d.ts +1 -0
- package/dist/index-Dlgtd3Mj.d.ts +78 -0
- package/dist/index-XDkuQ7zm.d.ts +89 -0
- package/dist/{index-DcSAZKsB.d.ts → index-YSKgfgg9.d.ts} +3 -1
- package/dist/index.d.ts +92 -83
- package/dist/index.js +4 -3
- package/dist/ingress-BfetZbMO.js +83 -0
- package/dist/ingress-BfetZbMO.js.map +1 -0
- package/dist/internal-CYlgHl1l.js +59 -0
- package/dist/internal-CYlgHl1l.js.map +1 -0
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +39 -19
- package/dist/lifecycle/index.js +2 -2
- package/dist/lifecycle-Mm_jQh7r.js +1314 -0
- package/dist/lifecycle-Mm_jQh7r.js.map +1 -0
- package/dist/mcp/client/index.d.ts +20 -20
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/index.d.ts +35 -35
- package/dist/mcp/index.js +2 -2
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.js +1 -1
- package/dist/queue/index.d.ts +123 -0
- package/dist/queue/index.js +2 -0
- package/dist/queue-BC9F5cUo.js +406 -0
- package/dist/queue-BC9F5cUo.js.map +1 -0
- package/dist/react.d.ts +34 -16
- package/dist/react.js +31 -8
- package/dist/react.js.map +1 -1
- package/dist/{retries-CAvxtG9d.d.ts → retries-D9B2UCq3.d.ts} +23 -6
- package/dist/retries.d.ts +10 -6
- package/dist/retries.js +21 -1
- package/dist/retries.js.map +1 -1
- package/dist/routing/index.d.ts +137 -0
- package/dist/routing/index.js +244 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/sanitize-D9TujEK8.js +79 -0
- package/dist/sanitize-D9TujEK8.js.map +1 -0
- package/dist/{scheduler-DQoTGoAW.d.ts → scheduler-BGq6M5Kd.d.ts} +20 -21
- package/dist/scheduler-D_KHqxBa.js +658 -0
- package/dist/scheduler-D_KHqxBa.js.map +1 -0
- package/dist/schedules/index.d.ts +1 -1
- package/dist/schedules/index.js +1 -1
- package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
- package/dist/serializable.d.ts +1 -1
- package/dist/sessions/index.d.ts +441 -0
- package/dist/sessions/index.js +2063 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/skills/index.d.ts +99 -0
- package/dist/skills/index.js +254 -5
- package/dist/skills/index.js.map +1 -1
- package/dist/{src-5W6JNKVb.js → src-BNU3ZiJM.js} +1524 -1441
- package/dist/src-BNU3ZiJM.js.map +1 -0
- package/dist/state/index.d.ts +6 -0
- package/dist/state/index.js +137 -0
- package/dist/state/index.js.map +1 -0
- package/dist/streams/index.d.ts +120 -0
- package/dist/streams/index.js +107 -0
- package/dist/streams/index.js.map +1 -0
- package/dist/streams-BcE8JP2X.d.ts +370 -0
- package/dist/streams-CCPRV6dt.js +709 -0
- package/dist/streams-CCPRV6dt.js.map +1 -0
- package/dist/sub-routing.d.ts +12 -12
- package/dist/surface-bZZJqBka.js +17 -0
- package/dist/surface-bZZJqBka.js.map +1 -0
- package/dist/tasks/index.d.ts +64 -0
- package/dist/tasks/index.js +2 -0
- package/dist/tasks-D4nLqVSI.js +1656 -0
- package/dist/tasks-D4nLqVSI.js.map +1 -0
- package/dist/tasks-V2lCT8ZV.d.ts +517 -0
- package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
- package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
- package/dist/text-stream-CpdiKrJB.js +272 -0
- package/dist/text-stream-CpdiKrJB.js.map +1 -0
- package/dist/tokens-nHAKcN6M.js +52 -0
- package/dist/tokens-nHAKcN6M.js.map +1 -0
- package/dist/tool-schema-CBjGPrsQ.js +31 -0
- package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
- package/dist/transport-protocol-BxyngQ_R.js +25 -0
- package/dist/transport-protocol-BxyngQ_R.js.map +1 -0
- package/dist/transport-protocol-ZTew5Wso.d.ts +27 -0
- package/dist/types-B7LojTe4.d.ts +202 -0
- package/dist/types-DCD6BNZH.d.ts +70 -0
- package/dist/types-_Faxb570.d.ts +439 -0
- package/dist/voice/client.d.ts +226 -0
- package/dist/voice/client.js +932 -0
- package/dist/voice/client.js.map +1 -0
- package/dist/voice/errors.d.ts +43 -0
- package/dist/voice/errors.js +41 -0
- package/dist/voice/errors.js.map +1 -0
- package/dist/voice/index.d.ts +271 -0
- package/dist/voice/index.js +1812 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/react.d.ts +167 -0
- package/dist/voice/react.js +234 -0
- package/dist/voice/react.js.map +1 -0
- package/dist/voice/sfu.d.ts +71 -0
- package/dist/voice/sfu.js +157 -0
- package/dist/voice/sfu.js.map +1 -0
- package/dist/voice/text.d.ts +6 -0
- package/dist/voice/text.js +2 -0
- package/dist/voice/types.d.ts +58 -0
- package/dist/voice/types.js +18 -0
- package/dist/voice/types.js.map +1 -0
- package/dist/voice/workers-ai.d.ts +136 -0
- package/dist/voice/workers-ai.js +568 -0
- package/dist/voice/workers-ai.js.map +1 -0
- package/dist/websockets/index.d.ts +301 -0
- package/dist/websockets/index.js +3 -0
- package/dist/websockets-D7IzWbZb.js +1005 -0
- package/dist/websockets-D7IzWbZb.js.map +1 -0
- package/dist/workflow-types.d.ts +25 -25
- package/dist/workflows.d.ts +21 -21
- package/dist/workflows.js +1 -1
- package/docs/agent-class.md +4 -4
- package/docs/agent-tools.md +2 -1
- package/docs/channels.md +323 -0
- package/docs/chat-agents.md +6 -13
- package/docs/client-sdk.md +30 -0
- package/docs/context.md +131 -0
- package/docs/index.md +16 -13
- package/docs/lifecycle.md +179 -57
- package/docs/long-running-agents.md +2 -2
- package/docs/mcp-servers.md +5 -1
- package/docs/queue.md +135 -241
- package/docs/resumable-streaming.md +1 -1
- package/docs/retries.md +1 -1
- package/docs/routing.md +105 -0
- package/docs/sessions.md +237 -871
- package/docs/streams.md +213 -0
- package/docs/sub-agents.md +184 -124
- package/docs/tasks.md +246 -0
- package/docs/voice.md +745 -0
- package/package.json +126 -14
- package/dist/capability-BjSKYpzg.js.map +0 -1
- package/dist/capability-runner-CvHGZqUu.d.ts +0 -150
- package/dist/client.js.map +0 -1
- package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
- package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
- package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
- package/dist/current-agent-CuMErtly.d.ts +0 -283
- package/dist/diagnostics-CaBjfz4J.js.map +0 -1
- package/dist/durable-object-lifecycle-D6nNQJJd.js +0 -862
- package/dist/durable-object-lifecycle-D6nNQJJd.js.map +0 -1
- package/dist/experimental/memory/session/index.d.ts +0 -671
- package/dist/experimental/memory/session/index.js +0 -2379
- package/dist/experimental/memory/session/index.js.map +0 -1
- package/dist/experimental/memory/utils/index.d.ts +0 -96
- package/dist/experimental/memory/utils/index.js +0 -79
- package/dist/experimental/memory/utils/index.js.map +0 -1
- package/dist/scheduler-CR9RHGos.js +0 -857
- package/dist/scheduler-CR9RHGos.js.map +0 -1
- package/dist/src-5W6JNKVb.js.map +0 -1
- package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
- package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
|
@@ -0,0 +1,272 @@
|
|
|
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 { t as TextSegmentJoiner } from "./text-segment-joiner-BtAFQSA_.js";
|
|
4
|
+
//#region src/voice/sentence-chunker.ts
|
|
5
|
+
/**
|
|
6
|
+
* Sentence chunker — accumulates streaming text and yields complete sentences.
|
|
7
|
+
*
|
|
8
|
+
* Isolated and testable: no dependencies on the voice pipeline, Agent, or AI APIs.
|
|
9
|
+
* Feed it tokens via `add()`, get back sentences via the return value.
|
|
10
|
+
* Call `flush()` at end-of-stream to get any remaining text.
|
|
11
|
+
*
|
|
12
|
+
* Current implementation: splits on sentence-ending punctuation (. ! ?) followed
|
|
13
|
+
* by a space or end-of-input. This is intentionally simple — optimize later with
|
|
14
|
+
* better heuristics (abbreviations, decimal numbers, quoted speech, etc.).
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Punctuation characters that can end a sentence.
|
|
18
|
+
*/
|
|
19
|
+
const SENTENCE_TERMINATORS = /* @__PURE__ */ new Set([
|
|
20
|
+
".",
|
|
21
|
+
"!",
|
|
22
|
+
"?"
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* Minimum character count before we'll emit a sentence.
|
|
26
|
+
* Prevents emitting fragments like "Dr." or "U.S." as standalone sentences,
|
|
27
|
+
* while still allowing short responses like "Sure thing!" to stream quickly.
|
|
28
|
+
*/
|
|
29
|
+
const MIN_SENTENCE_LENGTH = 10;
|
|
30
|
+
var _buffer = /* @__PURE__ */ new WeakMap();
|
|
31
|
+
var _SentenceChunker_brand = /* @__PURE__ */ new WeakSet();
|
|
32
|
+
var SentenceChunker = class {
|
|
33
|
+
constructor() {
|
|
34
|
+
_classPrivateMethodInitSpec(this, _SentenceChunker_brand);
|
|
35
|
+
_classPrivateFieldInitSpec(this, _buffer, "");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Add a chunk of text (e.g. a streamed LLM token).
|
|
39
|
+
* Returns an array of complete sentences extracted from the buffer.
|
|
40
|
+
* May return 0, 1, or multiple sentences depending on the input.
|
|
41
|
+
*/
|
|
42
|
+
add(text) {
|
|
43
|
+
_classPrivateFieldSet2(_buffer, this, _classPrivateFieldGet2(_buffer, this) + text);
|
|
44
|
+
return _assertClassBrand(_SentenceChunker_brand, this, _extractSentences).call(this);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Flush any remaining text in the buffer as a final sentence.
|
|
48
|
+
* Call this when the LLM stream ends.
|
|
49
|
+
* Returns the remaining text (trimmed), or an empty array if nothing is left.
|
|
50
|
+
*/
|
|
51
|
+
flush() {
|
|
52
|
+
const remaining = _classPrivateFieldGet2(_buffer, this).trim();
|
|
53
|
+
_classPrivateFieldSet2(_buffer, this, "");
|
|
54
|
+
if (remaining.length > 0) return [remaining];
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reset the chunker, discarding any buffered text.
|
|
59
|
+
*/
|
|
60
|
+
reset() {
|
|
61
|
+
_classPrivateFieldSet2(_buffer, this, "");
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Extract complete sentences from the buffer.
|
|
66
|
+
* A sentence boundary is a terminator (. ! ?) followed by:
|
|
67
|
+
* - a space and an uppercase letter (start of next sentence)
|
|
68
|
+
* - a space and end of current buffer (likely a boundary)
|
|
69
|
+
* - end of buffer after the terminator
|
|
70
|
+
*
|
|
71
|
+
* We leave ambiguous cases in the buffer until more text arrives.
|
|
72
|
+
*/
|
|
73
|
+
function _extractSentences() {
|
|
74
|
+
const sentences = [];
|
|
75
|
+
while (true) {
|
|
76
|
+
const boundary = _assertClassBrand(_SentenceChunker_brand, this, _findSentenceBoundary).call(this);
|
|
77
|
+
if (boundary === -1) break;
|
|
78
|
+
const sentence = _classPrivateFieldGet2(_buffer, this).slice(0, boundary + 1).trim();
|
|
79
|
+
_classPrivateFieldSet2(_buffer, this, _classPrivateFieldGet2(_buffer, this).slice(boundary + 1).trimStart());
|
|
80
|
+
if (sentence.length > 0) sentences.push(sentence);
|
|
81
|
+
}
|
|
82
|
+
return sentences;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Find the index of the end of the first complete sentence in the buffer.
|
|
86
|
+
* Returns -1 if no complete sentence boundary is found.
|
|
87
|
+
*/
|
|
88
|
+
function _findSentenceBoundary() {
|
|
89
|
+
for (let i = 0; i < _classPrivateFieldGet2(_buffer, this).length; i++) {
|
|
90
|
+
const char = _classPrivateFieldGet2(_buffer, this)[i];
|
|
91
|
+
if (!SENTENCE_TERMINATORS.has(char)) continue;
|
|
92
|
+
const nextChar = _classPrivateFieldGet2(_buffer, this)[i + 1];
|
|
93
|
+
if (nextChar === void 0) continue;
|
|
94
|
+
if (nextChar === " " || nextChar === "\n") {
|
|
95
|
+
if (_classPrivateFieldGet2(_buffer, this).slice(0, i + 1).trim().length >= MIN_SENTENCE_LENGTH) return i;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return -1;
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/voice/text-stream.ts
|
|
102
|
+
const warnedTextStreamSources = /* @__PURE__ */ new WeakSet();
|
|
103
|
+
/**
|
|
104
|
+
* Turn any {@link TextSource} into a lazy async generator of string chunks.
|
|
105
|
+
*
|
|
106
|
+
* - `string` → yields the string once (if non-empty).
|
|
107
|
+
* - `ReadableStream<string>` → yields each chunk directly.
|
|
108
|
+
* - `ReadableStream<Uint8Array>` → decodes and parses as newline-delimited
|
|
109
|
+
* JSON (NDJSON) / SSE (`data: …` lines), extracting text from common AI
|
|
110
|
+
* response formats.
|
|
111
|
+
* - `AsyncIterable<string>` → re-yields each chunk.
|
|
112
|
+
*/
|
|
113
|
+
async function* iterateText(source) {
|
|
114
|
+
for await (const event of iterateTextEvents(source)) if (event.type === "text") yield event.text;
|
|
115
|
+
else if (event.type === "error") throw toError(event.error);
|
|
116
|
+
}
|
|
117
|
+
async function* iterateTextEvents(source) {
|
|
118
|
+
if (typeof source === "string") {
|
|
119
|
+
if (source) yield textEvent(source);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (hasCustomAsyncIterator(source)) {
|
|
123
|
+
for await (const event of iterateAsyncTextEvents(source)) yield event;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (source instanceof ReadableStream) {
|
|
127
|
+
const reader = source.getReader();
|
|
128
|
+
const first = await reader.read();
|
|
129
|
+
if (first.done || first.value === void 0) return;
|
|
130
|
+
if (first.value instanceof Uint8Array) {
|
|
131
|
+
const peeked = first.value;
|
|
132
|
+
const combined = new ReadableStream({ async start(controller) {
|
|
133
|
+
controller.enqueue(peeked);
|
|
134
|
+
while (true) {
|
|
135
|
+
const { done, value } = await reader.read();
|
|
136
|
+
if (done) break;
|
|
137
|
+
controller.enqueue(value);
|
|
138
|
+
}
|
|
139
|
+
controller.close();
|
|
140
|
+
} });
|
|
141
|
+
for await (const chunk of parseNDJSON(combined.getReader())) {
|
|
142
|
+
const ai = chunk;
|
|
143
|
+
if (ai.response) yield textEvent(ai.response);
|
|
144
|
+
else if (ai.choices && ai.choices.length > 0) {
|
|
145
|
+
const choice = ai.choices[0];
|
|
146
|
+
if (choice.delta?.content && choice.delta?.role === "assistant") yield textEvent(choice.delta.content);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
} else for await (const event of iterateAsyncTextEvents(readWithFirst(first.value, reader))) yield event;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (Symbol.asyncIterator in source) for await (const event of iterateAsyncTextEvents(source)) yield event;
|
|
153
|
+
}
|
|
154
|
+
async function* readWithFirst(first, reader) {
|
|
155
|
+
yield first;
|
|
156
|
+
while (true) {
|
|
157
|
+
const { done, value } = await reader.read();
|
|
158
|
+
if (done) break;
|
|
159
|
+
yield value;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function hasCustomAsyncIterator(source) {
|
|
163
|
+
const iterator = source[Symbol.asyncIterator];
|
|
164
|
+
if (typeof iterator !== "function") return false;
|
|
165
|
+
if (!(source instanceof ReadableStream)) return true;
|
|
166
|
+
return Object.prototype.hasOwnProperty.call(source, Symbol.asyncIterator) || iterator !== ReadableStream.prototype[Symbol.asyncIterator];
|
|
167
|
+
}
|
|
168
|
+
async function* iterateAsyncTextEvents(source) {
|
|
169
|
+
const textSegmentJoiner = new TextSegmentJoiner();
|
|
170
|
+
for await (const value of source) {
|
|
171
|
+
if (typeof value === "string") {
|
|
172
|
+
warnDeprecatedTextStream(source);
|
|
173
|
+
if (value) yield textEvent(value);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (!isRecord(value)) continue;
|
|
177
|
+
const chunk = value;
|
|
178
|
+
for (const event of textSegmentJoiner.pushChunk(chunk)) yield event;
|
|
179
|
+
switch (chunk.type) {
|
|
180
|
+
case "reasoning-start":
|
|
181
|
+
case "reasoning-end":
|
|
182
|
+
yield chunk;
|
|
183
|
+
break;
|
|
184
|
+
case "reasoning-delta": break;
|
|
185
|
+
case "finish":
|
|
186
|
+
yield chunk;
|
|
187
|
+
break;
|
|
188
|
+
case "error":
|
|
189
|
+
yield {
|
|
190
|
+
type: "error",
|
|
191
|
+
error: toError(chunk.error)
|
|
192
|
+
};
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function textEvent(text) {
|
|
198
|
+
return {
|
|
199
|
+
type: "text",
|
|
200
|
+
text
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function warnDeprecatedTextStream(source) {
|
|
204
|
+
if (!source || !(source instanceof ReadableStream)) return;
|
|
205
|
+
if (warnedTextStreamSources.has(source)) return;
|
|
206
|
+
warnedTextStreamSources.add(source);
|
|
207
|
+
console.warn("[voice] AI SDK textStream is not recommended because non-adjacent text parts may be joined incorrectly. Return result.stream from onTurn() instead.");
|
|
208
|
+
}
|
|
209
|
+
function toError(error) {
|
|
210
|
+
if (error instanceof Error) return error;
|
|
211
|
+
if (typeof error === "string") return new Error(error);
|
|
212
|
+
return new Error("AI SDK stream error", { cause: error });
|
|
213
|
+
}
|
|
214
|
+
function isRecord(value) {
|
|
215
|
+
return typeof value === "object" && value !== null;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Parse a `ReadableStream<Uint8Array>` that contains newline-delimited JSON
|
|
219
|
+
* or Server-Sent Events (`data: {…}` lines). Yields each parsed JSON object.
|
|
220
|
+
*
|
|
221
|
+
* Handles the `data: [DONE]` sentinel used by OpenAI-compatible APIs.
|
|
222
|
+
*/
|
|
223
|
+
async function* parseNDJSON(reader, leftOverBuffer = "") {
|
|
224
|
+
const decoder = new TextDecoder();
|
|
225
|
+
let buffer = leftOverBuffer;
|
|
226
|
+
while (true) {
|
|
227
|
+
const { done, value } = await reader.read();
|
|
228
|
+
if (done) break;
|
|
229
|
+
buffer += decoder.decode(value, { stream: true });
|
|
230
|
+
const lines = buffer.split("\n");
|
|
231
|
+
buffer = lines.pop() ?? "";
|
|
232
|
+
for (const line of lines) {
|
|
233
|
+
const parsed = parseLine(line);
|
|
234
|
+
if (parsed === "DONE") return;
|
|
235
|
+
if (parsed) yield parsed;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (buffer.trim()) {
|
|
239
|
+
const remaining = buffer.split("\n").filter((l) => l.trim());
|
|
240
|
+
for (const line of remaining) {
|
|
241
|
+
const parsed = parseLine(line);
|
|
242
|
+
if (parsed === "DONE") return;
|
|
243
|
+
if (parsed) yield parsed;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function parseLine(line) {
|
|
248
|
+
const trimmed = line.trim();
|
|
249
|
+
if (!trimmed) return null;
|
|
250
|
+
if (trimmed.startsWith("data:")) {
|
|
251
|
+
const json = trimmed.slice(5).trim();
|
|
252
|
+
if (json === "[DONE]") return "DONE";
|
|
253
|
+
try {
|
|
254
|
+
return JSON.parse(json);
|
|
255
|
+
} catch {
|
|
256
|
+
console.warn("[voice] Skipping malformed SSE data:", json);
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (trimmed === "[DONE]") return "DONE";
|
|
261
|
+
if (trimmed.startsWith(":") || trimmed.startsWith("event:") || trimmed.startsWith("id:") || trimmed.startsWith("retry:")) return null;
|
|
262
|
+
try {
|
|
263
|
+
return JSON.parse(trimmed);
|
|
264
|
+
} catch {
|
|
265
|
+
console.warn("[voice] Skipping malformed NDJSON line:", trimmed);
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
//#endregion
|
|
270
|
+
export { iterateTextEvents as n, SentenceChunker as r, iterateText as t };
|
|
271
|
+
|
|
272
|
+
//# sourceMappingURL=text-stream-CpdiKrJB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-stream-CpdiKrJB.js","names":[],"sources":["../src/voice/sentence-chunker.ts","../src/voice/text-stream.ts"],"sourcesContent":["/**\n * Sentence chunker — accumulates streaming text and yields complete sentences.\n *\n * Isolated and testable: no dependencies on the voice pipeline, Agent, or AI APIs.\n * Feed it tokens via `add()`, get back sentences via the return value.\n * Call `flush()` at end-of-stream to get any remaining text.\n *\n * Current implementation: splits on sentence-ending punctuation (. ! ?) followed\n * by a space or end-of-input. This is intentionally simple — optimize later with\n * better heuristics (abbreviations, decimal numbers, quoted speech, etc.).\n */\n\n/**\n * Punctuation characters that can end a sentence.\n */\nconst SENTENCE_TERMINATORS = new Set([\".\", \"!\", \"?\"]);\n\n/**\n * Minimum character count before we'll emit a sentence.\n * Prevents emitting fragments like \"Dr.\" or \"U.S.\" as standalone sentences,\n * while still allowing short responses like \"Sure thing!\" to stream quickly.\n */\nconst MIN_SENTENCE_LENGTH = 10;\n\nexport class SentenceChunker {\n #buffer = \"\";\n\n /**\n * Add a chunk of text (e.g. a streamed LLM token).\n * Returns an array of complete sentences extracted from the buffer.\n * May return 0, 1, or multiple sentences depending on the input.\n */\n add(text: string): string[] {\n this.#buffer += text;\n return this.#extractSentences();\n }\n\n /**\n * Flush any remaining text in the buffer as a final sentence.\n * Call this when the LLM stream ends.\n * Returns the remaining text (trimmed), or an empty array if nothing is left.\n */\n flush(): string[] {\n const remaining = this.#buffer.trim();\n this.#buffer = \"\";\n if (remaining.length > 0) {\n return [remaining];\n }\n return [];\n }\n\n /**\n * Reset the chunker, discarding any buffered text.\n */\n reset() {\n this.#buffer = \"\";\n }\n\n /**\n * Extract complete sentences from the buffer.\n * A sentence boundary is a terminator (. ! ?) followed by:\n * - a space and an uppercase letter (start of next sentence)\n * - a space and end of current buffer (likely a boundary)\n * - end of buffer after the terminator\n *\n * We leave ambiguous cases in the buffer until more text arrives.\n */\n #extractSentences(): string[] {\n const sentences: string[] = [];\n\n while (true) {\n const boundary = this.#findSentenceBoundary();\n if (boundary === -1) break;\n\n const sentence = this.#buffer.slice(0, boundary + 1).trim();\n this.#buffer = this.#buffer.slice(boundary + 1).trimStart();\n\n if (sentence.length > 0) {\n sentences.push(sentence);\n }\n }\n\n return sentences;\n }\n\n /**\n * Find the index of the end of the first complete sentence in the buffer.\n * Returns -1 if no complete sentence boundary is found.\n */\n #findSentenceBoundary(): number {\n for (let i = 0; i < this.#buffer.length; i++) {\n const char = this.#buffer[i];\n\n if (!SENTENCE_TERMINATORS.has(char)) continue;\n\n // Check what follows the terminator\n const nextChar = this.#buffer[i + 1];\n\n // If this is the last character in the buffer, don't split yet —\n // more text might follow (e.g. \"3.14\" or \"Dr. Smith\")\n if (nextChar === undefined) continue;\n\n // Terminator followed by space — likely a real sentence boundary\n if (nextChar === \" \" || nextChar === \"\\n\") {\n // But only if the sentence is long enough to be real\n const candidate = this.#buffer.slice(0, i + 1).trim();\n if (candidate.length >= MIN_SENTENCE_LENGTH) {\n return i;\n }\n }\n }\n\n return -1;\n }\n}\n","import { TextSegmentJoiner } from \"../chat/text-segment-joiner\";\nimport type { TextSegmentChunk } from \"../chat/text-segment-joiner\";\nimport type { VoiceModelFinishReason } from \"./types\";\n\n/**\n * Utilities for normalising various text-producing sources into a uniform\n * `AsyncGenerator<string>`. This lets `onTurn()` return any of:\n *\n * - A plain `string`\n * - An `AsyncIterable<string>` (deprecated for AI SDK `textStream`)\n * - An `AsyncIterable` of AI SDK `stream` parts\n * - A `ReadableStream<Uint8Array>` (e.g. a raw `fetch` response body\n * containing newline-delimited JSON / SSE)\n * - A `ReadableStream<string>`\n *\n * The generator yields individual text chunks as they become available.\n */\n\n/** Union of every source type that {@link iterateText} accepts. */\nexport type TextSource = string | TextReadableStream | AsyncIterable<unknown>;\n\n/** @internal Semantic events retained while normalizing model streams. */\nexport type TextStreamEvent =\n | { type: \"text\"; text: string }\n | { type: \"boundary\" }\n | { type: \"reasoning-start\" }\n | { type: \"reasoning-end\" }\n | { type: \"finish\"; finishReason: VoiceModelFinishReason }\n | { type: \"error\"; error: Error };\n\ntype TextReadableStreamReader = {\n read(): Promise<ReadableStreamReadResult<unknown>>;\n};\n\ninterface TextReadableStream {\n getReader(): TextReadableStreamReader;\n}\n\n/** Shape of a parsed NDJSON/SSE chunk from common AI APIs. */\ninterface AIStreamChunk {\n response?: string;\n choices?: {\n delta?: { content?: string; role?: string };\n }[];\n}\n\ninterface StructuredStreamChunk extends TextSegmentChunk {\n type?: string;\n error?: unknown;\n finishReason?: VoiceModelFinishReason;\n}\n\nconst warnedTextStreamSources = new WeakSet<object>();\n\n/**\n * Turn any {@link TextSource} into a lazy async generator of string chunks.\n *\n * - `string` → yields the string once (if non-empty).\n * - `ReadableStream<string>` → yields each chunk directly.\n * - `ReadableStream<Uint8Array>` → decodes and parses as newline-delimited\n * JSON (NDJSON) / SSE (`data: …` lines), extracting text from common AI\n * response formats.\n * - `AsyncIterable<string>` → re-yields each chunk.\n */\nexport async function* iterateText(source: TextSource): AsyncGenerator<string> {\n for await (const event of iterateTextEvents(source)) {\n if (event.type === \"text\") {\n yield event.text;\n } else if (event.type === \"error\") {\n throw toError(event.error);\n }\n }\n}\n\nexport async function* iterateTextEvents(\n source: TextSource\n): AsyncGenerator<TextStreamEvent> {\n // --- plain string ---\n if (typeof source === \"string\") {\n if (source) yield textEvent(source);\n return;\n }\n\n // --- Custom AsyncIterable ---\n // AI SDK textStream/stream are ReadableStreams with custom async\n // iterators. Prefer those custom iterators before the generic ReadableStream\n // parser, while still letting native ReadableStream async iteration fall\n // through to the stream-specific branches below.\n if (hasCustomAsyncIterator(source)) {\n for await (const event of iterateAsyncTextEvents(\n source as AsyncIterable<unknown>\n )) {\n yield event;\n }\n return;\n }\n\n // --- ReadableStream ---\n if (source instanceof ReadableStream) {\n const reader = source.getReader();\n\n const first = await reader.read();\n if (first.done || first.value === undefined) return;\n\n if (first.value instanceof Uint8Array) {\n // ReadableStream<Uint8Array> — re-assemble into an NDJSON stream\n // by pushing the already-read first chunk back into a new stream.\n const peeked = first.value as Uint8Array;\n const combined = new ReadableStream<Uint8Array>({\n async start(controller) {\n controller.enqueue(peeked);\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n controller.enqueue(value as Uint8Array);\n }\n controller.close();\n }\n });\n\n for await (const chunk of parseNDJSON(combined.getReader())) {\n const ai = chunk as AIStreamChunk;\n if (ai.response) {\n yield textEvent(ai.response);\n } else if (ai.choices && ai.choices.length > 0) {\n const choice = ai.choices[0];\n if (choice.delta?.content && choice.delta?.role === \"assistant\") {\n yield textEvent(choice.delta.content);\n }\n }\n }\n } else {\n for await (const event of iterateAsyncTextEvents(\n readWithFirst(first.value, reader)\n )) {\n yield event;\n }\n }\n return;\n }\n\n // --- AsyncIterable ---\n if (Symbol.asyncIterator in source) {\n for await (const event of iterateAsyncTextEvents(source)) {\n yield event;\n }\n }\n}\n\nasync function* readWithFirst(\n first: unknown,\n reader: TextReadableStreamReader\n): AsyncGenerator<unknown> {\n yield first;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n yield value;\n }\n}\n\nfunction hasCustomAsyncIterator(source: Exclude<TextSource, string>): boolean {\n const iterator = (source as Partial<AsyncIterable<unknown>>)[\n Symbol.asyncIterator\n ];\n\n if (typeof iterator !== \"function\") return false;\n\n if (!(source instanceof ReadableStream)) return true;\n\n return (\n Object.prototype.hasOwnProperty.call(source, Symbol.asyncIterator) ||\n iterator !==\n (ReadableStream.prototype as Partial<AsyncIterable<unknown>>)[\n Symbol.asyncIterator\n ]\n );\n}\n\nasync function* iterateAsyncTextEvents(\n source: AsyncIterable<unknown>\n): AsyncGenerator<TextStreamEvent> {\n const textSegmentJoiner = new TextSegmentJoiner();\n\n for await (const value of source) {\n if (typeof value === \"string\") {\n warnDeprecatedTextStream(source);\n if (value) yield textEvent(value);\n continue;\n }\n\n if (!isRecord(value)) continue;\n const chunk = value as StructuredStreamChunk;\n\n for (const event of textSegmentJoiner.pushChunk(chunk)) {\n yield event;\n }\n\n switch (chunk.type) {\n case \"reasoning-start\":\n case \"reasoning-end\":\n yield chunk as TextStreamEvent;\n break;\n case \"reasoning-delta\":\n break;\n case \"finish\":\n yield chunk as TextStreamEvent;\n break;\n case \"error\":\n yield { type: \"error\", error: toError(chunk.error) };\n return;\n }\n }\n}\n\nfunction textEvent(text: string): TextStreamEvent {\n return { type: \"text\", text };\n}\n\nfunction warnDeprecatedTextStream(source?: object): void {\n if (!source || !(source instanceof ReadableStream)) return;\n if (warnedTextStreamSources.has(source)) return;\n warnedTextStreamSources.add(source);\n\n console.warn(\n \"[voice] AI SDK textStream is not recommended because non-adjacent text parts may be joined incorrectly. Return result.stream from onTurn() instead.\"\n );\n}\n\nfunction toError(error: unknown): Error {\n if (error instanceof Error) return error;\n if (typeof error === \"string\") return new Error(error);\n return new Error(\"AI SDK stream error\", { cause: error });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\n// ---------------------------------------------------------------------------\n// Internal: NDJSON / SSE stream parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parse a `ReadableStream<Uint8Array>` that contains newline-delimited JSON\n * or Server-Sent Events (`data: {…}` lines). Yields each parsed JSON object.\n *\n * Handles the `data: [DONE]` sentinel used by OpenAI-compatible APIs.\n */\nasync function* parseNDJSON(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n leftOverBuffer = \"\"\n): AsyncGenerator<Record<string, unknown>> {\n const decoder = new TextDecoder();\n let buffer = leftOverBuffer;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const parsed = parseLine(line);\n if (parsed === \"DONE\") return;\n if (parsed) yield parsed;\n }\n }\n\n // Flush remaining buffer\n if (buffer.trim()) {\n const remaining = buffer.split(\"\\n\").filter((l) => l.trim());\n for (const line of remaining) {\n const parsed = parseLine(line);\n if (parsed === \"DONE\") return;\n if (parsed) yield parsed;\n }\n }\n}\n\nfunction parseLine(line: string): Record<string, unknown> | \"DONE\" | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n\n if (trimmed.startsWith(\"data:\")) {\n const json = trimmed.slice(5).trim();\n if (json === \"[DONE]\") return \"DONE\";\n try {\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n console.warn(\"[voice] Skipping malformed SSE data:\", json);\n return null;\n }\n }\n\n if (trimmed === \"[DONE]\") return \"DONE\";\n\n // Ignore SSE metadata/comment lines. Only `data:` carries payload.\n if (\n trimmed.startsWith(\":\") ||\n trimmed.startsWith(\"event:\") ||\n trimmed.startsWith(\"id:\") ||\n trimmed.startsWith(\"retry:\")\n ) {\n return null;\n }\n\n try {\n return JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n console.warn(\"[voice] Skipping malformed NDJSON line:\", trimmed);\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAeA,MAAM,uCAAuB,IAAI,IAAI;CAAC;CAAK;CAAK;AAAG,CAAC;;;;;;AAOpD,MAAM,sBAAsB;;;AAE5B,IAAa,kBAAb,MAA6B;;;4CACjB,EAAA;;;;;;;CAOV,IAAI,MAAwB;EAC1B,uBAAA,SAAA,MAAA,uBAAA,SAAA,IAAA,IAAgB,IAAA;EAChB,OAAA,kBAAA,wBAAO,MAAA,iBAAA,CAAA,CAAA,KAAA,IAAuB;CAChC;;;;;;CAOA,QAAkB;EAChB,MAAM,YAAA,uBAAA,SAAY,IAAA,CAAA,CAAa,KAAK;EACpC,uBAAA,SAAA,MAAe,EAAA;EACf,IAAI,UAAU,SAAS,GACrB,OAAO,CAAC,SAAS;EAEnB,OAAO,CAAC;CACV;;;;CAKA,QAAQ;EACN,uBAAA,SAAA,MAAe,EAAA;CACjB;AA0DF;;;;;;;;;;AA/CE,SAAA,oBAA8B;CAC5B,MAAM,YAAsB,CAAC;CAE7B,OAAO,MAAM;EACX,MAAM,WAAA,kBAAA,wBAAW,MAAA,qBAAA,CAAA,CAAA,KAAA,IAA2B;EAC5C,IAAI,aAAa,IAAI;EAErB,MAAM,WAAA,uBAAA,SAAW,IAAA,CAAA,CAAa,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK;EAC1D,uBAAA,SAAA,MAAA,uBAAA,SAAe,IAAA,CAAA,CAAa,MAAM,WAAW,CAAC,CAAC,CAAC,UAAU,CAAA;EAE1D,IAAI,SAAS,SAAS,GACpB,UAAU,KAAK,QAAQ;CAE3B;CAEA,OAAO;AACT;;;;;AAMA,SAAA,wBAAgC;CAC9B,KAAK,IAAI,IAAI,GAAG,IAAA,uBAAA,SAAI,IAAA,CAAA,CAAa,QAAQ,KAAK;EAC5C,MAAM,OAAA,uBAAA,SAAO,IAAA,CAAA,CAAa;EAE1B,IAAI,CAAC,qBAAqB,IAAI,IAAI,GAAG;EAGrC,MAAM,WAAA,uBAAA,SAAW,IAAA,CAAA,CAAa,IAAI;EAIlC,IAAI,aAAa,KAAA,GAAW;EAG5B,IAAI,aAAa,OAAO,aAAa;uCAEjB,IAAA,CAAA,CAAa,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KACnC,CAAC,CAAC,UAAU,qBACtB,OAAO;EAAA;CAGb;CAEA,OAAO;AACT;;;AC7DF,MAAM,0CAA0B,IAAI,QAAgB;;;;;;;;;;;AAYpD,gBAAuB,YAAY,QAA4C;CAC7E,WAAW,MAAM,SAAS,kBAAkB,MAAM,GAChD,IAAI,MAAM,SAAS,QACjB,MAAM,MAAM;MACP,IAAI,MAAM,SAAS,SACxB,MAAM,QAAQ,MAAM,KAAK;AAG/B;AAEA,gBAAuB,kBACrB,QACiC;CAEjC,IAAI,OAAO,WAAW,UAAU;EAC9B,IAAI,QAAQ,MAAM,UAAU,MAAM;EAClC;CACF;CAOA,IAAI,uBAAuB,MAAM,GAAG;EAClC,WAAW,MAAM,SAAS,uBACxB,MACF,GACE,MAAM;EAER;CACF;CAGA,IAAI,kBAAkB,gBAAgB;EACpC,MAAM,SAAS,OAAO,UAAU;EAEhC,MAAM,QAAQ,MAAM,OAAO,KAAK;EAChC,IAAI,MAAM,QAAQ,MAAM,UAAU,KAAA,GAAW;EAE7C,IAAI,MAAM,iBAAiB,YAAY;GAGrC,MAAM,SAAS,MAAM;GACrB,MAAM,WAAW,IAAI,eAA2B,EAC9C,MAAM,MAAM,YAAY;IACtB,WAAW,QAAQ,MAAM;IACzB,OAAO,MAAM;KACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;KAC1C,IAAI,MAAM;KACV,WAAW,QAAQ,KAAmB;IACxC;IACA,WAAW,MAAM;GACnB,EACF,CAAC;GAED,WAAW,MAAM,SAAS,YAAY,SAAS,UAAU,CAAC,GAAG;IAC3D,MAAM,KAAK;IACX,IAAI,GAAG,UACL,MAAM,UAAU,GAAG,QAAQ;SACtB,IAAI,GAAG,WAAW,GAAG,QAAQ,SAAS,GAAG;KAC9C,MAAM,SAAS,GAAG,QAAQ;KAC1B,IAAI,OAAO,OAAO,WAAW,OAAO,OAAO,SAAS,aAClD,MAAM,UAAU,OAAO,MAAM,OAAO;IAExC;GACF;EACF,OACE,WAAW,MAAM,SAAS,uBACxB,cAAc,MAAM,OAAO,MAAM,CACnC,GACE,MAAM;EAGV;CACF;CAGA,IAAI,OAAO,iBAAiB,QAC1B,WAAW,MAAM,SAAS,uBAAuB,MAAM,GACrD,MAAM;AAGZ;AAEA,gBAAgB,cACd,OACA,QACyB;CACzB,MAAM;CAEN,OAAO,MAAM;EACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;EAC1C,IAAI,MAAM;EACV,MAAM;CACR;AACF;AAEA,SAAS,uBAAuB,QAA8C;CAC5E,MAAM,WAAY,OAChB,OAAO;CAGT,IAAI,OAAO,aAAa,YAAY,OAAO;CAE3C,IAAI,EAAE,kBAAkB,iBAAiB,OAAO;CAEhD,OACE,OAAO,UAAU,eAAe,KAAK,QAAQ,OAAO,aAAa,KACjE,aACG,eAAe,UACd,OAAO;AAGf;AAEA,gBAAgB,uBACd,QACiC;CACjC,MAAM,oBAAoB,IAAI,kBAAkB;CAEhD,WAAW,MAAM,SAAS,QAAQ;EAChC,IAAI,OAAO,UAAU,UAAU;GAC7B,yBAAyB,MAAM;GAC/B,IAAI,OAAO,MAAM,UAAU,KAAK;GAChC;EACF;EAEA,IAAI,CAAC,SAAS,KAAK,GAAG;EACtB,MAAM,QAAQ;EAEd,KAAK,MAAM,SAAS,kBAAkB,UAAU,KAAK,GACnD,MAAM;EAGR,QAAQ,MAAM,MAAd;GACE,KAAK;GACL,KAAK;IACH,MAAM;IACN;GACF,KAAK,mBACH;GACF,KAAK;IACH,MAAM;IACN;GACF,KAAK;IACH,MAAM;KAAE,MAAM;KAAS,OAAO,QAAQ,MAAM,KAAK;IAAE;IACnD;EACJ;CACF;AACF;AAEA,SAAS,UAAU,MAA+B;CAChD,OAAO;EAAE,MAAM;EAAQ;CAAK;AAC9B;AAEA,SAAS,yBAAyB,QAAuB;CACvD,IAAI,CAAC,UAAU,EAAE,kBAAkB,iBAAiB;CACpD,IAAI,wBAAwB,IAAI,MAAM,GAAG;CACzC,wBAAwB,IAAI,MAAM;CAElC,QAAQ,KACN,qJACF;AACF;AAEA,SAAS,QAAQ,OAAuB;CACtC,IAAI,iBAAiB,OAAO,OAAO;CACnC,IAAI,OAAO,UAAU,UAAU,OAAO,IAAI,MAAM,KAAK;CACrD,OAAO,IAAI,MAAM,uBAAuB,EAAE,OAAO,MAAM,CAAC;AAC1D;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;;;;;;;AAYA,gBAAgB,YACd,QACA,iBAAiB,IACwB;CACzC,MAAM,UAAU,IAAI,YAAY;CAChC,IAAI,SAAS;CAEb,OAAO,MAAM;EACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;EAC1C,IAAI,MAAM;EAEV,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;EAEhD,MAAM,QAAQ,OAAO,MAAM,IAAI;EAC/B,SAAS,MAAM,IAAI,KAAK;EAExB,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,SAAS,UAAU,IAAI;GAC7B,IAAI,WAAW,QAAQ;GACvB,IAAI,QAAQ,MAAM;EACpB;CACF;CAGA,IAAI,OAAO,KAAK,GAAG;EACjB,MAAM,YAAY,OAAO,MAAM,IAAI,CAAC,CAAC,QAAQ,MAAM,EAAE,KAAK,CAAC;EAC3D,KAAK,MAAM,QAAQ,WAAW;GAC5B,MAAM,SAAS,UAAU,IAAI;GAC7B,IAAI,WAAW,QAAQ;GACvB,IAAI,QAAQ,MAAM;EACpB;CACF;AACF;AAEA,SAAS,UAAU,MAAuD;CACxE,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI,QAAQ,WAAW,OAAO,GAAG;EAC/B,MAAM,OAAO,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK;EACnC,IAAI,SAAS,UAAU,OAAO;EAC9B,IAAI;GACF,OAAO,KAAK,MAAM,IAAI;EACxB,QAAQ;GACN,QAAQ,KAAK,wCAAwC,IAAI;GACzD,OAAO;EACT;CACF;CAEA,IAAI,YAAY,UAAU,OAAO;CAGjC,IACE,QAAQ,WAAW,GAAG,KACtB,QAAQ,WAAW,QAAQ,KAC3B,QAAQ,WAAW,KAAK,KACxB,QAAQ,WAAW,QAAQ,GAE3B,OAAO;CAGT,IAAI;EACF,OAAO,KAAK,MAAM,OAAO;CAC3B,QAAQ;EACN,QAAQ,KAAK,2CAA2C,OAAO;EAC/D,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Approximate token multiplier per whitespace-separated word */
|
|
2
|
+
const WORDS_TOKEN_MULTIPLIER = 1.3;
|
|
3
|
+
/** Flat token charge for an image attachment (vision-model ballpark). */
|
|
4
|
+
const IMAGE_ATTACHMENT_TOKENS = 1600;
|
|
5
|
+
/** Ceiling for a non-image attachment's bytes/4 token charge. */
|
|
6
|
+
const MAX_ATTACHMENT_TOKENS = 2e4;
|
|
7
|
+
function estimateStringTokens(text) {
|
|
8
|
+
if (!text) return 0;
|
|
9
|
+
const charEstimate = text.length / 4;
|
|
10
|
+
const wordEstimate = text.split(/\s+/).filter(Boolean).length * WORDS_TOKEN_MULTIPLIER;
|
|
11
|
+
return Math.ceil(Math.max(charEstimate, wordEstimate));
|
|
12
|
+
}
|
|
13
|
+
function estimateUnknownTokens(value) {
|
|
14
|
+
if (value === null || value === void 0) return 0;
|
|
15
|
+
if (typeof value === "string") return estimateStringTokens(value);
|
|
16
|
+
try {
|
|
17
|
+
return estimateStringTokens(JSON.stringify(value));
|
|
18
|
+
} catch {
|
|
19
|
+
return estimateStringTokens(String(value));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Estimate tokens for messages from their text, reasoning, and tool parts. */
|
|
23
|
+
function estimateMessageTokens(messages) {
|
|
24
|
+
let tokens = 0;
|
|
25
|
+
for (const msg of messages) {
|
|
26
|
+
tokens += 4;
|
|
27
|
+
for (const part of msg.parts) if (part.type === "text" || part.type === "reasoning") tokens += estimateUnknownTokens(part.text ?? part.reasoning);
|
|
28
|
+
else if (part.type.startsWith("tool-") || part.type === "dynamic-tool") {
|
|
29
|
+
tokens += estimateUnknownTokens(part.input);
|
|
30
|
+
tokens += estimateUnknownTokens(part.output ?? part.result);
|
|
31
|
+
} else if (part.text !== void 0) tokens += estimateUnknownTokens(part.text);
|
|
32
|
+
else if (part.result !== void 0) tokens += estimateUnknownTokens(part.result);
|
|
33
|
+
}
|
|
34
|
+
return tokens;
|
|
35
|
+
}
|
|
36
|
+
/** Heuristic token weight of one attachment so media never counts as zero. */
|
|
37
|
+
function estimateAttachmentTokens(mediaType, bytes) {
|
|
38
|
+
if (mediaType.startsWith("image/")) return IMAGE_ATTACHMENT_TOKENS;
|
|
39
|
+
return Math.min(Math.ceil(bytes / 4), MAX_ATTACHMENT_TOKENS);
|
|
40
|
+
}
|
|
41
|
+
/** Approximate decoded size of a `data:` URL without decoding it. */
|
|
42
|
+
function estimatedDataUrlBytes(url) {
|
|
43
|
+
const comma = url.indexOf(",");
|
|
44
|
+
if (!url.startsWith("data:") || comma < 0) return 0;
|
|
45
|
+
const header = url.slice(5, comma);
|
|
46
|
+
const payload = url.slice(comma + 1);
|
|
47
|
+
return header.endsWith(";base64") ? Math.floor(payload.length * 3 / 4) : payload.length;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { estimatedDataUrlBytes as i, estimateMessageTokens as n, estimateStringTokens as r, estimateAttachmentTokens as t };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=tokens-nHAKcN6M.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens-nHAKcN6M.js","names":[],"sources":["../src/sessions/tokens.ts"],"sourcesContent":["/**\n * Token estimation heuristics.\n *\n * Real tokenizers cost ~100 MB of heap, so Sessions estimates: the larger of\n * ~4 characters per token and ~1.3 tokens per word, plus a small per-message\n * framing charge. Attachments get a flat image charge or a bytes/4 charge\n * capped so a large document cannot dominate a compaction trigger. These\n * numbers gate cheap triggers only; model-reported usage stays authoritative.\n */\n\nimport type { SessionMessage } from \"./types\";\n\n/** Approximate characters per token for English text */\nexport const CHARS_PER_TOKEN = 4;\n\n/** Approximate token multiplier per whitespace-separated word */\nexport const WORDS_TOKEN_MULTIPLIER = 1.3;\n\n/** Approximate overhead tokens per message (role, framing) */\nexport const TOKENS_PER_MESSAGE = 4;\n\n/** Flat token charge for an image attachment (vision-model ballpark). */\nexport const IMAGE_ATTACHMENT_TOKENS = 1_600;\n\n/** Ceiling for a non-image attachment's bytes/4 token charge. */\nexport const MAX_ATTACHMENT_TOKENS = 20_000;\n\nexport function estimateStringTokens(text: string): number {\n if (!text) return 0;\n const charEstimate = text.length / CHARS_PER_TOKEN;\n const wordEstimate =\n text.split(/\\s+/).filter(Boolean).length * WORDS_TOKEN_MULTIPLIER;\n return Math.ceil(Math.max(charEstimate, wordEstimate));\n}\n\nfunction estimateUnknownTokens(value: unknown): number {\n if (value === null || value === undefined) return 0;\n if (typeof value === \"string\") return estimateStringTokens(value);\n try {\n return estimateStringTokens(JSON.stringify(value));\n } catch {\n return estimateStringTokens(String(value));\n }\n}\n\n/** Estimate tokens for messages from their text, reasoning, and tool parts. */\nexport function estimateMessageTokens(messages: SessionMessage[]): number {\n let tokens = 0;\n for (const msg of messages) {\n tokens += TOKENS_PER_MESSAGE;\n for (const part of msg.parts) {\n if (part.type === \"text\" || part.type === \"reasoning\") {\n tokens += estimateUnknownTokens(part.text ?? part.reasoning);\n } else if (\n part.type.startsWith(\"tool-\") ||\n part.type === \"dynamic-tool\"\n ) {\n tokens += estimateUnknownTokens(part.input);\n tokens += estimateUnknownTokens(part.output ?? part.result);\n } else if (part.text !== undefined) {\n tokens += estimateUnknownTokens(part.text);\n } else if (part.result !== undefined) {\n tokens += estimateUnknownTokens(part.result);\n }\n }\n }\n return tokens;\n}\n\n/** Heuristic token weight of one attachment so media never counts as zero. */\nexport function estimateAttachmentTokens(\n mediaType: string,\n bytes: number\n): number {\n if (mediaType.startsWith(\"image/\")) return IMAGE_ATTACHMENT_TOKENS;\n return Math.min(Math.ceil(bytes / 4), MAX_ATTACHMENT_TOKENS);\n}\n\n/** Approximate decoded size of a `data:` URL without decoding it. */\nexport function estimatedDataUrlBytes(url: string): number {\n const comma = url.indexOf(\",\");\n if (!url.startsWith(\"data:\") || comma < 0) return 0;\n const header = url.slice(\"data:\".length, comma);\n const payload = url.slice(comma + 1);\n return header.endsWith(\";base64\")\n ? Math.floor((payload.length * 3) / 4)\n : payload.length;\n}\n"],"mappings":";AAgBA,MAAa,yBAAyB;;AAMtC,MAAa,0BAA0B;;AAGvC,MAAa,wBAAwB;AAErC,SAAgB,qBAAqB,MAAsB;CACzD,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,eAAe,KAAK,SAAA;CAC1B,MAAM,eACJ,KAAK,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,SAAS;CAC7C,OAAO,KAAK,KAAK,KAAK,IAAI,cAAc,YAAY,CAAC;AACvD;AAEA,SAAS,sBAAsB,OAAwB;CACrD,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO,qBAAqB,KAAK;CAChE,IAAI;EACF,OAAO,qBAAqB,KAAK,UAAU,KAAK,CAAC;CACnD,QAAQ;EACN,OAAO,qBAAqB,OAAO,KAAK,CAAC;CAC3C;AACF;;AAGA,SAAgB,sBAAsB,UAAoC;CACxE,IAAI,SAAS;CACb,KAAK,MAAM,OAAO,UAAU;EAC1B,UAAA;EACA,KAAK,MAAM,QAAQ,IAAI,OACrB,IAAI,KAAK,SAAS,UAAU,KAAK,SAAS,aACxC,UAAU,sBAAsB,KAAK,QAAQ,KAAK,SAAS;OACtD,IACL,KAAK,KAAK,WAAW,OAAO,KAC5B,KAAK,SAAS,gBACd;GACA,UAAU,sBAAsB,KAAK,KAAK;GAC1C,UAAU,sBAAsB,KAAK,UAAU,KAAK,MAAM;EAC5D,OAAO,IAAI,KAAK,SAAS,KAAA,GACvB,UAAU,sBAAsB,KAAK,IAAI;OACpC,IAAI,KAAK,WAAW,KAAA,GACzB,UAAU,sBAAsB,KAAK,MAAM;CAGjD;CACA,OAAO;AACT;;AAGA,SAAgB,yBACd,WACA,OACQ;CACR,IAAI,UAAU,WAAW,QAAQ,GAAG,OAAO;CAC3C,OAAO,KAAK,IAAI,KAAK,KAAK,QAAQ,CAAC,GAAG,qBAAqB;AAC7D;;AAGA,SAAgB,sBAAsB,KAAqB;CACzD,MAAM,QAAQ,IAAI,QAAQ,GAAG;CAC7B,IAAI,CAAC,IAAI,WAAW,OAAO,KAAK,QAAQ,GAAG,OAAO;CAClD,MAAM,SAAS,IAAI,MAAM,GAAgB,KAAK;CAC9C,MAAM,UAAU,IAAI,MAAM,QAAQ,CAAC;CACnC,OAAO,OAAO,SAAS,SAAS,IAC5B,KAAK,MAAO,QAAQ,SAAS,IAAK,CAAC,IACnC,QAAQ;AACd"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/channels/tool-schema.ts
|
|
2
|
+
const channelMessageJsonSchema = {
|
|
3
|
+
type: "object",
|
|
4
|
+
properties: {
|
|
5
|
+
title: {
|
|
6
|
+
type: "string",
|
|
7
|
+
description: "Optional title or topic for the message"
|
|
8
|
+
},
|
|
9
|
+
markdown: {
|
|
10
|
+
type: "string",
|
|
11
|
+
minLength: 1,
|
|
12
|
+
description: "Message content formatted as Markdown"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
required: ["markdown"],
|
|
16
|
+
additionalProperties: false
|
|
17
|
+
};
|
|
18
|
+
function parseChannelMessage(value) {
|
|
19
|
+
if (typeof value === "object" && value !== null) {
|
|
20
|
+
const candidate = value;
|
|
21
|
+
if (typeof candidate.markdown === "string" && candidate.markdown.length > 0 && (candidate.title === void 0 || typeof candidate.title === "string")) return {
|
|
22
|
+
...typeof candidate.title === "string" ? { title: candidate.title } : {},
|
|
23
|
+
markdown: candidate.markdown
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
throw new Error("Expected an optional string title and a non-empty Markdown string");
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { parseChannelMessage as n, channelMessageJsonSchema as t };
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=tool-schema-CBjGPrsQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-schema-CBjGPrsQ.js","names":[],"sources":["../src/channels/tool-schema.ts"],"sourcesContent":["import type { ChannelMessage } from \"./channel\";\n\nexport const channelMessageJsonSchema: {\n type: \"object\";\n properties: {\n title: { type: \"string\"; description: string };\n markdown: { type: \"string\"; minLength: number; description: string };\n };\n required: string[];\n additionalProperties: false;\n} = {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"Optional title or topic for the message\"\n },\n markdown: {\n type: \"string\",\n minLength: 1,\n description: \"Message content formatted as Markdown\"\n }\n },\n required: [\"markdown\"],\n additionalProperties: false\n};\n\nexport function parseChannelMessage(value: unknown): ChannelMessage {\n if (typeof value === \"object\" && value !== null) {\n const candidate = value as Record<string, unknown>;\n if (\n typeof candidate.markdown === \"string\" &&\n candidate.markdown.length > 0 &&\n (candidate.title === undefined || typeof candidate.title === \"string\")\n ) {\n return {\n ...(typeof candidate.title === \"string\"\n ? { title: candidate.title }\n : {}),\n markdown: candidate.markdown\n };\n }\n }\n\n throw new Error(\n \"Expected an optional string title and a non-empty Markdown string\"\n );\n}\n"],"mappings":";AAEA,MAAa,2BAQT;CACF,MAAM;CACN,YAAY;EACV,OAAO;GACL,MAAM;GACN,aAAa;EACf;EACA,UAAU;GACR,MAAM;GACN,WAAW;GACX,aAAa;EACf;CACF;CACA,UAAU,CAAC,UAAU;CACrB,sBAAsB;AACxB;AAEA,SAAgB,oBAAoB,OAAgC;CAClE,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EAC/C,MAAM,YAAY;EAClB,IACE,OAAO,UAAU,aAAa,YAC9B,UAAU,SAAS,SAAS,MAC3B,UAAU,UAAU,KAAA,KAAa,OAAO,UAAU,UAAU,WAE7D,OAAO;GACL,GAAI,OAAO,UAAU,UAAU,WAC3B,EAAE,OAAO,UAAU,MAAM,IACzB,CAAC;GACL,UAAU,UAAU;EACtB;CAEJ;CAEA,MAAM,IAAI,MACR,mEACF;AACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/websockets/transport-protocol.ts
|
|
2
|
+
/** Query parameter selecting the Cap'n Web connection transport. */
|
|
3
|
+
const CAPNWEB_TRANSPORT_QUERY = "__agents_transport";
|
|
4
|
+
const CAPNWEB_TRANSPORT_VALUE = "capnweb";
|
|
5
|
+
/**
|
|
6
|
+
* The single method on the host's session root: the frame pipe from the
|
|
7
|
+
* client to the host. Every Agent protocol frame travels through it.
|
|
8
|
+
*/
|
|
9
|
+
const CAPNWEB_TRANSPORT_SEND = "__cf_agent_send";
|
|
10
|
+
/** Rewrite a host URL to select the Cap'n Web transport over `ws(s)`. */
|
|
11
|
+
function capnWebTransportUrl(url) {
|
|
12
|
+
const resolved = new URL(url);
|
|
13
|
+
if (resolved.protocol === "http:") resolved.protocol = "ws:";
|
|
14
|
+
if (resolved.protocol === "https:") resolved.protocol = "wss:";
|
|
15
|
+
resolved.searchParams.set(CAPNWEB_TRANSPORT_QUERY, CAPNWEB_TRANSPORT_VALUE);
|
|
16
|
+
return resolved.toString();
|
|
17
|
+
}
|
|
18
|
+
/** Whether a request is a WebSocket upgrade selecting the transport. */
|
|
19
|
+
function isCapnWebTransportUpgrade(request) {
|
|
20
|
+
return request.headers.get("Upgrade")?.toLowerCase() === "websocket" && new URL(request.url).searchParams.get("__agents_transport") === "capnweb";
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { isCapnWebTransportUpgrade as a, capnWebTransportUrl as i, CAPNWEB_TRANSPORT_SEND as n, CAPNWEB_TRANSPORT_VALUE as r, CAPNWEB_TRANSPORT_QUERY as t };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=transport-protocol-BxyngQ_R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-protocol-BxyngQ_R.js","names":[],"sources":["../src/websockets/transport-protocol.ts"],"sourcesContent":["/**\n * Isomorphic wire contract for the Cap'n Web connection transport.\n *\n * Imported by browser bundles and by the Worker runtime, so it must not\n * import `cloudflare:workers`.\n */\n\n/** Wire a `useAgent` / `AgentClient` connection travels on. */\nexport type AgentTransport = \"cf-websocket\" | \"capnweb\";\n\n/** Query parameter selecting the Cap'n Web connection transport. */\nexport const CAPNWEB_TRANSPORT_QUERY = \"__agents_transport\";\nexport const CAPNWEB_TRANSPORT_VALUE = \"capnweb\";\n\n/**\n * The single method on the host's session root: the frame pipe from the\n * client to the host. Every Agent protocol frame travels through it.\n */\nexport const CAPNWEB_TRANSPORT_SEND = \"__cf_agent_send\";\n\nexport type TransportMessage = string | ArrayBuffer | ArrayBufferView;\n\n/** Root the client exposes; the host delivers frames through it. */\nexport type TransportClientEvents = {\n message(value: TransportMessage): void | Promise<void>;\n};\n\n/** Root the host exposes; the client sends frames through it. */\nexport type TransportHostPipe = {\n [CAPNWEB_TRANSPORT_SEND](message: TransportMessage): Promise<void>;\n};\n\n/** Rewrite a host URL to select the Cap'n Web transport over `ws(s)`. */\nexport function capnWebTransportUrl(url: string | URL): string {\n const resolved = new URL(url);\n if (resolved.protocol === \"http:\") resolved.protocol = \"ws:\";\n if (resolved.protocol === \"https:\") resolved.protocol = \"wss:\";\n resolved.searchParams.set(CAPNWEB_TRANSPORT_QUERY, CAPNWEB_TRANSPORT_VALUE);\n return resolved.toString();\n}\n\n/** Whether a request is a WebSocket upgrade selecting the transport. */\nexport function isCapnWebTransportUpgrade(request: Request): boolean {\n return (\n request.headers.get(\"Upgrade\")?.toLowerCase() === \"websocket\" &&\n new URL(request.url).searchParams.get(CAPNWEB_TRANSPORT_QUERY) ===\n CAPNWEB_TRANSPORT_VALUE\n );\n}\n"],"mappings":";;AAWA,MAAa,0BAA0B;AACvC,MAAa,0BAA0B;;;;;AAMvC,MAAa,yBAAyB;;AAetC,SAAgB,oBAAoB,KAA2B;CAC7D,MAAM,WAAW,IAAI,IAAI,GAAG;CAC5B,IAAI,SAAS,aAAa,SAAS,SAAS,WAAW;CACvD,IAAI,SAAS,aAAa,UAAU,SAAS,WAAW;CACxD,SAAS,aAAa,IAAI,yBAAyB,uBAAuB;CAC1E,OAAO,SAAS,SAAS;AAC3B;;AAGA,SAAgB,0BAA0B,SAA2B;CACnE,OACE,QAAQ,QAAQ,IAAI,SAAS,CAAC,EAAE,YAAY,MAAM,eAClD,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,aAAa,IAAA,oBAA2B,MAAA;AAGjE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/websockets/transport-protocol.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Isomorphic wire contract for the Cap'n Web connection transport.
|
|
4
|
+
*
|
|
5
|
+
* Imported by browser bundles and by the Worker runtime, so it must not
|
|
6
|
+
* import `cloudflare:workers`.
|
|
7
|
+
*/
|
|
8
|
+
/** Wire a `useAgent` / `AgentClient` connection travels on. */
|
|
9
|
+
type AgentTransport = "cf-websocket" | "capnweb";
|
|
10
|
+
/** Query parameter selecting the Cap'n Web connection transport. */
|
|
11
|
+
declare const CAPNWEB_TRANSPORT_QUERY = "__agents_transport";
|
|
12
|
+
declare const CAPNWEB_TRANSPORT_VALUE = "capnweb";
|
|
13
|
+
type TransportMessage = string | ArrayBuffer | ArrayBufferView;
|
|
14
|
+
/** Rewrite a host URL to select the Cap'n Web transport over `ws(s)`. */
|
|
15
|
+
declare function capnWebTransportUrl(url: string | URL): string;
|
|
16
|
+
/** Whether a request is a WebSocket upgrade selecting the transport. */
|
|
17
|
+
declare function isCapnWebTransportUpgrade(request: Request): boolean;
|
|
18
|
+
//#endregion
|
|
19
|
+
export {
|
|
20
|
+
capnWebTransportUrl as a,
|
|
21
|
+
TransportMessage as i,
|
|
22
|
+
CAPNWEB_TRANSPORT_QUERY as n,
|
|
23
|
+
isCapnWebTransportUpgrade as o,
|
|
24
|
+
CAPNWEB_TRANSPORT_VALUE as r,
|
|
25
|
+
AgentTransport as t
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=transport-protocol-ZTew5Wso.d.ts.map
|