@askalf/dario 5.5.84 → 5.5.85
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/cli.js +2 -0
- package/dist/codex-accounts.d.ts +3 -0
- package/dist/codex-accounts.js +33 -0
- package/dist/proxy.js +18 -15
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1138,6 +1138,8 @@ async function codex() {
|
|
|
1138
1138
|
await completeAddCodexAccount(alias, code, codeVerifier);
|
|
1139
1139
|
console.log('');
|
|
1140
1140
|
console.log(` Added Codex account "${alias}".`);
|
|
1141
|
+
console.log(' A proxy that is already running picks it up within ~30s —');
|
|
1142
|
+
console.log(' no restart needed (dario#1138).');
|
|
1141
1143
|
console.log('');
|
|
1142
1144
|
}
|
|
1143
1145
|
catch (err) {
|
package/dist/codex-accounts.d.ts
CHANGED
|
@@ -6,6 +6,9 @@ export interface CodexAccountCredentials {
|
|
|
6
6
|
idToken?: string;
|
|
7
7
|
}
|
|
8
8
|
export declare function listCodexAccountAliases(): Promise<string[]>;
|
|
9
|
+
export declare function hasAnyCodexAccount(nowMs?: number): Promise<boolean>;
|
|
10
|
+
/** Drop the negative cache so a test doesn't have to sleep out its TTL. */
|
|
11
|
+
export declare function _resetCodexPresenceCacheForTest(): void;
|
|
9
12
|
export declare function loadCodexAccount(alias: string): Promise<CodexAccountCredentials | null>;
|
|
10
13
|
export declare function loadAllCodexAccounts(): Promise<CodexAccountCredentials[]>;
|
|
11
14
|
export declare function saveCodexAccount(creds: CodexAccountCredentials): Promise<void>;
|
package/dist/codex-accounts.js
CHANGED
|
@@ -43,6 +43,35 @@ export async function listCodexAccountAliases() {
|
|
|
43
43
|
return [];
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* "Is the codex route available at all" — the routing question, asked per
|
|
48
|
+
* request rather than once at startup (dario#1138).
|
|
49
|
+
*
|
|
50
|
+
* The proxy used to resolve this a single time while booting, so an account
|
|
51
|
+
* stored by `dario codex add` against an ALREADY-RUNNING proxy stayed
|
|
52
|
+
* invisible until a restart: /v1/models advertised no gpt slugs and a listed
|
|
53
|
+
* slug fell through to the Claude path as an unknown model. `dario login`
|
|
54
|
+
* restarts the proxy by convention, `dario codex add` does not.
|
|
55
|
+
*
|
|
56
|
+
* Cheap enough to ask often — a readdir of a directory holding at most a
|
|
57
|
+
* handful of files — but an idle proxy still shouldn't hit the filesystem on
|
|
58
|
+
* every request, so the NEGATIVE answer is cached briefly. The positive one
|
|
59
|
+
* isn't cached: the caller goes on to read the credentials anyway, and a
|
|
60
|
+
* `codex remove` has to take effect immediately.
|
|
61
|
+
*/
|
|
62
|
+
const CODEX_PRESENCE_NEGATIVE_TTL_MS = 30_000;
|
|
63
|
+
let codexAbsentUntil = 0;
|
|
64
|
+
export async function hasAnyCodexAccount(nowMs = Date.now()) {
|
|
65
|
+
if (nowMs < codexAbsentUntil)
|
|
66
|
+
return false;
|
|
67
|
+
const present = (await listCodexAccountAliases()).length > 0;
|
|
68
|
+
codexAbsentUntil = present ? 0 : nowMs + CODEX_PRESENCE_NEGATIVE_TTL_MS;
|
|
69
|
+
return present;
|
|
70
|
+
}
|
|
71
|
+
/** Drop the negative cache so a test doesn't have to sleep out its TTL. */
|
|
72
|
+
export function _resetCodexPresenceCacheForTest() {
|
|
73
|
+
codexAbsentUntil = 0;
|
|
74
|
+
}
|
|
46
75
|
export async function loadCodexAccount(alias) {
|
|
47
76
|
const path = safeAliasPath(alias);
|
|
48
77
|
if (!path)
|
|
@@ -66,6 +95,10 @@ export async function saveCodexAccount(creds) {
|
|
|
66
95
|
throw new Error(`invalid codex account alias: ${creds.alias}`);
|
|
67
96
|
await ensureDir();
|
|
68
97
|
await durableWriteFile(path, JSON.stringify(creds, null, 2), 0o600);
|
|
98
|
+
// An account stored in THIS process (`dario codex add` in a running admin
|
|
99
|
+
// path, or a test) must not be hidden by a negative cache entry taken
|
|
100
|
+
// moments earlier.
|
|
101
|
+
codexAbsentUntil = 0;
|
|
69
102
|
}
|
|
70
103
|
export async function removeCodexAccount(alias) {
|
|
71
104
|
const path = safeAliasPath(alias);
|
package/dist/proxy.js
CHANGED
|
@@ -21,7 +21,7 @@ import { handleAdminRequest } from './admin-api.js';
|
|
|
21
21
|
import { createTokenBucket } from './rate-limit.js';
|
|
22
22
|
import { getOpenAIBackend, isOpenAIModel, forwardToOpenAI } from './openai-backend.js';
|
|
23
23
|
import { forwardToCodex, getCodexModelSlugs, CODEX_BACKEND_BASE_URL } from './codex-backend.js';
|
|
24
|
-
import { listCodexAccountAliases, selectCodexAccount, getFreshCodexAccount } from './codex-accounts.js';
|
|
24
|
+
import { listCodexAccountAliases, hasAnyCodexAccount, selectCodexAccount, getFreshCodexAccount } from './codex-accounts.js';
|
|
25
25
|
import { route as routeProvider } from './provider-adapter.js';
|
|
26
26
|
import { RequestQueue, QueueFullError, QueueTimeoutError, DEFAULT_MAX_CONCURRENT, DEFAULT_MAX_QUEUED, DEFAULT_QUEUE_TIMEOUT_MS } from './request-queue.js';
|
|
27
27
|
import { redactSecrets } from './redact.js';
|
|
@@ -1222,12 +1222,16 @@ export async function startProxy(opts = {}) {
|
|
|
1222
1222
|
console.log(` OpenAI-compat backend: ${openaiBackend.name} → ${openaiBackend.baseUrl}`);
|
|
1223
1223
|
}
|
|
1224
1224
|
// Codex/ChatGPT-subscription accounts — the "altman" engine (dario#1009).
|
|
1225
|
-
//
|
|
1226
|
-
//
|
|
1227
|
-
//
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1225
|
+
// This startup probe only decides what to PRINT and whether a Claude login
|
|
1226
|
+
// is required to boot; routing re-asks hasAnyCodexAccount() per request
|
|
1227
|
+
// (dario#1138), so an account stored by `dario codex add` against an
|
|
1228
|
+
// already-running proxy is picked up without a restart — `dario login`
|
|
1229
|
+
// restarts the proxy by convention, `dario codex add` does not. The
|
|
1230
|
+
// credentials themselves are re-read per request too (they rotate on
|
|
1231
|
+
// refresh).
|
|
1232
|
+
const startupCodexAliases = await listCodexAccountAliases();
|
|
1233
|
+
if (startupCodexAliases.length > 0) {
|
|
1234
|
+
console.log(` Codex accounts: ${startupCodexAliases.join(', ')} → ${CODEX_BACKEND_BASE_URL}`);
|
|
1231
1235
|
}
|
|
1232
1236
|
// Pool-exhausted fallback (strictly opt-in). When the Claude pool can't
|
|
1233
1237
|
// serve — every seat rate-limited or in auth cool-down — OpenAI-shape
|
|
@@ -1421,7 +1425,7 @@ export async function startProxy(opts = {}) {
|
|
|
1421
1425
|
// dead-but-refreshable token (a container restarted right after a normal
|
|
1422
1426
|
// expiry, gap #1) is refreshed, then back-filled so the recovered login
|
|
1423
1427
|
// becomes the pool-of-one it should be — rather than crash-looping on exit(1).
|
|
1424
|
-
if (requiresClaudeLogin(pool.size, adminEnabled, !!upstreamApiKey, opts.noClaudeAuth ?? false,
|
|
1428
|
+
if (requiresClaudeLogin(pool.size, adminEnabled, !!upstreamApiKey, opts.noClaudeAuth ?? false, startupCodexAliases.length > 0)) {
|
|
1425
1429
|
const single = await resolveSingleAccountStartupStatus();
|
|
1426
1430
|
if (!single.authenticated) {
|
|
1427
1431
|
console.error('[dario] Not authenticated. Run `dario login` first.');
|
|
@@ -2168,7 +2172,7 @@ export async function startProxy(opts = {}) {
|
|
|
2168
2172
|
// models that account may actually use. Discovery is cached and never
|
|
2169
2173
|
// throws, so /v1/models keeps its "always answers" property.
|
|
2170
2174
|
let codexNames = [];
|
|
2171
|
-
if (
|
|
2175
|
+
if (await hasAnyCodexAccount()) {
|
|
2172
2176
|
const stored = await selectCodexAccount();
|
|
2173
2177
|
if (stored) {
|
|
2174
2178
|
const creds = await getFreshCodexAccount(stored).catch(() => stored);
|
|
@@ -2490,17 +2494,16 @@ export async function startProxy(opts = {}) {
|
|
|
2490
2494
|
// case is a map lookup, not a request.
|
|
2491
2495
|
let codexCreds = null;
|
|
2492
2496
|
let codexModels = [];
|
|
2493
|
-
|
|
2497
|
+
// Presence is re-asked here rather than read from a startup flag so
|
|
2498
|
+
// an account added while the proxy runs routes on the very next
|
|
2499
|
+
// request; the absent answer is cached ~30s, so an idle proxy with
|
|
2500
|
+
// no codex account is not stat-ing the filesystem per request.
|
|
2501
|
+
if (isOpenAI && await hasAnyCodexAccount()) {
|
|
2494
2502
|
const stored = await selectCodexAccount();
|
|
2495
2503
|
if (stored) {
|
|
2496
2504
|
codexCreds = await getFreshCodexAccount(stored);
|
|
2497
2505
|
codexModels = await getCodexModelSlugs(codexCreds);
|
|
2498
2506
|
}
|
|
2499
|
-
else {
|
|
2500
|
-
// Accounts disappeared since startup — re-arm the routing flag so
|
|
2501
|
-
// later requests skip the codex path entirely.
|
|
2502
|
-
hasCodexAccount = false;
|
|
2503
|
-
}
|
|
2504
2507
|
}
|
|
2505
2508
|
const decision = routeProvider({
|
|
2506
2509
|
isOpenAIPath: isOpenAI,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.85",
|
|
4
4
|
"description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|