@yourgpt/llm-sdk 2.5.0 → 2.5.1-beta.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 (59) hide show
  1. package/dist/adapters/index.d.mts +4 -4
  2. package/dist/adapters/index.d.ts +4 -4
  3. package/dist/adapters/index.js +156 -13
  4. package/dist/adapters/index.mjs +156 -13
  5. package/dist/base-C58Dsr9p.d.ts +259 -0
  6. package/dist/base-tNgbBaSo.d.mts +259 -0
  7. package/dist/fallback/index.d.mts +4 -4
  8. package/dist/fallback/index.d.ts +4 -4
  9. package/dist/index.d.mts +8 -7
  10. package/dist/index.d.ts +8 -7
  11. package/dist/index.js +12 -0
  12. package/dist/index.mjs +12 -0
  13. package/dist/providers/anthropic/index.d.mts +3 -3
  14. package/dist/providers/anthropic/index.d.ts +3 -3
  15. package/dist/providers/anthropic/index.js +271 -195
  16. package/dist/providers/anthropic/index.mjs +271 -195
  17. package/dist/providers/azure/index.d.mts +3 -3
  18. package/dist/providers/azure/index.d.ts +3 -3
  19. package/dist/providers/azure/index.js +49 -1
  20. package/dist/providers/azure/index.mjs +49 -1
  21. package/dist/providers/fireworks/index.d.mts +1 -1
  22. package/dist/providers/fireworks/index.d.ts +1 -1
  23. package/dist/providers/fireworks/index.js +56 -0
  24. package/dist/providers/fireworks/index.mjs +56 -0
  25. package/dist/providers/google/index.d.mts +3 -3
  26. package/dist/providers/google/index.d.ts +3 -3
  27. package/dist/providers/google/index.js +252 -205
  28. package/dist/providers/google/index.mjs +252 -205
  29. package/dist/providers/ollama/index.d.mts +4 -4
  30. package/dist/providers/ollama/index.d.ts +4 -4
  31. package/dist/providers/ollama/index.js +10 -2
  32. package/dist/providers/ollama/index.mjs +10 -2
  33. package/dist/providers/openai/index.d.mts +3 -3
  34. package/dist/providers/openai/index.d.ts +3 -3
  35. package/dist/providers/openai/index.js +267 -214
  36. package/dist/providers/openai/index.mjs +267 -214
  37. package/dist/providers/openrouter/index.d.mts +3 -3
  38. package/dist/providers/openrouter/index.d.ts +3 -3
  39. package/dist/providers/openrouter/index.js +257 -204
  40. package/dist/providers/openrouter/index.mjs +257 -204
  41. package/dist/providers/togetherai/index.d.mts +3 -3
  42. package/dist/providers/togetherai/index.d.ts +3 -3
  43. package/dist/providers/togetherai/index.js +257 -204
  44. package/dist/providers/togetherai/index.mjs +257 -204
  45. package/dist/providers/xai/index.d.mts +3 -3
  46. package/dist/providers/xai/index.d.ts +3 -3
  47. package/dist/providers/xai/index.js +256 -208
  48. package/dist/providers/xai/index.mjs +256 -208
  49. package/dist/{types-D4YfrQJR.d.mts → types-B6dhnguR.d.mts} +1 -1
  50. package/dist/{types-DRqxMIjF.d.mts → types-BQ31QIsA.d.ts} +2 -1
  51. package/dist/{types-BctsnC3g.d.ts → types-BSSiJW2o.d.mts} +2 -1
  52. package/dist/{base-D-U61JaB.d.mts → types-BkQCSiIt.d.mts} +388 -213
  53. package/dist/{base-iGi9Va6Z.d.ts → types-BkQCSiIt.d.ts} +388 -213
  54. package/dist/{types-38yolWJn.d.ts → types-CCxPmkmK.d.ts} +1 -1
  55. package/dist/yourgpt/index.d.mts +1 -1
  56. package/dist/yourgpt/index.d.ts +1 -1
  57. package/package.json +1 -1
  58. package/dist/types-CR8mi9I0.d.mts +0 -417
  59. package/dist/types-CR8mi9I0.d.ts +0 -417
