@kenkaiiii/gg-ai 4.4.0 → 4.6.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 +166 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +166 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -79,6 +79,12 @@ var GGAIError = class extends Error {
|
|
|
79
79
|
this.hint = options?.hint;
|
|
80
80
|
}
|
|
81
81
|
};
|
|
82
|
+
var VideoUnsupportedError = class extends GGAIError {
|
|
83
|
+
constructor() {
|
|
84
|
+
super("This model can't analyze video.", { source: "capability" });
|
|
85
|
+
this.name = "VideoUnsupportedError";
|
|
86
|
+
}
|
|
87
|
+
};
|
|
82
88
|
var ProviderError = class extends GGAIError {
|
|
83
89
|
provider;
|
|
84
90
|
statusCode;
|
|
@@ -194,6 +200,14 @@ function finaliseBySource(source, message, requestId, hint) {
|
|
|
194
200
|
guidance: hint ?? providerGuidance(void 0, message, void 0),
|
|
195
201
|
...requestId ? { requestId } : {}
|
|
196
202
|
};
|
|
203
|
+
case "capability":
|
|
204
|
+
return {
|
|
205
|
+
headline: message,
|
|
206
|
+
source,
|
|
207
|
+
message: "",
|
|
208
|
+
guidance: hint ?? "Only Kimi, Gemini, MiniMax, and MiMo-V2.5 can analyze video. Switch with /model.",
|
|
209
|
+
...requestId ? { requestId } : {}
|
|
210
|
+
};
|
|
197
211
|
case "ggcoder":
|
|
198
212
|
return {
|
|
199
213
|
headline: "ggcoder hit an unexpected error.",
|
|
@@ -554,6 +568,10 @@ function toolResultImages(content) {
|
|
|
554
568
|
if (typeof content === "string") return [];
|
|
555
569
|
return content.filter((b) => b.type === "image");
|
|
556
570
|
}
|
|
571
|
+
function toolResultVideos(content) {
|
|
572
|
+
if (typeof content === "string") return [];
|
|
573
|
+
return content.filter((b) => b.type === "video");
|
|
574
|
+
}
|
|
557
575
|
function toAnthropicCacheControl(retention, baseUrl) {
|
|
558
576
|
const resolved = retention ?? "short";
|
|
559
577
|
if (resolved === "none") return void 0;
|
|
@@ -564,6 +582,12 @@ function toAnthropicToolResultContent(content) {
|
|
|
564
582
|
if (typeof content === "string") return content;
|
|
565
583
|
return content.map((block) => {
|
|
566
584
|
if (block.type === "text") return { type: "text", text: block.text };
|
|
585
|
+
if (block.type === "video") {
|
|
586
|
+
return {
|
|
587
|
+
type: "video",
|
|
588
|
+
source: { type: "base64", media_type: block.mediaType, data: block.data }
|
|
589
|
+
};
|
|
590
|
+
}
|
|
567
591
|
return {
|
|
568
592
|
type: "image",
|
|
569
593
|
source: {
|
|
@@ -633,6 +657,8 @@ function toAnthropicMessages(messages, cacheControl) {
|
|
|
633
657
|
if (msg.role === "tool") {
|
|
634
658
|
out.push({
|
|
635
659
|
role: "user",
|
|
660
|
+
// Cast covers the video block (used by the Anthropic-compatible MiniMax
|
|
661
|
+
// API), which isn't in the first-party Anthropic tool_result types.
|
|
636
662
|
content: msg.content.map((result) => ({
|
|
637
663
|
type: "tool_result",
|
|
638
664
|
tool_use_id: remapAnthropicToolCallId(result.toolCallId, idMap),
|
|
@@ -773,11 +799,10 @@ function toOpenAIMessages(messages, options) {
|
|
|
773
799
|
(part) => {
|
|
774
800
|
if (part.type === "text") return { type: "text", text: part.text };
|
|
775
801
|
if (part.type === "video") {
|
|
802
|
+
const videoUrl = part.fileId ? { url: `ms://${part.fileId}`, id: part.fileId } : { url: `data:${part.mediaType};base64,${part.data}` };
|
|
776
803
|
return {
|
|
777
804
|
type: "video_url",
|
|
778
|
-
video_url:
|
|
779
|
-
url: `data:${part.mediaType};base64,${part.data}`
|
|
780
|
-
}
|
|
805
|
+
video_url: videoUrl
|
|
781
806
|
};
|
|
782
807
|
}
|
|
783
808
|
return {
|
|
@@ -822,29 +847,56 @@ function toOpenAIMessages(messages, options) {
|
|
|
822
847
|
continue;
|
|
823
848
|
}
|
|
824
849
|
if (msg.role === "tool") {
|
|
825
|
-
const
|
|
850
|
+
const isMoonshot = options?.provider === "moonshot";
|
|
851
|
+
const followUpMediaBlocks = [];
|
|
852
|
+
let followUpHasVideo = false;
|
|
826
853
|
for (const result of msg.content) {
|
|
827
854
|
const text = toolResultText(result.content);
|
|
828
855
|
const images = toolResultImages(result.content);
|
|
856
|
+
const videos = toolResultVideos(result.content);
|
|
829
857
|
const hasText = text.length > 0;
|
|
858
|
+
if (isMoonshot && videos.length > 0) {
|
|
859
|
+
const parts = [];
|
|
860
|
+
if (hasText) parts.push({ type: "text", text });
|
|
861
|
+
const videoParts = videos.map((v) => {
|
|
862
|
+
const videoUrl = v.fileId ? { url: `ms://${v.fileId}`, id: v.fileId } : { url: `data:${v.mediaType};base64,${v.data}` };
|
|
863
|
+
return { type: "video_url", video_url: videoUrl };
|
|
864
|
+
});
|
|
865
|
+
out.push({
|
|
866
|
+
role: "tool",
|
|
867
|
+
tool_call_id: remapToolCallId(result.toolCallId, idMap),
|
|
868
|
+
content: [...parts, ...videoParts]
|
|
869
|
+
});
|
|
870
|
+
continue;
|
|
871
|
+
}
|
|
830
872
|
out.push({
|
|
831
873
|
role: "tool",
|
|
832
874
|
tool_call_id: remapToolCallId(result.toolCallId, idMap),
|
|
833
|
-
content: hasText ? text : "(see attached
|
|
875
|
+
content: hasText ? text : "(see attached media)"
|
|
834
876
|
});
|
|
835
877
|
if (images.length > 0 && options?.supportsImages !== false) {
|
|
836
878
|
for (const img of images) {
|
|
837
|
-
|
|
879
|
+
followUpMediaBlocks.push({
|
|
838
880
|
type: "image_url",
|
|
839
881
|
image_url: { url: `data:${img.mediaType};base64,${img.data}` }
|
|
840
882
|
});
|
|
841
883
|
}
|
|
842
884
|
}
|
|
885
|
+
if (!isMoonshot && videos.length > 0) {
|
|
886
|
+
for (const v of videos) {
|
|
887
|
+
followUpMediaBlocks.push({
|
|
888
|
+
type: "video_url",
|
|
889
|
+
video_url: { url: `data:${v.mediaType};base64,${v.data}` }
|
|
890
|
+
});
|
|
891
|
+
followUpHasVideo = true;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
843
894
|
}
|
|
844
|
-
if (
|
|
895
|
+
if (followUpMediaBlocks.length > 0) {
|
|
896
|
+
const label = followUpHasVideo ? "Attached media from tool result:" : "Attached image(s) from tool result:";
|
|
845
897
|
out.push({
|
|
846
898
|
role: "user",
|
|
847
|
-
content: [{ type: "text", text:
|
|
899
|
+
content: [{ type: "text", text: label }, ...followUpMediaBlocks]
|
|
848
900
|
});
|
|
849
901
|
}
|
|
850
902
|
}
|
|
@@ -1411,6 +1463,75 @@ function fnv1aHash(value) {
|
|
|
1411
1463
|
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
1412
1464
|
}
|
|
1413
1465
|
|
|
1466
|
+
// src/utils/diag.ts
|
|
1467
|
+
var _diagFn = null;
|
|
1468
|
+
function setProviderDiagnostic(fn) {
|
|
1469
|
+
_diagFn = fn;
|
|
1470
|
+
}
|
|
1471
|
+
function providerDiag(phase, data) {
|
|
1472
|
+
_diagFn?.(phase, data);
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// src/providers/moonshot-video.ts
|
|
1476
|
+
async function uploadMoonshotVideos(client, messages, signal) {
|
|
1477
|
+
for (const msg of messages) {
|
|
1478
|
+
if (typeof msg.content === "string") continue;
|
|
1479
|
+
for (const part of msg.content) {
|
|
1480
|
+
if (part.type === "video") {
|
|
1481
|
+
await ensureUploaded(client, part, signal);
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
if (part.type === "tool_result" && Array.isArray(part.content)) {
|
|
1485
|
+
for (const inner of part.content) {
|
|
1486
|
+
if (inner.type === "video") {
|
|
1487
|
+
await ensureUploaded(client, inner, signal);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
async function ensureUploaded(client, video, signal) {
|
|
1495
|
+
if (video.fileId) {
|
|
1496
|
+
providerDiag("moonshot_video_cached", { fileId: video.fileId });
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
if (!video.data) {
|
|
1500
|
+
providerDiag("moonshot_video_skipped_no_data", {});
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
providerDiag("moonshot_video_upload_start", {
|
|
1504
|
+
mediaType: video.mediaType,
|
|
1505
|
+
bytes: Math.floor(video.data.length * 3 / 4)
|
|
1506
|
+
});
|
|
1507
|
+
video.fileId = await uploadOne(client, video, signal);
|
|
1508
|
+
providerDiag("moonshot_video_upload_done", { fileId: video.fileId });
|
|
1509
|
+
}
|
|
1510
|
+
async function uploadOne(client, video, signal) {
|
|
1511
|
+
const bytes = Buffer.from(video.data, "base64");
|
|
1512
|
+
const mediaType = video.mediaType || "video/mp4";
|
|
1513
|
+
const filename = `upload.${extForMime(mediaType)}`;
|
|
1514
|
+
const file = new File([new Uint8Array(bytes)], filename, { type: mediaType });
|
|
1515
|
+
const uploaded = await client.files.create(
|
|
1516
|
+
{ file, purpose: "video" },
|
|
1517
|
+
signal ? { signal } : void 0
|
|
1518
|
+
);
|
|
1519
|
+
return uploaded.id;
|
|
1520
|
+
}
|
|
1521
|
+
var MIME_TO_EXT = {
|
|
1522
|
+
"video/mp4": "mp4",
|
|
1523
|
+
"video/mpeg": "mpeg",
|
|
1524
|
+
"video/quicktime": "mov",
|
|
1525
|
+
"video/webm": "webm",
|
|
1526
|
+
"video/x-matroska": "mkv",
|
|
1527
|
+
"video/x-msvideo": "avi",
|
|
1528
|
+
"video/x-flv": "flv",
|
|
1529
|
+
"video/3gpp": "3gp"
|
|
1530
|
+
};
|
|
1531
|
+
function extForMime(mediaType) {
|
|
1532
|
+
return MIME_TO_EXT[mediaType.toLowerCase()] ?? "mp4";
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1414
1535
|
// src/utils/env.ts
|
|
1415
1536
|
function getEnvironment() {
|
|
1416
1537
|
return globalThis.process?.env;
|
|
@@ -1440,7 +1561,8 @@ function createClient2(options) {
|
|
|
1440
1561
|
return new import_openai.default({
|
|
1441
1562
|
apiKey: options.apiKey,
|
|
1442
1563
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
1443
|
-
...options.fetch ? { fetch: options.fetch } : {}
|
|
1564
|
+
...options.fetch ? { fetch: options.fetch } : {},
|
|
1565
|
+
...options.defaultHeaders ? { defaultHeaders: options.defaultHeaders } : {}
|
|
1444
1566
|
});
|
|
1445
1567
|
}
|
|
1446
1568
|
function streamOpenAI(options) {
|
|
@@ -1453,6 +1575,13 @@ async function* runStream2(options) {
|
|
|
1453
1575
|
const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" || options.provider === "xiaomi";
|
|
1454
1576
|
const downgradedImages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
1455
1577
|
const downgradedMessages = downgradeUnsupportedVideos(downgradedImages, options.supportsVideo);
|
|
1578
|
+
if (options.provider === "moonshot") {
|
|
1579
|
+
try {
|
|
1580
|
+
await uploadMoonshotVideos(client, downgradedMessages, options.signal);
|
|
1581
|
+
} catch (err) {
|
|
1582
|
+
throw toError2(err, providerName);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1456
1585
|
const messages = toOpenAIMessages(downgradedMessages, {
|
|
1457
1586
|
provider: options.provider,
|
|
1458
1587
|
thinking: !!options.thinking,
|
|
@@ -1756,15 +1885,6 @@ function toError2(err, provider = "openai") {
|
|
|
1756
1885
|
// src/providers/openai-codex.ts
|
|
1757
1886
|
var import_node_os = __toESM(require("os"), 1);
|
|
1758
1887
|
|
|
1759
|
-
// src/utils/diag.ts
|
|
1760
|
-
var _diagFn = null;
|
|
1761
|
-
function setProviderDiagnostic(fn) {
|
|
1762
|
-
_diagFn = fn;
|
|
1763
|
-
}
|
|
1764
|
-
function providerDiag(phase, data) {
|
|
1765
|
-
_diagFn?.(phase, data);
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
1888
|
// src/utils/sse.ts
|
|
1769
1889
|
function parseSseBuffer(buffer) {
|
|
1770
1890
|
const events = [];
|
|
@@ -2413,6 +2533,13 @@ ${msg.content}` : msg.content;
|
|
|
2413
2533
|
}
|
|
2414
2534
|
}
|
|
2415
2535
|
});
|
|
2536
|
+
if (typeof result.content !== "string") {
|
|
2537
|
+
for (const block of result.content) {
|
|
2538
|
+
if (block.type === "video") {
|
|
2539
|
+
parts.push({ inlineData: { mimeType: block.mediaType, data: block.data } });
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2416
2543
|
}
|
|
2417
2544
|
if (parts.length > 0) contents.push({ role: "user", parts });
|
|
2418
2545
|
}
|
|
@@ -2810,6 +2937,7 @@ var providerRegistry = new ProviderRegistryImpl();
|
|
|
2810
2937
|
|
|
2811
2938
|
// src/stream.ts
|
|
2812
2939
|
var GLM_CODING_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
|
|
2940
|
+
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${process.env.KIMI_CODE_VERSION ?? "1.0.11"}`;
|
|
2813
2941
|
providerRegistry.register("anthropic", {
|
|
2814
2942
|
stream: (options) => streamAnthropic(options)
|
|
2815
2943
|
});
|
|
@@ -2838,10 +2966,11 @@ providerRegistry.register("glm", {
|
|
|
2838
2966
|
})
|
|
2839
2967
|
});
|
|
2840
2968
|
providerRegistry.register("moonshot", {
|
|
2841
|
-
stream: (options) =>
|
|
2842
|
-
|
|
2843
|
-
baseUrl: options.
|
|
2844
|
-
|
|
2969
|
+
stream: (options) => {
|
|
2970
|
+
const baseUrl = options.baseUrl ?? "https://api.moonshot.ai/v1";
|
|
2971
|
+
const defaultHeaders = baseUrl.includes("api.kimi.com") ? { "User-Agent": KIMI_CODE_USER_AGENT, ...options.defaultHeaders } : options.defaultHeaders;
|
|
2972
|
+
return streamOpenAI({ ...options, baseUrl, defaultHeaders });
|
|
2973
|
+
}
|
|
2845
2974
|
});
|
|
2846
2975
|
providerRegistry.register("deepseek", {
|
|
2847
2976
|
stream: (options) => streamOpenAI({
|
|
@@ -2874,8 +3003,23 @@ function stream(options) {
|
|
|
2874
3003
|
`Unknown provider: "${options.provider}". Registered: ${providerRegistry.list().join(", ")}`
|
|
2875
3004
|
);
|
|
2876
3005
|
}
|
|
3006
|
+
if (options.supportsVideo !== true && messagesContainVideo(options.messages)) {
|
|
3007
|
+
throw new VideoUnsupportedError();
|
|
3008
|
+
}
|
|
2877
3009
|
return entry.stream(options);
|
|
2878
3010
|
}
|
|
3011
|
+
function messagesContainVideo(messages) {
|
|
3012
|
+
for (const msg of messages) {
|
|
3013
|
+
if (typeof msg.content === "string" || !Array.isArray(msg.content)) continue;
|
|
3014
|
+
for (const part of msg.content) {
|
|
3015
|
+
if (part.type === "video") return true;
|
|
3016
|
+
if (part.type === "tool_result" && Array.isArray(part.content)) {
|
|
3017
|
+
if (part.content.some((block) => block.type === "video")) return true;
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
return false;
|
|
3022
|
+
}
|
|
2879
3023
|
|
|
2880
3024
|
// src/error-classification.ts
|
|
2881
3025
|
var CONTEXT_OVERFLOW_PATTERNS = [
|