assistant-stream 0.3.12 → 0.3.14

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.
Files changed (92) hide show
  1. package/README.md +39 -0
  2. package/dist/core/AssistantStreamChunk.d.ts +2 -0
  3. package/dist/core/AssistantStreamChunk.d.ts.map +1 -1
  4. package/dist/core/accumulators/assistant-message-accumulator.d.ts.map +1 -1
  5. package/dist/core/accumulators/assistant-message-accumulator.js +3 -0
  6. package/dist/core/accumulators/assistant-message-accumulator.js.map +1 -1
  7. package/dist/core/modules/tool-call.d.ts.map +1 -1
  8. package/dist/core/modules/tool-call.js +3 -0
  9. package/dist/core/modules/tool-call.js.map +1 -1
  10. package/dist/core/tool/ToolExecutionStream.d.ts.map +1 -1
  11. package/dist/core/tool/ToolExecutionStream.js +3 -0
  12. package/dist/core/tool/ToolExecutionStream.js.map +1 -1
  13. package/dist/core/tool/ToolResponse.d.ts +3 -0
  14. package/dist/core/tool/ToolResponse.d.ts.map +1 -1
  15. package/dist/core/tool/ToolResponse.js +4 -0
  16. package/dist/core/tool/ToolResponse.js.map +1 -1
  17. package/dist/core/tool/tool-types.d.ts +17 -0
  18. package/dist/core/tool/tool-types.d.ts.map +1 -1
  19. package/dist/core/tool/toolResultStream.d.ts.map +1 -1
  20. package/dist/core/tool/toolResultStream.js +26 -1
  21. package/dist/core/tool/toolResultStream.js.map +1 -1
  22. package/dist/core/utils/types.d.ts +4 -0
  23. package/dist/core/utils/types.d.ts.map +1 -1
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/resumable/ResumableStreamContext.d.ts +27 -0
  28. package/dist/resumable/ResumableStreamContext.d.ts.map +1 -0
  29. package/dist/resumable/ResumableStreamContext.js +121 -0
  30. package/dist/resumable/ResumableStreamContext.js.map +1 -0
  31. package/dist/resumable/constants.d.ts +2 -0
  32. package/dist/resumable/constants.d.ts.map +1 -0
  33. package/dist/resumable/constants.js +2 -0
  34. package/dist/resumable/constants.js.map +1 -0
  35. package/dist/resumable/createResumableAssistantStreamResponse.d.ts +24 -0
  36. package/dist/resumable/createResumableAssistantStreamResponse.d.ts.map +1 -0
  37. package/dist/resumable/createResumableAssistantStreamResponse.js +40 -0
  38. package/dist/resumable/createResumableAssistantStreamResponse.js.map +1 -0
  39. package/dist/resumable/errors.d.ts +7 -0
  40. package/dist/resumable/errors.d.ts.map +1 -0
  41. package/dist/resumable/errors.js +15 -0
  42. package/dist/resumable/errors.js.map +1 -0
  43. package/dist/resumable/index.d.ts +7 -0
  44. package/dist/resumable/index.d.ts.map +1 -0
  45. package/dist/resumable/index.js +5 -0
  46. package/dist/resumable/index.js.map +1 -0
  47. package/dist/resumable/stores/InMemoryResumableStreamStore.d.ts +13 -0
  48. package/dist/resumable/stores/InMemoryResumableStreamStore.d.ts.map +1 -0
  49. package/dist/resumable/stores/InMemoryResumableStreamStore.js +199 -0
  50. package/dist/resumable/stores/InMemoryResumableStreamStore.js.map +1 -0
  51. package/dist/resumable/stores/ioredis.d.ts +10 -0
  52. package/dist/resumable/stores/ioredis.d.ts.map +1 -0
  53. package/dist/resumable/stores/ioredis.js +95 -0
  54. package/dist/resumable/stores/ioredis.js.map +1 -0
  55. package/dist/resumable/stores/redis-impl.d.ts +60 -0
  56. package/dist/resumable/stores/redis-impl.d.ts.map +1 -0
  57. package/dist/resumable/stores/redis-impl.js +198 -0
  58. package/dist/resumable/stores/redis-impl.js.map +1 -0
  59. package/dist/resumable/stores/redis.d.ts +39 -0
  60. package/dist/resumable/stores/redis.d.ts.map +1 -0
  61. package/dist/resumable/stores/redis.js +113 -0
  62. package/dist/resumable/stores/redis.js.map +1 -0
  63. package/dist/resumable/types.d.ts +30 -0
  64. package/dist/resumable/types.d.ts.map +1 -0
  65. package/dist/resumable/types.js +2 -0
  66. package/dist/resumable/types.js.map +1 -0
  67. package/package.json +30 -5
  68. package/src/core/AssistantStreamChunk.ts +2 -0
  69. package/src/core/accumulators/assistant-message-accumulator.ts +3 -0
  70. package/src/core/modules/tool-call.ts +3 -0
  71. package/src/core/tool/ToolExecutionStream.ts +3 -0
  72. package/src/core/tool/ToolResponse.ts +6 -0
  73. package/src/core/tool/tool-types.ts +23 -0
  74. package/src/core/tool/toolResultStream.test.ts +360 -2
  75. package/src/core/tool/toolResultStream.ts +30 -1
  76. package/src/core/utils/types.ts +4 -0
  77. package/src/index.ts +5 -1
  78. package/src/resumable/ResumableStreamContext.test.ts +274 -0
  79. package/src/resumable/ResumableStreamContext.ts +187 -0
  80. package/src/resumable/__tests__/integration.test.ts +159 -0
  81. package/src/resumable/constants.ts +1 -0
  82. package/src/resumable/createResumableAssistantStreamResponse.test.ts +243 -0
  83. package/src/resumable/createResumableAssistantStreamResponse.ts +80 -0
  84. package/src/resumable/errors.ts +26 -0
  85. package/src/resumable/index.ts +36 -0
  86. package/src/resumable/stores/InMemoryResumableStreamStore.test.ts +285 -0
  87. package/src/resumable/stores/InMemoryResumableStreamStore.ts +237 -0
  88. package/src/resumable/stores/ioredis.ts +123 -0
  89. package/src/resumable/stores/redis-impl.ts +304 -0
  90. package/src/resumable/stores/redis.test.ts +265 -0
  91. package/src/resumable/stores/redis.ts +171 -0
  92. package/src/resumable/types.ts +49 -0
