@kenkaiiii/gg-ai 5.68.0 → 5.69.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 +356 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -2
- package/dist/index.d.ts +85 -2
- package/dist/index.js +351 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -448,7 +448,11 @@ function zodToJsonSchema(schema) {
|
|
|
448
448
|
return normalized;
|
|
449
449
|
}
|
|
450
450
|
function resolveToolSchema(tool) {
|
|
451
|
-
|
|
451
|
+
const schema = tool.rawInputSchema ?? zodToJsonSchema(tool.parameters);
|
|
452
|
+
if (schema.type === "object" && schema.properties === void 0) {
|
|
453
|
+
return { ...schema, properties: {} };
|
|
454
|
+
}
|
|
455
|
+
return schema;
|
|
452
456
|
}
|
|
453
457
|
function normalizeRootForAnthropic(schema) {
|
|
454
458
|
const branches = schema.oneOf ?? schema.anyOf;
|
|
@@ -655,6 +659,10 @@ var ANTHROPIC_INPUT_BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
|
655
659
|
"connector_text",
|
|
656
660
|
"container_upload",
|
|
657
661
|
"document",
|
|
662
|
+
// Server-side refusal fallback marker. Only reaches the wire when the request
|
|
663
|
+
// carries the server-side-fallback beta; otherwise applyServerFallbackReplay
|
|
664
|
+
// strips it first (see toAnthropicMessages' `fallbackBlocks` option).
|
|
665
|
+
"fallback",
|
|
658
666
|
"image",
|
|
659
667
|
"mid_conv_system",
|
|
660
668
|
"redacted_thinking",
|
|
@@ -676,6 +684,42 @@ function isPositionSensitiveThinking(part) {
|
|
|
676
684
|
if (part.type === "thinking") return hasValidThinkingSignature(part);
|
|
677
685
|
return isRawThinking(part);
|
|
678
686
|
}
|
|
687
|
+
function isServerFallbackBlock(part) {
|
|
688
|
+
return part.type === "raw" && part.data.type === "fallback";
|
|
689
|
+
}
|
|
690
|
+
function applyServerFallbackReplay(content, keepMarkers, droppedToolCallIds) {
|
|
691
|
+
let lastFallbackIdx = -1;
|
|
692
|
+
content.forEach((part, idx) => {
|
|
693
|
+
if (isServerFallbackBlock(part)) lastFallbackIdx = idx;
|
|
694
|
+
});
|
|
695
|
+
if (lastFallbackIdx === -1) return content;
|
|
696
|
+
const resultIds = /* @__PURE__ */ new Set();
|
|
697
|
+
for (const part of content) {
|
|
698
|
+
if (part.type === "server_tool_result") resultIds.add(part.toolUseId);
|
|
699
|
+
else if (part.type === "raw" && typeof part.data.tool_use_id === "string")
|
|
700
|
+
resultIds.add(part.data.tool_use_id);
|
|
701
|
+
}
|
|
702
|
+
const out = [];
|
|
703
|
+
content.forEach((part, idx) => {
|
|
704
|
+
if (isServerFallbackBlock(part)) {
|
|
705
|
+
if (keepMarkers) out.push(part);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
if (idx < lastFallbackIdx) {
|
|
709
|
+
if (part.type === "thinking" || isRawThinking(part)) return;
|
|
710
|
+
if (part.type === "raw" && part.data.type === "connector_text") return;
|
|
711
|
+
if (part.type === "tool_call") {
|
|
712
|
+
droppedToolCallIds?.add(part.id);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
if (part.type === "server_tool_call" && !resultIds.has(part.id)) return;
|
|
716
|
+
if (part.type === "raw" && part.data.type === "server_tool_use" && !resultIds.has(String(part.data.id)))
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
out.push(part);
|
|
720
|
+
});
|
|
721
|
+
return out.every(isServerFallbackBlock) ? [] : out;
|
|
722
|
+
}
|
|
679
723
|
function toAnthropicAssistantPart(part, idMap) {
|
|
680
724
|
if (part.type === "text") return { type: "text", text: part.text };
|
|
681
725
|
if (part.type === "thinking") {
|
|
@@ -743,10 +787,17 @@ function countContextImages(messages) {
|
|
|
743
787
|
}
|
|
744
788
|
return count;
|
|
745
789
|
}
|
|
790
|
+
var IMAGE_DROP_BATCH = 30;
|
|
791
|
+
function providerImageDropCount(imageCount2, budget) {
|
|
792
|
+
const overflow = imageCount2 - budget;
|
|
793
|
+
if (overflow <= 0) return 0;
|
|
794
|
+
const batch = Math.max(1, Math.min(IMAGE_DROP_BATCH, Math.floor(budget / 3)));
|
|
795
|
+
return Math.min(imageCount2, Math.ceil(overflow / batch) * batch);
|
|
796
|
+
}
|
|
746
797
|
function clampProviderContextImages(messages, provider, supportsImages) {
|
|
747
798
|
if (supportsImages === false) return messages;
|
|
748
799
|
const budget = PROVIDER_IMAGE_BUDGETS[provider] ?? 5;
|
|
749
|
-
let remainingToRemove = countContextImages(messages)
|
|
800
|
+
let remainingToRemove = providerImageDropCount(countContextImages(messages), budget);
|
|
750
801
|
if (remainingToRemove <= 0) return messages;
|
|
751
802
|
return messages.map((message) => {
|
|
752
803
|
if (message.role === "user" && Array.isArray(message.content)) {
|
|
@@ -780,6 +831,144 @@ function clampProviderContextImages(messages, provider, supportsImages) {
|
|
|
780
831
|
return message;
|
|
781
832
|
});
|
|
782
833
|
}
|
|
834
|
+
var TOOL_CALL_NAME_RULES = {
|
|
835
|
+
// Anthropic Messages API: tool / tool_use name `^[a-zA-Z0-9_-]{1,128}$`.
|
|
836
|
+
anthropic: { id: "anthropic", maxLength: 128, pattern: /^[a-zA-Z0-9_-]{1,128}$/ },
|
|
837
|
+
// OpenAI Chat Completions: function name a-z A-Z 0-9 _ -, max length 64.
|
|
838
|
+
"openai-chat": { id: "openai-chat", maxLength: 64, pattern: /^[a-zA-Z0-9_-]{1,64}$/ },
|
|
839
|
+
// OpenAI Responses (Codex): same charset; replayed `input[N].name` over 128
|
|
840
|
+
// chars is rejected with `string_above_max_length`.
|
|
841
|
+
"openai-responses": {
|
|
842
|
+
id: "openai-responses",
|
|
843
|
+
maxLength: 128,
|
|
844
|
+
pattern: /^[a-zA-Z0-9_-]{1,128}$/
|
|
845
|
+
},
|
|
846
|
+
// Gemini FunctionDeclaration name: starts with a letter or underscore, then
|
|
847
|
+
// a-z A-Z 0-9 _ . : -, max length 128.
|
|
848
|
+
gemini: { id: "gemini", maxLength: 128, pattern: /^[a-zA-Z_][a-zA-Z0-9_.:-]{0,127}$/ },
|
|
849
|
+
// OpenAI-compatible third parties (GLM, Kimi, DeepSeek, OpenRouter, xAI,
|
|
850
|
+
// local servers, MiniMax, …) don't share one documented charset, so only
|
|
851
|
+
// reject what no declared tool name can contain: blank, >128 chars, or any
|
|
852
|
+
// whitespace / control character (the signature of invocation text).
|
|
853
|
+
generic: { id: "generic", maxLength: 128 }
|
|
854
|
+
};
|
|
855
|
+
var TOOL_NAME_FORBIDDEN_CHARS = /[\s\p{Cc}]/u;
|
|
856
|
+
function isValidToolCallName(name, rule) {
|
|
857
|
+
if (typeof name !== "string" || name.trim().length === 0) return false;
|
|
858
|
+
if (name.length > rule.maxLength) return false;
|
|
859
|
+
if (TOOL_NAME_FORBIDDEN_CHARS.test(name)) return false;
|
|
860
|
+
return rule.pattern ? rule.pattern.test(name) : true;
|
|
861
|
+
}
|
|
862
|
+
function isDefaultOrHost(baseUrl, host) {
|
|
863
|
+
if (!baseUrl) return true;
|
|
864
|
+
try {
|
|
865
|
+
return new URL(baseUrl).hostname === host;
|
|
866
|
+
} catch {
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
function toolCallNameRuleFor(provider, options) {
|
|
871
|
+
switch (provider) {
|
|
872
|
+
case "anthropic":
|
|
873
|
+
return TOOL_CALL_NAME_RULES.anthropic;
|
|
874
|
+
case "openai":
|
|
875
|
+
if (options?.accountId) return TOOL_CALL_NAME_RULES["openai-responses"];
|
|
876
|
+
return isDefaultOrHost(options?.baseUrl, "api.openai.com") ? TOOL_CALL_NAME_RULES["openai-chat"] : TOOL_CALL_NAME_RULES.generic;
|
|
877
|
+
case "gemini":
|
|
878
|
+
return TOOL_CALL_NAME_RULES.gemini;
|
|
879
|
+
default:
|
|
880
|
+
return TOOL_CALL_NAME_RULES.generic;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
function isValidToolCallId(id) {
|
|
884
|
+
return typeof id === "string" && id.trim().length > 0;
|
|
885
|
+
}
|
|
886
|
+
function isRawReasoning(part) {
|
|
887
|
+
return part.type === "raw" && part.data.type === "reasoning";
|
|
888
|
+
}
|
|
889
|
+
function isDanglingReasoning(parts, idx) {
|
|
890
|
+
for (let i = idx + 1; i < parts.length; i++) {
|
|
891
|
+
const next = parts[i];
|
|
892
|
+
if (isRawReasoning(next)) return true;
|
|
893
|
+
if (next.type === "text" || next.type === "tool_call") return false;
|
|
894
|
+
}
|
|
895
|
+
return true;
|
|
896
|
+
}
|
|
897
|
+
function hasReplayableAssistantContent(parts) {
|
|
898
|
+
return parts.some((part) => {
|
|
899
|
+
if (part.type === "text") return part.text.length > 0;
|
|
900
|
+
if (part.type === "thinking") return false;
|
|
901
|
+
if (part.type === "raw") {
|
|
902
|
+
const t = part.data.type;
|
|
903
|
+
return !(t === "thinking" || t === "redacted_thinking" || t === "reasoning" || t === "fallback");
|
|
904
|
+
}
|
|
905
|
+
return true;
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
function dropInvalidToolCalls(messages, rule) {
|
|
909
|
+
const isInvalid = (part) => part.type === "tool_call" && (!isValidToolCallName(part.name, rule) || !isValidToolCallId(part.id));
|
|
910
|
+
const hasInvalid = messages.some(
|
|
911
|
+
(m) => m.role === "assistant" && Array.isArray(m.content) && m.content.some(isInvalid)
|
|
912
|
+
);
|
|
913
|
+
if (!hasInvalid) return messages;
|
|
914
|
+
const out = [];
|
|
915
|
+
let pending = /* @__PURE__ */ new Map();
|
|
916
|
+
let prunedAssistant = null;
|
|
917
|
+
for (const msg of messages) {
|
|
918
|
+
if (msg.role === "user" || msg.role === "system") {
|
|
919
|
+
if (msg.role === "user") pending = /* @__PURE__ */ new Map();
|
|
920
|
+
out.push(msg);
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
if (msg.role === "assistant") {
|
|
924
|
+
pending = /* @__PURE__ */ new Map();
|
|
925
|
+
if (typeof msg.content === "string") {
|
|
926
|
+
out.push(msg);
|
|
927
|
+
continue;
|
|
928
|
+
}
|
|
929
|
+
const original = msg.content;
|
|
930
|
+
let dropped = false;
|
|
931
|
+
const kept = [];
|
|
932
|
+
for (const part of original) {
|
|
933
|
+
if (part.type === "tool_call") {
|
|
934
|
+
const keep = !isInvalid(part);
|
|
935
|
+
const queue = pending.get(part.id) ?? [];
|
|
936
|
+
queue.push(keep);
|
|
937
|
+
pending.set(part.id, queue);
|
|
938
|
+
if (!keep) {
|
|
939
|
+
dropped = true;
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
kept.push(part);
|
|
944
|
+
}
|
|
945
|
+
if (!dropped) {
|
|
946
|
+
out.push(msg);
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
const content = kept.filter(
|
|
950
|
+
(part, idx) => !isRawReasoning(part) || !isDanglingReasoning(kept, idx) || isDanglingReasoning(original, original.indexOf(part))
|
|
951
|
+
);
|
|
952
|
+
if (hasReplayableAssistantContent(content)) {
|
|
953
|
+
const pruned = { ...msg, content };
|
|
954
|
+
out.push(pruned);
|
|
955
|
+
prunedAssistant = pruned;
|
|
956
|
+
}
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
let changed = false;
|
|
960
|
+
const results = msg.content.filter((result) => {
|
|
961
|
+
const queue = pending.get(result.toolCallId);
|
|
962
|
+
const keep = queue && queue.length > 0 ? queue.shift() : true;
|
|
963
|
+
if (!keep) changed = true;
|
|
964
|
+
return keep;
|
|
965
|
+
});
|
|
966
|
+
if (!changed) out.push(msg);
|
|
967
|
+
else if (results.length > 0) out.push({ ...msg, content: results });
|
|
968
|
+
}
|
|
969
|
+
if (prunedAssistant && out[out.length - 1] === prunedAssistant) out.pop();
|
|
970
|
+
return out;
|
|
971
|
+
}
|
|
783
972
|
var NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
|
|
784
973
|
var NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
|
|
785
974
|
var NON_VIDEO_USER_PLACEHOLDER = "(video omitted: model does not support video)";
|
|
@@ -886,10 +1075,12 @@ function remapAnthropicToolCallId(id, idMap) {
|
|
|
886
1075
|
idMap.set(id, mapped);
|
|
887
1076
|
return mapped;
|
|
888
1077
|
}
|
|
889
|
-
function toAnthropicMessages(messages, cacheControl) {
|
|
1078
|
+
function toAnthropicMessages(messages, cacheControl, options) {
|
|
890
1079
|
let systemText;
|
|
891
1080
|
const out = [];
|
|
892
1081
|
const idMap = /* @__PURE__ */ new Map();
|
|
1082
|
+
const keepFallbackBlocks = options?.fallbackBlocks === true;
|
|
1083
|
+
const droppedToolCallIds = /* @__PURE__ */ new Set();
|
|
893
1084
|
const trajectoryStartIdx = messages.reduce(
|
|
894
1085
|
(last, m, i) => m.role === "user" ? i : last,
|
|
895
1086
|
-1
|
|
@@ -935,17 +1126,23 @@ function toAnthropicMessages(messages, cacheControl) {
|
|
|
935
1126
|
}
|
|
936
1127
|
if (msg.role === "assistant") {
|
|
937
1128
|
if (typeof msg.content === "string" && msg.content === "") continue;
|
|
938
|
-
const content = typeof msg.content === "string" ? msg.content : toAnthropicAssistantContent(
|
|
1129
|
+
const content = typeof msg.content === "string" ? msg.content : toAnthropicAssistantContent(
|
|
1130
|
+
applyServerFallbackReplay(msg.content, keepFallbackBlocks, droppedToolCallIds),
|
|
1131
|
+
msgIdx > trajectoryStartIdx,
|
|
1132
|
+
idMap
|
|
1133
|
+
);
|
|
939
1134
|
if (Array.isArray(content) && content.length === 0) continue;
|
|
940
1135
|
out.push({ role: "assistant", content });
|
|
941
1136
|
continue;
|
|
942
1137
|
}
|
|
943
1138
|
if (msg.role === "tool") {
|
|
1139
|
+
const results = droppedToolCallIds.size ? msg.content.filter((r) => !droppedToolCallIds.has(r.toolCallId)) : msg.content;
|
|
1140
|
+
if (results.length === 0) continue;
|
|
944
1141
|
out.push({
|
|
945
1142
|
role: "user",
|
|
946
1143
|
// Cast covers the video block (used by the Anthropic-compatible MiniMax
|
|
947
1144
|
// API), which isn't in the first-party Anthropic tool_result types.
|
|
948
|
-
content:
|
|
1145
|
+
content: results.map((result) => ({
|
|
949
1146
|
type: "tool_result",
|
|
950
1147
|
tool_use_id: remapAnthropicToolCallId(result.toolCallId, idMap),
|
|
951
1148
|
content: toAnthropicToolResultContent(result.content),
|
|
@@ -1285,6 +1482,48 @@ function fineGrainedToolStreamingEnabled() {
|
|
|
1285
1482
|
const v = raw.trim().toLowerCase();
|
|
1286
1483
|
return v === "1" || v === "true" || v === "yes" || v === "on";
|
|
1287
1484
|
}
|
|
1485
|
+
var SERVER_FALLBACK_BETA = "server-side-fallback-2026-07-01";
|
|
1486
|
+
var anthropicServerFallback = {
|
|
1487
|
+
disabled: /* @__PURE__ */ new Set(),
|
|
1488
|
+
reset() {
|
|
1489
|
+
this.disabled.clear();
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
function serverFallbackKey(options) {
|
|
1493
|
+
const auth = options.apiKey?.startsWith("sk-ant-oat") ? "oauth" : "key";
|
|
1494
|
+
return `${options.baseUrl ?? process.env.ANTHROPIC_BASE_URL ?? ""}|${auth}`;
|
|
1495
|
+
}
|
|
1496
|
+
function isDirectAnthropicApi(baseUrl) {
|
|
1497
|
+
const effective = baseUrl ?? process.env.ANTHROPIC_BASE_URL;
|
|
1498
|
+
if (!effective) return true;
|
|
1499
|
+
try {
|
|
1500
|
+
const url = new URL(effective);
|
|
1501
|
+
return url.protocol === "https:" && url.hostname === "api.anthropic.com";
|
|
1502
|
+
} catch {
|
|
1503
|
+
return false;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
function isServerFallbackRejection(err) {
|
|
1507
|
+
const status = err?.status;
|
|
1508
|
+
if (status !== 400) return false;
|
|
1509
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1510
|
+
return /fallbacks|server-side-fallback/i.test(message);
|
|
1511
|
+
}
|
|
1512
|
+
function sumUsageIterations(usage) {
|
|
1513
|
+
const iterations = usage?.iterations;
|
|
1514
|
+
if (!Array.isArray(iterations) || iterations.length === 0) return null;
|
|
1515
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
1516
|
+
const totals = { inputTokens: 0, outputTokens: 0, cacheRead: 0, cacheWrite: 0 };
|
|
1517
|
+
for (const it of iterations) {
|
|
1518
|
+
if (!it || typeof it !== "object") continue;
|
|
1519
|
+
const rec = it;
|
|
1520
|
+
totals.inputTokens += num(rec.input_tokens);
|
|
1521
|
+
totals.outputTokens += num(rec.output_tokens);
|
|
1522
|
+
totals.cacheRead += num(rec.cache_read_input_tokens);
|
|
1523
|
+
totals.cacheWrite += num(rec.cache_creation_input_tokens);
|
|
1524
|
+
}
|
|
1525
|
+
return totals;
|
|
1526
|
+
}
|
|
1288
1527
|
function createClient(options) {
|
|
1289
1528
|
const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
|
|
1290
1529
|
const userAgent = isOAuth ? options.userAgent ?? "claude-cli/2.1.75 (external, cli)" : "";
|
|
@@ -1381,7 +1620,11 @@ async function* runStream(options) {
|
|
|
1381
1620
|
const supportsFirstPartyToolExtras = !options.baseUrl || options.baseUrl.includes("api.anthropic.com");
|
|
1382
1621
|
const downgradedImages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
1383
1622
|
const downgradedMessages = downgradeUnsupportedVideos(downgradedImages, options.supportsVideo);
|
|
1384
|
-
const
|
|
1623
|
+
const fallbackKey = serverFallbackKey(options);
|
|
1624
|
+
const useServerFallback = options.provider !== "minimax" && isDirectAnthropicApi(options.baseUrl) && !anthropicServerFallback.disabled.has(fallbackKey);
|
|
1625
|
+
const { system: rawSystem, messages } = toAnthropicMessages(downgradedMessages, cacheControl, {
|
|
1626
|
+
fallbackBlocks: useServerFallback
|
|
1627
|
+
});
|
|
1385
1628
|
const system = isOAuth ? [
|
|
1386
1629
|
{
|
|
1387
1630
|
type: "text",
|
|
@@ -1451,6 +1694,7 @@ async function* runStream(options) {
|
|
|
1451
1694
|
];
|
|
1452
1695
|
return contextEdits.length ? { context_management: { edits: contextEdits } } : {};
|
|
1453
1696
|
})(),
|
|
1697
|
+
...useServerFallback ? { fallbacks: "default" } : {},
|
|
1454
1698
|
stream: useStreaming
|
|
1455
1699
|
};
|
|
1456
1700
|
const hasAdaptiveThinking = isAdaptiveThinkingModel(options.model);
|
|
@@ -1467,20 +1711,41 @@ async function* runStream(options) {
|
|
|
1467
1711
|
// it Anthropic silently ignores ttl:"1h" and falls back to the 5-min default,
|
|
1468
1712
|
// so a pre-warmed cache expires before the user's first turn. cacheControl.ttl
|
|
1469
1713
|
// is only "1h" on the first-party endpoint (see toAnthropicCacheControl).
|
|
1470
|
-
...cacheControl?.ttl === "1h" ? ["extended-cache-ttl-2025-04-11"] : []
|
|
1714
|
+
...cacheControl?.ttl === "1h" ? ["extended-cache-ttl-2025-04-11"] : [],
|
|
1715
|
+
...useServerFallback ? [SERVER_FALLBACK_BETA] : []
|
|
1471
1716
|
];
|
|
1472
|
-
const
|
|
1717
|
+
const toRequestOptions = (betas) => ({
|
|
1473
1718
|
signal: options.signal ?? void 0,
|
|
1474
|
-
...
|
|
1719
|
+
...betas.length ? { headers: { "anthropic-beta": betas.join(",") } } : {}
|
|
1720
|
+
});
|
|
1721
|
+
const requestOptions = toRequestOptions(betaHeaders);
|
|
1722
|
+
const send = async (create) => {
|
|
1723
|
+
try {
|
|
1724
|
+
return await create(params, requestOptions);
|
|
1725
|
+
} catch (err) {
|
|
1726
|
+
if (!useServerFallback || !isServerFallbackRejection(err)) throw err;
|
|
1727
|
+
anthropicServerFallback.disabled.add(fallbackKey);
|
|
1728
|
+
const { fallbacks: _dropped, ...rest } = params;
|
|
1729
|
+
const retryParams = {
|
|
1730
|
+
...rest,
|
|
1731
|
+
messages: toAnthropicMessages(downgradedMessages, cacheControl, { fallbackBlocks: false }).messages
|
|
1732
|
+
};
|
|
1733
|
+
return create(
|
|
1734
|
+
retryParams,
|
|
1735
|
+
toRequestOptions(betaHeaders.filter((b) => b !== SERVER_FALLBACK_BETA))
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1475
1738
|
};
|
|
1476
1739
|
if (!useStreaming) {
|
|
1477
1740
|
try {
|
|
1478
1741
|
const nonStreamingClient = client.withOptions({
|
|
1479
1742
|
timeout: NON_STREAMING_REQUEST_TIMEOUT_MS
|
|
1480
1743
|
});
|
|
1481
|
-
const message = await
|
|
1482
|
-
|
|
1483
|
-
|
|
1744
|
+
const message = await send(
|
|
1745
|
+
(p, o) => nonStreamingClient.messages.create(
|
|
1746
|
+
{ ...p, stream: false },
|
|
1747
|
+
o
|
|
1748
|
+
)
|
|
1484
1749
|
);
|
|
1485
1750
|
yield* synthesizeEventsFromMessage(message);
|
|
1486
1751
|
return messageToResponse(message);
|
|
@@ -1498,9 +1763,8 @@ async function* runStream(options) {
|
|
|
1498
1763
|
const keepalive = { type: "keepalive" };
|
|
1499
1764
|
let receivedAnyEvent = false;
|
|
1500
1765
|
try {
|
|
1501
|
-
const stream2 = await
|
|
1502
|
-
|
|
1503
|
-
requestOptions
|
|
1766
|
+
const stream2 = await send(
|
|
1767
|
+
(p, o) => client.messages.create(p, o)
|
|
1504
1768
|
);
|
|
1505
1769
|
for await (const event of stream2) {
|
|
1506
1770
|
receivedAnyEvent = true;
|
|
@@ -1678,6 +1942,13 @@ async function* runStream(options) {
|
|
|
1678
1942
|
if (usage?.output_tokens != null) {
|
|
1679
1943
|
outputTokens = usage.output_tokens;
|
|
1680
1944
|
}
|
|
1945
|
+
const totals = sumUsageIterations(usage);
|
|
1946
|
+
if (totals) {
|
|
1947
|
+
inputTokens = totals.inputTokens;
|
|
1948
|
+
outputTokens = totals.outputTokens;
|
|
1949
|
+
cacheRead = totals.cacheRead;
|
|
1950
|
+
cacheWrite = totals.cacheWrite;
|
|
1951
|
+
}
|
|
1681
1952
|
yield keepalive;
|
|
1682
1953
|
break;
|
|
1683
1954
|
}
|
|
@@ -1807,10 +2078,11 @@ function messageToResponse(message) {
|
|
|
1807
2078
|
}
|
|
1808
2079
|
}
|
|
1809
2080
|
const usage = message.usage;
|
|
1810
|
-
const
|
|
1811
|
-
const
|
|
1812
|
-
const
|
|
1813
|
-
const
|
|
2081
|
+
const totals = sumUsageIterations(usage);
|
|
2082
|
+
const inputTokens = totals?.inputTokens ?? usage.input_tokens ?? 0;
|
|
2083
|
+
const outputTokens = totals?.outputTokens ?? usage.output_tokens ?? 0;
|
|
2084
|
+
const cacheRead = totals?.cacheRead ?? usage.cache_read_input_tokens;
|
|
2085
|
+
const cacheWrite = totals?.cacheWrite ?? usage.cache_creation_input_tokens;
|
|
1814
2086
|
return {
|
|
1815
2087
|
message: {
|
|
1816
2088
|
role: "assistant",
|
|
@@ -3841,6 +4113,41 @@ function sanitizeMessagesForWire(messages) {
|
|
|
3841
4113
|
return sanitized ?? messages;
|
|
3842
4114
|
}
|
|
3843
4115
|
|
|
4116
|
+
// src/utils/context-observation.ts
|
|
4117
|
+
function imageCount(message) {
|
|
4118
|
+
if (!message || !Array.isArray(message.content)) return 0;
|
|
4119
|
+
if (message.role === "user")
|
|
4120
|
+
return message.content.filter((part) => part.type === "image").length;
|
|
4121
|
+
if (message.role !== "tool") return 0;
|
|
4122
|
+
return message.content.reduce(
|
|
4123
|
+
(count, result) => count + (Array.isArray(result.content) ? result.content.filter((part) => part.type === "image").length : 0),
|
|
4124
|
+
0
|
|
4125
|
+
);
|
|
4126
|
+
}
|
|
4127
|
+
function observePreparedContext(before, after, tools) {
|
|
4128
|
+
let imagesBefore = 0;
|
|
4129
|
+
let imagesAfter = 0;
|
|
4130
|
+
let firstImageDropMessage = null;
|
|
4131
|
+
for (let index = 0; index < before.length; index++) {
|
|
4132
|
+
const oldCount = imageCount(before[index]);
|
|
4133
|
+
const newCount = imageCount(after[index]);
|
|
4134
|
+
imagesBefore += oldCount;
|
|
4135
|
+
imagesAfter += newCount;
|
|
4136
|
+
if (firstImageDropMessage === null && newCount < oldCount) firstImageDropMessage = index;
|
|
4137
|
+
}
|
|
4138
|
+
return {
|
|
4139
|
+
messages: after,
|
|
4140
|
+
tools: tools.map((tool) => ({
|
|
4141
|
+
name: tool.name,
|
|
4142
|
+
description: tool.description,
|
|
4143
|
+
parameters: resolveToolSchema(tool)
|
|
4144
|
+
})),
|
|
4145
|
+
imagesBefore,
|
|
4146
|
+
imagesAfter,
|
|
4147
|
+
firstImageDropMessage
|
|
4148
|
+
};
|
|
4149
|
+
}
|
|
4150
|
+
|
|
3844
4151
|
// src/stream.ts
|
|
3845
4152
|
var GLM_CODING_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
|
|
3846
4153
|
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${process.env.KIMI_CODE_VERSION ?? "1.0.11"}`;
|
|
@@ -3983,11 +4290,27 @@ function stream(options) {
|
|
|
3983
4290
|
throw new VideoUnsupportedError();
|
|
3984
4291
|
}
|
|
3985
4292
|
const wireMessages = stripMessageProvenance(options.messages);
|
|
3986
|
-
const
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
options.
|
|
4293
|
+
const sanitized = sanitizeMessagesForWire(wireMessages);
|
|
4294
|
+
const replayable = dropInvalidToolCalls(
|
|
4295
|
+
sanitized,
|
|
4296
|
+
toolCallNameRuleFor(options.provider, {
|
|
4297
|
+
accountId: options.accountId,
|
|
4298
|
+
baseUrl: options.baseUrl
|
|
4299
|
+
})
|
|
3990
4300
|
);
|
|
4301
|
+
const messages = clampProviderContextImages(replayable, options.provider, options.supportsImages);
|
|
4302
|
+
if (options.onContextPrepared) {
|
|
4303
|
+
try {
|
|
4304
|
+
options.onContextPrepared(
|
|
4305
|
+
observePreparedContext(
|
|
4306
|
+
replayable === sanitized ? wireMessages : replayable,
|
|
4307
|
+
messages,
|
|
4308
|
+
options.tools ?? []
|
|
4309
|
+
)
|
|
4310
|
+
);
|
|
4311
|
+
} catch {
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
3991
4314
|
return entry.stream(messages === options.messages ? options : { ...options, messages });
|
|
3992
4315
|
}
|
|
3993
4316
|
function stripMessageProvenance(messages) {
|
|
@@ -4398,14 +4721,17 @@ export {
|
|
|
4398
4721
|
ProviderError,
|
|
4399
4722
|
REDACTED as REDACTION_MARKER,
|
|
4400
4723
|
StreamResult,
|
|
4724
|
+
TOOL_CALL_NAME_RULES,
|
|
4401
4725
|
clampProviderContextImages,
|
|
4402
4726
|
classifyProviderError,
|
|
4727
|
+
dropInvalidToolCalls,
|
|
4403
4728
|
environmentSecrets,
|
|
4404
4729
|
formatError,
|
|
4405
4730
|
formatErrorForDisplay,
|
|
4406
4731
|
hasLoneSurrogate,
|
|
4407
4732
|
isHardBillingMessage,
|
|
4408
4733
|
isUsageLimitError,
|
|
4734
|
+
isValidToolCallName,
|
|
4409
4735
|
localWireModelId,
|
|
4410
4736
|
palsuAssistantMessage,
|
|
4411
4737
|
palsuText,
|
|
@@ -4424,6 +4750,7 @@ export {
|
|
|
4424
4750
|
stream,
|
|
4425
4751
|
toAnthropicMessages,
|
|
4426
4752
|
toOpenAIMessages,
|
|
4427
|
-
toWellFormedText
|
|
4753
|
+
toWellFormedText,
|
|
4754
|
+
toolCallNameRuleFor
|
|
4428
4755
|
};
|
|
4429
4756
|
//# sourceMappingURL=index.js.map
|