@prestyj/ai 5.10.0 → 5.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +222 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -9
- package/dist/index.d.ts +39 -9
- package/dist/index.js +216 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,7 @@ __export(index_exports, {
|
|
|
40
40
|
environmentSecrets: () => environmentSecrets,
|
|
41
41
|
formatError: () => formatError,
|
|
42
42
|
formatErrorForDisplay: () => formatErrorForDisplay,
|
|
43
|
+
hasLoneSurrogate: () => hasLoneSurrogate,
|
|
43
44
|
isHardBillingMessage: () => isHardBillingMessage,
|
|
44
45
|
isUsageLimitError: () => isUsageLimitError,
|
|
45
46
|
localWireModelId: () => localWireModelId,
|
|
@@ -52,10 +53,14 @@ __export(index_exports, {
|
|
|
52
53
|
redactText: () => redactText,
|
|
53
54
|
redactValue: () => redactValue,
|
|
54
55
|
registerPalsuProvider: () => registerPalsuProvider,
|
|
56
|
+
sanitizeMessagesForWire: () => sanitizeMessagesForWire,
|
|
55
57
|
setProviderDiagnostic: () => setProviderDiagnostic,
|
|
58
|
+
sliceHead: () => sliceHead,
|
|
59
|
+
sliceTail: () => sliceTail,
|
|
56
60
|
stream: () => stream,
|
|
57
61
|
toAnthropicMessages: () => toAnthropicMessages,
|
|
58
|
-
toOpenAIMessages: () => toOpenAIMessages
|
|
62
|
+
toOpenAIMessages: () => toOpenAIMessages,
|
|
63
|
+
toWellFormedText: () => toWellFormedText
|
|
59
64
|
});
|
|
60
65
|
module.exports = __toCommonJS(index_exports);
|
|
61
66
|
|
|
@@ -1221,7 +1226,7 @@ function parseToolArguments(argsJson) {
|
|
|
1221
1226
|
var NON_STREAMING_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
1222
1227
|
var anthropicClientCache = /* @__PURE__ */ new Map();
|
|
1223
1228
|
function fineGrainedToolStreamingEnabled() {
|
|
1224
|
-
const raw = process.env.
|
|
1229
|
+
const raw = process.env.EZ_FINE_GRAINED_TOOL_STREAMING ?? process.env.CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING;
|
|
1225
1230
|
if (!raw) return false;
|
|
1226
1231
|
const v = raw.trim().toLowerCase();
|
|
1227
1232
|
return v === "1" || v === "true" || v === "yes" || v === "on";
|
|
@@ -2086,7 +2091,15 @@ async function* runStream2(options) {
|
|
|
2086
2091
|
if (chunk.usage) {
|
|
2087
2092
|
({ inputTokens, outputTokens, cacheRead, cacheWrite } = extractOpenAIUsage(chunk.usage));
|
|
2088
2093
|
}
|
|
2089
|
-
if (!choice)
|
|
2094
|
+
if (!choice) {
|
|
2095
|
+
const gatewayError = classifyChoicelessFrame(chunk);
|
|
2096
|
+
if (gatewayError) {
|
|
2097
|
+
throw new ProviderError(providerName, gatewayError.message, {
|
|
2098
|
+
statusCode: gatewayError.statusCode
|
|
2099
|
+
});
|
|
2100
|
+
}
|
|
2101
|
+
continue;
|
|
2102
|
+
}
|
|
2090
2103
|
if (choice.finish_reason) {
|
|
2091
2104
|
finishReason = choice.finish_reason;
|
|
2092
2105
|
}
|
|
@@ -2270,6 +2283,31 @@ function completionToResponse(completion, endpointKey) {
|
|
|
2270
2283
|
}
|
|
2271
2284
|
};
|
|
2272
2285
|
}
|
|
2286
|
+
function classifyChoicelessFrame(frame) {
|
|
2287
|
+
if (!frame || typeof frame !== "object" || Array.isArray(frame)) return null;
|
|
2288
|
+
const rec = frame;
|
|
2289
|
+
if (Array.isArray(rec.choices)) return null;
|
|
2290
|
+
const statusOf = (value) => {
|
|
2291
|
+
const n = typeof value === "string" ? Number(value) : value;
|
|
2292
|
+
return typeof n === "number" && Number.isFinite(n) && n >= 400 && n <= 599 ? n : void 0;
|
|
2293
|
+
};
|
|
2294
|
+
const statusCode = statusOf(rec.status) ?? statusOf(rec.statusCode) ?? statusOf(rec.code);
|
|
2295
|
+
const typeIsError = typeof rec.type === "string" && rec.type.toLowerCase() === "error";
|
|
2296
|
+
let detailText;
|
|
2297
|
+
const detail = rec.detail;
|
|
2298
|
+
if (typeof detail === "string" && detail.trim()) {
|
|
2299
|
+
detailText = detail.trim();
|
|
2300
|
+
} else if (Array.isArray(detail)) {
|
|
2301
|
+
const parts = detail.map(
|
|
2302
|
+
(d) => d && typeof d === "object" && typeof d.msg === "string" ? d.msg : typeof d === "string" ? d : ""
|
|
2303
|
+
).filter(Boolean);
|
|
2304
|
+
if (parts.length) detailText = parts.join("; ");
|
|
2305
|
+
}
|
|
2306
|
+
if (statusCode === void 0 && !typeIsError && !detailText) return null;
|
|
2307
|
+
const rawMessage = (typeof rec.message === "string" && rec.message.trim() ? rec.message.trim() : void 0) ?? detailText ?? (typeof rec.error === "string" && rec.error.trim() ? rec.error.trim() : void 0) ?? (statusCode !== void 0 ? `Gateway returned status ${statusCode}.` : "Gateway error.");
|
|
2308
|
+
const message = rawMessage.slice(0, 500);
|
|
2309
|
+
return { message, statusCode };
|
|
2310
|
+
}
|
|
2273
2311
|
function classifyOpenAICompatLimit(args) {
|
|
2274
2312
|
const { status, code, type, message } = args;
|
|
2275
2313
|
const codeType = `${code ?? ""} ${type ?? ""}`.toLowerCase();
|
|
@@ -2281,6 +2319,7 @@ function classifyOpenAICompatLimit(args) {
|
|
|
2281
2319
|
return null;
|
|
2282
2320
|
}
|
|
2283
2321
|
function toError2(err, provider = "openai") {
|
|
2322
|
+
if (err instanceof ProviderError) return err;
|
|
2284
2323
|
if (err instanceof import_openai.default.APIError) {
|
|
2285
2324
|
const body = err.error;
|
|
2286
2325
|
const bodyMessage = typeof body?.message === "string" && body.message.trim() ? body.message.trim() : void 0;
|
|
@@ -3380,14 +3419,16 @@ async function* runStream4(options) {
|
|
|
3380
3419
|
let thinkingAccum = "";
|
|
3381
3420
|
let stopReason = "end_turn";
|
|
3382
3421
|
let inputTokens = 0;
|
|
3383
|
-
let
|
|
3422
|
+
let candidateTokens = 0;
|
|
3423
|
+
let reasoningTokens = 0;
|
|
3384
3424
|
let cacheRead = 0;
|
|
3385
3425
|
let toolIndex = 0;
|
|
3386
3426
|
const handleResponse = function* (chunk) {
|
|
3387
3427
|
const usage = usageFromResponse(chunk);
|
|
3388
3428
|
if (usage) {
|
|
3389
3429
|
inputTokens = usage.promptTokenCount ?? inputTokens;
|
|
3390
|
-
|
|
3430
|
+
candidateTokens = usage.candidatesTokenCount ?? candidateTokens;
|
|
3431
|
+
reasoningTokens = usage.thoughtsTokenCount ?? reasoningTokens;
|
|
3391
3432
|
cacheRead = usage.cachedContentTokenCount ?? cacheRead;
|
|
3392
3433
|
}
|
|
3393
3434
|
const reason = finishReasonFromResponse(chunk);
|
|
@@ -3443,6 +3484,7 @@ async function* runStream4(options) {
|
|
|
3443
3484
|
}
|
|
3444
3485
|
if (pendingToolCalls.length > 0) stopReason = "tool_use";
|
|
3445
3486
|
const adjustedInputTokens = Math.max(0, inputTokens - cacheRead);
|
|
3487
|
+
const outputTokens = candidateTokens + reasoningTokens;
|
|
3446
3488
|
const streamResponse = {
|
|
3447
3489
|
message: {
|
|
3448
3490
|
role: "assistant",
|
|
@@ -3452,6 +3494,7 @@ async function* runStream4(options) {
|
|
|
3452
3494
|
usage: {
|
|
3453
3495
|
inputTokens: adjustedInputTokens,
|
|
3454
3496
|
outputTokens,
|
|
3497
|
+
...reasoningTokens > 0 ? { reasoningTokens } : {},
|
|
3455
3498
|
...cacheRead > 0 ? { cacheRead } : {}
|
|
3456
3499
|
}
|
|
3457
3500
|
};
|
|
@@ -3500,9 +3543,145 @@ var ProviderRegistryImpl = class {
|
|
|
3500
3543
|
};
|
|
3501
3544
|
var providerRegistry = new ProviderRegistryImpl();
|
|
3502
3545
|
|
|
3546
|
+
// src/utils/well-formed.ts
|
|
3547
|
+
var LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
|
|
3548
|
+
var LONE_SURROGATE_GLOBAL = new RegExp(LONE_SURROGATE, "g");
|
|
3549
|
+
var REPLACEMENT = "\uFFFD";
|
|
3550
|
+
function hasLoneSurrogate(text) {
|
|
3551
|
+
const isWellFormed = text.isWellFormed;
|
|
3552
|
+
if (typeof isWellFormed === "function") return !isWellFormed.call(text);
|
|
3553
|
+
return LONE_SURROGATE.test(text);
|
|
3554
|
+
}
|
|
3555
|
+
function toWellFormedText(text) {
|
|
3556
|
+
if (!hasLoneSurrogate(text)) return text;
|
|
3557
|
+
const toWellFormed = text.toWellFormed;
|
|
3558
|
+
if (typeof toWellFormed === "function") return toWellFormed.call(text);
|
|
3559
|
+
return text.replace(LONE_SURROGATE_GLOBAL, REPLACEMENT);
|
|
3560
|
+
}
|
|
3561
|
+
function isHighSurrogate(code) {
|
|
3562
|
+
return code !== void 0 && code >= 55296 && code <= 56319;
|
|
3563
|
+
}
|
|
3564
|
+
function isLowSurrogate(code) {
|
|
3565
|
+
return code !== void 0 && code >= 56320 && code <= 57343;
|
|
3566
|
+
}
|
|
3567
|
+
function sliceHead(text, chars) {
|
|
3568
|
+
if (chars <= 0) return "";
|
|
3569
|
+
if (chars >= text.length) return text;
|
|
3570
|
+
const end = isHighSurrogate(text.charCodeAt(chars - 1)) ? chars - 1 : chars;
|
|
3571
|
+
return text.slice(0, end);
|
|
3572
|
+
}
|
|
3573
|
+
function sliceTail(text, chars) {
|
|
3574
|
+
if (chars <= 0) return "";
|
|
3575
|
+
if (chars >= text.length) return text;
|
|
3576
|
+
const start = text.length - chars;
|
|
3577
|
+
return text.slice(isLowSurrogate(text.charCodeAt(start)) ? start + 1 : start);
|
|
3578
|
+
}
|
|
3579
|
+
function sanitizeJsonValue(value) {
|
|
3580
|
+
if (typeof value === "string") return toWellFormedText(value);
|
|
3581
|
+
if (Array.isArray(value)) {
|
|
3582
|
+
let changed = false;
|
|
3583
|
+
const next = value.map((item) => {
|
|
3584
|
+
const sanitized = sanitizeJsonValue(item);
|
|
3585
|
+
if (sanitized !== item) changed = true;
|
|
3586
|
+
return sanitized;
|
|
3587
|
+
});
|
|
3588
|
+
return changed ? next : value;
|
|
3589
|
+
}
|
|
3590
|
+
if (value !== null && typeof value === "object") {
|
|
3591
|
+
let changed = false;
|
|
3592
|
+
const next = {};
|
|
3593
|
+
for (const [key, item] of Object.entries(value)) {
|
|
3594
|
+
const sanitizedKey = toWellFormedText(key);
|
|
3595
|
+
const sanitized = sanitizeJsonValue(item);
|
|
3596
|
+
if (sanitizedKey !== key || sanitized !== item) changed = true;
|
|
3597
|
+
next[sanitizedKey] = sanitized;
|
|
3598
|
+
}
|
|
3599
|
+
return changed ? next : value;
|
|
3600
|
+
}
|
|
3601
|
+
return value;
|
|
3602
|
+
}
|
|
3603
|
+
function sanitizeRecord(value) {
|
|
3604
|
+
return sanitizeJsonValue(value);
|
|
3605
|
+
}
|
|
3606
|
+
function sanitizePart(part) {
|
|
3607
|
+
switch (part.type) {
|
|
3608
|
+
case "text":
|
|
3609
|
+
case "thinking": {
|
|
3610
|
+
const text = toWellFormedText(part.text);
|
|
3611
|
+
return text === part.text ? part : { ...part, text };
|
|
3612
|
+
}
|
|
3613
|
+
case "tool_call": {
|
|
3614
|
+
const args = sanitizeRecord(part.args);
|
|
3615
|
+
return args === part.args ? part : { ...part, args };
|
|
3616
|
+
}
|
|
3617
|
+
case "server_tool_call": {
|
|
3618
|
+
const input = sanitizeJsonValue(part.input);
|
|
3619
|
+
return input === part.input ? part : { ...part, input };
|
|
3620
|
+
}
|
|
3621
|
+
case "server_tool_result": {
|
|
3622
|
+
const data = sanitizeJsonValue(part.data);
|
|
3623
|
+
return data === part.data ? part : { ...part, data };
|
|
3624
|
+
}
|
|
3625
|
+
case "raw": {
|
|
3626
|
+
const data = sanitizeRecord(part.data);
|
|
3627
|
+
return data === part.data ? part : { ...part, data };
|
|
3628
|
+
}
|
|
3629
|
+
default:
|
|
3630
|
+
return part;
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
function sanitizeParts(parts) {
|
|
3634
|
+
let changed = false;
|
|
3635
|
+
const next = parts.map((part) => {
|
|
3636
|
+
const sanitized = sanitizePart(part);
|
|
3637
|
+
if (sanitized !== part) changed = true;
|
|
3638
|
+
return sanitized;
|
|
3639
|
+
});
|
|
3640
|
+
return changed ? next : parts;
|
|
3641
|
+
}
|
|
3642
|
+
function sanitizeToolResultContent(content) {
|
|
3643
|
+
if (typeof content === "string") return toWellFormedText(content);
|
|
3644
|
+
return sanitizeParts(content);
|
|
3645
|
+
}
|
|
3646
|
+
function sanitizeToolResults(results) {
|
|
3647
|
+
let changed = false;
|
|
3648
|
+
const next = results.map((result) => {
|
|
3649
|
+
const content = sanitizeToolResultContent(result.content);
|
|
3650
|
+
if (content === result.content) return result;
|
|
3651
|
+
changed = true;
|
|
3652
|
+
return { ...result, content };
|
|
3653
|
+
});
|
|
3654
|
+
return changed ? next : results;
|
|
3655
|
+
}
|
|
3656
|
+
function sanitizeMessage(message) {
|
|
3657
|
+
if (message.role === "tool") {
|
|
3658
|
+
const content2 = sanitizeToolResults(message.content);
|
|
3659
|
+
return content2 === message.content ? message : { ...message, content: content2 };
|
|
3660
|
+
}
|
|
3661
|
+
if (typeof message.content === "string") {
|
|
3662
|
+
const content2 = toWellFormedText(message.content);
|
|
3663
|
+
return content2 === message.content ? message : { ...message, content: content2 };
|
|
3664
|
+
}
|
|
3665
|
+
const content = sanitizeParts(message.content);
|
|
3666
|
+
return content === message.content ? message : { ...message, content };
|
|
3667
|
+
}
|
|
3668
|
+
function sanitizeMessagesForWire(messages) {
|
|
3669
|
+
let sanitized;
|
|
3670
|
+
for (let index = 0; index < messages.length; index++) {
|
|
3671
|
+
const message = messages[index];
|
|
3672
|
+
const next = sanitizeMessage(message);
|
|
3673
|
+
if (next === message) continue;
|
|
3674
|
+
sanitized ??= messages.slice();
|
|
3675
|
+
sanitized[index] = next;
|
|
3676
|
+
}
|
|
3677
|
+
return sanitized ?? messages;
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3503
3680
|
// src/stream.ts
|
|
3504
3681
|
var GLM_CODING_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
|
|
3505
3682
|
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${process.env.KIMI_CODE_VERSION ?? "1.0.11"}`;
|
|
3683
|
+
var GROK_CLI_PROXY_HOST = "cli-chat-proxy.grok.com";
|
|
3684
|
+
var GROK_CLI_VERSION = process.env.GROK_CLI_VERSION ?? "0.2.101";
|
|
3506
3685
|
providerRegistry.register("anthropic", {
|
|
3507
3686
|
stream: (options) => streamAnthropic(options)
|
|
3508
3687
|
});
|
|
@@ -3569,13 +3748,25 @@ providerRegistry.register("xai", {
|
|
|
3569
3748
|
// xAI's public API (console.x.ai key) is OpenAI-compatible — ride the Chat
|
|
3570
3749
|
// Completions transport like Moonshot/DeepSeek. Grok reasoning models take
|
|
3571
3750
|
// top-level `reasoning_effort` (low/medium/high), which the shared thinking
|
|
3572
|
-
// path already sends.
|
|
3573
|
-
//
|
|
3574
|
-
//
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3751
|
+
// path already sends.
|
|
3752
|
+
//
|
|
3753
|
+
// Subscription OAuth (SuperGrok / X Premium) routes to the Grok CLI chat proxy
|
|
3754
|
+
// instead, which speaks the same Chat Completions wire but gates on Grok-CLI
|
|
3755
|
+
// client identity. Inject those headers centrally here — exactly as the Kimi
|
|
3756
|
+
// endpoint above — so EVERY stream (agent loop, compaction, title-gen,
|
|
3757
|
+
// sub-agents) is accepted rather than depending on each call site to thread
|
|
3758
|
+
// headers. Caller-provided headers still win on collision.
|
|
3759
|
+
stream: (options) => {
|
|
3760
|
+
const baseUrl = options.baseUrl ?? "https://api.x.ai/v1";
|
|
3761
|
+
const defaultHeaders = baseUrl.includes(GROK_CLI_PROXY_HOST) ? {
|
|
3762
|
+
"X-XAI-Token-Auth": "xai-grok-cli",
|
|
3763
|
+
"x-grok-client-version": GROK_CLI_VERSION,
|
|
3764
|
+
"x-grok-client-identifier": "ezcoder",
|
|
3765
|
+
"x-grok-model-override": options.model,
|
|
3766
|
+
...options.defaultHeaders
|
|
3767
|
+
} : options.defaultHeaders;
|
|
3768
|
+
return streamOpenAI({ ...options, baseUrl, defaultHeaders });
|
|
3769
|
+
}
|
|
3579
3770
|
});
|
|
3580
3771
|
providerRegistry.register("minimax", {
|
|
3581
3772
|
stream: (options) => streamAnthropic({
|
|
@@ -3621,13 +3812,25 @@ function stream(options) {
|
|
|
3621
3812
|
if (options.supportsVideo !== true && messagesContainVideo(options.messages)) {
|
|
3622
3813
|
throw new VideoUnsupportedError();
|
|
3623
3814
|
}
|
|
3815
|
+
const wireMessages = stripMessageProvenance(options.messages);
|
|
3624
3816
|
const messages = clampProviderContextImages(
|
|
3625
|
-
|
|
3817
|
+
sanitizeMessagesForWire(wireMessages),
|
|
3626
3818
|
options.provider,
|
|
3627
3819
|
options.supportsImages
|
|
3628
3820
|
);
|
|
3629
3821
|
return entry.stream(messages === options.messages ? options : { ...options, messages });
|
|
3630
3822
|
}
|
|
3823
|
+
function stripMessageProvenance(messages) {
|
|
3824
|
+
let stripped;
|
|
3825
|
+
for (let index = 0; index < messages.length; index++) {
|
|
3826
|
+
const message = messages[index];
|
|
3827
|
+
if (!message.provenance) continue;
|
|
3828
|
+
stripped ??= messages.slice();
|
|
3829
|
+
const { provenance: _provenance, ...wireMessage } = message;
|
|
3830
|
+
stripped[index] = wireMessage;
|
|
3831
|
+
}
|
|
3832
|
+
return stripped ?? messages;
|
|
3833
|
+
}
|
|
3631
3834
|
function messagesContainVideo(messages) {
|
|
3632
3835
|
for (const msg of messages) {
|
|
3633
3836
|
if (typeof msg.content === "string" || !Array.isArray(msg.content)) continue;
|
|
@@ -4013,6 +4216,7 @@ function registerPalsuProvider(config) {
|
|
|
4013
4216
|
environmentSecrets,
|
|
4014
4217
|
formatError,
|
|
4015
4218
|
formatErrorForDisplay,
|
|
4219
|
+
hasLoneSurrogate,
|
|
4016
4220
|
isHardBillingMessage,
|
|
4017
4221
|
isUsageLimitError,
|
|
4018
4222
|
localWireModelId,
|
|
@@ -4025,9 +4229,13 @@ function registerPalsuProvider(config) {
|
|
|
4025
4229
|
redactText,
|
|
4026
4230
|
redactValue,
|
|
4027
4231
|
registerPalsuProvider,
|
|
4232
|
+
sanitizeMessagesForWire,
|
|
4028
4233
|
setProviderDiagnostic,
|
|
4234
|
+
sliceHead,
|
|
4235
|
+
sliceTail,
|
|
4029
4236
|
stream,
|
|
4030
4237
|
toAnthropicMessages,
|
|
4031
|
-
toOpenAIMessages
|
|
4238
|
+
toOpenAIMessages,
|
|
4239
|
+
toWellFormedText
|
|
4032
4240
|
});
|
|
4033
4241
|
//# sourceMappingURL=index.cjs.map
|