@@ -0,0 +1,121 @@
1
+ import { ResumableStreamError } from "./errors.js";
2
+ export function createResumableStreamContext(options) {
3
+ const { store, waitUntil, onAcquire, onAppend, onFinalize, onError } = options;
4
+ const acquireOptions = options.ttlMs !== undefined ? { ttlMs: options.ttlMs } : undefined;
5
+ return {
6
+ async run(streamId, makeStream) {
7
+ const role = await store.acquire(streamId, acquireOptions);
8
+ onAcquire?.(streamId, role);
9
+ if (role === "producer") {
10
+ startProducerTask(store, streamId, makeStream, {
11
+ waitUntil,
12
+ onAppend,
13
+ onFinalize,
14
+ onError,
15
+ });
16
+ }
17
+ return readFromStore(store, streamId);
18
+ },
19
+ async resume(streamId) {
20
+ const status = await store.status(streamId);
21
+ if (status === "missing")
22
+ return null;
23
+ return readFromStore(store, streamId);
24
+ },
25
+ async requireResume(streamId) {
26
+ const status = await store.status(streamId);
27
+ if (status === "missing") {
28
+ throw new ResumableStreamError("missing", `resumable stream not found: ${streamId}`);
29
+ }
30
+ return readFromStore(store, streamId);
31
+ },
32
+ async status(streamId) {
33
+ return store.status(streamId);
34
+ },
35
+ async delete(streamId) {
36
+ await store.delete(streamId);
37
+ },
38
+ };
39
+ }
40
+ function startProducerTask(store, streamId, makeStream, hooks) {
41
+ const { waitUntil, onAppend, onFinalize, onError } = hooks;
42
+ const task = (async () => {
43
+ let reader;
44
+ let cancelled = false;
45
+ try {
46
+ reader = makeStream().getReader();
47
+ while (true) {
48
+ const { done, value } = await reader.read();
49
+ if (done)
50
+ break;
51
+ await store.append(streamId, value);
52
+ onAppend?.(streamId, value.byteLength);
53
+ }
54
+ await store.finalize(streamId, "done");
55
+ onFinalize?.(streamId, "done");
56
+ }
57
+ catch (err) {
58
+ cancelled = true;
59
+ onError?.(streamId, err);
60
+ const message = err instanceof Error ? err.message : String(err);
61
+ try {
62
+ await reader?.cancel(err);
63
+ }
64
+ catch (cancelErr) {
65
+ console.error("resumable stream reader cancel failed:", cancelErr);
66
+ }
67
+ try {
68
+ await store.finalize(streamId, "error", message);
69
+ onFinalize?.(streamId, "error", message);
70
+ }
71
+ catch (finalizeErr) {
72
+ console.error("resumable stream finalize failed:", finalizeErr);
73
+ }
74
+ }
75
+ finally {
76
+ if (!cancelled)
77
+ reader?.releaseLock();
78
+ }
79
+ })();
80
+ if (waitUntil)
81
+ waitUntil(task);
82
+ task.catch((err) => {
83
+ console.error("resumable producer task failed:", err);
84
+ });
85
+ }
86
+ function readFromStore(store, streamId) {
87
+ const ac = new AbortController();
88
+ let iterator;
89
+ return new ReadableStream({
90
+ start() {
91
+ iterator = store.read(streamId, "", ac.signal)[Symbol.asyncIterator]();
92
+ },
93
+ async pull(controller) {
94
+ try {
95
+ if (!iterator)
96
+ return;
97
+ const { done, value } = await iterator.next();
98
+ if (done) {
99
+ controller.close();
100
+ return;
101
+ }
102
+ controller.enqueue(value.chunk);
103
+ }
104
+ catch (err) {
105
+ // the platform never calls cancel() on errored streams, so unwind
106
+ // the store iterator and abort the signal explicitly.
107
+ ac.abort();
108
+ try {
109
+ await iterator?.return?.();
110
+ }
111
+ catch { }
112
+ controller.error(err);
113
+ }
114
+ },
115
+ cancel() {
116
+ ac.abort();
117
+ iterator?.return?.().catch(() => { });
118
+ },
119
+ });
120
+ }
121
+ //# sourceMappingURL=ResumableStreamContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResumableStreamContext.js","sourceRoot":"","sources":["../../src/resumable/ResumableStreamContext.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_TTL_MS: number;
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/resumable/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,QAAsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
2
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/resumable/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { AssistantStreamEncoder } from "../core/AssistantStream.js";
2
+ import { type AssistantStreamController } from "../core/modules/assistant-stream.js";
3
+ import type { ResumableStreamContext } from "./ResumableStreamContext.js";
4
+ export declare const RESUMABLE_STREAM_ID_HEADER = "x-resumable-stream-id";
5
+ export type CreateResumableAssistantStreamResponseOptions = {
6
+ readonly context: ResumableStreamContext;
7
+ readonly streamId: string;
8
+ readonly callback: (controller: AssistantStreamController) => PromiseLike<void> | void;
9
+ /** Defaults to `DataStreamEncoder`. Also consulted for response headers. */
10
+ readonly encoder?: () => AssistantStreamEncoder;
11
+ readonly headers?: HeadersInit;
12
+ };
13
+ export declare function createResumableAssistantStreamResponse(options: CreateResumableAssistantStreamResponseOptions): Promise<Response>;
14
+ export type CreateResumeAssistantStreamResponseOptions = {
15
+ readonly context: ResumableStreamContext;
16
+ readonly streamId: string;
17
+ /** Read for `headers` only; the encoder transform is not invoked on resume. */
18
+ readonly encoder?: () => AssistantStreamEncoder;
19
+ readonly headers?: HeadersInit;
20
+ /** Defaults to a 404 JSON response. */
21
+ readonly missingResponse?: () => Response;
22
+ };
23
+ export declare function createResumeAssistantStreamResponse(options: CreateResumeAssistantStreamResponseOptions): Promise<Response>;
24
+ //# sourceMappingURL=createResumableAssistantStreamResponse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createResumableAssistantStreamResponse.d.ts","sourceRoot":"","sources":["../../src/resumable/createResumableAssistantStreamResponse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,mCAAgC;AACtE,OAAO,EAEL,KAAK,yBAAyB,EAC/B,4CAAyC;AAE1C,OAAO,KAAK,EAAE,sBAAsB,EAAE,oCAAiC;AAEvE,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAElE,MAAM,MAAM,6CAA6C,GAAG;IAC1D,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,CACjB,UAAU,EAAE,yBAAyB,KAClC,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,sBAAsB,CAAC;IAChD,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;CAChC,CAAC;AAEF,wBAAsB,sCAAsC,CAC1D,OAAO,EAAE,6CAA6C,GACrD,OAAO,CAAC,QAAQ,CAAC,CAWnB;AAED,MAAM,MAAM,0CAA0C,GAAG;IACvD,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,sBAAsB,CAAC;IAChD,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B,uCAAuC;IACvC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,QAAQ,CAAC;CAC3C,CAAC;AAEF,wBAAsB,mCAAmC,CACvD,OAAO,EAAE,0CAA0C,GAClD,OAAO,CAAC,QAAQ,CAAC,CASnB"}
@@ -0,0 +1,40 @@
1
+ import { createAssistantStream, } from "../core/modules/assistant-stream.js";
2
+ import { DataStreamEncoder } from "../core/serialization/data-stream/DataStream.js";
3
+ export const RESUMABLE_STREAM_ID_HEADER = "x-resumable-stream-id";
4
+ export async function createResumableAssistantStreamResponse(options) {
5
+ const encoder = (options.encoder ?? (() => new DataStreamEncoder()))();
6
+ const stream = await options.context.run(options.streamId, () => {
7
+ const aStream = createAssistantStream(options.callback);
8
+ return aStream.pipeThrough(encoder);
9
+ });
10
+ return new Response(stream, {
11
+ headers: mergeHeaders(encoder.headers, options.headers, options.streamId),
12
+ });
13
+ }
14
+ export async function createResumeAssistantStreamResponse(options) {
15
+ const stream = await options.context.resume(options.streamId);
16
+ if (!stream) {
17
+ return options.missingResponse?.() ?? defaultMissingResponse();
18
+ }
19
+ const encoder = (options.encoder ?? (() => new DataStreamEncoder()))();
20
+ return new Response(stream, {
21
+ headers: mergeHeaders(encoder.headers, options.headers, options.streamId),
22
+ });
23
+ }
24
+ function defaultMissingResponse() {
25
+ return new Response(JSON.stringify({ error: "stream not found" }), {
26
+ status: 404,
27
+ headers: { "Content-Type": "application/json" },
28
+ });
29
+ }
30
+ function mergeHeaders(encoderHeaders, extra, streamId) {
31
+ const merged = new Headers(encoderHeaders ?? {});
32
+ if (extra) {
33
+ for (const [key, value] of new Headers(extra)) {
34
+ merged.set(key, value);
35
+ }
36
+ }
37
+ merged.set(RESUMABLE_STREAM_ID_HEADER, streamId);
38
+ return merged;
39
+ }
40
+ //# sourceMappingURL=createResumableAssistantStreamResponse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createResumableAssistantStreamResponse.js","sourceRoot":"","sources":["../../src/resumable/createResumableAssistantStreamResponse.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,GAEtB,4CAAyC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,wDAAqD;AAGjF,MAAM,CAAC,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAalE,MAAM,CAAC,KAAK,UAAU,sCAAsC,CAC1D,OAAsD;IAEtD,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,EAAE,CAAC;IAEvE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,EAAE;QAC9D,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxD,OAAO,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;QAC1B,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC;KAC1E,CAAC,CAAC;AACL,CAAC;AAYD,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,OAAmD;IAEnD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC,eAAe,EAAE,EAAE,IAAI,sBAAsB,EAAE,CAAC;IACjE,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC,EAAE,CAAC;IACvE,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;QAC1B,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC;KAC1E,CAAC,CAAC;AACL,CAAC;AAED,SAAS,sBAAsB;IAC7B,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,EAAE;QACjE,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAChD,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CACnB,cAAmC,EACnC,KAA8B,EAC9B,QAAgB;IAEhB,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;IACjD,IAAI,KAAK,EAAE,CAAC;QACV,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9C,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,0BAA0B,EAAE,QAAQ,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type ResumableStreamErrorCode = "missing" | "exists" | "finalized" | "invalid-id";
2
+ export declare class ResumableStreamError extends Error {
3
+ readonly code: ResumableStreamErrorCode;
4
+ constructor(code: ResumableStreamErrorCode, message: string);
5
+ }
6
+ export declare function validateStreamId(streamId: string): void;
7
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/resumable/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAChC,SAAS,GACT,QAAQ,GACR,WAAW,GACX,YAAY,CAAC;AAEjB,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;gBAE5B,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM;CAK5D;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAOvD"}
@@ -0,0 +1,15 @@
1
+ export class ResumableStreamError extends Error {
2
+ code;
3
+ constructor(code, message) {
4
+ super(message);
5
+ this.name = "ResumableStreamError";
6
+ this.code = code;
7
+ }
8
+ }
9
+ const STREAM_ID_PATTERN = /^[A-Za-z0-9_.:-]{1,256}$/;
10
+ export function validateStreamId(streamId) {
11
+ if (!STREAM_ID_PATTERN.test(streamId)) {
12
+ throw new ResumableStreamError("invalid-id", `Invalid streamId: ${streamId} (must match ${STREAM_ID_PATTERN})`);
13
+ }
14
+ }
15
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/resumable/errors.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,IAAI,CAA2B;IAExC,YAAY,IAA8B,EAAE,OAAe;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,iBAAiB,GAAG,0BAA0B,CAAC;AAErD,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,oBAAoB,CAC5B,YAAY,EACZ,qBAAqB,QAAQ,gBAAgB,iBAAiB,GAAG,CAClE,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type { ResumableStreamStore, ResumableStreamRole, ResumableStreamStatus, ResumableStreamEntry, ResumableStreamAcquireOptions, } from "./types.js";
2
+ export { ResumableStreamError, type ResumableStreamErrorCode, } from "./errors.js";
3
+ export { createResumableStreamContext, type ResumableStreamContext, type ResumableStreamContextOptions, } from "./ResumableStreamContext.js";
4
+ export { createResumableAssistantStreamResponse, createResumeAssistantStreamResponse, RESUMABLE_STREAM_ID_HEADER, type CreateResumableAssistantStreamResponseOptions, type CreateResumeAssistantStreamResponseOptions, } from "./createResumableAssistantStreamResponse.js";
5
+ export { createInMemoryResumableStreamStore, type InMemoryResumableStreamStoreOptions, } from "./stores/InMemoryResumableStreamStore.js";
6
+ export type { RedisLikeClient, RedisResumableStreamStoreOptions, } from "./stores/redis-impl.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resumable/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,6BAA6B,GAC9B,mBAAgB;AAEjB,OAAO,EACL,oBAAoB,EACpB,KAAK,wBAAwB,GAC9B,oBAAiB;AAElB,OAAO,EACL,4BAA4B,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,GACnC,oCAAiC;AAElC,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,0BAA0B,EAC1B,KAAK,6CAA6C,EAClD,KAAK,0CAA0C,GAChD,oDAAiD;AAElD,OAAO,EACL,kCAAkC,EAClC,KAAK,mCAAmC,GACzC,iDAA8C;AAE/C,YAAY,EACV,eAAe,EACf,gCAAgC,GACjC,+BAA4B"}
@@ -0,0 +1,5 @@
1
+ export { ResumableStreamError, } from "./errors.js";
2
+ export { createResumableStreamContext, } from "./ResumableStreamContext.js";
3
+ export { createResumableAssistantStreamResponse, createResumeAssistantStreamResponse, RESUMABLE_STREAM_ID_HEADER, } from "./createResumableAssistantStreamResponse.js";
4
+ export { createInMemoryResumableStreamStore, } from "./stores/InMemoryResumableStreamStore.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resumable/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,oBAAoB,GAErB,oBAAiB;AAElB,OAAO,EACL,4BAA4B,GAG7B,oCAAiC;AAElC,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,0BAA0B,GAG3B,oDAAiD;AAElD,OAAO,EACL,kCAAkC,GAEnC,iDAA8C"}
@@ -0,0 +1,13 @@
1
+ import type { ResumableStreamStore } from "../types.js";
2
+ export type InMemoryResumableStreamStoreOptions = {
3
+ readonly defaultTtlMs?: number;
4
+ readonly now?: () => number;
5
+ readonly maxChunkBytes?: number;
6
+ readonly maxEntriesPerStream?: number;
7
+ readonly maxStreams?: number;
8
+ readonly gcIntervalMs?: number;
9
+ };
10
+ export declare function createInMemoryResumableStreamStore(options?: InMemoryResumableStreamStoreOptions): ResumableStreamStore & {
11
+ dispose: () => void;
12
+ };
13
+ //# sourceMappingURL=InMemoryResumableStreamStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryResumableStreamStore.d.ts","sourceRoot":"","sources":["../../../src/resumable/stores/InMemoryResumableStreamStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,oBAAoB,EACrB,oBAAiB;AAoBlB,MAAM,MAAM,mCAAmC,GAAG;IAChD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,wBAAgB,kCAAkC,CAChD,OAAO,GAAE,mCAAwC,GAChD,oBAAoB,GAAG;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAuMhD"}
@@ -0,0 +1,199 @@
1
+ import { DEFAULT_TTL_MS } from "../constants.js";
2
+ import { ResumableStreamError, validateStreamId } from "../errors.js";
3
+ const cursorOf = (seq) => seq.toString(36);
4
+ const seqFromCursor = (cursor) => {
5
+ if (cursor === "")
6
+ return 0;
7
+ const parsed = Number.parseInt(cursor, 36);
8
+ return Number.isNaN(parsed) ? 0 : parsed;
9
+ };
10
+ export function createInMemoryResumableStreamStore(options = {}) {
11
+ const streams = new Map();
12
+ const defaultTtlMs = options.defaultTtlMs ?? DEFAULT_TTL_MS;
13
+ const now = options.now ?? Date.now;
14
+ const maxChunkBytes = options.maxChunkBytes;
15
+ const maxEntriesPerStream = options.maxEntriesPerStream;
16
+ const maxStreams = options.maxStreams;
17
+ const evictExpired = () => {
18
+ const t = now();
19
+ for (const [id, state] of streams) {
20
+ if (state.expiresAt > t)
21
+ continue;
22
+ streams.delete(id);
23
+ state.final ??= { kind: "error", error: "Stream expired" };
24
+ notify(state);
25
+ }
26
+ };
27
+ const notify = (state) => {
28
+ const waiters = state.waiters;
29
+ state.waiters = [];
30
+ for (const wake of waiters)
31
+ wake();
32
+ };
33
+ const findStartIndex = (state, cursor) => {
34
+ if (cursor === "")
35
+ return 0;
36
+ const after = seqFromCursor(cursor);
37
+ let lo = 0;
38
+ let hi = state.entries.length;
39
+ while (lo < hi) {
40
+ const mid = (lo + hi) >>> 1;
41
+ const seq = seqFromCursor(state.entries[mid].cursor);
42
+ if (seq <= after)
43
+ lo = mid + 1;
44
+ else
45
+ hi = mid;
46
+ }
47
+ return lo;
48
+ };
49
+ const waitForUpdate = (state, signal, wakeBy) => new Promise((resolve) => {
50
+ let settled = false;
51
+ let timer;
52
+ const wake = () => {
53
+ if (settled)
54
+ return;
55
+ settled = true;
56
+ if (timer !== undefined)
57
+ clearTimeout(timer);
58
+ signal.removeEventListener("abort", wake);
59
+ const idx = state.waiters.indexOf(wake);
60
+ if (idx !== -1)
61
+ state.waiters.splice(idx, 1);
62
+ resolve();
63
+ };
64
+ if (signal.aborted) {
65
+ wake();
66
+ return;
67
+ }
68
+ state.waiters.push(wake);
69
+ signal.addEventListener("abort", wake, { once: true });
70
+ if (wakeBy !== undefined) {
71
+ if (wakeBy > 0) {
72
+ timer = setTimeout(wake, wakeBy);
73
+ }
74
+ else {
75
+ // already past the deadline; resolve so the caller can re-check
76
+ // expiration without waiting for an external notify.
77
+ wake();
78
+ }
79
+ }
80
+ });
81
+ const requireActive = (streamId) => {
82
+ evictExpired();
83
+ const state = streams.get(streamId);
84
+ if (!state)
85
+ throw new Error(`Stream not found: ${streamId}`);
86
+ if (state.final) {
87
+ throw new ResumableStreamError("finalized", `Stream already finalized: ${streamId}`);
88
+ }
89
+ return state;
90
+ };
91
+ const gcTimer = options.gcIntervalMs !== undefined
92
+ ? setInterval(evictExpired, options.gcIntervalMs)
93
+ : undefined;
94
+ gcTimer?.unref?.();
95
+ return {
96
+ async acquire(streamId, acquireOptions) {
97
+ validateStreamId(streamId);
98
+ evictExpired();
99
+ const existing = streams.get(streamId);
100
+ if (existing)
101
+ return "consumer";
102
+ if (maxStreams !== undefined && streams.size >= maxStreams) {
103
+ throw new Error("maxStreams exceeded");
104
+ }
105
+ const ttlMs = acquireOptions?.ttlMs ?? defaultTtlMs;
106
+ streams.set(streamId, {
107
+ entries: [],
108
+ nextSeq: 1,
109
+ expiresAt: now() + ttlMs,
110
+ ttlMs,
111
+ final: undefined,
112
+ waiters: [],
113
+ });
114
+ return "producer";
115
+ },
116
+ async append(streamId, chunk) {
117
+ validateStreamId(streamId);
118
+ if (maxChunkBytes !== undefined && chunk.byteLength > maxChunkBytes) {
119
+ throw new Error(`Chunk exceeds maxChunkBytes: ${chunk.byteLength}`);
120
+ }
121
+ const state = requireActive(streamId);
122
+ if (maxEntriesPerStream !== undefined &&
123
+ state.entries.length >= maxEntriesPerStream) {
124
+ throw new Error(`Stream exceeded maxEntriesPerStream: ${streamId}`);
125
+ }
126
+ const seq = state.nextSeq;
127
+ state.nextSeq += 1;
128
+ state.entries.push({ cursor: cursorOf(seq), chunk });
129
+ state.expiresAt = now() + state.ttlMs;
130
+ notify(state);
131
+ },
132
+ async finalize(streamId, status, error) {
133
+ validateStreamId(streamId);
134
+ evictExpired();
135
+ const state = streams.get(streamId);
136
+ if (!state)
137
+ throw new Error(`Stream not found: ${streamId}`);
138
+ if (state.final)
139
+ return;
140
+ state.final =
141
+ status === "done"
142
+ ? { kind: "done" }
143
+ : { kind: "error", error: error ?? "Stream errored" };
144
+ state.expiresAt = now() + state.ttlMs;
145
+ notify(state);
146
+ },
147
+ async *read(streamId, cursor, signal) {
148
+ validateStreamId(streamId);
149
+ evictExpired();
150
+ const state = streams.get(streamId);
151
+ if (!state)
152
+ throw new Error(`Stream not found: ${streamId}`);
153
+ let idx = findStartIndex(state, cursor);
154
+ while (true) {
155
+ if (signal.aborted)
156
+ return;
157
+ while (idx < state.entries.length) {
158
+ if (signal.aborted)
159
+ return;
160
+ yield state.entries[idx];
161
+ idx += 1;
162
+ }
163
+ if (state.final) {
164
+ if (state.final.kind === "error") {
165
+ throw new Error(state.final.error);
166
+ }
167
+ return;
168
+ }
169
+ const wakeBy = state.expiresAt - now();
170
+ await waitForUpdate(state, signal, wakeBy);
171
+ evictExpired();
172
+ }
173
+ },
174
+ async status(streamId) {
175
+ validateStreamId(streamId);
176
+ evictExpired();
177
+ const state = streams.get(streamId);
178
+ if (!state)
179
+ return "missing";
180
+ if (!state.final)
181
+ return "streaming";
182
+ return state.final.kind === "error" ? "error" : "done";
183
+ },
184
+ async delete(streamId) {
185
+ validateStreamId(streamId);
186
+ const state = streams.get(streamId);
187
+ if (!state)
188
+ return;
189
+ streams.delete(streamId);
190
+ state.final ??= { kind: "done" };
191
+ notify(state);
192
+ },
193
+ dispose() {
194
+ if (gcTimer !== undefined)
195
+ clearInterval(gcTimer);
196
+ },
197
+ };
198
+ }
199
+ //# sourceMappingURL=InMemoryResumableStreamStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InMemoryResumableStreamStore.js","sourceRoot":"","sources":["../../../src/resumable/stores/InMemoryResumableStreamStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Cluster as IoRedisCluster, Redis as IoRedis } from "ioredis";
2
+ import { type RedisResumableStreamStoreOptions } from "./redis-impl.js";
3
+ import type { ResumableStreamStore } from "../types.js";
4
+ export type IoRedisLike = IoRedis | IoRedisCluster;
5
+ /**
6
+ * Resumable stream store backed by [`ioredis`](https://www.npmjs.com/package/ioredis)
7
+ * v5. Accepts a `Redis` or `Cluster` instance.
8
+ */
9
+ export declare function createIoredisResumableStreamStore(client: IoRedisLike, options?: RedisResumableStreamStoreOptions): ResumableStreamStore;
10
+ //# sourceMappingURL=ioredis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ioredis.d.ts","sourceRoot":"","sources":["../../../src/resumable/stores/ioredis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,OAAO,IAAI,cAAc,EACzB,KAAK,IAAI,OAAO,EACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAIL,KAAK,gCAAgC,EACtC,wBAAqB;AACtB,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAiB;AAErD,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,WAAW,EACnB,OAAO,CAAC,EAAE,gCAAgC,GACzC,oBAAoB,CAEtB"}
@@ -0,0 +1,95 @@
1
+ import { RedisResumableStreamStore, } from "./redis-impl.js";
2
+ /**
3
+ * Resumable stream store backed by [`ioredis`](https://www.npmjs.com/package/ioredis)
4
+ * v5. Accepts a `Redis` or `Cluster` instance.
5
+ */
6
+ export function createIoredisResumableStreamStore(client, options) {
7
+ return new RedisResumableStreamStore(adapt(client), options);
8
+ }
9
+ function adapt(client) {
10
+ return {
11
+ async setNX(key, value, ttlSec) {
12
+ const result = await client.set(key, value, "EX", ttlSec, "NX");
13
+ return result === "OK";
14
+ },
15
+ async set(key, value, ttlSec) {
16
+ await client.set(key, value, "EX", ttlSec);
17
+ },
18
+ async get(key) {
19
+ return client.get(key);
20
+ },
21
+ async expire(key, ttlSec) {
22
+ await client.expire(key, ttlSec);
23
+ },
24
+ async exists(key) {
25
+ const result = await client.exists(key);
26
+ return result > 0;
27
+ },
28
+ async del(keys) {
29
+ if (keys.length === 0)
30
+ return;
31
+ await client.del(...keys);
32
+ },
33
+ async xAdd(key, fields) {
34
+ const id = await client.xadd(key, "*", ...toFieldArgs(fields));
35
+ return id ?? "";
36
+ },
37
+ async xRange(key, start, end) {
38
+ const entries = await client.xrangeBuffer(key, start, end);
39
+ return entries.map(([idBuf, fieldArray]) => ({
40
+ id: idBuf.toString("utf8"),
41
+ fields: bufferFieldsToRecord(fieldArray),
42
+ }));
43
+ },
44
+ async pipeline(commands) {
45
+ if (commands.length === 0)
46
+ return;
47
+ const pipe = client.pipeline();
48
+ for (const cmd of commands) {
49
+ applyPipelineCommand(pipe, cmd);
50
+ }
51
+ const results = (await pipe.exec()) ?? [];
52
+ for (const [err] of results) {
53
+ if (err)
54
+ throw err;
55
+ }
56
+ },
57
+ };
58
+ }
59
+ function applyPipelineCommand(pipe, cmd) {
60
+ switch (cmd.type) {
61
+ case "xAdd":
62
+ pipe.xadd(cmd.key, "*", ...toFieldArgs(cmd.fields));
63
+ return;
64
+ case "expire":
65
+ pipe.expire(cmd.key, cmd.ttlSec);
66
+ return;
67
+ case "set":
68
+ pipe.set(cmd.key, cmd.value, "EX", cmd.ttlSec);
69
+ return;
70
+ }
71
+ }
72
+ function toFieldArgs(fields) {
73
+ const args = [];
74
+ for (const [k, v] of Object.entries(fields)) {
75
+ args.push(k, typeof v === "string" ? v : toBuffer(v));
76
+ }
77
+ return args;
78
+ }
79
+ function toBuffer(bytes) {
80
+ if (Buffer.isBuffer(bytes))
81
+ return bytes;
82
+ return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
83
+ }
84
+ function bufferFieldsToRecord(fields) {
85
+ const out = {};
86
+ for (let i = 0; i + 1 < fields.length; i += 2) {
87
+ const key = fields[i]?.toString("utf8");
88
+ const value = fields[i + 1];
89
+ if (key !== undefined && value !== undefined) {
90
+ out[key] = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
91
+ }
92
+ }
93
+ return out;
94
+ }
95
+ //# sourceMappingURL=ioredis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ioredis.js","sourceRoot":"","sources":["../../../src/resumable/stores/ioredis.ts"],"names":[],"mappings":"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"}