@prestyj/ai 5.5.0 → 5.7.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 -14
- 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 +237 -14
- 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, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, 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, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, 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, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, 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, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, 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)";
|
|
@@ -1582,7 +1650,8 @@ function toError(err) {
|
|
|
1582
1650
|
const bodyMessage = typeof nestedError?.message === "string" && nestedError.message.trim() ? nestedError.message.trim() : typeof errorBody?.message === "string" && errorBody.message.trim() ? errorBody.message.trim() : void 0;
|
|
1583
1651
|
const bodyType = typeof nestedError?.type === "string" ? nestedError.type : typeof errorBody?.type === "string" ? errorBody.type : typeof err.type === "string" ? err.type : void 0;
|
|
1584
1652
|
const fallbackMessage = isRawJsonErrorEcho(err.message) ? emptyProviderErrorMessage(err.status) : err.message;
|
|
1585
|
-
const
|
|
1653
|
+
const messageCandidate = bodyMessage ?? err.message;
|
|
1654
|
+
const message = isRawHtmlErrorEcho(messageCandidate) ? providerHtmlErrorMessage(err.status) : bodyType && bodyMessage ? `${bodyType}: ${bodyMessage}` : bodyMessage ?? fallbackMessage;
|
|
1586
1655
|
if (err.status === 429) {
|
|
1587
1656
|
const limit = readUnifiedRateLimit(err.headers);
|
|
1588
1657
|
const farOff = limit.resetsAt != null && limit.resetsAt * 1e3 - Date.now() > 6e4;
|
|
@@ -2050,7 +2119,8 @@ function toError2(err, provider = "openai") {
|
|
|
2050
2119
|
const body = err.error;
|
|
2051
2120
|
const bodyMessage = typeof body?.message === "string" && body.message.trim() ? body.message.trim() : void 0;
|
|
2052
2121
|
const modelName = typeof body?.model === "string" ? body.model : "";
|
|
2053
|
-
const
|
|
2122
|
+
const messageCandidate = bodyMessage ?? err.message;
|
|
2123
|
+
const cleanMessage = isRawHtmlErrorEcho(messageCandidate) ? providerHtmlErrorMessage(err.status) : bodyMessage ? bodyMessage : isRawJsonErrorEcho(err.message) ? emptyProviderErrorMessage(err.status) : err.message;
|
|
2054
2124
|
let hint;
|
|
2055
2125
|
if (modelName === "codex-mini-latest" || cleanMessage.includes("codex-mini-latest")) {
|
|
2056
2126
|
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.";
|
|
@@ -2164,6 +2234,24 @@ function outputTextKey(itemId, contentIndex) {
|
|
|
2164
2234
|
function isVisibleOutputItem(itemType) {
|
|
2165
2235
|
return itemType === "message";
|
|
2166
2236
|
}
|
|
2237
|
+
function toCodexToolChoice(choice, tools) {
|
|
2238
|
+
const resolved = choice ?? "auto";
|
|
2239
|
+
if (typeof resolved === "object") {
|
|
2240
|
+
throw new EZCoderAIError(
|
|
2241
|
+
`OpenAI Codex does not support selecting the named tool \`${resolved.name}\`; use auto, none, or required.`,
|
|
2242
|
+
{ source: "capability" }
|
|
2243
|
+
);
|
|
2244
|
+
}
|
|
2245
|
+
if (resolved === "required" && !tools?.length) {
|
|
2246
|
+
throw new EZCoderAIError(
|
|
2247
|
+
"OpenAI Codex cannot require a tool call when no tools are configured.",
|
|
2248
|
+
{
|
|
2249
|
+
source: "capability"
|
|
2250
|
+
}
|
|
2251
|
+
);
|
|
2252
|
+
}
|
|
2253
|
+
return resolved;
|
|
2254
|
+
}
|
|
2167
2255
|
function streamOpenAICodex(options) {
|
|
2168
2256
|
return new StreamResult(runStream3(options), options.signal);
|
|
2169
2257
|
}
|
|
@@ -2180,7 +2268,7 @@ async function* runStream3(options) {
|
|
|
2180
2268
|
stream: true,
|
|
2181
2269
|
instructions: system,
|
|
2182
2270
|
input,
|
|
2183
|
-
tool_choice:
|
|
2271
|
+
tool_choice: toCodexToolChoice(options.toolChoice, options.tools),
|
|
2184
2272
|
parallel_tool_calls: !responsesLite,
|
|
2185
2273
|
include: ["reasoning.encrypted_content"]
|
|
2186
2274
|
};
|
|
@@ -2213,8 +2301,9 @@ async function* runStream3(options) {
|
|
|
2213
2301
|
headers["chatgpt-account-id"] = options.accountId;
|
|
2214
2302
|
}
|
|
2215
2303
|
if (options.transportSessionId) {
|
|
2216
|
-
|
|
2217
|
-
headers["
|
|
2304
|
+
const transportSessionId = normalizePromptCacheKey(options.transportSessionId);
|
|
2305
|
+
headers["session_id"] = transportSessionId;
|
|
2306
|
+
headers["x-client-request-id"] = transportSessionId;
|
|
2218
2307
|
}
|
|
2219
2308
|
const response = await fetch(url, {
|
|
2220
2309
|
method: "POST",
|
|
@@ -2224,7 +2313,7 @@ async function* runStream3(options) {
|
|
|
2224
2313
|
});
|
|
2225
2314
|
if (!response.ok) {
|
|
2226
2315
|
const text = await response.text().catch(() => "");
|
|
2227
|
-
const parsed = parseCodexErrorBody(text);
|
|
2316
|
+
const parsed = parseCodexErrorBody(text, response.status);
|
|
2228
2317
|
const message = parsed.message ?? `Codex API returned HTTP ${response.status}.`;
|
|
2229
2318
|
const requestId = parsed.requestId ?? readHeader(response.headers, "x-request-id", "openai-request-id", "x-oai-request-id");
|
|
2230
2319
|
const usageLimit = codexUsageLimitError(parsed.errorObj, response.status, requestId);
|
|
@@ -2618,13 +2707,14 @@ function toCodexTools(tools) {
|
|
|
2618
2707
|
strict: null
|
|
2619
2708
|
}));
|
|
2620
2709
|
}
|
|
2621
|
-
function parseCodexErrorBody(text) {
|
|
2710
|
+
function parseCodexErrorBody(text, statusCode) {
|
|
2622
2711
|
if (!text) return {};
|
|
2623
2712
|
try {
|
|
2624
2713
|
const parsed = JSON.parse(text);
|
|
2625
2714
|
const error = parsed.error;
|
|
2626
2715
|
const detail = parsed.detail;
|
|
2627
|
-
const
|
|
2716
|
+
const rawMessage = error?.message ?? parsed.message ?? (typeof detail === "string" ? detail : void 0);
|
|
2717
|
+
const message = rawMessage && isRawHtmlErrorEcho(rawMessage) ? providerHtmlErrorMessage(statusCode) : rawMessage;
|
|
2628
2718
|
const requestId = parsed.request_id ?? error?.request_id ?? (message ? extractRequestIdFromMessage(message) : void 0);
|
|
2629
2719
|
const errorObj = error ?? parsed;
|
|
2630
2720
|
return {
|
|
@@ -2633,8 +2723,12 @@ function parseCodexErrorBody(text) {
|
|
|
2633
2723
|
...errorObj ? { errorObj } : {}
|
|
2634
2724
|
};
|
|
2635
2725
|
} catch {
|
|
2636
|
-
const trimmed = text.trim()
|
|
2637
|
-
|
|
2726
|
+
const trimmed = text.trim();
|
|
2727
|
+
if (isRawHtmlErrorEcho(trimmed)) {
|
|
2728
|
+
return { message: providerHtmlErrorMessage(statusCode) };
|
|
2729
|
+
}
|
|
2730
|
+
const bounded = trimmed.slice(0, 240);
|
|
2731
|
+
return bounded ? { message: bounded } : {};
|
|
2638
2732
|
}
|
|
2639
2733
|
}
|
|
2640
2734
|
var CODEX_USAGE_LIMIT_CODE = /usage_limit_reached|usage_not_included/i;
|
|
@@ -3275,7 +3369,12 @@ function stream(options) {
|
|
|
3275
3369
|
if (options.supportsVideo !== true && messagesContainVideo(options.messages)) {
|
|
3276
3370
|
throw new VideoUnsupportedError();
|
|
3277
3371
|
}
|
|
3278
|
-
|
|
3372
|
+
const messages = clampProviderContextImages(
|
|
3373
|
+
options.messages,
|
|
3374
|
+
options.provider,
|
|
3375
|
+
options.supportsImages
|
|
3376
|
+
);
|
|
3377
|
+
return entry.stream(messages === options.messages ? options : { ...options, messages });
|
|
3279
3378
|
}
|
|
3280
3379
|
function messagesContainVideo(messages) {
|
|
3281
3380
|
for (const msg of messages) {
|
|
@@ -3380,6 +3479,125 @@ Original: ${message}`;
|
|
|
3380
3479
|
return message;
|
|
3381
3480
|
}
|
|
3382
3481
|
|
|
3482
|
+
// src/redaction.ts
|
|
3483
|
+
var REDACTED = "[REDACTED]";
|
|
3484
|
+
var TRUNCATED = "[TRUNCATED]";
|
|
3485
|
+
var CIRCULAR = "[CIRCULAR]";
|
|
3486
|
+
var SENSITIVE_NAME = /(?:^|[_-])(?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|key|auth(?:orization)?|bearer|cookie|credential|private[_-]?key|password|passwd|secret)(?:$|[_-])/i;
|
|
3487
|
+
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;
|
|
3488
|
+
function escaped(value) {
|
|
3489
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3490
|
+
}
|
|
3491
|
+
function normalizedSecrets(secrets) {
|
|
3492
|
+
if (!secrets) return [];
|
|
3493
|
+
return [...new Set([...secrets].filter((value) => value.length >= 8 && value !== REDACTED))].sort(
|
|
3494
|
+
(a, b) => b.length - a.length
|
|
3495
|
+
);
|
|
3496
|
+
}
|
|
3497
|
+
function environmentSecrets(env) {
|
|
3498
|
+
const values = /* @__PURE__ */ new Set();
|
|
3499
|
+
for (const [name, value] of Object.entries(env)) {
|
|
3500
|
+
if (!value || value.length < 8 || value === REDACTED || !SENSITIVE_NAME.test(name)) continue;
|
|
3501
|
+
values.add(value);
|
|
3502
|
+
}
|
|
3503
|
+
return [...values].sort((a, b) => b.length - a.length);
|
|
3504
|
+
}
|
|
3505
|
+
function redactText(text, options = {}) {
|
|
3506
|
+
let result = text;
|
|
3507
|
+
result = result.replace(
|
|
3508
|
+
/-----BEGIN (?:[A-Z0-9 ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9 ]+ )?PRIVATE KEY-----/g,
|
|
3509
|
+
REDACTED
|
|
3510
|
+
);
|
|
3511
|
+
result = result.replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]+:[^\s/@]+@/gi, `$1${REDACTED}@`);
|
|
3512
|
+
result = result.replace(
|
|
3513
|
+
/\b(authorization\s*[:=]\s*)(?:bearer|basic)\s+[^\s,;]+/gi,
|
|
3514
|
+
`$1${REDACTED}`
|
|
3515
|
+
);
|
|
3516
|
+
result = result.replace(/\b(bearer|basic)\s+[A-Za-z0-9+/_.=-]{8,}/gi, `$1 ${REDACTED}`);
|
|
3517
|
+
result = result.replace(/\b(cookie|set-cookie)(\s*[:=]\s*)[^\r\n]+/gi, `$1$2${REDACTED}`);
|
|
3518
|
+
result = result.replace(
|
|
3519
|
+
/\beyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\b/g,
|
|
3520
|
+
REDACTED
|
|
3521
|
+
);
|
|
3522
|
+
result = result.replace(
|
|
3523
|
+
/\b(?:sk-(?:ant-|proj-)?|xox[baprs]-|gh[pousr]_|github_pat_|AIza)[A-Za-z0-9_-]{12,}\b/g,
|
|
3524
|
+
REDACTED
|
|
3525
|
+
);
|
|
3526
|
+
result = result.replace(
|
|
3527
|
+
SENSITIVE_ASSIGNMENT,
|
|
3528
|
+
(_match, name, separator) => `${name}${separator}${REDACTED}`
|
|
3529
|
+
);
|
|
3530
|
+
for (const secret of normalizedSecrets(options.secrets)) {
|
|
3531
|
+
result = result.replace(new RegExp(escaped(secret), "g"), REDACTED);
|
|
3532
|
+
}
|
|
3533
|
+
const maxStringLength = options.maxStringLength ?? 1e6;
|
|
3534
|
+
if (result.length > maxStringLength) {
|
|
3535
|
+
result = `${result.slice(0, maxStringLength)}${TRUNCATED}`;
|
|
3536
|
+
}
|
|
3537
|
+
return result;
|
|
3538
|
+
}
|
|
3539
|
+
function isBinary(value) {
|
|
3540
|
+
return value instanceof ArrayBuffer || ArrayBuffer.isView(value) || typeof Blob !== "undefined" && value instanceof Blob;
|
|
3541
|
+
}
|
|
3542
|
+
function isMediaObject(value) {
|
|
3543
|
+
return (value.type === "image" || value.type === "video") && (typeof value.data === "string" || typeof value.url === "string");
|
|
3544
|
+
}
|
|
3545
|
+
function redactValue(value, options = {}) {
|
|
3546
|
+
const maxDepth = options.maxDepth ?? 20;
|
|
3547
|
+
const maxEntries = options.maxEntries ?? 1e4;
|
|
3548
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
3549
|
+
let entries = 0;
|
|
3550
|
+
const visit = (current, depth, sensitive = false) => {
|
|
3551
|
+
if (typeof current === "string") {
|
|
3552
|
+
if (sensitive && current.length > 0 && current !== REDACTED) return REDACTED;
|
|
3553
|
+
return redactText(current, options);
|
|
3554
|
+
}
|
|
3555
|
+
if (current === null || current === void 0 || typeof current === "number" || typeof current === "boolean" || typeof current === "bigint") {
|
|
3556
|
+
return current;
|
|
3557
|
+
}
|
|
3558
|
+
if (typeof current !== "object") return current;
|
|
3559
|
+
if (isBinary(current)) return current;
|
|
3560
|
+
if (current instanceof Date) return new Date(current.getTime());
|
|
3561
|
+
if (depth >= maxDepth) return TRUNCATED;
|
|
3562
|
+
if (seen.has(current)) return CIRCULAR;
|
|
3563
|
+
seen.add(current);
|
|
3564
|
+
if (current instanceof Error) {
|
|
3565
|
+
const error = {
|
|
3566
|
+
name: current.name,
|
|
3567
|
+
message: visit(current.message, depth + 1),
|
|
3568
|
+
stack: visit(current.stack, depth + 1)
|
|
3569
|
+
};
|
|
3570
|
+
for (const [key, child] of Object.entries(current)) {
|
|
3571
|
+
error[key] = visit(child, depth + 1, SENSITIVE_NAME.test(key));
|
|
3572
|
+
}
|
|
3573
|
+
return error;
|
|
3574
|
+
}
|
|
3575
|
+
if (Array.isArray(current)) {
|
|
3576
|
+
const clone2 = [];
|
|
3577
|
+
for (const child of current) {
|
|
3578
|
+
if (++entries > maxEntries) {
|
|
3579
|
+
clone2.push(TRUNCATED);
|
|
3580
|
+
break;
|
|
3581
|
+
}
|
|
3582
|
+
clone2.push(visit(child, depth + 1));
|
|
3583
|
+
}
|
|
3584
|
+
return clone2;
|
|
3585
|
+
}
|
|
3586
|
+
const record = current;
|
|
3587
|
+
if (isMediaObject(record)) return { ...record };
|
|
3588
|
+
const clone = {};
|
|
3589
|
+
for (const [key, child] of Object.entries(record)) {
|
|
3590
|
+
if (++entries > maxEntries) {
|
|
3591
|
+
clone[TRUNCATED] = true;
|
|
3592
|
+
break;
|
|
3593
|
+
}
|
|
3594
|
+
clone[key] = visit(child, depth + 1, SENSITIVE_NAME.test(key));
|
|
3595
|
+
}
|
|
3596
|
+
return clone;
|
|
3597
|
+
};
|
|
3598
|
+
return visit(value, 0);
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3383
3601
|
// src/providers/palsu.ts
|
|
3384
3602
|
function palsuText(text) {
|
|
3385
3603
|
return { role: "assistant", content: text ? [{ type: "text", text }] : [] };
|
|
@@ -3535,8 +3753,11 @@ export {
|
|
|
3535
3753
|
EZCoderAIError,
|
|
3536
3754
|
EventStream,
|
|
3537
3755
|
ProviderError,
|
|
3756
|
+
REDACTED as REDACTION_MARKER,
|
|
3538
3757
|
StreamResult,
|
|
3758
|
+
clampProviderContextImages,
|
|
3539
3759
|
classifyProviderError,
|
|
3760
|
+
environmentSecrets,
|
|
3540
3761
|
formatError,
|
|
3541
3762
|
formatErrorForDisplay,
|
|
3542
3763
|
isHardBillingMessage,
|
|
@@ -3547,6 +3768,8 @@ export {
|
|
|
3547
3768
|
palsuToolCall,
|
|
3548
3769
|
prewarmAnthropicCache,
|
|
3549
3770
|
providerRegistry,
|
|
3771
|
+
redactText,
|
|
3772
|
+
redactValue,
|
|
3550
3773
|
registerPalsuProvider,
|
|
3551
3774
|
setProviderDiagnostic,
|
|
3552
3775
|
stream,
|