@swifty.js/swifty 0.0.21 → 0.0.23

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/dist/{agent-ZCMBUWLZ.js → agent-RABW3Z3R.js} +1 -1
  2. package/dist/anthropic-V22T6E6E.js +4 -0
  3. package/dist/{checker-OJFS2MZY.js → checker-3RWAYF2U.js} +1 -1
  4. package/dist/{chunk-Y5WGBAGP.js → chunk-5KXBVL2A.js} +1 -1
  5. package/dist/{chunk-MUPVOATV.js → chunk-CV7OKXYC.js} +1 -1
  6. package/dist/chunk-MJR2C7S7.js +130 -0
  7. package/dist/{chunk-GUXBLUNR.js → chunk-NR62AA5K.js} +1 -1
  8. package/dist/{chunk-S6ZADC7C.js → chunk-OCQ6TYLT.js} +21 -20
  9. package/dist/chunk-QN27QEFS.js +4 -0
  10. package/dist/{chunk-LX2LK3TF.js → chunk-SIWLMWHH.js} +12 -11
  11. package/dist/chunk-Y43POSIW.js +389 -0
  12. package/dist/lib/agent-GHXYOARN.js +9 -0
  13. package/dist/lib/anthropic-7YEN2QTU.js +22 -0
  14. package/dist/lib/bwrap-QRGPUP4J.js +6 -0
  15. package/dist/lib/checker-6BW4222R.js +19 -0
  16. package/dist/lib/chunk-7IZEK7X5.js +545 -0
  17. package/dist/lib/chunk-BN4Q54G2.js +1096 -0
  18. package/dist/lib/chunk-BO76JDFZ.js +617 -0
  19. package/dist/lib/chunk-CYDNMEBC.js +339 -0
  20. package/dist/lib/chunk-EY7HE52Q.js +384 -0
  21. package/dist/lib/chunk-GHF2PSEW.js +8 -0
  22. package/dist/lib/chunk-GNI7YX6F.js +426 -0
  23. package/dist/lib/chunk-HK2Z6WP4.js +223 -0
  24. package/dist/lib/chunk-MF3YLQDS.js +1277 -0
  25. package/dist/lib/chunk-OO2CLOEE.js +88 -0
  26. package/dist/lib/chunk-ORSYNBMM.js +38 -0
  27. package/dist/lib/chunk-PZ42NAFA.js +242 -0
  28. package/dist/lib/chunk-VUD72RTY.js +39 -0
  29. package/dist/lib/glob.wasm +0 -0
  30. package/dist/lib/index.d.ts +5347 -0
  31. package/dist/lib/index.js +11990 -0
  32. package/dist/lib/openai-RDHZFJUT.js +15 -0
  33. package/dist/lib/seatbelt-FT5IY73W.js +6 -0
  34. package/dist/lib/tool-filter-VF7TZRE5.js +19 -0
  35. package/dist/main.js +204 -466
  36. package/dist/{openai-HXD52MZB.js → openai-6NWVJ5LI.js} +15 -15
  37. package/dist/{server-VMHWEO2Y.js → server-KQTLAXC6.js} +17 -17
  38. package/package.json +18 -6
  39. package/dist/anthropic-4ZVG7AMA.js +0 -4
  40. package/dist/chunk-6E6UA7MT.js +0 -126
  41. package/dist/chunk-DDBH5AEN.js +0 -386
  42. package/dist/chunk-ZZQE743W.js +0 -4
