@absolutejs/ai 0.0.1

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 (42) hide show
  1. package/README.md +6 -0
  2. package/dist/ai/client/index.js +682 -0
  3. package/dist/ai/client/index.js.map +15 -0
  4. package/dist/ai/index.js +3317 -0
  5. package/dist/ai/index.js.map +28 -0
  6. package/dist/ai/providers/anthropic.js +371 -0
  7. package/dist/ai/providers/anthropic.js.map +10 -0
  8. package/dist/ai/providers/gemini.js +260 -0
  9. package/dist/ai/providers/gemini.js.map +10 -0
  10. package/dist/ai/providers/ollama.js +221 -0
  11. package/dist/ai/providers/ollama.js.map +10 -0
  12. package/dist/ai/providers/openai.js +322 -0
  13. package/dist/ai/providers/openai.js.map +10 -0
  14. package/dist/ai/providers/openaiCompatible.js +360 -0
  15. package/dist/ai/providers/openaiCompatible.js.map +11 -0
  16. package/dist/ai/providers/openaiResponses.js +381 -0
  17. package/dist/ai/providers/openaiResponses.js.map +10 -0
  18. package/dist/src/ai/client/actions.d.ts +186 -0
  19. package/dist/src/ai/client/connection.d.ts +9 -0
  20. package/dist/src/ai/client/createAIStream.d.ts +12 -0
  21. package/dist/src/ai/client/index.d.ts +4 -0
  22. package/dist/src/ai/client/messageStore.d.ts +12 -0
  23. package/dist/src/ai/conversationManager.d.ts +19 -0
  24. package/dist/src/ai/htmxRenderers.d.ts +3 -0
  25. package/dist/src/ai/index.d.ts +19 -0
  26. package/dist/src/ai/memoryStore.d.ts +2 -0
  27. package/dist/src/ai/protocol.d.ts +4 -0
  28. package/dist/src/ai/providers/anthropic.d.ts +3 -0
  29. package/dist/src/ai/providers/gemini.d.ts +8 -0
  30. package/dist/src/ai/providers/ollama.d.ts +6 -0
  31. package/dist/src/ai/providers/openai.d.ts +7 -0
  32. package/dist/src/ai/providers/openaiCompatible.d.ts +30 -0
  33. package/dist/src/ai/providers/openaiResponses.d.ts +33 -0
  34. package/dist/src/ai/streamAI.d.ts +2 -0
  35. package/dist/src/ai/streamAIToSSE.d.ts +6 -0
  36. package/dist/src/constants.d.ts +60 -0
  37. package/dist/src/plugins/aiChat.d.ts +239 -0
  38. package/dist/types/ai.d.ts +4773 -0
  39. package/dist/types/anthropic.d.ts +20 -0
  40. package/dist/types/session.d.ts +16 -0
  41. package/dist/types/typeGuards.d.ts +3 -0
  42. package/package.json +59 -0
