lemon-model 1.2.1 → 1.2.2

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 (45) hide show
  1. package/README.md +20 -2
  2. package/dist/buffer/index.d.ts +9 -0
  3. package/dist/buffer/index.js +26 -0
  4. package/dist/buffer/index.js.map +1 -0
  5. package/dist/buffer/network.d.ts +89 -0
  6. package/dist/buffer/network.js +172 -0
  7. package/dist/buffer/network.js.map +1 -0
  8. package/dist/buffer/stream.d.ts +220 -0
  9. package/dist/buffer/stream.js +563 -0
  10. package/dist/buffer/stream.js.map +1 -0
  11. package/dist/buffer/testing.d.ts +56 -0
  12. package/dist/buffer/testing.js +92 -0
  13. package/dist/buffer/testing.js.map +1 -0
  14. package/dist/buffer/token.d.ts +49 -0
  15. package/dist/buffer/token.js +112 -0
  16. package/dist/buffer/token.js.map +1 -0
  17. package/dist/esm/buffer/index.js +10 -0
  18. package/dist/esm/buffer/index.js.map +1 -0
  19. package/dist/esm/buffer/network.js +163 -0
  20. package/dist/esm/buffer/network.js.map +1 -0
  21. package/dist/esm/buffer/stream.js +554 -0
  22. package/dist/esm/buffer/stream.js.map +1 -0
  23. package/dist/esm/buffer/testing.js +88 -0
  24. package/dist/esm/buffer/testing.js.map +1 -0
  25. package/dist/esm/buffer/token.js +108 -0
  26. package/dist/esm/buffer/token.js.map +1 -0
  27. package/dist/esm/genai/mocks.js +1 -1
  28. package/dist/esm/genai/transport.js +3 -34
  29. package/dist/esm/genai/transport.js.map +1 -1
  30. package/dist/esm/index.js +1 -0
  31. package/dist/esm/index.js.map +1 -1
  32. package/dist/esm/socket/websocket.js +212 -0
  33. package/dist/esm/socket/websocket.js.map +1 -1
  34. package/dist/genai/mocks.d.ts +1 -1
  35. package/dist/genai/mocks.js +1 -1
  36. package/dist/genai/transport.js +3 -34
  37. package/dist/genai/transport.js.map +1 -1
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.js +1 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/socket/types.d.ts +5 -3
  42. package/dist/socket/websocket.d.ts +63 -0
  43. package/dist/socket/websocket.js +216 -1
  44. package/dist/socket/websocket.js.map +1 -1
  45. package/package.json +7 -1
package/README.md CHANGED
@@ -32,6 +32,7 @@ Frontend bundlers use the ESM build. Existing Node `require()` consumers use the
32
32
  | `types` | Shared request, identity, storage, and service shapes | Source types |
33
33
  | `cores` | Small shared transform helpers | Source tests |
34
34
  | `socket` | Peer socket, network contract, WebSocket bridge, JSON chunk transport | `src/socket/README.md` |
35
+ | `buffer` | Provider-neutral GenAI stream buffering and network adapters | `src/buffer/README.md` |
35
36
  | `genai` | Gemini-like `generateContent()` adapter over Lemon agents APIs | `src/genai/README.md` |
36
37
  | `samples` | Real usage cases and PR-ready sample notes | `samples/README.md` |
37
38
 
@@ -68,12 +69,28 @@ flowchart TD
68
69
  B -- Yes --> D{Which behavior}
69
70
  D -- Data transforms --> E[Use cores]
70
71
  D -- Socket or network test --> F[Use socket]
72
+ D -- GenAI stream batching --> J[Use buffer]
71
73
  D -- Agents generateContent --> G[Use genai]
72
74
  F --> H[Read src/socket/README.md]
73
75
  G --> I[Read src/genai/README.md]
