assistant-stream 0.3.25 → 0.3.27
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 +4 -1
- package/dist/core/AssistantStream.d.ts +0 -1
- package/dist/core/AssistantStream.d.ts.map +1 -1
- package/dist/core/AssistantStreamChunk.d.ts +26 -14
- package/dist/core/AssistantStreamChunk.d.ts.map +1 -1
- package/dist/core/accumulators/AssistantMessageStream.d.ts +0 -1
- package/dist/core/accumulators/AssistantMessageStream.d.ts.map +1 -1
- package/dist/core/accumulators/TimingTracker.d.ts +0 -1
- package/dist/core/accumulators/TimingTracker.d.ts.map +1 -1
- package/dist/core/accumulators/assistant-message-accumulator.d.ts +3 -9
- package/dist/core/accumulators/assistant-message-accumulator.d.ts.map +1 -1
- package/dist/core/accumulators/assistant-message-accumulator.js +70 -28
- package/dist/core/accumulators/assistant-message-accumulator.js.map +1 -1
- package/dist/core/converters/toGenericMessages.d.ts.map +1 -1
- package/dist/core/converters/toGenericMessages.js +2 -1
- package/dist/core/converters/toGenericMessages.js.map +1 -1
- package/dist/core/gorp/GorpStreamAccumulator.d.ts +15 -0
- package/dist/core/gorp/GorpStreamAccumulator.d.ts.map +1 -0
- package/dist/core/{object/ObjectStreamAccumulator.js → gorp/GorpStreamAccumulator.js} +11 -9
- package/dist/core/gorp/GorpStreamAccumulator.js.map +1 -0
- package/dist/core/gorp/GorpStreamDeltaTracker.d.ts +17 -0
- package/dist/core/gorp/GorpStreamDeltaTracker.d.ts.map +1 -0
- package/dist/core/gorp/GorpStreamDeltaTracker.js +38 -0
- package/dist/core/gorp/GorpStreamDeltaTracker.js.map +1 -0
- package/dist/core/gorp/GorpStreamResponse.d.ts +16 -0
- package/dist/core/gorp/GorpStreamResponse.d.ts.map +1 -0
- package/dist/core/gorp/GorpStreamResponse.js +51 -0
- package/dist/core/gorp/GorpStreamResponse.js.map +1 -0
- package/dist/core/gorp/changeTree.d.ts +16 -0
- package/dist/core/gorp/changeTree.d.ts.map +1 -0
- package/dist/core/gorp/changeTree.js +77 -0
- package/dist/core/gorp/changeTree.js.map +1 -0
- package/dist/core/gorp/createGorpStream.d.ts +16 -0
- package/dist/core/gorp/createGorpStream.d.ts.map +1 -0
- package/dist/core/{object/createObjectStream.js → gorp/createGorpStream.js} +13 -8
- package/dist/core/gorp/createGorpStream.js.map +1 -0
- package/dist/core/gorp/types.d.ts +20 -0
- package/dist/core/gorp/types.d.ts.map +1 -0
- package/dist/core/modules/assistant-stream.d.ts +18 -11
- package/dist/core/modules/assistant-stream.d.ts.map +1 -1
- package/dist/core/modules/assistant-stream.js +10 -6
- package/dist/core/modules/assistant-stream.js.map +1 -1
- package/dist/core/modules/text.d.ts +0 -1
- package/dist/core/modules/text.d.ts.map +1 -1
- package/dist/core/modules/tool-call.d.ts +0 -1
- package/dist/core/modules/tool-call.d.ts.map +1 -1
- package/dist/core/modules/tool-call.js +2 -2
- package/dist/core/modules/tool-call.js.map +1 -1
- package/dist/core/serialization/PlainText.d.ts +0 -1
- package/dist/core/serialization/PlainText.d.ts.map +1 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.d.ts +0 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.d.ts.map +1 -1
- package/dist/core/serialization/assistant-transport/AssistantTransport.js +93 -53
- package/dist/core/serialization/assistant-transport/AssistantTransport.js.map +1 -1
- package/dist/core/serialization/data-stream/DataStream.d.ts +0 -1
- package/dist/core/serialization/data-stream/DataStream.d.ts.map +1 -1
- package/dist/core/serialization/data-stream/chunk-types.d.ts +3 -4
- package/dist/core/serialization/data-stream/chunk-types.d.ts.map +1 -1
- package/dist/core/serialization/data-stream/chunk-types.js.map +1 -1
- package/dist/core/serialization/data-stream/serialization.d.ts +0 -1
- package/dist/core/serialization/data-stream/serialization.d.ts.map +1 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts +0 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts.map +1 -1
- package/dist/core/serialization/ui-message-stream/UIMessageStream.js +76 -53
- package/dist/core/serialization/ui-message-stream/UIMessageStream.js.map +1 -1
- package/dist/core/serialization/ui-message-stream/chunk-types.d.ts +0 -1
- package/dist/core/serialization/ui-message-stream/chunk-types.d.ts.map +1 -1
- package/dist/core/tool/ToolCallReader.d.ts +1 -0
- package/dist/core/tool/ToolCallReader.d.ts.map +1 -1
- package/dist/core/tool/ToolCallReader.js.map +1 -1
- package/dist/core/tool/ToolExecutionStream.d.ts +0 -1
- package/dist/core/tool/ToolExecutionStream.d.ts.map +1 -1
- package/dist/core/tool/ToolExecutionStream.js +9 -1
- package/dist/core/tool/ToolExecutionStream.js.map +1 -1
- package/dist/core/tool/ToolResponse.d.ts +6 -4
- package/dist/core/tool/ToolResponse.d.ts.map +1 -1
- package/dist/core/tool/schema-utils.d.ts +0 -1
- package/dist/core/tool/schema-utils.d.ts.map +1 -1
- package/dist/core/tool/tool-types.d.ts +71 -33
- package/dist/core/tool/tool-types.d.ts.map +1 -1
- package/dist/core/tool/toolResultStream.d.ts +3 -2
- package/dist/core/tool/toolResultStream.d.ts.map +1 -1
- package/dist/core/tool/toolResultStream.js +7 -2
- package/dist/core/tool/toolResultStream.js.map +1 -1
- package/dist/core/tool/type-path-utils.d.ts +2 -2
- package/dist/core/tool/type-path-utils.d.ts.map +1 -1
- package/dist/core/utils/Counter.d.ts.map +1 -1
- package/dist/core/utils/generateId.d.ts.map +1 -1
- package/dist/core/utils/stream/AssistantMetaTransformStream.d.ts +0 -1
- package/dist/core/utils/stream/AssistantMetaTransformStream.d.ts.map +1 -1
- package/dist/core/utils/stream/AssistantTransformStream.d.ts +0 -1
- package/dist/core/utils/stream/AssistantTransformStream.d.ts.map +1 -1
- package/dist/core/utils/stream/LineDecoderStream.d.ts +1 -0
- package/dist/core/utils/stream/LineDecoderStream.d.ts.map +1 -1
- package/dist/core/utils/stream/LineDecoderStream.js +19 -6
- package/dist/core/utils/stream/LineDecoderStream.js.map +1 -1
- package/dist/core/utils/stream/PipeableTransformStream.d.ts.map +1 -1
- package/dist/core/utils/stream/SSE.d.ts +0 -1
- package/dist/core/utils/stream/SSE.d.ts.map +1 -1
- package/dist/core/utils/stream/SSE.js +2 -52
- package/dist/core/utils/stream/SSE.js.map +1 -1
- package/dist/core/utils/stream/SSEEventDecoder.d.ts +27 -0
- package/dist/core/utils/stream/SSEEventDecoder.d.ts.map +1 -0
- package/dist/core/utils/stream/SSEEventDecoder.js +84 -0
- package/dist/core/utils/stream/SSEEventDecoder.js.map +1 -0
- package/dist/core/utils/stream/SSEEventDecoderStream.d.ts +13 -0
- package/dist/core/utils/stream/SSEEventDecoderStream.d.ts.map +1 -0
- package/dist/core/utils/stream/SSEEventDecoderStream.js +24 -0
- package/dist/core/utils/stream/SSEEventDecoderStream.js.map +1 -0
- package/dist/core/utils/stream/UnderlyingReadable.d.ts.map +1 -1
- package/dist/core/utils/stream/merge.d.ts +2 -1
- package/dist/core/utils/stream/merge.d.ts.map +1 -1
- package/dist/core/utils/stream/merge.js +27 -8
- package/dist/core/utils/stream/merge.js.map +1 -1
- package/dist/core/utils/stream/path-utils.d.ts +0 -1
- package/dist/core/utils/stream/path-utils.d.ts.map +1 -1
- package/dist/core/utils/types.d.ts +16 -8
- package/dist/core/utils/types.d.ts.map +1 -1
- package/dist/core/utils/withPromiseOrValue.d.ts.map +1 -1
- package/dist/index.d.ts +25 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +3 -3
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +1 -1
- package/dist/resumable/ResumableStreamContext.d.ts +0 -1
- package/dist/resumable/ResumableStreamContext.d.ts.map +1 -1
- package/dist/resumable/ResumableStreamContext.js +12 -5
- package/dist/resumable/ResumableStreamContext.js.map +1 -1
- package/dist/resumable/constants.d.ts.map +1 -1
- package/dist/resumable/createResumableAssistantStreamResponse.d.ts +6 -4
- package/dist/resumable/createResumableAssistantStreamResponse.d.ts.map +1 -1
- package/dist/resumable/errors.d.ts.map +1 -1
- package/dist/resumable/stores/InMemoryResumableStreamStore.d.ts +0 -1
- package/dist/resumable/stores/InMemoryResumableStreamStore.d.ts.map +1 -1
- package/dist/resumable/stores/InMemoryResumableStreamStore.js +2 -1
- package/dist/resumable/stores/InMemoryResumableStreamStore.js.map +1 -1
- package/dist/resumable/stores/ioredis.d.ts +0 -1
- package/dist/resumable/stores/ioredis.d.ts.map +1 -1
- package/dist/resumable/stores/redis-impl.d.ts +2 -2
- package/dist/resumable/stores/redis-impl.d.ts.map +1 -1
- package/dist/resumable/stores/redis.d.ts +0 -1
- package/dist/resumable/stores/redis.d.ts.map +1 -1
- package/dist/resumable/types.d.ts.map +1 -1
- package/dist/utils/AsyncIterableStream.d.ts.map +1 -1
- package/dist/utils/AsyncIterableStream.js +18 -3
- package/dist/utils/AsyncIterableStream.js.map +1 -1
- package/dist/utils/json/fix-json.d.ts.map +1 -1
- package/dist/utils/json/json-value.d.ts.map +1 -1
- package/dist/utils/json/parse-partial-json-object.d.ts +0 -1
- package/dist/utils/json/parse-partial-json-object.d.ts.map +1 -1
- package/dist/utils/promiseWithResolvers.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +2 -1
- package/package.json +5 -5
- package/src/core/AssistantStreamChunk.ts +5 -3
- package/src/core/accumulators/assistant-message-accumulator.test.ts +437 -1
- package/src/core/accumulators/assistant-message-accumulator.ts +89 -26
- package/src/core/{object/ObjectStream.test.ts → gorp/GorpStream.test.ts} +104 -23
- package/src/core/gorp/GorpStreamAccumulator.test.ts +28 -0
- package/src/core/{object/ObjectStreamAccumulator.ts → gorp/GorpStreamAccumulator.ts} +13 -15
- package/src/core/gorp/GorpStreamDeltaTracker.test.ts +182 -0
- package/src/core/gorp/GorpStreamDeltaTracker.ts +55 -0
- package/src/core/gorp/GorpStreamResponse.test.ts +32 -0
- package/src/core/gorp/GorpStreamResponse.ts +88 -0
- package/src/core/gorp/changeTree.test.ts +168 -0
- package/src/core/gorp/changeTree.ts +96 -0
- package/src/core/{object/createObjectStream.ts → gorp/createGorpStream.ts} +23 -17
- package/src/core/{object → gorp}/types.ts +5 -3
- package/src/core/modules/assistant-stream.test.ts +154 -2
- package/src/core/modules/assistant-stream.ts +16 -6
- package/src/core/modules/tool-call.test.ts +67 -0
- package/src/core/modules/tool-call.ts +3 -3
- package/src/core/serialization/assistant-transport/AssistantTransport.test.ts +215 -1
- package/src/core/serialization/assistant-transport/AssistantTransport.ts +83 -71
- package/src/core/serialization/data-stream/chunk-types.ts +2 -2
- package/src/core/serialization/ui-message-stream/UIMessageStream.test.ts +323 -4
- package/src/core/serialization/ui-message-stream/UIMessageStream.ts +81 -71
- package/src/core/tool/ToolExecutionStream.ts +10 -0
- package/src/core/tool/toolResultStream.test.ts +50 -0
- package/src/core/tool/toolResultStream.ts +7 -2
- package/src/core/utils/stream/LineDecoderStream.test.ts +26 -2
- package/src/core/utils/stream/LineDecoderStream.ts +21 -11
- package/src/core/utils/stream/SSE.ts +6 -70
- package/src/core/utils/stream/SSEEventDecoder.test.ts +146 -0
- package/src/core/utils/stream/SSEEventDecoder.ts +109 -0
- package/src/core/utils/stream/SSEEventDecoderStream.test.ts +42 -0
- package/src/core/utils/stream/SSEEventDecoderStream.ts +34 -0
- package/src/core/utils/stream/merge.ts +31 -9
- package/src/gorp.test.ts +42 -0
- package/src/index.ts +21 -6
- package/src/resumable/ResumableStreamContext.test.ts +116 -1
- package/src/resumable/ResumableStreamContext.ts +32 -5
- package/src/resumable/createResumableAssistantStreamResponse.test.ts +1 -25
- package/src/utils/AsyncIterableStream.test.ts +61 -0
- package/src/utils/AsyncIterableStream.ts +18 -3
- package/src/utils.ts +4 -0
- package/dist/core/object/ObjectStreamAccumulator.d.ts +0 -15
- package/dist/core/object/ObjectStreamAccumulator.d.ts.map +0 -1
- package/dist/core/object/ObjectStreamAccumulator.js.map +0 -1
- package/dist/core/object/ObjectStreamResponse.d.ts +0 -17
- package/dist/core/object/ObjectStreamResponse.d.ts.map +0 -1
- package/dist/core/object/ObjectStreamResponse.js +0 -57
- package/dist/core/object/ObjectStreamResponse.js.map +0 -1
- package/dist/core/object/createObjectStream.d.ts +0 -19
- package/dist/core/object/createObjectStream.d.ts.map +0 -1
- package/dist/core/object/createObjectStream.js.map +0 -1
- package/dist/core/object/types.d.ts +0 -18
- package/dist/core/object/types.d.ts.map +0 -1
- package/dist/utils/json/is-json.d.ts +0 -9
- package/dist/utils/json/is-json.d.ts.map +0 -1
- package/dist/utils/json/is-json.js +0 -17
- package/dist/utils/json/is-json.js.map +0 -1
- package/src/core/object/ObjectStreamResponse.ts +0 -109
- package/src/utils/json/is-json.ts +0 -43
- /package/dist/core/{object → gorp}/types.js +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import { createResumableStreamContext } from "./ResumableStreamContext";
|
|
3
3
|
import { ResumableStreamError } from "./errors";
|
|
4
4
|
import { createInMemoryResumableStreamStore } from "./stores/InMemoryResumableStreamStore";
|
|
@@ -8,6 +8,10 @@ const dec = new TextDecoder();
|
|
|
8
8
|
|
|
9
9
|
const bytes = (s: string): Uint8Array => enc.encode(s);
|
|
10
10
|
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
vi.restoreAllMocks();
|
|
13
|
+
});
|
|
14
|
+
|
|
11
15
|
async function collect(stream: ReadableStream<Uint8Array>): Promise<string> {
|
|
12
16
|
const reader = stream.getReader();
|
|
13
17
|
let out = "";
|
|
@@ -271,4 +275,115 @@ describe("createResumableStreamContext", () => {
|
|
|
271
275
|
expect(errors[0]!.id).toBe("a");
|
|
272
276
|
expect((errors[0]!.error as Error).message).toBe("boom");
|
|
273
277
|
});
|
|
278
|
+
|
|
279
|
+
it("continues acquisition when onAcquire throws", async () => {
|
|
280
|
+
const consoleError = vi
|
|
281
|
+
.spyOn(console, "error")
|
|
282
|
+
.mockImplementation(() => {});
|
|
283
|
+
const hookError = new Error("acquire observer failed");
|
|
284
|
+
const store = createInMemoryResumableStreamStore();
|
|
285
|
+
const ctx = createResumableStreamContext({
|
|
286
|
+
store,
|
|
287
|
+
onAcquire: () => {
|
|
288
|
+
throw hookError;
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const stream = await ctx.run("a", () => makeStringStream(["hello"]));
|
|
293
|
+
|
|
294
|
+
expect(await collect(stream)).toBe("hello");
|
|
295
|
+
expect(await ctx.status("a")).toBe("done");
|
|
296
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
297
|
+
"resumable stream onAcquire hook failed:",
|
|
298
|
+
hookError,
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("continues streaming when onAppend throws", async () => {
|
|
303
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
304
|
+
const store = createInMemoryResumableStreamStore();
|
|
305
|
+
const ctx = createResumableStreamContext({
|
|
306
|
+
store,
|
|
307
|
+
onAppend: () => {
|
|
308
|
+
throw new Error("append observer failed");
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const stream = await ctx.run("a", () =>
|
|
313
|
+
makeStringStream(["hello ", "world"]),
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
expect(await collect(stream)).toBe("hello world");
|
|
317
|
+
expect(await ctx.status("a")).toBe("done");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("continues streaming when async onAppend rejects", async () => {
|
|
321
|
+
const consoleError = vi
|
|
322
|
+
.spyOn(console, "error")
|
|
323
|
+
.mockImplementation(() => {});
|
|
324
|
+
const hookError = new Error("async append observer failed");
|
|
325
|
+
const store = createInMemoryResumableStreamStore();
|
|
326
|
+
const ctx = createResumableStreamContext({
|
|
327
|
+
store,
|
|
328
|
+
onAppend: async () => {
|
|
329
|
+
throw hookError;
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const stream = await ctx.run("a", () => makeStringStream(["hello"]));
|
|
334
|
+
|
|
335
|
+
expect(await collect(stream)).toBe("hello");
|
|
336
|
+
expect(await ctx.status("a")).toBe("done");
|
|
337
|
+
await vi.waitFor(() => {
|
|
338
|
+
expect(consoleError).toHaveBeenCalledWith(
|
|
339
|
+
"resumable stream onAppend hook failed:",
|
|
340
|
+
hookError,
|
|
341
|
+
);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("keeps successful completion when onFinalize throws", async () => {
|
|
346
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
347
|
+
const onError = vi.fn();
|
|
348
|
+
const onFinalize = vi.fn(() => {
|
|
349
|
+
throw new Error("finalize observer failed");
|
|
350
|
+
});
|
|
351
|
+
const store = createInMemoryResumableStreamStore();
|
|
352
|
+
const ctx = createResumableStreamContext({ store, onError, onFinalize });
|
|
353
|
+
|
|
354
|
+
const stream = await ctx.run("a", () => makeStringStream(["hello"]));
|
|
355
|
+
|
|
356
|
+
expect(await collect(stream)).toBe("hello");
|
|
357
|
+
expect(await ctx.status("a")).toBe("done");
|
|
358
|
+
expect(onFinalize).toHaveBeenCalledOnce();
|
|
359
|
+
expect(onError).not.toHaveBeenCalled();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it("finalizes producer errors when onError throws", async () => {
|
|
363
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
364
|
+
const tasks: Promise<unknown>[] = [];
|
|
365
|
+
const store = createInMemoryResumableStreamStore();
|
|
366
|
+
const ctx = createResumableStreamContext({
|
|
367
|
+
store,
|
|
368
|
+
waitUntil: (task) => tasks.push(task),
|
|
369
|
+
onError: () => {
|
|
370
|
+
throw new Error("error observer failed");
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
const producerError = new Error("producer failed");
|
|
374
|
+
|
|
375
|
+
const stream = await ctx.run(
|
|
376
|
+
"a",
|
|
377
|
+
() =>
|
|
378
|
+
new ReadableStream<Uint8Array>({
|
|
379
|
+
start(controller) {
|
|
380
|
+
controller.error(producerError);
|
|
381
|
+
},
|
|
382
|
+
}),
|
|
383
|
+
);
|
|
384
|
+
await Promise.allSettled(tasks);
|
|
385
|
+
|
|
386
|
+
expect(await ctx.status("a")).toBe("error");
|
|
387
|
+
await expect(collect(stream)).rejects.toThrow("producer failed");
|
|
388
|
+
});
|
|
274
389
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ResumableStreamError } from "./errors";
|
|
2
|
+
import { withPromiseOrValue } from "../core/utils/withPromiseOrValue";
|
|
2
3
|
import type {
|
|
3
4
|
ResumableStreamRole,
|
|
4
5
|
ResumableStreamStatus,
|
|
@@ -42,6 +43,21 @@ export interface ResumableStreamContext {
|
|
|
42
43
|
delete(streamId: string): Promise<void>;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
const invokeObservabilityHook = <TArgs extends unknown[]>(
|
|
47
|
+
name: string,
|
|
48
|
+
hook: ((...args: TArgs) => void) | undefined,
|
|
49
|
+
...args: TArgs
|
|
50
|
+
): void => {
|
|
51
|
+
if (!hook) return;
|
|
52
|
+
void withPromiseOrValue(
|
|
53
|
+
() => hook(...args),
|
|
54
|
+
() => {},
|
|
55
|
+
(error) => {
|
|
56
|
+
console.error(`resumable stream ${name} hook failed:`, error);
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
45
61
|
export function createResumableStreamContext(
|
|
46
62
|
options: ResumableStreamContextOptions,
|
|
47
63
|
): ResumableStreamContext {
|
|
@@ -53,7 +69,7 @@ export function createResumableStreamContext(
|
|
|
53
69
|
return {
|
|
54
70
|
async run(streamId, makeStream) {
|
|
55
71
|
const role = await store.acquire(streamId, acquireOptions);
|
|
56
|
-
onAcquire
|
|
72
|
+
invokeObservabilityHook("onAcquire", onAcquire, streamId, role);
|
|
57
73
|
if (role === "producer") {
|
|
58
74
|
startProducerTask(store, streamId, makeStream, {
|
|
59
75
|
waitUntil,
|
|
@@ -119,13 +135,18 @@ function startProducerTask(
|
|
|
119
135
|
const { done, value } = await reader.read();
|
|
120
136
|
if (done) break;
|
|
121
137
|
await store.append(streamId, value);
|
|
122
|
-
|
|
138
|
+
invokeObservabilityHook(
|
|
139
|
+
"onAppend",
|
|
140
|
+
onAppend,
|
|
141
|
+
streamId,
|
|
142
|
+
value.byteLength,
|
|
143
|
+
);
|
|
123
144
|
}
|
|
124
145
|
await store.finalize(streamId, "done");
|
|
125
|
-
onFinalize
|
|
146
|
+
invokeObservabilityHook("onFinalize", onFinalize, streamId, "done");
|
|
126
147
|
} catch (err) {
|
|
127
148
|
cancelled = true;
|
|
128
|
-
onError
|
|
149
|
+
invokeObservabilityHook("onError", onError, streamId, err);
|
|
129
150
|
const message = err instanceof Error ? err.message : String(err);
|
|
130
151
|
try {
|
|
131
152
|
await reader?.cancel(err);
|
|
@@ -134,7 +155,13 @@ function startProducerTask(
|
|
|
134
155
|
}
|
|
135
156
|
try {
|
|
136
157
|
await store.finalize(streamId, "error", message);
|
|
137
|
-
|
|
158
|
+
invokeObservabilityHook(
|
|
159
|
+
"onFinalize",
|
|
160
|
+
onFinalize,
|
|
161
|
+
streamId,
|
|
162
|
+
"error",
|
|
163
|
+
message,
|
|
164
|
+
);
|
|
138
165
|
} catch (finalizeErr) {
|
|
139
166
|
console.error("resumable stream finalize failed:", finalizeErr);
|
|
140
167
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
RESUMABLE_STREAM_ID_HEADER,
|
|
4
4
|
createResumableAssistantStreamResponse,
|
|
@@ -140,25 +140,6 @@ describe("createResumableAssistantStreamResponse", () => {
|
|
|
140
140
|
});
|
|
141
141
|
|
|
142
142
|
describe("producer crash", () => {
|
|
143
|
-
let suppressed: unknown[];
|
|
144
|
-
let original: NodeJS.UnhandledRejectionListener[];
|
|
145
|
-
const swallow: NodeJS.UnhandledRejectionListener = (reason) => {
|
|
146
|
-
suppressed.push(reason);
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
beforeEach(() => {
|
|
150
|
-
suppressed = [];
|
|
151
|
-
original = process.listeners("unhandledRejection");
|
|
152
|
-
for (const l of original) process.off("unhandledRejection", l);
|
|
153
|
-
process.on("unhandledRejection", swallow);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
afterEach(async () => {
|
|
157
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
158
|
-
process.off("unhandledRejection", swallow);
|
|
159
|
-
for (const l of original) process.on("unhandledRejection", l);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
143
|
it("synchronous callback throw is encoded into the body and finalizes the stream", async () => {
|
|
163
144
|
const ctx = createResumableStreamContext({
|
|
164
145
|
store: createInMemoryResumableStreamStore(),
|
|
@@ -184,11 +165,6 @@ describe("createResumableAssistantStreamResponse", () => {
|
|
|
184
165
|
expect(replay).not.toBeNull();
|
|
185
166
|
const replayBytes = await new Response(replay).arrayBuffer();
|
|
186
167
|
expect(new Uint8Array(replayBytes)).toEqual(new Uint8Array(firstBytes));
|
|
187
|
-
|
|
188
|
-
while (suppressed.length === 0) {
|
|
189
|
-
await new Promise((r) => setTimeout(r, 5));
|
|
190
|
-
}
|
|
191
|
-
expect(suppressed.map((e) => (e as Error).message)).toContain("boom");
|
|
192
168
|
});
|
|
193
169
|
});
|
|
194
170
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { asAsyncIterableStream } from "./AsyncIterableStream";
|
|
3
|
+
|
|
4
|
+
const forcePolyfilledIterator = <T>(
|
|
5
|
+
stream: ReadableStream<T>,
|
|
6
|
+
): AsyncIterable<T> & ReadableStream<T> => {
|
|
7
|
+
Object.defineProperty(stream, Symbol.asyncIterator, {
|
|
8
|
+
configurable: true,
|
|
9
|
+
value: undefined,
|
|
10
|
+
writable: true,
|
|
11
|
+
});
|
|
12
|
+
return asAsyncIterableStream(stream);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe("asAsyncIterableStream", () => {
|
|
16
|
+
it("cancels the source when iteration stops early", async () => {
|
|
17
|
+
const cancel = vi.fn();
|
|
18
|
+
const stream = forcePolyfilledIterator(
|
|
19
|
+
new ReadableStream<string>({
|
|
20
|
+
start(controller) {
|
|
21
|
+
controller.enqueue("first");
|
|
22
|
+
controller.enqueue("second");
|
|
23
|
+
},
|
|
24
|
+
cancel,
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const values: string[] = [];
|
|
29
|
+
for await (const value of stream) {
|
|
30
|
+
values.push(value);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
expect(values).toEqual(["first"]);
|
|
35
|
+
expect(cancel).toHaveBeenCalledOnce();
|
|
36
|
+
expect(stream.locked).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("does not cancel a fully consumed source", async () => {
|
|
40
|
+
const cancel = vi.fn();
|
|
41
|
+
const stream = forcePolyfilledIterator(
|
|
42
|
+
new ReadableStream<string>({
|
|
43
|
+
start(controller) {
|
|
44
|
+
controller.enqueue("first");
|
|
45
|
+
controller.enqueue("second");
|
|
46
|
+
controller.close();
|
|
47
|
+
},
|
|
48
|
+
cancel,
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const values: string[] = [];
|
|
53
|
+
for await (const value of stream) {
|
|
54
|
+
values.push(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
expect(values).toEqual(["first", "second"]);
|
|
58
|
+
expect(cancel).not.toHaveBeenCalled();
|
|
59
|
+
expect(stream.locked).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -4,14 +4,29 @@ async function* streamGeneratorPolyfill<T>(
|
|
|
4
4
|
this: ReadableStream<T>,
|
|
5
5
|
): AsyncGenerator<T, undefined, unknown> {
|
|
6
6
|
const reader = this.getReader();
|
|
7
|
+
let shouldCancel = true;
|
|
7
8
|
try {
|
|
8
9
|
while (true) {
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
let result: ReadableStreamReadResult<T>;
|
|
11
|
+
try {
|
|
12
|
+
result = await reader.read();
|
|
13
|
+
} catch (error) {
|
|
14
|
+
shouldCancel = false;
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
if (result.done) {
|
|
18
|
+
shouldCancel = false;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
const { value } = result;
|
|
11
22
|
yield value;
|
|
12
23
|
}
|
|
13
24
|
} finally {
|
|
14
|
-
|
|
25
|
+
try {
|
|
26
|
+
if (shouldCancel) await reader.cancel();
|
|
27
|
+
} finally {
|
|
28
|
+
reader.releaseLock();
|
|
29
|
+
}
|
|
15
30
|
}
|
|
16
31
|
}
|
|
17
32
|
|
package/src/utils.ts
CHANGED
|
@@ -15,3 +15,7 @@ export type {
|
|
|
15
15
|
|
|
16
16
|
export { AssistantTransformStream } from "./core/utils/stream/AssistantTransformStream";
|
|
17
17
|
export { AssistantMetaTransformStream } from "./core/utils/stream/AssistantMetaTransformStream";
|
|
18
|
+
export {
|
|
19
|
+
SSEEventDecoder,
|
|
20
|
+
type SSEEvent,
|
|
21
|
+
} from "./core/utils/stream/SSEEventDecoder";
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ReadonlyJSONValue } from "../../utils/json/json-value.js";
|
|
2
|
-
import { ObjectStreamOperation } from "./types.js";
|
|
3
|
-
|
|
4
|
-
//#region src/core/object/ObjectStreamAccumulator.d.ts
|
|
5
|
-
declare class ObjectStreamAccumulator {
|
|
6
|
-
private _state;
|
|
7
|
-
constructor(initialValue?: ReadonlyJSONValue);
|
|
8
|
-
get state(): ReadonlyJSONValue;
|
|
9
|
-
append(ops: readonly ObjectStreamOperation[]): void;
|
|
10
|
-
private static apply;
|
|
11
|
-
private static updatePath;
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
export { ObjectStreamAccumulator };
|
|
15
|
-
//# sourceMappingURL=ObjectStreamAccumulator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectStreamAccumulator.d.ts","names":[],"sources":["../../../src/core/object/ObjectStreamAccumulator.ts"],"mappings":";;;;cAGa,uBAAA;EAAA,QACH,MAAA;cAEI,YAAA,GAAc,iBAAA;EAAA,IAItB,KAAA,IAAK,iBAAA;EAIT,MAAA,CAAO,GAAA,WAAc,qBAAA;EAAA,eAON,KAAA;EAAA,eAuBA,UAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectStreamAccumulator.js","names":["_exhaustiveCheck"],"sources":["../../../src/core/object/ObjectStreamAccumulator.ts"],"sourcesContent":["import type { ReadonlyJSONValue, ReadonlyJSONObject } from \"../../utils\";\nimport type { ObjectStreamOperation } from \"./types\";\n\nexport class ObjectStreamAccumulator {\n private _state: ReadonlyJSONValue;\n\n constructor(initialValue: ReadonlyJSONValue = null) {\n this._state = initialValue;\n }\n\n get state() {\n return this._state;\n }\n\n append(ops: readonly ObjectStreamOperation[]) {\n this._state = ops.reduce(\n (state, op) => ObjectStreamAccumulator.apply(state, op),\n this._state,\n );\n }\n\n private static apply(state: ReadonlyJSONValue, op: ObjectStreamOperation) {\n const type = op.type;\n switch (type) {\n case \"set\":\n return ObjectStreamAccumulator.updatePath(\n state,\n op.path,\n () => op.value,\n );\n case \"append-text\":\n return ObjectStreamAccumulator.updatePath(state, op.path, (current) => {\n if (typeof current !== \"string\")\n throw new Error(`Expected string at path [${op.path.join(\", \")}]`);\n return current + op.value;\n });\n\n default: {\n const _exhaustiveCheck: never = type;\n throw new Error(`Invalid operation type: ${_exhaustiveCheck}`);\n }\n }\n }\n\n private static updatePath(\n state: ReadonlyJSONValue | undefined,\n path: readonly string[],\n updater: (current: ReadonlyJSONValue | undefined) => ReadonlyJSONValue,\n ): ReadonlyJSONValue {\n if (path.length === 0) return updater(state);\n\n // Initialize state as empty object if it's null and we're trying to set a property\n state ??= {};\n\n if (typeof state !== \"object\") {\n throw new Error(`Invalid path: [${path.join(\", \")}]`);\n }\n\n const [key, ...rest] = path as [string, ...(readonly string[])];\n if (Array.isArray(state)) {\n const idx = Number(key);\n if (Number.isNaN(idx))\n throw new Error(`Expected array index at [${path.join(\", \")}]`);\n if (idx > state.length || idx < 0)\n throw new Error(`Insert array index out of bounds`);\n\n const nextState = [...state];\n nextState[idx] = ObjectStreamAccumulator.updatePath(\n nextState[idx],\n rest,\n updater,\n );\n\n return nextState;\n }\n\n const nextState = { ...(state as ReadonlyJSONObject) };\n nextState[key] = ObjectStreamAccumulator.updatePath(\n nextState[key],\n rest,\n updater,\n );\n\n return nextState;\n }\n}\n"],"mappings":";AAGA,IAAa,0BAAb,MAAa,wBAAwB;CACnC;CAEA,YAAY,eAAkC,MAAM;EAClD,KAAK,SAAS;CAChB;CAEA,IAAI,QAAQ;EACV,OAAO,KAAK;CACd;CAEA,OAAO,KAAuC;EAC5C,KAAK,SAAS,IAAI,QACf,OAAO,OAAO,wBAAwB,MAAM,OAAO,EAAE,GACtD,KAAK,MACP;CACF;CAEA,OAAe,MAAM,OAA0B,IAA2B;EACxE,MAAM,OAAO,GAAG;EAChB,QAAQ,MAAR;GACE,KAAK,OACH,OAAO,wBAAwB,WAC7B,OACA,GAAG,YACG,GAAG,KACX;GACF,KAAK,eACH,OAAO,wBAAwB,WAAW,OAAO,GAAG,OAAO,YAAY;IACrE,IAAI,OAAO,YAAY,UACrB,MAAM,IAAI,MAAM,4BAA4B,GAAG,KAAK,KAAK,IAAI,EAAE,EAAE;IACnE,OAAO,UAAU,GAAG;GACtB,CAAC;GAEH,SAEE,MAAM,IAAI,MAAM,2BAA2BA,MAAkB;EAEjE;CACF;CAEA,OAAe,WACb,OACA,MACA,SACmB;EACnB,IAAI,KAAK,WAAW,GAAG,OAAO,QAAQ,KAAK;EAG3C,UAAU,CAAC;EAEX,IAAI,OAAO,UAAU,UACnB,MAAM,IAAI,MAAM,kBAAkB,KAAK,KAAK,IAAI,EAAE,EAAE;EAGtD,MAAM,CAAC,KAAK,GAAG,QAAQ;EACvB,IAAI,MAAM,QAAQ,KAAK,GAAG;GACxB,MAAM,MAAM,OAAO,GAAG;GACtB,IAAI,OAAO,MAAM,GAAG,GAClB,MAAM,IAAI,MAAM,4BAA4B,KAAK,KAAK,IAAI,EAAE,EAAE;GAChE,IAAI,MAAM,MAAM,UAAU,MAAM,GAC9B,MAAM,IAAI,MAAM,kCAAkC;GAEpD,MAAM,YAAY,CAAC,GAAG,KAAK;GAC3B,UAAU,OAAO,wBAAwB,WACvC,UAAU,MACV,MACA,OACF;GAEA,OAAO;EACT;EAEA,MAAM,YAAY,EAAE,GAAI,MAA6B;EACrD,UAAU,OAAO,wBAAwB,WACvC,UAAU,MACV,MACA,OACF;EAEA,OAAO;CACT;AACF"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ObjectStreamChunk } from "./types.js";
|
|
2
|
-
import { PipeableTransformStream } from "../utils/stream/PipeableTransformStream.js";
|
|
3
|
-
|
|
4
|
-
//#region src/core/object/ObjectStreamResponse.d.ts
|
|
5
|
-
declare class ObjectStreamEncoder extends PipeableTransformStream<ObjectStreamChunk, Uint8Array> {
|
|
6
|
-
constructor();
|
|
7
|
-
}
|
|
8
|
-
declare class ObjectStreamDecoder extends PipeableTransformStream<Uint8Array<ArrayBuffer>, ObjectStreamChunk> {
|
|
9
|
-
constructor();
|
|
10
|
-
}
|
|
11
|
-
declare class ObjectStreamResponse extends Response {
|
|
12
|
-
constructor(body: ReadableStream<ObjectStreamChunk>);
|
|
13
|
-
}
|
|
14
|
-
declare const fromObjectStreamResponse: (response: Response) => ReadableStream<ObjectStreamChunk>;
|
|
15
|
-
//#endregion
|
|
16
|
-
export { ObjectStreamDecoder, ObjectStreamEncoder, ObjectStreamResponse, fromObjectStreamResponse };
|
|
17
|
-
//# sourceMappingURL=ObjectStreamResponse.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectStreamResponse.d.ts","names":[],"sources":["../../../src/core/object/ObjectStreamResponse.ts"],"mappings":";;;;cAKa,mBAAA,SAA4B,uBAAA,CACvC,iBAAA,EACA,UAAA;;;cAgDW,mBAAA,SAA4B,uBAAA,CACvC,UAAA,CAAW,WAAA,GACX,iBAAA;;;cAyBW,oBAAA,SAA6B,QAAA;cAC5B,IAAA,EAAM,cAAA,CAAe,iBAAA;AAAA;AAAA,cAYtB,wBAAA,GACX,QAAA,EAAU,QAAA,KACT,cAAA,CAAe,iBAAA"}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { PipeableTransformStream } from "../utils/stream/PipeableTransformStream.js";
|
|
2
|
-
import { ObjectStreamAccumulator } from "./ObjectStreamAccumulator.js";
|
|
3
|
-
import { SSEDecoder, SSEEncoder } from "../utils/stream/SSE.js";
|
|
4
|
-
//#region src/core/object/ObjectStreamResponse.ts
|
|
5
|
-
var ObjectStreamEncoder = class extends PipeableTransformStream {
|
|
6
|
-
constructor() {
|
|
7
|
-
super((readable) => readable.pipeThrough((() => {
|
|
8
|
-
class ObjectStreamTransformer {
|
|
9
|
-
#isFirstChunk = true;
|
|
10
|
-
start() {}
|
|
11
|
-
transform(chunk, controller) {
|
|
12
|
-
if (this.#isFirstChunk && chunk.snapshot && Object.keys(chunk.snapshot).length > 0) controller.enqueue([{
|
|
13
|
-
type: "set",
|
|
14
|
-
path: [],
|
|
15
|
-
value: chunk.snapshot
|
|
16
|
-
}, ...chunk.operations]);
|
|
17
|
-
else controller.enqueue(chunk.operations);
|
|
18
|
-
this.#isFirstChunk = false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return new TransformStream(new ObjectStreamTransformer());
|
|
22
|
-
})()).pipeThrough(new SSEEncoder()));
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
var ObjectStreamDecoder = class extends PipeableTransformStream {
|
|
26
|
-
constructor() {
|
|
27
|
-
const accumulator = new ObjectStreamAccumulator();
|
|
28
|
-
super((readable) => readable.pipeThrough(new SSEDecoder()).pipeThrough(new TransformStream({ transform(operations, controller) {
|
|
29
|
-
accumulator.append(operations);
|
|
30
|
-
controller.enqueue({
|
|
31
|
-
snapshot: accumulator.state,
|
|
32
|
-
operations
|
|
33
|
-
});
|
|
34
|
-
} })));
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
var ObjectStreamResponse = class extends Response {
|
|
38
|
-
constructor(body) {
|
|
39
|
-
super(body.pipeThrough(new ObjectStreamEncoder()), { headers: new Headers({
|
|
40
|
-
"Content-Type": "text/event-stream",
|
|
41
|
-
"Cache-Control": "no-cache",
|
|
42
|
-
Connection: "keep-alive",
|
|
43
|
-
"Assistant-Stream-Format": "object-stream/v0"
|
|
44
|
-
}) });
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
const fromObjectStreamResponse = (response) => {
|
|
48
|
-
if (!response.ok) throw new Error(`Response failed, status ${response.status}`);
|
|
49
|
-
if (!response.body) throw new Error("Response body is null");
|
|
50
|
-
if (response.headers.get("Content-Type") !== "text/event-stream") throw new Error("Response is not an event stream");
|
|
51
|
-
if (response.headers.get("Assistant-Stream-Format") !== "object-stream/v0") throw new Error("Unsupported Assistant-Stream-Format header");
|
|
52
|
-
return response.body.pipeThrough(new ObjectStreamDecoder());
|
|
53
|
-
};
|
|
54
|
-
//#endregion
|
|
55
|
-
export { ObjectStreamDecoder, ObjectStreamEncoder, ObjectStreamResponse, fromObjectStreamResponse };
|
|
56
|
-
|
|
57
|
-
//# sourceMappingURL=ObjectStreamResponse.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectStreamResponse.js","names":["#isFirstChunk"],"sources":["../../../src/core/object/ObjectStreamResponse.ts"],"sourcesContent":["import { PipeableTransformStream } from \"../utils/stream/PipeableTransformStream\";\nimport { ObjectStreamAccumulator } from \"./ObjectStreamAccumulator\";\nimport { SSEDecoder, SSEEncoder } from \"../utils/stream/SSE\";\nimport type { ObjectStreamChunk, ObjectStreamOperation } from \"./types\";\n\nexport class ObjectStreamEncoder extends PipeableTransformStream<\n ObjectStreamChunk,\n Uint8Array\n> {\n constructor() {\n super((readable) =>\n readable\n .pipeThrough(\n (() => {\n class ObjectStreamTransformer implements Transformer<\n ObjectStreamChunk,\n readonly ObjectStreamOperation[]\n > {\n #isFirstChunk = true;\n\n start() {\n // Nothing needed here since we initialize in the field declaration\n }\n\n transform(\n chunk: ObjectStreamChunk,\n controller: TransformStreamDefaultController<\n readonly ObjectStreamOperation[]\n >,\n ) {\n if (\n this.#isFirstChunk &&\n chunk.snapshot &&\n Object.keys(chunk.snapshot).length > 0\n ) {\n // For the first chunk, if there's an initial state that's not empty,\n // prepend a set operation for the initial state\n controller.enqueue([\n { type: \"set\", path: [], value: chunk.snapshot },\n ...chunk.operations,\n ]);\n } else {\n controller.enqueue(chunk.operations);\n }\n this.#isFirstChunk = false;\n }\n }\n return new TransformStream(new ObjectStreamTransformer());\n })(),\n )\n .pipeThrough(new SSEEncoder()),\n );\n }\n}\n\nexport class ObjectStreamDecoder extends PipeableTransformStream<\n Uint8Array<ArrayBuffer>,\n ObjectStreamChunk\n> {\n constructor() {\n const accumulator = new ObjectStreamAccumulator();\n super((readable) =>\n readable\n .pipeThrough(new SSEDecoder<readonly ObjectStreamOperation[]>())\n .pipeThrough(\n new TransformStream<\n readonly ObjectStreamOperation[],\n ObjectStreamChunk\n >({\n transform(operations, controller) {\n accumulator.append(operations);\n controller.enqueue({\n snapshot: accumulator.state,\n operations,\n });\n },\n }),\n ),\n );\n }\n}\n\nexport class ObjectStreamResponse extends Response {\n constructor(body: ReadableStream<ObjectStreamChunk>) {\n super(body.pipeThrough(new ObjectStreamEncoder()), {\n headers: new Headers({\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Assistant-Stream-Format\": \"object-stream/v0\",\n }),\n });\n }\n}\n\nexport const fromObjectStreamResponse = (\n response: Response,\n): ReadableStream<ObjectStreamChunk> => {\n if (!response.ok)\n throw new Error(`Response failed, status ${response.status}`);\n if (!response.body) throw new Error(\"Response body is null\");\n if (response.headers.get(\"Content-Type\") !== \"text/event-stream\") {\n throw new Error(\"Response is not an event stream\");\n }\n if (response.headers.get(\"Assistant-Stream-Format\") !== \"object-stream/v0\") {\n throw new Error(\"Unsupported Assistant-Stream-Format header\");\n }\n return response.body.pipeThrough(new ObjectStreamDecoder());\n};\n"],"mappings":";;;;AAKA,IAAa,sBAAb,cAAyC,wBAGvC;CACA,cAAc;EACZ,OAAO,aACL,SACG,mBACQ;GACL,MAAM,wBAGJ;IACA,gBAAgB;IAEhB,QAAQ,CAER;IAEA,UACE,OACA,YAGA;KACA,IACE,KAAKA,iBACL,MAAM,YACN,OAAO,KAAK,MAAM,QAAQ,CAAC,CAAC,SAAS,GAIrC,WAAW,QAAQ,CACjB;MAAE,MAAM;MAAO,MAAM,CAAC;MAAG,OAAO,MAAM;KAAS,GAC/C,GAAG,MAAM,UACX,CAAC;UAED,WAAW,QAAQ,MAAM,UAAU;KAErC,KAAKA,gBAAgB;IACvB;GACF;GACA,OAAO,IAAI,gBAAgB,IAAI,wBAAwB,CAAC;EAC1D,EAAA,CAAG,CACL,CAAC,CACA,YAAY,IAAI,WAAW,CAAC,CACjC;CACF;AACF;AAEA,IAAa,sBAAb,cAAyC,wBAGvC;CACA,cAAc;EACZ,MAAM,cAAc,IAAI,wBAAwB;EAChD,OAAO,aACL,SACG,YAAY,IAAI,WAA6C,CAAC,CAAC,CAC/D,YACC,IAAI,gBAGF,EACA,UAAU,YAAY,YAAY;GAChC,YAAY,OAAO,UAAU;GAC7B,WAAW,QAAQ;IACjB,UAAU,YAAY;IACtB;GACF,CAAC;EACH,EACF,CAAC,CACH,CACJ;CACF;AACF;AAEA,IAAa,uBAAb,cAA0C,SAAS;CACjD,YAAY,MAAyC;EACnD,MAAM,KAAK,YAAY,IAAI,oBAAoB,CAAC,GAAG,EACjD,SAAS,IAAI,QAAQ;GACnB,gBAAgB;GAChB,iBAAiB;GACjB,YAAY;GACZ,2BAA2B;EAC7B,CAAC,EACH,CAAC;CACH;AACF;AAEA,MAAa,4BACX,aACsC;CACtC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,2BAA2B,SAAS,QAAQ;CAC9D,IAAI,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,uBAAuB;CAC3D,IAAI,SAAS,QAAQ,IAAI,cAAc,MAAM,qBAC3C,MAAM,IAAI,MAAM,iCAAiC;CAEnD,IAAI,SAAS,QAAQ,IAAI,yBAAyB,MAAM,oBACtD,MAAM,IAAI,MAAM,4CAA4C;CAE9D,OAAO,SAAS,KAAK,YAAY,IAAI,oBAAoB,CAAC;AAC5D"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ReadonlyJSONValue } from "../../utils/json/json-value.js";
|
|
2
|
-
import { ObjectStreamChunk, ObjectStreamOperation } from "./types.js";
|
|
3
|
-
|
|
4
|
-
//#region src/core/object/createObjectStream.d.ts
|
|
5
|
-
type ObjectStreamController = {
|
|
6
|
-
readonly abortSignal: AbortSignal;
|
|
7
|
-
enqueue(operations: readonly ObjectStreamOperation[]): void;
|
|
8
|
-
};
|
|
9
|
-
type CreateObjectStreamOptions = {
|
|
10
|
-
execute: (controller: ObjectStreamController) => void | PromiseLike<void>;
|
|
11
|
-
defaultValue?: ReadonlyJSONValue;
|
|
12
|
-
};
|
|
13
|
-
declare const createObjectStream: ({
|
|
14
|
-
execute,
|
|
15
|
-
defaultValue
|
|
16
|
-
}: CreateObjectStreamOptions) => ReadableStream<ObjectStreamChunk>;
|
|
17
|
-
//#endregion
|
|
18
|
-
export { createObjectStream };
|
|
19
|
-
//# sourceMappingURL=createObjectStream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createObjectStream.d.ts","names":[],"sources":["../../../src/core/object/createObjectStream.ts"],"mappings":";;;;KAKK,sBAAA;EAAA,SACM,WAAA,EAAa,WAAA;EAEtB,OAAA,CAAQ,UAAA,WAAqB,qBAAqB;AAAA;AAAA,KAwD/C,yBAAA;EACH,OAAA,GAAU,UAAA,EAAY,sBAAA,YAAkC,WAAA;EACxD,YAAA,GAAe,iBAAA;AAAA;AAAA,cAGJ,kBAAA;EAAsB,OAAA;EAAA;AAAA,GAGhC,yBAAA,KAAyB,cAAA,CAAA,iBAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createObjectStream.js","names":[],"sources":["../../../src/core/object/createObjectStream.ts"],"sourcesContent":["import type { ReadonlyJSONValue } from \"../../utils\";\nimport { withPromiseOrValue } from \"../utils/withPromiseOrValue\";\nimport { ObjectStreamAccumulator } from \"./ObjectStreamAccumulator\";\nimport type { ObjectStreamOperation, ObjectStreamChunk } from \"./types\";\n\ntype ObjectStreamController = {\n readonly abortSignal: AbortSignal;\n\n enqueue(operations: readonly ObjectStreamOperation[]): void;\n};\n\nclass ObjectStreamControllerImpl implements ObjectStreamController {\n private _controller: ReadableStreamDefaultController<ObjectStreamChunk>;\n private _abortController = new AbortController();\n private _accumulator: ObjectStreamAccumulator;\n\n get abortSignal() {\n return this._abortController.signal;\n }\n\n constructor(\n controller: ReadableStreamDefaultController<ObjectStreamChunk>,\n defaultValue: ReadonlyJSONValue,\n ) {\n this._controller = controller;\n this._accumulator = new ObjectStreamAccumulator(defaultValue);\n }\n\n enqueue(operations: readonly ObjectStreamOperation[]) {\n this._accumulator.append(operations);\n\n this._controller.enqueue({\n snapshot: this._accumulator.state,\n operations,\n });\n }\n\n __internalError(error: unknown) {\n this._controller.error(error);\n }\n\n __internalClose() {\n this._controller.close();\n }\n\n __internalCancel(reason?: unknown) {\n this._abortController.abort(reason);\n }\n}\n\nconst getStreamControllerPair = (defaultValue: ReadonlyJSONValue) => {\n let controller!: ObjectStreamControllerImpl;\n const stream = new ReadableStream<ObjectStreamChunk>({\n start(c) {\n controller = new ObjectStreamControllerImpl(c, defaultValue);\n },\n cancel(reason: unknown) {\n controller.__internalCancel(reason);\n },\n });\n\n return [stream, controller] as const;\n};\n\ntype CreateObjectStreamOptions = {\n execute: (controller: ObjectStreamController) => void | PromiseLike<void>;\n defaultValue?: ReadonlyJSONValue;\n};\n\nexport const createObjectStream = ({\n execute,\n defaultValue = {},\n}: CreateObjectStreamOptions) => {\n const [stream, controller] = getStreamControllerPair(defaultValue);\n\n withPromiseOrValue(\n () => execute(controller),\n () => {\n controller.__internalClose();\n },\n (e: unknown) => {\n controller.__internalError(e);\n },\n );\n\n return stream;\n};\n"],"mappings":";;;AAWA,IAAM,6BAAN,MAAmE;CACjE;CACA,mBAA2B,IAAI,gBAAgB;CAC/C;CAEA,IAAI,cAAc;EAChB,OAAO,KAAK,iBAAiB;CAC/B;CAEA,YACE,YACA,cACA;EACA,KAAK,cAAc;EACnB,KAAK,eAAe,IAAI,wBAAwB,YAAY;CAC9D;CAEA,QAAQ,YAA8C;EACpD,KAAK,aAAa,OAAO,UAAU;EAEnC,KAAK,YAAY,QAAQ;GACvB,UAAU,KAAK,aAAa;GAC5B;EACF,CAAC;CACH;CAEA,gBAAgB,OAAgB;EAC9B,KAAK,YAAY,MAAM,KAAK;CAC9B;CAEA,kBAAkB;EAChB,KAAK,YAAY,MAAM;CACzB;CAEA,iBAAiB,QAAkB;EACjC,KAAK,iBAAiB,MAAM,MAAM;CACpC;AACF;AAEA,MAAM,2BAA2B,iBAAoC;CACnE,IAAI;CAUJ,OAAO,CAAC,IATW,eAAkC;EACnD,MAAM,GAAG;GACP,aAAa,IAAI,2BAA2B,GAAG,YAAY;EAC7D;EACA,OAAO,QAAiB;GACtB,WAAW,iBAAiB,MAAM;EACpC;CACF,CAEa,GAAG,UAAU;AAC5B;AAOA,MAAa,sBAAsB,EACjC,SACA,eAAe,CAAC,QACe;CAC/B,MAAM,CAAC,QAAQ,cAAc,wBAAwB,YAAY;CAEjE,yBACQ,QAAQ,UAAU,SAClB;EACJ,WAAW,gBAAgB;CAC7B,IACC,MAAe;EACd,WAAW,gBAAgB,CAAC;CAC9B,CACF;CAEA,OAAO;AACT"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ReadonlyJSONValue } from "../../utils/json/json-value.js";
|
|
2
|
-
//#region src/core/object/types.d.ts
|
|
3
|
-
type ObjectStreamOperation = {
|
|
4
|
-
readonly type: "set";
|
|
5
|
-
readonly path: readonly string[];
|
|
6
|
-
readonly value: ReadonlyJSONValue;
|
|
7
|
-
} | {
|
|
8
|
-
readonly type: "append-text";
|
|
9
|
-
readonly path: readonly string[];
|
|
10
|
-
readonly value: string;
|
|
11
|
-
};
|
|
12
|
-
type ObjectStreamChunk = {
|
|
13
|
-
readonly snapshot: ReadonlyJSONValue;
|
|
14
|
-
readonly operations: readonly ObjectStreamOperation[];
|
|
15
|
-
};
|
|
16
|
-
//#endregion
|
|
17
|
-
export { ObjectStreamChunk, ObjectStreamOperation };
|
|
18
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/object/types.ts"],"mappings":";;KAEY,qBAAA;EAAA,SAEG,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA,EAAO,iBAAiB;AAAA;EAAA,SAGxB,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;AAAA;AAAA,KAGH,iBAAA;EAAA,SACD,QAAA,EAAU,iBAAA;EAAA,SACV,UAAA,WAAqB,qBAAqB;AAAA"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { ReadonlyJSONArray, ReadonlyJSONObject, ReadonlyJSONValue } from "./json-value.js";
|
|
2
|
-
|
|
3
|
-
//#region src/utils/json/is-json.d.ts
|
|
4
|
-
declare function isJSONValue(value: unknown): value is ReadonlyJSONValue;
|
|
5
|
-
declare function isJSONArray(value: unknown): value is ReadonlyJSONArray;
|
|
6
|
-
declare function isJSONObject(value: unknown): value is ReadonlyJSONObject;
|
|
7
|
-
//#endregion
|
|
8
|
-
export { isJSONArray, isJSONObject, isJSONValue };
|
|
9
|
-
//# sourceMappingURL=is-json.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-json.d.ts","names":[],"sources":["../../../src/utils/json/is-json.ts"],"mappings":";;;iBAMgB,WAAA,CAAY,KAAA,YAAiB,KAAA,IAAS,iBAAiB;AAAA,iBAuBvD,WAAA,CAAY,KAAA,YAAiB,KAAA,IAAS,iBAAiB;AAAA,iBAIvD,YAAA,CAAa,KAAA,YAAiB,KAAA,IAAS,kBAAkB"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
//#region src/utils/json/is-json.ts
|
|
2
|
-
function isJSONValue(value) {
|
|
3
|
-
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return true;
|
|
4
|
-
if (Array.isArray(value)) return value.every(isJSONValue);
|
|
5
|
-
if (typeof value === "object") return Object.entries(value).every(([key, val]) => typeof key === "string" && isJSONValue(val));
|
|
6
|
-
return false;
|
|
7
|
-
}
|
|
8
|
-
function isJSONArray(value) {
|
|
9
|
-
return Array.isArray(value) && value.every(isJSONValue);
|
|
10
|
-
}
|
|
11
|
-
function isJSONObject(value) {
|
|
12
|
-
return value != null && typeof value === "object" && !Array.isArray(value) && Object.entries(value).every(([key, val]) => typeof key === "string" && isJSONValue(val));
|
|
13
|
-
}
|
|
14
|
-
//#endregion
|
|
15
|
-
export { isJSONArray, isJSONObject, isJSONValue };
|
|
16
|
-
|
|
17
|
-
//# sourceMappingURL=is-json.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is-json.js","names":[],"sources":["../../../src/utils/json/is-json.ts"],"sourcesContent":["import type {\n ReadonlyJSONArray,\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"./json-value\";\n\nexport function isJSONValue(value: unknown): value is ReadonlyJSONValue {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.every(isJSONValue);\n }\n\n if (typeof value === \"object\") {\n return Object.entries(value).every(\n ([key, val]) => typeof key === \"string\" && isJSONValue(val),\n );\n }\n\n return false;\n}\n\nexport function isJSONArray(value: unknown): value is ReadonlyJSONArray {\n return Array.isArray(value) && value.every(isJSONValue);\n}\n\nexport function isJSONObject(value: unknown): value is ReadonlyJSONObject {\n return (\n value != null &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n Object.entries(value).every(\n ([key, val]) => typeof key === \"string\" && isJSONValue(val),\n )\n );\n}\n"],"mappings":";AAMA,SAAgB,YAAY,OAA4C;CACtE,IACE,UAAU,QACV,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,WAEjB,OAAO;CAGT,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,MAAM,WAAW;CAGhC,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,QAAQ,KAAK,CAAC,CAAC,OAC1B,CAAC,KAAK,SAAS,OAAO,QAAQ,YAAY,YAAY,GAAG,CAC5D;CAGF,OAAO;AACT;AAEA,SAAgB,YAAY,OAA4C;CACtE,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,WAAW;AACxD;AAEA,SAAgB,aAAa,OAA6C;CACxE,OACE,SAAS,QACT,OAAO,UAAU,YACjB,CAAC,MAAM,QAAQ,KAAK,KACpB,OAAO,QAAQ,KAAK,CAAC,CAAC,OACnB,CAAC,KAAK,SAAS,OAAO,QAAQ,YAAY,YAAY,GAAG,CAC5D;AAEJ"}
|