@prestyj/ai 4.3.210 → 4.3.237
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 +1 -1
- package/dist/index.cjs +323 -191
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +319 -190
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
// src/errors.ts
|
|
2
|
+
function readHeader(headers, ...names) {
|
|
3
|
+
if (!headers) return void 0;
|
|
4
|
+
const getter = typeof headers.get === "function" ? (name) => headers.get(name) ?? void 0 : typeof headers === "object" ? (name) => {
|
|
5
|
+
const rec = headers;
|
|
6
|
+
const value = rec[name] ?? rec[name.toLowerCase()];
|
|
7
|
+
return typeof value === "string" ? value : void 0;
|
|
8
|
+
} : void 0;
|
|
9
|
+
if (!getter) return void 0;
|
|
10
|
+
for (const name of names) {
|
|
11
|
+
const value = getter(name);
|
|
12
|
+
if (value != null) return value;
|
|
13
|
+
}
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
2
16
|
var EZCoderAIError = class extends Error {
|
|
3
17
|
source;
|
|
4
18
|
requestId;
|
|
@@ -14,6 +28,8 @@ var EZCoderAIError = class extends Error {
|
|
|
14
28
|
var ProviderError = class extends EZCoderAIError {
|
|
15
29
|
provider;
|
|
16
30
|
statusCode;
|
|
31
|
+
/** Unix seconds when a usage/rate limit resets, when the provider reports it. */
|
|
32
|
+
resetsAt;
|
|
17
33
|
constructor(provider, message, options) {
|
|
18
34
|
super(message, {
|
|
19
35
|
source: "provider",
|
|
@@ -24,6 +40,7 @@ var ProviderError = class extends EZCoderAIError {
|
|
|
24
40
|
this.name = "ProviderError";
|
|
25
41
|
this.provider = provider;
|
|
26
42
|
this.statusCode = options?.statusCode;
|
|
43
|
+
this.resetsAt = options?.resetsAt;
|
|
27
44
|
}
|
|
28
45
|
};
|
|
29
46
|
var PROVIDER_DISPLAY = {
|
|
@@ -44,10 +61,36 @@ var PROVIDER_STATUS_URL = {
|
|
|
44
61
|
function providerDisplayName(provider) {
|
|
45
62
|
return PROVIDER_DISPLAY[provider] ?? provider;
|
|
46
63
|
}
|
|
64
|
+
function isUsageLimitError(err) {
|
|
65
|
+
if (!(err instanceof Error)) return false;
|
|
66
|
+
return /usage limit reached/i.test(err.message);
|
|
67
|
+
}
|
|
68
|
+
function formatResetTime(resetsAt) {
|
|
69
|
+
const when = new Date(resetsAt * 1e3);
|
|
70
|
+
const sameDay = when.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
|
|
71
|
+
return sameDay ? when.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" }) : when.toLocaleString(void 0, {
|
|
72
|
+
weekday: "short",
|
|
73
|
+
hour: "numeric",
|
|
74
|
+
minute: "2-digit"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
47
77
|
function formatError(err) {
|
|
48
78
|
if (err instanceof ProviderError) {
|
|
49
79
|
const name = providerDisplayName(err.provider);
|
|
50
80
|
const cleanMessage = cleanProviderMessage(err.message);
|
|
81
|
+
if (isUsageLimitError(err)) {
|
|
82
|
+
const resetClause = err.resetsAt ? ` It resets at ${formatResetTime(err.resetsAt)}.` : "";
|
|
83
|
+
return {
|
|
84
|
+
headline: `${name} usage limit reached.`,
|
|
85
|
+
source: "provider",
|
|
86
|
+
message: `Your ${name} usage is finished.${resetClause}`,
|
|
87
|
+
provider: err.provider,
|
|
88
|
+
statusCode: err.statusCode,
|
|
89
|
+
...err.requestId ? { requestId: err.requestId } : {},
|
|
90
|
+
...err.resetsAt ? { resetsAt: err.resetsAt } : {},
|
|
91
|
+
guidance: "Try again once it's back. Your conversation is preserved."
|
|
92
|
+
};
|
|
93
|
+
}
|
|
51
94
|
return {
|
|
52
95
|
headline: `${name} returned an error.`,
|
|
53
96
|
source: "provider",
|
|
@@ -271,6 +314,9 @@ function zodToJsonSchema(schema) {
|
|
|
271
314
|
const { $schema: _schema, ...rest } = jsonSchema;
|
|
272
315
|
return normalizeRootForAnthropic(rest);
|
|
273
316
|
}
|
|
317
|
+
function resolveToolSchema(tool) {
|
|
318
|
+
return tool.rawInputSchema ?? zodToJsonSchema(tool.parameters);
|
|
319
|
+
}
|
|
274
320
|
function normalizeRootForAnthropic(schema) {
|
|
275
321
|
const branches = schema.oneOf ?? schema.anyOf;
|
|
276
322
|
if (!branches || branches.length === 0) {
|
|
@@ -327,6 +373,61 @@ function normalizeRootForAnthropic(schema) {
|
|
|
327
373
|
}
|
|
328
374
|
|
|
329
375
|
// src/providers/transform.ts
|
|
376
|
+
function hasValidThinkingSignature(part) {
|
|
377
|
+
return typeof part.signature === "string" && part.signature.trim().length > 0;
|
|
378
|
+
}
|
|
379
|
+
function isRawThinking(part) {
|
|
380
|
+
if (part.type !== "raw") return false;
|
|
381
|
+
const t = part.data.type;
|
|
382
|
+
return t === "thinking" || t === "redacted_thinking";
|
|
383
|
+
}
|
|
384
|
+
function isPositionSensitiveThinking(part) {
|
|
385
|
+
if (part.type === "thinking") return hasValidThinkingSignature(part);
|
|
386
|
+
return isRawThinking(part);
|
|
387
|
+
}
|
|
388
|
+
function toAnthropicAssistantPart(part, idMap) {
|
|
389
|
+
if (part.type === "text") return { type: "text", text: part.text };
|
|
390
|
+
if (part.type === "thinking") {
|
|
391
|
+
const sig = part.signature;
|
|
392
|
+
return sig && sig.trim().length > 0 ? { type: "thinking", thinking: part.text, signature: sig } : { type: "text", text: part.text };
|
|
393
|
+
}
|
|
394
|
+
if (part.type === "tool_call")
|
|
395
|
+
return {
|
|
396
|
+
type: "tool_use",
|
|
397
|
+
id: remapAnthropicToolCallId(part.id, idMap),
|
|
398
|
+
name: part.name,
|
|
399
|
+
input: part.args
|
|
400
|
+
};
|
|
401
|
+
if (part.type === "server_tool_call")
|
|
402
|
+
return {
|
|
403
|
+
type: "server_tool_use",
|
|
404
|
+
id: part.id,
|
|
405
|
+
name: part.name,
|
|
406
|
+
input: part.input
|
|
407
|
+
};
|
|
408
|
+
if (part.type === "server_tool_result")
|
|
409
|
+
return part.data;
|
|
410
|
+
if (part.type === "raw") return part.data;
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
function toAnthropicAssistantContent(content, isLatest, idMap) {
|
|
414
|
+
if (!isLatest) {
|
|
415
|
+
return content.filter((part) => {
|
|
416
|
+
if (part.type === "thinking" || isRawThinking(part)) return false;
|
|
417
|
+
if (part.type === "text" && !part.text) return false;
|
|
418
|
+
return true;
|
|
419
|
+
}).map((part) => toAnthropicAssistantPart(part, idMap)).filter((b) => b !== null);
|
|
420
|
+
}
|
|
421
|
+
const lastThinkingIdx = content.reduce(
|
|
422
|
+
(last, part, idx) => isPositionSensitiveThinking(part) ? idx : last,
|
|
423
|
+
-1
|
|
424
|
+
);
|
|
425
|
+
return content.filter((part, idx) => {
|
|
426
|
+
if (part.type === "thinking" && !hasValidThinkingSignature(part) && !part.text) return false;
|
|
427
|
+
if (part.type === "text" && !part.text && idx > lastThinkingIdx) return false;
|
|
428
|
+
return true;
|
|
429
|
+
}).map((part) => toAnthropicAssistantPart(part, idMap)).filter((b) => b !== null);
|
|
430
|
+
}
|
|
330
431
|
var NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
|
|
331
432
|
var NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
|
|
332
433
|
function stripImages(content, placeholder) {
|
|
@@ -403,7 +504,13 @@ function toAnthropicMessages(messages, cacheControl) {
|
|
|
403
504
|
let systemText;
|
|
404
505
|
const out = [];
|
|
405
506
|
const idMap = /* @__PURE__ */ new Map();
|
|
507
|
+
const lastAssistantIdx = messages.reduce(
|
|
508
|
+
(last, m, i) => m.role === "assistant" ? i : last,
|
|
509
|
+
-1
|
|
510
|
+
);
|
|
511
|
+
let msgIdx = -1;
|
|
406
512
|
for (const msg of messages) {
|
|
513
|
+
msgIdx++;
|
|
407
514
|
if (msg.role === "system") {
|
|
408
515
|
systemText = msg.content;
|
|
409
516
|
continue;
|
|
@@ -426,33 +533,7 @@ function toAnthropicMessages(messages, cacheControl) {
|
|
|
426
533
|
continue;
|
|
427
534
|
}
|
|
428
535
|
if (msg.role === "assistant") {
|
|
429
|
-
const content = typeof msg.content === "string" ? msg.content : msg.content
|
|
430
|
-
if (part.type === "thinking" && !part.signature) return false;
|
|
431
|
-
if (part.type === "text" && !part.text) return false;
|
|
432
|
-
return true;
|
|
433
|
-
}).map((part) => {
|
|
434
|
-
if (part.type === "text") return { type: "text", text: part.text };
|
|
435
|
-
if (part.type === "thinking")
|
|
436
|
-
return { type: "thinking", thinking: part.text, signature: part.signature };
|
|
437
|
-
if (part.type === "tool_call")
|
|
438
|
-
return {
|
|
439
|
-
type: "tool_use",
|
|
440
|
-
id: remapAnthropicToolCallId(part.id, idMap),
|
|
441
|
-
name: part.name,
|
|
442
|
-
input: part.args
|
|
443
|
-
};
|
|
444
|
-
if (part.type === "server_tool_call")
|
|
445
|
-
return {
|
|
446
|
-
type: "server_tool_use",
|
|
447
|
-
id: part.id,
|
|
448
|
-
name: part.name,
|
|
449
|
-
input: part.input
|
|
450
|
-
};
|
|
451
|
-
if (part.type === "server_tool_result")
|
|
452
|
-
return part.data;
|
|
453
|
-
if (part.type === "raw") return part.data;
|
|
454
|
-
return null;
|
|
455
|
-
}).filter(Boolean);
|
|
536
|
+
const content = typeof msg.content === "string" ? msg.content : toAnthropicAssistantContent(msg.content, msgIdx === lastAssistantIdx, idMap);
|
|
456
537
|
if (Array.isArray(content) && content.length === 0) continue;
|
|
457
538
|
out.push({ role: "assistant", content });
|
|
458
539
|
continue;
|
|
@@ -538,13 +619,13 @@ function toAnthropicToolChoice(choice) {
|
|
|
538
619
|
if (choice === "required") return { type: "any" };
|
|
539
620
|
return { type: "tool", name: choice.name };
|
|
540
621
|
}
|
|
541
|
-
function
|
|
542
|
-
return /opus-4-7|opus-4
|
|
622
|
+
function isAdaptiveThinkingModel(model) {
|
|
623
|
+
return /opus-4[-.]8|opus-4[-.]7|opus-4[-.]6|sonnet-4[-.]6/.test(model);
|
|
543
624
|
}
|
|
544
625
|
function toAnthropicThinking(level, maxTokens, model) {
|
|
545
|
-
if (
|
|
546
|
-
let effort = level
|
|
547
|
-
if (effort === "
|
|
626
|
+
if (isAdaptiveThinkingModel(model)) {
|
|
627
|
+
let effort = level;
|
|
628
|
+
if (effort === "xhigh" && !/opus-4-8|opus-4-7/.test(model)) {
|
|
548
629
|
effort = "high";
|
|
549
630
|
}
|
|
550
631
|
return {
|
|
@@ -553,7 +634,7 @@ function toAnthropicThinking(level, maxTokens, model) {
|
|
|
553
634
|
outputConfig: { effort }
|
|
554
635
|
};
|
|
555
636
|
}
|
|
556
|
-
const effectiveLevel = level === "xhigh" ? "high" : level;
|
|
637
|
+
const effectiveLevel = level === "xhigh" || level === "max" ? "high" : level;
|
|
557
638
|
const budgetMap = {
|
|
558
639
|
low: Math.max(1024, Math.floor(maxTokens * 0.25)),
|
|
559
640
|
medium: Math.max(2048, Math.floor(maxTokens * 0.5)),
|
|
@@ -676,7 +757,7 @@ function toOpenAITools(tools) {
|
|
|
676
757
|
function: {
|
|
677
758
|
name: tool.name,
|
|
678
759
|
description: tool.description,
|
|
679
|
-
parameters:
|
|
760
|
+
parameters: resolveToolSchema(tool)
|
|
680
761
|
}
|
|
681
762
|
}));
|
|
682
763
|
}
|
|
@@ -687,7 +768,7 @@ function toOpenAIToolChoice(choice) {
|
|
|
687
768
|
return { type: "function", function: { name: choice.name } };
|
|
688
769
|
}
|
|
689
770
|
function toOpenAIReasoningEffort(level, _model) {
|
|
690
|
-
return level;
|
|
771
|
+
return level === "max" ? "xhigh" : level;
|
|
691
772
|
}
|
|
692
773
|
function normalizeAnthropicStopReason(reason) {
|
|
693
774
|
switch (reason) {
|
|
@@ -718,10 +799,22 @@ function normalizeOpenAIStopReason(reason) {
|
|
|
718
799
|
}
|
|
719
800
|
}
|
|
720
801
|
|
|
721
|
-
// src/
|
|
802
|
+
// src/utils/json.ts
|
|
722
803
|
function isJsonObject(value) {
|
|
723
804
|
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
724
805
|
}
|
|
806
|
+
function parseToolArguments(argsJson) {
|
|
807
|
+
if (!argsJson) return {};
|
|
808
|
+
try {
|
|
809
|
+
const parsed = JSON.parse(argsJson);
|
|
810
|
+
const unwrapped = typeof parsed === "string" ? JSON.parse(parsed) : parsed;
|
|
811
|
+
return isJsonObject(unwrapped) ? unwrapped : {};
|
|
812
|
+
} catch {
|
|
813
|
+
return {};
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// src/providers/anthropic.ts
|
|
725
818
|
function createClient(options) {
|
|
726
819
|
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
727
820
|
return new Anthropic({
|
|
@@ -814,7 +907,7 @@ async function* runStream(options) {
|
|
|
814
907
|
})(),
|
|
815
908
|
stream: useStreaming
|
|
816
909
|
};
|
|
817
|
-
const hasAdaptiveThinking =
|
|
910
|
+
const hasAdaptiveThinking = isAdaptiveThinkingModel(options.model);
|
|
818
911
|
const betaHeaders = [
|
|
819
912
|
...isOAuth ? ["claude-code-20250219", "oauth-2025-04-20"] : [],
|
|
820
913
|
...options.compaction ? ["compact-2026-01-12"] : [],
|
|
@@ -1138,6 +1231,18 @@ function messageToResponse(message) {
|
|
|
1138
1231
|
}
|
|
1139
1232
|
};
|
|
1140
1233
|
}
|
|
1234
|
+
function readUnifiedRateLimit(headers) {
|
|
1235
|
+
const status = readHeader(headers, "anthropic-ratelimit-unified-status");
|
|
1236
|
+
const resetRaw = readHeader(
|
|
1237
|
+
headers,
|
|
1238
|
+
"anthropic-ratelimit-unified-reset",
|
|
1239
|
+
"anthropic-ratelimit-unified-5h-reset",
|
|
1240
|
+
"anthropic-ratelimit-unified-7d-reset"
|
|
1241
|
+
);
|
|
1242
|
+
const resetNum = resetRaw != null ? Number(resetRaw) : Number.NaN;
|
|
1243
|
+
const resetsAt = Number.isFinite(resetNum) && resetNum > 0 ? resetNum : void 0;
|
|
1244
|
+
return { rejected: status === "rejected", ...resetsAt ? { resetsAt } : {} };
|
|
1245
|
+
}
|
|
1141
1246
|
function toError(err) {
|
|
1142
1247
|
if (err instanceof Anthropic.APIError) {
|
|
1143
1248
|
const errorBody = err.error;
|
|
@@ -1146,6 +1251,18 @@ function toError(err) {
|
|
|
1146
1251
|
const bodyMessage = typeof nestedError?.message === "string" ? nestedError.message : typeof errorBody?.message === "string" ? errorBody.message : void 0;
|
|
1147
1252
|
const bodyType = typeof nestedError?.type === "string" ? nestedError.type : typeof errorBody?.type === "string" ? errorBody.type : typeof err.type === "string" ? err.type : void 0;
|
|
1148
1253
|
const message = bodyType && bodyMessage ? `${bodyType}: ${bodyMessage}` : bodyMessage ?? err.message;
|
|
1254
|
+
if (err.status === 429) {
|
|
1255
|
+
const limit = readUnifiedRateLimit(err.headers);
|
|
1256
|
+
const farOff = limit.resetsAt != null && limit.resetsAt * 1e3 - Date.now() > 6e4;
|
|
1257
|
+
if (limit.rejected || farOff) {
|
|
1258
|
+
return new ProviderError("anthropic", "Claude usage limit reached", {
|
|
1259
|
+
statusCode: 429,
|
|
1260
|
+
...requestId ? { requestId } : {},
|
|
1261
|
+
...limit.resetsAt ? { resetsAt: limit.resetsAt } : {},
|
|
1262
|
+
cause: err
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1149
1266
|
return new ProviderError("anthropic", message, {
|
|
1150
1267
|
statusCode: err.status,
|
|
1151
1268
|
...requestId ? { requestId } : {},
|
|
@@ -1178,19 +1295,30 @@ function fnv1aHash(value) {
|
|
|
1178
1295
|
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
1179
1296
|
}
|
|
1180
1297
|
|
|
1181
|
-
// src/
|
|
1182
|
-
function
|
|
1183
|
-
return
|
|
1298
|
+
// src/utils/env.ts
|
|
1299
|
+
function getEnvironment() {
|
|
1300
|
+
return globalThis.process?.env;
|
|
1184
1301
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
return {};
|
|
1302
|
+
|
|
1303
|
+
// src/providers/openai.ts
|
|
1304
|
+
function extractOpenAIUsage(usage) {
|
|
1305
|
+
let cacheRead = 0;
|
|
1306
|
+
const details = usage.prompt_tokens_details;
|
|
1307
|
+
if (details?.cached_tokens) {
|
|
1308
|
+
cacheRead = details.cached_tokens;
|
|
1193
1309
|
}
|
|
1310
|
+
const usageAny = usage;
|
|
1311
|
+
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
1312
|
+
cacheRead = usageAny.cached_tokens;
|
|
1313
|
+
}
|
|
1314
|
+
if (!cacheRead && typeof usageAny.prompt_cache_hit_tokens === "number" && usageAny.prompt_cache_hit_tokens > 0) {
|
|
1315
|
+
cacheRead = usageAny.prompt_cache_hit_tokens;
|
|
1316
|
+
}
|
|
1317
|
+
return {
|
|
1318
|
+
inputTokens: usage.prompt_tokens - cacheRead,
|
|
1319
|
+
outputTokens: usage.completion_tokens,
|
|
1320
|
+
cacheRead
|
|
1321
|
+
};
|
|
1194
1322
|
}
|
|
1195
1323
|
function createClient2(options) {
|
|
1196
1324
|
return new OpenAI({
|
|
@@ -1246,7 +1374,7 @@ async function* runStream2(options) {
|
|
|
1246
1374
|
params.thinking = { type: "disabled" };
|
|
1247
1375
|
}
|
|
1248
1376
|
}
|
|
1249
|
-
if (
|
|
1377
|
+
if (getEnvironment()?.GGAI_DUMP_REQUEST) {
|
|
1250
1378
|
const fs = await import("fs");
|
|
1251
1379
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1252
1380
|
const dumpPath = `/tmp/ggai-request-${ts}.json`;
|
|
@@ -1287,19 +1415,7 @@ async function* runStream2(options) {
|
|
|
1287
1415
|
for await (const chunk of stream2) {
|
|
1288
1416
|
const choice = chunk.choices?.[0];
|
|
1289
1417
|
if (chunk.usage) {
|
|
1290
|
-
outputTokens = chunk.usage
|
|
1291
|
-
const details = chunk.usage.prompt_tokens_details;
|
|
1292
|
-
if (details?.cached_tokens) {
|
|
1293
|
-
cacheRead = details.cached_tokens;
|
|
1294
|
-
}
|
|
1295
|
-
const usageAny = chunk.usage;
|
|
1296
|
-
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
1297
|
-
cacheRead = usageAny.cached_tokens;
|
|
1298
|
-
}
|
|
1299
|
-
if (!cacheRead && typeof usageAny.prompt_cache_hit_tokens === "number" && usageAny.prompt_cache_hit_tokens > 0) {
|
|
1300
|
-
cacheRead = usageAny.prompt_cache_hit_tokens;
|
|
1301
|
-
}
|
|
1302
|
-
inputTokens = chunk.usage.prompt_tokens - cacheRead;
|
|
1418
|
+
({ inputTokens, outputTokens, cacheRead } = extractOpenAIUsage(chunk.usage));
|
|
1303
1419
|
}
|
|
1304
1420
|
if (!choice) continue;
|
|
1305
1421
|
if (choice.finish_reason) {
|
|
@@ -1445,17 +1561,7 @@ function completionToResponse(completion) {
|
|
|
1445
1561
|
let outputTokens = 0;
|
|
1446
1562
|
let cacheRead = 0;
|
|
1447
1563
|
if (completion.usage) {
|
|
1448
|
-
outputTokens = completion.usage
|
|
1449
|
-
const details = completion.usage.prompt_tokens_details;
|
|
1450
|
-
if (details?.cached_tokens) cacheRead = details.cached_tokens;
|
|
1451
|
-
const usageAny = completion.usage;
|
|
1452
|
-
if (!cacheRead && typeof usageAny.cached_tokens === "number" && usageAny.cached_tokens > 0) {
|
|
1453
|
-
cacheRead = usageAny.cached_tokens;
|
|
1454
|
-
}
|
|
1455
|
-
if (!cacheRead && typeof usageAny.prompt_cache_hit_tokens === "number" && usageAny.prompt_cache_hit_tokens > 0) {
|
|
1456
|
-
cacheRead = usageAny.prompt_cache_hit_tokens;
|
|
1457
|
-
}
|
|
1458
|
-
inputTokens = completion.usage.prompt_tokens - cacheRead;
|
|
1564
|
+
({ inputTokens, outputTokens, cacheRead } = extractOpenAIUsage(completion.usage));
|
|
1459
1565
|
}
|
|
1460
1566
|
const stopReason = normalizeOpenAIStopReason(choice?.finish_reason ?? null);
|
|
1461
1567
|
return {
|
|
@@ -1503,24 +1609,65 @@ function providerDiag(phase, data) {
|
|
|
1503
1609
|
_diagFn?.(phase, data);
|
|
1504
1610
|
}
|
|
1505
1611
|
|
|
1506
|
-
// src/
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1612
|
+
// src/utils/sse.ts
|
|
1613
|
+
function parseSseBuffer(buffer) {
|
|
1614
|
+
const events = [];
|
|
1615
|
+
let cursor = 0;
|
|
1616
|
+
while (true) {
|
|
1617
|
+
const next = buffer.indexOf("\n\n", cursor);
|
|
1618
|
+
if (next === -1) break;
|
|
1619
|
+
const raw = buffer.slice(cursor, next);
|
|
1620
|
+
cursor = next + 2;
|
|
1621
|
+
let eventName;
|
|
1622
|
+
const dataLines = [];
|
|
1623
|
+
for (const line of raw.split("\n")) {
|
|
1624
|
+
if (line.startsWith("event:")) {
|
|
1625
|
+
eventName = line.slice("event:".length).trim();
|
|
1626
|
+
} else if (line.startsWith("data:")) {
|
|
1627
|
+
dataLines.push(line.slice("data:".length).trimStart());
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
if (dataLines.length > 0) {
|
|
1631
|
+
events.push({ event: eventName, data: dataLines.join("\n") });
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
return { events, remaining: buffer.slice(cursor) };
|
|
1510
1635
|
}
|
|
1511
|
-
function
|
|
1512
|
-
|
|
1636
|
+
async function* readSseStream(body) {
|
|
1637
|
+
const reader = body.getReader();
|
|
1638
|
+
const decoder = new TextDecoder();
|
|
1639
|
+
let buffer = "";
|
|
1513
1640
|
try {
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1641
|
+
while (true) {
|
|
1642
|
+
const { done, value } = await reader.read();
|
|
1643
|
+
if (done) break;
|
|
1644
|
+
buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, "\n");
|
|
1645
|
+
const parsed2 = parseSseBuffer(buffer);
|
|
1646
|
+
buffer = parsed2.remaining;
|
|
1647
|
+
yield* parsed2.events;
|
|
1648
|
+
}
|
|
1649
|
+
buffer += decoder.decode().replace(/\r\n/g, "\n");
|
|
1650
|
+
const parsed = parseSseBuffer(buffer + "\n\n");
|
|
1651
|
+
yield* parsed.events;
|
|
1652
|
+
} finally {
|
|
1653
|
+
reader.releaseLock();
|
|
1519
1654
|
}
|
|
1520
1655
|
}
|
|
1656
|
+
|
|
1657
|
+
// src/utils/request-id.ts
|
|
1658
|
+
function extractRequestIdFromMessage(message) {
|
|
1659
|
+
const match = message.match(/request ID ([a-z0-9-]{8,})/i);
|
|
1660
|
+
return match?.[1];
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
// src/providers/openai-codex.ts
|
|
1664
|
+
var DEFAULT_BASE_URL = "https://chatgpt.com/backend-api";
|
|
1521
1665
|
function outputTextKey(itemId, contentIndex) {
|
|
1522
1666
|
return `${itemId ?? ""}:${contentIndex ?? 0}`;
|
|
1523
1667
|
}
|
|
1668
|
+
function isVisibleOutputItem(itemType) {
|
|
1669
|
+
return itemType === "message";
|
|
1670
|
+
}
|
|
1524
1671
|
function streamOpenAICodex(options) {
|
|
1525
1672
|
return new StreamResult(runStream3(options));
|
|
1526
1673
|
}
|
|
@@ -1579,7 +1726,9 @@ async function* runStream3(options) {
|
|
|
1579
1726
|
const text = await response.text().catch(() => "");
|
|
1580
1727
|
const parsed = parseCodexErrorBody(text);
|
|
1581
1728
|
const message = parsed.message ?? `Codex API returned HTTP ${response.status}.`;
|
|
1582
|
-
const requestId = parsed.requestId ?? response.headers
|
|
1729
|
+
const requestId = parsed.requestId ?? readHeader(response.headers, "x-request-id", "openai-request-id", "x-oai-request-id");
|
|
1730
|
+
const usageLimit = codexUsageLimitError(parsed.errorObj, response.status, requestId);
|
|
1731
|
+
if (usageLimit) throw usageLimit;
|
|
1583
1732
|
let hint;
|
|
1584
1733
|
if (response.status === 400 && text.includes("not supported")) {
|
|
1585
1734
|
if (options.model === "gpt-5.5-pro") {
|
|
@@ -1604,6 +1753,7 @@ async function* runStream3(options) {
|
|
|
1604
1753
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
1605
1754
|
const outputItemTypes = /* @__PURE__ */ new Map();
|
|
1606
1755
|
const outputTextByPart = /* @__PURE__ */ new Map();
|
|
1756
|
+
const pendingOutputTextByPart = /* @__PURE__ */ new Map();
|
|
1607
1757
|
let inputTokens = 0;
|
|
1608
1758
|
let outputTokens = 0;
|
|
1609
1759
|
let cacheRead = 0;
|
|
@@ -1620,7 +1770,13 @@ async function* runStream3(options) {
|
|
|
1620
1770
|
const nested = event.error ?? void 0;
|
|
1621
1771
|
const message = nested?.message ?? event.message ?? "Codex stream emitted an error chunk without a message.";
|
|
1622
1772
|
const code = nested?.code ?? nested?.type ?? event.code ?? "server_error";
|
|
1623
|
-
const requestId =
|
|
1773
|
+
const requestId = extractRequestIdFromMessage(message) ?? event.request_id;
|
|
1774
|
+
const usageLimit = codexUsageLimitError(
|
|
1775
|
+
nested ?? event,
|
|
1776
|
+
void 0,
|
|
1777
|
+
requestId
|
|
1778
|
+
);
|
|
1779
|
+
if (usageLimit) throw usageLimit;
|
|
1624
1780
|
throw new ProviderError("openai", message, {
|
|
1625
1781
|
...requestId != null ? { requestId } : {},
|
|
1626
1782
|
...code === "server_error" ? { statusCode: 500 } : {}
|
|
@@ -1629,7 +1785,7 @@ async function* runStream3(options) {
|
|
|
1629
1785
|
if (type === "response.failed") {
|
|
1630
1786
|
const nested = event.error;
|
|
1631
1787
|
const message = nested?.message ?? "Codex response failed.";
|
|
1632
|
-
const requestId =
|
|
1788
|
+
const requestId = extractRequestIdFromMessage(message) ?? event.request_id;
|
|
1633
1789
|
throw new ProviderError("openai", message, {
|
|
1634
1790
|
...requestId != null ? { requestId } : {}
|
|
1635
1791
|
});
|
|
@@ -1640,11 +1796,17 @@ async function* runStream3(options) {
|
|
|
1640
1796
|
const contentIndex = event.content_index;
|
|
1641
1797
|
const key = outputTextKey(itemId, contentIndex);
|
|
1642
1798
|
outputTextByPart.set(key, `${outputTextByPart.get(key) ?? ""}${delta}`);
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
} else {
|
|
1799
|
+
const itemType = itemId ? outputItemTypes.get(itemId) : void 0;
|
|
1800
|
+
if (itemId && isVisibleOutputItem(itemType)) {
|
|
1646
1801
|
textAccum += delta;
|
|
1647
1802
|
yield { type: "text_delta", text: delta };
|
|
1803
|
+
} else if (itemId && itemType == null) {
|
|
1804
|
+
const pending = pendingOutputTextByPart.get(key);
|
|
1805
|
+
pendingOutputTextByPart.set(key, {
|
|
1806
|
+
itemId,
|
|
1807
|
+
contentIndex: contentIndex ?? 0,
|
|
1808
|
+
text: `${pending?.text ?? ""}${delta}`
|
|
1809
|
+
});
|
|
1648
1810
|
}
|
|
1649
1811
|
}
|
|
1650
1812
|
if (type === "response.output_text.done") {
|
|
@@ -1657,11 +1819,17 @@ async function* runStream3(options) {
|
|
|
1657
1819
|
const missingText = streamedText ? fullText.slice(streamedText.length) : fullText;
|
|
1658
1820
|
outputTextByPart.set(key, fullText);
|
|
1659
1821
|
if (missingText && fullText.startsWith(streamedText)) {
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
} else {
|
|
1822
|
+
const itemType = itemId ? outputItemTypes.get(itemId) : void 0;
|
|
1823
|
+
if (itemId && isVisibleOutputItem(itemType)) {
|
|
1663
1824
|
textAccum += missingText;
|
|
1664
1825
|
yield { type: "text_delta", text: missingText };
|
|
1826
|
+
} else if (itemId && itemType == null) {
|
|
1827
|
+
const pending = pendingOutputTextByPart.get(key);
|
|
1828
|
+
pendingOutputTextByPart.set(key, {
|
|
1829
|
+
itemId,
|
|
1830
|
+
contentIndex: contentIndex ?? 0,
|
|
1831
|
+
text: `${pending?.text ?? ""}${missingText}`
|
|
1832
|
+
});
|
|
1665
1833
|
}
|
|
1666
1834
|
}
|
|
1667
1835
|
}
|
|
@@ -1680,6 +1848,17 @@ async function* runStream3(options) {
|
|
|
1680
1848
|
if (itemType === "reasoning" && options.thinking) {
|
|
1681
1849
|
yield { type: "thinking_delta", text: "" };
|
|
1682
1850
|
}
|
|
1851
|
+
if (itemId && itemType) {
|
|
1852
|
+
const pending = [...pendingOutputTextByPart.entries()].filter(([, pendingPart]) => pendingPart.itemId === itemId).sort(([, a], [, b]) => a.contentIndex - b.contentIndex);
|
|
1853
|
+
for (const [key, pendingPart] of pending) {
|
|
1854
|
+
pendingOutputTextByPart.delete(key);
|
|
1855
|
+
if (!pendingPart.text) continue;
|
|
1856
|
+
if (isVisibleOutputItem(itemType)) {
|
|
1857
|
+
textAccum += pendingPart.text;
|
|
1858
|
+
yield { type: "text_delta", text: pendingPart.text };
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1683
1862
|
}
|
|
1684
1863
|
if (type === "response.output_item.added") {
|
|
1685
1864
|
const item = event.item;
|
|
@@ -1725,7 +1904,7 @@ async function* runStream3(options) {
|
|
|
1725
1904
|
const id = `${callId}|${itemId}`;
|
|
1726
1905
|
const tc = toolCalls.get(id);
|
|
1727
1906
|
if (tc) {
|
|
1728
|
-
const args =
|
|
1907
|
+
const args = parseToolArguments(tc.argsJson);
|
|
1729
1908
|
yield {
|
|
1730
1909
|
type: "toolcall_done",
|
|
1731
1910
|
id: tc.id,
|
|
@@ -1749,7 +1928,7 @@ async function* runStream3(options) {
|
|
|
1749
1928
|
contentParts.push({ type: "text", text: textAccum });
|
|
1750
1929
|
}
|
|
1751
1930
|
for (const [, tc] of toolCalls) {
|
|
1752
|
-
const args =
|
|
1931
|
+
const args = parseToolArguments(tc.argsJson);
|
|
1753
1932
|
const toolCall = {
|
|
1754
1933
|
type: "tool_call",
|
|
1755
1934
|
id: tc.id,
|
|
@@ -1772,33 +1951,13 @@ async function* runStream3(options) {
|
|
|
1772
1951
|
return streamResponse;
|
|
1773
1952
|
}
|
|
1774
1953
|
async function* parseSSE(body) {
|
|
1775
|
-
const
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
if (done) break;
|
|
1782
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1783
|
-
let idx = buffer.indexOf("\n\n");
|
|
1784
|
-
while (idx !== -1) {
|
|
1785
|
-
const chunk = buffer.slice(0, idx);
|
|
1786
|
-
buffer = buffer.slice(idx + 2);
|
|
1787
|
-
const dataLines = chunk.split("\n").filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trim());
|
|
1788
|
-
if (dataLines.length > 0) {
|
|
1789
|
-
const data = dataLines.join("\n").trim();
|
|
1790
|
-
if (data && data !== "[DONE]") {
|
|
1791
|
-
try {
|
|
1792
|
-
yield JSON.parse(data);
|
|
1793
|
-
} catch {
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
}
|
|
1797
|
-
idx = buffer.indexOf("\n\n");
|
|
1798
|
-
}
|
|
1954
|
+
for await (const event of readSseStream(body)) {
|
|
1955
|
+
const data = event.data.trim();
|
|
1956
|
+
if (!data || data === "[DONE]") continue;
|
|
1957
|
+
try {
|
|
1958
|
+
yield JSON.parse(data);
|
|
1959
|
+
} catch {
|
|
1799
1960
|
}
|
|
1800
|
-
} finally {
|
|
1801
|
-
reader.releaseLock();
|
|
1802
1961
|
}
|
|
1803
1962
|
}
|
|
1804
1963
|
function remapCodexId(id, idMap) {
|
|
@@ -1809,10 +1968,6 @@ function remapCodexId(id, idMap) {
|
|
|
1809
1968
|
idMap.set(id, mapped);
|
|
1810
1969
|
return mapped;
|
|
1811
1970
|
}
|
|
1812
|
-
function codexToolResultText(content) {
|
|
1813
|
-
if (typeof content === "string") return content;
|
|
1814
|
-
return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
1815
|
-
}
|
|
1816
1971
|
function toCodexInput(messages, options) {
|
|
1817
1972
|
let system;
|
|
1818
1973
|
const input = [];
|
|
@@ -1869,7 +2024,7 @@ function toCodexInput(messages, options) {
|
|
|
1869
2024
|
const toolImages = [];
|
|
1870
2025
|
for (const result of msg.content) {
|
|
1871
2026
|
const [callId] = result.toolCallId.includes("|") ? result.toolCallId.split("|", 2) : [result.toolCallId];
|
|
1872
|
-
const text =
|
|
2027
|
+
const text = toolResultText(result.content);
|
|
1873
2028
|
input.push({
|
|
1874
2029
|
type: "function_call_output",
|
|
1875
2030
|
call_id: remapCodexId(callId, idMap),
|
|
@@ -1904,14 +2059,10 @@ function toCodexTools(tools) {
|
|
|
1904
2059
|
type: "function",
|
|
1905
2060
|
name: tool.name,
|
|
1906
2061
|
description: tool.description,
|
|
1907
|
-
parameters:
|
|
2062
|
+
parameters: resolveToolSchema(tool),
|
|
1908
2063
|
strict: null
|
|
1909
2064
|
}));
|
|
1910
2065
|
}
|
|
1911
|
-
function extractCodexRequestId(message) {
|
|
1912
|
-
const match = message.match(/request ID ([a-z0-9-]{8,})/i);
|
|
1913
|
-
return match?.[1];
|
|
1914
|
-
}
|
|
1915
2066
|
function parseCodexErrorBody(text) {
|
|
1916
2067
|
if (!text) return {};
|
|
1917
2068
|
try {
|
|
@@ -1919,13 +2070,35 @@ function parseCodexErrorBody(text) {
|
|
|
1919
2070
|
const error = parsed.error;
|
|
1920
2071
|
const detail = parsed.detail;
|
|
1921
2072
|
const message = error?.message ?? parsed.message ?? (typeof detail === "string" ? detail : void 0);
|
|
1922
|
-
const requestId = parsed.request_id ?? error?.request_id ?? (message ?
|
|
1923
|
-
|
|
2073
|
+
const requestId = parsed.request_id ?? error?.request_id ?? (message ? extractRequestIdFromMessage(message) : void 0);
|
|
2074
|
+
const errorObj = error ?? parsed;
|
|
2075
|
+
return {
|
|
2076
|
+
...message ? { message } : {},
|
|
2077
|
+
...requestId ? { requestId } : {},
|
|
2078
|
+
...errorObj ? { errorObj } : {}
|
|
2079
|
+
};
|
|
1924
2080
|
} catch {
|
|
1925
2081
|
const trimmed = text.trim().slice(0, 240);
|
|
1926
2082
|
return trimmed ? { message: trimmed } : {};
|
|
1927
2083
|
}
|
|
1928
2084
|
}
|
|
2085
|
+
var CODEX_USAGE_LIMIT_CODE = /usage_limit_reached|usage_not_included/i;
|
|
2086
|
+
var CODEX_RATE_LIMIT_CODE = /rate_limit_exceeded/i;
|
|
2087
|
+
function codexUsageLimitError(errorObj, statusCode, requestId) {
|
|
2088
|
+
const code = String(errorObj?.code ?? errorObj?.type ?? "");
|
|
2089
|
+
const rateLimits = errorObj?.rate_limits;
|
|
2090
|
+
const resetsAtRaw = (typeof errorObj?.resets_at === "number" ? errorObj.resets_at : void 0) ?? rateLimits?.primary?.resets_at ?? rateLimits?.secondary?.resets_at;
|
|
2091
|
+
const resetsInSeconds = typeof errorObj?.resets_in_seconds === "number" ? errorObj.resets_in_seconds : void 0;
|
|
2092
|
+
const resetsAt = typeof resetsAtRaw === "number" && resetsAtRaw > 0 ? resetsAtRaw : resetsInSeconds != null && resetsInSeconds > 0 ? Math.floor(Date.now() / 1e3) + resetsInSeconds : void 0;
|
|
2093
|
+
const isHardUsage = CODEX_USAGE_LIMIT_CODE.test(code);
|
|
2094
|
+
const isRateOr429 = CODEX_RATE_LIMIT_CODE.test(code) || statusCode === 429;
|
|
2095
|
+
if (!isHardUsage && !(isRateOr429 && resetsAt != null)) return null;
|
|
2096
|
+
return new ProviderError("openai", "ChatGPT usage limit reached", {
|
|
2097
|
+
statusCode: statusCode ?? 429,
|
|
2098
|
+
...requestId ? { requestId } : {},
|
|
2099
|
+
...resetsAt ? { resetsAt } : {}
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
1929
2102
|
|
|
1930
2103
|
// src/providers/gemini.ts
|
|
1931
2104
|
var DEFAULT_CODE_ASSIST_BASE_URL = "https://cloudcode-pa.googleapis.com";
|
|
@@ -1947,12 +2120,6 @@ var CODE_ASSIST_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
|
|
|
1947
2120
|
"gemma-4-31b-it",
|
|
1948
2121
|
"gemma-4-26b-a4b-it"
|
|
1949
2122
|
]);
|
|
1950
|
-
function isJsonObject4(value) {
|
|
1951
|
-
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
1952
|
-
}
|
|
1953
|
-
function getEnvironment() {
|
|
1954
|
-
return globalThis.process?.env;
|
|
1955
|
-
}
|
|
1956
2123
|
function getGoogleProject(options) {
|
|
1957
2124
|
const env = getEnvironment();
|
|
1958
2125
|
return options.projectId ?? env?.GOOGLE_CLOUD_PROJECT ?? env?.GOOGLE_CLOUD_PROJECT_ID;
|
|
@@ -2052,7 +2219,7 @@ function toGeminiTools(tools) {
|
|
|
2052
2219
|
functionDeclarations: tools.map((tool) => ({
|
|
2053
2220
|
name: tool.name,
|
|
2054
2221
|
description: tool.description,
|
|
2055
|
-
parameters: sanitizeSchema(
|
|
2222
|
+
parameters: sanitizeSchema(resolveToolSchema(tool))
|
|
2056
2223
|
}))
|
|
2057
2224
|
}
|
|
2058
2225
|
];
|
|
@@ -2063,7 +2230,7 @@ function sanitizeSchema(schema) {
|
|
|
2063
2230
|
return clone;
|
|
2064
2231
|
}
|
|
2065
2232
|
function stripUnsupportedSchemaFields(value) {
|
|
2066
|
-
if (!
|
|
2233
|
+
if (!isJsonObject(value)) {
|
|
2067
2234
|
if (Array.isArray(value)) {
|
|
2068
2235
|
for (const item of value) stripUnsupportedSchemaFields(item);
|
|
2069
2236
|
}
|
|
@@ -2072,7 +2239,7 @@ function stripUnsupportedSchemaFields(value) {
|
|
|
2072
2239
|
delete value.$schema;
|
|
2073
2240
|
delete value.additionalProperties;
|
|
2074
2241
|
for (const item of Object.values(value)) {
|
|
2075
|
-
if (
|
|
2242
|
+
if (isJsonObject(item) || Array.isArray(item)) {
|
|
2076
2243
|
stripUnsupportedSchemaFields(item);
|
|
2077
2244
|
}
|
|
2078
2245
|
}
|
|
@@ -2095,6 +2262,7 @@ function toGemini3ThinkingLevel(level) {
|
|
|
2095
2262
|
return "MEDIUM";
|
|
2096
2263
|
case "high":
|
|
2097
2264
|
case "xhigh":
|
|
2265
|
+
case "max":
|
|
2098
2266
|
return "HIGH";
|
|
2099
2267
|
}
|
|
2100
2268
|
}
|
|
@@ -2106,6 +2274,7 @@ function toThinkingBudget(level) {
|
|
|
2106
2274
|
return 8192;
|
|
2107
2275
|
case "high":
|
|
2108
2276
|
case "xhigh":
|
|
2277
|
+
case "max":
|
|
2109
2278
|
return 8192;
|
|
2110
2279
|
}
|
|
2111
2280
|
}
|
|
@@ -2185,54 +2354,11 @@ function normalizeGeminiStopReason(reason) {
|
|
|
2185
2354
|
return "end_turn";
|
|
2186
2355
|
}
|
|
2187
2356
|
}
|
|
2188
|
-
function parseSseEvents(buffer) {
|
|
2189
|
-
const events = [];
|
|
2190
|
-
let cursor = 0;
|
|
2191
|
-
while (true) {
|
|
2192
|
-
const next = buffer.indexOf("\n\n", cursor);
|
|
2193
|
-
if (next === -1) break;
|
|
2194
|
-
const raw = buffer.slice(cursor, next);
|
|
2195
|
-
cursor = next + 2;
|
|
2196
|
-
let eventName;
|
|
2197
|
-
const dataLines = [];
|
|
2198
|
-
for (const line of raw.split("\n")) {
|
|
2199
|
-
if (line.startsWith("event:")) {
|
|
2200
|
-
eventName = line.slice("event:".length).trim();
|
|
2201
|
-
} else if (line.startsWith("data:")) {
|
|
2202
|
-
dataLines.push(line.slice("data:".length).trimStart());
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
if (dataLines.length > 0) {
|
|
2206
|
-
events.push({ event: eventName, data: dataLines.join("\n") });
|
|
2207
|
-
}
|
|
2208
|
-
}
|
|
2209
|
-
return { events, remaining: buffer.slice(cursor) };
|
|
2210
|
-
}
|
|
2211
2357
|
async function* streamSse(response) {
|
|
2212
2358
|
if (!response.body) return;
|
|
2213
|
-
const
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
try {
|
|
2217
|
-
while (true) {
|
|
2218
|
-
const { done, value } = await reader.read();
|
|
2219
|
-
if (done) break;
|
|
2220
|
-
buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, "\n");
|
|
2221
|
-
const parsed2 = parseSseEvents(buffer);
|
|
2222
|
-
buffer = parsed2.remaining;
|
|
2223
|
-
for (const event of parsed2.events) {
|
|
2224
|
-
if (event.data === "[DONE]") continue;
|
|
2225
|
-
yield JSON.parse(event.data);
|
|
2226
|
-
}
|
|
2227
|
-
}
|
|
2228
|
-
buffer += decoder.decode().replace(/\r\n/g, "\n");
|
|
2229
|
-
const parsed = parseSseEvents(buffer + "\n\n");
|
|
2230
|
-
for (const event of parsed.events) {
|
|
2231
|
-
if (event.data === "[DONE]") continue;
|
|
2232
|
-
yield JSON.parse(event.data);
|
|
2233
|
-
}
|
|
2234
|
-
} finally {
|
|
2235
|
-
reader.releaseLock();
|
|
2359
|
+
for await (const event of readSseStream(response.body)) {
|
|
2360
|
+
if (event.data === "[DONE]") continue;
|
|
2361
|
+
yield JSON.parse(event.data);
|
|
2236
2362
|
}
|
|
2237
2363
|
}
|
|
2238
2364
|
function candidatesFromResponse(response) {
|
|
@@ -2255,7 +2381,7 @@ function readFunctionCallPart(part) {
|
|
|
2255
2381
|
return {
|
|
2256
2382
|
...part.functionCall.id ? { id: part.functionCall.id } : {},
|
|
2257
2383
|
name: part.functionCall.name,
|
|
2258
|
-
args:
|
|
2384
|
+
args: isJsonObject(part.functionCall.args) ? part.functionCall.args : {}
|
|
2259
2385
|
};
|
|
2260
2386
|
}
|
|
2261
2387
|
function makeToolCallId(index, providerId) {
|
|
@@ -2686,6 +2812,7 @@ export {
|
|
|
2686
2812
|
StreamResult,
|
|
2687
2813
|
formatError,
|
|
2688
2814
|
formatErrorForDisplay,
|
|
2815
|
+
isUsageLimitError,
|
|
2689
2816
|
palsuAssistantMessage,
|
|
2690
2817
|
palsuText,
|
|
2691
2818
|
palsuThinking,
|
|
@@ -2693,6 +2820,8 @@ export {
|
|
|
2693
2820
|
providerRegistry,
|
|
2694
2821
|
registerPalsuProvider,
|
|
2695
2822
|
setProviderDiagnostic,
|
|
2696
|
-
stream
|
|
2823
|
+
stream,
|
|
2824
|
+
toAnthropicMessages,
|
|
2825
|
+
toOpenAIMessages
|
|
2697
2826
|
};
|
|
2698
2827
|
//# sourceMappingURL=index.js.map
|