@bitkyc08/opencodex 2.40.0 → 2.41.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 +4 -0
- package/gui/dist/assets/index-B2YjLA-i.css +1 -0
- package/gui/dist/assets/{index-BHe2rl_C.js → index-aPup8CKb.js} +20 -20
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/meta.svg +1 -0
- package/package.json +4 -3
- package/src/adapters/cursor/catalog.ts +71 -29
- package/src/adapters/cursor/claude-id.ts +76 -0
- package/src/adapters/cursor/discovery.ts +16 -3
- package/src/adapters/cursor/effort-map.ts +27 -12
- package/src/adapters/google.ts +39 -2
- package/src/adapters/openai-responses.ts +14 -1
- package/src/cli/claude.ts +11 -2
- package/src/cli/connect.ts +7 -1
- package/src/cli/registry.ts +1 -1
- package/src/cli/status.ts +19 -4
- package/src/client/connect.ts +5 -1
- package/src/client/hub-client.ts +29 -5
- package/src/clients/config-export.ts +12 -2
- package/src/codex/catalog/aggregation.ts +8 -0
- package/src/codex/catalog/metadata.ts +5 -0
- package/src/codex/catalog/parsing.ts +2 -0
- package/src/codex/catalog/provider-fetch.ts +163 -26
- package/src/codex/catalog.ts +1 -1
- package/src/codex/convergence-types.ts +1 -0
- package/src/codex/desired-state.ts +18 -11
- package/src/combos/failover.ts +185 -6
- package/src/combos/index.ts +6 -0
- package/src/combos/resolve.ts +43 -6
- package/src/config.ts +5 -1
- package/src/generated/compatibility-version.json +85 -61
- package/src/generated/model-metadata.ts +1 -1
- package/src/grok/sync.ts +10 -2
- package/src/integrations/cursor-effort-table.ts +143 -0
- package/src/integrations/state.ts +1 -1
- package/src/integrations/writer.ts +2 -2
- package/src/lib/app-owned-memory-stores.ts +27 -8
- package/src/lib/bounded-body.ts +16 -1
- package/src/oauth/generic-account-failover.ts +2 -2
- package/src/oauth/index.ts +11 -0
- package/src/oauth/meta-muse.ts +235 -0
- package/src/providers/antigravity-models.ts +71 -13
- package/src/providers/command-code-efforts.ts +15 -0
- package/src/providers/free-directory.ts +4 -1
- package/src/providers/registry.ts +116 -8
- package/src/responses/code-mode-helper-compat.ts +4 -1
- package/src/responses/state.ts +5 -4
- package/src/server/auth-cors.ts +241 -56
- package/src/server/chat-completions.ts +11 -2
- package/src/server/chat-native.ts +30 -4
- package/src/server/claude-messages.ts +17 -3
- package/src/server/effort-row.ts +131 -0
- package/src/server/index.ts +67 -38
- package/src/server/management/api-key-rotation.ts +2 -1
- package/src/server/management/api-key-usage.ts +97 -43
- package/src/server/management/context.ts +3 -0
- package/src/server/management/cursor-integration-routes.ts +36 -7
- package/src/server/management/logs-usage-routes.ts +64 -87
- package/src/server/management/provider-routes.ts +218 -1
- package/src/server/management/route-registry.ts +1 -0
- package/src/server/management/usage-aggregate-cache.ts +464 -0
- package/src/server/management/usage-summary-cache.ts +4 -0
- package/src/server/models-capabilities.ts +60 -5
- package/src/server/responses/core.ts +61 -7
- package/src/types/config.ts +10 -1
- package/src/types/tools.ts +12 -9
- package/src/usage/expected-prices.ts +43 -7
- package/src/usage/ledger-scanner.ts +448 -0
- package/src/usage/log.ts +1 -1
- package/src/usage/summary.ts +915 -655
- package/src/web-search/index.ts +1 -1
- package/gui/dist/assets/index-CJSb3HPe.css +0 -1
package/src/client/hub-client.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MAX_REMOTE_CATALOG_BYTES } from "../server/catalog-download";
|
|
2
2
|
import { readBoundedResponseBytes } from "../lib/bounded-body";
|
|
3
|
+
import { clearableDeadline } from "../lib/abort";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* A pairing grant may cross loopback or authenticated HTTPS, and nothing else.
|
|
@@ -84,13 +85,17 @@ async function fetchBounded(
|
|
|
84
85
|
url: string,
|
|
85
86
|
init: RequestInit,
|
|
86
87
|
timeoutMs: number | undefined,
|
|
88
|
+
timeoutScope: "request" | "headers" = "request",
|
|
87
89
|
): Promise<Response> {
|
|
90
|
+
const timeout = safeTimeout(timeoutMs);
|
|
91
|
+
const headerDeadline = timeoutScope === "headers" ? clearableDeadline(timeout) : null;
|
|
88
92
|
try {
|
|
89
93
|
const response = await fetchImpl(url, {
|
|
90
94
|
...init,
|
|
91
95
|
redirect: "manual",
|
|
92
|
-
signal: AbortSignal.timeout(
|
|
96
|
+
signal: headerDeadline?.signal ?? AbortSignal.timeout(timeout),
|
|
93
97
|
});
|
|
98
|
+
headerDeadline?.clear();
|
|
94
99
|
if (response.status >= 300 && response.status < 400 && response.status !== 304) {
|
|
95
100
|
throw new HubClientError("redirect_refused", "Hub request redirect was refused", response.status);
|
|
96
101
|
}
|
|
@@ -98,15 +103,24 @@ async function fetchBounded(
|
|
|
98
103
|
} catch (error) {
|
|
99
104
|
if (error instanceof HubClientError) throw error;
|
|
100
105
|
throw new HubClientError("unreachable", "Hub request did not complete", undefined, { cause: error });
|
|
106
|
+
} finally {
|
|
107
|
+
headerDeadline?.clear();
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
|
|
104
|
-
async function boundedText(
|
|
111
|
+
async function boundedText(
|
|
112
|
+
response: Response,
|
|
113
|
+
maxBytes: number,
|
|
114
|
+
options: { inactivityTimeoutMs?: number } = {},
|
|
115
|
+
): Promise<string> {
|
|
105
116
|
const declared = Number(response.headers.get("content-length") ?? "0");
|
|
106
117
|
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
107
118
|
throw new HubClientError("body_too_large", "Hub response exceeded the allowed size", response.status);
|
|
108
119
|
}
|
|
109
|
-
const result = await readBoundedResponseBytes(response, {
|
|
120
|
+
const result = await readBoundedResponseBytes(response, {
|
|
121
|
+
maxBytes,
|
|
122
|
+
...(options.inactivityTimeoutMs === undefined ? {} : { inactivityTimeoutMs: options.inactivityTimeoutMs }),
|
|
123
|
+
});
|
|
110
124
|
if (result.oversized) {
|
|
111
125
|
throw new HubClientError("body_too_large", "Hub response exceeded the allowed size", response.status);
|
|
112
126
|
}
|
|
@@ -422,7 +436,7 @@ export async function downloadClientCatalog(
|
|
|
422
436
|
const response = await fetchBounded(options.fetchImpl ?? fetch, `${origin}/v1/catalog`, {
|
|
423
437
|
method: "GET",
|
|
424
438
|
headers,
|
|
425
|
-
}, options.timeoutMs);
|
|
439
|
+
}, options.timeoutMs, "headers");
|
|
426
440
|
if (response.status === 304) {
|
|
427
441
|
throw new HubClientError("catalog_unexpected_304", "Hub answered 304 to an unconditional catalog request", 304);
|
|
428
442
|
}
|
|
@@ -434,7 +448,17 @@ export async function downloadClientCatalog(
|
|
|
434
448
|
try { await response.body?.cancel(); } catch { /* best effort */ }
|
|
435
449
|
throw new HubClientError("catalog_content_type_invalid", "Hub catalog response was not JSON", response.status);
|
|
436
450
|
}
|
|
437
|
-
|
|
451
|
+
let body: string;
|
|
452
|
+
try {
|
|
453
|
+
body = await boundedText(response, options.maxBytes ?? MAX_REMOTE_CATALOG_BYTES, {
|
|
454
|
+
inactivityTimeoutMs: safeTimeout(options.timeoutMs),
|
|
455
|
+
});
|
|
456
|
+
} catch (error) {
|
|
457
|
+
if (error instanceof DOMException && error.name === "TimeoutError") {
|
|
458
|
+
throw new HubClientError("unreachable", "Hub catalog download stalled", undefined, { cause: error });
|
|
459
|
+
}
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
438
462
|
const parsed = parseJson(body, "catalog_invalid");
|
|
439
463
|
validateRemoteCatalog(parsed);
|
|
440
464
|
const keyId = response.headers.get("x-opencodex-key-id")?.trim() || undefined;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { homedir } from "node:os";
|
|
23
23
|
import { existsSync, readFileSync } from "node:fs";
|
|
24
24
|
import { isAbsolute, join, resolve } from "node:path";
|
|
25
|
-
import { shouldInjectApiAuthHeader } from "../codex/inject";
|
|
25
|
+
import { shouldInjectApiAuthHeader, standaloneCodexRoutingTarget } from "../codex/inject";
|
|
26
26
|
import { FORMAT_MEDIA_TYPE, serializeDocument, type ConfigFormat } from "../integrations/serialize";
|
|
27
27
|
import { providerCodexAccountMode } from "../providers/registry";
|
|
28
28
|
import { canonicalizeReasoningEfforts, sanitizeCodexReasoningEfforts } from "../reasoning-effort";
|
|
@@ -301,7 +301,17 @@ export function ompModelsConfigPath(env: OpencodeLaunchEnv = process.env, home:
|
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
/** Compose the OpenAI-compatible proxy base URL from a live probe result. */
|
|
304
|
-
export function opencodeProxyBaseUrl(
|
|
304
|
+
export function opencodeProxyBaseUrl(
|
|
305
|
+
port: number,
|
|
306
|
+
hostname?: string,
|
|
307
|
+
config?: Pick<OcxConfig, "unauthenticatedLoopbackListener">,
|
|
308
|
+
): string {
|
|
309
|
+
if (config?.unauthenticatedLoopbackListener?.enabled) {
|
|
310
|
+
return standaloneCodexRoutingTarget(port, {
|
|
311
|
+
hostname,
|
|
312
|
+
unauthenticatedLoopbackListener: config.unauthenticatedLoopbackListener,
|
|
313
|
+
}).baseUrl;
|
|
314
|
+
}
|
|
305
315
|
return `http://${probeHostname(hostname)}:${port}/v1`;
|
|
306
316
|
}
|
|
307
317
|
|
|
@@ -162,6 +162,12 @@ export function deriveComboCatalogModel(
|
|
|
162
162
|
contextWindow,
|
|
163
163
|
...members.map(member => member.maxInputTokens ?? member.contextWindow!),
|
|
164
164
|
);
|
|
165
|
+
const knownMaxOutputTokens = members
|
|
166
|
+
.map(member => member.maxOutputTokens)
|
|
167
|
+
.filter((value): value is number => typeof value === "number" && value > 0);
|
|
168
|
+
const maxOutputTokens = knownMaxOutputTokens.length === members.length
|
|
169
|
+
? Math.min(...knownMaxOutputTokens)
|
|
170
|
+
: undefined;
|
|
165
171
|
const autoCompactTokenLimit = Math.min(
|
|
166
172
|
...members.map(member => clampAutoCompactTokenLimit(
|
|
167
173
|
member.contextWindow!,
|
|
@@ -180,6 +186,7 @@ export function deriveComboCatalogModel(
|
|
|
180
186
|
owned_by: COMBO_NAMESPACE,
|
|
181
187
|
contextWindow,
|
|
182
188
|
maxInputTokens,
|
|
189
|
+
...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),
|
|
183
190
|
autoCompactTokenLimit,
|
|
184
191
|
...(hasLimitingContextCapMetadata ? { contextCapped } : {}),
|
|
185
192
|
inputModalities,
|
|
@@ -320,6 +327,7 @@ export function normalizedOpenAiApiSignature(model: CatalogModel): string {
|
|
|
320
327
|
id: model.id,
|
|
321
328
|
contextWindow: model.contextWindow ?? null,
|
|
322
329
|
maxInputTokens: model.maxInputTokens ?? null,
|
|
330
|
+
maxOutputTokens: model.maxOutputTokens ?? null,
|
|
323
331
|
autoCompactTokenLimit: model.autoCompactTokenLimit ?? null,
|
|
324
332
|
inputModalities: [...new Set(model.inputModalities ?? [])].sort(),
|
|
325
333
|
reasoningEfforts: [...new Set(model.reasoningEfforts ?? [])].sort(),
|
|
@@ -271,6 +271,11 @@ export function nativeOpenAiContextWindow(slug: string, limits?: NativeContextLi
|
|
|
271
271
|
return narrowToLimits(raw, slug, limits);
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
+
export function nativeOpenAiMaxOutputTokens(slug: string): number | undefined {
|
|
275
|
+
const sourceSlug = nativeOpenAiCapabilitySourceSlug(slug);
|
|
276
|
+
return positiveInt(getModelMetadata("openai", sourceSlug)?.maxTokens);
|
|
277
|
+
}
|
|
278
|
+
|
|
274
279
|
/**
|
|
275
280
|
* Long-context tier for a native slug as a (default, long) pair, for clients that let the user
|
|
276
281
|
* pick a window per request (Cursor's local-agent "Context" selector). The pair is the family's
|
|
@@ -112,6 +112,8 @@ export interface CatalogModel {
|
|
|
112
112
|
defaultReasoningEffort?: string;
|
|
113
113
|
contextWindow?: number;
|
|
114
114
|
maxInputTokens?: number;
|
|
115
|
+
/** Model-scoped output-token ceiling; omitted when no authoritative value is known. */
|
|
116
|
+
maxOutputTokens?: number;
|
|
115
117
|
/** Soft client compaction threshold; hard context/input limits remain authoritative. */
|
|
116
118
|
autoCompactTokenLimit?: number;
|
|
117
119
|
contextCap?: number;
|