@@ -1,3 +1,232 @@
1
+ // src/adapters/base.ts
2
+ function stringifyForDebug(value) {
3
+ return JSON.stringify(
4
+ value,
5
+ (_key, currentValue) => {
6
+ if (typeof currentValue === "bigint") {
7
+ return currentValue.toString();
8
+ }
9
+ if (currentValue instanceof Error) {
10
+ return {
11
+ name: currentValue.name,
12
+ message: currentValue.message,
13
+ stack: currentValue.stack
14
+ };
15
+ }
16
+ return currentValue;
17
+ },
18
+ 2
19
+ );
20
+ }
21
+ function logProviderPayload(provider, label, payload, enabled) {
22
+ if (!enabled) {
23
+ return;
24
+ }
25
+ if (label.toLowerCase().includes("stream ")) {
26
+ return;
27
+ }
28
+ try {
29
+ console.log(
30
+ `[llm-sdk:${provider}] ${label}
31
+ ${stringifyForDebug(payload)}`
32
+ );
33
+ } catch (error) {
34
+ console.log(
35
+ `[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
36
+ error
37
+ );
38
+ }
39
+ }
40
+ function parameterToJsonSchema(param) {
41
+ const schema = {
42
+ type: param.type
43
+ };
44
+ if (param.description) {
45
+ schema.description = param.description;
46
+ }
47
+ if (param.enum) {
48
+ schema.enum = param.enum;
49
+ }
50
+ if (param.type === "array" && param.items) {
51
+ schema.items = parameterToJsonSchema(
52
+ param.items
53
+ );
54
+ }
55
+ if (param.type === "object" && param.properties) {
56
+ schema.properties = Object.fromEntries(
57
+ Object.entries(param.properties).map(([key, prop]) => [
58
+ key,
59
+ parameterToJsonSchema(
60
+ prop
61
+ )
62
+ ])
63
+ );
64
+ schema.additionalProperties = false;
65
+ }
66
+ return schema;
67
+ }
68
+ function normalizeObjectJsonSchema(schema) {
69
+ if (!schema || typeof schema !== "object") {
70
+ return {
71
+ type: "object",
72
+ properties: {},
73
+ required: [],
74
+ additionalProperties: false
75
+ };
76
+ }
77
+ const normalized = { ...schema };
78
+ const type = normalized.type;
79
+ if (type === "object") {
80
+ const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
81
+ normalized.properties = Object.fromEntries(
82
+ Object.entries(properties).map(([key, value]) => [
83
+ key,
84
+ normalizeObjectJsonSchema(value)
85
+ ])
86
+ );
87
+ const propertyKeys = Object.keys(properties);
88
+ const required = Array.isArray(normalized.required) ? normalized.required.filter(
89
+ (value) => typeof value === "string"
90
+ ) : [];
91
+ normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
92
+ if (normalized.additionalProperties === void 0) {
93
+ normalized.additionalProperties = false;
94
+ }
95
+ } else if (type === "array" && normalized.items && typeof normalized.items === "object") {
96
+ normalized.items = normalizeObjectJsonSchema(
97
+ normalized.items
98
+ );
99
+ }
100
+ return normalized;
101
+ }
102
+ function isOpenAIReasoningModel(modelId) {
103
+ if (!modelId) return false;
104
+ return /^(o1|o3|o4|gpt-5)/i.test(modelId);
105
+ }
106
+ function buildOpenAITokenParams(modelId, maxTokens, temperature) {
107
+ if (isOpenAIReasoningModel(modelId)) {
108
+ return { max_completion_tokens: maxTokens };
109
+ }
110
+ return { max_tokens: maxTokens, temperature };
111
+ }
112
+ function toOpenAIResponseFormat(rf) {
113
+ if (!rf) return void 0;
114
+ if (rf.type === "json_object") return { type: "json_object" };
115
+ return {
116
+ type: "json_schema",
117
+ json_schema: {
118
+ name: rf.json_schema.name,
119
+ schema: normalizeObjectJsonSchema(rf.json_schema.schema),
120
+ strict: rf.json_schema.strict ?? true
121
+ }
122
+ };
123
+ }
124
+ function toOpenAIResponsesTextFormat(rf) {
125
+ if (!rf || rf.type !== "json_schema") return void 0;
126
+ return {
127
+ type: "json_schema",
128
+ name: rf.json_schema.name,
129
+ schema: normalizeObjectJsonSchema(rf.json_schema.schema),
130
+ strict: rf.json_schema.strict ?? true
131
+ };
132
+ }
133
+ function formatTools(actions) {
134
+ return actions.map((action) => ({
135
+ type: "function",
136
+ function: {
137
+ name: action.name,
138
+ description: action.description,
139
+ parameters: {
140
+ type: "object",
141
+ properties: action.parameters ? Object.fromEntries(
142
+ Object.entries(action.parameters).map(([key, param]) => [
143
+ key,
144
+ parameterToJsonSchema(param)
145
+ ])
146
+ ) : {},
147
+ required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
148
+ additionalProperties: false
149
+ }
150
+ }
151
+ }));
152
+ }
153
+ function hasImageAttachments(message) {
154
+ const attachments = message.metadata?.attachments;
155
+ return attachments?.some((a) => a.type === "image") ?? false;
156
+ }
157
+ function attachmentToOpenAIImage(attachment) {
158
+ if (attachment.type !== "image") return null;
159
+ let imageUrl;
160
+ if (attachment.url) {
161
+ imageUrl = attachment.url;
162
+ } else if (attachment.data) {
163
+ imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
164
+ } else {
165
+ return null;
166
+ }
167
+ return {
168
+ type: "image_url",
169
+ image_url: {
170
+ url: imageUrl,
171
+ detail: "auto"
172
+ }
173
+ };
174
+ }
175
+ function messageToOpenAIContent(message) {
176
+ const attachments = message.metadata?.attachments;
177
+ const content = message.content ?? "";
178
+ if (!hasImageAttachments(message)) {
179
+ return content;
180
+ }
181
+ const blocks = [];
182
+ if (content) {
183
+ blocks.push({ type: "text", text: content });
184
+ }
185
+ if (attachments) {
186
+ for (const attachment of attachments) {
187
+ const imageBlock = attachmentToOpenAIImage(attachment);
188
+ if (imageBlock) {
189
+ blocks.push(imageBlock);
190
+ }
191
+ }
192
+ }
193
+ return blocks;
194
+ }
195
+ function formatMessagesForOpenAI(messages, systemPrompt) {
196
+ const formatted = [];
197
+ if (systemPrompt) {
198
+ formatted.push({ role: "system", content: systemPrompt });
199
+ }
200
+ for (const msg of messages) {
201
+ if (msg.role === "system") {
202
+ formatted.push({ role: "system", content: msg.content ?? "" });
203
+ } else if (msg.role === "user") {
204
+ formatted.push({
205
+ role: "user",
206
+ content: messageToOpenAIContent(msg)
207
+ });
208
+ } else if (msg.role === "assistant") {
209
+ const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
210
+ const assistantMsg = {
211
+ role: "assistant",
212
+ // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
213
+ content: hasToolCalls ? msg.content || null : msg.content
214
+ };
215
+ if (hasToolCalls) {
216
+ assistantMsg.tool_calls = msg.tool_calls;
217
+ }
218
+ formatted.push(assistantMsg);
219
+ } else if (msg.role === "tool" && msg.tool_call_id) {
220
+ formatted.push({
221
+ role: "tool",
222
+ content: msg.content ?? "",
223
+ tool_call_id: msg.tool_call_id
224
+ });
225
+ }
226
+ }
227
+ return formatted;
228
+ }
229
+
1
230
  // src/providers/togetherai/provider.ts
2
231
  function togetherai(modelId, options = {}) {
3
232
  const apiKey = options.apiKey ?? process.env.TOGETHER_API_KEY;
@@ -40,6 +269,10 @@ function togetherai(modelId, options = {}) {
40
269
  if (params.tools) {
41
270
  requestBody.tools = params.tools;
42
271
  }
272
+ const responseFormat = toOpenAIResponseFormat(params.responseFormat);
273
+ if (responseFormat) {
274
+ requestBody.response_format = responseFormat;
275
+ }
43
276
  const response = await client2.chat.completions.create(requestBody);
44
277
  const choice = response.choices[0];
45
278
  const message = choice.message;
@@ -75,6 +308,10 @@ function togetherai(modelId, options = {}) {
75
308
  if (params.tools) {
76
309
  requestBody.tools = params.tools;
77
310
  }
311
+ const responseFormat = toOpenAIResponseFormat(params.responseFormat);
312
+ if (responseFormat) {
313
+ requestBody.response_format = responseFormat;
314
+ }
78
315
  const stream = await client2.chat.completions.create(requestBody);
79
316
  const toolCallMap = /* @__PURE__ */ new Map();
80
317
  let totalPromptTokens = 0;
@@ -213,204 +450,6 @@ function generateToolCallId() {
213
450
  return generateId("call");
214
451
  }
215
452
 
216
- // src/adapters/base.ts
217
- function stringifyForDebug(value) {
218
- return JSON.stringify(
219
- value,
220
- (_key, currentValue) => {
221
- if (typeof currentValue === "bigint") {
222
- return currentValue.toString();
223
- }
224
- if (currentValue instanceof Error) {
225
- return {
226
- name: currentValue.name,
227
- message: currentValue.message,
228
- stack: currentValue.stack
229
- };
230
- }
231
- return currentValue;
232
- },
233
- 2
234
- );
235
- }
236
- function logProviderPayload(provider, label, payload, enabled) {
237
- if (!enabled) {
238
- return;
239
- }
240
- if (label.toLowerCase().includes("stream ")) {
241
- return;
242
- }
243
- try {
244
- console.log(
245
- `[llm-sdk:${provider}] ${label}
246
- ${stringifyForDebug(payload)}`
247
- );
248
- } catch (error) {
249
- console.log(
250
- `[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
251
- error
252
- );
253
- }
254
- }
255
- function parameterToJsonSchema(param) {
256
- const schema = {
257
- type: param.type
258
- };
259
- if (param.description) {
260
- schema.description = param.description;
261
- }
262
- if (param.enum) {
263
- schema.enum = param.enum;
264
- }
265
- if (param.type === "array" && param.items) {
266
- schema.items = parameterToJsonSchema(
267
- param.items
268
- );
269
- }
270
- if (param.type === "object" && param.properties) {
271
- schema.properties = Object.fromEntries(
272
- Object.entries(param.properties).map(([key, prop]) => [
273
- key,
274
- parameterToJsonSchema(
275
- prop
276
- )
277
- ])
278
- );
279
- schema.additionalProperties = false;
280
- }
281
- return schema;
282
- }
283
- function normalizeObjectJsonSchema(schema) {
284
- if (!schema || typeof schema !== "object") {
285
- return {
286
- type: "object",
287
- properties: {},
288
- required: [],
289
- additionalProperties: false
290
- };
291
- }
292
- const normalized = { ...schema };
293
- const type = normalized.type;
294
- if (type === "object") {
295
- const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
296
- normalized.properties = Object.fromEntries(
297
- Object.entries(properties).map(([key, value]) => [
298
- key,
299
- normalizeObjectJsonSchema(value)
300
- ])
301
- );
302
- const propertyKeys = Object.keys(properties);
303
- const required = Array.isArray(normalized.required) ? normalized.required.filter(
304
- (value) => typeof value === "string"
305
- ) : [];
306
- normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
307
- if (normalized.additionalProperties === void 0) {
308
- normalized.additionalProperties = false;
309
- }
310
- } else if (type === "array" && normalized.items && typeof normalized.items === "object") {
311
- normalized.items = normalizeObjectJsonSchema(
312
- normalized.items
313
- );
314
- }
315
- return normalized;
316
- }
317
- function formatTools(actions) {
318
- return actions.map((action) => ({
319
- type: "function",
320
- function: {
321
- name: action.name,
322
- description: action.description,
323
- parameters: {
324
- type: "object",
325
- properties: action.parameters ? Object.fromEntries(
326
- Object.entries(action.parameters).map(([key, param]) => [
327
- key,
328
- parameterToJsonSchema(param)
329
- ])
330
- ) : {},
331
- required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
332
- additionalProperties: false
333
- }
334
- }
335
- }));
336
- }
337
- function hasImageAttachments(message) {
338
- const attachments = message.metadata?.attachments;
339
- return attachments?.some((a) => a.type === "image") ?? false;
340
- }
341
- function attachmentToOpenAIImage(attachment) {
342
- if (attachment.type !== "image") return null;
343
- let imageUrl;
344
- if (attachment.url) {
345
- imageUrl = attachment.url;
346
- } else if (attachment.data) {
347
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
348
- } else {
349
- return null;
350
- }
351
- return {
352
- type: "image_url",
353
- image_url: {
354
- url: imageUrl,
355
- detail: "auto"
356
- }
357
- };
358
- }
359
- function messageToOpenAIContent(message) {
360
- const attachments = message.metadata?.attachments;
361
- const content = message.content ?? "";
362
- if (!hasImageAttachments(message)) {
363
- return content;
364
- }
365
- const blocks = [];
366
- if (content) {
367
- blocks.push({ type: "text", text: content });
368
- }
369
- if (attachments) {
370
- for (const attachment of attachments) {
371
- const imageBlock = attachmentToOpenAIImage(attachment);
372
- if (imageBlock) {
373
- blocks.push(imageBlock);
374
- }
375
- }
376
- }
377
- return blocks;
378
- }
379
- function formatMessagesForOpenAI(messages, systemPrompt) {
380
- const formatted = [];
381
- if (systemPrompt) {
382
- formatted.push({ role: "system", content: systemPrompt });
383
- }
384
- for (const msg of messages) {
385
- if (msg.role === "system") {
386
- formatted.push({ role: "system", content: msg.content ?? "" });
387
- } else if (msg.role === "user") {
388
- formatted.push({
389
- role: "user",
390
- content: messageToOpenAIContent(msg)
391
- });
392
- } else if (msg.role === "assistant") {
393
- const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
394
- const assistantMsg = {
395
- role: "assistant",
396
- // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
397
- content: hasToolCalls ? msg.content || null : msg.content
398
- };
399
- if (hasToolCalls) {
400
- assistantMsg.tool_calls = msg.tool_calls;
401
- }
402
- formatted.push(assistantMsg);
403
- } else if (msg.role === "tool" && msg.tool_call_id) {
404
- formatted.push({
405
- role: "tool",
406
- content: msg.content ?? "",
407
- tool_call_id: msg.tool_call_id
408
- });
409
- }
410
- }
411
- return formatted;
412
- }
413
-
414
453
  // src/adapters/openai.ts
415
454
  var OpenAIAdapter = class _OpenAIAdapter {
416
455
  constructor(config) {
@@ -525,6 +564,9 @@ var OpenAIAdapter = class _OpenAIAdapter {
525
564
  async completeWithResponses(request) {
526
565
  const client = await this.getClient();
527
566
  const openaiToolOptions = request.providerToolOptions?.openai;
567
+ const responsesTextFormat = toOpenAIResponsesTextFormat(
568
+ request.config?.responseFormat
569
+ );
528
570
  const payload = {
529
571
  model: request.config?.model || this.model,
530
572
  instructions: request.systemPrompt,
@@ -534,6 +576,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
534
576
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
535
577
  temperature: request.config?.temperature ?? this.config.temperature,
536
578
  max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
579
+ ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
537
580
  stream: false
538
581
  };
539
582
  logProviderPayload("openai", "request payload", payload, request.debug);
@@ -655,14 +698,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
655
698
  name: openaiToolOptions.toolChoice.name
656
699
  }
657
700
  } : openaiToolOptions?.toolChoice;
701
+ const modelIdForPayload = request.config?.model || this.model;
658
702
  const payload = {
659
- model: request.config?.model || this.model,
703
+ model: modelIdForPayload,
660
704
  messages,
661
705
  tools: tools.length > 0 ? tools : void 0,
662
706
  tool_choice: tools.length > 0 ? toolChoice : void 0,
663
707
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
664
- temperature: request.config?.temperature ?? this.config.temperature,
665
- max_tokens: request.config?.maxTokens ?? this.config.maxTokens,
708
+ ...buildOpenAITokenParams(
709
+ modelIdForPayload,
710
+ request.config?.maxTokens ?? this.config.maxTokens,
711
+ request.config?.temperature ?? this.config.temperature
712
+ ),
713
+ response_format: toOpenAIResponseFormat(request.config?.responseFormat),
666
714
  stream: true,
667
715
  stream_options: { include_usage: true }
668
716
  };
@@ -804,14 +852,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
804
852
  name: openaiToolOptions.toolChoice.name
805
853
  }
806
854
  } : openaiToolOptions?.toolChoice;
855
+ const modelIdForCompletePayload = request.config?.model || this.model;
807
856
  const payload = {
808
- model: request.config?.model || this.model,
857
+ model: modelIdForCompletePayload,
809
858
  messages,
810
859
  tools: tools.length > 0 ? tools : void 0,
811
860
  tool_choice: tools.length > 0 ? toolChoice : void 0,
812
861
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
813
- temperature: request.config?.temperature ?? this.config.temperature,
814
- max_tokens: request.config?.maxTokens ?? this.config.maxTokens,
862
+ ...buildOpenAITokenParams(
863
+ modelIdForCompletePayload,
864
+ request.config?.maxTokens ?? this.config.maxTokens,
865
+ request.config?.temperature ?? this.config.temperature
866
+ ),
867
+ response_format: toOpenAIResponseFormat(request.config?.responseFormat),
815
868
  stream: false
816
869
  };
817
870
  logProviderPayload("openai", "request payload", payload, request.debug);
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-CR8mi9I0.mjs';
2
- import { X as XAIProviderConfig, A as AIProvider } from '../../types-DRqxMIjF.mjs';
1
+ import { L as LanguageModel } from '../../types-BkQCSiIt.mjs';
2
+ import { X as XAIProviderConfig, A as AIProvider } from '../../types-BSSiJW2o.mjs';
3
3
  import 'zod';
4
- import '../../base-D-U61JaB.mjs';
4
+ import '../../base-tNgbBaSo.mjs';
5
5
 
6
6
  /**
7
7
  * xAI Provider - Modern Pattern
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-CR8mi9I0.js';
2
- import { X as XAIProviderConfig, A as AIProvider } from '../../types-BctsnC3g.js';
1
+ import { L as LanguageModel } from '../../types-BkQCSiIt.js';
2
+ import { X as XAIProviderConfig, A as AIProvider } from '../../types-BQ31QIsA.js';
3
3
  import 'zod';
4
- import '../../base-iGi9Va6Z.js';
4
+ import '../../base-C58Dsr9p.js';
5
5
 
6
6
  /**
7
7
  * xAI Provider - Modern Pattern