@f5-sales-demo/pi-ai 21.41.3 → 21.41.5
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/pi-ai",
|
|
4
|
-
"version": "21.41.
|
|
4
|
+
"version": "21.41.5",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@anthropic-ai/sdk": "0.123.0",
|
|
47
47
|
"@aws-sdk/client-bedrock-runtime": "3.1126.0",
|
|
48
48
|
"@bufbuild/protobuf": "2.14.1",
|
|
49
|
-
"@f5-sales-demo/pi-utils": "21.41.
|
|
49
|
+
"@f5-sales-demo/pi-utils": "21.41.5",
|
|
50
50
|
"@google/genai": "2.21.0",
|
|
51
51
|
"@sinclair/typebox": "0.34.52",
|
|
52
52
|
"@smithy/node-http-handler": "4.12.1",
|
|
@@ -14,6 +14,7 @@ export type CodexRateLimits = {
|
|
|
14
14
|
export type CodexErrorInfo = {
|
|
15
15
|
message: string;
|
|
16
16
|
status: number;
|
|
17
|
+
code?: string;
|
|
17
18
|
friendlyMessage?: string;
|
|
18
19
|
rateLimits?: CodexRateLimits;
|
|
19
20
|
raw?: string;
|
|
@@ -24,6 +25,7 @@ export async function parseCodexError(response: Response): Promise<CodexErrorInf
|
|
|
24
25
|
let message = raw || response.statusText || "Request failed";
|
|
25
26
|
let friendlyMessage: string | undefined;
|
|
26
27
|
let rateLimits: CodexRateLimits | undefined;
|
|
28
|
+
let code: string | undefined;
|
|
27
29
|
|
|
28
30
|
try {
|
|
29
31
|
const parsed = JSON.parse(raw) as { error?: Record<string, unknown> };
|
|
@@ -45,16 +47,17 @@ export async function parseCodexError(response: Response): Promise<CodexErrorInf
|
|
|
45
47
|
? { primary, secondary }
|
|
46
48
|
: undefined;
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
code =
|
|
51
|
+
String((err as { code?: string; type?: string }).code ?? (err as { type?: string }).type ?? "") || undefined;
|
|
49
52
|
const resetsAt = (err as { resets_at?: number }).resets_at ?? primary.resets_at ?? secondary.resets_at;
|
|
50
53
|
const mins = resetsAt ? Math.max(0, Math.round((resetsAt * 1000 - Date.now()) / 60000)) : undefined;
|
|
51
54
|
|
|
52
|
-
if (/usage_limit_reached|usage_not_included/i.test(code)) {
|
|
55
|
+
if (/usage_limit_reached|usage_not_included/i.test(code ?? "")) {
|
|
53
56
|
const planType = (err as { plan_type?: string }).plan_type;
|
|
54
57
|
const plan = planType ? ` (${String(planType).toLowerCase()} plan)` : "";
|
|
55
58
|
const when = mins !== undefined ? ` Try again in ~${mins} min.` : "";
|
|
56
59
|
friendlyMessage = `You have hit your ChatGPT usage limit${plan}.${when}`.trim();
|
|
57
|
-
} else if (/rate_limit_exceeded/i.test(code) || response.status === 429) {
|
|
60
|
+
} else if (/rate_limit_exceeded/i.test(code ?? "") || response.status === 429) {
|
|
58
61
|
const when = mins !== undefined ? ` Try again in ~${mins} min.` : "";
|
|
59
62
|
friendlyMessage = `ChatGPT rate limit exceeded.${when}`.trim();
|
|
60
63
|
}
|
|
@@ -68,6 +71,7 @@ export async function parseCodexError(response: Response): Promise<CodexErrorInf
|
|
|
68
71
|
return {
|
|
69
72
|
message,
|
|
70
73
|
status: response.status,
|
|
74
|
+
...(code ? { code } : {}),
|
|
71
75
|
friendlyMessage,
|
|
72
76
|
rateLimits,
|
|
73
77
|
raw: raw,
|
|
@@ -401,6 +401,7 @@ function resetOutputState(output: AssistantMessage): void {
|
|
|
401
401
|
output.content.length = 0;
|
|
402
402
|
output.usage = createEmptyUsage();
|
|
403
403
|
output.stopReason = "stop";
|
|
404
|
+
delete output.providerFailureCode;
|
|
404
405
|
}
|
|
405
406
|
|
|
406
407
|
function removeTransientBlockIndices(output: AssistantMessage): void {
|
|
@@ -1325,6 +1326,11 @@ async function handleCodexStreamFailure(
|
|
|
1325
1326
|
}
|
|
1326
1327
|
output.stopReason = context.options?.signal?.aborted ? "aborted" : "error";
|
|
1327
1328
|
output.errorMessage = await finalizeErrorMessage(error, context.requestContext.rawRequestDump);
|
|
1329
|
+
output.providerFailureCode = sanitizeProviderFailureCode(
|
|
1330
|
+
error instanceof CodexProviderStreamError
|
|
1331
|
+
? error.code
|
|
1332
|
+
: (error as { providerFailureCode?: unknown } | null)?.providerFailureCode,
|
|
1333
|
+
);
|
|
1328
1334
|
output.duration = Date.now() - context.startTime;
|
|
1329
1335
|
if (context.firstTokenTime) {
|
|
1330
1336
|
output.ttft = context.firstTokenTime - context.startTime;
|
|
@@ -1937,8 +1943,10 @@ async function openCodexSseEventStream(
|
|
|
1937
1943
|
if (!response.ok) {
|
|
1938
1944
|
const info = await parseCodexError(response);
|
|
1939
1945
|
const error = new Error(info.friendlyMessage || info.message);
|
|
1940
|
-
|
|
1941
|
-
|
|
1946
|
+
const details = error as { headers?: Headers; status?: number; providerFailureCode?: string };
|
|
1947
|
+
details.headers = response.headers;
|
|
1948
|
+
details.status = response.status;
|
|
1949
|
+
details.providerFailureCode = sanitizeProviderFailureCode(info.code);
|
|
1942
1950
|
throw error;
|
|
1943
1951
|
}
|
|
1944
1952
|
if (!response.body) {
|
|
@@ -2301,6 +2309,10 @@ function getString(value: unknown): string | undefined {
|
|
|
2301
2309
|
return typeof value === "string" ? value : undefined;
|
|
2302
2310
|
}
|
|
2303
2311
|
|
|
2312
|
+
function sanitizeProviderFailureCode(value: unknown): string | undefined {
|
|
2313
|
+
return typeof value === "string" && value.length <= 128 && /^[A-Za-z0-9._-]+$/.test(value) ? value : undefined;
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2304
2316
|
class CodexProviderStreamError extends Error {
|
|
2305
2317
|
readonly retryable: boolean;
|
|
2306
2318
|
readonly code?: string;
|
|
@@ -2309,7 +2321,7 @@ class CodexProviderStreamError extends Error {
|
|
|
2309
2321
|
super(message);
|
|
2310
2322
|
this.name = "CodexProviderStreamError";
|
|
2311
2323
|
this.retryable = retryable;
|
|
2312
|
-
this.code = code;
|
|
2324
|
+
this.code = sanitizeProviderFailureCode(code);
|
|
2313
2325
|
}
|
|
2314
2326
|
}
|
|
2315
2327
|
|
|
@@ -2325,7 +2337,9 @@ function isRetryableCodexFailureEvent(rawEvent: Record<string, unknown>): boolea
|
|
|
2325
2337
|
}
|
|
2326
2338
|
|
|
2327
2339
|
function createCodexProviderStreamError(rawEvent: Record<string, unknown>): CodexProviderStreamError {
|
|
2328
|
-
const
|
|
2340
|
+
const response = asRecord(rawEvent.response);
|
|
2341
|
+
const providerError = asRecord(rawEvent.error) ?? (response ? asRecord(response.error) : null);
|
|
2342
|
+
const code = getString(providerError?.code) ?? getString(providerError?.type) ?? getString(rawEvent.code) ?? "";
|
|
2329
2343
|
const message = getString(rawEvent.message) ?? "";
|
|
2330
2344
|
const formattedMessage =
|
|
2331
2345
|
typeof rawEvent.type === "string" && rawEvent.type === "error"
|
package/src/types.ts
CHANGED
|
@@ -393,6 +393,8 @@ export interface AssistantMessage {
|
|
|
393
393
|
usage: Usage;
|
|
394
394
|
stopReason: StopReason;
|
|
395
395
|
errorMessage?: string;
|
|
396
|
+
/** Sanitized provider error identifier used for internal lifecycle classification. */
|
|
397
|
+
providerFailureCode?: string;
|
|
396
398
|
/** Provider-native completion reason retained for diagnostics and transport-specific recovery. */
|
|
397
399
|
rawStopReason?: string;
|
|
398
400
|
/** Provider-specific opaque payload used to reconstruct transport-native history. */
|