@@ -0,0 +1,371 @@
1
+ // @bun
2
+ // src/ai/providers/anthropic.ts
3
+ var DEFAULT_BASE_URL = "https://api.anthropic.com";
4
+ var API_VERSION = "2023-06-01";
5
+ var MAX_TOKENS = 8192;
6
+ var EVENT_PREFIX_LENGTH = 7;
7
+ var DATA_PREFIX_LENGTH = 6;
8
+ var EMPTY_CHUNKS = [];
9
+ var isRecord = (val) => typeof val === "object" && val !== null;
10
+ var mapContentBlock = (block) => {
11
+ if (block.type === "thinking") {
12
+ return {
13
+ signature: block.signature,
14
+ thinking: block.thinking,
15
+ type: "thinking"
16
+ };
17
+ }
18
+ if (block.type === "image") {
19
+ return {
20
+ source: block.source,
21
+ type: "image"
22
+ };
23
+ }
24
+ if (block.type === "document") {
25
+ return {
26
+ source: block.source,
27
+ type: "document"
28
+ };
29
+ }
30
+ if (block.type === "tool_result") {
31
+ return {
32
+ content: block.content,
33
+ tool_use_id: block.tool_use_id,
34
+ type: "tool_result"
35
+ };
36
+ }
37
+ if (block.type === "tool_use") {
38
+ return {
39
+ id: block.id,
40
+ input: block.input,
41
+ name: block.name,
42
+ type: "tool_use"
43
+ };
44
+ }
45
+ return { text: block.content, type: "text" };
46
+ };
47
+ var mapMessage = (msg) => ({
48
+ content: typeof msg.content === "string" ? msg.content : msg.content.map(mapContentBlock),
49
+ role: msg.role === "system" ? "user" : msg.role
50
+ });
51
+ var mapToolDefinition = (tool) => ({
52
+ description: tool.description,
53
+ input_schema: tool.input_schema,
54
+ name: tool.name
55
+ });
56
+ var buildRequestBody = (params) => {
57
+ const messages = params.messages.filter((msg) => msg.role !== "system").map(mapMessage);
58
+ const body = {
59
+ max_tokens: MAX_TOKENS,
60
+ messages,
61
+ model: params.model,
62
+ stream: true
63
+ };
64
+ if (params.systemPrompt) {
65
+ body.system = params.systemPrompt;
66
+ }
67
+ if (params.tools && params.tools.length > 0) {
68
+ body.tools = params.tools.map(mapToolDefinition);
69
+ }
70
+ if (params.thinking) {
71
+ body.thinking = params.thinking;
72
+ body.max_tokens = Math.max(MAX_TOKENS, params.thinking.budget_tokens + MAX_TOKENS);
73
+ }
74
+ return body;
75
+ };
76
+ var classifyLine = (line) => {
77
+ if (line.startsWith("event: ")) {
78
+ return {
79
+ field: "event",
80
+ value: line.slice(EVENT_PREFIX_LENGTH)
81
+ };
82
+ }
83
+ if (line.startsWith("data: ")) {
84
+ return {
85
+ field: "data",
86
+ value: line.slice(DATA_PREFIX_LENGTH)
87
+ };
88
+ }
89
+ return;
90
+ };
91
+ var applyClassified = (acc, classified) => {
92
+ if (!classified) {
93
+ return acc;
94
+ }
95
+ if (classified.field === "event") {
96
+ return { eventData: acc.eventData, eventType: classified.value };
97
+ }
98
+ return { eventData: classified.value, eventType: acc.eventType };
99
+ };
100
+ var parseEventLines = (event) => event.split(`
101
+ `).reduce((acc, line) => applyClassified(acc, classifyLine(line)), {
102
+ eventData: "",
103
+ eventType: ""
104
+ });
105
+ var safeParse = (text) => {
106
+ try {
107
+ const result = JSON.parse(text);
108
+ return result;
109
+ } catch {
110
+ return;
111
+ }
112
+ };
113
+ var tryParseJson = (text) => {
114
+ const result = safeParse(text);
115
+ if (isRecord(result)) {
116
+ return result;
117
+ }
118
+ return;
119
+ };
120
+ var getRecord = (obj, key) => {
121
+ const val = obj[key];
122
+ if (isRecord(val)) {
123
+ return val;
124
+ }
125
+ return;
126
+ };
127
+ var getString = (obj, key) => {
128
+ const val = obj[key];
129
+ if (typeof val === "string") {
130
+ return val;
131
+ }
132
+ return "";
133
+ };
134
+ var getNumber = (obj, key) => {
135
+ const val = obj[key];
136
+ if (typeof val === "number") {
137
+ return val;
138
+ }
139
+ return 0;
140
+ };
141
+ var handleContentBlockStart = (parsed, state) => {
142
+ const block = getRecord(parsed, "content_block");
143
+ if (block && block.type === "tool_use") {
144
+ state.currentToolId = getString(block, "id");
145
+ state.currentToolName = getString(block, "name");
146
+ state.toolInputJson = "";
147
+ state.isThinkingBlock = false;
148
+ } else if (block && block.type === "thinking") {
149
+ state.isThinkingBlock = true;
150
+ state.thinkingSignature = "";
151
+ } else {
152
+ state.isThinkingBlock = false;
153
+ }
154
+ };
155
+ var handleContentBlockDelta = (parsed, state) => {
156
+ const delta = getRecord(parsed, "delta");
157
+ if (!delta) {
158
+ return;
159
+ }
160
+ if (delta.type === "thinking_delta") {
161
+ return {
162
+ content: getString(delta, "thinking"),
163
+ type: "thinking"
164
+ };
165
+ }
166
+ if (delta.type === "text_delta") {
167
+ return {
168
+ content: getString(delta, "text"),
169
+ type: "text"
170
+ };
171
+ }
172
+ if (delta.type === "input_json_delta") {
173
+ state.toolInputJson += getString(delta, "partial_json");
174
+ }
175
+ if (delta.type === "signature_delta") {
176
+ state.thinkingSignature += getString(delta, "signature");
177
+ }
178
+ return;
179
+ };
180
+ var handleContentBlockStop = (state) => {
181
+ if (state.isThinkingBlock && state.thinkingSignature) {
182
+ state.isThinkingBlock = false;
183
+ const signature = state.thinkingSignature;
184
+ state.thinkingSignature = "";
185
+ return {
186
+ content: "",
187
+ signature,
188
+ type: "thinking"
189
+ };
190
+ }
191
+ if (!state.currentToolId) {
192
+ return;
193
+ }
194
+ const input = tryParseJson(state.toolInputJson) ?? state.toolInputJson;
195
+ const chunk = {
196
+ id: state.currentToolId,
197
+ input,
198
+ name: state.currentToolName,
199
+ type: "tool_use"
200
+ };
201
+ state.currentToolId = "";
202
+ state.currentToolName = "";
203
+ state.toolInputJson = "";
204
+ return chunk;
205
+ };
206
+ var extractUsage = (usageRecord, existingUsage) => {
207
+ if (!usageRecord) {
208
+ return existingUsage;
209
+ }
210
+ return {
211
+ inputTokens: getNumber(usageRecord, "input_tokens") || existingUsage?.inputTokens || 0,
212
+ outputTokens: getNumber(usageRecord, "output_tokens") || existingUsage?.outputTokens || 0
213
+ };
214
+ };
215
+ var handleMessageDelta = (parsed, state) => {
216
+ const deltaUsage = getRecord(parsed, "usage");
217
+ state.usage = extractUsage(deltaUsage, state.usage);
218
+ };
219
+ var handleMessageStart = (parsed, state) => {
220
+ const message = getRecord(parsed, "message");
221
+ if (!message) {
222
+ return;
223
+ }
224
+ const startUsage = getRecord(message, "usage");
225
+ state.usage = extractUsage(startUsage, state.usage);
226
+ };
227
+ var handleError = (parsed) => {
228
+ const error = getRecord(parsed, "error");
229
+ const errorMessage = error ? getString(error, "message") : "";
230
+ throw new Error(errorMessage || "Anthropic API error");
231
+ };
232
+ var processEvent = (eventType, parsed, state) => {
233
+ switch (eventType) {
234
+ case "content_block_start": {
235
+ handleContentBlockStart(parsed, state);
236
+ return;
237
+ }
238
+ case "content_block_delta": {
239
+ return handleContentBlockDelta(parsed, state);
240
+ }
241
+ case "content_block_stop": {
242
+ return handleContentBlockStop(state);
243
+ }
244
+ case "message_delta": {
245
+ handleMessageDelta(parsed, state);
246
+ return;
247
+ }
248
+ case "message_start": {
249
+ handleMessageStart(parsed, state);
250
+ return;
251
+ }
252
+ case "message_stop": {
253
+ return { type: "done", usage: state.usage };
254
+ }
255
+ case "error": {
256
+ handleError(parsed);
257
+ return;
258
+ }
259
+ default: {
260
+ return;
261
+ }
262
+ }
263
+ };
264
+ var processSingleEvent = (event, state) => {
265
+ if (!event.trim()) {
266
+ return;
267
+ }
268
+ const { eventData, eventType } = parseEventLines(event);
269
+ if (!eventData) {
270
+ return;
271
+ }
272
+ const parsed = tryParseJson(eventData);
273
+ if (!parsed) {
274
+ return;
275
+ }
276
+ return processEvent(eventType, parsed, state);
277
+ };
278
+ var collectChunk = (event, state) => {
279
+ const chunk = processSingleEvent(event, state);
280
+ return chunk ? [chunk] : [];
281
+ };
282
+ var processBufferedEvents = (eventsText, state) => {
283
+ const events = eventsText.split(`
284
+
285
+ `);
286
+ state.buffer = events.pop() ?? "";
287
+ return events.flatMap((event) => collectChunk(event, state));
288
+ };
289
+ var readNextChunks = async (reader, decoder, state, signal) => {
290
+ if (signal?.aborted) {
291
+ return { chunks: EMPTY_CHUNKS, done: true };
292
+ }
293
+ const { done, value } = await reader.read();
294
+ if (done) {
295
+ return { chunks: EMPTY_CHUNKS, done: true };
296
+ }
297
+ const rawText = state.buffer + decoder.decode(value, { stream: true });
298
+ const chunks = processBufferedEvents(rawText, state);
299
+ return { chunks, done: false };
300
+ };
301
+ var findDoneChunk = (chunks) => chunks.findIndex((c) => c.type === "done");
302
+ var sseStreamLoop = async (reader, decoder, state, signal) => {
303
+ const result = await readNextChunks(reader, decoder, state, signal);
304
+ if (result.done) {
305
+ return { chunks: result.chunks, finished: true };
306
+ }
307
+ const doneIdx = findDoneChunk(result.chunks);
308
+ if (doneIdx >= 0) {
309
+ return { chunks: result.chunks.slice(0, doneIdx + 1), finished: true };
310
+ }
311
+ return { chunks: result.chunks, finished: false };
312
+ };
313
+ async function* streamChunks(reader, decoder, state, signal) {
314
+ let finished = false;
315
+ while (!finished) {
316
+ const result = await sseStreamLoop(reader, decoder, state, signal);
317
+ ({ finished } = result);
318
+ yield* result.chunks;
319
+ }
320
+ }
321
+ async function* parseSSEStream(body, signal) {
322
+ const reader = body.getReader();
323
+ const decoder = new TextDecoder;
324
+ const state = {
325
+ buffer: "",
326
+ currentToolId: "",
327
+ currentToolName: "",
328
+ isThinkingBlock: false,
329
+ thinkingSignature: "",
330
+ toolInputJson: "",
331
+ usage: undefined
332
+ };
333
+ try {
334
+ yield* streamChunks(reader, decoder, state, signal);
335
+ } finally {
336
+ reader.releaseLock();
337
+ }
338
+ }
339
+ var fetchAndStream = async function* (baseUrl, config, params) {
340
+ const body = buildRequestBody(params);
341
+ const response = await fetch(`${baseUrl}/v1/messages`, {
342
+ body: JSON.stringify(body),
343
+ headers: {
344
+ "anthropic-version": API_VERSION,
345
+ "Content-Type": "application/json",
346
+ "x-api-key": config.apiKey
347
+ },
348
+ method: "POST",
349
+ signal: params.signal
350
+ });
351
+ if (!response.ok) {
352
+ const errorText = await response.text();
353
+ throw new Error(`Anthropic API error ${response.status}: ${errorText}`);
354
+ }
355
+ if (!response.body) {
356
+ throw new Error("Anthropic API returned no response body");
357
+ }
358
+ yield* parseSSEStream(response.body, params.signal);
359
+ };
360
+ var anthropic = (config) => {
361
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
362
+ return {
363
+ stream: (params) => fetchAndStream(baseUrl, config, params)
364
+ };
365
+ };
366
+ export {
367
+ anthropic
368
+ };
369
+
370
+ //# debugId=46FDFC941805E6B864756E2164756E21
371
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/ai/providers/anthropic.ts"],
4
+ "sourcesContent": [
5
+ "import type {\n\tAIChunk,\n\tAIProviderConfig,\n\tAIProviderContentBlock,\n\tAIProviderMessage,\n\tAIProviderStreamParams,\n\tAIProviderToolDefinition,\n\tAIUsage\n} from '../../../types/ai';\nimport type {\n\tAnthropicConfig,\n\tAnthropicMessage,\n\tAnthropicSSEState\n} from '../../../types/anthropic';\n\nconst DEFAULT_BASE_URL = 'https://api.anthropic.com';\nconst API_VERSION = '2023-06-01';\nconst MAX_TOKENS = 8192;\nconst EVENT_PREFIX_LENGTH = 7;\nconst DATA_PREFIX_LENGTH = 6;\n\nconst EMPTY_CHUNKS: AIChunk[] = [];\n\nconst isRecord = (val: unknown): val is Record<string, unknown> =>\n\ttypeof val === 'object' && val !== null;\n\nconst mapContentBlock = (block: AIProviderContentBlock) => {\n\tif (block.type === 'thinking') {\n\t\treturn {\n\t\t\tsignature: block.signature,\n\t\t\tthinking: block.thinking,\n\t\t\ttype: 'thinking'\n\t\t};\n\t}\n\n\tif (block.type === 'image') {\n\t\treturn {\n\t\t\tsource: block.source,\n\t\t\ttype: 'image'\n\t\t};\n\t}\n\n\tif (block.type === 'document') {\n\t\treturn {\n\t\t\tsource: block.source,\n\t\t\ttype: 'document'\n\t\t};\n\t}\n\n\tif (block.type === 'tool_result') {\n\t\treturn {\n\t\t\tcontent: block.content,\n\t\t\ttool_use_id: block.tool_use_id,\n\t\t\ttype: 'tool_result'\n\t\t};\n\t}\n\n\tif (block.type === 'tool_use') {\n\t\treturn {\n\t\t\tid: block.id,\n\t\t\tinput: block.input,\n\t\t\tname: block.name,\n\t\t\ttype: 'tool_use'\n\t\t};\n\t}\n\n\treturn { text: block.content, type: 'text' };\n};\n\nconst mapMessage = (msg: AIProviderMessage): AnthropicMessage => ({\n\tcontent:\n\t\ttypeof msg.content === 'string'\n\t\t\t? msg.content\n\t\t\t: msg.content.map(mapContentBlock),\n\trole: msg.role === 'system' ? 'user' : msg.role\n});\n\nconst mapToolDefinition = (tool: AIProviderToolDefinition) => ({\n\tdescription: tool.description,\n\tinput_schema: tool.input_schema,\n\tname: tool.name\n});\n\nconst buildRequestBody = (params: AIProviderStreamParams) => {\n\tconst messages: AnthropicMessage[] = params.messages\n\t\t.filter((msg) => msg.role !== 'system')\n\t\t.map(mapMessage);\n\n\tconst body: Record<string, unknown> = {\n\t\tmax_tokens: MAX_TOKENS,\n\t\tmessages,\n\t\tmodel: params.model,\n\t\tstream: true\n\t};\n\n\tif (params.systemPrompt) {\n\t\tbody.system = params.systemPrompt;\n\t}\n\n\tif (params.tools && params.tools.length > 0) {\n\t\tbody.tools = params.tools.map(mapToolDefinition);\n\t}\n\n\tif (params.thinking) {\n\t\tbody.thinking = params.thinking;\n\t\t// When thinking is enabled, max_tokens must be higher\n\t\tbody.max_tokens = Math.max(\n\t\t\tMAX_TOKENS,\n\t\t\tparams.thinking.budget_tokens + MAX_TOKENS\n\t\t);\n\t}\n\n\treturn body;\n};\n\nconst classifyLine = (line: string) => {\n\tif (line.startsWith('event: ')) {\n\t\treturn {\n\t\t\tfield: 'event' as const,\n\t\t\tvalue: line.slice(EVENT_PREFIX_LENGTH)\n\t\t};\n\t}\n\n\tif (line.startsWith('data: ')) {\n\t\treturn {\n\t\t\tfield: 'data' as const,\n\t\t\tvalue: line.slice(DATA_PREFIX_LENGTH)\n\t\t};\n\t}\n\n\treturn undefined;\n};\n\nconst applyClassified = (\n\tacc: { eventData: string; eventType: string },\n\tclassified: { field: 'event' | 'data'; value: string } | undefined\n) => {\n\tif (!classified) {\n\t\treturn acc;\n\t}\n\n\tif (classified.field === 'event') {\n\t\treturn { eventData: acc.eventData, eventType: classified.value };\n\t}\n\n\treturn { eventData: classified.value, eventType: acc.eventType };\n};\n\nconst parseEventLines = (event: string) =>\n\tevent\n\t\t.split('\\n')\n\t\t.reduce((acc, line) => applyClassified(acc, classifyLine(line)), {\n\t\t\teventData: '',\n\t\t\teventType: ''\n\t\t});\n\nconst safeParse = (text: string) => {\n\ttry {\n\t\tconst result: unknown = JSON.parse(text);\n\n\t\treturn result;\n\t} catch {\n\t\treturn undefined;\n\t}\n};\n\nconst tryParseJson = (text: string) => {\n\tconst result = safeParse(text);\n\n\tif (isRecord(result)) {\n\t\treturn result;\n\t}\n\n\treturn undefined;\n};\n\nconst getRecord = (obj: Record<string, unknown>, key: string) => {\n\tconst val = obj[key];\n\n\tif (isRecord(val)) {\n\t\treturn val;\n\t}\n\n\treturn undefined;\n};\n\nconst getString = (obj: Record<string, unknown>, key: string) => {\n\tconst val = obj[key];\n\n\tif (typeof val === 'string') {\n\t\treturn val;\n\t}\n\n\treturn '';\n};\n\nconst getNumber = (obj: Record<string, unknown>, key: string) => {\n\tconst val = obj[key];\n\n\tif (typeof val === 'number') {\n\t\treturn val;\n\t}\n\n\treturn 0;\n};\n\nconst handleContentBlockStart = (\n\tparsed: Record<string, unknown>,\n\tstate: AnthropicSSEState\n) => {\n\tconst block = getRecord(parsed, 'content_block');\n\n\tif (block && block.type === 'tool_use') {\n\t\tstate.currentToolId = getString(block, 'id');\n\t\tstate.currentToolName = getString(block, 'name');\n\t\tstate.toolInputJson = '';\n\t\tstate.isThinkingBlock = false;\n\t} else if (block && block.type === 'thinking') {\n\t\tstate.isThinkingBlock = true;\n\t\tstate.thinkingSignature = '';\n\t} else {\n\t\tstate.isThinkingBlock = false;\n\t}\n};\n\nconst handleContentBlockDelta = (\n\tparsed: Record<string, unknown>,\n\tstate: AnthropicSSEState\n) => {\n\tconst delta = getRecord(parsed, 'delta');\n\n\tif (!delta) {\n\t\treturn undefined;\n\t}\n\n\tif (delta.type === 'thinking_delta') {\n\t\treturn {\n\t\t\tcontent: getString(delta, 'thinking'),\n\t\t\ttype: 'thinking'\n\t\t} satisfies AIChunk;\n\t}\n\n\tif (delta.type === 'text_delta') {\n\t\treturn {\n\t\t\tcontent: getString(delta, 'text'),\n\t\t\ttype: 'text'\n\t\t} satisfies AIChunk;\n\t}\n\n\tif (delta.type === 'input_json_delta') {\n\t\tstate.toolInputJson += getString(delta, 'partial_json');\n\t}\n\n\tif (delta.type === 'signature_delta') {\n\t\tstate.thinkingSignature += getString(delta, 'signature');\n\t}\n\n\treturn undefined;\n};\n\nconst handleContentBlockStop = (state: AnthropicSSEState) => {\n\t// Emit thinking signature when thinking block completes\n\tif (state.isThinkingBlock && state.thinkingSignature) {\n\t\tstate.isThinkingBlock = false;\n\t\tconst signature = state.thinkingSignature;\n\t\tstate.thinkingSignature = '';\n\n\t\treturn {\n\t\t\tcontent: '',\n\t\t\tsignature,\n\t\t\ttype: 'thinking'\n\t\t} satisfies AIChunk;\n\t}\n\n\tif (!state.currentToolId) {\n\t\treturn undefined;\n\t}\n\n\tconst input = tryParseJson(state.toolInputJson) ?? state.toolInputJson;\n\n\tconst chunk: AIChunk = {\n\t\tid: state.currentToolId,\n\t\tinput,\n\t\tname: state.currentToolName,\n\t\ttype: 'tool_use'\n\t};\n\n\tstate.currentToolId = '';\n\tstate.currentToolName = '';\n\tstate.toolInputJson = '';\n\n\treturn chunk;\n};\n\nconst extractUsage = (\n\tusageRecord: Record<string, unknown> | undefined,\n\texistingUsage: AIUsage | undefined\n) => {\n\tif (!usageRecord) {\n\t\treturn existingUsage;\n\t}\n\n\treturn {\n\t\tinputTokens:\n\t\t\tgetNumber(usageRecord, 'input_tokens') ||\n\t\t\texistingUsage?.inputTokens ||\n\t\t\t0,\n\t\toutputTokens:\n\t\t\tgetNumber(usageRecord, 'output_tokens') ||\n\t\t\texistingUsage?.outputTokens ||\n\t\t\t0\n\t};\n};\n\nconst handleMessageDelta = (\n\tparsed: Record<string, unknown>,\n\tstate: AnthropicSSEState\n) => {\n\tconst deltaUsage = getRecord(parsed, 'usage');\n\tstate.usage = extractUsage(deltaUsage, state.usage);\n};\n\nconst handleMessageStart = (\n\tparsed: Record<string, unknown>,\n\tstate: AnthropicSSEState\n) => {\n\tconst message = getRecord(parsed, 'message');\n\n\tif (!message) {\n\t\treturn;\n\t}\n\n\tconst startUsage = getRecord(message, 'usage');\n\tstate.usage = extractUsage(startUsage, state.usage);\n};\n\nconst handleError = (parsed: Record<string, unknown>) => {\n\tconst error = getRecord(parsed, 'error');\n\tconst errorMessage = error ? getString(error, 'message') : '';\n\n\tthrow new Error(errorMessage || 'Anthropic API error');\n};\n\nconst processEvent = (\n\teventType: string,\n\tparsed: Record<string, unknown>,\n\tstate: AnthropicSSEState\n) => {\n\tswitch (eventType) {\n\t\tcase 'content_block_start': {\n\t\t\thandleContentBlockStart(parsed, state);\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase 'content_block_delta': {\n\t\t\treturn handleContentBlockDelta(parsed, state);\n\t\t}\n\n\t\tcase 'content_block_stop': {\n\t\t\treturn handleContentBlockStop(state);\n\t\t}\n\n\t\tcase 'message_delta': {\n\t\t\thandleMessageDelta(parsed, state);\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase 'message_start': {\n\t\t\thandleMessageStart(parsed, state);\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase 'message_stop': {\n\t\t\treturn { type: 'done' as const, usage: state.usage };\n\t\t}\n\n\t\tcase 'error': {\n\t\t\thandleError(parsed);\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tdefault: {\n\t\t\treturn undefined;\n\t\t}\n\t}\n};\n\nconst processSingleEvent = (event: string, state: AnthropicSSEState) => {\n\tif (!event.trim()) {\n\t\treturn undefined;\n\t}\n\n\tconst { eventData, eventType } = parseEventLines(event);\n\n\tif (!eventData) {\n\t\treturn undefined;\n\t}\n\n\tconst parsed = tryParseJson(eventData);\n\n\tif (!parsed) {\n\t\treturn undefined;\n\t}\n\n\treturn processEvent(eventType, parsed, state);\n};\n\nconst collectChunk = (event: string, state: AnthropicSSEState) => {\n\tconst chunk = processSingleEvent(event, state);\n\n\treturn chunk ? [chunk] : [];\n};\n\nconst processBufferedEvents = (\n\teventsText: string,\n\tstate: AnthropicSSEState\n) => {\n\tconst events = eventsText.split('\\n\\n');\n\tstate.buffer = events.pop() ?? '';\n\n\treturn events.flatMap((event) => collectChunk(event, state));\n};\n\nconst readNextChunks = async (\n\treader: ReadableStreamDefaultReader<Uint8Array>,\n\tdecoder: TextDecoder,\n\tstate: AnthropicSSEState,\n\tsignal?: AbortSignal\n) => {\n\tif (signal?.aborted) {\n\t\treturn { chunks: EMPTY_CHUNKS, done: true };\n\t}\n\n\tconst { done, value } = await reader.read();\n\n\tif (done) {\n\t\treturn { chunks: EMPTY_CHUNKS, done: true };\n\t}\n\n\tconst rawText = state.buffer + decoder.decode(value, { stream: true });\n\tconst chunks = processBufferedEvents(rawText, state);\n\n\treturn { chunks, done: false };\n};\n\nconst findDoneChunk = (chunks: AIChunk[]) =>\n\tchunks.findIndex((c) => c.type === 'done');\n\nconst sseStreamLoop = async (\n\treader: ReadableStreamDefaultReader<Uint8Array>,\n\tdecoder: TextDecoder,\n\tstate: AnthropicSSEState,\n\tsignal?: AbortSignal\n) => {\n\tconst result = await readNextChunks(reader, decoder, state, signal);\n\n\tif (result.done) {\n\t\treturn { chunks: result.chunks, finished: true };\n\t}\n\n\tconst doneIdx = findDoneChunk(result.chunks);\n\n\tif (doneIdx >= 0) {\n\t\treturn { chunks: result.chunks.slice(0, doneIdx + 1), finished: true };\n\t}\n\n\treturn { chunks: result.chunks, finished: false };\n};\n\n// eslint-disable-next-line func-style\nasync function* streamChunks(\n\treader: ReadableStreamDefaultReader<Uint8Array>,\n\tdecoder: TextDecoder,\n\tstate: AnthropicSSEState,\n\tsignal?: AbortSignal\n) {\n\tlet finished = false;\n\n\twhile (!finished) {\n\t\t// eslint-disable-next-line no-await-in-loop\n\t\tconst result = await sseStreamLoop(reader, decoder, state, signal);\n\t\t({ finished } = result);\n\t\tyield* result.chunks;\n\t}\n}\n\n// eslint-disable-next-line func-style\nasync function* parseSSEStream(\n\tbody: ReadableStream<Uint8Array>,\n\tsignal?: AbortSignal\n) {\n\tconst reader = body.getReader();\n\tconst decoder = new TextDecoder();\n\n\tconst state: AnthropicSSEState = {\n\t\tbuffer: '',\n\t\tcurrentToolId: '',\n\t\tcurrentToolName: '',\n\t\tisThinkingBlock: false,\n\t\tthinkingSignature: '',\n\t\ttoolInputJson: '',\n\t\tusage: undefined\n\t};\n\n\ttry {\n\t\tyield* streamChunks(reader, decoder, state, signal);\n\t} finally {\n\t\treader.releaseLock();\n\t}\n}\n\nconst fetchAndStream = async function* (\n\tbaseUrl: string,\n\tconfig: AnthropicConfig,\n\tparams: AIProviderStreamParams\n) {\n\tconst body = buildRequestBody(params);\n\n\tconst response = await fetch(`${baseUrl}/v1/messages`, {\n\t\tbody: JSON.stringify(body),\n\t\theaders: {\n\t\t\t'anthropic-version': API_VERSION,\n\t\t\t'Content-Type': 'application/json',\n\t\t\t'x-api-key': config.apiKey\n\t\t},\n\t\tmethod: 'POST',\n\t\tsignal: params.signal\n\t});\n\n\tif (!response.ok) {\n\t\tconst errorText = await response.text();\n\n\t\tthrow new Error(`Anthropic API error ${response.status}: ${errorText}`);\n\t}\n\n\tif (!response.body) {\n\t\tthrow new Error('Anthropic API returned no response body');\n\t}\n\n\tyield* parseSSEStream(response.body, params.signal);\n};\n\nexport const anthropic = (config: AnthropicConfig): AIProviderConfig => {\n\tconst baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n\n\treturn {\n\t\tstream: (params: AIProviderStreamParams) =>\n\t\t\tfetchAndStream(baseUrl, config, params)\n\t};\n};\n"
6
+ ],
7
+ "mappings": ";;AAeA,IAAM,mBAAmB;AACzB,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,sBAAsB;AAC5B,IAAM,qBAAqB;AAE3B,IAAM,eAA0B,CAAC;AAEjC,IAAM,WAAW,CAAC,QACjB,OAAO,QAAQ,YAAY,QAAQ;AAEpC,IAAM,kBAAkB,CAAC,UAAkC;AAAA,EAC1D,IAAI,MAAM,SAAS,YAAY;AAAA,IAC9B,OAAO;AAAA,MACN,WAAW,MAAM;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,IAAI,MAAM,SAAS,SAAS;AAAA,IAC3B,OAAO;AAAA,MACN,QAAQ,MAAM;AAAA,MACd,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,IAAI,MAAM,SAAS,YAAY;AAAA,IAC9B,OAAO;AAAA,MACN,QAAQ,MAAM;AAAA,MACd,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,IAAI,MAAM,SAAS,eAAe;AAAA,IACjC,OAAO;AAAA,MACN,SAAS,MAAM;AAAA,MACf,aAAa,MAAM;AAAA,MACnB,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,IAAI,MAAM,SAAS,YAAY;AAAA,IAC9B,OAAO;AAAA,MACN,IAAI,MAAM;AAAA,MACV,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,OAAO,EAAE,MAAM,MAAM,SAAS,MAAM,OAAO;AAAA;AAG5C,IAAM,aAAa,CAAC,SAA8C;AAAA,EACjE,SACC,OAAO,IAAI,YAAY,WACpB,IAAI,UACJ,IAAI,QAAQ,IAAI,eAAe;AAAA,EACnC,MAAM,IAAI,SAAS,WAAW,SAAS,IAAI;AAC5C;AAEA,IAAM,oBAAoB,CAAC,UAAoC;AAAA,EAC9D,aAAa,KAAK;AAAA,EAClB,cAAc,KAAK;AAAA,EACnB,MAAM,KAAK;AACZ;AAEA,IAAM,mBAAmB,CAAC,WAAmC;AAAA,EAC5D,MAAM,WAA+B,OAAO,SAC1C,OAAO,CAAC,QAAQ,IAAI,SAAS,QAAQ,EACrC,IAAI,UAAU;AAAA,EAEhB,MAAM,OAAgC;AAAA,IACrC,YAAY;AAAA,IACZ;AAAA,IACA,OAAO,OAAO;AAAA,IACd,QAAQ;AAAA,EACT;AAAA,EAEA,IAAI,OAAO,cAAc;AAAA,IACxB,KAAK,SAAS,OAAO;AAAA,EACtB;AAAA,EAEA,IAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAAA,IAC5C,KAAK,QAAQ,OAAO,MAAM,IAAI,iBAAiB;AAAA,EAChD;AAAA,EAEA,IAAI,OAAO,UAAU;AAAA,IACpB,KAAK,WAAW,OAAO;AAAA,IAEvB,KAAK,aAAa,KAAK,IACtB,YACA,OAAO,SAAS,gBAAgB,UACjC;AAAA,EACD;AAAA,EAEA,OAAO;AAAA;AAGR,IAAM,eAAe,CAAC,SAAiB;AAAA,EACtC,IAAI,KAAK,WAAW,SAAS,GAAG;AAAA,IAC/B,OAAO;AAAA,MACN,OAAO;AAAA,MACP,OAAO,KAAK,MAAM,mBAAmB;AAAA,IACtC;AAAA,EACD;AAAA,EAEA,IAAI,KAAK,WAAW,QAAQ,GAAG;AAAA,IAC9B,OAAO;AAAA,MACN,OAAO;AAAA,MACP,OAAO,KAAK,MAAM,kBAAkB;AAAA,IACrC;AAAA,EACD;AAAA,EAEA;AAAA;AAGD,IAAM,kBAAkB,CACvB,KACA,eACI;AAAA,EACJ,IAAI,CAAC,YAAY;AAAA,IAChB,OAAO;AAAA,EACR;AAAA,EAEA,IAAI,WAAW,UAAU,SAAS;AAAA,IACjC,OAAO,EAAE,WAAW,IAAI,WAAW,WAAW,WAAW,MAAM;AAAA,EAChE;AAAA,EAEA,OAAO,EAAE,WAAW,WAAW,OAAO,WAAW,IAAI,UAAU;AAAA;AAGhE,IAAM,kBAAkB,CAAC,UACxB,MACE,MAAM;AAAA,CAAI,EACV,OAAO,CAAC,KAAK,SAAS,gBAAgB,KAAK,aAAa,IAAI,CAAC,GAAG;AAAA,EAChE,WAAW;AAAA,EACX,WAAW;AACZ,CAAC;AAEH,IAAM,YAAY,CAAC,SAAiB;AAAA,EACnC,IAAI;AAAA,IACH,MAAM,SAAkB,KAAK,MAAM,IAAI;AAAA,IAEvC,OAAO;AAAA,IACN,MAAM;AAAA,IACP;AAAA;AAAA;AAIF,IAAM,eAAe,CAAC,SAAiB;AAAA,EACtC,MAAM,SAAS,UAAU,IAAI;AAAA,EAE7B,IAAI,SAAS,MAAM,GAAG;AAAA,IACrB,OAAO;AAAA,EACR;AAAA,EAEA;AAAA;AAGD,IAAM,YAAY,CAAC,KAA8B,QAAgB;AAAA,EAChE,MAAM,MAAM,IAAI;AAAA,EAEhB,IAAI,SAAS,GAAG,GAAG;AAAA,IAClB,OAAO;AAAA,EACR;AAAA,EAEA;AAAA;AAGD,IAAM,YAAY,CAAC,KAA8B,QAAgB;AAAA,EAChE,MAAM,MAAM,IAAI;AAAA,EAEhB,IAAI,OAAO,QAAQ,UAAU;AAAA,IAC5B,OAAO;AAAA,EACR;AAAA,EAEA,OAAO;AAAA;AAGR,IAAM,YAAY,CAAC,KAA8B,QAAgB;AAAA,EAChE,MAAM,MAAM,IAAI;AAAA,EAEhB,IAAI,OAAO,QAAQ,UAAU;AAAA,IAC5B,OAAO;AAAA,EACR;AAAA,EAEA,OAAO;AAAA;AAGR,IAAM,0BAA0B,CAC/B,QACA,UACI;AAAA,EACJ,MAAM,QAAQ,UAAU,QAAQ,eAAe;AAAA,EAE/C,IAAI,SAAS,MAAM,SAAS,YAAY;AAAA,IACvC,MAAM,gBAAgB,UAAU,OAAO,IAAI;AAAA,IAC3C,MAAM,kBAAkB,UAAU,OAAO,MAAM;AAAA,IAC/C,MAAM,gBAAgB;AAAA,IACtB,MAAM,kBAAkB;AAAA,EACzB,EAAO,SAAI,SAAS,MAAM,SAAS,YAAY;AAAA,IAC9C,MAAM,kBAAkB;AAAA,IACxB,MAAM,oBAAoB;AAAA,EAC3B,EAAO;AAAA,IACN,MAAM,kBAAkB;AAAA;AAAA;AAI1B,IAAM,0BAA0B,CAC/B,QACA,UACI;AAAA,EACJ,MAAM,QAAQ,UAAU,QAAQ,OAAO;AAAA,EAEvC,IAAI,CAAC,OAAO;AAAA,IACX;AAAA,EACD;AAAA,EAEA,IAAI,MAAM,SAAS,kBAAkB;AAAA,IACpC,OAAO;AAAA,MACN,SAAS,UAAU,OAAO,UAAU;AAAA,MACpC,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,IAAI,MAAM,SAAS,cAAc;AAAA,IAChC,OAAO;AAAA,MACN,SAAS,UAAU,OAAO,MAAM;AAAA,MAChC,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,IAAI,MAAM,SAAS,oBAAoB;AAAA,IACtC,MAAM,iBAAiB,UAAU,OAAO,cAAc;AAAA,EACvD;AAAA,EAEA,IAAI,MAAM,SAAS,mBAAmB;AAAA,IACrC,MAAM,qBAAqB,UAAU,OAAO,WAAW;AAAA,EACxD;AAAA,EAEA;AAAA;AAGD,IAAM,yBAAyB,CAAC,UAA6B;AAAA,EAE5D,IAAI,MAAM,mBAAmB,MAAM,mBAAmB;AAAA,IACrD,MAAM,kBAAkB;AAAA,IACxB,MAAM,YAAY,MAAM;AAAA,IACxB,MAAM,oBAAoB;AAAA,IAE1B,OAAO;AAAA,MACN,SAAS;AAAA,MACT;AAAA,MACA,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,IAAI,CAAC,MAAM,eAAe;AAAA,IACzB;AAAA,EACD;AAAA,EAEA,MAAM,QAAQ,aAAa,MAAM,aAAa,KAAK,MAAM;AAAA,EAEzD,MAAM,QAAiB;AAAA,IACtB,IAAI,MAAM;AAAA,IACV;AAAA,IACA,MAAM,MAAM;AAAA,IACZ,MAAM;AAAA,EACP;AAAA,EAEA,MAAM,gBAAgB;AAAA,EACtB,MAAM,kBAAkB;AAAA,EACxB,MAAM,gBAAgB;AAAA,EAEtB,OAAO;AAAA;AAGR,IAAM,eAAe,CACpB,aACA,kBACI;AAAA,EACJ,IAAI,CAAC,aAAa;AAAA,IACjB,OAAO;AAAA,EACR;AAAA,EAEA,OAAO;AAAA,IACN,aACC,UAAU,aAAa,cAAc,KACrC,eAAe,eACf;AAAA,IACD,cACC,UAAU,aAAa,eAAe,KACtC,eAAe,gBACf;AAAA,EACF;AAAA;AAGD,IAAM,qBAAqB,CAC1B,QACA,UACI;AAAA,EACJ,MAAM,aAAa,UAAU,QAAQ,OAAO;AAAA,EAC5C,MAAM,QAAQ,aAAa,YAAY,MAAM,KAAK;AAAA;AAGnD,IAAM,qBAAqB,CAC1B,QACA,UACI;AAAA,EACJ,MAAM,UAAU,UAAU,QAAQ,SAAS;AAAA,EAE3C,IAAI,CAAC,SAAS;AAAA,IACb;AAAA,EACD;AAAA,EAEA,MAAM,aAAa,UAAU,SAAS,OAAO;AAAA,EAC7C,MAAM,QAAQ,aAAa,YAAY,MAAM,KAAK;AAAA;AAGnD,IAAM,cAAc,CAAC,WAAoC;AAAA,EACxD,MAAM,QAAQ,UAAU,QAAQ,OAAO;AAAA,EACvC,MAAM,eAAe,QAAQ,UAAU,OAAO,SAAS,IAAI;AAAA,EAE3D,MAAM,IAAI,MAAM,gBAAgB,qBAAqB;AAAA;AAGtD,IAAM,eAAe,CACpB,WACA,QACA,UACI;AAAA,EACJ,QAAQ;AAAA,SACF,uBAAuB;AAAA,MAC3B,wBAAwB,QAAQ,KAAK;AAAA,MAErC;AAAA,IACD;AAAA,SAEK,uBAAuB;AAAA,MAC3B,OAAO,wBAAwB,QAAQ,KAAK;AAAA,IAC7C;AAAA,SAEK,sBAAsB;AAAA,MAC1B,OAAO,uBAAuB,KAAK;AAAA,IACpC;AAAA,SAEK,iBAAiB;AAAA,MACrB,mBAAmB,QAAQ,KAAK;AAAA,MAEhC;AAAA,IACD;AAAA,SAEK,iBAAiB;AAAA,MACrB,mBAAmB,QAAQ,KAAK;AAAA,MAEhC;AAAA,IACD;AAAA,SAEK,gBAAgB;AAAA,MACpB,OAAO,EAAE,MAAM,QAAiB,OAAO,MAAM,MAAM;AAAA,IACpD;AAAA,SAEK,SAAS;AAAA,MACb,YAAY,MAAM;AAAA,MAElB;AAAA,IACD;AAAA,aAES;AAAA,MACR;AAAA,IACD;AAAA;AAAA;AAIF,IAAM,qBAAqB,CAAC,OAAe,UAA6B;AAAA,EACvE,IAAI,CAAC,MAAM,KAAK,GAAG;AAAA,IAClB;AAAA,EACD;AAAA,EAEA,QAAQ,WAAW,cAAc,gBAAgB,KAAK;AAAA,EAEtD,IAAI,CAAC,WAAW;AAAA,IACf;AAAA,EACD;AAAA,EAEA,MAAM,SAAS,aAAa,SAAS;AAAA,EAErC,IAAI,CAAC,QAAQ;AAAA,IACZ;AAAA,EACD;AAAA,EAEA,OAAO,aAAa,WAAW,QAAQ,KAAK;AAAA;AAG7C,IAAM,eAAe,CAAC,OAAe,UAA6B;AAAA,EACjE,MAAM,QAAQ,mBAAmB,OAAO,KAAK;AAAA,EAE7C,OAAO,QAAQ,CAAC,KAAK,IAAI,CAAC;AAAA;AAG3B,IAAM,wBAAwB,CAC7B,YACA,UACI;AAAA,EACJ,MAAM,SAAS,WAAW,MAAM;AAAA;AAAA,CAAM;AAAA,EACtC,MAAM,SAAS,OAAO,IAAI,KAAK;AAAA,EAE/B,OAAO,OAAO,QAAQ,CAAC,UAAU,aAAa,OAAO,KAAK,CAAC;AAAA;AAG5D,IAAM,iBAAiB,OACtB,QACA,SACA,OACA,WACI;AAAA,EACJ,IAAI,QAAQ,SAAS;AAAA,IACpB,OAAO,EAAE,QAAQ,cAAc,MAAM,KAAK;AAAA,EAC3C;AAAA,EAEA,QAAQ,MAAM,UAAU,MAAM,OAAO,KAAK;AAAA,EAE1C,IAAI,MAAM;AAAA,IACT,OAAO,EAAE,QAAQ,cAAc,MAAM,KAAK;AAAA,EAC3C;AAAA,EAEA,MAAM,UAAU,MAAM,SAAS,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAAA,EACrE,MAAM,SAAS,sBAAsB,SAAS,KAAK;AAAA,EAEnD,OAAO,EAAE,QAAQ,MAAM,MAAM;AAAA;AAG9B,IAAM,gBAAgB,CAAC,WACtB,OAAO,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM;AAE1C,IAAM,gBAAgB,OACrB,QACA,SACA,OACA,WACI;AAAA,EACJ,MAAM,SAAS,MAAM,eAAe,QAAQ,SAAS,OAAO,MAAM;AAAA,EAElE,IAAI,OAAO,MAAM;AAAA,IAChB,OAAO,EAAE,QAAQ,OAAO,QAAQ,UAAU,KAAK;AAAA,EAChD;AAAA,EAEA,MAAM,UAAU,cAAc,OAAO,MAAM;AAAA,EAE3C,IAAI,WAAW,GAAG;AAAA,IACjB,OAAO,EAAE,QAAQ,OAAO,OAAO,MAAM,GAAG,UAAU,CAAC,GAAG,UAAU,KAAK;AAAA,EACtE;AAAA,EAEA,OAAO,EAAE,QAAQ,OAAO,QAAQ,UAAU,MAAM;AAAA;AAIjD,gBAAgB,YAAY,CAC3B,QACA,SACA,OACA,QACC;AAAA,EACD,IAAI,WAAW;AAAA,EAEf,OAAO,CAAC,UAAU;AAAA,IAEjB,MAAM,SAAS,MAAM,cAAc,QAAQ,SAAS,OAAO,MAAM;AAAA,KAChE,EAAE,SAAS,IAAI;AAAA,IAChB,OAAO,OAAO;AAAA,EACf;AAAA;AAID,gBAAgB,cAAc,CAC7B,MACA,QACC;AAAA,EACD,MAAM,SAAS,KAAK,UAAU;AAAA,EAC9B,MAAM,UAAU,IAAI;AAAA,EAEpB,MAAM,QAA2B;AAAA,IAChC,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,OAAO;AAAA,EACR;AAAA,EAEA,IAAI;AAAA,IACH,OAAO,aAAa,QAAQ,SAAS,OAAO,MAAM;AAAA,YACjD;AAAA,IACD,OAAO,YAAY;AAAA;AAAA;AAIrB,IAAM,iBAAiB,gBAAgB,CACtC,SACA,QACA,QACC;AAAA,EACD,MAAM,OAAO,iBAAiB,MAAM;AAAA,EAEpC,MAAM,WAAW,MAAM,MAAM,GAAG,uBAAuB;AAAA,IACtD,MAAM,KAAK,UAAU,IAAI;AAAA,IACzB,SAAS;AAAA,MACR,qBAAqB;AAAA,MACrB,gBAAgB;AAAA,MAChB,aAAa,OAAO;AAAA,IACrB;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ,OAAO;AAAA,EAChB,CAAC;AAAA,EAED,IAAI,CAAC,SAAS,IAAI;AAAA,IACjB,MAAM,YAAY,MAAM,SAAS,KAAK;AAAA,IAEtC,MAAM,IAAI,MAAM,uBAAuB,SAAS,WAAW,WAAW;AAAA,EACvE;AAAA,EAEA,IAAI,CAAC,SAAS,MAAM;AAAA,IACnB,MAAM,IAAI,MAAM,yCAAyC;AAAA,EAC1D;AAAA,EAEA,OAAO,eAAe,SAAS,MAAM,OAAO,MAAM;AAAA;AAG5C,IAAM,YAAY,CAAC,WAA8C;AAAA,EACvE,MAAM,UAAU,OAAO,WAAW;AAAA,EAElC,OAAO;AAAA,IACN,QAAQ,CAAC,WACR,eAAe,SAAS,QAAQ,MAAM;AAAA,EACxC;AAAA;",
8
+ "debugId": "46FDFC941805E6B864756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,260 @@
1
+ // @bun
2
+ // src/ai/providers/gemini.ts
3
+ var DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com";
4
+ var SSE_DATA_PREFIX_LENGTH = 6;
5
+ var isRecord = (value) => typeof value === "object" && value !== null;
6
+ var isRecordArray = (value) => Array.isArray(value) && value.length > 0 && isRecord(value[0]);
7
+ var mapRole = (role) => {
8
+ if (role === "assistant" || role === "system")
9
+ return "model";
10
+ return "user";
11
+ };
12
+ var mapContentBlock = (block) => {
13
+ switch (block.type) {
14
+ case "text":
15
+ return { text: block.content };
16
+ case "image":
17
+ return {
18
+ inlineData: {
19
+ data: block.source.data,
20
+ mimeType: block.source.media_type
21
+ }
22
+ };
23
+ case "document":
24
+ return {
25
+ inlineData: {
26
+ data: block.source.data,
27
+ mimeType: block.source.media_type
28
+ }
29
+ };
30
+ case "tool_use":
31
+ return {
32
+ functionCall: {
33
+ args: typeof block.input === "string" ? JSON.parse(block.input) : block.input,
34
+ name: block.name
35
+ }
36
+ };
37
+ case "tool_result":
38
+ return {
39
+ functionResponse: {
40
+ name: block.tool_use_id,
41
+ response: { result: block.content }
42
+ }
43
+ };
44
+ default:
45
+ return null;
46
+ }
47
+ };
48
+ var convertMessageContent = (content) => {
49
+ if (typeof content === "string") {
50
+ return [{ text: content }];
51
+ }
52
+ return content.map(mapContentBlock).filter((mapped) => mapped !== null);
53
+ };
54
+ var hasFunctionResponse = (content) => content.some((block) => block.type === "tool_result");
55
+ var convertSingleMessage = (msg) => {
56
+ if (typeof msg.content !== "string" && hasFunctionResponse(msg.content)) {
57
+ return { parts: convertMessageContent(msg.content), role: "user" };
58
+ }
59
+ return {
60
+ parts: convertMessageContent(msg.content),
61
+ role: mapRole(msg.role)
62
+ };
63
+ };
64
+ var convertMessages = (messages) => messages.map(convertSingleMessage);
65
+ var mapToolDefinitions = (tools) => tools.map((tool) => ({
66
+ description: tool.description,
67
+ name: tool.name,
68
+ parameters: tool.input_schema
69
+ }));
70
+ var buildRequestBody = (params, isImageModel) => {
71
+ const body = {
72
+ contents: convertMessages(params.messages)
73
+ };
74
+ if (isImageModel) {
75
+ body.generationConfig = {
76
+ responseModalities: ["TEXT", "IMAGE"]
77
+ };
78
+ }
79
+ if (params.systemPrompt) {
80
+ body.systemInstruction = {
81
+ parts: [{ text: params.systemPrompt }]
82
+ };
83
+ }
84
+ if (params.tools && params.tools.length > 0) {
85
+ body.tools = [
86
+ { functionDeclarations: mapToolDefinitions(params.tools) }
87
+ ];
88
+ }
89
+ return body;
90
+ };
91
+ var extractMimeFormat = (mimeType) => {
92
+ if (typeof mimeType !== "string") {
93
+ return "png";
94
+ }
95
+ if (mimeType.includes("jpeg") || mimeType.includes("jpg"))
96
+ return "jpeg";
97
+ if (mimeType.includes("webp"))
98
+ return "webp";
99
+ return "png";
100
+ };
101
+ var processTextPart = function* (part) {
102
+ if (typeof part.text === "string" && part.text) {
103
+ yield { content: part.text, type: "text" };
104
+ }
105
+ };
106
+ var processInlineDataPart = function* (inlineData) {
107
+ const data = typeof inlineData.data === "string" ? inlineData.data : "";
108
+ const { mimeType } = inlineData;
109
+ if (!data) {
110
+ return;
111
+ }
112
+ yield {
113
+ data,
114
+ format: extractMimeFormat(mimeType),
115
+ isPartial: false,
116
+ type: "image"
117
+ };
118
+ };
119
+ var processFunctionCallPart = function* (functionCall) {
120
+ const name = typeof functionCall.name === "string" ? functionCall.name : "";
121
+ const args = functionCall.args ?? {};
122
+ yield {
123
+ id: `gemini-${name}-${Date.now()}`,
124
+ input: args,
125
+ name,
126
+ type: "tool_use"
127
+ };
128
+ };
129
+ var processPart = function* (part) {
130
+ if ("text" in part) {
131
+ yield* processTextPart(part);
132
+ }
133
+ if (isRecord(part.inlineData)) {
134
+ yield* processInlineDataPart(part.inlineData);
135
+ }
136
+ if (isRecord(part.functionCall)) {
137
+ yield* processFunctionCallPart(part.functionCall);
138
+ }
139
+ };
140
+ var extractUsage = (parsed) => {
141
+ if (!isRecord(parsed.usageMetadata)) {
142
+ return;
143
+ }
144
+ const { usageMetadata } = parsed;
145
+ return {
146
+ inputTokens: typeof usageMetadata.promptTokenCount === "number" ? usageMetadata.promptTokenCount : 0,
147
+ outputTokens: typeof usageMetadata.candidatesTokenCount === "number" ? usageMetadata.candidatesTokenCount : 0
148
+ };
149
+ };
150
+ var processChunk = function* (parsed, state) {
151
+ const usage = extractUsage(parsed);
152
+ if (usage) {
153
+ state.usage = usage;
154
+ }
155
+ if (!isRecordArray(parsed.candidates)) {
156
+ return;
157
+ }
158
+ const [candidate] = parsed.candidates;
159
+ if (!candidate || !isRecord(candidate.content)) {
160
+ return;
161
+ }
162
+ const { content } = candidate;
163
+ if (!isRecordArray(content.parts)) {
164
+ return;
165
+ }
166
+ for (const part of content.parts) {
167
+ yield* processPart(part);
168
+ }
169
+ };
170
+ var processSSELine = function* (line, state) {
171
+ const trimmed = line.trim();
172
+ if (!trimmed || !trimmed.startsWith("data: ")) {
173
+ return;
174
+ }
175
+ const data = trimmed.slice(SSE_DATA_PREFIX_LENGTH);
176
+ let parsed;
177
+ try {
178
+ parsed = JSON.parse(data);
179
+ } catch {
180
+ return;
181
+ }
182
+ yield* processChunk(parsed, state);
183
+ };
184
+ var processSSEBuffer = function* (lines, state) {
185
+ for (const line of lines) {
186
+ yield* processSSELine(line, state);
187
+ }
188
+ };
189
+ var drainReader = async function* (reader, decoder, state, signal) {
190
+ let textBuffer = "";
191
+ for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
192
+ textBuffer += decoder.decode(result.value, { stream: true });
193
+ const lines = textBuffer.split(`
194
+ `);
195
+ textBuffer = lines.pop() ?? "";
196
+ yield* processSSEBuffer(lines, state);
197
+ }
198
+ if (textBuffer.trim()) {
199
+ yield* processSSELine(textBuffer, state);
200
+ }
201
+ yield { type: "done", usage: state.usage };
202
+ };
203
+ var parseSSEStream = async function* (body, signal) {
204
+ const reader = body.getReader();
205
+ const decoder = new TextDecoder;
206
+ const state = {
207
+ buffer: "",
208
+ usage: undefined
209
+ };
210
+ try {
211
+ yield* drainReader(reader, decoder, state, signal);
212
+ } finally {
213
+ reader.releaseLock();
214
+ }
215
+ };
216
+ var fetchGeminiStream = async function* (baseUrl, apiKey, model, body, signal) {
217
+ const url = `${baseUrl}/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${apiKey}`;
218
+ const response = await fetch(url, {
219
+ body: JSON.stringify(body),
220
+ headers: {
221
+ "Content-Type": "application/json"
222
+ },
223
+ method: "POST",
224
+ signal
225
+ });
226
+ if (!response.ok) {
227
+ const errorText = await response.text();
228
+ throw new Error(`Gemini API error ${response.status}: ${errorText}`);
229
+ }
230
+ if (!response.body) {
231
+ throw new Error("Gemini API returned no response body");
232
+ }
233
+ yield* parseSSEStream(response.body, signal);
234
+ };
235
+ var resolveImageModels = (raw) => {
236
+ if (!raw) {
237
+ return new Set;
238
+ }
239
+ if (raw instanceof Set) {
240
+ return raw;
241
+ }
242
+ return new Set(raw);
243
+ };
244
+ var gemini = (config) => {
245
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
246
+ const imageModels = resolveImageModels(config.imageModels);
247
+ return {
248
+ stream: (params) => {
249
+ const isImageModel = imageModels.has(params.model);
250
+ const body = buildRequestBody(params, isImageModel);
251
+ return fetchGeminiStream(baseUrl, config.apiKey, params.model, body, params.signal);
252
+ }
253
+ };
254
+ };
255
+ export {
256
+ gemini
257
+ };
258
+
259
+ //# debugId=9DAEE9BA5DB0F89864756E2164756E21
260
+ //# sourceMappingURL=gemini.js.map