@kubuild/ai 0.3.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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-27AY2KBI.js +500 -0
  3. package/dist/chunk-27AY2KBI.js.map +1 -0
  4. package/dist/chunk-JY4NHD3Q.js +227 -0
  5. package/dist/chunk-JY4NHD3Q.js.map +1 -0
  6. package/dist/chunk-UH24LHRY.js +443 -0
  7. package/dist/chunk-UH24LHRY.js.map +1 -0
  8. package/dist/client/ai-client.d.ts +59 -0
  9. package/dist/client/ai-client.d.ts.map +1 -0
  10. package/dist/client/index.cjs +254 -0
  11. package/dist/client/index.cjs.map +1 -0
  12. package/dist/client/index.d.ts +2 -0
  13. package/dist/client/index.d.ts.map +1 -0
  14. package/dist/client/index.js +9 -0
  15. package/dist/client/index.js.map +1 -0
  16. package/dist/core/index.d.ts +3 -0
  17. package/dist/core/index.d.ts.map +1 -0
  18. package/dist/core/normalizer.d.ts +9 -0
  19. package/dist/core/normalizer.d.ts.map +1 -0
  20. package/dist/core/prompt-compiler.d.ts +10 -0
  21. package/dist/core/prompt-compiler.d.ts.map +1 -0
  22. package/dist/index.cjs +468 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +23 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/react/index.cjs +584 -0
  29. package/dist/react/index.cjs.map +1 -0
  30. package/dist/react/index.d.ts +3 -0
  31. package/dist/react/index.d.ts.map +1 -0
  32. package/dist/react/index.js +336 -0
  33. package/dist/react/index.js.map +1 -0
  34. package/dist/react/use-ai-chat.d.ts +63 -0
  35. package/dist/react/use-ai-chat.d.ts.map +1 -0
  36. package/dist/react/use-ai-generator.d.ts +19 -0
  37. package/dist/react/use-ai-generator.d.ts.map +1 -0
  38. package/dist/server/adapters/anthropic.d.ts +30 -0
  39. package/dist/server/adapters/anthropic.d.ts.map +1 -0
  40. package/dist/server/adapters/base.d.ts +2 -0
  41. package/dist/server/adapters/base.d.ts.map +1 -0
  42. package/dist/server/adapters/custom.d.ts +18 -0
  43. package/dist/server/adapters/custom.d.ts.map +1 -0
  44. package/dist/server/adapters/gemini.d.ts +22 -0
  45. package/dist/server/adapters/gemini.d.ts.map +1 -0
  46. package/dist/server/adapters/index.cjs +529 -0
  47. package/dist/server/adapters/index.cjs.map +1 -0
  48. package/dist/server/adapters/index.d.ts +6 -0
  49. package/dist/server/adapters/index.d.ts.map +1 -0
  50. package/dist/server/adapters/index.js +13 -0
  51. package/dist/server/adapters/index.js.map +1 -0
  52. package/dist/server/adapters/openai.d.ts +26 -0
  53. package/dist/server/adapters/openai.d.ts.map +1 -0
  54. package/dist/server/adapters/stream-utils.d.ts +12 -0
  55. package/dist/server/adapters/stream-utils.d.ts.map +1 -0
  56. package/dist/server/engine.d.ts +59 -0
  57. package/dist/server/engine.d.ts.map +1 -0
  58. package/dist/server/handler.d.ts +66 -0
  59. package/dist/server/handler.d.ts.map +1 -0
  60. package/dist/server/index.cjs +1824 -0
  61. package/dist/server/index.cjs.map +1 -0
  62. package/dist/server/index.d.ts +4 -0
  63. package/dist/server/index.d.ts.map +1 -0
  64. package/dist/server/index.js +890 -0
  65. package/dist/server/index.js.map +1 -0
  66. package/dist/types.d.ts +184 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/package.json +94 -0