76
+ J --> K[Read src/buffer/README.md]
74
77
  ```
75
78
 
76
- Main branch: type-only, transform helper, socket flow, or GenAI proxy.
79
+ Main branch: type-only, transform helper, socket flow, GenAI stream buffer, or GenAI proxy.
80
+
81
+ ## Buffer
82
+
83
+ `buffer` provides provider-neutral stream primitives for GenAI responses.
84
+
85
+ ```ts
86
+ import { GenAIStreamBuffer, createGenAIStreamNetworkConsumer } from 'lemon-model';
87
+ ```
88
+
89
+ Use it when a provider emits small stream fragments and the app needs consistent `start`, `chunk`, `progress`, `flush`, `eof`, and `error` events.
90
+
91
+ The network adapter can send `GenAIStreamEvent` over the shared socket/json-transport layer. Diagnostic helpers live under `lemon-model/buffer/testing`.
92
+
93
+ Provider probe tools are available under `tools/`, but provider SDKs are not part of the runtime package contract. Install the matching SDK in the workspace where you run a probe.
77
94
 
78
95
  ## Build Formats
79
96
 
@@ -81,12 +98,13 @@ Main branch: type-only, transform helper, socket flow, or GenAI proxy.
81
98
  - ESM entry: `dist/esm/index.js`
82
99
  - Type declarations: `dist/index.d.ts`
83
100
  - Package export: `import { ... } from 'lemon-model'`
84
- - Test helper exports: `lemon-model/genai/testing`, `lemon-model/socket/testing`
101
+ - Test helper exports: `lemon-model/genai/testing`, `lemon-model/buffer/testing`, `lemon-model/socket/testing`
85
102
 
86
103
  ## Module Docs
87
104
 
88
105
  - `src/socket/README.md`: peer socket and network contract
89
106
  - `src/socket/JSON_TRANSPORT_SPEC.md`: JSON chunk transport protocol
107
+ - `src/buffer/README.md`: GenAI stream buffering and network adapter contract
90
108
  - `src/genai/README.md`: GenAI adapter contract
91
109
  - `samples/README.md`: sample case rules
92
110
 
@@ -0,0 +1,9 @@
1
+ /**
2
+ * `buffer/index.ts`
3
+ * - Public exports for token, stream, and network buffering utilities.
4
+ *
5
+ * @origin eureka-agents-api / src/lib/buffer/index.ts
6
+ */
7
+ export * from './token';
8
+ export * from './stream';
9
+ export * from './network';
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * `buffer/index.ts`
19
+ * - Public exports for token, stream, and network buffering utilities.
20
+ *
21
+ * @origin eureka-agents-api / src/lib/buffer/index.ts
22
+ */
23
+ __exportStar(require("./token"), exports);
24
+ __exportStar(require("./stream"), exports);
25
+ __exportStar(require("./network"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/buffer/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;GAKG;AACH,0CAAwB;AACxB,2CAAyB;AACzB,4CAA0B"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `buffer/network.ts`
3
+ * - Network transport adapters and diagnostics for GenAI stream events.
4
+ *
5
+ * @origin eureka-agents-api / src/lib/buffer/network.ts
6
+ *
7
+ * GenAIStreamConsumer emits typed events, while NetworkSupportable only accepts
8
+ * raw strings and may enforce a packet-size limit. This adapter keeps those
9
+ * concerns separate by sending stream events through JSONTransport.
10
+ */
11
+ import { JSONTransportOptions, JSONTransportSupportable } from '../socket/transport';
12
+ import { NetworkSupportable, SocketErrorHandler, SocketUnsubscribe } from '../socket/types';
13
+ import { GenAIStreamConsumer, GenAIStreamEvent } from './stream';
14
+ export interface GenAIStreamNetworkPacket {
15
+ /** packet discriminator used after JSONTransport reassembly */
16
+ type: 'genai:stream';
17
+ /** compact logical stream/session id for multiplexing over one network */
18
+ sid?: string;
19
+ /** monotonically increasing event sequence assigned by the sender */
20
+ seq: number;
21
+ /** sender-side timestamp in epoch milliseconds */
22
+ sentAt: number;
23
+ /** original or wire-compacted GenAI stream event */
24
+ event: GenAIStreamEvent;
25
+ /** optional wire-compaction metadata used by restoreStreamEvent() */
26
+ compact?: GenAIStreamNetworkCompactMeta;
27
+ }
28
+ export interface GenAIStreamNetworkCompactMeta {
29
+ /** chunk data was removed because it can be reconstructed from flush.data */
30
+ flushChunksData?: 'fromFlushData';
31
+ }
32
+ export interface GenAIStreamNetworkOptions {
33
+ /** optional stream/session id carried with every network packet */
34
+ streamId?: string;
35
+ /** known raw network packet limit; used to derive JSONTransport chunkBytes */
36
+ maxPacketBytes?: number;
37
+ /** JSONTransport chunking/reassembly options */
38
+ jsonTransport?: JSONTransportOptions;
39
+ /** wait for network.ready() before each event send; defaults to true */
40
+ waitReady?: boolean;
41
+ /** observe errors thrown by the receiver-side consumer */
42
+ onConsumerError?: SocketErrorHandler;
43
+ /** observe every accepted stream network packet before forwarding its event */
44
+ onPacket?: (packet: GenAIStreamNetworkPacket) => void;
45
+ /** deliver stream packets by seq order; useful for unordered networks */
46
+ reorder?: boolean;
47
+ /** remove duplicated flush chunks[].data on the wire and restore it on receive */
48
+ compactFlush?: boolean;
49
+ }
50
+ export interface GenAIStreamNetworkConsumerHandle {
51
+ consumer: GenAIStreamConsumer;
52
+ transport: JSONTransportSupportable<GenAIStreamNetworkPacket>;
53
+ detach(): void;
54
+ }
55
+ export interface GenAIStreamNetworkReceiver {
56
+ transport: JSONTransportSupportable<GenAIStreamNetworkPacket>;
57
+ detach(): void;
58
+ }
59
+ export declare const asGenAIStreamNetworkTransportOptions: (options?: GenAIStreamNetworkOptions) => JSONTransportOptions | undefined;
60
+ /**
61
+ * Create a GenAIStreamConsumer that serializes stream events and sends them over
62
+ * NetworkSupportable via JSONTransport.
63
+ *
64
+ * The returned consumer preserves the normal GenAIStreamConsumer contract. The
65
+ * only network-specific behavior is packet wrapping, optional flush compaction,
66
+ * and JSONTransport splitting for large string payloads.
67
+ */
68
+ export declare const createGenAIStreamNetworkConsumer: (network: NetworkSupportable, options?: GenAIStreamNetworkOptions) => GenAIStreamNetworkConsumerHandle;
69
+ /**
70
+ * Receive GenAI stream event packets from a NetworkSupportable and forward the
71
+ * rebuilt events to a GenAIStreamConsumer.
72
+ *
73
+ * When reorder is enabled, packets are held until their seq number can be
74
+ * delivered contiguously. This is intentionally stream-local; callers should set
75
+ * streamId when multiplexing multiple streams over one network. On the wire,
76
+ * that stream id is carried as the compact `sid` field.
77
+ */
78
+ export declare const createGenAIStreamNetworkReceiver: (network: NetworkSupportable, consumer: GenAIStreamConsumer, options?: GenAIStreamNetworkOptions) => GenAIStreamNetworkReceiver;
79
+ /** subscribe to JSONTransport/network errors from a stream network handle */
80
+ export declare const onGenAIStreamNetworkError: (handle: GenAIStreamNetworkConsumerHandle | GenAIStreamNetworkReceiver, handler: SocketErrorHandler) => SocketUnsubscribe;
81
+ export declare const compactStreamEvent: (event: GenAIStreamEvent) => {
82
+ event: GenAIStreamEvent;
83
+ compact?: GenAIStreamNetworkCompactMeta;
84
+ };
85
+ /**
86
+ * Restore a network packet into the public GenAIStreamEvent shape expected by
87
+ * downstream consumers.
88
+ */
89
+ export declare const restoreStreamEvent: (packet: GenAIStreamNetworkPacket) => GenAIStreamEvent;
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.restoreStreamEvent = exports.compactStreamEvent = exports.onGenAIStreamNetworkError = exports.createGenAIStreamNetworkReceiver = exports.createGenAIStreamNetworkConsumer = exports.asGenAIStreamNetworkTransportOptions = void 0;
24
+ /**
25
+ * `buffer/network.ts`
26
+ * - Network transport adapters and diagnostics for GenAI stream events.
27
+ *
28
+ * @origin eureka-agents-api / src/lib/buffer/network.ts
29
+ *
30
+ * GenAIStreamConsumer emits typed events, while NetworkSupportable only accepts
31
+ * raw strings and may enforce a packet-size limit. This adapter keeps those
32
+ * concerns separate by sending stream events through JSONTransport.
33
+ */
34
+ const transport_1 = require("../socket/transport");
35
+ // eslint-disable-next-line prettier/prettier
36
+ const STREAM_EVENT_SPLIT_PATHS = ['/event/data', '/event/chunks/*/data', '/event/error/message', '/event/error/stack'];
37
+ const asGenAIStreamNetworkTransportOptions = (options) => {
38
+ var _a, _b, _c;
39
+ const jsonTransport = (_a = options === null || options === void 0 ? void 0 : options.jsonTransport) !== null && _a !== void 0 ? _a : {};
40
+ const chunkBytes = (_b = jsonTransport.chunkBytes) !== null && _b !== void 0 ? _b : ((options === null || options === void 0 ? void 0 : options.maxPacketBytes)
41
+ ? (0, transport_1.calculateJSONTransportChunkBytes)(options.maxPacketBytes, jsonTransport.envelopeReserveBytes)
42
+ : undefined);
43
+ return Object.assign(Object.assign({}, jsonTransport), { chunkBytes,
44
+ // eslint-disable-next-line prettier/prettier
45
+ preferredSplitPaths: [...STREAM_EVENT_SPLIT_PATHS, ...((_c = jsonTransport.preferredSplitPaths) !== null && _c !== void 0 ? _c : [])] });
46
+ };
47
+ exports.asGenAIStreamNetworkTransportOptions = asGenAIStreamNetworkTransportOptions;
48
+ /**
49
+ * Create a GenAIStreamConsumer that serializes stream events and sends them over
50
+ * NetworkSupportable via JSONTransport.
51
+ *
52
+ * The returned consumer preserves the normal GenAIStreamConsumer contract. The
53
+ * only network-specific behavior is packet wrapping, optional flush compaction,
54
+ * and JSONTransport splitting for large string payloads.
55
+ */
56
+ const createGenAIStreamNetworkConsumer = (network, options) => {
57
+ var _a;
58
+ const transport = (0, transport_1.createJSONTransport)(network, (0, exports.asGenAIStreamNetworkTransportOptions)(options));
59
+ const waitReady = (_a = options === null || options === void 0 ? void 0 : options.waitReady) !== null && _a !== void 0 ? _a : true;
60
+ let seq = 0;
61
+ const consumer = (event) => __awaiter(void 0, void 0, void 0, function* () {
62
+ if (waitReady && network.ready)
63
+ yield network.ready();
64
+ const compacted = (options === null || options === void 0 ? void 0 : options.compactFlush) ? (0, exports.compactStreamEvent)(event) : { event };
65
+ transport.send(Object.assign({ type: 'genai:stream', sid: options === null || options === void 0 ? void 0 : options.streamId, seq: seq++, sentAt: Date.now() }, compacted));
66
+ });
67
+ return {
68
+ consumer,
69
+ transport,
70
+ detach: () => transport.detach(),
71
+ };
72
+ };
73
+ exports.createGenAIStreamNetworkConsumer = createGenAIStreamNetworkConsumer;
74
+ /**
75
+ * Receive GenAI stream event packets from a NetworkSupportable and forward the
76
+ * rebuilt events to a GenAIStreamConsumer.
77
+ *
78
+ * When reorder is enabled, packets are held until their seq number can be
79
+ * delivered contiguously. This is intentionally stream-local; callers should set
80
+ * streamId when multiplexing multiple streams over one network. On the wire,
81
+ * that stream id is carried as the compact `sid` field.
82
+ */
83
+ const createGenAIStreamNetworkReceiver = (network, consumer, options) => {
84
+ const transport = (0, transport_1.createJSONTransport)(network, (0, exports.asGenAIStreamNetworkTransportOptions)(options));
85
+ // Reordering is deliberately simple: it waits for contiguous seq numbers
86
+ // from zero. A higher-level timeout policy should own missing packets.
87
+ let nextSeq = 0;
88
+ const pending = new Map();
89
+ const deliver = (packet) => {
90
+ const event = (0, exports.restoreStreamEvent)(packet);
91
+ void Promise.resolve(consumer(event)).catch(error => {
92
+ var _a;
93
+ (_a = options === null || options === void 0 ? void 0 : options.onConsumerError) === null || _a === void 0 ? void 0 : _a.call(options, error, { scope: 'genai.stream.consumer', network });
94
+ });
95
+ };
96
+ const accept = (packet) => {
97
+ var _a;
98
+ (_a = options === null || options === void 0 ? void 0 : options.onPacket) === null || _a === void 0 ? void 0 : _a.call(options, packet);
99
+ if (!(options === null || options === void 0 ? void 0 : options.reorder)) {
100
+ deliver(packet);
101
+ return;
102
+ }
103
+ pending.set(packet.seq, packet);
104
+ while (pending.has(nextSeq)) {
105
+ const ordered = pending.get(nextSeq);
106
+ pending.delete(nextSeq++);
107
+ deliver(ordered);
108
+ }
109
+ };
110
+ transport.onMessage(packet => {
111
+ if ((packet === null || packet === void 0 ? void 0 : packet.type) !== 'genai:stream')
112
+ return;
113
+ if ((options === null || options === void 0 ? void 0 : options.streamId) && packet.sid !== options.streamId)
114
+ return;
115
+ accept(packet);
116
+ });
117
+ return {
118
+ transport,
119
+ detach: () => transport.detach(),
120
+ };
121
+ };
122
+ exports.createGenAIStreamNetworkReceiver = createGenAIStreamNetworkReceiver;
123
+ /** subscribe to JSONTransport/network errors from a stream network handle */
124
+ const onGenAIStreamNetworkError = (handle, handler) => handle.transport.onError(handler);
125
+ exports.onGenAIStreamNetworkError = onGenAIStreamNetworkError;
126
+ const compactStreamEvent = (event) => {
127
+ if (event.type !== 'flush' || !canCompactFlushEvent(event))
128
+ return { event };
129
+ return {
130
+ event: Object.assign(Object.assign({}, event), { chunks: event.chunks.map(chunk => {
131
+ const { data: _data } = chunk, rest = __rest(chunk, ["data"]);
132
+ return rest;
133
+ }) }),
134
+ compact: { flushChunksData: 'fromFlushData' },
135
+ };
136
+ };
137
+ exports.compactStreamEvent = compactStreamEvent;
138
+ /**
139
+ * Restore a network packet into the public GenAIStreamEvent shape expected by
140
+ * downstream consumers.
141
+ */
142
+ const restoreStreamEvent = (packet) => {
143
+ var _a;
144
+ const event = packet.event;
145
+ if (event.type !== 'flush' || ((_a = packet.compact) === null || _a === void 0 ? void 0 : _a.flushChunksData) !== 'fromFlushData')
146
+ return event;
147
+ let offset = 0;
148
+ return Object.assign(Object.assign({}, event), { chunks: event.chunks.map(chunk => {
149
+ var _a;
150
+ const chars = (_a = chunk.chars) !== null && _a !== void 0 ? _a : 0;
151
+ const data = event.data.substring(offset, offset + chars);
152
+ offset += chars;
153
+ return Object.assign(Object.assign({}, chunk), { data });
154
+ }) });
155
+ };
156
+ exports.restoreStreamEvent = restoreStreamEvent;
157
+ /**
158
+ * Flush events normally carry both joined data and per-chunk data. Compacting is
159
+ * safe only when chunk data is exactly contiguous within flush.data.
160
+ */
161
+ const canCompactFlushEvent = (event) => {
162
+ var _a;
163
+ let offset = 0;
164
+ for (const chunk of event.chunks) {
165
+ const chars = (_a = chunk.chars) !== null && _a !== void 0 ? _a : chunk.data.length;
166
+ if (event.data.substring(offset, offset + chars) !== chunk.data)
167
+ return false;
168
+ offset += chars;
169
+ }
170
+ return offset === event.data.length;
171
+ };
172
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/buffer/network.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,220 @@
1
+ /**
2
+ * `buffer/stream.ts`
3
+ * - Provider-neutral GenAI stream buffering primitives.
4
+ *
5
+ * @origin eureka-agents-api / src/lib/buffer/stream.ts
6
+ *
7
+ * Common stream buffering primitives for GenAI providers.
8
+ *
9
+ * This module is intentionally provider-neutral. Gemini/OpenAI adapters can
10
+ * convert their native stream chunks into GenAIStreamEvent and let this buffer
11
+ * handle batching, FIFO ordering, and progress calculation.
12
+ */
13
+ export declare type GenAIStreamKind = 'text' | 'json' | 'image' | 'binary' | 'unknown';
14
+ export declare type GenAIStreamFlushStrategy = 'size' | 'time' | 'bytes' | 'hybrid';
15
+ export interface GenAIStreamEstimate {
16
+ /** expected generated character count, if known or estimated */
17
+ totalChars?: number;
18
+ /** expected generated byte count, if known or estimated */
19
+ totalBytes?: number;
20
+ /** expected generated token count, if known or estimated */
21
+ totalTokens?: number;
22
+ /** where the estimate came from, e.g. maxOutputTokens, sample, imageSize */
23
+ source?: string;
24
+ /** true when the value is inferred rather than exact */
25
+ estimated?: boolean;
26
+ /** optional confidence in [0, 1] */
27
+ confidence?: number;
28
+ }
29
+ export interface GenAIStreamProgress {
30
+ loadedChars: number;
31
+ loadedBytes: number;
32
+ loadedTokens?: number;
33
+ totalChars?: number;
34
+ totalBytes?: number;
35
+ totalTokens?: number;
36
+ /** stream-total progress from chars/bytes/tokens estimates, if available */
37
+ percent?: number;
38
+ /** buffer-cycle progress, always present while the buffer can estimate it */
39
+ bufferPercent?: number;
40
+ /** buffer-cycle progress source */
41
+ source?: 'chunk' | 'interval' | 'flush' | 'eof' | 'snapshot';
42
+ pendingChunks?: number;
43
+ pendingBytes?: number;
44
+ pendingChars?: number;
45
+ bufferElapsedMs?: number;
46
+ bufferTargetChunks?: number;
47
+ bufferTargetBytes?: number;
48
+ bufferTargetMs?: number;
49
+ estimated: boolean;
50
+ }
51
+ export interface GenAIStreamMeta {
52
+ provider?: string;
53
+ model?: string;
54
+ kind?: GenAIStreamKind;
55
+ estimate?: GenAIStreamEstimate;
56
+ [key: string]: any;
57
+ }
58
+ export interface GenAIStreamEventBase {
59
+ id?: string;
60
+ index?: number;
61
+ createdAt?: number;
62
+ meta?: GenAIStreamMeta;
63
+ }
64
+ export interface GenAIStreamStartEvent extends GenAIStreamEventBase {
65
+ type: 'start';
66
+ estimate?: GenAIStreamEstimate;
67
+ }
68
+ export interface GenAIStreamChunkEvent extends GenAIStreamEventBase {
69
+ type: 'chunk';
70
+ data: string;
71
+ chars?: number;
72
+ bytes?: number;
73
+ tokens?: number;
74
+ progress?: GenAIStreamProgress;
75
+ }
76
+ export interface GenAIStreamFlushEvent extends GenAIStreamEventBase {
77
+ type: 'flush';
78
+ data: string;
79
+ chunks: GenAIStreamChunkEvent[];
80
+ count: number;
81
+ chars: number;
82
+ bytes: number;
83
+ progress: GenAIStreamProgress;
84
+ }
85
+ export interface GenAIStreamProgressEvent extends GenAIStreamEventBase {
86
+ type: 'progress';
87
+ progress: GenAIStreamProgress;
88
+ }
89
+ export interface GenAIStreamEofEvent extends GenAIStreamEventBase {
90
+ type: 'eof';
91
+ progress: GenAIStreamProgress;
92
+ }
93
+ export interface GenAIStreamErrorEvent extends GenAIStreamEventBase {
94
+ type: 'error';
95
+ error: any;
96
+ }
97
+ export declare type GenAIStreamEvent = GenAIStreamStartEvent | GenAIStreamChunkEvent | GenAIStreamFlushEvent | GenAIStreamProgressEvent | GenAIStreamEofEvent | GenAIStreamErrorEvent;
98
+ export interface GenAIStreamConsumer {
99
+ (event: GenAIStreamEvent): Promise<void> | void;
100
+ }
101
+ export interface GenAILegacyTokenConsumer {
102
+ (token?: string | null): Promise<void> | void;
103
+ }
104
+ export interface GenAIStreamBufferOptions {
105
+ /** disable buffering and flush every chunk immediately */
106
+ useBuffer?: boolean;
107
+ /** size: count, time: timer, bytes: bytes, hybrid: any condition */
108
+ flushStrategy?: GenAIStreamFlushStrategy;
109
+ /** chunk count threshold */
110
+ bufferSize?: number;
111
+ /** byte threshold */
112
+ bufferBytes?: number;
113
+ /** time strategy interval */
114
+ bufferMs?: number;
115
+ /** max wait for size/bytes/hybrid strategies */
116
+ maxWaitMs?: number;
117
+ /** initial stream metadata */
118
+ meta?: GenAIStreamMeta;
119
+ /** emit progress events after each accepted chunk */
120
+ emitProgress?: boolean;
121
+ /** emit current buffer progress on this interval while chunks are pending; 0 disables */
122
+ progressIntervalMs?: number;
123
+ /** emit an error and close the buffer if the stream stays open longer than this; 0 disables */
124
+ timeoutMs?: number;
125
+ }
126
+ export interface GenAIStreamBufferSnapshot {
127
+ pendingChunks: number;
128
+ pendingChars: number;
129
+ pendingBytes: number;
130
+ loadedChars: number;
131
+ loadedBytes: number;
132
+ loadedTokens?: number;
133
+ closed: boolean;
134
+ progress: GenAIStreamProgress;
135
+ }
136
+ export interface GenAIMockStreamOptions {
137
+ kind?: GenAIStreamKind;
138
+ provider?: string;
139
+ model?: string;
140
+ chunkSize?: number;
141
+ intervalMs?: number;
142
+ estimate?: GenAIStreamEstimate;
143
+ }
144
+ /**
145
+ * Estimate text output size from common generation hints.
146
+ */
147
+ export declare const estimateGenAIStreamSize: (hint?: {
148
+ kind?: GenAIStreamKind;
149
+ maxOutputTokens?: number;
150
+ maxTokens?: number;
151
+ totalChars?: number;
152
+ totalBytes?: number;
153
+ totalTokens?: number;
154
+ imageSize?: '1k' | '2k' | '4k' | string;
155
+ imageFormat?: 'png' | 'jpeg' | 'jpg' | 'webp' | string;
156
+ }) => GenAIStreamEstimate | undefined;
157
+ /**
158
+ * FIFO stream buffer. Chunk events are queued and flushed as a single `flush`
159
+ * event when size/time/byte conditions are met.
160
+ */
161
+ export declare class GenAIStreamBuffer {
162
+ private readonly consumer;
163
+ private readonly options;
164
+ private readonly meta?;
165
+ private queue;
166
+ private timer?;
167
+ private progressTimer?;
168
+ private timeoutTimer?;
169
+ private processing;
170
+ private closed;
171
+ private index;
172
+ private loadedChars;
173
+ private loadedBytes;
174
+ private loadedTokens;
175
+ private estimate?;
176
+ private cycleStartedAt?;
177
+ private lastProgress?;
178
+ constructor(consumer: GenAIStreamConsumer, options?: GenAIStreamBufferOptions);
179
+ start(meta?: GenAIStreamMeta): Promise<void>;
180
+ write(data: string, meta?: GenAIStreamMeta & {
181
+ tokens?: number;
182
+ }): Promise<void>;
183
+ push(event: string | GenAIStreamEvent): Promise<void>;
184
+ flush(): Promise<void>;
185
+ close(): Promise<void>;
186
+ cancel(reason?: any): Promise<void>;
187
+ snapshot(): GenAIStreamBufferSnapshot;
188
+ private enqueue;
189
+ private normalizeEvent;
190
+ private normalizeChunk;
191
+ private asChunk;
192
+ private progress;
193
+ private bufferProgress;
194
+ private emitProgress;
195
+ private shouldFlush;
196
+ private scheduleFlush;
197
+ private scheduleProgress;
198
+ private scheduleTimeout;
199
+ private clearTimer;
200
+ private clearProgressTimer;
201
+ private clearTimeout;
202
+ private reportError;
203
+ private ensureOpen;
204
+ }
205
+ /**
206
+ * Convert a stream-event consumer into the existing token/null consumer shape.
207
+ */
208
+ export declare const asLegacyTokenConsumer: (consumer: GenAIStreamConsumer) => GenAILegacyTokenConsumer;
209
+ /**
210
+ * Convert a legacy token consumer into a stream-event consumer.
211
+ */
212
+ export declare const asStreamConsumer: (consumer: GenAILegacyTokenConsumer) => GenAIStreamConsumer;
213
+ /**
214
+ * Create provider-like mock stream events from a text payload.
215
+ */
216
+ export declare function mockGenAIStream(content: string, options?: GenAIMockStreamOptions): AsyncGenerator<GenAIStreamEvent, void, unknown>;
217
+ /**
218
+ * Run mock stream events through GenAIStreamBuffer.
219
+ */
220
+ export declare const runMockGenAIStream: (content: string, consumer: GenAIStreamConsumer, bufferOptions?: GenAIStreamBufferOptions, mockOptions?: GenAIMockStreamOptions) => Promise<GenAIStreamBufferSnapshot>;