@@ -0,0 +1,617 @@
1
+ import {
2
+ getMaxOutputTokens,
3
+ resolveAPIKey
4
+ } from "./chunk-CYDNMEBC.js";
5
+ import {
6
+ AuthenticationError,
7
+ ContextTooLongError,
8
+ LLMError,
9
+ NetworkError,
10
+ RateLimitError,
11
+ ensureToolPairing
12
+ } from "./chunk-OO2CLOEE.js";
13
+ import {
14
+ asRecord,
15
+ asString,
16
+ contentToText,
17
+ createChildLogger,
18
+ isRecord,
19
+ strArg
20
+ } from "./chunk-EY7HE52Q.js";
21
+
22
+ // src/llm/openai.ts
23
+ import OpenAI from "openai";
24
+ var log = createChildLogger({ module: "llm" });
25
+ var OpenAIClient = class {
26
+ client;
27
+ model;
28
+ systemPrompt;
29
+ maxOutputTokens;
30
+ constructor(config, systemPrompt) {
31
+ const apiKey = resolveAPIKey(config);
32
+ if (!apiKey) {
33
+ throw new AuthenticationError(
34
+ "OpenAI API key not found, set OPENAI_API_KEY in .swifty/config.y(a)ml, or via OPENAI_API_KEY env variable."
35
+ );
36
+ }
37
+ this.client = new OpenAI({
38
+ apiKey,
39
+ baseURL: config.base_url
40
+ });
41
+ this.model = config.model;
42
+ this.systemPrompt = systemPrompt;
43
+ this.maxOutputTokens = getMaxOutputTokens(config);
44
+ }
45
+ async *stream(conversation, toolSchemas, abortSignal) {
46
+ const messages = buildOpenAIInput(ensureToolPairing(conversation.getMessages()));
47
+ const input = [];
48
+ input.push({
49
+ role: "system",
50
+ content: this.systemPrompt
51
+ });
52
+ for (const message of messages) {
53
+ input.push(message);
54
+ }
55
+ const tools = toolSchemas.map((s) => {
56
+ const schema = s.input_schema;
57
+ return {
58
+ type: "function",
59
+ name: s.name,
60
+ description: s.description,
61
+ parameters: schema,
62
+ strict: false
63
+ };
64
+ });
65
+ const params = {
66
+ model: this.model,
67
+ input,
68
+ stream: true,
69
+ max_output_tokens: this.maxOutputTokens,
70
+ ...tools.length > 0 ? { tools } : {}
71
+ };
72
+ let inputTokens = 0;
73
+ let outputTokens = 0;
74
+ let cacheReadInputTokens = 0;
75
+ const cacheCreationInputTokens = 0;
76
+ try {
77
+ const stream = await this.client.responses.create(params, {
78
+ ...abortSignal ? { signal: abortSignal } : {}
79
+ });
80
+ let currentToolName = "";
81
+ let currentToolId = "";
82
+ let jsonAccumulate = "";
83
+ let reasoningId = "";
84
+ let reasoningText = "";
85
+ for await (const event of stream) {
86
+ if (event.type === "response.output_text.delta") {
87
+ yield {
88
+ type: "text_delta",
89
+ text: event.delta
90
+ };
91
+ } else if (event.type === "response.reasoning_summary_text.delta") {
92
+ reasoningText += event.delta;
93
+ yield { type: "thinking_delta", text: event.delta };
94
+ } else if (event.type === "response.reasoning_summary_text.done") {
95
+ yield {
96
+ type: "thinking_complete",
97
+ thinking: reasoningText,
98
+ signature: reasoningId
99
+ };
100
+ } else if (event.type === "response.function_call_arguments.delta") {
101
+ jsonAccumulate += event.delta;
102
+ yield {
103
+ type: "tool_call_delta",
104
+ text: event.delta
105
+ };
106
+ } else if (event.type === "response.output_item.added") {
107
+ if (event.item.type === "function_call") {
108
+ currentToolName = event.item.name;
109
+ currentToolId = event.item.call_id;
110
+ jsonAccumulate = "";
111
+ yield {
112
+ type: "tool_call_start",
113
+ toolName: currentToolName,
114
+ toolId: currentToolId
115
+ };
116
+ } else if (event.item.type === "reasoning") {
117
+ reasoningId = event.item.id ?? "";
118
+ reasoningText = "";
119
+ }
120
+ } else if (event.type === "response.output_item.done") {
121
+ if (event.item.type === "function_call" && currentToolName) {
122
+ let args = {};
123
+ if (jsonAccumulate) {
124
+ try {
125
+ const parsed = JSON.parse(jsonAccumulate);
126
+ args = isRecord(parsed) ? asRecord(parsed) : {};
127
+ } catch (err) {
128
+ log.error({ err }, "llm operation failed");
129
+ args = {};
130
+ }
131
+ }
132
+ yield {
133
+ type: "tool_call_complete",
134
+ toolId: currentToolId,
135
+ toolName: currentToolName,
136
+ arguments: args
137
+ };
138
+ currentToolName = "";
139
+ currentToolId = "";
140
+ jsonAccumulate = "";
141
+ }
142
+ } else if (event.type === "response.completed") {
143
+ const usage = event.response.usage;
144
+ if (usage) {
145
+ outputTokens = usage.output_tokens;
146
+ cacheReadInputTokens = usage.input_tokens_details.cached_tokens;
147
+ inputTokens = Math.max(0, usage.input_tokens - cacheReadInputTokens);
148
+ }
149
+ let stopReason = "end_turn";
150
+ const resp = event.response;
151
+ if (resp.status === "incomplete") {
152
+ const details = resp.incomplete_details;
153
+ if (details?.reason === "max_output_tokens") {
154
+ stopReason = "max_tokens";
155
+ }
156
+ }
157
+ yield {
158
+ type: "stream_end",
159
+ stopReason,
160
+ usage: {
161
+ inputTokens,
162
+ outputTokens,
163
+ cacheReadInputTokens,
164
+ cacheCreationInputTokens
165
+ // 0
166
+ }
167
+ };
168
+ }
169
+ }
170
+ } catch (err) {
171
+ log.error({ err }, "llm operation failed");
172
+ throw classifyOpenAIError(err);
173
+ }
174
+ }
175
+ setSystemPrompt(prompt) {
176
+ this.systemPrompt = prompt;
177
+ }
178
+ setMaxOutputTokens(maxTokens) {
179
+ this.maxOutputTokens = maxTokens;
180
+ }
181
+ };
182
+ function imageDataUrl(block) {
183
+ if (!isRecord(block) || block.type !== "image" || !isRecord(block.source)) {
184
+ return null;
185
+ }
186
+ if (block.source.type === "url") {
187
+ return strArg(block.source, "url") || null;
188
+ }
189
+ if (block.source.type !== "base64") {
190
+ return null;
191
+ }
192
+ const mediaType = strArg(block.source, "media_type");
193
+ const data = strArg(block.source, "data");
194
+ return mediaType && data ? `data:${mediaType};base64,${data}` : null;
195
+ }
196
+ function documentForResponses(block) {
197
+ if (!isRecord(block) || block.type !== "document" || !isRecord(block.source)) {
198
+ return null;
199
+ }
200
+ const title = typeof block.title === "string" && block.title ? block.title : "tool-result";
201
+ if (block.source.type === "url") {
202
+ const fileUrl = strArg(block.source, "url");
203
+ return fileUrl ? { type: "input_file", file_url: fileUrl } : null;
204
+ }
205
+ if (block.source.type === "base64") {
206
+ const data = strArg(block.source, "data");
207
+ return data ? { type: "input_file", file_data: data, filename: `${title}.pdf` } : null;
208
+ }
209
+ if (block.source.type === "text") {
210
+ const data = strArg(block.source, "data");
211
+ return data ? {
212
+ type: "input_file",
213
+ file_data: Buffer.from(data, "utf-8").toString("base64"),
214
+ filename: `${title}.txt`
215
+ } : null;
216
+ }
217
+ return null;
218
+ }
219
+ function documentForChat(block) {
220
+ if (!isRecord(block) || block.type !== "document" || !isRecord(block.source)) {
221
+ return null;
222
+ }
223
+ const title = typeof block.title === "string" && block.title ? block.title : "tool-result";
224
+ if (block.source.type === "base64") {
225
+ const data = strArg(block.source, "data");
226
+ return data ? { type: "file", file: { file_data: data, filename: `${title}.pdf` } } : null;
227
+ }
228
+ if (block.source.type === "text") {
229
+ const data = strArg(block.source, "data");
230
+ return data ? {
231
+ type: "file",
232
+ file: {
233
+ file_data: Buffer.from(data, "utf-8").toString("base64"),
234
+ filename: `${title}.txt`
235
+ }
236
+ } : null;
237
+ }
238
+ return null;
239
+ }
240
+ function toolOutputForResponses(tr) {
241
+ if (!tr.contentBlocks?.length) {
242
+ return tr.content;
243
+ }
244
+ const rich = [];
245
+ if (tr.content) {
246
+ rich.push({ type: "input_text", text: tr.content });
247
+ }
248
+ for (const block of tr.contentBlocks) {
249
+ const imageUrl = imageDataUrl(block);
250
+ if (imageUrl) {
251
+ rich.push({ type: "input_image", image_url: imageUrl, detail: "auto" });
252
+ continue;
253
+ }
254
+ const file = documentForResponses(block);
255
+ if (file) {
256
+ rich.push(file);
257
+ }
258
+ }
259
+ return rich.length > 0 ? rich : tr.content;
260
+ }
261
+ function collectRichParts(tr) {
262
+ if (!tr.contentBlocks?.length) {
263
+ return [];
264
+ }
265
+ const rich = [];
266
+ for (const block of tr.contentBlocks) {
267
+ const imageUrl = imageDataUrl(block);
268
+ if (imageUrl) {
269
+ rich.push({ type: "image_url", image_url: { url: imageUrl } });
270
+ continue;
271
+ }
272
+ const file = documentForChat(block);
273
+ if (file) {
274
+ rich.push(file);
275
+ }
276
+ }
277
+ if (rich.length === 0) {
278
+ return [];
279
+ }
280
+ return [{ type: "text", text: `[Rich content returned by tool call ${tr.toolUseId}]` }, ...rich];
281
+ }
282
+ function userContentsFor(content) {
283
+ if (typeof content === "string") {
284
+ return content;
285
+ }
286
+ const parts = [];
287
+ for (const block of content) {
288
+ if (block.type === "text") {
289
+ parts.push({ type: "input_text", text: strArg(block, "text") });
290
+ } else {
291
+ const url = imageDataUrl(block);
292
+ if (url) {
293
+ parts.push({ type: "input_image", image_url: url, detail: "auto" });
294
+ }
295
+ }
296
+ }
297
+ return parts;
298
+ }
299
+ function userPartsFor(content) {
300
+ if (typeof content === "string") {
301
+ return content;
302
+ }
303
+ const parts = [];
304
+ for (const block of content) {
305
+ if (block.type === "text") {
306
+ parts.push({ type: "text", text: strArg(block, "text") });
307
+ } else {
308
+ const url = imageDataUrl(block);
309
+ if (url) {
310
+ parts.push({ type: "image_url", image_url: { url } });
311
+ }
312
+ }
313
+ }
314
+ return parts;
315
+ }
316
+ function buildOpenAIInput(messages) {
317
+ const result = [];
318
+ for (const m of messages) {
319
+ if (m.thinkingBlocks) {
320
+ for (const tb of m.thinkingBlocks) {
321
+ result.push({
322
+ type: "reasoning",
323
+ id: tb.signature,
324
+ summary: [{ type: "summary_text", text: tb.thinking }]
325
+ });
326
+ }
327
+ }
328
+ if (m.toolUses && m.toolUses.length > 0) {
329
+ const assistantText = typeof m.content === "string" ? m.content : contentToText(m.content);
330
+ if (assistantText) {
331
+ result.push({
332
+ role: "assistant",
333
+ content: assistantText
334
+ });
335
+ }
336
+ for (const tu of m.toolUses) {
337
+ result.push({
338
+ type: "function_call",
339
+ name: tu.toolName,
340
+ call_id: tu.toolUseId,
341
+ arguments: JSON.stringify(tu.arguments)
342
+ });
343
+ }
344
+ } else if (m.toolResults && m.toolResults.length > 0) {
345
+ for (const tr of m.toolResults) {
346
+ result.push({
347
+ type: "function_call_output",
348
+ call_id: tr.toolUseId,
349
+ output: toolOutputForResponses(tr)
350
+ });
351
+ }
352
+ } else if (m.role === "assistant") {
353
+ result.push({
354
+ role: "assistant",
355
+ content: typeof m.content === "string" ? m.content : contentToText(m.content)
356
+ });
357
+ } else {
358
+ result.push({
359
+ role: m.role,
360
+ content: userContentsFor(m.content)
361
+ });
362
+ }
363
+ }
364
+ return result;
365
+ }
366
+ function containsContextLengthError(msg) {
367
+ return /context_length_exceeded/i.test(msg) || /maximum\scontext\slength/i.test(msg) || /prompts?\s+too\s+long/i.test(msg);
368
+ }
369
+ var OpenAICompatClient = class {
370
+ client;
371
+ model;
372
+ systemPrompt;
373
+ maxOutputTokens;
374
+ constructor(config, systemPrompt) {
375
+ const apiKey = resolveAPIKey(config);
376
+ if (!apiKey) {
377
+ throw new AuthenticationError(
378
+ "OpenAI API key not found. Set OPENAI_API_KEY in .swifty/config.y(a)ml, or via OPENAI_API_KEY env variable."
379
+ );
380
+ }
381
+ this.client = new OpenAI({ apiKey, baseURL: config.base_url });
382
+ this.model = config.model;
383
+ this.systemPrompt = systemPrompt;
384
+ this.maxOutputTokens = getMaxOutputTokens(config);
385
+ }
386
+ setSystemPrompt(prompt) {
387
+ this.systemPrompt = prompt;
388
+ }
389
+ setMaxOutputTokens(maxTokens) {
390
+ this.maxOutputTokens = maxTokens;
391
+ }
392
+ async *stream(conversation, toolSchemas, abortSignal) {
393
+ const messages = [
394
+ {
395
+ role: "system",
396
+ content: this.systemPrompt
397
+ },
398
+ ...buildChatCompletionMessages(ensureToolPairing(conversation.getMessages()))
399
+ ];
400
+ const tools = toolSchemas.map((ts) => ({
401
+ // name: ts.name,
402
+ // description: ts.description,
403
+ type: "function",
404
+ function: {
405
+ name: ts.name,
406
+ description: ts.description,
407
+ parameters: ts.input_schema,
408
+ strict: false
409
+ }
410
+ }));
411
+ const params = {
412
+ model: this.model,
413
+ messages,
414
+ stream: true,
415
+ stream_options: { include_usage: true },
416
+ max_tokens: this.maxOutputTokens,
417
+ ...tools.length > 0 ? { tools } : {}
418
+ };
419
+ let inputTokens = 0;
420
+ let outputTokens = 0;
421
+ let cacheReadInputTokens = 0;
422
+ const cacheCreationInputTokens = 0;
423
+ try {
424
+ const stream = await this.client.chat.completions.create(params, {
425
+ ...abortSignal ? { signal: abortSignal } : {}
426
+ });
427
+ const toolCalls = /* @__PURE__ */ new Map();
428
+ let finishReason = null;
429
+ let reasoningAccumulate = "";
430
+ for await (const chunk of stream) {
431
+ if (chunk.usage) {
432
+ outputTokens = chunk.usage.completion_tokens ?? 0;
433
+ cacheReadInputTokens = chunk.usage.prompt_tokens_details?.cached_tokens ?? 0;
434
+ inputTokens = Math.max(0, (chunk.usage.prompt_tokens ?? 0) - cacheReadInputTokens);
435
+ }
436
+ if (chunk.choices.length === 0) {
437
+ continue;
438
+ }
439
+ const delta = chunk.choices[0].delta;
440
+ if (delta.content) {
441
+ yield { type: "text_delta", text: delta.content };
442
+ }
443
+ const reasoningContent = strArg(asRecord(delta), "reasoning_content");
444
+ if (reasoningContent) {
445
+ reasoningAccumulate += reasoningContent;
446
+ yield { type: "thinking_delta", text: reasoningContent };
447
+ }
448
+ if (delta.tool_calls) {
449
+ for (const tc of delta.tool_calls) {
450
+ if (!toolCalls.has(tc.index)) {
451
+ toolCalls.set(tc.index, {
452
+ id: tc.id ?? "",
453
+ name: tc.function?.name ?? "",
454
+ args: ""
455
+ });
456
+ if (tc.id) {
457
+ yield {
458
+ type: "tool_call_start",
459
+ toolName: tc.function?.name ?? "",
460
+ toolId: tc.id ?? ""
461
+ };
462
+ }
463
+ }
464
+ const existing = toolCalls.get(tc.index);
465
+ if (existing) {
466
+ if (tc.id) {
467
+ existing.id = tc.id;
468
+ }
469
+ if (tc.function?.name) {
470
+ existing.name = tc.function.name;
471
+ }
472
+ if (tc.function?.arguments) {
473
+ existing.args += tc.function.arguments;
474
+ yield {
475
+ type: "tool_call_delta",
476
+ text: tc.function.arguments
477
+ };
478
+ }
479
+ }
480
+ }
481
+ }
482
+ if (chunk.choices[0].finish_reason) {
483
+ finishReason = chunk.choices[0].finish_reason;
484
+ if (reasoningAccumulate) {
485
+ yield {
486
+ type: "thinking_complete",
487
+ thinking: reasoningAccumulate,
488
+ signature: ""
489
+ };
490
+ reasoningAccumulate = "";
491
+ }
492
+ for (const tu of toolCalls.values()) {
493
+ let args = {};
494
+ const jsonArgs = tu.args;
495
+ if (jsonArgs) {
496
+ try {
497
+ const parsed = JSON.parse(jsonArgs);
498
+ args = isRecord(parsed) ? asRecord(parsed) : {};
499
+ } catch (err) {
500
+ log.error({ err }, "llm operation failed");
501
+ args = {};
502
+ }
503
+ yield {
504
+ type: "tool_call_complete",
505
+ toolName: tu.name,
506
+ toolId: tu.id,
507
+ arguments: args
508
+ };
509
+ }
510
+ }
511
+ }
512
+ }
513
+ let stopReason;
514
+ if (finishReason === "length") {
515
+ stopReason = "max_tokens";
516
+ } else if (finishReason === "tool_calls" || toolCalls.size > 0) {
517
+ stopReason = "tool_use";
518
+ } else {
519
+ stopReason = "end_turn";
520
+ }
521
+ yield {
522
+ type: "stream_end",
523
+ stopReason,
524
+ usage: {
525
+ inputTokens,
526
+ outputTokens,
527
+ cacheReadInputTokens,
528
+ cacheCreationInputTokens
529
+ }
530
+ };
531
+ } catch (err) {
532
+ log.error({ err }, "llm operation failed");
533
+ throw classifyOpenAIError(err);
534
+ }
535
+ }
536
+ };
537
+ function classifyOpenAIError(err) {
538
+ if (err instanceof OpenAI.APIError) {
539
+ if (err.status === 413 /* PromptTooLong */ || err.status === 400 /* BadRequest */ && containsContextLengthError(err.message)) {
540
+ return new ContextTooLongError(`Context Too Long: ${err.message}`);
541
+ }
542
+ if (err.status === 401 /* InvalidAPIKey */) {
543
+ return new AuthenticationError(`Invalid API key: ${err.message}`);
544
+ }
545
+ if (err.status === 429 /* RateLimitError */) {
546
+ return new RateLimitError(`Rate limit error, please wait.`);
547
+ }
548
+ return new LLMError(`OpenAI API error (${asString(err.status)}): ${err.message}`);
549
+ }
550
+ return new NetworkError(`Network error: ${err instanceof Error ? err.message : asString(err)}`);
551
+ }
552
+ function buildChatCompletionMessages(messages) {
553
+ const params = [];
554
+ for (const m of messages) {
555
+ const reasoning = m.thinkingBlocks?.map((tb) => tb.thinking).join("") ?? "";
556
+ const assistantText = typeof m.content === "string" ? m.content : contentToText(m.content);
557
+ if (m.toolUses && m.toolUses.length > 0) {
558
+ params.push({
559
+ role: "assistant",
560
+ content: assistantText || null,
561
+ tool_calls: m.toolUses.map((tu) => ({
562
+ id: tu.toolUseId,
563
+ type: "function",
564
+ function: {
565
+ name: tu.toolName,
566
+ arguments: JSON.stringify(tu.arguments)
567
+ },
568
+ ...reasoning ? {
569
+ reasoning_content: reasoning
570
+ } : {}
571
+ }))
572
+ });
573
+ } else if (m.toolResults && m.toolResults.length > 0) {
574
+ const pendingRichParts = [];
575
+ for (const tr of m.toolResults) {
576
+ params.push({
577
+ role: "tool",
578
+ tool_call_id: tr.toolUseId,
579
+ content: tr.content
580
+ });
581
+ pendingRichParts.push(...collectRichParts(tr));
582
+ }
583
+ if (pendingRichParts.length > 0) {
584
+ params.push({
585
+ role: "user",
586
+ content: pendingRichParts
587
+ });
588
+ }
589
+ } else if (m.role === "assistant") {
590
+ params.push({
591
+ role: "assistant",
592
+ content: assistantText,
593
+ ...reasoning ? {
594
+ reasoning_content: reasoning
595
+ } : {}
596
+ });
597
+ } else if (m.role === "system") {
598
+ params.push({
599
+ role: "system",
600
+ content: typeof m.content === "string" ? m.content : contentToText(m.content)
601
+ });
602
+ } else {
603
+ params.push({
604
+ role: "user",
605
+ content: userPartsFor(m.content)
606
+ });
607
+ }
608
+ }
609
+ return params;
610
+ }
611
+
612
+ export {
613
+ OpenAIClient,
614
+ buildOpenAIInput,
615
+ OpenAICompatClient,
616
+ buildChatCompletionMessages
617
+ };