codex-multi-auth 2.1.2 → 2.1.4
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 +4 -2
- package/dist/lib/auto-update-checker.d.ts.map +1 -1
- package/dist/lib/auto-update-checker.js +6 -1
- package/dist/lib/auto-update-checker.js.map +1 -1
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +13 -5
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/dist/lib/runtime/app-bind.d.ts.map +1 -1
- package/dist/lib/runtime/app-bind.js +16 -1
- package/dist/lib/runtime/app-bind.js.map +1 -1
- package/dist/lib/runtime/config-toml.d.ts +2 -0
- package/dist/lib/runtime/config-toml.d.ts.map +1 -1
- package/dist/lib/runtime/config-toml.js +57 -4
- package/dist/lib/runtime/config-toml.js.map +1 -1
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +199 -8
- package/dist/lib/runtime-rotation-proxy.js.map +1 -1
- package/dist/lib/usage/ledger.d.ts.map +1 -1
- package/dist/lib/usage/ledger.js +1 -0
- package/dist/lib/usage/ledger.js.map +1 -1
- package/dist/lib/usage/redaction.d.ts.map +1 -1
- package/dist/lib/usage/redaction.js +1 -0
- package/dist/lib/usage/redaction.js.map +1 -1
- package/dist/lib/usage/types.d.ts +1 -1
- package/dist/lib/usage/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/scripts/codex-multi-auth.js +4 -0
- package/scripts/codex-routing.js +8 -0
- package/scripts/codex.js +292 -6
- package/scripts/test-model-matrix.js +97 -13
|
@@ -70,15 +70,39 @@ export function rewriteTopLevelModelProvider(rawConfig) {
|
|
|
70
70
|
output.push(rewrittenLine);
|
|
71
71
|
return output.join(lineEnding);
|
|
72
72
|
}
|
|
73
|
-
function
|
|
73
|
+
export function enableTopLevelResponseStorage(rawConfig) {
|
|
74
|
+
const lineEnding = rawConfig.includes("\r\n") ? "\r\n" : "\n";
|
|
75
|
+
const lines = rawConfig.length > 0 ? rawConfig.split(/\r?\n/) : [];
|
|
76
|
+
const output = [];
|
|
77
|
+
let inTopLevel = true;
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
if (readTomlTableName(line) !== null) {
|
|
80
|
+
inTopLevel = false;
|
|
81
|
+
output.push(line);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (inTopLevel &&
|
|
85
|
+
/^\s*disable_response_storage\s*=\s*true\s*(?:#.*)?$/i.test(line)) {
|
|
86
|
+
output.push("disable_response_storage = false");
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
output.push(line);
|
|
90
|
+
}
|
|
91
|
+
return output.join(lineEnding);
|
|
92
|
+
}
|
|
93
|
+
function extractTopLevelLine(rawConfig, key) {
|
|
94
|
+
const pattern = new RegExp(`^\\s*${key}\\s*=`);
|
|
74
95
|
for (const line of rawConfig.split(/\r?\n/)) {
|
|
75
96
|
if (readTomlTableName(line) !== null)
|
|
76
97
|
return null;
|
|
77
|
-
if (
|
|
98
|
+
if (pattern.test(line))
|
|
78
99
|
return line;
|
|
79
100
|
}
|
|
80
101
|
return null;
|
|
81
102
|
}
|
|
103
|
+
function extractTopLevelModelProviderLine(rawConfig) {
|
|
104
|
+
return extractTopLevelLine(rawConfig, "model_provider");
|
|
105
|
+
}
|
|
82
106
|
export function restoreTopLevelModelProvider(currentConfig, originalConfig) {
|
|
83
107
|
const lineEnding = currentConfig.includes("\r\n") ? "\r\n" : "\n";
|
|
84
108
|
const originalLine = extractTopLevelModelProviderLine(originalConfig);
|
|
@@ -98,6 +122,33 @@ export function restoreTopLevelModelProvider(currentConfig, originalConfig) {
|
|
|
98
122
|
}
|
|
99
123
|
return output.join(lineEnding);
|
|
100
124
|
}
|
|
125
|
+
export function restoreTopLevelResponseStorage(currentConfig, originalConfig) {
|
|
126
|
+
const lineEnding = currentConfig.includes("\r\n") ? "\r\n" : "\n";
|
|
127
|
+
const originalLine = extractTopLevelLine(originalConfig, "disable_response_storage");
|
|
128
|
+
if (!originalLine)
|
|
129
|
+
return currentConfig;
|
|
130
|
+
const lines = currentConfig.length > 0 ? currentConfig.split(/\r?\n/) : [];
|
|
131
|
+
const output = [];
|
|
132
|
+
let handled = false;
|
|
133
|
+
let inTopLevel = true;
|
|
134
|
+
for (const line of lines) {
|
|
135
|
+
if (readTomlTableName(line) !== null) {
|
|
136
|
+
inTopLevel = false;
|
|
137
|
+
output.push(line);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (!handled &&
|
|
141
|
+
inTopLevel &&
|
|
142
|
+
/^\s*disable_response_storage\s*=/.test(line) &&
|
|
143
|
+
readTomlTableName(line) === null) {
|
|
144
|
+
output.push(originalLine);
|
|
145
|
+
handled = true;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
output.push(line);
|
|
149
|
+
}
|
|
150
|
+
return output.join(lineEnding);
|
|
151
|
+
}
|
|
101
152
|
export function ensureTomlTrailingNewline(value) {
|
|
102
153
|
return value.replace(/[\r\n]*$/, "\n");
|
|
103
154
|
}
|
|
@@ -118,11 +169,13 @@ export function rewriteConfigTomlForRuntimeRotationProvider(rawConfig, baseUrl,
|
|
|
118
169
|
const lineEnding = rawConfig.includes("\r\n") ? "\r\n" : "\n";
|
|
119
170
|
const withoutOldProvider = removeRuntimeRotationProviderBlock(rawConfig).replace(/[\r\n]*$/, "");
|
|
120
171
|
const withModelProvider = rewriteTopLevelModelProvider(withoutOldProvider).replace(/[\r\n]*$/, "");
|
|
172
|
+
const withResponseStorage = enableTopLevelResponseStorage(withModelProvider).replace(/[\r\n]*$/, "");
|
|
121
173
|
const providerBlock = createRuntimeRotationProviderBlock(baseUrl, clientApiKey).join(lineEnding);
|
|
122
|
-
return `${
|
|
174
|
+
return `${withResponseStorage}${lineEnding}${lineEnding}${providerBlock}${lineEnding}`;
|
|
123
175
|
}
|
|
124
176
|
export function restoreConfigTomlFromRuntimeRotationProvider(currentConfig, originalConfig) {
|
|
125
177
|
const withoutProvider = removeRuntimeRotationProviderBlock(currentConfig);
|
|
126
|
-
|
|
178
|
+
const withResponseStorage = restoreTopLevelResponseStorage(withoutProvider, originalConfig);
|
|
179
|
+
return ensureTomlTrailingNewline(restoreTopLevelModelProvider(withResponseStorage, originalConfig).replace(/[\r\n]*$/, ""));
|
|
127
180
|
}
|
|
128
181
|
//# sourceMappingURL=config-toml.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-toml.js","sourceRoot":"","sources":["../../../lib/runtime/config-toml.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config-toml.js","sourceRoot":"","sources":["../../../lib/runtime/config-toml.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,cAAc,EAGd,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,cAAc,EAGd,MAAM,eAAe,CAAC;AAkCvB,MAAM,WAAW,0BAA0B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,SAAS,EAAE,MAAM,0BAA0B,CAAC;CAC5C;AAED,MAAM,WAAW,0BAA0B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,2BAA2B;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAwyBD,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CAkkBrC"}
|
|
@@ -7,6 +7,7 @@ import { getModelFamily } from "./prompts/codex.js";
|
|
|
7
7
|
import { queuedRefresh } from "./refresh-queue.js";
|
|
8
8
|
import { mutateRuntimeObservabilitySnapshot } from "./runtime/runtime-observability.js";
|
|
9
9
|
import { createRuntimeUsageRecorder, evaluateRuntimePolicy, loadRuntimePolicyState, } from "./policy/runtime-policy.js";
|
|
10
|
+
import { isWorkspaceDisabledError } from "./request/fetch-helpers.js";
|
|
10
11
|
import { SessionAffinityStore } from "./session-affinity.js";
|
|
11
12
|
import { isRecord } from "./utils.js";
|
|
12
13
|
const DEFAULT_HOST = "127.0.0.1";
|
|
@@ -14,6 +15,7 @@ const DEFAULT_QUOTA_REMAINING_THRESHOLD = 10;
|
|
|
14
15
|
const DEFAULT_AUTH_FAILURE_COOLDOWN_MS = 30_000;
|
|
15
16
|
const DEFAULT_MAX_RUNTIME_ACCOUNT_ATTEMPTS = 4;
|
|
16
17
|
const MAX_REQUEST_BODY_BYTES = 64 * 1024 * 1024;
|
|
18
|
+
const MAX_THREAD_GOAL_FALLBACKS = 512;
|
|
17
19
|
const HOP_BY_HOP_HEADERS = new Set([
|
|
18
20
|
"connection",
|
|
19
21
|
"content-length",
|
|
@@ -46,12 +48,24 @@ const ALLOWED_MODELS_PATHS = new Set([
|
|
|
46
48
|
URL_PATHS.MODELS,
|
|
47
49
|
`/v1${URL_PATHS.MODELS}`,
|
|
48
50
|
]);
|
|
51
|
+
const ALLOWED_THREAD_GOAL_PATHS = new Set([
|
|
52
|
+
"/thread/goal/get",
|
|
53
|
+
"/thread/goal/set",
|
|
54
|
+
"/codex/thread/goal/get",
|
|
55
|
+
"/codex/thread/goal/set",
|
|
56
|
+
]);
|
|
49
57
|
function isResponsesPath(pathname) {
|
|
50
58
|
return ALLOWED_RESPONSES_PATHS.has(pathname);
|
|
51
59
|
}
|
|
52
60
|
function isModelsPath(pathname) {
|
|
53
61
|
return ALLOWED_MODELS_PATHS.has(pathname);
|
|
54
62
|
}
|
|
63
|
+
function isThreadGoalPath(pathname) {
|
|
64
|
+
return ALLOWED_THREAD_GOAL_PATHS.has(pathname);
|
|
65
|
+
}
|
|
66
|
+
function normalizeThreadGoalUpstreamPath(pathname) {
|
|
67
|
+
return pathname.startsWith("/codex/") ? pathname : `/codex${pathname}`;
|
|
68
|
+
}
|
|
55
69
|
function headersFromIncoming(req) {
|
|
56
70
|
const headers = new Headers();
|
|
57
71
|
for (const [key, value] of Object.entries(req.headers)) {
|
|
@@ -191,6 +205,33 @@ function readStringRecordValue(record, key) {
|
|
|
191
205
|
? value.trim()
|
|
192
206
|
: null;
|
|
193
207
|
}
|
|
208
|
+
function readStringSearchParam(searchParams, key) {
|
|
209
|
+
const value = searchParams.get(key);
|
|
210
|
+
return value && value.trim().length > 0 ? value.trim() : null;
|
|
211
|
+
}
|
|
212
|
+
function isThreadGoalFallbackStatus(status) {
|
|
213
|
+
return status === HTTP_STATUS.FORBIDDEN;
|
|
214
|
+
}
|
|
215
|
+
function setThreadGoalFallback(fallbacks, key, goal) {
|
|
216
|
+
if (fallbacks.has(key)) {
|
|
217
|
+
fallbacks.delete(key);
|
|
218
|
+
}
|
|
219
|
+
fallbacks.set(key, goal);
|
|
220
|
+
while (fallbacks.size > MAX_THREAD_GOAL_FALLBACKS) {
|
|
221
|
+
const oldestKey = fallbacks.keys().next().value;
|
|
222
|
+
if (typeof oldestKey !== "string")
|
|
223
|
+
break;
|
|
224
|
+
fallbacks.delete(oldestKey);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function getThreadGoalFallback(fallbacks, key) {
|
|
228
|
+
if (!fallbacks.has(key))
|
|
229
|
+
return null;
|
|
230
|
+
const goal = fallbacks.get(key) ?? null;
|
|
231
|
+
fallbacks.delete(key);
|
|
232
|
+
fallbacks.set(key, goal);
|
|
233
|
+
return goal;
|
|
234
|
+
}
|
|
194
235
|
function resolveSessionKey(headers, parsedBody) {
|
|
195
236
|
const headerKey = headers.get(OPENAI_HEADERS.SESSION_ID) ??
|
|
196
237
|
headers.get(OPENAI_HEADERS.CONVERSATION_ID) ??
|
|
@@ -246,6 +287,28 @@ function buildModelsRequestContext(req) {
|
|
|
246
287
|
sessionKey: null,
|
|
247
288
|
};
|
|
248
289
|
}
|
|
290
|
+
function buildThreadGoalRequestContext(req, body, pathname) {
|
|
291
|
+
const headers = headersFromIncoming(req);
|
|
292
|
+
const parsedBody = parseRequestBody(body);
|
|
293
|
+
const searchParams = new URL(req.url ?? "/", "http://127.0.0.1").searchParams;
|
|
294
|
+
const queryThreadKey = readStringSearchParam(searchParams, "thread_id") ??
|
|
295
|
+
readStringSearchParam(searchParams, "threadId");
|
|
296
|
+
const bodyThreadKey = parsedBody
|
|
297
|
+
? (readStringRecordValue(parsedBody, "thread_id") ??
|
|
298
|
+
readStringRecordValue(parsedBody, "threadId"))
|
|
299
|
+
: null;
|
|
300
|
+
const sessionKey = bodyThreadKey ?? queryThreadKey ?? resolveSessionKey(headers, parsedBody);
|
|
301
|
+
return {
|
|
302
|
+
body,
|
|
303
|
+
headers,
|
|
304
|
+
method: req.method === "GET" ? "GET" : "POST",
|
|
305
|
+
upstreamPath: normalizeThreadGoalUpstreamPath(pathname),
|
|
306
|
+
model: null,
|
|
307
|
+
family: "codex",
|
|
308
|
+
stream: false,
|
|
309
|
+
sessionKey,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
249
312
|
function buildUpstreamUrl(req, upstreamBaseUrl, upstreamPath) {
|
|
250
313
|
const incomingUrl = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
251
314
|
const upstream = new URL(upstreamBaseUrl);
|
|
@@ -386,6 +449,29 @@ async function readErrorBody(response) {
|
|
|
386
449
|
return "";
|
|
387
450
|
}
|
|
388
451
|
}
|
|
452
|
+
function extractErrorCodeFromBody(bodyText) {
|
|
453
|
+
if (!bodyText.trim())
|
|
454
|
+
return null;
|
|
455
|
+
try {
|
|
456
|
+
const parsed = JSON.parse(bodyText);
|
|
457
|
+
if (!isRecord(parsed))
|
|
458
|
+
return null;
|
|
459
|
+
const directCode = parsed.code;
|
|
460
|
+
if (typeof directCode === "string" && directCode.trim()) {
|
|
461
|
+
return directCode.trim();
|
|
462
|
+
}
|
|
463
|
+
const maybeError = parsed.error;
|
|
464
|
+
if (!isRecord(maybeError))
|
|
465
|
+
return null;
|
|
466
|
+
const nestedCode = maybeError.code;
|
|
467
|
+
return typeof nestedCode === "string" && nestedCode.trim()
|
|
468
|
+
? nestedCode.trim()
|
|
469
|
+
: null;
|
|
470
|
+
}
|
|
471
|
+
catch {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
389
475
|
function getQuotaWindowWaitMs(headers, prefix, now) {
|
|
390
476
|
const resetAfterSeconds = Number.parseInt(headers.get(`${prefix}-reset-after-seconds`) ?? "", 10);
|
|
391
477
|
if (Number.isFinite(resetAfterSeconds) && resetAfterSeconds > 0) {
|
|
@@ -465,7 +551,7 @@ function writeJson(res, status, payload) {
|
|
|
465
551
|
function writeMethodOrPathError(res) {
|
|
466
552
|
writeJson(res, 404, {
|
|
467
553
|
error: {
|
|
468
|
-
message: "Runtime rotation proxy only accepts Responses API
|
|
554
|
+
message: "Runtime rotation proxy only accepts Responses API, model discovery, and Codex thread goal requests.",
|
|
469
555
|
code: "runtime_rotation_proxy_not_found",
|
|
470
556
|
},
|
|
471
557
|
});
|
|
@@ -593,13 +679,16 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
593
679
|
lastAccountId: null,
|
|
594
680
|
lastAccountUpdatedAt: null,
|
|
595
681
|
};
|
|
682
|
+
const threadGoalFallbacks = new Map();
|
|
596
683
|
const handleRequest = async (req, res) => {
|
|
597
684
|
let usageRecorder = null;
|
|
598
685
|
try {
|
|
599
686
|
const incomingUrl = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
600
687
|
const isResponsesRequest = req.method === "POST" && isResponsesPath(incomingUrl.pathname);
|
|
601
688
|
const isModelsRequest = req.method === "GET" && isModelsPath(incomingUrl.pathname);
|
|
602
|
-
|
|
689
|
+
const isThreadGoalRequest = (req.method === "GET" || req.method === "POST") &&
|
|
690
|
+
isThreadGoalPath(incomingUrl.pathname);
|
|
691
|
+
if (!isResponsesRequest && !isModelsRequest && !isThreadGoalRequest) {
|
|
603
692
|
writeMethodOrPathError(res);
|
|
604
693
|
return;
|
|
605
694
|
}
|
|
@@ -609,9 +698,14 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
609
698
|
return;
|
|
610
699
|
}
|
|
611
700
|
status.totalRequests += 1;
|
|
701
|
+
const requestBody = isResponsesRequest || (isThreadGoalRequest && req.method === "POST")
|
|
702
|
+
? await readRequestBody(req, maxRequestBodyBytes)
|
|
703
|
+
: Buffer.alloc(0);
|
|
612
704
|
const context = isModelsRequest
|
|
613
705
|
? buildModelsRequestContext(req)
|
|
614
|
-
:
|
|
706
|
+
: isThreadGoalRequest
|
|
707
|
+
? buildThreadGoalRequestContext(req, requestBody, incomingUrl.pathname)
|
|
708
|
+
: buildResponsesRequestContext(req, requestBody);
|
|
615
709
|
const requestStartedAt = now();
|
|
616
710
|
let policyDecision = null;
|
|
617
711
|
let projectKey = null;
|
|
@@ -632,7 +726,11 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
632
726
|
}
|
|
633
727
|
usageRecorder = createRuntimeUsageRecorder({
|
|
634
728
|
source: "runtime-proxy",
|
|
635
|
-
operation: isModelsRequest
|
|
729
|
+
operation: isModelsRequest
|
|
730
|
+
? "models"
|
|
731
|
+
: isThreadGoalRequest
|
|
732
|
+
? "thread-goal"
|
|
733
|
+
: "responses",
|
|
636
734
|
model: context.model,
|
|
637
735
|
projectKey,
|
|
638
736
|
requestId: context.sessionKey,
|
|
@@ -670,8 +768,12 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
670
768
|
const upstreamUrl = buildUpstreamUrl(req, upstreamBaseUrl, context.upstreamPath);
|
|
671
769
|
const attemptedIndexes = new Set();
|
|
672
770
|
let exhaustionReason = "no-account";
|
|
673
|
-
const
|
|
674
|
-
|
|
771
|
+
const accountCount = accountManager.getAccountCount();
|
|
772
|
+
const transientAttemptLimit = Math.max(1, Math.min(accountCount, maxRuntimeAccountAttempts));
|
|
773
|
+
let transientAttempts = 0;
|
|
774
|
+
let transientExhaustionReason = null;
|
|
775
|
+
while (attemptedIndexes.size < accountCount &&
|
|
776
|
+
transientAttempts < transientAttemptLimit) {
|
|
675
777
|
const selected = chooseAccount({
|
|
676
778
|
accountManager,
|
|
677
779
|
sessionAffinityStore,
|
|
@@ -702,6 +804,8 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
702
804
|
exhaustionReason = "auth-failure";
|
|
703
805
|
if (!refreshed.retryable)
|
|
704
806
|
continue;
|
|
807
|
+
transientAttempts += 1;
|
|
808
|
+
transientExhaustionReason = "auth-failure";
|
|
705
809
|
status.retries += 1;
|
|
706
810
|
status.rotations += 1;
|
|
707
811
|
continue;
|
|
@@ -712,6 +816,8 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
712
816
|
accountManager.recordFailure(refreshed.account, context.family, context.model);
|
|
713
817
|
accountManager.markAccountCoolingDown(refreshed.account, DEFAULT_AUTH_FAILURE_COOLDOWN_MS, "auth-failure");
|
|
714
818
|
exhaustionReason = "auth-failure";
|
|
819
|
+
transientAttempts += 1;
|
|
820
|
+
transientExhaustionReason = "auth-failure";
|
|
715
821
|
status.retries += 1;
|
|
716
822
|
status.rotations += 1;
|
|
717
823
|
continue;
|
|
@@ -740,6 +846,8 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
740
846
|
accountManager.markAccountCoolingDown(refreshed.account, networkErrorCooldownMs, "network-error");
|
|
741
847
|
accountManager.saveToDiskDebounced();
|
|
742
848
|
exhaustionReason = "network-error";
|
|
849
|
+
transientAttempts += 1;
|
|
850
|
+
transientExhaustionReason = "network-error";
|
|
743
851
|
status.retries += 1;
|
|
744
852
|
status.rotations += 1;
|
|
745
853
|
continue;
|
|
@@ -755,10 +863,75 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
755
863
|
accountManager.markRateLimitedWithReason(refreshed.account, retryAfterMs, context.family, "quota", context.model);
|
|
756
864
|
accountManager.saveToDiskDebounced();
|
|
757
865
|
exhaustionReason = "rate-limit";
|
|
866
|
+
transientAttempts += 1;
|
|
867
|
+
transientExhaustionReason = "rate-limit";
|
|
758
868
|
status.retries += 1;
|
|
759
869
|
status.rotations += 1;
|
|
760
870
|
continue;
|
|
761
871
|
}
|
|
872
|
+
if (upstream.status === 402 || upstream.status === HTTP_STATUS.FORBIDDEN) {
|
|
873
|
+
const bodyText = await readErrorBody(upstream);
|
|
874
|
+
const errorCode = extractErrorCodeFromBody(bodyText);
|
|
875
|
+
if (isWorkspaceDisabledError(upstream.status, errorCode, bodyText)) {
|
|
876
|
+
const accountWasEnabled = accountManager.getAccountByIndex(refreshed.account.index)?.enabled !==
|
|
877
|
+
false;
|
|
878
|
+
accountManager.refundToken(refreshed.account, context.family, context.model);
|
|
879
|
+
if (accountWasEnabled) {
|
|
880
|
+
accountManager.recordFailure(refreshed.account, context.family, context.model);
|
|
881
|
+
accountManager.setAccountEnabled(refreshed.account.index, false);
|
|
882
|
+
accountManager.saveToDiskDebounced();
|
|
883
|
+
}
|
|
884
|
+
sessionAffinityStore?.forgetSession(context.sessionKey);
|
|
885
|
+
exhaustionReason = "deactivated";
|
|
886
|
+
status.retries += 1;
|
|
887
|
+
status.rotations += 1;
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
if (isThreadGoalRequest && isThreadGoalFallbackStatus(upstream.status)) {
|
|
891
|
+
const parsedGoalBody = parseRequestBody(context.body);
|
|
892
|
+
const fallbackKey = context.sessionKey;
|
|
893
|
+
const goal = typeof parsedGoalBody?.goal === "string" ? parsedGoalBody.goal : null;
|
|
894
|
+
if (!fallbackKey) {
|
|
895
|
+
await usageRecorder.record({
|
|
896
|
+
outcome: "failure",
|
|
897
|
+
statusCode: HTTP_STATUS.BAD_REQUEST,
|
|
898
|
+
errorCode: "thread_goal_session_key_required",
|
|
899
|
+
account: refreshed.account,
|
|
900
|
+
});
|
|
901
|
+
writeJson(res, HTTP_STATUS.BAD_REQUEST, {
|
|
902
|
+
error: {
|
|
903
|
+
message: "Thread goal fallback requires a thread_id, threadId, or session header.",
|
|
904
|
+
code: "thread_goal_session_key_required",
|
|
905
|
+
},
|
|
906
|
+
});
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
await usageRecorder.record({
|
|
910
|
+
outcome: "failure",
|
|
911
|
+
statusCode: upstream.status,
|
|
912
|
+
errorCode: "thread_goal_upstream_blocked",
|
|
913
|
+
account: refreshed.account,
|
|
914
|
+
});
|
|
915
|
+
if (context.upstreamPath.endsWith("/set")) {
|
|
916
|
+
setThreadGoalFallback(threadGoalFallbacks, fallbackKey, goal);
|
|
917
|
+
writeJson(res, HTTP_STATUS.OK, { ok: true, goal });
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
writeJson(res, HTTP_STATUS.OK, {
|
|
921
|
+
goal: getThreadGoalFallback(threadGoalFallbacks, fallbackKey),
|
|
922
|
+
});
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
res.writeHead(upstream.status, responseHeadersForClient(upstream.headers));
|
|
926
|
+
res.end(bodyText);
|
|
927
|
+
await usageRecorder.record({
|
|
928
|
+
outcome: "failure",
|
|
929
|
+
statusCode: upstream.status,
|
|
930
|
+
errorCode,
|
|
931
|
+
account: refreshed.account,
|
|
932
|
+
});
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
762
935
|
if (upstream.status === HTTP_STATUS.UNAUTHORIZED) {
|
|
763
936
|
await readErrorBody(upstream);
|
|
764
937
|
accountManager.refundToken(refreshed.account, context.family, context.model);
|
|
@@ -766,6 +939,8 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
766
939
|
accountManager.markAccountCoolingDown(refreshed.account, DEFAULT_AUTH_FAILURE_COOLDOWN_MS, "auth-failure");
|
|
767
940
|
accountManager.saveToDiskDebounced();
|
|
768
941
|
exhaustionReason = "auth-failure";
|
|
942
|
+
transientAttempts += 1;
|
|
943
|
+
transientExhaustionReason = "auth-failure";
|
|
769
944
|
status.retries += 1;
|
|
770
945
|
status.rotations += 1;
|
|
771
946
|
continue;
|
|
@@ -777,10 +952,22 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
777
952
|
accountManager.markAccountCoolingDown(refreshed.account, serverErrorCooldownMs, "server-error");
|
|
778
953
|
accountManager.saveToDiskDebounced();
|
|
779
954
|
exhaustionReason = "server-error";
|
|
955
|
+
transientAttempts += 1;
|
|
956
|
+
transientExhaustionReason = "server-error";
|
|
780
957
|
status.retries += 1;
|
|
781
958
|
status.rotations += 1;
|
|
782
959
|
continue;
|
|
783
960
|
}
|
|
961
|
+
if (isThreadGoalRequest && upstream.status >= 400) {
|
|
962
|
+
const forwarded = await forwardStreamingResponse(upstream, res, status, () => undefined, streamStallTimeoutMs);
|
|
963
|
+
await usageRecorder.record({
|
|
964
|
+
outcome: "failure",
|
|
965
|
+
statusCode: upstream.status,
|
|
966
|
+
errorCode: forwarded ? "thread_goal_upstream_error" : "stream_forward_failed",
|
|
967
|
+
account: refreshed.account,
|
|
968
|
+
});
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
784
971
|
accountManager.recordSuccess(refreshed.account, context.family, context.model);
|
|
785
972
|
const nearExhaustionWaitMs = getQuotaNearExhaustionWaitMs(upstream.headers, quotaRemainingPercentThreshold, now());
|
|
786
973
|
if (nearExhaustionWaitMs > 0) {
|
|
@@ -806,10 +993,14 @@ export async function startRuntimeRotationProxy(options) {
|
|
|
806
993
|
});
|
|
807
994
|
return;
|
|
808
995
|
}
|
|
809
|
-
if (
|
|
810
|
-
|
|
996
|
+
if (transientAttempts >= transientAttemptLimit &&
|
|
997
|
+
attemptedIndexes.size < accountCount) {
|
|
811
998
|
exhaustionReason = "budget";
|
|
812
999
|
}
|
|
1000
|
+
else if (exhaustionReason === "deactivated" &&
|
|
1001
|
+
transientExhaustionReason) {
|
|
1002
|
+
exhaustionReason = transientExhaustionReason;
|
|
1003
|
+
}
|
|
813
1004
|
await usageRecorder?.record({
|
|
814
1005
|
outcome: "failure",
|
|
815
1006
|
statusCode: normalizeExhaustionStatus(exhaustionReason),
|