@kenkaiiii/gg-ai 4.3.243 → 4.5.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 +242 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -3
- package/dist/index.d.ts +26 -3
- package/dist/index.js +241 -17
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -23,6 +23,11 @@ interface VideoContent {
|
|
|
23
23
|
type: "video";
|
|
24
24
|
mediaType: string;
|
|
25
25
|
data: string;
|
|
26
|
+
/** Moonshot/Kimi file id (e.g. "d4f0…") after uploading via the files API.
|
|
27
|
+
* Moonshot rejects inline base64 video; the provider uploads the clip once
|
|
28
|
+
* and caches the id here so later turns reference `ms://<fileId>` instead of
|
|
29
|
+
* re-sending the bytes. */
|
|
30
|
+
fileId?: string;
|
|
26
31
|
}
|
|
27
32
|
interface ToolCall {
|
|
28
33
|
type: "tool_call";
|
|
@@ -30,7 +35,7 @@ interface ToolCall {
|
|
|
30
35
|
name: string;
|
|
31
36
|
args: Record<string, unknown>;
|
|
32
37
|
}
|
|
33
|
-
type ToolResultContent = string | (TextContent | ImageContent)[];
|
|
38
|
+
type ToolResultContent = string | (TextContent | ImageContent | VideoContent)[];
|
|
34
39
|
interface ToolResult {
|
|
35
40
|
type: "tool_result";
|
|
36
41
|
toolCallId: string;
|
|
@@ -208,6 +213,11 @@ interface StreamOptions {
|
|
|
208
213
|
* version should pass it here. Ignored for non-Anthropic providers and for
|
|
209
214
|
* Anthropic requests using a regular API key. */
|
|
210
215
|
userAgent?: string;
|
|
216
|
+
/** Extra HTTP headers attached to every model request. Used by providers
|
|
217
|
+
* whose endpoint gates on client identity (e.g. Kimi For Coding requires a
|
|
218
|
+
* `User-Agent: kimi-code-cli/...` and `X-Msh-*` device headers). Merged
|
|
219
|
+
* into the underlying SDK's default headers. */
|
|
220
|
+
defaultHeaders?: Record<string, string>;
|
|
211
221
|
}
|
|
212
222
|
|
|
213
223
|
/**
|
|
@@ -330,7 +340,7 @@ declare const providerRegistry: ProviderRegistryImpl;
|
|
|
330
340
|
* Cannot read property 'foo' of undefined
|
|
331
341
|
* → This is a ggcoder bug — please report it.
|
|
332
342
|
*/
|
|
333
|
-
type ErrorSource = "provider" | "ggcoder" | "network" | "auth";
|
|
343
|
+
type ErrorSource = "provider" | "ggcoder" | "network" | "auth" | "capability";
|
|
334
344
|
interface FormattedError {
|
|
335
345
|
/** Plain-English headline, e.g. "OpenAI returned an error." */
|
|
336
346
|
headline: string;
|
|
@@ -404,6 +414,19 @@ declare function formatError(err: unknown): FormattedError;
|
|
|
404
414
|
*/
|
|
405
415
|
declare function formatErrorForDisplay(err: unknown): string;
|
|
406
416
|
|
|
417
|
+
/**
|
|
418
|
+
* Inspect a raw provider error message and tag it with a clearer, actionable
|
|
419
|
+
* prefix so a worker orchestrator can route on intent instead of regexing JSON.
|
|
420
|
+
* Preserves the original message verbatim after the prefix — helpful for
|
|
421
|
+
* debugging.
|
|
422
|
+
*
|
|
423
|
+
* Order matters: context-overflow is checked first because some providers wrap
|
|
424
|
+
* overflow errors in HTTP 429 envelopes; we want the structural meaning, not
|
|
425
|
+
* the transport status. Billing comes before auth/rate-limit because "402
|
|
426
|
+
* Payment Required" must not be mis-routed as a rate-limit retry.
|
|
427
|
+
*/
|
|
428
|
+
declare function classifyProviderError(message: string): string;
|
|
429
|
+
|
|
407
430
|
/**
|
|
408
431
|
* Provider-level diagnostic hook. Mirrors the pattern used by gg-agent's
|
|
409
432
|
* setStreamDiagnostic — the host app wires a callback (typically writing to
|
|
@@ -496,4 +519,4 @@ interface PalsuProviderConfig {
|
|
|
496
519
|
*/
|
|
497
520
|
declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
|
|
498
521
|
|
|
499
|
-
export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, formatError, formatErrorForDisplay, isHardBillingMessage, isUsageLimitError, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
|
|
522
|
+
export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, classifyProviderError, formatError, formatErrorForDisplay, isHardBillingMessage, isUsageLimitError, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,11 @@ interface VideoContent {
|
|
|
23
23
|
type: "video";
|
|
24
24
|
mediaType: string;
|
|
25
25
|
data: string;
|
|
26
|
+
/** Moonshot/Kimi file id (e.g. "d4f0…") after uploading via the files API.
|
|
27
|
+
* Moonshot rejects inline base64 video; the provider uploads the clip once
|
|
28
|
+
* and caches the id here so later turns reference `ms://<fileId>` instead of
|
|
29
|
+
* re-sending the bytes. */
|
|
30
|
+
fileId?: string;
|
|
26
31
|
}
|
|
27
32
|
interface ToolCall {
|
|
28
33
|
type: "tool_call";
|
|
@@ -30,7 +35,7 @@ interface ToolCall {
|
|
|
30
35
|
name: string;
|
|
31
36
|
args: Record<string, unknown>;
|
|
32
37
|
}
|
|
33
|
-
type ToolResultContent = string | (TextContent | ImageContent)[];
|
|
38
|
+
type ToolResultContent = string | (TextContent | ImageContent | VideoContent)[];
|
|
34
39
|
interface ToolResult {
|
|
35
40
|
type: "tool_result";
|
|
36
41
|
toolCallId: string;
|
|
@@ -208,6 +213,11 @@ interface StreamOptions {
|
|
|
208
213
|
* version should pass it here. Ignored for non-Anthropic providers and for
|
|
209
214
|
* Anthropic requests using a regular API key. */
|
|
210
215
|
userAgent?: string;
|
|
216
|
+
/** Extra HTTP headers attached to every model request. Used by providers
|
|
217
|
+
* whose endpoint gates on client identity (e.g. Kimi For Coding requires a
|
|
218
|
+
* `User-Agent: kimi-code-cli/...` and `X-Msh-*` device headers). Merged
|
|
219
|
+
* into the underlying SDK's default headers. */
|
|
220
|
+
defaultHeaders?: Record<string, string>;
|
|
211
221
|
}
|
|
212
222
|
|
|
213
223
|
/**
|
|
@@ -330,7 +340,7 @@ declare const providerRegistry: ProviderRegistryImpl;
|
|
|
330
340
|
* Cannot read property 'foo' of undefined
|
|
331
341
|
* → This is a ggcoder bug — please report it.
|
|
332
342
|
*/
|
|
333
|
-
type ErrorSource = "provider" | "ggcoder" | "network" | "auth";
|
|
343
|
+
type ErrorSource = "provider" | "ggcoder" | "network" | "auth" | "capability";
|
|
334
344
|
interface FormattedError {
|
|
335
345
|
/** Plain-English headline, e.g. "OpenAI returned an error." */
|
|
336
346
|
headline: string;
|
|
@@ -404,6 +414,19 @@ declare function formatError(err: unknown): FormattedError;
|
|
|
404
414
|
*/
|
|
405
415
|
declare function formatErrorForDisplay(err: unknown): string;
|
|
406
416
|
|
|
417
|
+
/**
|
|
418
|
+
* Inspect a raw provider error message and tag it with a clearer, actionable
|
|
419
|
+
* prefix so a worker orchestrator can route on intent instead of regexing JSON.
|
|
420
|
+
* Preserves the original message verbatim after the prefix — helpful for
|
|
421
|
+
* debugging.
|
|
422
|
+
*
|
|
423
|
+
* Order matters: context-overflow is checked first because some providers wrap
|
|
424
|
+
* overflow errors in HTTP 429 envelopes; we want the structural meaning, not
|
|
425
|
+
* the transport status. Billing comes before auth/rate-limit because "402
|
|
426
|
+
* Payment Required" must not be mis-routed as a rate-limit retry.
|
|
427
|
+
*/
|
|
428
|
+
declare function classifyProviderError(message: string): string;
|
|
429
|
+
|
|
407
430
|
/**
|
|
408
431
|
* Provider-level diagnostic hook. Mirrors the pattern used by gg-agent's
|
|
409
432
|
* setStreamDiagnostic — the host app wires a callback (typically writing to
|
|
@@ -496,4 +519,4 @@ interface PalsuProviderConfig {
|
|
|
496
519
|
*/
|
|
497
520
|
declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
|
|
498
521
|
|
|
499
|
-
export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, formatError, formatErrorForDisplay, isHardBillingMessage, isUsageLimitError, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
|
|
522
|
+
export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, classifyProviderError, formatError, formatErrorForDisplay, isHardBillingMessage, isUsageLimitError, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,12 @@ var GGAIError = class extends Error {
|
|
|
25
25
|
this.hint = options?.hint;
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
|
+
var VideoUnsupportedError = class extends GGAIError {
|
|
29
|
+
constructor() {
|
|
30
|
+
super("This model can't analyze video.", { source: "capability" });
|
|
31
|
+
this.name = "VideoUnsupportedError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
28
34
|
var ProviderError = class extends GGAIError {
|
|
29
35
|
provider;
|
|
30
36
|
statusCode;
|
|
@@ -140,6 +146,14 @@ function finaliseBySource(source, message, requestId, hint) {
|
|
|
140
146
|
guidance: hint ?? providerGuidance(void 0, message, void 0),
|
|
141
147
|
...requestId ? { requestId } : {}
|
|
142
148
|
};
|
|
149
|
+
case "capability":
|
|
150
|
+
return {
|
|
151
|
+
headline: message,
|
|
152
|
+
source,
|
|
153
|
+
message: "",
|
|
154
|
+
guidance: hint ?? "Only Kimi, Gemini, and MiniMax can analyze video. Switch with /model.",
|
|
155
|
+
...requestId ? { requestId } : {}
|
|
156
|
+
};
|
|
143
157
|
case "ggcoder":
|
|
144
158
|
return {
|
|
145
159
|
headline: "ggcoder hit an unexpected error.",
|
|
@@ -500,6 +514,10 @@ function toolResultImages(content) {
|
|
|
500
514
|
if (typeof content === "string") return [];
|
|
501
515
|
return content.filter((b) => b.type === "image");
|
|
502
516
|
}
|
|
517
|
+
function toolResultVideos(content) {
|
|
518
|
+
if (typeof content === "string") return [];
|
|
519
|
+
return content.filter((b) => b.type === "video");
|
|
520
|
+
}
|
|
503
521
|
function toAnthropicCacheControl(retention, baseUrl) {
|
|
504
522
|
const resolved = retention ?? "short";
|
|
505
523
|
if (resolved === "none") return void 0;
|
|
@@ -510,6 +528,12 @@ function toAnthropicToolResultContent(content) {
|
|
|
510
528
|
if (typeof content === "string") return content;
|
|
511
529
|
return content.map((block) => {
|
|
512
530
|
if (block.type === "text") return { type: "text", text: block.text };
|
|
531
|
+
if (block.type === "video") {
|
|
532
|
+
return {
|
|
533
|
+
type: "video",
|
|
534
|
+
source: { type: "base64", media_type: block.mediaType, data: block.data }
|
|
535
|
+
};
|
|
536
|
+
}
|
|
513
537
|
return {
|
|
514
538
|
type: "image",
|
|
515
539
|
source: {
|
|
@@ -579,6 +603,8 @@ function toAnthropicMessages(messages, cacheControl) {
|
|
|
579
603
|
if (msg.role === "tool") {
|
|
580
604
|
out.push({
|
|
581
605
|
role: "user",
|
|
606
|
+
// Cast covers the video block (used by the Anthropic-compatible MiniMax
|
|
607
|
+
// API), which isn't in the first-party Anthropic tool_result types.
|
|
582
608
|
content: msg.content.map((result) => ({
|
|
583
609
|
type: "tool_result",
|
|
584
610
|
tool_use_id: remapAnthropicToolCallId(result.toolCallId, idMap),
|
|
@@ -719,11 +745,10 @@ function toOpenAIMessages(messages, options) {
|
|
|
719
745
|
(part) => {
|
|
720
746
|
if (part.type === "text") return { type: "text", text: part.text };
|
|
721
747
|
if (part.type === "video") {
|
|
748
|
+
const videoUrl = part.fileId ? { url: `ms://${part.fileId}`, id: part.fileId } : { url: `data:${part.mediaType};base64,${part.data}` };
|
|
722
749
|
return {
|
|
723
750
|
type: "video_url",
|
|
724
|
-
video_url:
|
|
725
|
-
url: `data:${part.mediaType};base64,${part.data}`
|
|
726
|
-
}
|
|
751
|
+
video_url: videoUrl
|
|
727
752
|
};
|
|
728
753
|
}
|
|
729
754
|
return {
|
|
@@ -768,11 +793,27 @@ function toOpenAIMessages(messages, options) {
|
|
|
768
793
|
continue;
|
|
769
794
|
}
|
|
770
795
|
if (msg.role === "tool") {
|
|
796
|
+
const isMoonshot = options?.provider === "moonshot";
|
|
771
797
|
const imageBlocks = [];
|
|
772
798
|
for (const result of msg.content) {
|
|
773
799
|
const text = toolResultText(result.content);
|
|
774
800
|
const images = toolResultImages(result.content);
|
|
801
|
+
const videos = isMoonshot ? toolResultVideos(result.content) : [];
|
|
775
802
|
const hasText = text.length > 0;
|
|
803
|
+
if (videos.length > 0) {
|
|
804
|
+
const parts = [];
|
|
805
|
+
if (hasText) parts.push({ type: "text", text });
|
|
806
|
+
const videoParts = videos.map((v) => {
|
|
807
|
+
const videoUrl = v.fileId ? { url: `ms://${v.fileId}`, id: v.fileId } : { url: `data:${v.mediaType};base64,${v.data}` };
|
|
808
|
+
return { type: "video_url", video_url: videoUrl };
|
|
809
|
+
});
|
|
810
|
+
out.push({
|
|
811
|
+
role: "tool",
|
|
812
|
+
tool_call_id: remapToolCallId(result.toolCallId, idMap),
|
|
813
|
+
content: [...parts, ...videoParts]
|
|
814
|
+
});
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
776
817
|
out.push({
|
|
777
818
|
role: "tool",
|
|
778
819
|
tool_call_id: remapToolCallId(result.toolCallId, idMap),
|
|
@@ -1357,6 +1398,75 @@ function fnv1aHash(value) {
|
|
|
1357
1398
|
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
1358
1399
|
}
|
|
1359
1400
|
|
|
1401
|
+
// src/utils/diag.ts
|
|
1402
|
+
var _diagFn = null;
|
|
1403
|
+
function setProviderDiagnostic(fn) {
|
|
1404
|
+
_diagFn = fn;
|
|
1405
|
+
}
|
|
1406
|
+
function providerDiag(phase, data) {
|
|
1407
|
+
_diagFn?.(phase, data);
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
// src/providers/moonshot-video.ts
|
|
1411
|
+
async function uploadMoonshotVideos(client, messages, signal) {
|
|
1412
|
+
for (const msg of messages) {
|
|
1413
|
+
if (typeof msg.content === "string") continue;
|
|
1414
|
+
for (const part of msg.content) {
|
|
1415
|
+
if (part.type === "video") {
|
|
1416
|
+
await ensureUploaded(client, part, signal);
|
|
1417
|
+
continue;
|
|
1418
|
+
}
|
|
1419
|
+
if (part.type === "tool_result" && Array.isArray(part.content)) {
|
|
1420
|
+
for (const inner of part.content) {
|
|
1421
|
+
if (inner.type === "video") {
|
|
1422
|
+
await ensureUploaded(client, inner, signal);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
async function ensureUploaded(client, video, signal) {
|
|
1430
|
+
if (video.fileId) {
|
|
1431
|
+
providerDiag("moonshot_video_cached", { fileId: video.fileId });
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
if (!video.data) {
|
|
1435
|
+
providerDiag("moonshot_video_skipped_no_data", {});
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
providerDiag("moonshot_video_upload_start", {
|
|
1439
|
+
mediaType: video.mediaType,
|
|
1440
|
+
bytes: Math.floor(video.data.length * 3 / 4)
|
|
1441
|
+
});
|
|
1442
|
+
video.fileId = await uploadOne(client, video, signal);
|
|
1443
|
+
providerDiag("moonshot_video_upload_done", { fileId: video.fileId });
|
|
1444
|
+
}
|
|
1445
|
+
async function uploadOne(client, video, signal) {
|
|
1446
|
+
const bytes = Buffer.from(video.data, "base64");
|
|
1447
|
+
const mediaType = video.mediaType || "video/mp4";
|
|
1448
|
+
const filename = `upload.${extForMime(mediaType)}`;
|
|
1449
|
+
const file = new File([new Uint8Array(bytes)], filename, { type: mediaType });
|
|
1450
|
+
const uploaded = await client.files.create(
|
|
1451
|
+
{ file, purpose: "video" },
|
|
1452
|
+
signal ? { signal } : void 0
|
|
1453
|
+
);
|
|
1454
|
+
return uploaded.id;
|
|
1455
|
+
}
|
|
1456
|
+
var MIME_TO_EXT = {
|
|
1457
|
+
"video/mp4": "mp4",
|
|
1458
|
+
"video/mpeg": "mpeg",
|
|
1459
|
+
"video/quicktime": "mov",
|
|
1460
|
+
"video/webm": "webm",
|
|
1461
|
+
"video/x-matroska": "mkv",
|
|
1462
|
+
"video/x-msvideo": "avi",
|
|
1463
|
+
"video/x-flv": "flv",
|
|
1464
|
+
"video/3gpp": "3gp"
|
|
1465
|
+
};
|
|
1466
|
+
function extForMime(mediaType) {
|
|
1467
|
+
return MIME_TO_EXT[mediaType.toLowerCase()] ?? "mp4";
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1360
1470
|
// src/utils/env.ts
|
|
1361
1471
|
function getEnvironment() {
|
|
1362
1472
|
return globalThis.process?.env;
|
|
@@ -1386,7 +1496,8 @@ function createClient2(options) {
|
|
|
1386
1496
|
return new OpenAI({
|
|
1387
1497
|
apiKey: options.apiKey,
|
|
1388
1498
|
...options.baseUrl ? { baseURL: options.baseUrl } : {},
|
|
1389
|
-
...options.fetch ? { fetch: options.fetch } : {}
|
|
1499
|
+
...options.fetch ? { fetch: options.fetch } : {},
|
|
1500
|
+
...options.defaultHeaders ? { defaultHeaders: options.defaultHeaders } : {}
|
|
1390
1501
|
});
|
|
1391
1502
|
}
|
|
1392
1503
|
function streamOpenAI(options) {
|
|
@@ -1399,6 +1510,13 @@ async function* runStream2(options) {
|
|
|
1399
1510
|
const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" || options.provider === "xiaomi";
|
|
1400
1511
|
const downgradedImages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
1401
1512
|
const downgradedMessages = downgradeUnsupportedVideos(downgradedImages, options.supportsVideo);
|
|
1513
|
+
if (options.provider === "moonshot") {
|
|
1514
|
+
try {
|
|
1515
|
+
await uploadMoonshotVideos(client, downgradedMessages, options.signal);
|
|
1516
|
+
} catch (err) {
|
|
1517
|
+
throw toError2(err, providerName);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1402
1520
|
const messages = toOpenAIMessages(downgradedMessages, {
|
|
1403
1521
|
provider: options.provider,
|
|
1404
1522
|
thinking: !!options.thinking,
|
|
@@ -1702,15 +1820,6 @@ function toError2(err, provider = "openai") {
|
|
|
1702
1820
|
// src/providers/openai-codex.ts
|
|
1703
1821
|
import os from "os";
|
|
1704
1822
|
|
|
1705
|
-
// src/utils/diag.ts
|
|
1706
|
-
var _diagFn = null;
|
|
1707
|
-
function setProviderDiagnostic(fn) {
|
|
1708
|
-
_diagFn = fn;
|
|
1709
|
-
}
|
|
1710
|
-
function providerDiag(phase, data) {
|
|
1711
|
-
_diagFn?.(phase, data);
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
1823
|
// src/utils/sse.ts
|
|
1715
1824
|
function parseSseBuffer(buffer) {
|
|
1716
1825
|
const events = [];
|
|
@@ -2359,6 +2468,13 @@ ${msg.content}` : msg.content;
|
|
|
2359
2468
|
}
|
|
2360
2469
|
}
|
|
2361
2470
|
});
|
|
2471
|
+
if (typeof result.content !== "string") {
|
|
2472
|
+
for (const block of result.content) {
|
|
2473
|
+
if (block.type === "video") {
|
|
2474
|
+
parts.push({ inlineData: { mimeType: block.mediaType, data: block.data } });
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2362
2478
|
}
|
|
2363
2479
|
if (parts.length > 0) contents.push({ role: "user", parts });
|
|
2364
2480
|
}
|
|
@@ -2756,6 +2872,7 @@ var providerRegistry = new ProviderRegistryImpl();
|
|
|
2756
2872
|
|
|
2757
2873
|
// src/stream.ts
|
|
2758
2874
|
var GLM_CODING_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
|
|
2875
|
+
var KIMI_CODE_USER_AGENT = `kimi-code-cli/${process.env.KIMI_CODE_VERSION ?? "1.0.11"}`;
|
|
2759
2876
|
providerRegistry.register("anthropic", {
|
|
2760
2877
|
stream: (options) => streamAnthropic(options)
|
|
2761
2878
|
});
|
|
@@ -2784,10 +2901,11 @@ providerRegistry.register("glm", {
|
|
|
2784
2901
|
})
|
|
2785
2902
|
});
|
|
2786
2903
|
providerRegistry.register("moonshot", {
|
|
2787
|
-
stream: (options) =>
|
|
2788
|
-
|
|
2789
|
-
baseUrl: options.
|
|
2790
|
-
|
|
2904
|
+
stream: (options) => {
|
|
2905
|
+
const baseUrl = options.baseUrl ?? "https://api.moonshot.ai/v1";
|
|
2906
|
+
const defaultHeaders = baseUrl.includes("api.kimi.com") ? { "User-Agent": KIMI_CODE_USER_AGENT, ...options.defaultHeaders } : options.defaultHeaders;
|
|
2907
|
+
return streamOpenAI({ ...options, baseUrl, defaultHeaders });
|
|
2908
|
+
}
|
|
2791
2909
|
});
|
|
2792
2910
|
providerRegistry.register("deepseek", {
|
|
2793
2911
|
stream: (options) => streamOpenAI({
|
|
@@ -2820,8 +2938,113 @@ function stream(options) {
|
|
|
2820
2938
|
`Unknown provider: "${options.provider}". Registered: ${providerRegistry.list().join(", ")}`
|
|
2821
2939
|
);
|
|
2822
2940
|
}
|
|
2941
|
+
if (options.supportsVideo !== true && messagesContainVideo(options.messages)) {
|
|
2942
|
+
throw new VideoUnsupportedError();
|
|
2943
|
+
}
|
|
2823
2944
|
return entry.stream(options);
|
|
2824
2945
|
}
|
|
2946
|
+
function messagesContainVideo(messages) {
|
|
2947
|
+
for (const msg of messages) {
|
|
2948
|
+
if (typeof msg.content === "string" || !Array.isArray(msg.content)) continue;
|
|
2949
|
+
for (const part of msg.content) {
|
|
2950
|
+
if (part.type === "video") return true;
|
|
2951
|
+
if (part.type === "tool_result" && Array.isArray(part.content)) {
|
|
2952
|
+
if (part.content.some((block) => block.type === "video")) return true;
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
return false;
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2959
|
+
// src/error-classification.ts
|
|
2960
|
+
var CONTEXT_OVERFLOW_PATTERNS = [
|
|
2961
|
+
/context_length_exceeded/i,
|
|
2962
|
+
/context length exceeded/i,
|
|
2963
|
+
/context window/i,
|
|
2964
|
+
// OpenAI Codex / Responses
|
|
2965
|
+
/maximum context length/i,
|
|
2966
|
+
// OpenAI / OpenRouter / Mistral
|
|
2967
|
+
/prompt is too long/i,
|
|
2968
|
+
// Anthropic
|
|
2969
|
+
/request_too_large/i,
|
|
2970
|
+
// Anthropic HTTP 413
|
|
2971
|
+
/input is too long/i,
|
|
2972
|
+
// Bedrock
|
|
2973
|
+
/input token count.*exceeds the maximum/i,
|
|
2974
|
+
// Gemini
|
|
2975
|
+
/maximum prompt length/i,
|
|
2976
|
+
// xAI / Grok
|
|
2977
|
+
/reduce the length of the messages/i,
|
|
2978
|
+
// Groq
|
|
2979
|
+
/too large for model/i,
|
|
2980
|
+
// Mistral
|
|
2981
|
+
/token limit/i
|
|
2982
|
+
// generic
|
|
2983
|
+
];
|
|
2984
|
+
var RATE_LIMIT_PATTERNS = [
|
|
2985
|
+
/rate[ _-]?limit/i,
|
|
2986
|
+
/\b429\b/,
|
|
2987
|
+
/too many requests/i,
|
|
2988
|
+
/tokens per minute/i,
|
|
2989
|
+
/requests per minute/i
|
|
2990
|
+
];
|
|
2991
|
+
var PROVIDER_TRANSIENT_PATTERNS = [
|
|
2992
|
+
/\b5\d\d\b/,
|
|
2993
|
+
/api_error/i,
|
|
2994
|
+
/server_error/i,
|
|
2995
|
+
/internal server error/i,
|
|
2996
|
+
/bad gateway/i,
|
|
2997
|
+
/service unavailable/i,
|
|
2998
|
+
/gateway timeout/i,
|
|
2999
|
+
/overloaded/i,
|
|
3000
|
+
/\b529\b/
|
|
3001
|
+
];
|
|
3002
|
+
var BILLING_PATTERNS = [
|
|
3003
|
+
/payment required/i,
|
|
3004
|
+
/\b402\b/,
|
|
3005
|
+
/quota_exceeded/i,
|
|
3006
|
+
// underscore variant not in isHardBillingMessage
|
|
3007
|
+
/credit balance/i
|
|
3008
|
+
];
|
|
3009
|
+
var AUTH_PATTERNS = [
|
|
3010
|
+
/invalid[ _]api[ _]key/i,
|
|
3011
|
+
/unauthorized/i,
|
|
3012
|
+
/\b401\b/,
|
|
3013
|
+
/authentication[ _]failed/i,
|
|
3014
|
+
/please run \/login/i
|
|
3015
|
+
// Anthropic Claude Code-style hint
|
|
3016
|
+
];
|
|
3017
|
+
function matchesAny(message, patterns) {
|
|
3018
|
+
return patterns.some((p) => p.test(message));
|
|
3019
|
+
}
|
|
3020
|
+
function classifyProviderError(message) {
|
|
3021
|
+
if (matchesAny(message, CONTEXT_OVERFLOW_PATTERNS)) {
|
|
3022
|
+
return `[context_overflow] Worker context window exceeded \u2014 the conversation is too large to continue. Recovery: call reset_worker(project) to wipe history, then re-prompt with the task. Re-prompting WITHOUT reset will fail the same way.
|
|
3023
|
+
|
|
3024
|
+
Original: ${message}`;
|
|
3025
|
+
}
|
|
3026
|
+
if (isHardBillingMessage(message) || matchesAny(message, BILLING_PATTERNS)) {
|
|
3027
|
+
return `[billing] Provider billing/quota issue. Recovery: surface to the user \u2014 they need to top up or switch providers. Do NOT retry.
|
|
3028
|
+
|
|
3029
|
+
Original: ${message}`;
|
|
3030
|
+
}
|
|
3031
|
+
if (matchesAny(message, AUTH_PATTERNS)) {
|
|
3032
|
+
return `[auth] Provider authentication failed. Recovery: surface to the user \u2014 they need to re-login. Do NOT retry.
|
|
3033
|
+
|
|
3034
|
+
Original: ${message}`;
|
|
3035
|
+
}
|
|
3036
|
+
if (matchesAny(message, RATE_LIMIT_PATTERNS)) {
|
|
3037
|
+
return `[rate_limited] Provider rate limit hit. Recovery: wait ~30s, then re-prompt the same worker (no reset needed).
|
|
3038
|
+
|
|
3039
|
+
Original: ${message}`;
|
|
3040
|
+
}
|
|
3041
|
+
if (matchesAny(message, PROVIDER_TRANSIENT_PATTERNS)) {
|
|
3042
|
+
return `[provider_transient] Provider server-side/transient error. Recovery: wait briefly, then re-prompt the same worker (no reset needed). If it keeps happening, switch models/providers or check provider status.
|
|
3043
|
+
|
|
3044
|
+
Original: ${message}`;
|
|
3045
|
+
}
|
|
3046
|
+
return message;
|
|
3047
|
+
}
|
|
2825
3048
|
|
|
2826
3049
|
// src/providers/palsu.ts
|
|
2827
3050
|
function palsuText(text) {
|
|
@@ -2979,6 +3202,7 @@ export {
|
|
|
2979
3202
|
GGAIError,
|
|
2980
3203
|
ProviderError,
|
|
2981
3204
|
StreamResult,
|
|
3205
|
+
classifyProviderError,
|
|
2982
3206
|
formatError,
|
|
2983
3207
|
formatErrorForDisplay,
|
|
2984
3208
|
isHardBillingMessage,
|