llm-stream-assemble 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,372 @@
1
+ // src/adapters/utils.ts
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function asString(value) {
6
+ return typeof value === "string" ? value : void 0;
7
+ }
8
+ function asNumber(value) {
9
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
10
+ }
11
+ function optionalRawChunk(input) {
12
+ return Object.fromEntries(
13
+ Object.entries(input).filter(([, value]) => value !== void 0)
14
+ );
15
+ }
16
+ function prefixedAdapterError(feature, message) {
17
+ return adapterScopedError(feature, message);
18
+ }
19
+ function createStreamAdapter(config) {
20
+ return {
21
+ parseChunk(raw) {
22
+ return config.parser.parseChunk(raw);
23
+ },
24
+ parseResponse(body) {
25
+ return config.parseResponse(body, config.options);
26
+ }
27
+ };
28
+ }
29
+ function parseAdapterJSON(raw, feature) {
30
+ try {
31
+ return JSON.parse(raw);
32
+ } catch (error) {
33
+ const message = error instanceof Error ? error.message : String(error);
34
+ throw prefixedAdapterError(feature, message);
35
+ }
36
+ }
37
+
38
+ // src/adapters/errors.ts
39
+ function libraryError(message) {
40
+ return new Error(`llm-stream-assemble: ${message}`);
41
+ }
42
+ function adapterScopedError(scope, message) {
43
+ return new Error(`llm-stream-assemble: ${scope}: ${message}`);
44
+ }
45
+ function providerErrorChunks(error, recoverable = false) {
46
+ return [
47
+ { kind: "provider-error", error, recoverable },
48
+ { kind: "finish", reason: "error" }
49
+ ];
50
+ }
51
+ function providerErrorChunksFromMessage(message, recoverable = false) {
52
+ return providerErrorChunks(libraryError(message), recoverable);
53
+ }
54
+ function providerErrorChunksFromPayload(errorPayload, scope, recoverable, fallbackMessage) {
55
+ const message = asString(errorPayload.message) ?? fallbackMessage;
56
+ const error = adapterScopedError(scope, message);
57
+ Object.defineProperty(error, "raw", {
58
+ value: errorPayload,
59
+ enumerable: false
60
+ });
61
+ return providerErrorChunks(error, recoverable);
62
+ }
63
+
64
+ // src/adapters/gemini.ts
65
+ function geminiAdapter(options = {}) {
66
+ const parser = new GeminiStreamParser(options);
67
+ return createStreamAdapter({
68
+ parser,
69
+ parseResponse,
70
+ options
71
+ });
72
+ }
73
+ var GeminiStreamParser = class {
74
+ constructor(options) {
75
+ this.options = options;
76
+ }
77
+ options;
78
+ metadataEmitted = false;
79
+ tools = /* @__PURE__ */ new Map();
80
+ openToolByChoice = /* @__PURE__ */ new Map();
81
+ toolCounter = 0;
82
+ parseChunk(raw) {
83
+ const trimmed = raw.trim();
84
+ if (trimmed.length === 0 || trimmed === "[DONE]") return [];
85
+ const payload = parseAdapterJSON(trimmed, "geminiAdapter.parseChunk");
86
+ if (!isRecord(payload)) {
87
+ throw libraryError("geminiAdapter.parseChunk expected a JSON object");
88
+ }
89
+ if (isRecord(payload.error)) {
90
+ return providerErrorChunksFromPayload(
91
+ payload.error,
92
+ "geminiAdapter.parseChunk",
93
+ false,
94
+ "Gemini provider error"
95
+ );
96
+ }
97
+ const chunks = [];
98
+ const feedback = isRecord(payload.promptFeedback) ? payload.promptFeedback : void 0;
99
+ const blockReason = feedback ? asString(feedback.blockReason) : void 0;
100
+ if (blockReason) {
101
+ return providerErrorChunksFromMessage(`Gemini prompt blocked: ${blockReason}`, false);
102
+ }
103
+ chunks.push(...this.metadataChunks(payload));
104
+ const usage = usageChunk(payload.usageMetadata);
105
+ if (usage) chunks.push(usage);
106
+ const candidates = Array.isArray(payload.candidates) ? payload.candidates : [];
107
+ for (const candidate of candidates) {
108
+ if (!isRecord(candidate)) continue;
109
+ chunks.push(...this.candidateChunks(candidate));
110
+ }
111
+ return chunks;
112
+ }
113
+ metadataChunks(payload) {
114
+ if (this.metadataEmitted) return [];
115
+ const responseId = asString(payload.responseId);
116
+ const model = asString(payload.modelVersion);
117
+ if (!responseId && !model) return [];
118
+ this.metadataEmitted = true;
119
+ const chunks = [];
120
+ if (responseId) chunks.push({ kind: "message-start", id: responseId });
121
+ chunks.push(
122
+ optionalRawChunk({
123
+ kind: "metadata",
124
+ responseId,
125
+ model,
126
+ raw: { responseId, modelVersion: model }
127
+ })
128
+ );
129
+ return chunks;
130
+ }
131
+ candidateChunks(candidate) {
132
+ const chunks = [];
133
+ const choiceIndex = asNumber(candidate.index) ?? 0;
134
+ const citation = candidate.citationMetadata;
135
+ const grounding = candidate.groundingMetadata;
136
+ if (citation !== void 0 || grounding !== void 0) {
137
+ chunks.push(
138
+ optionalRawChunk({
139
+ kind: "metadata",
140
+ raw: { citationMetadata: citation, groundingMetadata: grounding }
141
+ })
142
+ );
143
+ }
144
+ const content = isRecord(candidate.content) ? candidate.content : void 0;
145
+ const parts = content && Array.isArray(content.parts) ? content.parts : [];
146
+ for (let partIndex = 0; partIndex < parts.length; partIndex += 1) {
147
+ const part = parts[partIndex];
148
+ if (!isRecord(part)) continue;
149
+ chunks.push(...this.partChunks(part, partIndex, choiceIndex));
150
+ }
151
+ const finishReason = asString(candidate.finishReason);
152
+ if (finishReason) {
153
+ const mapped = mapFinishReason(finishReason);
154
+ if (mapped === "error") {
155
+ chunks.push(
156
+ ...providerErrorChunksFromMessage(`Gemini finishReason: ${finishReason}`, false)
157
+ );
158
+ } else {
159
+ chunks.push({ kind: "finish", reason: mapped, choiceIndex });
160
+ }
161
+ }
162
+ return chunks;
163
+ }
164
+ partChunks(part, partIndex, choiceIndex) {
165
+ if (isRecord(part.functionResponse)) return [];
166
+ if (part.inlineData !== void 0 || part.fileData !== void 0) return [];
167
+ if (part.executableCode !== void 0 || part.codeExecutionResult !== void 0) return [];
168
+ const thought = part.thought === true;
169
+ const text = asString(part.text);
170
+ if (thought && text) {
171
+ return [{ kind: "reasoning-delta", text, variant: "detail" }];
172
+ }
173
+ if (thought && !text) return [];
174
+ if (text !== void 0) {
175
+ if (text.length === 0) return [];
176
+ if (this.options.jsonMode) return [{ kind: "json-delta", delta: text }];
177
+ return [{ kind: "text-delta", text, choiceIndex }];
178
+ }
179
+ const functionCall = isRecord(part.functionCall) ? part.functionCall : void 0;
180
+ if (functionCall) return this.functionCallChunks(functionCall, partIndex, choiceIndex);
181
+ if (Object.keys(part).length === 0) return [];
182
+ return [];
183
+ }
184
+ functionCallChunks(functionCall, partIndex, choiceIndex) {
185
+ const chunks = [];
186
+ const explicitId = asString(functionCall.id);
187
+ const name = asString(functionCall.name);
188
+ let toolKey = this.resolveToolKey(explicitId, partIndex, choiceIndex, name);
189
+ if (name && !this.tools.has(toolKey)) {
190
+ toolKey = explicitId ?? `${choiceIndex}:${partIndex}`;
191
+ const id = explicitId ?? `gemini:${choiceIndex}:${this.toolCounter++}`;
192
+ this.tools.set(toolKey, {
193
+ id,
194
+ name,
195
+ index: partIndex,
196
+ choiceIndex,
197
+ lastArgsJson: "",
198
+ open: true
199
+ });
200
+ this.openToolByChoice.set(choiceIndex, toolKey);
201
+ chunks.push(
202
+ optionalRawChunk({
203
+ kind: "tool-start",
204
+ id,
205
+ name,
206
+ index: partIndex,
207
+ choiceIndex
208
+ })
209
+ );
210
+ }
211
+ const current = this.tools.get(toolKey);
212
+ if (!current) return chunks;
213
+ const partialArgs = Array.isArray(functionCall.partialArgs) ? functionCall.partialArgs : [];
214
+ for (const item of partialArgs) {
215
+ if (!isRecord(item)) continue;
216
+ const delta = partialArgDelta(item);
217
+ if (delta) {
218
+ chunks.push(
219
+ optionalRawChunk({
220
+ kind: "tool-args-delta",
221
+ id: current.id,
222
+ delta,
223
+ index: current.index,
224
+ choiceIndex
225
+ })
226
+ );
227
+ }
228
+ }
229
+ if (isRecord(functionCall.args)) {
230
+ const delta = this.argsObjectDelta(toolKey, functionCall.args);
231
+ if (delta) {
232
+ chunks.push(
233
+ optionalRawChunk({
234
+ kind: "tool-args-delta",
235
+ id: current.id,
236
+ delta,
237
+ index: current.index,
238
+ choiceIndex
239
+ })
240
+ );
241
+ }
242
+ }
243
+ const willContinue = functionCall.willContinue === true;
244
+ const hasPartialArgs = partialArgs.length > 0;
245
+ const hasArgs = isRecord(functionCall.args) && Object.keys(functionCall.args).length > 0;
246
+ if (!willContinue && !hasPartialArgs && (hasArgs || name && isRecord(functionCall.args))) {
247
+ chunks.push(
248
+ optionalRawChunk({
249
+ kind: "tool-done",
250
+ id: current.id,
251
+ index: current.index,
252
+ choiceIndex
253
+ })
254
+ );
255
+ current.open = false;
256
+ } else if (!willContinue && hasPartialArgs && partialArgs.every((item) => isRecord(item) && item.willContinue !== true)) {
257
+ if (current.open) {
258
+ chunks.push(
259
+ optionalRawChunk({
260
+ kind: "tool-done",
261
+ id: current.id,
262
+ index: current.index,
263
+ choiceIndex
264
+ })
265
+ );
266
+ current.open = false;
267
+ }
268
+ }
269
+ return chunks;
270
+ }
271
+ resolveToolKey(explicitId, partIndex, choiceIndex, name) {
272
+ if (explicitId) return explicitId;
273
+ const openKey = this.openToolByChoice.get(choiceIndex);
274
+ if (openKey && this.tools.get(openKey)?.open) return openKey;
275
+ if (name) {
276
+ for (const [key, state] of this.tools) {
277
+ if (state.choiceIndex === choiceIndex && state.name === name && state.open) return key;
278
+ }
279
+ }
280
+ return `${choiceIndex}:${partIndex}`;
281
+ }
282
+ argsObjectDelta(toolKey, args) {
283
+ const next = JSON.stringify(args);
284
+ const state = this.tools.get(toolKey);
285
+ const prev = state?.lastArgsJson ?? "";
286
+ if (next === prev) return void 0;
287
+ let delta;
288
+ if (prev.length > 0 && next.startsWith(prev)) {
289
+ delta = next.slice(prev.length);
290
+ } else {
291
+ delta = next;
292
+ }
293
+ if (state) state.lastArgsJson = next;
294
+ return delta.length > 0 ? delta : void 0;
295
+ }
296
+ };
297
+ function parseResponse(body, options) {
298
+ if (!isRecord(body)) {
299
+ throw libraryError("geminiAdapter.parseResponse expected a GenerateContentResponse object");
300
+ }
301
+ const parser = new GeminiStreamParser(options);
302
+ const chunks = [];
303
+ if (isRecord(body.error)) {
304
+ return providerErrorChunksFromPayload(
305
+ body.error,
306
+ "geminiAdapter.parseResponse",
307
+ false,
308
+ "Gemini provider error"
309
+ );
310
+ }
311
+ const feedback = isRecord(body.promptFeedback) ? body.promptFeedback : void 0;
312
+ const blockReason = feedback ? asString(feedback.blockReason) : void 0;
313
+ if (blockReason) {
314
+ return providerErrorChunksFromMessage(`Gemini prompt blocked: ${blockReason}`, false);
315
+ }
316
+ chunks.push(...parser.parseChunk(JSON.stringify(body)));
317
+ const hasFinish = chunks.some((chunk) => chunk.kind === "finish");
318
+ if (!hasFinish) {
319
+ chunks.push({ kind: "finish", reason: "stop" });
320
+ }
321
+ return chunks;
322
+ }
323
+ function partialArgDelta(arg) {
324
+ const stringValue = asString(arg.stringValue);
325
+ if (stringValue !== void 0) return stringValue;
326
+ const jsonPath = asString(arg.jsonPath) ?? "$";
327
+ const key = jsonPath.replace(/^\$\.?/, "").split(".")[0] ?? "value";
328
+ if (arg.numberValue !== void 0) return JSON.stringify({ [key]: arg.numberValue });
329
+ if (arg.boolValue !== void 0) return JSON.stringify({ [key]: arg.boolValue });
330
+ if (arg.nullValue !== void 0) return JSON.stringify({ [key]: null });
331
+ return void 0;
332
+ }
333
+ function mapFinishReason(value) {
334
+ switch (value) {
335
+ case "STOP":
336
+ case "STOP_REASON_UNSPECIFIED":
337
+ return "stop";
338
+ case "MAX_TOKENS":
339
+ return "length";
340
+ case "SAFETY":
341
+ case "RECITATION":
342
+ case "BLOCKLIST":
343
+ case "PROHIBITED_CONTENT":
344
+ case "SPII":
345
+ case "LANGUAGE":
346
+ return "content_filter";
347
+ case "MALFORMED_FUNCTION_CALL":
348
+ return "error";
349
+ default:
350
+ return "error";
351
+ }
352
+ }
353
+ function usageChunk(value) {
354
+ if (!isRecord(value)) return void 0;
355
+ const inputTokens = asNumber(value.promptTokenCount);
356
+ const outputTokens = asNumber(value.candidatesTokenCount);
357
+ const reasoningTokens = asNumber(value.thoughtsTokenCount);
358
+ if (inputTokens === void 0 && outputTokens === void 0 && reasoningTokens === void 0) {
359
+ return void 0;
360
+ }
361
+ return optionalRawChunk({
362
+ kind: "usage",
363
+ inputTokens,
364
+ outputTokens,
365
+ reasoningTokens,
366
+ raw: value
367
+ });
368
+ }
369
+
370
+ export { geminiAdapter };
371
+ //# sourceMappingURL=gemini.js.map
372
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/utils.ts","../../src/adapters/errors.ts","../../src/adapters/gemini.ts"],"names":[],"mappings":"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","file":"gemini.js","sourcesContent":["/** Internal adapter utilities. Not part of the public API. */\nimport type { RawChunk, StreamAdapter } from \"../core/types\";\nimport { adapterScopedError } from \"./errors\";\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function asString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : undefined;\n}\n\nexport function asNumber(value: unknown): number | undefined {\n\treturn typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nexport function optionalRawChunk(input: Record<string, unknown>): RawChunk {\n\treturn Object.fromEntries(\n\t\tObject.entries(input).filter(([, value]) => value !== undefined),\n\t) as RawChunk;\n}\n\nexport function prefixedAdapterError(feature: string, message: string): Error {\n\treturn adapterScopedError(feature, message);\n}\n\nexport function createStreamAdapter<TOptions>(config: {\n\tparser: { parseChunk(raw: string): RawChunk[] };\n\tparseResponse: (body: unknown, options: TOptions) => RawChunk[];\n\toptions: TOptions;\n}): StreamAdapter {\n\treturn {\n\t\tparseChunk(raw) {\n\t\t\treturn config.parser.parseChunk(raw);\n\t\t},\n\t\tparseResponse(body) {\n\t\t\treturn config.parseResponse(body, config.options);\n\t\t},\n\t};\n}\n\nexport function parseAdapterJSON(raw: string, feature: string): unknown {\n\ttry {\n\t\treturn JSON.parse(raw) as unknown;\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow prefixedAdapterError(feature, message);\n\t}\n}\n","/** Internal adapter error helpers. Not part of the public API. */\nimport type { RawChunk } from \"../core/types\";\nimport { asString } from \"./utils\";\n\nexport function libraryError(message: string): Error {\n\treturn new Error(`llm-stream-assemble: ${message}`);\n}\n\nexport function adapterScopedError(scope: string, message: string): Error {\n\treturn new Error(`llm-stream-assemble: ${scope}: ${message}`);\n}\n\nexport function providerErrorChunks(error: Error, recoverable = false): RawChunk[] {\n\treturn [\n\t\t{ kind: \"provider-error\", error, recoverable },\n\t\t{ kind: \"finish\", reason: \"error\" },\n\t];\n}\n\nexport function providerErrorChunksFromMessage(message: string, recoverable = false): RawChunk[] {\n\treturn providerErrorChunks(libraryError(message), recoverable);\n}\n\nexport function providerErrorChunksFromPayload(\n\terrorPayload: Record<string, unknown>,\n\tscope: string,\n\trecoverable: boolean,\n\tfallbackMessage: string,\n): RawChunk[] {\n\tconst message = asString(errorPayload.message) ?? fallbackMessage;\n\tconst error = adapterScopedError(scope, message);\n\tObject.defineProperty(error, \"raw\", {\n\t\tvalue: errorPayload,\n\t\tenumerable: false,\n\t});\n\treturn providerErrorChunks(error, recoverable);\n}\n","import type { FinishReason, RawChunk, StreamAdapter } from \"../core/types\";\nimport {\n\tlibraryError,\n\tproviderErrorChunksFromMessage,\n\tproviderErrorChunksFromPayload,\n} from \"./errors\";\nimport {\n\tasNumber,\n\tasString,\n\tcreateStreamAdapter,\n\tisRecord,\n\toptionalRawChunk,\n\tparseAdapterJSON,\n} from \"./utils\";\n\nexport interface GeminiAdapterOptions {\n\t/** Map text parts to json-delta instead of text-delta. */\n\tjsonMode?: boolean;\n}\n\ninterface ToolState {\n\tid: string;\n\tname: string;\n\tindex: number;\n\tchoiceIndex: number;\n\tlastArgsJson: string;\n\topen: boolean;\n}\n\nexport function geminiAdapter(options: GeminiAdapterOptions = {}): StreamAdapter {\n\tconst parser = new GeminiStreamParser(options);\n\treturn createStreamAdapter({\n\t\tparser,\n\t\tparseResponse,\n\t\toptions,\n\t});\n}\n\nclass GeminiStreamParser {\n\tprivate metadataEmitted = false;\n\tprivate readonly tools = new Map<string, ToolState>();\n\tprivate readonly openToolByChoice = new Map<number, string>();\n\tprivate toolCounter = 0;\n\n\tconstructor(private readonly options: GeminiAdapterOptions) {}\n\n\tparseChunk(raw: string): RawChunk[] {\n\t\tconst trimmed = raw.trim();\n\t\tif (trimmed.length === 0 || trimmed === \"[DONE]\") return [];\n\n\t\tconst payload = parseAdapterJSON(trimmed, \"geminiAdapter.parseChunk\");\n\t\tif (!isRecord(payload)) {\n\t\t\tthrow libraryError(\"geminiAdapter.parseChunk expected a JSON object\");\n\t\t}\n\n\t\tif (isRecord(payload.error)) {\n\t\t\treturn providerErrorChunksFromPayload(\n\t\t\t\tpayload.error,\n\t\t\t\t\"geminiAdapter.parseChunk\",\n\t\t\t\tfalse,\n\t\t\t\t\"Gemini provider error\",\n\t\t\t);\n\t\t}\n\n\t\tconst chunks: RawChunk[] = [];\n\t\tconst feedback = isRecord(payload.promptFeedback) ? payload.promptFeedback : undefined;\n\t\tconst blockReason = feedback ? asString(feedback.blockReason) : undefined;\n\t\tif (blockReason) {\n\t\t\treturn providerErrorChunksFromMessage(`Gemini prompt blocked: ${blockReason}`, false);\n\t\t}\n\n\t\tchunks.push(...this.metadataChunks(payload));\n\n\t\tconst usage = usageChunk(payload.usageMetadata);\n\t\tif (usage) chunks.push(usage);\n\n\t\tconst candidates = Array.isArray(payload.candidates) ? payload.candidates : [];\n\t\tfor (const candidate of candidates) {\n\t\t\tif (!isRecord(candidate)) continue;\n\t\t\tchunks.push(...this.candidateChunks(candidate));\n\t\t}\n\n\t\treturn chunks;\n\t}\n\n\tprivate metadataChunks(payload: Record<string, unknown>): RawChunk[] {\n\t\tif (this.metadataEmitted) return [];\n\t\tconst responseId = asString(payload.responseId);\n\t\tconst model = asString(payload.modelVersion);\n\t\tif (!responseId && !model) return [];\n\n\t\tthis.metadataEmitted = true;\n\t\tconst chunks: RawChunk[] = [];\n\t\tif (responseId) chunks.push({ kind: \"message-start\", id: responseId });\n\t\tchunks.push(\n\t\t\toptionalRawChunk({\n\t\t\t\tkind: \"metadata\",\n\t\t\t\tresponseId,\n\t\t\t\tmodel,\n\t\t\t\traw: { responseId, modelVersion: model },\n\t\t\t}),\n\t\t);\n\t\treturn chunks;\n\t}\n\n\tprivate candidateChunks(candidate: Record<string, unknown>): RawChunk[] {\n\t\tconst chunks: RawChunk[] = [];\n\t\tconst choiceIndex = asNumber(candidate.index) ?? 0;\n\n\t\tconst citation = candidate.citationMetadata;\n\t\tconst grounding = candidate.groundingMetadata;\n\t\tif (citation !== undefined || grounding !== undefined) {\n\t\t\tchunks.push(\n\t\t\t\toptionalRawChunk({\n\t\t\t\t\tkind: \"metadata\",\n\t\t\t\t\traw: { citationMetadata: citation, groundingMetadata: grounding },\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst content = isRecord(candidate.content) ? candidate.content : undefined;\n\t\tconst parts = content && Array.isArray(content.parts) ? content.parts : [];\n\t\tfor (let partIndex = 0; partIndex < parts.length; partIndex += 1) {\n\t\t\tconst part = parts[partIndex];\n\t\t\tif (!isRecord(part)) continue;\n\t\t\tchunks.push(...this.partChunks(part, partIndex, choiceIndex));\n\t\t}\n\n\t\tconst finishReason = asString(candidate.finishReason);\n\t\tif (finishReason) {\n\t\t\tconst mapped = mapFinishReason(finishReason);\n\t\t\tif (mapped === \"error\") {\n\t\t\t\tchunks.push(\n\t\t\t\t\t...providerErrorChunksFromMessage(`Gemini finishReason: ${finishReason}`, false),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tchunks.push({ kind: \"finish\", reason: mapped, choiceIndex });\n\t\t\t}\n\t\t}\n\n\t\treturn chunks;\n\t}\n\n\tprivate partChunks(\n\t\tpart: Record<string, unknown>,\n\t\tpartIndex: number,\n\t\tchoiceIndex: number,\n\t): RawChunk[] {\n\t\tif (isRecord(part.functionResponse)) return [];\n\t\tif (part.inlineData !== undefined || part.fileData !== undefined) return [];\n\t\tif (part.executableCode !== undefined || part.codeExecutionResult !== undefined) return [];\n\n\t\tconst thought = part.thought === true;\n\t\tconst text = asString(part.text);\n\t\tif (thought && text) {\n\t\t\treturn [{ kind: \"reasoning-delta\", text, variant: \"detail\" }];\n\t\t}\n\t\tif (thought && !text) return [];\n\n\t\tif (text !== undefined) {\n\t\t\tif (text.length === 0) return [];\n\t\t\tif (this.options.jsonMode) return [{ kind: \"json-delta\", delta: text }];\n\t\t\treturn [{ kind: \"text-delta\", text, choiceIndex }];\n\t\t}\n\n\t\tconst functionCall = isRecord(part.functionCall) ? part.functionCall : undefined;\n\t\tif (functionCall) return this.functionCallChunks(functionCall, partIndex, choiceIndex);\n\n\t\tif (Object.keys(part).length === 0) return [];\n\t\treturn [];\n\t}\n\n\tprivate functionCallChunks(\n\t\tfunctionCall: Record<string, unknown>,\n\t\tpartIndex: number,\n\t\tchoiceIndex: number,\n\t): RawChunk[] {\n\t\tconst chunks: RawChunk[] = [];\n\t\tconst explicitId = asString(functionCall.id);\n\t\tconst name = asString(functionCall.name);\n\t\tlet toolKey = this.resolveToolKey(explicitId, partIndex, choiceIndex, name);\n\n\t\tif (name && !this.tools.has(toolKey)) {\n\t\t\ttoolKey = explicitId ?? `${choiceIndex}:${partIndex}`;\n\t\t\tconst id = explicitId ?? `gemini:${choiceIndex}:${this.toolCounter++}`;\n\t\t\tthis.tools.set(toolKey, {\n\t\t\t\tid,\n\t\t\t\tname,\n\t\t\t\tindex: partIndex,\n\t\t\t\tchoiceIndex,\n\t\t\t\tlastArgsJson: \"\",\n\t\t\t\topen: true,\n\t\t\t});\n\t\t\tthis.openToolByChoice.set(choiceIndex, toolKey);\n\t\t\tchunks.push(\n\t\t\t\toptionalRawChunk({\n\t\t\t\t\tkind: \"tool-start\",\n\t\t\t\t\tid,\n\t\t\t\t\tname,\n\t\t\t\t\tindex: partIndex,\n\t\t\t\t\tchoiceIndex,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst current = this.tools.get(toolKey);\n\t\tif (!current) return chunks;\n\n\t\tconst partialArgs = Array.isArray(functionCall.partialArgs) ? functionCall.partialArgs : [];\n\t\tfor (const item of partialArgs) {\n\t\t\tif (!isRecord(item)) continue;\n\t\t\tconst delta = partialArgDelta(item);\n\t\t\tif (delta) {\n\t\t\t\tchunks.push(\n\t\t\t\t\toptionalRawChunk({\n\t\t\t\t\t\tkind: \"tool-args-delta\",\n\t\t\t\t\t\tid: current.id,\n\t\t\t\t\t\tdelta,\n\t\t\t\t\t\tindex: current.index,\n\t\t\t\t\t\tchoiceIndex,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (isRecord(functionCall.args)) {\n\t\t\tconst delta = this.argsObjectDelta(toolKey, functionCall.args);\n\t\t\tif (delta) {\n\t\t\t\tchunks.push(\n\t\t\t\t\toptionalRawChunk({\n\t\t\t\t\t\tkind: \"tool-args-delta\",\n\t\t\t\t\t\tid: current.id,\n\t\t\t\t\t\tdelta,\n\t\t\t\t\t\tindex: current.index,\n\t\t\t\t\t\tchoiceIndex,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst willContinue = functionCall.willContinue === true;\n\t\tconst hasPartialArgs = partialArgs.length > 0;\n\t\tconst hasArgs = isRecord(functionCall.args) && Object.keys(functionCall.args).length > 0;\n\n\t\tif (!willContinue && !hasPartialArgs && (hasArgs || (name && isRecord(functionCall.args)))) {\n\t\t\tchunks.push(\n\t\t\t\toptionalRawChunk({\n\t\t\t\t\tkind: \"tool-done\",\n\t\t\t\t\tid: current.id,\n\t\t\t\t\tindex: current.index,\n\t\t\t\t\tchoiceIndex,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tcurrent.open = false;\n\t\t} else if (\n\t\t\t!willContinue &&\n\t\t\thasPartialArgs &&\n\t\t\tpartialArgs.every((item) => isRecord(item) && item.willContinue !== true)\n\t\t) {\n\t\t\tif (current.open) {\n\t\t\t\tchunks.push(\n\t\t\t\t\toptionalRawChunk({\n\t\t\t\t\t\tkind: \"tool-done\",\n\t\t\t\t\t\tid: current.id,\n\t\t\t\t\t\tindex: current.index,\n\t\t\t\t\t\tchoiceIndex,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tcurrent.open = false;\n\t\t\t}\n\t\t}\n\n\t\treturn chunks;\n\t}\n\n\tprivate resolveToolKey(\n\t\texplicitId: string | undefined,\n\t\tpartIndex: number,\n\t\tchoiceIndex: number,\n\t\tname: string | undefined,\n\t): string {\n\t\tif (explicitId) return explicitId;\n\t\tconst openKey = this.openToolByChoice.get(choiceIndex);\n\t\tif (openKey && this.tools.get(openKey)?.open) return openKey;\n\t\tif (name) {\n\t\t\tfor (const [key, state] of this.tools) {\n\t\t\t\tif (state.choiceIndex === choiceIndex && state.name === name && state.open) return key;\n\t\t\t}\n\t\t}\n\t\treturn `${choiceIndex}:${partIndex}`;\n\t}\n\n\tprivate argsObjectDelta(toolKey: string, args: Record<string, unknown>): string | undefined {\n\t\tconst next = JSON.stringify(args);\n\t\tconst state = this.tools.get(toolKey);\n\t\tconst prev = state?.lastArgsJson ?? \"\";\n\t\tif (next === prev) return undefined;\n\t\tlet delta: string;\n\t\tif (prev.length > 0 && next.startsWith(prev)) {\n\t\t\tdelta = next.slice(prev.length);\n\t\t} else {\n\t\t\tdelta = next;\n\t\t}\n\t\tif (state) state.lastArgsJson = next;\n\t\treturn delta.length > 0 ? delta : undefined;\n\t}\n}\n\nfunction parseResponse(body: unknown, options: GeminiAdapterOptions): RawChunk[] {\n\tif (!isRecord(body)) {\n\t\tthrow libraryError(\"geminiAdapter.parseResponse expected a GenerateContentResponse object\");\n\t}\n\n\tconst parser = new GeminiStreamParser(options);\n\tconst chunks: RawChunk[] = [];\n\n\tif (isRecord(body.error)) {\n\t\treturn providerErrorChunksFromPayload(\n\t\t\tbody.error,\n\t\t\t\"geminiAdapter.parseResponse\",\n\t\t\tfalse,\n\t\t\t\"Gemini provider error\",\n\t\t);\n\t}\n\n\tconst feedback = isRecord(body.promptFeedback) ? body.promptFeedback : undefined;\n\tconst blockReason = feedback ? asString(feedback.blockReason) : undefined;\n\tif (blockReason) {\n\t\treturn providerErrorChunksFromMessage(`Gemini prompt blocked: ${blockReason}`, false);\n\t}\n\n\tchunks.push(...parser.parseChunk(JSON.stringify(body)));\n\n\tconst hasFinish = chunks.some((chunk) => chunk.kind === \"finish\");\n\tif (!hasFinish) {\n\t\tchunks.push({ kind: \"finish\", reason: \"stop\" });\n\t}\n\n\treturn chunks;\n}\n\nfunction partialArgDelta(arg: Record<string, unknown>): string | undefined {\n\tconst stringValue = asString(arg.stringValue);\n\tif (stringValue !== undefined) return stringValue;\n\n\tconst jsonPath = asString(arg.jsonPath) ?? \"$\";\n\tconst key = jsonPath.replace(/^\\$\\.?/, \"\").split(\".\")[0] ?? \"value\";\n\tif (arg.numberValue !== undefined) return JSON.stringify({ [key]: arg.numberValue });\n\tif (arg.boolValue !== undefined) return JSON.stringify({ [key]: arg.boolValue });\n\tif (arg.nullValue !== undefined) return JSON.stringify({ [key]: null });\n\treturn undefined;\n}\n\nfunction mapFinishReason(value: string): FinishReason {\n\tswitch (value) {\n\t\tcase \"STOP\":\n\t\tcase \"STOP_REASON_UNSPECIFIED\":\n\t\t\treturn \"stop\";\n\t\tcase \"MAX_TOKENS\":\n\t\t\treturn \"length\";\n\t\tcase \"SAFETY\":\n\t\tcase \"RECITATION\":\n\t\tcase \"BLOCKLIST\":\n\t\tcase \"PROHIBITED_CONTENT\":\n\t\tcase \"SPII\":\n\t\tcase \"LANGUAGE\":\n\t\t\treturn \"content_filter\";\n\t\tcase \"MALFORMED_FUNCTION_CALL\":\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"error\";\n\t}\n}\n\nfunction usageChunk(value: unknown): RawChunk | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst inputTokens = asNumber(value.promptTokenCount);\n\tconst outputTokens = asNumber(value.candidatesTokenCount);\n\tconst reasoningTokens = asNumber(value.thoughtsTokenCount);\n\tif (inputTokens === undefined && outputTokens === undefined && reasoningTokens === undefined) {\n\t\treturn undefined;\n\t}\n\treturn optionalRawChunk({\n\t\tkind: \"usage\",\n\t\tinputTokens,\n\t\toutputTokens,\n\t\treasoningTokens,\n\t\traw: value,\n\t});\n}\n"]}
@@ -240,6 +240,9 @@ var OpenAIChatLikeParser = class {
240
240
  }
241
241
  const looseError = providerErrorPayload(payload, this.options);
242
242
  if (looseError) return openAIProviderErrorChunks(looseError, false, this.options);
243
+ if (!this.options.looseErrorShape && asString(payload.error) && !isRecord(payload.error)) {
244
+ return [];
245
+ }
243
246
  if (this.options.rejectUnrecognizedPayloads && !this.isRecognizableChunk(payload)) {
244
247
  throwUnrecognizedChunkError(this.options);
245
248
  }