@@ -0,0 +1,529 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/server/adapters/index.ts
21
+ var adapters_exports = {};
22
+ __export(adapters_exports, {
23
+ AnthropicAdapter: () => AnthropicAdapter,
24
+ CustomHttpAdapter: () => CustomHttpAdapter,
25
+ GeminiAdapter: () => GeminiAdapter,
26
+ OpenAiAdapter: () => OpenAiAdapter
27
+ });
28
+ module.exports = __toCommonJS(adapters_exports);
29
+
30
+ // src/server/adapters/stream-utils.ts
31
+ async function* readSseDataLines(body, signal) {
32
+ const reader = body.getReader();
33
+ const decoder = new TextDecoder();
34
+ let buffer = "";
35
+ try {
36
+ while (true) {
37
+ if (signal?.aborted) {
38
+ throw new Error("Streaming aborted by client");
39
+ }
40
+ const { done, value } = await reader.read();
41
+ if (done) break;
42
+ buffer += decoder.decode(value, { stream: true });
43
+ const frames = buffer.split("\n\n");
44
+ buffer = frames.pop() || "";
45
+ for (const frame of frames) {
46
+ for (const line of frame.split("\n")) {
47
+ const trimmed = line.trim();
48
+ if (trimmed.startsWith("data:")) {
49
+ yield trimmed.slice(5).trim();
50
+ }
51
+ }
52
+ }
53
+ }
54
+ } finally {
55
+ reader.releaseLock();
56
+ }
57
+ }
58
+
59
+ // src/server/adapters/gemini.ts
60
+ var GeminiAdapter = class {
61
+ name = "gemini";
62
+ apiKey;
63
+ model;
64
+ temperature;
65
+ baseUrl;
66
+ constructor(options) {
67
+ if (!options.apiKey) {
68
+ throw new Error("GeminiAdapter requires an apiKey");
69
+ }
70
+ this.apiKey = options.apiKey;
71
+ this.model = options.model || "gemini-2.5-flash";
72
+ this.temperature = options.temperature ?? 0.4;
73
+ this.baseUrl = options.baseUrl || "https://generativelanguage.googleapis.com/v1beta";
74
+ }
75
+ buildContents(params) {
76
+ const { userPrompt, messages: chatMessages } = params;
77
+ return chatMessages && chatMessages.length > 0 ? chatMessages.map((m) => ({
78
+ role: m.role === "assistant" ? "model" : "user",
79
+ parts: [{ text: m.content }]
80
+ })) : [
81
+ {
82
+ role: "user",
83
+ parts: [{ text: userPrompt }]
84
+ }
85
+ ];
86
+ }
87
+ async generate(params) {
88
+ const { systemPrompt, messages: chatMessages, signal } = params;
89
+ const url = `${this.baseUrl}/models/${encodeURIComponent(this.model)}:generateContent?key=${encodeURIComponent(this.apiKey)}`;
90
+ const contents = this.buildContents(params);
91
+ const generationConfig = {
92
+ temperature: this.temperature
93
+ };
94
+ if (params.jsonSchema || !chatMessages && (systemPrompt.includes("JSON") || systemPrompt.includes("json"))) {
95
+ generationConfig.responseMimeType = "application/json";
96
+ }
97
+ const body = {
98
+ system_instruction: {
99
+ parts: [{ text: systemPrompt }]
100
+ },
101
+ contents,
102
+ generationConfig
103
+ };
104
+ const res = await fetch(url, {
105
+ method: "POST",
106
+ headers: {
107
+ "Content-Type": "application/json"
108
+ },
109
+ body: JSON.stringify(body),
110
+ signal
111
+ });
112
+ if (!res.ok) {
113
+ const errText = await res.text().catch(() => "");
114
+ throw new Error(
115
+ `Gemini API error [${res.status} ${res.statusText}]: ${errText || "Unknown error"}`
116
+ );
117
+ }
118
+ const data = await res.json();
119
+ const candidateText = data.candidates?.[0]?.content?.parts?.[0]?.text;
120
+ if (!candidateText) {
121
+ throw new Error("Gemini returned an empty or invalid candidate response");
122
+ }
123
+ return {
124
+ text: candidateText,
125
+ usage: data.usageMetadata ? {
126
+ promptTokens: data.usageMetadata.promptTokenCount,
127
+ completionTokens: data.usageMetadata.candidatesTokenCount
128
+ } : void 0
129
+ };
130
+ }
131
+ /**
132
+ * Token-level streaming via Gemini's `streamGenerateContent` SSE endpoint (STORA-515).
133
+ */
134
+ async *generateStream(params) {
135
+ const { systemPrompt, signal } = params;
136
+ const url = `${this.baseUrl}/models/${encodeURIComponent(this.model)}:streamGenerateContent?alt=sse&key=${encodeURIComponent(this.apiKey)}`;
137
+ const contents = this.buildContents(params);
138
+ const generationConfig = {
139
+ temperature: this.temperature
140
+ };
141
+ const body = {
142
+ system_instruction: {
143
+ parts: [{ text: systemPrompt }]
144
+ },
145
+ contents,
146
+ generationConfig
147
+ };
148
+ const res = await fetch(url, {
149
+ method: "POST",
150
+ headers: {
151
+ "Content-Type": "application/json"
152
+ },
153
+ body: JSON.stringify(body),
154
+ signal
155
+ });
156
+ if (!res.ok) {
157
+ const errText = await res.text().catch(() => "");
158
+ throw new Error(
159
+ `Gemini API error [${res.status} ${res.statusText}]: ${errText || "Unknown error"}`
160
+ );
161
+ }
162
+ if (!res.body) {
163
+ throw new Error("Gemini streaming response has no readable body");
164
+ }
165
+ let text = "";
166
+ let usage;
167
+ for await (const raw of readSseDataLines(res.body, signal)) {
168
+ let parsed;
169
+ try {
170
+ parsed = JSON.parse(raw);
171
+ } catch {
172
+ continue;
173
+ }
174
+ const delta = parsed.candidates?.[0]?.content?.parts?.[0]?.text;
175
+ if (typeof delta === "string" && delta.length > 0) {
176
+ text += delta;
177
+ yield delta;
178
+ }
179
+ if (parsed.usageMetadata) {
180
+ usage = {
181
+ promptTokens: parsed.usageMetadata.promptTokenCount,
182
+ completionTokens: parsed.usageMetadata.candidatesTokenCount
183
+ };
184
+ }
185
+ }
186
+ return { text, usage };
187
+ }
188
+ };
189
+
190
+ // src/server/adapters/openai.ts
191
+ var OpenAiAdapter = class {
192
+ name = "openai";
193
+ apiKey;
194
+ model;
195
+ temperature;
196
+ baseUrl;
197
+ customHeaders;
198
+ constructor(options) {
199
+ if (!options.apiKey) {
200
+ throw new Error("OpenAiAdapter requires an apiKey");
201
+ }
202
+ this.apiKey = options.apiKey;
203
+ this.model = options.model || "gpt-4o";
204
+ this.temperature = options.temperature ?? 0.4;
205
+ this.baseUrl = (options.baseUrl || "https://api.openai.com/v1").replace(/\/+$/, "");
206
+ this.customHeaders = options.headers;
207
+ }
208
+ buildMessages(params) {
209
+ const { systemPrompt, userPrompt, messages: chatMessages } = params;
210
+ return chatMessages && chatMessages.length > 0 ? [
211
+ { role: "system", content: systemPrompt },
212
+ ...chatMessages.map((m) => ({ role: m.role, content: m.content }))
213
+ ] : [
214
+ { role: "system", content: systemPrompt },
215
+ { role: "user", content: userPrompt }
216
+ ];
217
+ }
218
+ async generate(params) {
219
+ const { systemPrompt, signal } = params;
220
+ const url = `${this.baseUrl}/chat/completions`;
221
+ const messages = this.buildMessages(params);
222
+ const chatMessages = params.messages;
223
+ const body = {
224
+ model: this.model,
225
+ temperature: this.temperature,
226
+ messages
227
+ };
228
+ if (params.jsonSchema || !chatMessages && (systemPrompt.includes("JSON") || systemPrompt.includes("json"))) {
229
+ body.response_format = { type: "json_object" };
230
+ }
231
+ const res = await fetch(url, {
232
+ method: "POST",
233
+ headers: {
234
+ "Content-Type": "application/json",
235
+ Authorization: `Bearer ${this.apiKey}`,
236
+ ...this.customHeaders
237
+ },
238
+ body: JSON.stringify(body),
239
+ signal
240
+ });
241
+ if (!res.ok) {
242
+ const errText = await res.text().catch(() => "");
243
+ throw new Error(
244
+ `OpenAI API error [${res.status} ${res.statusText}]: ${errText || "Unknown error"}`
245
+ );
246
+ }
247
+ const data = await res.json();
248
+ const content = data.choices?.[0]?.message?.content;
249
+ if (!content) {
250
+ throw new Error("OpenAI returned an empty message content");
251
+ }
252
+ return {
253
+ text: content,
254
+ usage: data.usage ? {
255
+ promptTokens: data.usage.prompt_tokens,
256
+ completionTokens: data.usage.completion_tokens
257
+ } : void 0
258
+ };
259
+ }
260
+ /**
261
+ * Token-level streaming via OpenAI's `stream: true` chat completions mode (STORA-515).
262
+ * Yields each `delta.content` fragment as it arrives and returns the fully assembled
263
+ * text + usage (when the final chunk includes it) once the stream ends.
264
+ */
265
+ async *generateStream(params) {
266
+ const { signal } = params;
267
+ const url = `${this.baseUrl}/chat/completions`;
268
+ const messages = this.buildMessages(params);
269
+ const body = {
270
+ model: this.model,
271
+ temperature: this.temperature,
272
+ messages,
273
+ stream: true
274
+ };
275
+ const res = await fetch(url, {
276
+ method: "POST",
277
+ headers: {
278
+ "Content-Type": "application/json",
279
+ Authorization: `Bearer ${this.apiKey}`,
280
+ ...this.customHeaders
281
+ },
282
+ body: JSON.stringify(body),
283
+ signal
284
+ });
285
+ if (!res.ok) {
286
+ const errText = await res.text().catch(() => "");
287
+ throw new Error(
288
+ `OpenAI API error [${res.status} ${res.statusText}]: ${errText || "Unknown error"}`
289
+ );
290
+ }
291
+ if (!res.body) {
292
+ throw new Error("OpenAI streaming response has no readable body");
293
+ }
294
+ let text = "";
295
+ let usage;
296
+ for await (const raw of readSseDataLines(res.body, signal)) {
297
+ if (raw === "[DONE]") break;
298
+ let parsed;
299
+ try {
300
+ parsed = JSON.parse(raw);
301
+ } catch {
302
+ continue;
303
+ }
304
+ const delta = parsed.choices?.[0]?.delta?.content;
305
+ if (typeof delta === "string" && delta.length > 0) {
306
+ text += delta;
307
+ yield delta;
308
+ }
309
+ if (parsed.usage) {
310
+ usage = {
311
+ promptTokens: parsed.usage.prompt_tokens,
312
+ completionTokens: parsed.usage.completion_tokens
313
+ };
314
+ }
315
+ }
316
+ return { text, usage };
317
+ }
318
+ };
319
+
320
+ // src/server/adapters/anthropic.ts
321
+ var AnthropicAdapter = class {
322
+ name = "anthropic";
323
+ apiKey;
324
+ model;
325
+ maxTokens;
326
+ temperature;
327
+ baseUrl;
328
+ anthropicVersion;
329
+ customHeaders;
330
+ constructor(options) {
331
+ if (!options.apiKey) {
332
+ throw new Error("AnthropicAdapter requires an apiKey");
333
+ }
334
+ this.apiKey = options.apiKey;
335
+ this.model = options.model || "claude-3-5-sonnet-20241022";
336
+ this.maxTokens = options.maxTokens ?? 4096;
337
+ this.temperature = options.temperature ?? 0.4;
338
+ this.baseUrl = (options.baseUrl || "https://api.anthropic.com/v1").replace(/\/+$/, "");
339
+ this.anthropicVersion = options.anthropicVersion || "2023-06-01";
340
+ this.customHeaders = options.headers;
341
+ }
342
+ buildMessages(params) {
343
+ const { userPrompt, messages: chatMessages } = params;
344
+ return chatMessages && chatMessages.length > 0 ? chatMessages.filter((m) => m.role === "user" || m.role === "assistant").map((m) => ({ role: m.role, content: m.content })) : [
345
+ {
346
+ role: "user",
347
+ content: userPrompt
348
+ }
349
+ ];
350
+ }
351
+ async generate(params) {
352
+ const { systemPrompt, signal } = params;
353
+ const url = `${this.baseUrl}/messages`;
354
+ const messages = this.buildMessages(params);
355
+ const body = {
356
+ model: this.model,
357
+ max_tokens: this.maxTokens,
358
+ temperature: this.temperature,
359
+ system: systemPrompt,
360
+ messages
361
+ };
362
+ const res = await fetch(url, {
363
+ method: "POST",
364
+ headers: {
365
+ "Content-Type": "application/json",
366
+ "x-api-key": this.apiKey,
367
+ "anthropic-version": this.anthropicVersion,
368
+ ...this.customHeaders
369
+ },
370
+ body: JSON.stringify(body),
371
+ signal
372
+ });
373
+ if (!res.ok) {
374
+ const errText = await res.text().catch(() => "");
375
+ throw new Error(
376
+ `Anthropic API error [${res.status} ${res.statusText}]: ${errText || "Unknown error"}`
377
+ );
378
+ }
379
+ const data = await res.json();
380
+ const textPart = data.content?.find((c) => c.type === "text")?.text;
381
+ if (!textPart) {
382
+ throw new Error("Anthropic returned an empty text content");
383
+ }
384
+ return {
385
+ text: textPart,
386
+ usage: data.usage ? {
387
+ promptTokens: data.usage.input_tokens,
388
+ completionTokens: data.usage.output_tokens
389
+ } : void 0
390
+ };
391
+ }
392
+ /**
393
+ * Token-level streaming via Anthropic's `stream: true` Messages API (STORA-515).
394
+ * Parses the `content_block_delta` (`text_delta`) events for incremental text and the
395
+ * `message_start`/`message_delta` events for usage accounting.
396
+ */
397
+ async *generateStream(params) {
398
+ const { systemPrompt, signal } = params;
399
+ const url = `${this.baseUrl}/messages`;
400
+ const messages = this.buildMessages(params);
401
+ const body = {
402
+ model: this.model,
403
+ max_tokens: this.maxTokens,
404
+ temperature: this.temperature,
405
+ system: systemPrompt,
406
+ messages,
407
+ stream: true
408
+ };
409
+ const res = await fetch(url, {
410
+ method: "POST",
411
+ headers: {
412
+ "Content-Type": "application/json",
413
+ "x-api-key": this.apiKey,
414
+ "anthropic-version": this.anthropicVersion,
415
+ ...this.customHeaders
416
+ },
417
+ body: JSON.stringify(body),
418
+ signal
419
+ });
420
+ if (!res.ok) {
421
+ const errText = await res.text().catch(() => "");
422
+ throw new Error(
423
+ `Anthropic API error [${res.status} ${res.statusText}]: ${errText || "Unknown error"}`
424
+ );
425
+ }
426
+ if (!res.body) {
427
+ throw new Error("Anthropic streaming response has no readable body");
428
+ }
429
+ let text = "";
430
+ let promptTokens;
431
+ let completionTokens;
432
+ for await (const raw of readSseDataLines(res.body, signal)) {
433
+ if (!raw) continue;
434
+ let evt;
435
+ try {
436
+ evt = JSON.parse(raw);
437
+ } catch {
438
+ continue;
439
+ }
440
+ if (evt.type === "content_block_delta" && evt.delta?.type === "text_delta") {
441
+ const delta = evt.delta.text;
442
+ if (typeof delta === "string" && delta.length > 0) {
443
+ text += delta;
444
+ yield delta;
445
+ }
446
+ } else if (evt.type === "message_start" && evt.message?.usage?.input_tokens !== void 0) {
447
+ promptTokens = evt.message.usage.input_tokens;
448
+ } else if (evt.type === "message_delta" && evt.usage?.output_tokens !== void 0) {
449
+ completionTokens = evt.usage.output_tokens;
450
+ }
451
+ }
452
+ return {
453
+ text,
454
+ usage: promptTokens !== void 0 || completionTokens !== void 0 ? { promptTokens, completionTokens } : void 0
455
+ };
456
+ }
457
+ };
458
+
459
+ // src/server/adapters/custom.ts
460
+ var CustomHttpAdapter = class {
461
+ name;
462
+ url;
463
+ headers;
464
+ formatRequestBody;
465
+ parseResponse;
466
+ constructor(options) {
467
+ if (!options.url) {
468
+ throw new Error("CustomHttpAdapter requires a url");
469
+ }
470
+ this.url = options.url;
471
+ this.name = options.name || "custom-http";
472
+ this.headers = options.headers;
473
+ this.formatRequestBody = options.formatRequestBody || ((params) => ({
474
+ messages: params.messages && params.messages.length > 0 ? [
475
+ { role: "system", content: params.systemPrompt },
476
+ ...params.messages.map((m) => ({ role: m.role, content: m.content }))
477
+ ] : [
478
+ { role: "system", content: params.systemPrompt },
479
+ { role: "user", content: params.userPrompt }
480
+ ]
481
+ }));
482
+ this.parseResponse = options.parseResponse || ((json) => {
483
+ if (!json || typeof json !== "object") {
484
+ throw new Error("Response is not a valid JSON object");
485
+ }
486
+ const obj = json;
487
+ if (typeof obj.response === "string") return obj.response;
488
+ if (typeof obj.text === "string") return obj.text;
489
+ const choices = obj.choices;
490
+ if (Array.isArray(choices) && choices[0]?.message?.content) {
491
+ return choices[0].message.content;
492
+ }
493
+ const message = obj.message;
494
+ if (message && typeof message.content === "string") {
495
+ return message.content;
496
+ }
497
+ throw new Error("Unable to extract generated text from custom HTTP response");
498
+ });
499
+ }
500
+ async generate(params) {
501
+ const body = this.formatRequestBody(params);
502
+ const res = await fetch(this.url, {
503
+ method: "POST",
504
+ headers: {
505
+ "Content-Type": "application/json",
506
+ ...this.headers
507
+ },
508
+ body: JSON.stringify(body),
509
+ signal: params.signal
510
+ });
511
+ if (!res.ok) {
512
+ const errText = await res.text().catch(() => "");
513
+ throw new Error(
514
+ `Custom HTTP adapter error [${res.status} ${res.statusText}]: ${errText || "Unknown error"}`
515
+ );
516
+ }
517
+ const json = await res.json();
518
+ const text = this.parseResponse(json);
519
+ return { text };
520
+ }
521
+ };
522
+ // Annotate the CommonJS export names for ESM import in node:
523
+ 0 && (module.exports = {
524
+ AnthropicAdapter,
525
+ CustomHttpAdapter,
526
+ GeminiAdapter,
527
+ OpenAiAdapter
528
+ });
529
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/adapters/index.ts","../../../src/server/adapters/stream-utils.ts","../../../src/server/adapters/gemini.ts","../../../src/server/adapters/openai.ts","../../../src/server/adapters/anthropic.ts","../../../src/server/adapters/custom.ts"],"sourcesContent":["export * from './base';\nexport * from './gemini';\nexport * from './openai';\nexport * from './anthropic';\nexport * from './custom';\n","/**\n * Shared SSE (server-sent events) frame reader for provider adapters that support\n * token-level streaming (STORA-515) — OpenAI, Anthropic and Gemini all expose their\n * streaming APIs as `data: <json>\\n\\n` frames, so every adapter reuses this single\n * low-level reader instead of re-implementing buffering/decoding three times.\n *\n * Yields the raw string payload of each `data:` line (already trimmed), in arrival\n * order. Callers are responsible for `JSON.parse`-ing (or ignoring sentinel values\n * like OpenAI's `[DONE]`) and for interpreting provider-specific event shapes.\n */\nexport async function* readSseDataLines(\n body: ReadableStream<Uint8Array>,\n signal?: AbortSignal,\n): AsyncGenerator<string, void, void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n if (signal?.aborted) {\n throw new Error('Streaming aborted by client');\n }\n\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop() || '';\n\n for (const frame of frames) {\n for (const line of frame.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed.startsWith('data:')) {\n yield trimmed.slice(5).trim();\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n","import type {\n AiProviderAdapter,\n AiProviderGenerateParams,\n AiProviderGenerateResult,\n} from '../../types';\nimport { readSseDataLines } from './stream-utils';\n\nexport interface GeminiAdapterOptions {\n apiKey: string;\n model?: string;\n temperature?: number;\n baseUrl?: string;\n}\n\nexport class GeminiAdapter implements AiProviderAdapter {\n readonly name = 'gemini';\n private apiKey: string;\n private model: string;\n private temperature: number;\n private baseUrl: string;\n\n constructor(options: GeminiAdapterOptions) {\n if (!options.apiKey) {\n throw new Error('GeminiAdapter requires an apiKey');\n }\n this.apiKey = options.apiKey;\n this.model = options.model || 'gemini-2.5-flash';\n this.temperature = options.temperature ?? 0.4;\n this.baseUrl =\n options.baseUrl || 'https://generativelanguage.googleapis.com/v1beta';\n }\n\n private buildContents(\n params: AiProviderGenerateParams,\n ): Array<{ role: string; parts: Array<{ text: string }> }> {\n const { userPrompt, messages: chatMessages } = params;\n return chatMessages && chatMessages.length > 0\n ? chatMessages.map((m) => ({\n role: m.role === 'assistant' ? 'model' : 'user',\n parts: [{ text: m.content }],\n }))\n : [\n {\n role: 'user',\n parts: [{ text: userPrompt }],\n },\n ];\n }\n\n async generate(params: AiProviderGenerateParams): Promise<AiProviderGenerateResult> {\n const { systemPrompt, messages: chatMessages, signal } = params;\n\n const url = `${this.baseUrl}/models/${encodeURIComponent(this.model)}:generateContent?key=${encodeURIComponent(this.apiKey)}`;\n const contents = this.buildContents(params);\n\n const generationConfig: Record<string, unknown> = {\n temperature: this.temperature,\n };\n\n if (params.jsonSchema || (!chatMessages && (systemPrompt.includes('JSON') || systemPrompt.includes('json')))) {\n generationConfig.responseMimeType = 'application/json';\n }\n\n const body: Record<string, unknown> = {\n system_instruction: {\n parts: [{ text: systemPrompt }],\n },\n contents,\n generationConfig,\n };\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!res.ok) {\n const errText = await res.text().catch(() => '');\n throw new Error(\n `Gemini API error [${res.status} ${res.statusText}]: ${errText || 'Unknown error'}`,\n );\n }\n\n const data = (await res.json()) as {\n candidates?: Array<{\n content?: {\n parts?: Array<{ text?: string }>;\n };\n }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n };\n };\n\n const candidateText = data.candidates?.[0]?.content?.parts?.[0]?.text;\n if (!candidateText) {\n throw new Error('Gemini returned an empty or invalid candidate response');\n }\n\n return {\n text: candidateText,\n usage: data.usageMetadata\n ? {\n promptTokens: data.usageMetadata.promptTokenCount,\n completionTokens: data.usageMetadata.candidatesTokenCount,\n }\n : undefined,\n };\n }\n\n /**\n * Token-level streaming via Gemini's `streamGenerateContent` SSE endpoint (STORA-515).\n */\n async *generateStream(\n params: AiProviderGenerateParams,\n ): AsyncGenerator<string, AiProviderGenerateResult, void> {\n const { systemPrompt, signal } = params;\n const url = `${this.baseUrl}/models/${encodeURIComponent(this.model)}:streamGenerateContent?alt=sse&key=${encodeURIComponent(this.apiKey)}`;\n const contents = this.buildContents(params);\n\n const generationConfig: Record<string, unknown> = {\n temperature: this.temperature,\n };\n\n const body: Record<string, unknown> = {\n system_instruction: {\n parts: [{ text: systemPrompt }],\n },\n contents,\n generationConfig,\n };\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!res.ok) {\n const errText = await res.text().catch(() => '');\n throw new Error(\n `Gemini API error [${res.status} ${res.statusText}]: ${errText || 'Unknown error'}`,\n );\n }\n\n if (!res.body) {\n throw new Error('Gemini streaming response has no readable body');\n }\n\n let text = '';\n let usage: AiProviderGenerateResult['usage'];\n\n for await (const raw of readSseDataLines(res.body, signal)) {\n let parsed: {\n candidates?: Array<{ content?: { parts?: Array<{ text?: string }> } }>;\n usageMetadata?: { promptTokenCount?: number; candidatesTokenCount?: number };\n };\n try {\n parsed = JSON.parse(raw);\n } catch {\n continue;\n }\n\n const delta = parsed.candidates?.[0]?.content?.parts?.[0]?.text;\n if (typeof delta === 'string' && delta.length > 0) {\n text += delta;\n yield delta;\n }\n\n if (parsed.usageMetadata) {\n usage = {\n promptTokens: parsed.usageMetadata.promptTokenCount,\n completionTokens: parsed.usageMetadata.candidatesTokenCount,\n };\n }\n }\n\n return { text, usage };\n }\n}\n","import type {\n AiProviderAdapter,\n AiProviderGenerateParams,\n AiProviderGenerateResult,\n} from '../../types';\nimport { readSseDataLines } from './stream-utils';\n\nexport interface OpenAiAdapterOptions {\n apiKey: string;\n model?: string;\n temperature?: number;\n baseUrl?: string;\n headers?: Record<string, string>;\n}\n\nexport class OpenAiAdapter implements AiProviderAdapter {\n readonly name = 'openai';\n private apiKey: string;\n private model: string;\n private temperature: number;\n private baseUrl: string;\n private customHeaders?: Record<string, string>;\n\n constructor(options: OpenAiAdapterOptions) {\n if (!options.apiKey) {\n throw new Error('OpenAiAdapter requires an apiKey');\n }\n this.apiKey = options.apiKey;\n this.model = options.model || 'gpt-4o';\n this.temperature = options.temperature ?? 0.4;\n this.baseUrl = (options.baseUrl || 'https://api.openai.com/v1').replace(/\\/+$/, '');\n this.customHeaders = options.headers;\n }\n\n private buildMessages(params: AiProviderGenerateParams): Array<{ role: string; content: string }> {\n const { systemPrompt, userPrompt, messages: chatMessages } = params;\n return chatMessages && chatMessages.length > 0\n ? [\n { role: 'system', content: systemPrompt },\n ...chatMessages.map((m) => ({ role: m.role, content: m.content })),\n ]\n : [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userPrompt },\n ];\n }\n\n async generate(params: AiProviderGenerateParams): Promise<AiProviderGenerateResult> {\n const { systemPrompt, signal } = params;\n\n const url = `${this.baseUrl}/chat/completions`;\n const messages = this.buildMessages(params);\n const chatMessages = params.messages;\n\n const body: Record<string, unknown> = {\n model: this.model,\n temperature: this.temperature,\n messages,\n };\n\n // Only force json_object when JSON schema is provided or specifically requested,\n // allowing natural conversation text in chat mode.\n if (params.jsonSchema || (!chatMessages && (systemPrompt.includes('JSON') || systemPrompt.includes('json')))) {\n body.response_format = { type: 'json_object' };\n }\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n ...this.customHeaders,\n },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!res.ok) {\n const errText = await res.text().catch(() => '');\n throw new Error(\n `OpenAI API error [${res.status} ${res.statusText}]: ${errText || 'Unknown error'}`,\n );\n }\n\n const data = (await res.json()) as {\n choices?: Array<{\n message?: {\n content?: string;\n };\n }>;\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n };\n };\n\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n throw new Error('OpenAI returned an empty message content');\n }\n\n return {\n text: content,\n usage: data.usage\n ? {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n }\n : undefined,\n };\n }\n\n /**\n * Token-level streaming via OpenAI's `stream: true` chat completions mode (STORA-515).\n * Yields each `delta.content` fragment as it arrives and returns the fully assembled\n * text + usage (when the final chunk includes it) once the stream ends.\n */\n async *generateStream(\n params: AiProviderGenerateParams,\n ): AsyncGenerator<string, AiProviderGenerateResult, void> {\n const { signal } = params;\n const url = `${this.baseUrl}/chat/completions`;\n const messages = this.buildMessages(params);\n\n const body: Record<string, unknown> = {\n model: this.model,\n temperature: this.temperature,\n messages,\n stream: true,\n };\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n ...this.customHeaders,\n },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!res.ok) {\n const errText = await res.text().catch(() => '');\n throw new Error(\n `OpenAI API error [${res.status} ${res.statusText}]: ${errText || 'Unknown error'}`,\n );\n }\n\n if (!res.body) {\n throw new Error('OpenAI streaming response has no readable body');\n }\n\n let text = '';\n let usage: AiProviderGenerateResult['usage'];\n\n for await (const raw of readSseDataLines(res.body, signal)) {\n if (raw === '[DONE]') break;\n\n let parsed: {\n choices?: Array<{ delta?: { content?: string } }>;\n usage?: { prompt_tokens?: number; completion_tokens?: number };\n };\n try {\n parsed = JSON.parse(raw);\n } catch {\n continue;\n }\n\n const delta = parsed.choices?.[0]?.delta?.content;\n if (typeof delta === 'string' && delta.length > 0) {\n text += delta;\n yield delta;\n }\n\n if (parsed.usage) {\n usage = {\n promptTokens: parsed.usage.prompt_tokens,\n completionTokens: parsed.usage.completion_tokens,\n };\n }\n }\n\n return { text, usage };\n }\n}\n","import type {\n AiProviderAdapter,\n AiProviderGenerateParams,\n AiProviderGenerateResult,\n} from '../../types';\nimport { readSseDataLines } from './stream-utils';\n\nexport interface AnthropicAdapterOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n temperature?: number;\n baseUrl?: string;\n anthropicVersion?: string;\n headers?: Record<string, string>;\n}\n\nexport class AnthropicAdapter implements AiProviderAdapter {\n readonly name = 'anthropic';\n private apiKey: string;\n private model: string;\n private maxTokens: number;\n private temperature: number;\n private baseUrl: string;\n private anthropicVersion: string;\n private customHeaders?: Record<string, string>;\n\n constructor(options: AnthropicAdapterOptions) {\n if (!options.apiKey) {\n throw new Error('AnthropicAdapter requires an apiKey');\n }\n this.apiKey = options.apiKey;\n this.model = options.model || 'claude-3-5-sonnet-20241022';\n this.maxTokens = options.maxTokens ?? 4096;\n this.temperature = options.temperature ?? 0.4;\n this.baseUrl = (options.baseUrl || 'https://api.anthropic.com/v1').replace(/\\/+$/, '');\n this.anthropicVersion = options.anthropicVersion || '2023-06-01';\n this.customHeaders = options.headers;\n }\n\n private buildMessages(\n params: AiProviderGenerateParams,\n ): Array<{ role: 'user' | 'assistant'; content: string }> {\n const { userPrompt, messages: chatMessages } = params;\n return chatMessages && chatMessages.length > 0\n ? chatMessages\n .filter((m) => m.role === 'user' || m.role === 'assistant')\n .map((m) => ({ role: m.role as 'user' | 'assistant', content: m.content }))\n : [\n {\n role: 'user' as const,\n content: userPrompt,\n },\n ];\n }\n\n async generate(params: AiProviderGenerateParams): Promise<AiProviderGenerateResult> {\n const { systemPrompt, signal } = params;\n\n const url = `${this.baseUrl}/messages`;\n const messages = this.buildMessages(params);\n\n const body: Record<string, unknown> = {\n model: this.model,\n max_tokens: this.maxTokens,\n temperature: this.temperature,\n system: systemPrompt,\n messages,\n };\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n 'anthropic-version': this.anthropicVersion,\n ...this.customHeaders,\n },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!res.ok) {\n const errText = await res.text().catch(() => '');\n throw new Error(\n `Anthropic API error [${res.status} ${res.statusText}]: ${errText || 'Unknown error'}`,\n );\n }\n\n const data = (await res.json()) as {\n content?: Array<{\n type?: string;\n text?: string;\n }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n };\n\n const textPart = data.content?.find((c) => c.type === 'text')?.text;\n if (!textPart) {\n throw new Error('Anthropic returned an empty text content');\n }\n\n return {\n text: textPart,\n usage: data.usage\n ? {\n promptTokens: data.usage.input_tokens,\n completionTokens: data.usage.output_tokens,\n }\n : undefined,\n };\n }\n\n /**\n * Token-level streaming via Anthropic's `stream: true` Messages API (STORA-515).\n * Parses the `content_block_delta` (`text_delta`) events for incremental text and the\n * `message_start`/`message_delta` events for usage accounting.\n */\n async *generateStream(\n params: AiProviderGenerateParams,\n ): AsyncGenerator<string, AiProviderGenerateResult, void> {\n const { systemPrompt, signal } = params;\n const url = `${this.baseUrl}/messages`;\n const messages = this.buildMessages(params);\n\n const body: Record<string, unknown> = {\n model: this.model,\n max_tokens: this.maxTokens,\n temperature: this.temperature,\n system: systemPrompt,\n messages,\n stream: true,\n };\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n 'anthropic-version': this.anthropicVersion,\n ...this.customHeaders,\n },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!res.ok) {\n const errText = await res.text().catch(() => '');\n throw new Error(\n `Anthropic API error [${res.status} ${res.statusText}]: ${errText || 'Unknown error'}`,\n );\n }\n\n if (!res.body) {\n throw new Error('Anthropic streaming response has no readable body');\n }\n\n let text = '';\n let promptTokens: number | undefined;\n let completionTokens: number | undefined;\n\n for await (const raw of readSseDataLines(res.body, signal)) {\n if (!raw) continue;\n\n let evt: {\n type?: string;\n delta?: { type?: string; text?: string };\n usage?: { output_tokens?: number };\n message?: { usage?: { input_tokens?: number } };\n };\n try {\n evt = JSON.parse(raw);\n } catch {\n continue;\n }\n\n if (evt.type === 'content_block_delta' && evt.delta?.type === 'text_delta') {\n const delta = evt.delta.text;\n if (typeof delta === 'string' && delta.length > 0) {\n text += delta;\n yield delta;\n }\n } else if (evt.type === 'message_start' && evt.message?.usage?.input_tokens !== undefined) {\n promptTokens = evt.message.usage.input_tokens;\n } else if (evt.type === 'message_delta' && evt.usage?.output_tokens !== undefined) {\n completionTokens = evt.usage.output_tokens;\n }\n }\n\n return {\n text,\n usage:\n promptTokens !== undefined || completionTokens !== undefined\n ? { promptTokens, completionTokens }\n : undefined,\n };\n }\n}\n","import type {\n AiProviderAdapter,\n AiProviderGenerateParams,\n AiProviderGenerateResult,\n} from '../../types';\n\nexport interface CustomHttpAdapterOptions {\n url: string;\n name?: string;\n headers?: Record<string, string>;\n formatRequestBody?: (params: AiProviderGenerateParams) => unknown;\n parseResponse?: (json: unknown) => string;\n}\n\nexport class CustomHttpAdapter implements AiProviderAdapter {\n readonly name: string;\n private url: string;\n private headers?: Record<string, string>;\n private formatRequestBody: (params: AiProviderGenerateParams) => unknown;\n private parseResponse: (json: unknown) => string;\n\n constructor(options: CustomHttpAdapterOptions) {\n if (!options.url) {\n throw new Error('CustomHttpAdapter requires a url');\n }\n this.url = options.url;\n this.name = options.name || 'custom-http';\n this.headers = options.headers;\n\n // Default body formatter (OpenAI compatible or Ollama chat compatible)\n this.formatRequestBody =\n options.formatRequestBody ||\n ((params) => ({\n messages:\n params.messages && params.messages.length > 0\n ? [\n { role: 'system', content: params.systemPrompt },\n ...params.messages.map((m) => ({ role: m.role, content: m.content })),\n ]\n : [\n { role: 'system', content: params.systemPrompt },\n { role: 'user', content: params.userPrompt },\n ],\n }));\n\n // Default response parser\n this.parseResponse =\n options.parseResponse ||\n ((json: unknown) => {\n if (!json || typeof json !== 'object') {\n throw new Error('Response is not a valid JSON object');\n }\n const obj = json as Record<string, unknown>;\n if (typeof obj.response === 'string') return obj.response; // Ollama generate\n if (typeof obj.text === 'string') return obj.text;\n const choices = obj.choices as Array<{ message?: { content?: string } }>;\n if (Array.isArray(choices) && choices[0]?.message?.content) {\n return choices[0].message.content; // OpenAI format\n }\n const message = obj.message as { content?: string };\n if (message && typeof message.content === 'string') {\n return message.content; // Ollama chat format\n }\n throw new Error('Unable to extract generated text from custom HTTP response');\n });\n }\n\n async generate(params: AiProviderGenerateParams): Promise<AiProviderGenerateResult> {\n const body = this.formatRequestBody(params);\n\n const res = await fetch(this.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.headers,\n },\n body: JSON.stringify(body),\n signal: params.signal,\n });\n\n if (!res.ok) {\n const errText = await res.text().catch(() => '');\n throw new Error(\n `Custom HTTP adapter error [${res.status} ${res.statusText}]: ${errText || 'Unknown error'}`,\n );\n }\n\n const json = await res.json();\n const text = this.parseResponse(json);\n\n return { text };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,6 @@
1
+ export * from './base';
2
+ export * from './gemini';
3
+ export * from './openai';
4
+ export * from './anthropic';
5
+ export * from './custom';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
@@ -0,0 +1,13 @@
1
+ import {
2
+ AnthropicAdapter,
3
+ CustomHttpAdapter,
4
+ GeminiAdapter,
5
+ OpenAiAdapter
6
+ } from "../../chunk-27AY2KBI.js";
7
+ export {
8
+ AnthropicAdapter,
9
+ CustomHttpAdapter,
10
+ GeminiAdapter,
11
+ OpenAiAdapter
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,26 @@
1
+ import type { AiProviderAdapter, AiProviderGenerateParams, AiProviderGenerateResult } from '../../types';
2
+ export interface OpenAiAdapterOptions {
3
+ apiKey: string;
4
+ model?: string;
5
+ temperature?: number;
6
+ baseUrl?: string;
7
+ headers?: Record<string, string>;
8
+ }
9
+ export declare class OpenAiAdapter implements AiProviderAdapter {
10
+ readonly name = "openai";
11
+ private apiKey;
12
+ private model;
13
+ private temperature;
14
+ private baseUrl;
15
+ private customHeaders?;
16
+ constructor(options: OpenAiAdapterOptions);
17
+ private buildMessages;
18
+ generate(params: AiProviderGenerateParams): Promise<AiProviderGenerateResult>;
19
+ /**
20
+ * Token-level streaming via OpenAI's `stream: true` chat completions mode (STORA-515).
21
+ * Yields each `delta.content` fragment as it arrives and returns the fully assembled
22
+ * text + usage (when the final chunk includes it) once the stream ends.
23
+ */
24
+ generateStream(params: AiProviderGenerateParams): AsyncGenerator<string, AiProviderGenerateResult, void>;
25
+ }
26
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,qBAAa,aAAc,YAAW,iBAAiB;IACrD,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAC,CAAyB;gBAEnC,OAAO,EAAE,oBAAoB;IAWzC,OAAO,CAAC,aAAa;IAaf,QAAQ,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAiEnF;;;;OAIG;IACI,cAAc,CACnB,MAAM,EAAE,wBAAwB,GAC/B,cAAc,CAAC,MAAM,EAAE,wBAAwB,EAAE,IAAI,CAAC;CAkE1D"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared SSE (server-sent events) frame reader for provider adapters that support
3
+ * token-level streaming (STORA-515) — OpenAI, Anthropic and Gemini all expose their
4
+ * streaming APIs as `data: <json>\n\n` frames, so every adapter reuses this single
5
+ * low-level reader instead of re-implementing buffering/decoding three times.
6
+ *
7
+ * Yields the raw string payload of each `data:` line (already trimmed), in arrival
8
+ * order. Callers are responsible for `JSON.parse`-ing (or ignoring sentinel values
9
+ * like OpenAI's `[DONE]`) and for interpreting provider-specific event shapes.
10
+ */
11
+ export declare function readSseDataLines(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<string, void, void>;
12
+ //# sourceMappingURL=stream-utils.d.ts.map