@providerprotocol/ai 0.0.4 → 0.0.6
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.
- package/README.md +19 -0
- package/dist/anthropic/index.js +1 -24
- package/dist/anthropic/index.js.map +1 -1
- package/dist/google/index.js +3 -46
- package/dist/google/index.js.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/ollama/index.js +13 -44
- package/dist/ollama/index.js.map +1 -1
- package/dist/openai/index.d.ts +46 -27
- package/dist/openai/index.js +2 -116
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.d.ts +23 -10
- package/dist/openrouter/index.js +2 -85
- package/dist/openrouter/index.js.map +1 -1
- package/dist/xai/index.d.ts +306 -0
- package/dist/xai/index.js +1696 -0
- package/dist/xai/index.js.map +1 -0
- package/package.json +9 -1
- package/src/core/llm.ts +6 -1
- package/src/openai/index.ts +2 -1
- package/src/openrouter/index.ts +2 -1
- package/src/providers/anthropic/transform.ts +7 -29
- package/src/providers/google/transform.ts +9 -49
- package/src/providers/ollama/transform.ts +27 -49
- package/src/providers/openai/index.ts +12 -8
- package/src/providers/openai/llm.completions.ts +9 -9
- package/src/providers/openai/llm.responses.ts +9 -9
- package/src/providers/openai/transform.completions.ts +12 -79
- package/src/providers/openai/transform.responses.ts +12 -54
- package/src/providers/openai/types.ts +54 -31
- package/src/providers/openrouter/index.ts +12 -8
- package/src/providers/openrouter/llm.completions.ts +9 -9
- package/src/providers/openrouter/llm.responses.ts +9 -9
- package/src/providers/openrouter/transform.completions.ts +12 -79
- package/src/providers/openrouter/transform.responses.ts +12 -25
- package/src/providers/openrouter/types.ts +22 -28
- package/src/providers/xai/index.ts +223 -0
- package/src/providers/xai/llm.completions.ts +201 -0
- package/src/providers/xai/llm.messages.ts +195 -0
- package/src/providers/xai/llm.responses.ts +211 -0
- package/src/providers/xai/transform.completions.ts +565 -0
- package/src/providers/xai/transform.messages.ts +448 -0
- package/src/providers/xai/transform.responses.ts +678 -0
- package/src/providers/xai/types.ts +938 -0
- package/src/xai/index.ts +41 -0
|
@@ -0,0 +1,1696 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AssistantMessage,
|
|
3
|
+
isAssistantMessage,
|
|
4
|
+
isToolResultMessage,
|
|
5
|
+
isUserMessage
|
|
6
|
+
} from "../chunk-QUUX4G7U.js";
|
|
7
|
+
import {
|
|
8
|
+
parseSSEStream
|
|
9
|
+
} from "../chunk-X5G4EHL7.js";
|
|
10
|
+
import {
|
|
11
|
+
UPPError,
|
|
12
|
+
doFetch,
|
|
13
|
+
doStreamFetch,
|
|
14
|
+
normalizeHttpError,
|
|
15
|
+
resolveApiKey
|
|
16
|
+
} from "../chunk-SUNYWHTH.js";
|
|
17
|
+
|
|
18
|
+
// src/providers/xai/transform.completions.ts
|
|
19
|
+
function transformRequest(request, modelId) {
|
|
20
|
+
const params = request.params ?? {};
|
|
21
|
+
const xaiRequest = {
|
|
22
|
+
...params,
|
|
23
|
+
model: modelId,
|
|
24
|
+
messages: transformMessages(request.messages, request.system)
|
|
25
|
+
};
|
|
26
|
+
if (request.tools && request.tools.length > 0) {
|
|
27
|
+
xaiRequest.tools = request.tools.map(transformTool);
|
|
28
|
+
}
|
|
29
|
+
if (request.structure) {
|
|
30
|
+
const schema = {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: request.structure.properties,
|
|
33
|
+
required: request.structure.required,
|
|
34
|
+
...request.structure.additionalProperties !== void 0 ? { additionalProperties: request.structure.additionalProperties } : { additionalProperties: false }
|
|
35
|
+
};
|
|
36
|
+
if (request.structure.description) {
|
|
37
|
+
schema.description = request.structure.description;
|
|
38
|
+
}
|
|
39
|
+
xaiRequest.response_format = {
|
|
40
|
+
type: "json_schema",
|
|
41
|
+
json_schema: {
|
|
42
|
+
name: "json_response",
|
|
43
|
+
description: request.structure.description,
|
|
44
|
+
schema,
|
|
45
|
+
strict: true
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return xaiRequest;
|
|
50
|
+
}
|
|
51
|
+
function transformMessages(messages, system) {
|
|
52
|
+
const result = [];
|
|
53
|
+
if (system) {
|
|
54
|
+
result.push({
|
|
55
|
+
role: "system",
|
|
56
|
+
content: system
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
for (const message of messages) {
|
|
60
|
+
if (isToolResultMessage(message)) {
|
|
61
|
+
const toolMessages = transformToolResults(message);
|
|
62
|
+
result.push(...toolMessages);
|
|
63
|
+
} else {
|
|
64
|
+
const transformed = transformMessage(message);
|
|
65
|
+
if (transformed) {
|
|
66
|
+
result.push(transformed);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
function filterValidContent(content) {
|
|
73
|
+
return content.filter((c) => c && typeof c.type === "string");
|
|
74
|
+
}
|
|
75
|
+
function transformMessage(message) {
|
|
76
|
+
if (isUserMessage(message)) {
|
|
77
|
+
const validContent = filterValidContent(message.content);
|
|
78
|
+
if (validContent.length === 1 && validContent[0]?.type === "text") {
|
|
79
|
+
return {
|
|
80
|
+
role: "user",
|
|
81
|
+
content: validContent[0].text
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
role: "user",
|
|
86
|
+
content: validContent.map(transformContentBlock)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (isAssistantMessage(message)) {
|
|
90
|
+
const validContent = filterValidContent(message.content);
|
|
91
|
+
const textContent = validContent.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
92
|
+
const hasToolCalls = message.toolCalls && message.toolCalls.length > 0;
|
|
93
|
+
const assistantMessage = {
|
|
94
|
+
role: "assistant",
|
|
95
|
+
// xAI/OpenAI: content should be null when tool_calls are present and there's no text
|
|
96
|
+
content: hasToolCalls && !textContent ? null : textContent
|
|
97
|
+
};
|
|
98
|
+
if (hasToolCalls) {
|
|
99
|
+
assistantMessage.tool_calls = message.toolCalls.map((call) => ({
|
|
100
|
+
id: call.toolCallId,
|
|
101
|
+
type: "function",
|
|
102
|
+
function: {
|
|
103
|
+
name: call.toolName,
|
|
104
|
+
arguments: JSON.stringify(call.arguments)
|
|
105
|
+
}
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
return assistantMessage;
|
|
109
|
+
}
|
|
110
|
+
if (isToolResultMessage(message)) {
|
|
111
|
+
const results = message.results.map((result) => ({
|
|
112
|
+
role: "tool",
|
|
113
|
+
tool_call_id: result.toolCallId,
|
|
114
|
+
content: typeof result.result === "string" ? result.result : JSON.stringify(result.result)
|
|
115
|
+
}));
|
|
116
|
+
return results[0] ?? null;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
function transformToolResults(message) {
|
|
121
|
+
if (!isToolResultMessage(message)) {
|
|
122
|
+
const single = transformMessage(message);
|
|
123
|
+
return single ? [single] : [];
|
|
124
|
+
}
|
|
125
|
+
return message.results.map((result) => ({
|
|
126
|
+
role: "tool",
|
|
127
|
+
tool_call_id: result.toolCallId,
|
|
128
|
+
content: typeof result.result === "string" ? result.result : JSON.stringify(result.result)
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
function transformContentBlock(block) {
|
|
132
|
+
switch (block.type) {
|
|
133
|
+
case "text":
|
|
134
|
+
return { type: "text", text: block.text };
|
|
135
|
+
case "image": {
|
|
136
|
+
const imageBlock = block;
|
|
137
|
+
let url;
|
|
138
|
+
if (imageBlock.source.type === "base64") {
|
|
139
|
+
url = `data:${imageBlock.mimeType};base64,${imageBlock.source.data}`;
|
|
140
|
+
} else if (imageBlock.source.type === "url") {
|
|
141
|
+
url = imageBlock.source.url;
|
|
142
|
+
} else if (imageBlock.source.type === "bytes") {
|
|
143
|
+
const base64 = btoa(
|
|
144
|
+
Array.from(imageBlock.source.data).map((b) => String.fromCharCode(b)).join("")
|
|
145
|
+
);
|
|
146
|
+
url = `data:${imageBlock.mimeType};base64,${base64}`;
|
|
147
|
+
} else {
|
|
148
|
+
throw new Error("Unknown image source type");
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
type: "image_url",
|
|
152
|
+
image_url: { url }
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
default:
|
|
156
|
+
throw new Error(`Unsupported content type: ${block.type}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function transformTool(tool) {
|
|
160
|
+
return {
|
|
161
|
+
type: "function",
|
|
162
|
+
function: {
|
|
163
|
+
name: tool.name,
|
|
164
|
+
description: tool.description,
|
|
165
|
+
parameters: {
|
|
166
|
+
type: "object",
|
|
167
|
+
properties: tool.parameters.properties,
|
|
168
|
+
required: tool.parameters.required,
|
|
169
|
+
...tool.parameters.additionalProperties !== void 0 ? { additionalProperties: tool.parameters.additionalProperties } : {}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function transformResponse(data) {
|
|
175
|
+
const choice = data.choices[0];
|
|
176
|
+
if (!choice) {
|
|
177
|
+
throw new Error("No choices in xAI response");
|
|
178
|
+
}
|
|
179
|
+
const textContent = [];
|
|
180
|
+
let structuredData;
|
|
181
|
+
if (choice.message.content) {
|
|
182
|
+
textContent.push({ type: "text", text: choice.message.content });
|
|
183
|
+
try {
|
|
184
|
+
structuredData = JSON.parse(choice.message.content);
|
|
185
|
+
} catch {
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
let hadRefusal = false;
|
|
189
|
+
if (choice.message.refusal) {
|
|
190
|
+
textContent.push({ type: "text", text: choice.message.refusal });
|
|
191
|
+
hadRefusal = true;
|
|
192
|
+
}
|
|
193
|
+
const toolCalls = [];
|
|
194
|
+
if (choice.message.tool_calls) {
|
|
195
|
+
for (const call of choice.message.tool_calls) {
|
|
196
|
+
let args = {};
|
|
197
|
+
try {
|
|
198
|
+
args = JSON.parse(call.function.arguments);
|
|
199
|
+
} catch {
|
|
200
|
+
}
|
|
201
|
+
toolCalls.push({
|
|
202
|
+
toolCallId: call.id,
|
|
203
|
+
toolName: call.function.name,
|
|
204
|
+
arguments: args
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const message = new AssistantMessage(
|
|
209
|
+
textContent,
|
|
210
|
+
toolCalls.length > 0 ? toolCalls : void 0,
|
|
211
|
+
{
|
|
212
|
+
id: data.id,
|
|
213
|
+
metadata: {
|
|
214
|
+
xai: {
|
|
215
|
+
model: data.model,
|
|
216
|
+
finish_reason: choice.finish_reason,
|
|
217
|
+
system_fingerprint: data.system_fingerprint,
|
|
218
|
+
citations: data.citations,
|
|
219
|
+
inline_citations: data.inline_citations
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
const usage = {
|
|
225
|
+
inputTokens: data.usage.prompt_tokens,
|
|
226
|
+
outputTokens: data.usage.completion_tokens,
|
|
227
|
+
totalTokens: data.usage.total_tokens
|
|
228
|
+
};
|
|
229
|
+
let stopReason = "end_turn";
|
|
230
|
+
switch (choice.finish_reason) {
|
|
231
|
+
case "stop":
|
|
232
|
+
stopReason = "end_turn";
|
|
233
|
+
break;
|
|
234
|
+
case "length":
|
|
235
|
+
stopReason = "max_tokens";
|
|
236
|
+
break;
|
|
237
|
+
case "tool_calls":
|
|
238
|
+
stopReason = "tool_use";
|
|
239
|
+
break;
|
|
240
|
+
case "content_filter":
|
|
241
|
+
stopReason = "content_filter";
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
if (hadRefusal && stopReason !== "content_filter") {
|
|
245
|
+
stopReason = "content_filter";
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
message,
|
|
249
|
+
usage,
|
|
250
|
+
stopReason,
|
|
251
|
+
data: structuredData
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function createStreamState() {
|
|
255
|
+
return {
|
|
256
|
+
id: "",
|
|
257
|
+
model: "",
|
|
258
|
+
text: "",
|
|
259
|
+
toolCalls: /* @__PURE__ */ new Map(),
|
|
260
|
+
finishReason: null,
|
|
261
|
+
inputTokens: 0,
|
|
262
|
+
outputTokens: 0,
|
|
263
|
+
hadRefusal: false
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function transformStreamEvent(chunk, state) {
|
|
267
|
+
const events = [];
|
|
268
|
+
if (chunk.id && !state.id) {
|
|
269
|
+
state.id = chunk.id;
|
|
270
|
+
events.push({ type: "message_start", index: 0, delta: {} });
|
|
271
|
+
}
|
|
272
|
+
if (chunk.model) {
|
|
273
|
+
state.model = chunk.model;
|
|
274
|
+
}
|
|
275
|
+
const choice = chunk.choices[0];
|
|
276
|
+
if (choice) {
|
|
277
|
+
if (choice.delta.content) {
|
|
278
|
+
state.text += choice.delta.content;
|
|
279
|
+
events.push({
|
|
280
|
+
type: "text_delta",
|
|
281
|
+
index: 0,
|
|
282
|
+
delta: { text: choice.delta.content }
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
if (choice.delta.refusal) {
|
|
286
|
+
state.hadRefusal = true;
|
|
287
|
+
state.text += choice.delta.refusal;
|
|
288
|
+
events.push({
|
|
289
|
+
type: "text_delta",
|
|
290
|
+
index: 0,
|
|
291
|
+
delta: { text: choice.delta.refusal }
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
if (choice.delta.tool_calls) {
|
|
295
|
+
for (const toolCallDelta of choice.delta.tool_calls) {
|
|
296
|
+
const index = toolCallDelta.index;
|
|
297
|
+
let toolCall = state.toolCalls.get(index);
|
|
298
|
+
if (!toolCall) {
|
|
299
|
+
toolCall = { id: "", name: "", arguments: "" };
|
|
300
|
+
state.toolCalls.set(index, toolCall);
|
|
301
|
+
}
|
|
302
|
+
if (toolCallDelta.id) {
|
|
303
|
+
toolCall.id = toolCallDelta.id;
|
|
304
|
+
}
|
|
305
|
+
if (toolCallDelta.function?.name) {
|
|
306
|
+
toolCall.name = toolCallDelta.function.name;
|
|
307
|
+
}
|
|
308
|
+
if (toolCallDelta.function?.arguments) {
|
|
309
|
+
toolCall.arguments += toolCallDelta.function.arguments;
|
|
310
|
+
events.push({
|
|
311
|
+
type: "tool_call_delta",
|
|
312
|
+
index,
|
|
313
|
+
delta: {
|
|
314
|
+
toolCallId: toolCall.id,
|
|
315
|
+
toolName: toolCall.name,
|
|
316
|
+
argumentsJson: toolCallDelta.function.arguments
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (choice.finish_reason) {
|
|
323
|
+
state.finishReason = choice.finish_reason;
|
|
324
|
+
events.push({ type: "message_stop", index: 0, delta: {} });
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (chunk.usage) {
|
|
328
|
+
state.inputTokens = chunk.usage.prompt_tokens;
|
|
329
|
+
state.outputTokens = chunk.usage.completion_tokens;
|
|
330
|
+
}
|
|
331
|
+
return events;
|
|
332
|
+
}
|
|
333
|
+
function buildResponseFromState(state) {
|
|
334
|
+
const textContent = [];
|
|
335
|
+
let structuredData;
|
|
336
|
+
if (state.text) {
|
|
337
|
+
textContent.push({ type: "text", text: state.text });
|
|
338
|
+
try {
|
|
339
|
+
structuredData = JSON.parse(state.text);
|
|
340
|
+
} catch {
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
const toolCalls = [];
|
|
344
|
+
for (const [, toolCall] of state.toolCalls) {
|
|
345
|
+
let args = {};
|
|
346
|
+
if (toolCall.arguments) {
|
|
347
|
+
try {
|
|
348
|
+
args = JSON.parse(toolCall.arguments);
|
|
349
|
+
} catch {
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
toolCalls.push({
|
|
353
|
+
toolCallId: toolCall.id,
|
|
354
|
+
toolName: toolCall.name,
|
|
355
|
+
arguments: args
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
const message = new AssistantMessage(
|
|
359
|
+
textContent,
|
|
360
|
+
toolCalls.length > 0 ? toolCalls : void 0,
|
|
361
|
+
{
|
|
362
|
+
id: state.id,
|
|
363
|
+
metadata: {
|
|
364
|
+
xai: {
|
|
365
|
+
model: state.model,
|
|
366
|
+
finish_reason: state.finishReason
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
);
|
|
371
|
+
const usage = {
|
|
372
|
+
inputTokens: state.inputTokens,
|
|
373
|
+
outputTokens: state.outputTokens,
|
|
374
|
+
totalTokens: state.inputTokens + state.outputTokens
|
|
375
|
+
};
|
|
376
|
+
let stopReason = "end_turn";
|
|
377
|
+
switch (state.finishReason) {
|
|
378
|
+
case "stop":
|
|
379
|
+
stopReason = "end_turn";
|
|
380
|
+
break;
|
|
381
|
+
case "length":
|
|
382
|
+
stopReason = "max_tokens";
|
|
383
|
+
break;
|
|
384
|
+
case "tool_calls":
|
|
385
|
+
stopReason = "tool_use";
|
|
386
|
+
break;
|
|
387
|
+
case "content_filter":
|
|
388
|
+
stopReason = "content_filter";
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
if (state.hadRefusal && stopReason !== "content_filter") {
|
|
392
|
+
stopReason = "content_filter";
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
message,
|
|
396
|
+
usage,
|
|
397
|
+
stopReason,
|
|
398
|
+
data: structuredData
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/providers/xai/llm.completions.ts
|
|
403
|
+
var XAI_COMPLETIONS_API_URL = "https://api.x.ai/v1/chat/completions";
|
|
404
|
+
var XAI_COMPLETIONS_CAPABILITIES = {
|
|
405
|
+
streaming: true,
|
|
406
|
+
tools: true,
|
|
407
|
+
structuredOutput: true,
|
|
408
|
+
imageInput: true,
|
|
409
|
+
videoInput: false,
|
|
410
|
+
audioInput: false
|
|
411
|
+
};
|
|
412
|
+
function createCompletionsLLMHandler() {
|
|
413
|
+
let providerRef = null;
|
|
414
|
+
return {
|
|
415
|
+
_setProvider(provider) {
|
|
416
|
+
providerRef = provider;
|
|
417
|
+
},
|
|
418
|
+
bind(modelId) {
|
|
419
|
+
if (!providerRef) {
|
|
420
|
+
throw new UPPError(
|
|
421
|
+
"Provider reference not set. Handler must be used with createProvider() or have _setProvider called.",
|
|
422
|
+
"INVALID_REQUEST",
|
|
423
|
+
"xai",
|
|
424
|
+
"llm"
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
const model = {
|
|
428
|
+
modelId,
|
|
429
|
+
capabilities: XAI_COMPLETIONS_CAPABILITIES,
|
|
430
|
+
get provider() {
|
|
431
|
+
return providerRef;
|
|
432
|
+
},
|
|
433
|
+
async complete(request) {
|
|
434
|
+
const apiKey = await resolveApiKey(
|
|
435
|
+
request.config,
|
|
436
|
+
"XAI_API_KEY",
|
|
437
|
+
"xai",
|
|
438
|
+
"llm"
|
|
439
|
+
);
|
|
440
|
+
const baseUrl = request.config.baseUrl ?? XAI_COMPLETIONS_API_URL;
|
|
441
|
+
const body = transformRequest(request, modelId);
|
|
442
|
+
const response = await doFetch(
|
|
443
|
+
baseUrl,
|
|
444
|
+
{
|
|
445
|
+
method: "POST",
|
|
446
|
+
headers: {
|
|
447
|
+
"Content-Type": "application/json",
|
|
448
|
+
Authorization: `Bearer ${apiKey}`
|
|
449
|
+
},
|
|
450
|
+
body: JSON.stringify(body),
|
|
451
|
+
signal: request.signal
|
|
452
|
+
},
|
|
453
|
+
request.config,
|
|
454
|
+
"xai",
|
|
455
|
+
"llm"
|
|
456
|
+
);
|
|
457
|
+
const data = await response.json();
|
|
458
|
+
return transformResponse(data);
|
|
459
|
+
},
|
|
460
|
+
stream(request) {
|
|
461
|
+
const state = createStreamState();
|
|
462
|
+
let responseResolve;
|
|
463
|
+
let responseReject;
|
|
464
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
465
|
+
responseResolve = resolve;
|
|
466
|
+
responseReject = reject;
|
|
467
|
+
});
|
|
468
|
+
async function* generateEvents() {
|
|
469
|
+
try {
|
|
470
|
+
const apiKey = await resolveApiKey(
|
|
471
|
+
request.config,
|
|
472
|
+
"XAI_API_KEY",
|
|
473
|
+
"xai",
|
|
474
|
+
"llm"
|
|
475
|
+
);
|
|
476
|
+
const baseUrl = request.config.baseUrl ?? XAI_COMPLETIONS_API_URL;
|
|
477
|
+
const body = transformRequest(request, modelId);
|
|
478
|
+
body.stream = true;
|
|
479
|
+
body.stream_options = { include_usage: true };
|
|
480
|
+
const response = await doStreamFetch(
|
|
481
|
+
baseUrl,
|
|
482
|
+
{
|
|
483
|
+
method: "POST",
|
|
484
|
+
headers: {
|
|
485
|
+
"Content-Type": "application/json",
|
|
486
|
+
Authorization: `Bearer ${apiKey}`
|
|
487
|
+
},
|
|
488
|
+
body: JSON.stringify(body),
|
|
489
|
+
signal: request.signal
|
|
490
|
+
},
|
|
491
|
+
request.config,
|
|
492
|
+
"xai",
|
|
493
|
+
"llm"
|
|
494
|
+
);
|
|
495
|
+
if (!response.ok) {
|
|
496
|
+
const error = await normalizeHttpError(response, "xai", "llm");
|
|
497
|
+
responseReject(error);
|
|
498
|
+
throw error;
|
|
499
|
+
}
|
|
500
|
+
if (!response.body) {
|
|
501
|
+
const error = new UPPError(
|
|
502
|
+
"No response body for streaming request",
|
|
503
|
+
"PROVIDER_ERROR",
|
|
504
|
+
"xai",
|
|
505
|
+
"llm"
|
|
506
|
+
);
|
|
507
|
+
responseReject(error);
|
|
508
|
+
throw error;
|
|
509
|
+
}
|
|
510
|
+
for await (const data of parseSSEStream(response.body)) {
|
|
511
|
+
if (data === "[DONE]") {
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
if (typeof data === "object" && data !== null) {
|
|
515
|
+
const chunk = data;
|
|
516
|
+
if ("error" in chunk && chunk.error) {
|
|
517
|
+
const errorData = chunk.error;
|
|
518
|
+
const error = new UPPError(
|
|
519
|
+
errorData.message ?? "Unknown error",
|
|
520
|
+
"PROVIDER_ERROR",
|
|
521
|
+
"xai",
|
|
522
|
+
"llm"
|
|
523
|
+
);
|
|
524
|
+
responseReject(error);
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
const uppEvents = transformStreamEvent(chunk, state);
|
|
528
|
+
for (const event of uppEvents) {
|
|
529
|
+
yield event;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
responseResolve(buildResponseFromState(state));
|
|
534
|
+
} catch (error) {
|
|
535
|
+
responseReject(error);
|
|
536
|
+
throw error;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return {
|
|
540
|
+
[Symbol.asyncIterator]() {
|
|
541
|
+
return generateEvents();
|
|
542
|
+
},
|
|
543
|
+
response: responsePromise
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
return model;
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/providers/xai/transform.responses.ts
|
|
553
|
+
function transformRequest2(request, modelId) {
|
|
554
|
+
const params = request.params ?? {};
|
|
555
|
+
const xaiRequest = {
|
|
556
|
+
...params,
|
|
557
|
+
model: modelId,
|
|
558
|
+
input: transformInputItems(request.messages, request.system)
|
|
559
|
+
};
|
|
560
|
+
if (request.tools && request.tools.length > 0) {
|
|
561
|
+
xaiRequest.tools = request.tools.map(transformTool2);
|
|
562
|
+
}
|
|
563
|
+
if (request.structure) {
|
|
564
|
+
const schema = {
|
|
565
|
+
type: "object",
|
|
566
|
+
properties: request.structure.properties,
|
|
567
|
+
required: request.structure.required,
|
|
568
|
+
...request.structure.additionalProperties !== void 0 ? { additionalProperties: request.structure.additionalProperties } : { additionalProperties: false }
|
|
569
|
+
};
|
|
570
|
+
if (request.structure.description) {
|
|
571
|
+
schema.description = request.structure.description;
|
|
572
|
+
}
|
|
573
|
+
xaiRequest.text = {
|
|
574
|
+
format: {
|
|
575
|
+
type: "json_schema",
|
|
576
|
+
name: "json_response",
|
|
577
|
+
description: request.structure.description,
|
|
578
|
+
schema,
|
|
579
|
+
strict: true
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
return xaiRequest;
|
|
584
|
+
}
|
|
585
|
+
function transformInputItems(messages, system) {
|
|
586
|
+
const result = [];
|
|
587
|
+
if (system) {
|
|
588
|
+
result.push({
|
|
589
|
+
type: "message",
|
|
590
|
+
role: "system",
|
|
591
|
+
content: system
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
for (const message of messages) {
|
|
595
|
+
const items = transformMessage2(message);
|
|
596
|
+
result.push(...items);
|
|
597
|
+
}
|
|
598
|
+
if (result.length === 1 && result[0]?.type === "message") {
|
|
599
|
+
const item = result[0];
|
|
600
|
+
if (item.role === "user" && typeof item.content === "string") {
|
|
601
|
+
return item.content;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return result;
|
|
605
|
+
}
|
|
606
|
+
function filterValidContent2(content) {
|
|
607
|
+
return content.filter((c) => c && typeof c.type === "string");
|
|
608
|
+
}
|
|
609
|
+
function transformMessage2(message) {
|
|
610
|
+
if (isUserMessage(message)) {
|
|
611
|
+
const validContent = filterValidContent2(message.content);
|
|
612
|
+
if (validContent.length === 1 && validContent[0]?.type === "text") {
|
|
613
|
+
return [
|
|
614
|
+
{
|
|
615
|
+
type: "message",
|
|
616
|
+
role: "user",
|
|
617
|
+
content: validContent[0].text
|
|
618
|
+
}
|
|
619
|
+
];
|
|
620
|
+
}
|
|
621
|
+
return [
|
|
622
|
+
{
|
|
623
|
+
type: "message",
|
|
624
|
+
role: "user",
|
|
625
|
+
content: validContent.map(transformContentPart)
|
|
626
|
+
}
|
|
627
|
+
];
|
|
628
|
+
}
|
|
629
|
+
if (isAssistantMessage(message)) {
|
|
630
|
+
const validContent = filterValidContent2(message.content);
|
|
631
|
+
const items = [];
|
|
632
|
+
const textContent = validContent.filter((c) => c.type === "text").map((c) => c.text).join("\n\n");
|
|
633
|
+
if (textContent) {
|
|
634
|
+
items.push({
|
|
635
|
+
type: "message",
|
|
636
|
+
role: "assistant",
|
|
637
|
+
content: textContent
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
const xaiMeta = message.metadata?.xai;
|
|
641
|
+
const functionCallItems = xaiMeta?.functionCallItems;
|
|
642
|
+
if (functionCallItems && functionCallItems.length > 0) {
|
|
643
|
+
for (const fc of functionCallItems) {
|
|
644
|
+
items.push({
|
|
645
|
+
type: "function_call",
|
|
646
|
+
id: fc.id,
|
|
647
|
+
call_id: fc.call_id,
|
|
648
|
+
name: fc.name,
|
|
649
|
+
arguments: fc.arguments
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
} else if (message.toolCalls && message.toolCalls.length > 0) {
|
|
653
|
+
for (const call of message.toolCalls) {
|
|
654
|
+
items.push({
|
|
655
|
+
type: "function_call",
|
|
656
|
+
id: `fc_${call.toolCallId}`,
|
|
657
|
+
call_id: call.toolCallId,
|
|
658
|
+
name: call.toolName,
|
|
659
|
+
arguments: JSON.stringify(call.arguments)
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return items;
|
|
664
|
+
}
|
|
665
|
+
if (isToolResultMessage(message)) {
|
|
666
|
+
return message.results.map((result) => ({
|
|
667
|
+
type: "function_call_output",
|
|
668
|
+
call_id: result.toolCallId,
|
|
669
|
+
output: typeof result.result === "string" ? result.result : JSON.stringify(result.result)
|
|
670
|
+
}));
|
|
671
|
+
}
|
|
672
|
+
return [];
|
|
673
|
+
}
|
|
674
|
+
function transformContentPart(block) {
|
|
675
|
+
switch (block.type) {
|
|
676
|
+
case "text":
|
|
677
|
+
return { type: "input_text", text: block.text };
|
|
678
|
+
case "image": {
|
|
679
|
+
const imageBlock = block;
|
|
680
|
+
if (imageBlock.source.type === "base64") {
|
|
681
|
+
return {
|
|
682
|
+
type: "input_image",
|
|
683
|
+
image_url: `data:${imageBlock.mimeType};base64,${imageBlock.source.data}`
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
if (imageBlock.source.type === "url") {
|
|
687
|
+
return {
|
|
688
|
+
type: "input_image",
|
|
689
|
+
image_url: imageBlock.source.url
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
if (imageBlock.source.type === "bytes") {
|
|
693
|
+
const base64 = btoa(
|
|
694
|
+
Array.from(imageBlock.source.data).map((b) => String.fromCharCode(b)).join("")
|
|
695
|
+
);
|
|
696
|
+
return {
|
|
697
|
+
type: "input_image",
|
|
698
|
+
image_url: `data:${imageBlock.mimeType};base64,${base64}`
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
throw new Error("Unknown image source type");
|
|
702
|
+
}
|
|
703
|
+
default:
|
|
704
|
+
throw new Error(`Unsupported content type: ${block.type}`);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function transformTool2(tool) {
|
|
708
|
+
return {
|
|
709
|
+
type: "function",
|
|
710
|
+
name: tool.name,
|
|
711
|
+
description: tool.description,
|
|
712
|
+
parameters: {
|
|
713
|
+
type: "object",
|
|
714
|
+
properties: tool.parameters.properties,
|
|
715
|
+
required: tool.parameters.required,
|
|
716
|
+
...tool.parameters.additionalProperties !== void 0 ? { additionalProperties: tool.parameters.additionalProperties } : {}
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function transformResponse2(data) {
|
|
721
|
+
const textContent = [];
|
|
722
|
+
const toolCalls = [];
|
|
723
|
+
const functionCallItems = [];
|
|
724
|
+
let hadRefusal = false;
|
|
725
|
+
let structuredData;
|
|
726
|
+
for (const item of data.output) {
|
|
727
|
+
if (item.type === "message") {
|
|
728
|
+
const messageItem = item;
|
|
729
|
+
for (const content of messageItem.content) {
|
|
730
|
+
if (content.type === "output_text") {
|
|
731
|
+
textContent.push({ type: "text", text: content.text });
|
|
732
|
+
if (structuredData === void 0) {
|
|
733
|
+
try {
|
|
734
|
+
structuredData = JSON.parse(content.text);
|
|
735
|
+
} catch {
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
} else if (content.type === "refusal") {
|
|
739
|
+
textContent.push({ type: "text", text: content.refusal });
|
|
740
|
+
hadRefusal = true;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
} else if (item.type === "function_call") {
|
|
744
|
+
const functionCall = item;
|
|
745
|
+
let args = {};
|
|
746
|
+
try {
|
|
747
|
+
args = JSON.parse(functionCall.arguments);
|
|
748
|
+
} catch {
|
|
749
|
+
}
|
|
750
|
+
toolCalls.push({
|
|
751
|
+
toolCallId: functionCall.call_id,
|
|
752
|
+
toolName: functionCall.name,
|
|
753
|
+
arguments: args
|
|
754
|
+
});
|
|
755
|
+
functionCallItems.push({
|
|
756
|
+
id: functionCall.id,
|
|
757
|
+
call_id: functionCall.call_id,
|
|
758
|
+
name: functionCall.name,
|
|
759
|
+
arguments: functionCall.arguments
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
const message = new AssistantMessage(
|
|
764
|
+
textContent,
|
|
765
|
+
toolCalls.length > 0 ? toolCalls : void 0,
|
|
766
|
+
{
|
|
767
|
+
id: data.id,
|
|
768
|
+
metadata: {
|
|
769
|
+
xai: {
|
|
770
|
+
model: data.model,
|
|
771
|
+
status: data.status,
|
|
772
|
+
// Store response_id for multi-turn tool calling
|
|
773
|
+
response_id: data.id,
|
|
774
|
+
functionCallItems: functionCallItems.length > 0 ? functionCallItems : void 0,
|
|
775
|
+
citations: data.citations,
|
|
776
|
+
inline_citations: data.inline_citations
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
);
|
|
781
|
+
const usage = {
|
|
782
|
+
inputTokens: data.usage.input_tokens,
|
|
783
|
+
outputTokens: data.usage.output_tokens,
|
|
784
|
+
totalTokens: data.usage.total_tokens
|
|
785
|
+
};
|
|
786
|
+
let stopReason = "end_turn";
|
|
787
|
+
if (data.status === "completed") {
|
|
788
|
+
stopReason = toolCalls.length > 0 ? "tool_use" : "end_turn";
|
|
789
|
+
} else if (data.status === "incomplete") {
|
|
790
|
+
stopReason = data.incomplete_details?.reason === "max_output_tokens" ? "max_tokens" : "end_turn";
|
|
791
|
+
} else if (data.status === "failed") {
|
|
792
|
+
stopReason = "error";
|
|
793
|
+
}
|
|
794
|
+
if (hadRefusal && stopReason !== "error") {
|
|
795
|
+
stopReason = "content_filter";
|
|
796
|
+
}
|
|
797
|
+
return {
|
|
798
|
+
message,
|
|
799
|
+
usage,
|
|
800
|
+
stopReason,
|
|
801
|
+
data: structuredData
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
function createStreamState2() {
|
|
805
|
+
return {
|
|
806
|
+
id: "",
|
|
807
|
+
model: "",
|
|
808
|
+
textByIndex: /* @__PURE__ */ new Map(),
|
|
809
|
+
toolCalls: /* @__PURE__ */ new Map(),
|
|
810
|
+
status: "in_progress",
|
|
811
|
+
inputTokens: 0,
|
|
812
|
+
outputTokens: 0,
|
|
813
|
+
hadRefusal: false
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function transformStreamEvent2(event, state) {
|
|
817
|
+
const events = [];
|
|
818
|
+
switch (event.type) {
|
|
819
|
+
case "response.created":
|
|
820
|
+
state.id = event.response.id;
|
|
821
|
+
state.model = event.response.model;
|
|
822
|
+
events.push({ type: "message_start", index: 0, delta: {} });
|
|
823
|
+
break;
|
|
824
|
+
case "response.in_progress":
|
|
825
|
+
state.status = "in_progress";
|
|
826
|
+
break;
|
|
827
|
+
case "response.completed":
|
|
828
|
+
state.status = "completed";
|
|
829
|
+
if (event.response.usage) {
|
|
830
|
+
state.inputTokens = event.response.usage.input_tokens;
|
|
831
|
+
state.outputTokens = event.response.usage.output_tokens;
|
|
832
|
+
}
|
|
833
|
+
events.push({ type: "message_stop", index: 0, delta: {} });
|
|
834
|
+
break;
|
|
835
|
+
case "response.failed":
|
|
836
|
+
state.status = "failed";
|
|
837
|
+
events.push({ type: "message_stop", index: 0, delta: {} });
|
|
838
|
+
break;
|
|
839
|
+
case "response.output_item.added":
|
|
840
|
+
if (event.item.type === "function_call") {
|
|
841
|
+
const functionCall = event.item;
|
|
842
|
+
const existing = state.toolCalls.get(event.output_index) ?? {
|
|
843
|
+
arguments: ""
|
|
844
|
+
};
|
|
845
|
+
existing.itemId = functionCall.id;
|
|
846
|
+
existing.callId = functionCall.call_id;
|
|
847
|
+
existing.name = functionCall.name;
|
|
848
|
+
if (functionCall.arguments) {
|
|
849
|
+
existing.arguments = functionCall.arguments;
|
|
850
|
+
}
|
|
851
|
+
state.toolCalls.set(event.output_index, existing);
|
|
852
|
+
}
|
|
853
|
+
events.push({
|
|
854
|
+
type: "content_block_start",
|
|
855
|
+
index: event.output_index,
|
|
856
|
+
delta: {}
|
|
857
|
+
});
|
|
858
|
+
break;
|
|
859
|
+
case "response.output_item.done":
|
|
860
|
+
if (event.item.type === "function_call") {
|
|
861
|
+
const functionCall = event.item;
|
|
862
|
+
const existing = state.toolCalls.get(event.output_index) ?? {
|
|
863
|
+
arguments: ""
|
|
864
|
+
};
|
|
865
|
+
existing.itemId = functionCall.id;
|
|
866
|
+
existing.callId = functionCall.call_id;
|
|
867
|
+
existing.name = functionCall.name;
|
|
868
|
+
if (functionCall.arguments) {
|
|
869
|
+
existing.arguments = functionCall.arguments;
|
|
870
|
+
}
|
|
871
|
+
state.toolCalls.set(event.output_index, existing);
|
|
872
|
+
}
|
|
873
|
+
events.push({
|
|
874
|
+
type: "content_block_stop",
|
|
875
|
+
index: event.output_index,
|
|
876
|
+
delta: {}
|
|
877
|
+
});
|
|
878
|
+
break;
|
|
879
|
+
case "response.output_text.delta":
|
|
880
|
+
const currentText = state.textByIndex.get(event.output_index) ?? "";
|
|
881
|
+
state.textByIndex.set(event.output_index, currentText + event.delta);
|
|
882
|
+
events.push({
|
|
883
|
+
type: "text_delta",
|
|
884
|
+
index: event.output_index,
|
|
885
|
+
delta: { text: event.delta }
|
|
886
|
+
});
|
|
887
|
+
break;
|
|
888
|
+
case "response.output_text.done":
|
|
889
|
+
state.textByIndex.set(event.output_index, event.text);
|
|
890
|
+
break;
|
|
891
|
+
case "response.refusal.delta": {
|
|
892
|
+
state.hadRefusal = true;
|
|
893
|
+
const currentRefusal = state.textByIndex.get(event.output_index) ?? "";
|
|
894
|
+
state.textByIndex.set(event.output_index, currentRefusal + event.delta);
|
|
895
|
+
events.push({
|
|
896
|
+
type: "text_delta",
|
|
897
|
+
index: event.output_index,
|
|
898
|
+
delta: { text: event.delta }
|
|
899
|
+
});
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
case "response.refusal.done":
|
|
903
|
+
state.hadRefusal = true;
|
|
904
|
+
state.textByIndex.set(event.output_index, event.refusal);
|
|
905
|
+
break;
|
|
906
|
+
case "response.function_call_arguments.delta": {
|
|
907
|
+
let toolCall = state.toolCalls.get(event.output_index);
|
|
908
|
+
if (!toolCall) {
|
|
909
|
+
toolCall = { arguments: "" };
|
|
910
|
+
state.toolCalls.set(event.output_index, toolCall);
|
|
911
|
+
}
|
|
912
|
+
if (event.item_id && !toolCall.itemId) {
|
|
913
|
+
toolCall.itemId = event.item_id;
|
|
914
|
+
}
|
|
915
|
+
if (event.call_id && !toolCall.callId) {
|
|
916
|
+
toolCall.callId = event.call_id;
|
|
917
|
+
}
|
|
918
|
+
toolCall.arguments += event.delta;
|
|
919
|
+
events.push({
|
|
920
|
+
type: "tool_call_delta",
|
|
921
|
+
index: event.output_index,
|
|
922
|
+
delta: {
|
|
923
|
+
toolCallId: toolCall.callId ?? toolCall.itemId ?? "",
|
|
924
|
+
toolName: toolCall.name,
|
|
925
|
+
argumentsJson: event.delta
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
case "response.function_call_arguments.done": {
|
|
931
|
+
let toolCall = state.toolCalls.get(event.output_index);
|
|
932
|
+
if (!toolCall) {
|
|
933
|
+
toolCall = { arguments: "" };
|
|
934
|
+
state.toolCalls.set(event.output_index, toolCall);
|
|
935
|
+
}
|
|
936
|
+
if (event.item_id) {
|
|
937
|
+
toolCall.itemId = event.item_id;
|
|
938
|
+
}
|
|
939
|
+
if (event.call_id) {
|
|
940
|
+
toolCall.callId = event.call_id;
|
|
941
|
+
}
|
|
942
|
+
toolCall.name = event.name;
|
|
943
|
+
toolCall.arguments = event.arguments;
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
946
|
+
case "error":
|
|
947
|
+
break;
|
|
948
|
+
default:
|
|
949
|
+
break;
|
|
950
|
+
}
|
|
951
|
+
return events;
|
|
952
|
+
}
|
|
953
|
+
function buildResponseFromState2(state) {
|
|
954
|
+
const textContent = [];
|
|
955
|
+
let structuredData;
|
|
956
|
+
for (const [, text] of state.textByIndex) {
|
|
957
|
+
if (text) {
|
|
958
|
+
textContent.push({ type: "text", text });
|
|
959
|
+
if (structuredData === void 0) {
|
|
960
|
+
try {
|
|
961
|
+
structuredData = JSON.parse(text);
|
|
962
|
+
} catch {
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
const toolCalls = [];
|
|
968
|
+
const functionCallItems = [];
|
|
969
|
+
for (const [, toolCall] of state.toolCalls) {
|
|
970
|
+
let args = {};
|
|
971
|
+
if (toolCall.arguments) {
|
|
972
|
+
try {
|
|
973
|
+
args = JSON.parse(toolCall.arguments);
|
|
974
|
+
} catch {
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
const itemId = toolCall.itemId ?? "";
|
|
978
|
+
const callId = toolCall.callId ?? toolCall.itemId ?? "";
|
|
979
|
+
const name = toolCall.name ?? "";
|
|
980
|
+
toolCalls.push({
|
|
981
|
+
toolCallId: callId,
|
|
982
|
+
toolName: name,
|
|
983
|
+
arguments: args
|
|
984
|
+
});
|
|
985
|
+
if (itemId && callId && name) {
|
|
986
|
+
functionCallItems.push({
|
|
987
|
+
id: itemId,
|
|
988
|
+
call_id: callId,
|
|
989
|
+
name,
|
|
990
|
+
arguments: toolCall.arguments
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
const message = new AssistantMessage(
|
|
995
|
+
textContent,
|
|
996
|
+
toolCalls.length > 0 ? toolCalls : void 0,
|
|
997
|
+
{
|
|
998
|
+
id: state.id,
|
|
999
|
+
metadata: {
|
|
1000
|
+
xai: {
|
|
1001
|
+
model: state.model,
|
|
1002
|
+
status: state.status,
|
|
1003
|
+
// Store response_id for multi-turn tool calling
|
|
1004
|
+
response_id: state.id,
|
|
1005
|
+
functionCallItems: functionCallItems.length > 0 ? functionCallItems : void 0
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
);
|
|
1010
|
+
const usage = {
|
|
1011
|
+
inputTokens: state.inputTokens,
|
|
1012
|
+
outputTokens: state.outputTokens,
|
|
1013
|
+
totalTokens: state.inputTokens + state.outputTokens
|
|
1014
|
+
};
|
|
1015
|
+
let stopReason = "end_turn";
|
|
1016
|
+
if (state.status === "completed") {
|
|
1017
|
+
stopReason = toolCalls.length > 0 ? "tool_use" : "end_turn";
|
|
1018
|
+
} else if (state.status === "failed") {
|
|
1019
|
+
stopReason = "error";
|
|
1020
|
+
}
|
|
1021
|
+
if (state.hadRefusal && stopReason !== "error") {
|
|
1022
|
+
stopReason = "content_filter";
|
|
1023
|
+
}
|
|
1024
|
+
return {
|
|
1025
|
+
message,
|
|
1026
|
+
usage,
|
|
1027
|
+
stopReason,
|
|
1028
|
+
data: structuredData
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// src/providers/xai/llm.responses.ts
|
|
1033
|
+
var XAI_RESPONSES_API_URL = "https://api.x.ai/v1/responses";
|
|
1034
|
+
var XAI_RESPONSES_CAPABILITIES = {
|
|
1035
|
+
streaming: true,
|
|
1036
|
+
tools: true,
|
|
1037
|
+
structuredOutput: true,
|
|
1038
|
+
imageInput: true,
|
|
1039
|
+
videoInput: false,
|
|
1040
|
+
audioInput: false
|
|
1041
|
+
};
|
|
1042
|
+
function createResponsesLLMHandler() {
|
|
1043
|
+
let providerRef = null;
|
|
1044
|
+
return {
|
|
1045
|
+
_setProvider(provider) {
|
|
1046
|
+
providerRef = provider;
|
|
1047
|
+
},
|
|
1048
|
+
bind(modelId) {
|
|
1049
|
+
if (!providerRef) {
|
|
1050
|
+
throw new UPPError(
|
|
1051
|
+
"Provider reference not set. Handler must be used with createProvider() or have _setProvider called.",
|
|
1052
|
+
"INVALID_REQUEST",
|
|
1053
|
+
"xai",
|
|
1054
|
+
"llm"
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
const model = {
|
|
1058
|
+
modelId,
|
|
1059
|
+
capabilities: XAI_RESPONSES_CAPABILITIES,
|
|
1060
|
+
get provider() {
|
|
1061
|
+
return providerRef;
|
|
1062
|
+
},
|
|
1063
|
+
async complete(request) {
|
|
1064
|
+
const apiKey = await resolveApiKey(
|
|
1065
|
+
request.config,
|
|
1066
|
+
"XAI_API_KEY",
|
|
1067
|
+
"xai",
|
|
1068
|
+
"llm"
|
|
1069
|
+
);
|
|
1070
|
+
const baseUrl = request.config.baseUrl ?? XAI_RESPONSES_API_URL;
|
|
1071
|
+
const body = transformRequest2(request, modelId);
|
|
1072
|
+
const response = await doFetch(
|
|
1073
|
+
baseUrl,
|
|
1074
|
+
{
|
|
1075
|
+
method: "POST",
|
|
1076
|
+
headers: {
|
|
1077
|
+
"Content-Type": "application/json",
|
|
1078
|
+
Authorization: `Bearer ${apiKey}`
|
|
1079
|
+
},
|
|
1080
|
+
body: JSON.stringify(body),
|
|
1081
|
+
signal: request.signal
|
|
1082
|
+
},
|
|
1083
|
+
request.config,
|
|
1084
|
+
"xai",
|
|
1085
|
+
"llm"
|
|
1086
|
+
);
|
|
1087
|
+
const data = await response.json();
|
|
1088
|
+
if (data.status === "failed" && data.error) {
|
|
1089
|
+
throw new UPPError(
|
|
1090
|
+
data.error.message,
|
|
1091
|
+
"PROVIDER_ERROR",
|
|
1092
|
+
"xai",
|
|
1093
|
+
"llm"
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
return transformResponse2(data);
|
|
1097
|
+
},
|
|
1098
|
+
stream(request) {
|
|
1099
|
+
const state = createStreamState2();
|
|
1100
|
+
let responseResolve;
|
|
1101
|
+
let responseReject;
|
|
1102
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
1103
|
+
responseResolve = resolve;
|
|
1104
|
+
responseReject = reject;
|
|
1105
|
+
});
|
|
1106
|
+
async function* generateEvents() {
|
|
1107
|
+
try {
|
|
1108
|
+
const apiKey = await resolveApiKey(
|
|
1109
|
+
request.config,
|
|
1110
|
+
"XAI_API_KEY",
|
|
1111
|
+
"xai",
|
|
1112
|
+
"llm"
|
|
1113
|
+
);
|
|
1114
|
+
const baseUrl = request.config.baseUrl ?? XAI_RESPONSES_API_URL;
|
|
1115
|
+
const body = transformRequest2(request, modelId);
|
|
1116
|
+
body.stream = true;
|
|
1117
|
+
const response = await doStreamFetch(
|
|
1118
|
+
baseUrl,
|
|
1119
|
+
{
|
|
1120
|
+
method: "POST",
|
|
1121
|
+
headers: {
|
|
1122
|
+
"Content-Type": "application/json",
|
|
1123
|
+
Authorization: `Bearer ${apiKey}`
|
|
1124
|
+
},
|
|
1125
|
+
body: JSON.stringify(body),
|
|
1126
|
+
signal: request.signal
|
|
1127
|
+
},
|
|
1128
|
+
request.config,
|
|
1129
|
+
"xai",
|
|
1130
|
+
"llm"
|
|
1131
|
+
);
|
|
1132
|
+
if (!response.ok) {
|
|
1133
|
+
const error = await normalizeHttpError(response, "xai", "llm");
|
|
1134
|
+
responseReject(error);
|
|
1135
|
+
throw error;
|
|
1136
|
+
}
|
|
1137
|
+
if (!response.body) {
|
|
1138
|
+
const error = new UPPError(
|
|
1139
|
+
"No response body for streaming request",
|
|
1140
|
+
"PROVIDER_ERROR",
|
|
1141
|
+
"xai",
|
|
1142
|
+
"llm"
|
|
1143
|
+
);
|
|
1144
|
+
responseReject(error);
|
|
1145
|
+
throw error;
|
|
1146
|
+
}
|
|
1147
|
+
for await (const data of parseSSEStream(response.body)) {
|
|
1148
|
+
if (data === "[DONE]") {
|
|
1149
|
+
continue;
|
|
1150
|
+
}
|
|
1151
|
+
if (typeof data === "object" && data !== null) {
|
|
1152
|
+
const event = data;
|
|
1153
|
+
if (event.type === "error") {
|
|
1154
|
+
const errorEvent = event;
|
|
1155
|
+
const error = new UPPError(
|
|
1156
|
+
errorEvent.error.message,
|
|
1157
|
+
"PROVIDER_ERROR",
|
|
1158
|
+
"xai",
|
|
1159
|
+
"llm"
|
|
1160
|
+
);
|
|
1161
|
+
responseReject(error);
|
|
1162
|
+
throw error;
|
|
1163
|
+
}
|
|
1164
|
+
const uppEvents = transformStreamEvent2(event, state);
|
|
1165
|
+
for (const uppEvent of uppEvents) {
|
|
1166
|
+
yield uppEvent;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
responseResolve(buildResponseFromState2(state));
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
responseReject(error);
|
|
1173
|
+
throw error;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
return {
|
|
1177
|
+
[Symbol.asyncIterator]() {
|
|
1178
|
+
return generateEvents();
|
|
1179
|
+
},
|
|
1180
|
+
response: responsePromise
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
return model;
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// src/providers/xai/transform.messages.ts
|
|
1190
|
+
function transformRequest3(request, modelId) {
|
|
1191
|
+
const params = request.params ?? {};
|
|
1192
|
+
const xaiRequest = {
|
|
1193
|
+
...params,
|
|
1194
|
+
model: modelId,
|
|
1195
|
+
messages: request.messages.map(transformMessage3)
|
|
1196
|
+
};
|
|
1197
|
+
if (request.system) {
|
|
1198
|
+
xaiRequest.system = request.system;
|
|
1199
|
+
}
|
|
1200
|
+
if (request.tools && request.tools.length > 0) {
|
|
1201
|
+
xaiRequest.tools = request.tools.map(transformTool3);
|
|
1202
|
+
xaiRequest.tool_choice = { type: "auto" };
|
|
1203
|
+
}
|
|
1204
|
+
if (request.structure) {
|
|
1205
|
+
const structuredTool = {
|
|
1206
|
+
name: "json_response",
|
|
1207
|
+
description: "Return the response in the specified JSON format. You MUST use this tool to provide your response.",
|
|
1208
|
+
input_schema: {
|
|
1209
|
+
type: "object",
|
|
1210
|
+
properties: request.structure.properties,
|
|
1211
|
+
required: request.structure.required
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
xaiRequest.tools = [...xaiRequest.tools ?? [], structuredTool];
|
|
1215
|
+
xaiRequest.tool_choice = { type: "tool", name: "json_response" };
|
|
1216
|
+
}
|
|
1217
|
+
return xaiRequest;
|
|
1218
|
+
}
|
|
1219
|
+
function filterValidContent3(content) {
|
|
1220
|
+
return content.filter((c) => c && typeof c.type === "string");
|
|
1221
|
+
}
|
|
1222
|
+
function transformMessage3(message) {
|
|
1223
|
+
if (isUserMessage(message)) {
|
|
1224
|
+
const validContent = filterValidContent3(message.content);
|
|
1225
|
+
return {
|
|
1226
|
+
role: "user",
|
|
1227
|
+
content: validContent.map(transformContentBlock2)
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
if (isAssistantMessage(message)) {
|
|
1231
|
+
const validContent = filterValidContent3(message.content);
|
|
1232
|
+
const content = validContent.map(transformContentBlock2);
|
|
1233
|
+
if (message.toolCalls) {
|
|
1234
|
+
for (const call of message.toolCalls) {
|
|
1235
|
+
content.push({
|
|
1236
|
+
type: "tool_use",
|
|
1237
|
+
id: call.toolCallId,
|
|
1238
|
+
name: call.toolName,
|
|
1239
|
+
input: call.arguments
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
if (content.length === 0) {
|
|
1244
|
+
content.push({ type: "text", text: "" });
|
|
1245
|
+
}
|
|
1246
|
+
return {
|
|
1247
|
+
role: "assistant",
|
|
1248
|
+
content
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
if (isToolResultMessage(message)) {
|
|
1252
|
+
return {
|
|
1253
|
+
role: "user",
|
|
1254
|
+
content: message.results.map((result) => ({
|
|
1255
|
+
type: "tool_result",
|
|
1256
|
+
tool_use_id: result.toolCallId,
|
|
1257
|
+
content: typeof result.result === "string" ? result.result : JSON.stringify(result.result),
|
|
1258
|
+
is_error: result.isError
|
|
1259
|
+
}))
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
throw new Error(`Unknown message type: ${message.type}`);
|
|
1263
|
+
}
|
|
1264
|
+
function transformContentBlock2(block) {
|
|
1265
|
+
switch (block.type) {
|
|
1266
|
+
case "text":
|
|
1267
|
+
return { type: "text", text: block.text };
|
|
1268
|
+
case "image": {
|
|
1269
|
+
const imageBlock = block;
|
|
1270
|
+
if (imageBlock.source.type === "base64") {
|
|
1271
|
+
return {
|
|
1272
|
+
type: "image",
|
|
1273
|
+
source: {
|
|
1274
|
+
type: "base64",
|
|
1275
|
+
media_type: imageBlock.mimeType,
|
|
1276
|
+
data: imageBlock.source.data
|
|
1277
|
+
}
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
if (imageBlock.source.type === "url") {
|
|
1281
|
+
return {
|
|
1282
|
+
type: "image",
|
|
1283
|
+
source: {
|
|
1284
|
+
type: "url",
|
|
1285
|
+
url: imageBlock.source.url
|
|
1286
|
+
}
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
if (imageBlock.source.type === "bytes") {
|
|
1290
|
+
const base64 = btoa(
|
|
1291
|
+
Array.from(imageBlock.source.data).map((b) => String.fromCharCode(b)).join("")
|
|
1292
|
+
);
|
|
1293
|
+
return {
|
|
1294
|
+
type: "image",
|
|
1295
|
+
source: {
|
|
1296
|
+
type: "base64",
|
|
1297
|
+
media_type: imageBlock.mimeType,
|
|
1298
|
+
data: base64
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
throw new Error(`Unknown image source type`);
|
|
1303
|
+
}
|
|
1304
|
+
default:
|
|
1305
|
+
throw new Error(`Unsupported content type: ${block.type}`);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
function transformTool3(tool) {
|
|
1309
|
+
return {
|
|
1310
|
+
name: tool.name,
|
|
1311
|
+
description: tool.description,
|
|
1312
|
+
input_schema: {
|
|
1313
|
+
type: "object",
|
|
1314
|
+
properties: tool.parameters.properties,
|
|
1315
|
+
required: tool.parameters.required
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
function transformResponse3(data) {
|
|
1320
|
+
const textContent = [];
|
|
1321
|
+
const toolCalls = [];
|
|
1322
|
+
let structuredData;
|
|
1323
|
+
for (const block of data.content) {
|
|
1324
|
+
if (block.type === "text") {
|
|
1325
|
+
textContent.push({ type: "text", text: block.text });
|
|
1326
|
+
} else if (block.type === "tool_use") {
|
|
1327
|
+
if (block.name === "json_response") {
|
|
1328
|
+
structuredData = block.input;
|
|
1329
|
+
}
|
|
1330
|
+
toolCalls.push({
|
|
1331
|
+
toolCallId: block.id,
|
|
1332
|
+
toolName: block.name,
|
|
1333
|
+
arguments: block.input
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
const message = new AssistantMessage(
|
|
1338
|
+
textContent,
|
|
1339
|
+
toolCalls.length > 0 ? toolCalls : void 0,
|
|
1340
|
+
{
|
|
1341
|
+
id: data.id,
|
|
1342
|
+
metadata: {
|
|
1343
|
+
xai: {
|
|
1344
|
+
stop_reason: data.stop_reason,
|
|
1345
|
+
stop_sequence: data.stop_sequence,
|
|
1346
|
+
model: data.model
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
);
|
|
1351
|
+
const usage = {
|
|
1352
|
+
inputTokens: data.usage.input_tokens,
|
|
1353
|
+
outputTokens: data.usage.output_tokens,
|
|
1354
|
+
totalTokens: data.usage.input_tokens + data.usage.output_tokens
|
|
1355
|
+
};
|
|
1356
|
+
return {
|
|
1357
|
+
message,
|
|
1358
|
+
usage,
|
|
1359
|
+
stopReason: data.stop_reason ?? "end_turn",
|
|
1360
|
+
data: structuredData
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
function createStreamState3() {
|
|
1364
|
+
return {
|
|
1365
|
+
messageId: "",
|
|
1366
|
+
model: "",
|
|
1367
|
+
content: [],
|
|
1368
|
+
stopReason: null,
|
|
1369
|
+
inputTokens: 0,
|
|
1370
|
+
outputTokens: 0,
|
|
1371
|
+
currentIndex: 0
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
function transformStreamEvent3(event, state) {
|
|
1375
|
+
switch (event.type) {
|
|
1376
|
+
case "message_start":
|
|
1377
|
+
state.messageId = event.message.id;
|
|
1378
|
+
state.model = event.message.model;
|
|
1379
|
+
state.inputTokens = event.message.usage.input_tokens;
|
|
1380
|
+
return { type: "message_start", index: 0, delta: {} };
|
|
1381
|
+
case "content_block_start":
|
|
1382
|
+
state.currentIndex = event.index;
|
|
1383
|
+
if (event.content_block.type === "text") {
|
|
1384
|
+
state.content[event.index] = { type: "text", text: "" };
|
|
1385
|
+
} else if (event.content_block.type === "tool_use") {
|
|
1386
|
+
state.content[event.index] = {
|
|
1387
|
+
type: "tool_use",
|
|
1388
|
+
id: event.content_block.id,
|
|
1389
|
+
name: event.content_block.name,
|
|
1390
|
+
input: ""
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
return { type: "content_block_start", index: event.index, delta: {} };
|
|
1394
|
+
case "content_block_delta": {
|
|
1395
|
+
const delta = event.delta;
|
|
1396
|
+
const index = event.index ?? state.currentIndex;
|
|
1397
|
+
if (delta.type === "text_delta") {
|
|
1398
|
+
if (!state.content[index]) {
|
|
1399
|
+
state.content[index] = { type: "text", text: "" };
|
|
1400
|
+
}
|
|
1401
|
+
state.content[index].text = (state.content[index].text ?? "") + delta.text;
|
|
1402
|
+
return {
|
|
1403
|
+
type: "text_delta",
|
|
1404
|
+
index,
|
|
1405
|
+
delta: { text: delta.text }
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
if (delta.type === "input_json_delta") {
|
|
1409
|
+
if (!state.content[index]) {
|
|
1410
|
+
state.content[index] = { type: "tool_use", id: "", name: "", input: "" };
|
|
1411
|
+
}
|
|
1412
|
+
state.content[index].input = (state.content[index].input ?? "") + delta.partial_json;
|
|
1413
|
+
return {
|
|
1414
|
+
type: "tool_call_delta",
|
|
1415
|
+
index,
|
|
1416
|
+
delta: {
|
|
1417
|
+
argumentsJson: delta.partial_json,
|
|
1418
|
+
toolCallId: state.content[index]?.id,
|
|
1419
|
+
toolName: state.content[index]?.name
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
if (delta.type === "thinking_delta") {
|
|
1424
|
+
return {
|
|
1425
|
+
type: "reasoning_delta",
|
|
1426
|
+
index,
|
|
1427
|
+
delta: { text: delta.thinking }
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
return null;
|
|
1431
|
+
}
|
|
1432
|
+
case "content_block_stop":
|
|
1433
|
+
return { type: "content_block_stop", index: event.index ?? state.currentIndex, delta: {} };
|
|
1434
|
+
case "message_delta":
|
|
1435
|
+
state.stopReason = event.delta.stop_reason;
|
|
1436
|
+
state.outputTokens = event.usage.output_tokens;
|
|
1437
|
+
return null;
|
|
1438
|
+
case "message_stop":
|
|
1439
|
+
return { type: "message_stop", index: 0, delta: {} };
|
|
1440
|
+
case "ping":
|
|
1441
|
+
case "error":
|
|
1442
|
+
return null;
|
|
1443
|
+
default:
|
|
1444
|
+
return null;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
function buildResponseFromState3(state) {
|
|
1448
|
+
const textContent = [];
|
|
1449
|
+
const toolCalls = [];
|
|
1450
|
+
let structuredData;
|
|
1451
|
+
for (const block of state.content) {
|
|
1452
|
+
if (block.type === "text" && block.text) {
|
|
1453
|
+
textContent.push({ type: "text", text: block.text });
|
|
1454
|
+
} else if (block.type === "tool_use" && block.id && block.name) {
|
|
1455
|
+
let args = {};
|
|
1456
|
+
if (block.input) {
|
|
1457
|
+
try {
|
|
1458
|
+
args = JSON.parse(block.input);
|
|
1459
|
+
} catch {
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
if (block.name === "json_response") {
|
|
1463
|
+
structuredData = args;
|
|
1464
|
+
}
|
|
1465
|
+
toolCalls.push({
|
|
1466
|
+
toolCallId: block.id,
|
|
1467
|
+
toolName: block.name,
|
|
1468
|
+
arguments: args
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
const message = new AssistantMessage(
|
|
1473
|
+
textContent,
|
|
1474
|
+
toolCalls.length > 0 ? toolCalls : void 0,
|
|
1475
|
+
{
|
|
1476
|
+
id: state.messageId,
|
|
1477
|
+
metadata: {
|
|
1478
|
+
xai: {
|
|
1479
|
+
stop_reason: state.stopReason,
|
|
1480
|
+
model: state.model
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
);
|
|
1485
|
+
const usage = {
|
|
1486
|
+
inputTokens: state.inputTokens,
|
|
1487
|
+
outputTokens: state.outputTokens,
|
|
1488
|
+
totalTokens: state.inputTokens + state.outputTokens
|
|
1489
|
+
};
|
|
1490
|
+
return {
|
|
1491
|
+
message,
|
|
1492
|
+
usage,
|
|
1493
|
+
stopReason: state.stopReason ?? "end_turn",
|
|
1494
|
+
data: structuredData
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
// src/providers/xai/llm.messages.ts
|
|
1499
|
+
var XAI_MESSAGES_API_URL = "https://api.x.ai/v1/messages";
|
|
1500
|
+
var XAI_MESSAGES_CAPABILITIES = {
|
|
1501
|
+
streaming: true,
|
|
1502
|
+
tools: true,
|
|
1503
|
+
structuredOutput: true,
|
|
1504
|
+
imageInput: true,
|
|
1505
|
+
videoInput: false,
|
|
1506
|
+
audioInput: false
|
|
1507
|
+
};
|
|
1508
|
+
function createMessagesLLMHandler() {
|
|
1509
|
+
let providerRef = null;
|
|
1510
|
+
return {
|
|
1511
|
+
_setProvider(provider) {
|
|
1512
|
+
providerRef = provider;
|
|
1513
|
+
},
|
|
1514
|
+
bind(modelId) {
|
|
1515
|
+
if (!providerRef) {
|
|
1516
|
+
throw new UPPError(
|
|
1517
|
+
"Provider reference not set. Handler must be used with createProvider() or have _setProvider called.",
|
|
1518
|
+
"INVALID_REQUEST",
|
|
1519
|
+
"xai",
|
|
1520
|
+
"llm"
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
const model = {
|
|
1524
|
+
modelId,
|
|
1525
|
+
capabilities: XAI_MESSAGES_CAPABILITIES,
|
|
1526
|
+
get provider() {
|
|
1527
|
+
return providerRef;
|
|
1528
|
+
},
|
|
1529
|
+
async complete(request) {
|
|
1530
|
+
const apiKey = await resolveApiKey(
|
|
1531
|
+
request.config,
|
|
1532
|
+
"XAI_API_KEY",
|
|
1533
|
+
"xai",
|
|
1534
|
+
"llm"
|
|
1535
|
+
);
|
|
1536
|
+
const baseUrl = request.config.baseUrl ?? XAI_MESSAGES_API_URL;
|
|
1537
|
+
const body = transformRequest3(request, modelId);
|
|
1538
|
+
const response = await doFetch(
|
|
1539
|
+
baseUrl,
|
|
1540
|
+
{
|
|
1541
|
+
method: "POST",
|
|
1542
|
+
headers: {
|
|
1543
|
+
"Content-Type": "application/json",
|
|
1544
|
+
"x-api-key": apiKey,
|
|
1545
|
+
"anthropic-version": "2023-06-01"
|
|
1546
|
+
},
|
|
1547
|
+
body: JSON.stringify(body),
|
|
1548
|
+
signal: request.signal
|
|
1549
|
+
},
|
|
1550
|
+
request.config,
|
|
1551
|
+
"xai",
|
|
1552
|
+
"llm"
|
|
1553
|
+
);
|
|
1554
|
+
const data = await response.json();
|
|
1555
|
+
return transformResponse3(data);
|
|
1556
|
+
},
|
|
1557
|
+
stream(request) {
|
|
1558
|
+
const state = createStreamState3();
|
|
1559
|
+
let responseResolve;
|
|
1560
|
+
let responseReject;
|
|
1561
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
1562
|
+
responseResolve = resolve;
|
|
1563
|
+
responseReject = reject;
|
|
1564
|
+
});
|
|
1565
|
+
async function* generateEvents() {
|
|
1566
|
+
try {
|
|
1567
|
+
const apiKey = await resolveApiKey(
|
|
1568
|
+
request.config,
|
|
1569
|
+
"XAI_API_KEY",
|
|
1570
|
+
"xai",
|
|
1571
|
+
"llm"
|
|
1572
|
+
);
|
|
1573
|
+
const baseUrl = request.config.baseUrl ?? XAI_MESSAGES_API_URL;
|
|
1574
|
+
const body = transformRequest3(request, modelId);
|
|
1575
|
+
body.stream = true;
|
|
1576
|
+
const response = await doStreamFetch(
|
|
1577
|
+
baseUrl,
|
|
1578
|
+
{
|
|
1579
|
+
method: "POST",
|
|
1580
|
+
headers: {
|
|
1581
|
+
"Content-Type": "application/json",
|
|
1582
|
+
"x-api-key": apiKey,
|
|
1583
|
+
"anthropic-version": "2023-06-01"
|
|
1584
|
+
},
|
|
1585
|
+
body: JSON.stringify(body),
|
|
1586
|
+
signal: request.signal
|
|
1587
|
+
},
|
|
1588
|
+
request.config,
|
|
1589
|
+
"xai",
|
|
1590
|
+
"llm"
|
|
1591
|
+
);
|
|
1592
|
+
if (!response.ok) {
|
|
1593
|
+
const error = await normalizeHttpError(response, "xai", "llm");
|
|
1594
|
+
responseReject(error);
|
|
1595
|
+
throw error;
|
|
1596
|
+
}
|
|
1597
|
+
if (!response.body) {
|
|
1598
|
+
const error = new UPPError(
|
|
1599
|
+
"No response body for streaming request",
|
|
1600
|
+
"PROVIDER_ERROR",
|
|
1601
|
+
"xai",
|
|
1602
|
+
"llm"
|
|
1603
|
+
);
|
|
1604
|
+
responseReject(error);
|
|
1605
|
+
throw error;
|
|
1606
|
+
}
|
|
1607
|
+
for await (const data of parseSSEStream(response.body)) {
|
|
1608
|
+
if (typeof data === "object" && data !== null && "type" in data) {
|
|
1609
|
+
const event = data;
|
|
1610
|
+
if (event.type === "error") {
|
|
1611
|
+
const error = new UPPError(
|
|
1612
|
+
event.error.message,
|
|
1613
|
+
"PROVIDER_ERROR",
|
|
1614
|
+
"xai",
|
|
1615
|
+
"llm"
|
|
1616
|
+
);
|
|
1617
|
+
responseReject(error);
|
|
1618
|
+
throw error;
|
|
1619
|
+
}
|
|
1620
|
+
const uppEvent = transformStreamEvent3(event, state);
|
|
1621
|
+
if (uppEvent) {
|
|
1622
|
+
yield uppEvent;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
responseResolve(buildResponseFromState3(state));
|
|
1627
|
+
} catch (error) {
|
|
1628
|
+
responseReject(error);
|
|
1629
|
+
throw error;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return {
|
|
1633
|
+
[Symbol.asyncIterator]() {
|
|
1634
|
+
return generateEvents();
|
|
1635
|
+
},
|
|
1636
|
+
response: responsePromise
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
};
|
|
1640
|
+
return model;
|
|
1641
|
+
}
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
// src/providers/xai/index.ts
|
|
1646
|
+
function createXAIProvider() {
|
|
1647
|
+
let currentApiMode = "completions";
|
|
1648
|
+
const completionsHandler = createCompletionsLLMHandler();
|
|
1649
|
+
const responsesHandler = createResponsesLLMHandler();
|
|
1650
|
+
const messagesHandler = createMessagesLLMHandler();
|
|
1651
|
+
const fn = function(modelId, options) {
|
|
1652
|
+
const apiMode = options?.api ?? "completions";
|
|
1653
|
+
currentApiMode = apiMode;
|
|
1654
|
+
return { modelId, provider };
|
|
1655
|
+
};
|
|
1656
|
+
const modalities = {
|
|
1657
|
+
get llm() {
|
|
1658
|
+
switch (currentApiMode) {
|
|
1659
|
+
case "responses":
|
|
1660
|
+
return responsesHandler;
|
|
1661
|
+
case "messages":
|
|
1662
|
+
return messagesHandler;
|
|
1663
|
+
case "completions":
|
|
1664
|
+
default:
|
|
1665
|
+
return completionsHandler;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
Object.defineProperties(fn, {
|
|
1670
|
+
name: {
|
|
1671
|
+
value: "xai",
|
|
1672
|
+
writable: false,
|
|
1673
|
+
configurable: true
|
|
1674
|
+
},
|
|
1675
|
+
version: {
|
|
1676
|
+
value: "1.0.0",
|
|
1677
|
+
writable: false,
|
|
1678
|
+
configurable: true
|
|
1679
|
+
},
|
|
1680
|
+
modalities: {
|
|
1681
|
+
value: modalities,
|
|
1682
|
+
writable: false,
|
|
1683
|
+
configurable: true
|
|
1684
|
+
}
|
|
1685
|
+
});
|
|
1686
|
+
const provider = fn;
|
|
1687
|
+
completionsHandler._setProvider?.(provider);
|
|
1688
|
+
responsesHandler._setProvider?.(provider);
|
|
1689
|
+
messagesHandler._setProvider?.(provider);
|
|
1690
|
+
return provider;
|
|
1691
|
+
}
|
|
1692
|
+
var xai = createXAIProvider();
|
|
1693
|
+
export {
|
|
1694
|
+
xai
|
|
1695
|
+
};
|
|
1696
|
+
//# sourceMappingURL=index.js.map
|