@kenkaiiii/gg-ai 5.16.0 → 5.18.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/README.md +1 -1
- package/dist/index.cjs +259 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +254 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -444,6 +444,27 @@ declare function formatErrorForDisplay(err: unknown): string;
|
|
|
444
444
|
*/
|
|
445
445
|
declare function classifyProviderError(message: string): string;
|
|
446
446
|
|
|
447
|
+
declare const REDACTED = "[REDACTED]";
|
|
448
|
+
interface RedactionOptions {
|
|
449
|
+
/** Exact secret values to remove in addition to high-confidence formats. */
|
|
450
|
+
secrets?: Iterable<string>;
|
|
451
|
+
/** Maximum recursive object depth before a stable truncation marker is emitted. */
|
|
452
|
+
maxDepth?: number;
|
|
453
|
+
/** Maximum total array/object entries cloned before truncation markers are emitted. */
|
|
454
|
+
maxEntries?: number;
|
|
455
|
+
/** Maximum retained string length after sanitization. */
|
|
456
|
+
maxStringLength?: number;
|
|
457
|
+
}
|
|
458
|
+
/** Collect sufficiently distinctive secrets from security-sensitive environment variables. */
|
|
459
|
+
declare function environmentSecrets(env: Record<string, string | undefined>): string[];
|
|
460
|
+
/** Redact credentials from arbitrary text without mutating its source. */
|
|
461
|
+
declare function redactText(text: string, options?: RedactionOptions): string;
|
|
462
|
+
/**
|
|
463
|
+
* Recursively clone and sanitize transport/persistence payloads.
|
|
464
|
+
* Cycles, excessive depth, and excessive collection sizes become stable markers.
|
|
465
|
+
*/
|
|
466
|
+
declare function redactValue<T>(value: T, options?: RedactionOptions): T;
|
|
467
|
+
|
|
447
468
|
/**
|
|
448
469
|
* Provider-level diagnostic hook. Mirrors the pattern used by gg-agent's
|
|
449
470
|
* setStreamDiagnostic — the host app wires a callback (typically writing to
|
|
@@ -454,6 +475,12 @@ type ProviderDiagnosticFn = (phase: string, data?: Record<string, unknown>) => v
|
|
|
454
475
|
/** Register a diagnostic callback for provider-level tracing. */
|
|
455
476
|
declare function setProviderDiagnostic(fn: ProviderDiagnosticFn | null): void;
|
|
456
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Cap historical images before provider dispatch, removing the oldest first.
|
|
480
|
+
* The persisted/live conversation is never mutated; only modified messages and
|
|
481
|
+
* tool results are cloned for the outgoing request.
|
|
482
|
+
*/
|
|
483
|
+
declare function clampProviderContextImages(messages: Message[], provider: Provider, supportsImages: boolean | undefined): Message[];
|
|
457
484
|
declare function toAnthropicMessages(messages: Message[], cacheControl?: {
|
|
458
485
|
type: "ephemeral";
|
|
459
486
|
ttl?: "1h";
|
|
@@ -558,4 +585,4 @@ interface PalsuProviderConfig {
|
|
|
558
585
|
*/
|
|
559
586
|
declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
|
|
560
587
|
|
|
561
|
-
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, prewarmAnthropicCache, providerRegistry, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
|
|
588
|
+
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, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, 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, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, isHardBillingMessage, isUsageLimitError, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
|
package/dist/index.d.ts
CHANGED
|
@@ -444,6 +444,27 @@ declare function formatErrorForDisplay(err: unknown): string;
|
|
|
444
444
|
*/
|
|
445
445
|
declare function classifyProviderError(message: string): string;
|
|
446
446
|
|
|
447
|
+
declare const REDACTED = "[REDACTED]";
|
|
448
|
+
interface RedactionOptions {
|
|
449
|
+
/** Exact secret values to remove in addition to high-confidence formats. */
|
|
450
|
+
secrets?: Iterable<string>;
|
|
451
|
+
/** Maximum recursive object depth before a stable truncation marker is emitted. */
|
|
452
|
+
maxDepth?: number;
|
|
453
|
+
/** Maximum total array/object entries cloned before truncation markers are emitted. */
|
|
454
|
+
maxEntries?: number;
|
|
455
|
+
/** Maximum retained string length after sanitization. */
|
|
456
|
+
maxStringLength?: number;
|
|
457
|
+
}
|
|
458
|
+
/** Collect sufficiently distinctive secrets from security-sensitive environment variables. */
|
|
459
|
+
declare function environmentSecrets(env: Record<string, string | undefined>): string[];
|
|
460
|
+
/** Redact credentials from arbitrary text without mutating its source. */
|
|
461
|
+
declare function redactText(text: string, options?: RedactionOptions): string;
|
|
462
|
+
/**
|
|
463
|
+
* Recursively clone and sanitize transport/persistence payloads.
|
|
464
|
+
* Cycles, excessive depth, and excessive collection sizes become stable markers.
|
|
465
|
+
*/
|
|
466
|
+
declare function redactValue<T>(value: T, options?: RedactionOptions): T;
|
|
467
|
+
|
|
447
468
|
/**
|
|
448
469
|
* Provider-level diagnostic hook. Mirrors the pattern used by gg-agent's
|
|
449
470
|
* setStreamDiagnostic — the host app wires a callback (typically writing to
|
|
@@ -454,6 +475,12 @@ type ProviderDiagnosticFn = (phase: string, data?: Record<string, unknown>) => v
|
|
|
454
475
|
/** Register a diagnostic callback for provider-level tracing. */
|
|
455
476
|
declare function setProviderDiagnostic(fn: ProviderDiagnosticFn | null): void;
|
|
456
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Cap historical images before provider dispatch, removing the oldest first.
|
|
480
|
+
* The persisted/live conversation is never mutated; only modified messages and
|
|
481
|
+
* tool results are cloned for the outgoing request.
|
|
482
|
+
*/
|
|
483
|
+
declare function clampProviderContextImages(messages: Message[], provider: Provider, supportsImages: boolean | undefined): Message[];
|
|
457
484
|
declare function toAnthropicMessages(messages: Message[], cacheControl?: {
|
|
458
485
|
type: "ephemeral";
|
|
459
486
|
ttl?: "1h";
|
|
@@ -558,4 +585,4 @@ interface PalsuProviderConfig {
|
|
|
558
585
|
*/
|
|
559
586
|
declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
|
|
560
587
|
|
|
561
|
-
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, prewarmAnthropicCache, providerRegistry, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
|
|
588
|
+
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, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, 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, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, isHardBillingMessage, isUsageLimitError, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
|
package/dist/index.js
CHANGED
|
@@ -102,13 +102,20 @@ function isRawJsonErrorEcho(message) {
|
|
|
102
102
|
return false;
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
+
function isRawHtmlErrorEcho(message) {
|
|
106
|
+
const withoutStatus = message.trimStart().replace(/^\d{3}\s+/, "").trimStart();
|
|
107
|
+
return /^<!doctype\s+html(?:\s|>)/i.test(withoutStatus) || /^<html(?:\s|>)/i.test(withoutStatus);
|
|
108
|
+
}
|
|
109
|
+
function providerHtmlErrorMessage(statusCode) {
|
|
110
|
+
return statusCode ? `The provider returned an HTML error page (HTTP ${statusCode}) instead of an API response.` : "The provider returned an HTML error page instead of an API response.";
|
|
111
|
+
}
|
|
105
112
|
function emptyProviderErrorMessage(statusCode) {
|
|
106
113
|
return statusCode ? `The provider returned an empty error response (HTTP ${statusCode}), with no further detail.` : "The provider returned an empty error response, with no further detail.";
|
|
107
114
|
}
|
|
108
115
|
function formatError(err) {
|
|
109
116
|
if (err instanceof ProviderError) {
|
|
110
117
|
const name = providerDisplayName(err.provider);
|
|
111
|
-
const cleanMessage = cleanProviderMessage(err.message);
|
|
118
|
+
const cleanMessage = cleanProviderMessage(err.message, err.statusCode);
|
|
112
119
|
if (isMythosAccessError(cleanMessage)) {
|
|
113
120
|
return {
|
|
114
121
|
headline: "Claude Mythos 5 is invitation-only.",
|
|
@@ -203,8 +210,9 @@ function formatErrorForDisplay(err) {
|
|
|
203
210
|
lines.push(` \u2192 ${f.guidance}`);
|
|
204
211
|
return lines.join("\n");
|
|
205
212
|
}
|
|
206
|
-
function cleanProviderMessage(message) {
|
|
207
|
-
|
|
213
|
+
function cleanProviderMessage(message, statusCode) {
|
|
214
|
+
const clean = message.replace(/^\[[^\]]+\]\s*/, "").trim();
|
|
215
|
+
return isRawHtmlErrorEcho(clean) ? providerHtmlErrorMessage(statusCode) : clean;
|
|
208
216
|
}
|
|
209
217
|
function inferSource(err) {
|
|
210
218
|
const msg = err.message.toLowerCase();
|
|
@@ -565,6 +573,66 @@ function toAnthropicAssistantContent(content, preserveThinking, idMap) {
|
|
|
565
573
|
return true;
|
|
566
574
|
}).map((part) => toAnthropicAssistantPart(part, idMap)).filter((b) => b !== null);
|
|
567
575
|
}
|
|
576
|
+
var PROVIDER_IMAGE_LIMIT_PLACEHOLDER = "[image omitted: provider image limit]";
|
|
577
|
+
var PROVIDER_IMAGE_BUDGETS = {
|
|
578
|
+
anthropic: 90,
|
|
579
|
+
minimax: 90,
|
|
580
|
+
openai: 200,
|
|
581
|
+
gemini: 200,
|
|
582
|
+
openrouter: 90
|
|
583
|
+
};
|
|
584
|
+
function countContextImages(messages) {
|
|
585
|
+
let count = 0;
|
|
586
|
+
for (const message of messages) {
|
|
587
|
+
if (message.role === "user" && Array.isArray(message.content)) {
|
|
588
|
+
count += message.content.filter((part) => part.type === "image").length;
|
|
589
|
+
} else if (message.role === "tool") {
|
|
590
|
+
for (const result of message.content) {
|
|
591
|
+
if (Array.isArray(result.content)) {
|
|
592
|
+
count += result.content.filter((part) => part.type === "image").length;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return count;
|
|
598
|
+
}
|
|
599
|
+
function clampProviderContextImages(messages, provider, supportsImages) {
|
|
600
|
+
if (supportsImages === false) return messages;
|
|
601
|
+
const budget = PROVIDER_IMAGE_BUDGETS[provider] ?? 5;
|
|
602
|
+
let remainingToRemove = countContextImages(messages) - budget;
|
|
603
|
+
if (remainingToRemove <= 0) return messages;
|
|
604
|
+
return messages.map((message) => {
|
|
605
|
+
if (message.role === "user" && Array.isArray(message.content)) {
|
|
606
|
+
const content = message.content.filter((part) => {
|
|
607
|
+
if (part.type !== "image" || remainingToRemove <= 0) return true;
|
|
608
|
+
remainingToRemove--;
|
|
609
|
+
return false;
|
|
610
|
+
});
|
|
611
|
+
return {
|
|
612
|
+
...message,
|
|
613
|
+
content: content.length > 0 ? content : [{ type: "text", text: PROVIDER_IMAGE_LIMIT_PLACEHOLDER }]
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
if (message.role === "tool") {
|
|
617
|
+
return {
|
|
618
|
+
...message,
|
|
619
|
+
content: message.content.map((result) => {
|
|
620
|
+
if (!Array.isArray(result.content)) return result;
|
|
621
|
+
const content = result.content.filter((part) => {
|
|
622
|
+
if (part.type !== "image" || remainingToRemove <= 0) return true;
|
|
623
|
+
remainingToRemove--;
|
|
624
|
+
return false;
|
|
625
|
+
});
|
|
626
|
+
return {
|
|
627
|
+
...result,
|
|
628
|
+
content: content.length > 0 ? content : [{ type: "text", text: PROVIDER_IMAGE_LIMIT_PLACEHOLDER }]
|
|
629
|
+
};
|
|
630
|
+
})
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
return message;
|
|
634
|
+
});
|
|
635
|
+
}
|
|
568
636
|
var NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
|
|
569
637
|
var NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
|
|
570
638
|
var NON_VIDEO_USER_PLACEHOLDER = "(video omitted: model does not support video)";
|
|
@@ -1581,7 +1649,8 @@ function toError(err) {
|
|
|
1581
1649
|
const bodyMessage = typeof nestedError?.message === "string" && nestedError.message.trim() ? nestedError.message.trim() : typeof errorBody?.message === "string" && errorBody.message.trim() ? errorBody.message.trim() : void 0;
|
|
1582
1650
|
const bodyType = typeof nestedError?.type === "string" ? nestedError.type : typeof errorBody?.type === "string" ? errorBody.type : typeof err.type === "string" ? err.type : void 0;
|
|
1583
1651
|
const fallbackMessage = isRawJsonErrorEcho(err.message) ? emptyProviderErrorMessage(err.status) : err.message;
|
|
1584
|
-
const
|
|
1652
|
+
const messageCandidate = bodyMessage ?? err.message;
|
|
1653
|
+
const message = isRawHtmlErrorEcho(messageCandidate) ? providerHtmlErrorMessage(err.status) : bodyType && bodyMessage ? `${bodyType}: ${bodyMessage}` : bodyMessage ?? fallbackMessage;
|
|
1585
1654
|
if (err.status === 429) {
|
|
1586
1655
|
const limit = readUnifiedRateLimit(err.headers);
|
|
1587
1656
|
const farOff = limit.resetsAt != null && limit.resetsAt * 1e3 - Date.now() > 6e4;
|
|
@@ -1763,7 +1832,11 @@ async function* runStream2(options) {
|
|
|
1763
1832
|
const providerName = options.provider ?? "openai";
|
|
1764
1833
|
const useStreaming = options.streaming !== false;
|
|
1765
1834
|
const client = createClient2(options);
|
|
1766
|
-
const
|
|
1835
|
+
const isKimiK3 = options.provider === "moonshot" && options.model === "kimi-k3";
|
|
1836
|
+
const isManagedKimiK3 = isKimiK3 && options.baseUrl?.replace(/\/+$/, "").endsWith("/coding/v1") === true;
|
|
1837
|
+
const isKimiK27 = options.provider === "moonshot" && options.model.startsWith("kimi-k2.7-code");
|
|
1838
|
+
const hasFixedKimiSampling = isKimiK3 || isKimiK27;
|
|
1839
|
+
const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" && !isKimiK3 && !isKimiK27 || options.provider === "xiaomi";
|
|
1767
1840
|
const downgradedImages = downgradeUnsupportedImages(options.messages, options.supportsImages);
|
|
1768
1841
|
const downgradedMessages = downgradeUnsupportedVideos(downgradedImages, options.supportsVideo);
|
|
1769
1842
|
if (options.provider === "moonshot") {
|
|
@@ -1775,7 +1848,9 @@ async function* runStream2(options) {
|
|
|
1775
1848
|
}
|
|
1776
1849
|
const messages = toOpenAIMessages(downgradedMessages, {
|
|
1777
1850
|
provider: options.provider,
|
|
1778
|
-
|
|
1851
|
+
// K3 and K2.7 preserve reasoning even when the user hides thinking in the
|
|
1852
|
+
// UI; keep assistant tool-call history wire-valid in that display mode.
|
|
1853
|
+
thinking: isKimiK3 || isKimiK27 || !!options.thinking,
|
|
1779
1854
|
supportsImages: options.supportsImages
|
|
1780
1855
|
});
|
|
1781
1856
|
const defaultTemp = options.provider === "glm" ? 0.6 : void 0;
|
|
@@ -1785,10 +1860,10 @@ async function* runStream2(options) {
|
|
|
1785
1860
|
messages,
|
|
1786
1861
|
stream: useStreaming,
|
|
1787
1862
|
...options.maxTokens ? { max_completion_tokens: options.maxTokens } : {},
|
|
1788
|
-
...effectiveTemp != null && !options.thinking ? { temperature: effectiveTemp } : {},
|
|
1789
|
-
...options.topP != null ? { top_p: options.topP } : {},
|
|
1863
|
+
...effectiveTemp != null && !options.thinking && !hasFixedKimiSampling ? { temperature: effectiveTemp } : {},
|
|
1864
|
+
...options.topP != null && !hasFixedKimiSampling ? { top_p: options.topP } : {},
|
|
1790
1865
|
...options.stop ? { stop: options.stop } : {},
|
|
1791
|
-
...options.thinking && !usesThinkingParam ? { reasoning_effort: toOpenAIReasoningEffort(options.thinking, options.model) } : {},
|
|
1866
|
+
...options.thinking && !usesThinkingParam && !isKimiK3 && !isKimiK27 ? { reasoning_effort: toOpenAIReasoningEffort(options.thinking, options.model) } : {},
|
|
1792
1867
|
...options.tools?.length ? { tools: toOpenAITools(options.tools) } : {},
|
|
1793
1868
|
...options.toolChoice && options.tools?.length ? { tool_choice: toOpenAIToolChoice(options.toolChoice) } : {},
|
|
1794
1869
|
...useStreaming ? { stream_options: { include_usage: true } } : {}
|
|
@@ -1798,13 +1873,21 @@ async function* runStream2(options) {
|
|
|
1798
1873
|
paramsAny.prompt_cache_key = normalizePromptCacheKey(options.promptCacheKey ?? "ggcoder");
|
|
1799
1874
|
if (options.provider === "openai" && options.model.startsWith("gpt-5.6")) {
|
|
1800
1875
|
paramsAny.prompt_cache_options = { mode: "implicit", ttl: "30m" };
|
|
1801
|
-
} else if ((options.cacheRetention ?? "short") === "long") {
|
|
1876
|
+
} else if (!isKimiK3 && (options.cacheRetention ?? "short") === "long") {
|
|
1802
1877
|
paramsAny.prompt_cache_retention = "24h";
|
|
1803
1878
|
}
|
|
1804
1879
|
}
|
|
1805
1880
|
if (options.provider === "openai" && options.serviceTier) {
|
|
1806
1881
|
params.service_tier = options.serviceTier;
|
|
1807
1882
|
}
|
|
1883
|
+
if (isKimiK3) {
|
|
1884
|
+
const paramsAny = params;
|
|
1885
|
+
if (isManagedKimiK3) {
|
|
1886
|
+
paramsAny.thinking = { type: "enabled", effort: "max", keep: "all" };
|
|
1887
|
+
} else {
|
|
1888
|
+
paramsAny.reasoning_effort = "max";
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1808
1891
|
if (usesThinkingParam) {
|
|
1809
1892
|
if (options.thinking) {
|
|
1810
1893
|
params.thinking = { type: "enabled" };
|
|
@@ -2049,7 +2132,8 @@ function toError2(err, provider = "openai") {
|
|
|
2049
2132
|
const body = err.error;
|
|
2050
2133
|
const bodyMessage = typeof body?.message === "string" && body.message.trim() ? body.message.trim() : void 0;
|
|
2051
2134
|
const modelName = typeof body?.model === "string" ? body.model : "";
|
|
2052
|
-
const
|
|
2135
|
+
const messageCandidate = bodyMessage ?? err.message;
|
|
2136
|
+
const cleanMessage = isRawHtmlErrorEcho(messageCandidate) ? providerHtmlErrorMessage(err.status) : bodyMessage ? bodyMessage : isRawJsonErrorEcho(err.message) ? emptyProviderErrorMessage(err.status) : err.message;
|
|
2053
2137
|
let hint;
|
|
2054
2138
|
if (modelName === "codex-mini-latest" || cleanMessage.includes("codex-mini-latest")) {
|
|
2055
2139
|
hint = "codex-mini-latest requires an OpenAI Pro or Max subscription. Your account currently has access to GPT-5.4 and GPT-5.4 Mini.";
|
|
@@ -2163,6 +2247,21 @@ function outputTextKey(itemId, contentIndex) {
|
|
|
2163
2247
|
function isVisibleOutputItem(itemType) {
|
|
2164
2248
|
return itemType === "message";
|
|
2165
2249
|
}
|
|
2250
|
+
function toCodexToolChoice(choice, tools) {
|
|
2251
|
+
const resolved = choice ?? "auto";
|
|
2252
|
+
if (typeof resolved === "object") {
|
|
2253
|
+
throw new GGAIError(
|
|
2254
|
+
`OpenAI Codex does not support selecting the named tool \`${resolved.name}\`; use auto, none, or required.`,
|
|
2255
|
+
{ source: "capability" }
|
|
2256
|
+
);
|
|
2257
|
+
}
|
|
2258
|
+
if (resolved === "required" && !tools?.length) {
|
|
2259
|
+
throw new GGAIError("OpenAI Codex cannot require a tool call when no tools are configured.", {
|
|
2260
|
+
source: "capability"
|
|
2261
|
+
});
|
|
2262
|
+
}
|
|
2263
|
+
return resolved;
|
|
2264
|
+
}
|
|
2166
2265
|
function streamOpenAICodex(options) {
|
|
2167
2266
|
return new StreamResult(runStream3(options), options.signal);
|
|
2168
2267
|
}
|
|
@@ -2179,7 +2278,7 @@ async function* runStream3(options) {
|
|
|
2179
2278
|
stream: true,
|
|
2180
2279
|
instructions: system,
|
|
2181
2280
|
input,
|
|
2182
|
-
tool_choice:
|
|
2281
|
+
tool_choice: toCodexToolChoice(options.toolChoice, options.tools),
|
|
2183
2282
|
parallel_tool_calls: !responsesLite,
|
|
2184
2283
|
include: ["reasoning.encrypted_content"]
|
|
2185
2284
|
};
|
|
@@ -2212,8 +2311,9 @@ async function* runStream3(options) {
|
|
|
2212
2311
|
headers["chatgpt-account-id"] = options.accountId;
|
|
2213
2312
|
}
|
|
2214
2313
|
if (options.transportSessionId) {
|
|
2215
|
-
|
|
2216
|
-
headers["
|
|
2314
|
+
const transportSessionId = normalizePromptCacheKey(options.transportSessionId);
|
|
2315
|
+
headers["session_id"] = transportSessionId;
|
|
2316
|
+
headers["x-client-request-id"] = transportSessionId;
|
|
2217
2317
|
}
|
|
2218
2318
|
const response = await fetch(url, {
|
|
2219
2319
|
method: "POST",
|
|
@@ -2223,7 +2323,7 @@ async function* runStream3(options) {
|
|
|
2223
2323
|
});
|
|
2224
2324
|
if (!response.ok) {
|
|
2225
2325
|
const text = await response.text().catch(() => "");
|
|
2226
|
-
const parsed = parseCodexErrorBody(text);
|
|
2326
|
+
const parsed = parseCodexErrorBody(text, response.status);
|
|
2227
2327
|
const message = parsed.message ?? `Codex API returned HTTP ${response.status}.`;
|
|
2228
2328
|
const requestId = parsed.requestId ?? readHeader(response.headers, "x-request-id", "openai-request-id", "x-oai-request-id");
|
|
2229
2329
|
const usageLimit = codexUsageLimitError(parsed.errorObj, response.status, requestId);
|
|
@@ -2617,13 +2717,14 @@ function toCodexTools(tools) {
|
|
|
2617
2717
|
strict: null
|
|
2618
2718
|
}));
|
|
2619
2719
|
}
|
|
2620
|
-
function parseCodexErrorBody(text) {
|
|
2720
|
+
function parseCodexErrorBody(text, statusCode) {
|
|
2621
2721
|
if (!text) return {};
|
|
2622
2722
|
try {
|
|
2623
2723
|
const parsed = JSON.parse(text);
|
|
2624
2724
|
const error = parsed.error;
|
|
2625
2725
|
const detail = parsed.detail;
|
|
2626
|
-
const
|
|
2726
|
+
const rawMessage = error?.message ?? parsed.message ?? (typeof detail === "string" ? detail : void 0);
|
|
2727
|
+
const message = rawMessage && isRawHtmlErrorEcho(rawMessage) ? providerHtmlErrorMessage(statusCode) : rawMessage;
|
|
2627
2728
|
const requestId = parsed.request_id ?? error?.request_id ?? (message ? extractRequestIdFromMessage(message) : void 0);
|
|
2628
2729
|
const errorObj = error ?? parsed;
|
|
2629
2730
|
return {
|
|
@@ -2632,8 +2733,12 @@ function parseCodexErrorBody(text) {
|
|
|
2632
2733
|
...errorObj ? { errorObj } : {}
|
|
2633
2734
|
};
|
|
2634
2735
|
} catch {
|
|
2635
|
-
const trimmed = text.trim()
|
|
2636
|
-
|
|
2736
|
+
const trimmed = text.trim();
|
|
2737
|
+
if (isRawHtmlErrorEcho(trimmed)) {
|
|
2738
|
+
return { message: providerHtmlErrorMessage(statusCode) };
|
|
2739
|
+
}
|
|
2740
|
+
const bounded = trimmed.slice(0, 240);
|
|
2741
|
+
return bounded ? { message: bounded } : {};
|
|
2637
2742
|
}
|
|
2638
2743
|
}
|
|
2639
2744
|
var CODEX_USAGE_LIMIT_CODE = /usage_limit_reached|usage_not_included/i;
|
|
@@ -3268,7 +3373,12 @@ function stream(options) {
|
|
|
3268
3373
|
if (options.supportsVideo !== true && messagesContainVideo(options.messages)) {
|
|
3269
3374
|
throw new VideoUnsupportedError();
|
|
3270
3375
|
}
|
|
3271
|
-
|
|
3376
|
+
const messages = clampProviderContextImages(
|
|
3377
|
+
options.messages,
|
|
3378
|
+
options.provider,
|
|
3379
|
+
options.supportsImages
|
|
3380
|
+
);
|
|
3381
|
+
return entry.stream(messages === options.messages ? options : { ...options, messages });
|
|
3272
3382
|
}
|
|
3273
3383
|
function messagesContainVideo(messages) {
|
|
3274
3384
|
for (const msg of messages) {
|
|
@@ -3373,6 +3483,125 @@ Original: ${message}`;
|
|
|
3373
3483
|
return message;
|
|
3374
3484
|
}
|
|
3375
3485
|
|
|
3486
|
+
// src/redaction.ts
|
|
3487
|
+
var REDACTED = "[REDACTED]";
|
|
3488
|
+
var TRUNCATED = "[TRUNCATED]";
|
|
3489
|
+
var CIRCULAR = "[CIRCULAR]";
|
|
3490
|
+
var SENSITIVE_NAME = /(?:^|[_-])(?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|key|auth(?:orization)?|bearer|cookie|credential|private[_-]?key|password|passwd|secret)(?:$|[_-])/i;
|
|
3491
|
+
var SENSITIVE_ASSIGNMENT = /\b((?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|key|auth(?:orization)?|bearer|cookie|credential|private[_-]?key|password|passwd|secret))\b(\s*[=:]\s*)(["']?)([^\s,"';}]+)\3/gi;
|
|
3492
|
+
function escaped(value) {
|
|
3493
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3494
|
+
}
|
|
3495
|
+
function normalizedSecrets(secrets) {
|
|
3496
|
+
if (!secrets) return [];
|
|
3497
|
+
return [...new Set([...secrets].filter((value) => value.length >= 8 && value !== REDACTED))].sort(
|
|
3498
|
+
(a, b) => b.length - a.length
|
|
3499
|
+
);
|
|
3500
|
+
}
|
|
3501
|
+
function environmentSecrets(env) {
|
|
3502
|
+
const values = /* @__PURE__ */ new Set();
|
|
3503
|
+
for (const [name, value] of Object.entries(env)) {
|
|
3504
|
+
if (!value || value.length < 8 || value === REDACTED || !SENSITIVE_NAME.test(name)) continue;
|
|
3505
|
+
values.add(value);
|
|
3506
|
+
}
|
|
3507
|
+
return [...values].sort((a, b) => b.length - a.length);
|
|
3508
|
+
}
|
|
3509
|
+
function redactText(text, options = {}) {
|
|
3510
|
+
let result = text;
|
|
3511
|
+
result = result.replace(
|
|
3512
|
+
/-----BEGIN (?:[A-Z0-9 ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9 ]+ )?PRIVATE KEY-----/g,
|
|
3513
|
+
REDACTED
|
|
3514
|
+
);
|
|
3515
|
+
result = result.replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]+:[^\s/@]+@/gi, `$1${REDACTED}@`);
|
|
3516
|
+
result = result.replace(
|
|
3517
|
+
/\b(authorization\s*[:=]\s*)(?:bearer|basic)\s+[^\s,;]+/gi,
|
|
3518
|
+
`$1${REDACTED}`
|
|
3519
|
+
);
|
|
3520
|
+
result = result.replace(/\b(bearer|basic)\s+[A-Za-z0-9+/_.=-]{8,}/gi, `$1 ${REDACTED}`);
|
|
3521
|
+
result = result.replace(/\b(cookie|set-cookie)(\s*[:=]\s*)[^\r\n]+/gi, `$1$2${REDACTED}`);
|
|
3522
|
+
result = result.replace(
|
|
3523
|
+
/\beyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\b/g,
|
|
3524
|
+
REDACTED
|
|
3525
|
+
);
|
|
3526
|
+
result = result.replace(
|
|
3527
|
+
/\b(?:sk-(?:ant-|proj-)?|xox[baprs]-|gh[pousr]_|github_pat_|AIza)[A-Za-z0-9_-]{12,}\b/g,
|
|
3528
|
+
REDACTED
|
|
3529
|
+
);
|
|
3530
|
+
result = result.replace(
|
|
3531
|
+
SENSITIVE_ASSIGNMENT,
|
|
3532
|
+
(_match, name, separator) => `${name}${separator}${REDACTED}`
|
|
3533
|
+
);
|
|
3534
|
+
for (const secret of normalizedSecrets(options.secrets)) {
|
|
3535
|
+
result = result.replace(new RegExp(escaped(secret), "g"), REDACTED);
|
|
3536
|
+
}
|
|
3537
|
+
const maxStringLength = options.maxStringLength ?? 1e6;
|
|
3538
|
+
if (result.length > maxStringLength) {
|
|
3539
|
+
result = `${result.slice(0, maxStringLength)}${TRUNCATED}`;
|
|
3540
|
+
}
|
|
3541
|
+
return result;
|
|
3542
|
+
}
|
|
3543
|
+
function isBinary(value) {
|
|
3544
|
+
return value instanceof ArrayBuffer || ArrayBuffer.isView(value) || typeof Blob !== "undefined" && value instanceof Blob;
|
|
3545
|
+
}
|
|
3546
|
+
function isMediaObject(value) {
|
|
3547
|
+
return (value.type === "image" || value.type === "video") && (typeof value.data === "string" || typeof value.url === "string");
|
|
3548
|
+
}
|
|
3549
|
+
function redactValue(value, options = {}) {
|
|
3550
|
+
const maxDepth = options.maxDepth ?? 20;
|
|
3551
|
+
const maxEntries = options.maxEntries ?? 1e4;
|
|
3552
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
3553
|
+
let entries = 0;
|
|
3554
|
+
const visit = (current, depth, sensitive = false) => {
|
|
3555
|
+
if (typeof current === "string") {
|
|
3556
|
+
if (sensitive && current.length > 0 && current !== REDACTED) return REDACTED;
|
|
3557
|
+
return redactText(current, options);
|
|
3558
|
+
}
|
|
3559
|
+
if (current === null || current === void 0 || typeof current === "number" || typeof current === "boolean" || typeof current === "bigint") {
|
|
3560
|
+
return current;
|
|
3561
|
+
}
|
|
3562
|
+
if (typeof current !== "object") return current;
|
|
3563
|
+
if (isBinary(current)) return current;
|
|
3564
|
+
if (current instanceof Date) return new Date(current.getTime());
|
|
3565
|
+
if (depth >= maxDepth) return TRUNCATED;
|
|
3566
|
+
if (seen.has(current)) return CIRCULAR;
|
|
3567
|
+
seen.add(current);
|
|
3568
|
+
if (current instanceof Error) {
|
|
3569
|
+
const error = {
|
|
3570
|
+
name: current.name,
|
|
3571
|
+
message: visit(current.message, depth + 1),
|
|
3572
|
+
stack: visit(current.stack, depth + 1)
|
|
3573
|
+
};
|
|
3574
|
+
for (const [key, child] of Object.entries(current)) {
|
|
3575
|
+
error[key] = visit(child, depth + 1, SENSITIVE_NAME.test(key));
|
|
3576
|
+
}
|
|
3577
|
+
return error;
|
|
3578
|
+
}
|
|
3579
|
+
if (Array.isArray(current)) {
|
|
3580
|
+
const clone2 = [];
|
|
3581
|
+
for (const child of current) {
|
|
3582
|
+
if (++entries > maxEntries) {
|
|
3583
|
+
clone2.push(TRUNCATED);
|
|
3584
|
+
break;
|
|
3585
|
+
}
|
|
3586
|
+
clone2.push(visit(child, depth + 1));
|
|
3587
|
+
}
|
|
3588
|
+
return clone2;
|
|
3589
|
+
}
|
|
3590
|
+
const record = current;
|
|
3591
|
+
if (isMediaObject(record)) return { ...record };
|
|
3592
|
+
const clone = {};
|
|
3593
|
+
for (const [key, child] of Object.entries(record)) {
|
|
3594
|
+
if (++entries > maxEntries) {
|
|
3595
|
+
clone[TRUNCATED] = true;
|
|
3596
|
+
break;
|
|
3597
|
+
}
|
|
3598
|
+
clone[key] = visit(child, depth + 1, SENSITIVE_NAME.test(key));
|
|
3599
|
+
}
|
|
3600
|
+
return clone;
|
|
3601
|
+
};
|
|
3602
|
+
return visit(value, 0);
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3376
3605
|
// src/providers/palsu.ts
|
|
3377
3606
|
function palsuText(text) {
|
|
3378
3607
|
return { role: "assistant", content: text ? [{ type: "text", text }] : [] };
|
|
@@ -3528,8 +3757,11 @@ export {
|
|
|
3528
3757
|
EventStream,
|
|
3529
3758
|
GGAIError,
|
|
3530
3759
|
ProviderError,
|
|
3760
|
+
REDACTED as REDACTION_MARKER,
|
|
3531
3761
|
StreamResult,
|
|
3762
|
+
clampProviderContextImages,
|
|
3532
3763
|
classifyProviderError,
|
|
3764
|
+
environmentSecrets,
|
|
3533
3765
|
formatError,
|
|
3534
3766
|
formatErrorForDisplay,
|
|
3535
3767
|
isHardBillingMessage,
|
|
@@ -3540,6 +3772,8 @@ export {
|
|
|
3540
3772
|
palsuToolCall,
|
|
3541
3773
|
prewarmAnthropicCache,
|
|
3542
3774
|
providerRegistry,
|
|
3775
|
+
redactText,
|
|
3776
|
+
redactValue,
|
|
3543
3777
|
registerPalsuProvider,
|
|
3544
3778
|
setProviderDiagnostic,
|
|
3545
3779
|
stream,
|