@bitkyc08/opencodex 2.90.0 → 2.91.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/gui/dist/assets/App-DMps4OLk.css +1 -0
- package/gui/dist/assets/{App-DgxkE6Md.js → App-nZ34cR5G.js} +18 -18
- package/gui/dist/assets/{Tray-DbTNc_88.js → Tray-BuLy7hL1.js} +1 -1
- package/gui/dist/assets/{index-TmaHa54u.js → index-DGXS51sp.js} +12 -12
- package/gui/dist/assets/{quota-summary-B16x5DZZ.js → quota-summary-DO1Sx5TM.js} +1 -1
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic.ts +2 -5
- package/src/adapters/claude-cli/usage-admission.ts +14 -0
- package/src/adapters/openai-responses/passthrough.ts +2 -1
- package/src/adapters/openai-responses/request-strips.ts +32 -0
- package/src/adapters/openai-responses/transport.ts +6 -0
- package/src/chat/inbound.ts +20 -2
- package/src/chat/outbound.ts +36 -4
- package/src/chat/reasoning-details.ts +137 -0
- package/src/cli/capabilities-agents-routing.ts +50 -0
- package/src/cli/capabilities-base.ts +15 -2
- package/src/cli/capabilities-observe-system.ts +4 -4
- package/src/cli/codex-shim-autorestore.ts +5 -0
- package/src/cli/dispatch.ts +30 -0
- package/src/cli/fallback.ts +127 -0
- package/src/cli/help.ts +1 -0
- package/src/cli/index.ts +1 -2
- package/src/cli/link-apply-restart.ts +72 -0
- package/src/cli/link-child.ts +6 -2
- package/src/cli/link-cleanup.ts +95 -0
- package/src/cli/link-enrollment.ts +4 -0
- package/src/cli/link.ts +84 -9
- package/src/cli/provider.ts +44 -2
- package/src/cli/registry.ts +13 -1
- package/src/cli/restart-failure.ts +4 -0
- package/src/cli/runtime-api.ts +1 -1
- package/src/cli/status-codex-settings.ts +56 -0
- package/src/cli/status-fallback.ts +29 -0
- package/src/cli/status-install.ts +52 -0
- package/src/cli/status.ts +20 -1
- package/src/cli/system-restart-client.ts +32 -1
- package/src/cli/update-restart-child.ts +4 -3
- package/src/cli/update-restart-home.ts +20 -8
- package/src/client/connect.ts +82 -6
- package/src/client/home-unreachable.ts +16 -0
- package/src/client/hub-relay.ts +8 -2
- package/src/client/link-home.ts +119 -6
- package/src/client/link-parity-reporter.ts +107 -0
- package/src/client/link-relay-transport.ts +8 -1
- package/src/client/link-relay.ts +27 -3
- package/src/client/machine-listener.ts +83 -1
- package/src/client/runtime-restart.ts +127 -0
- package/src/client/runtime.ts +137 -25
- package/src/codex/auth-context.ts +10 -6
- package/src/codex/catalog/parsing.ts +4 -0
- package/src/codex/desktop-compatibility/windows-key-protection.ts +18 -6
- package/src/codex/quota-history.ts +7 -0
- package/src/codex/quota.ts +10 -0
- package/src/codex/subagent-model-fallback.ts +24 -1
- package/src/combos/index.ts +1 -0
- package/src/combos/resolve.ts +12 -0
- package/src/config/diagnostics.ts +5 -0
- package/src/config/load-degrade.ts +2 -0
- package/src/config/schema/config-schema.ts +3 -0
- package/src/config/schema/fallback-policy.ts +40 -0
- package/src/generated/compatibility-version.json +205 -97
- package/src/lib/authorization-scheme.ts +95 -0
- package/src/lib/provider-client-headers.ts +1 -0
- package/src/lib/redact.ts +2 -2
- package/src/lib/system-restart-contract.ts +24 -0
- package/src/lib/test-home-guard.ts +78 -11
- package/src/link/child-parity.ts +124 -0
- package/src/link/codex-settings.ts +37 -0
- package/src/link/compatibility.ts +119 -0
- package/src/link/management-routes.ts +2 -0
- package/src/link/peer-report.ts +100 -0
- package/src/link/remote-platform.ts +78 -0
- package/src/link/ssh-argv.ts +19 -0
- package/src/link/status-projection.ts +24 -2
- package/src/oauth/index.ts +1 -1
- package/src/oauth/kimi.ts +2 -0
- package/src/oauth/nous.ts +4 -1
- package/src/oauth/store.ts +2 -1
- package/src/protocols/codecs/chat.ts +3 -3
- package/src/protocols/encoders/adapter-events.ts +26 -2
- package/src/protocols/encoders/chat.ts +55 -3
- package/src/providers/mistral-transport.ts +37 -4
- package/src/providers/quota/antigravity.ts +2 -8
- package/src/quota-pool/assemble.ts +326 -0
- package/src/quota-pool/contract.ts +58 -0
- package/src/quota-pool/identity.ts +203 -0
- package/src/remote/features.ts +74 -0
- package/src/remote/protocol.ts +2 -0
- package/src/remote/served-by.ts +57 -0
- package/src/responses/parser.ts +7 -0
- package/src/responses/reasoning-envelope.ts +12 -0
- package/src/routing/fallback-policy.ts +290 -0
- package/src/routing/fallback-state.ts +179 -0
- package/src/server/audio-client.ts +2 -1
- package/src/server/audio-dictation.ts +2 -1
- package/src/server/audio-upstream.ts +2 -1
- package/src/server/auth-cors.ts +6 -5
- package/src/server/background-lifecycle.ts +4 -0
- package/src/server/chat-completions.ts +8 -1
- package/src/server/gui-session.ts +2 -1
- package/src/server/index/link-listener.ts +11 -1
- package/src/server/index/link-management.ts +47 -0
- package/src/server/index/link-relay-sessions.ts +11 -2
- package/src/server/index/optional-listeners.ts +7 -2
- package/src/server/index/serve-options.ts +19 -2
- package/src/server/live.ts +5 -0
- package/src/server/management/context.ts +1 -1
- package/src/server/management/fallback-routes.ts +75 -0
- package/src/server/management/link-enrollment.ts +21 -3
- package/src/server/management/link-route-state.ts +2 -0
- package/src/server/management/link-routes.ts +12 -1
- package/src/server/management/quota-pool-routes.ts +24 -0
- package/src/server/management/route-registry.ts +3 -0
- package/src/server/management-api.ts +16 -0
- package/src/server/management-auth.ts +2 -1
- package/src/server/responses/agent-task-recovery.ts +1 -1
- package/src/server/responses/compact.ts +2 -2
- package/src/server/responses/core-auth.ts +11 -1
- package/src/server/responses/core-combo.ts +72 -1
- package/src/server/responses/encrypted-payload.ts +3 -3
- package/src/server/responses/main-hard-lock-routing.ts +54 -2
- package/src/server/responses/policy-fallback.ts +44 -1
- package/src/server/responses/request-prepare.ts +9 -1
- package/src/server/restart-replacement.ts +50 -2
- package/src/server/ws-bridge.ts +5 -0
- package/src/service/cli.ts +25 -2
- package/src/service/diagnostics.ts +20 -6
- package/src/service/status-json.ts +116 -0
- package/src/types/config.ts +7 -0
- package/src/types/fallback.ts +38 -0
- package/gui/dist/assets/App-dnkJ85te.css +0 -1
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
isCanonicalOpenAiForwardProvider,
|
|
39
39
|
} from "../providers/openai-tiers";
|
|
40
40
|
import { routeModel, type RouteResult } from "../router";
|
|
41
|
+
import { guardFallbackHop, type FallbackAdmission } from "../routing/fallback-policy";
|
|
41
42
|
import { sweepExpiredOnWrite } from "../lib/state-store-sweeper";
|
|
42
43
|
import { codexAccountNamespaceForModel } from "./account-namespace-match";
|
|
43
44
|
import { ACCOUNT_GATED_NATIVE_OPENAI_MODELS, NATIVE_MAIN_DRAIN_SENTINEL_MODELS } from "./catalog/native-models";
|
|
@@ -629,7 +630,8 @@ export function applySubagentModelFallback(
|
|
|
629
630
|
modelEligibleAccountIdsForModel?: SubagentModelEligibleAccountIds,
|
|
630
631
|
resolvedFallbackChain?: readonly string[] | null,
|
|
631
632
|
restrictedRouteEligible?: SubagentFallbackRouteEligibility,
|
|
632
|
-
|
|
633
|
+
admission?: FallbackAdmission,
|
|
634
|
+
): { from?: string; to?: string; skipped?: string[]; refusal?: Response } | null {
|
|
633
635
|
if (!isThreadSpawnRequest(headers)) return null;
|
|
634
636
|
const fallbackChain = resolvedFallbackChain === undefined
|
|
635
637
|
? resolveSubagentFallbackChain(parsed, config)
|
|
@@ -653,10 +655,31 @@ export function applySubagentModelFallback(
|
|
|
653
655
|
? { from: parsed.modelId, to: parsed.modelId, skipped: selection.skipped }
|
|
654
656
|
: null;
|
|
655
657
|
const from = parsed.modelId;
|
|
658
|
+
// OCX-11: the rewrite is a proactive hop away from an unavailable primary. Refused, the spawn
|
|
659
|
+
// keeps its model and the caller answers with the refusal instead of sending anything.
|
|
660
|
+
const hop = guardFallbackHop(config, {
|
|
661
|
+
site: "subagent",
|
|
662
|
+
route: from,
|
|
663
|
+
from: fallbackTargetOf(config, from),
|
|
664
|
+
to: fallbackTargetOf(config, selection.model),
|
|
665
|
+
trigger: "unavailable",
|
|
666
|
+
admission,
|
|
667
|
+
now,
|
|
668
|
+
});
|
|
669
|
+
if (!hop.ok) return { from, to: from, skipped: selection.skipped, refusal: hop.response };
|
|
670
|
+
// The rewrite is this site's admission: the spawn now carries the fallback model.
|
|
671
|
+
hop.commit();
|
|
656
672
|
rewriteParsedModel(parsed, selection.model);
|
|
657
673
|
return { from, to: selection.model, skipped: selection.skipped };
|
|
658
674
|
}
|
|
659
675
|
|
|
676
|
+
function fallbackTargetOf(config: OcxConfig, model: string): { provider: string; model: string } {
|
|
677
|
+
const route = tryRouteFallbackModel(config, model);
|
|
678
|
+
if (route) return { provider: route.providerName, model: route.modelId };
|
|
679
|
+
const slash = model.indexOf("/");
|
|
680
|
+
return slash > 0 ? { provider: model.slice(0, slash), model: model.slice(slash + 1) } : { provider: "", model };
|
|
681
|
+
}
|
|
682
|
+
|
|
660
683
|
/** Resolve the effective fallback chain once for one logical spawn request. */
|
|
661
684
|
export function resolveSubagentFallbackChain(
|
|
662
685
|
parsed: OcxParsedRequest,
|
package/src/combos/index.ts
CHANGED
package/src/combos/resolve.ts
CHANGED
|
@@ -74,6 +74,18 @@ function targetProviderIsUsable(config: OcxConfig, target: OcxComboTarget, now:
|
|
|
74
74
|
return providerExclusionReason(config, target, now) === undefined;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* OCX-11: the coarse fallback trigger for a target the picker passed over for a reason other
|
|
79
|
+
* than a cooldown (provider missing or disabled, cached quota spent, ineligible for the request).
|
|
80
|
+
*/
|
|
81
|
+
export function comboTargetSkipTrigger(
|
|
82
|
+
config: OcxConfig,
|
|
83
|
+
target: OcxComboTarget,
|
|
84
|
+
now = Date.now(),
|
|
85
|
+
): "quota_exhausted" | "unavailable" {
|
|
86
|
+
return providerExclusionReason(config, target, now) === "quota exhausted" ? "quota_exhausted" : "unavailable";
|
|
87
|
+
}
|
|
88
|
+
|
|
77
89
|
/**
|
|
78
90
|
* Why each target of a combo cannot be picked right now, for a zero-attempt refusal. Only the
|
|
79
91
|
* configured provider/model and a coarse label are named, never account or request data.
|
|
@@ -11,6 +11,7 @@ import { nativeReasoningRetentionConfigError } from "./schema/native-reasoning-r
|
|
|
11
11
|
import { desktopCompatibilityConfigError } from "./schema/desktop-compatibility";
|
|
12
12
|
import { blockedModelRedirectsError } from "./schema/blocked-model-redirects";
|
|
13
13
|
import { mainAccountHardLockFallbackError } from "./schema/main-account-hard-lock-fallback";
|
|
14
|
+
import { fallbackPolicyError } from "./schema/fallback-policy";
|
|
14
15
|
import type { OcxConfig } from "../types";
|
|
15
16
|
import { anthropicAccountPoolConfigError, anthropicOAuthInstanceConfigError, anthropicSidecarConfigError } from "./schema/anthropic-account-pool";
|
|
16
17
|
import { configReasoningPinsConfigError } from "./provider-validation";
|
|
@@ -145,6 +146,7 @@ function validFileConfigDiagnostics(config: OcxConfig, rawParsed: unknown): Conf
|
|
|
145
146
|
if (blockedModelRedirectsError(rawParsed)) warnings.push("blockedModelRedirects ignored: expected a map of nonempty model keys to nonempty string targets");
|
|
146
147
|
if (nativeReasoningRetentionConfigError(rawParsed)) warnings.push("nativeReasoningRetention ignored: expected only optional boolean modelSwitch and accountSwitch fields; both remain off");
|
|
147
148
|
if (mainAccountHardLockFallbackError(rawParsed)) warnings.push("codexMainAccountHardLockFallback ignored: expected a nonblank model selector and an optional declared reasoningEffort");
|
|
149
|
+
if (fallbackPolicyError(rawParsed)) warnings.push("fallback partly ignored: expected boolean model/provider switches, providers/routes/devices maps of them, and devices.<id>.localFallback; ignored leaves keep today's fallback behavior");
|
|
148
150
|
const quotaAutoRefreshWarning = degradedCodexQuotaAutoRefreshWarning(rawParsed, normalized);
|
|
149
151
|
if (quotaAutoRefreshWarning) warnings.push(quotaAutoRefreshWarning);
|
|
150
152
|
if (rawEffort !== undefined && !isClaudeSubagentEffort(rawEffort)) {
|
|
@@ -729,6 +731,9 @@ export function validateConfigCandidate(value: unknown): { ok: true; config: Ocx
|
|
|
729
731
|
const anthropicError = anthropicOAuthInstanceConfigError(value) ?? anthropicAccountPoolConfigError(value) ?? anthropicSidecarConfigError(value);
|
|
730
732
|
if (anthropicError) return { ok: false, error: anthropicError };
|
|
731
733
|
const boundaryError = blockedModelRedirectsError(value)
|
|
734
|
+
// OCX-11: the read schema degrades a malformed fallback leaf to absent, which would silently
|
|
735
|
+
// drop a refusal on the next whole-config save; the write boundary rejects it instead.
|
|
736
|
+
?? fallbackPolicyError(value)
|
|
732
737
|
?? nativeReasoningRetentionConfigError(value)
|
|
733
738
|
?? mainAccountHardLockFallbackError(value)
|
|
734
739
|
?? compactionRecoveryConfigError(value) ?? desktopCompatibilityConfigError(value) ?? configReasoningPinsConfigError(value)
|
|
@@ -7,6 +7,7 @@ import { nativeReasoningRetentionConfigError } from "./schema/native-reasoning-r
|
|
|
7
7
|
import { desktopCompatibilityConfigError } from "./schema/desktop-compatibility";
|
|
8
8
|
import { blockedModelRedirectsError } from "./schema/blocked-model-redirects";
|
|
9
9
|
import { mainAccountHardLockFallbackError } from "./schema/main-account-hard-lock-fallback";
|
|
10
|
+
import { fallbackPolicyError } from "./schema/fallback-policy";
|
|
10
11
|
import { anthropicSidecarConfigError } from "./schema/anthropic-account-pool";
|
|
11
12
|
import {
|
|
12
13
|
modelPinnedEffortsConfigError,
|
|
@@ -142,6 +143,7 @@ export function warnDegradedTopLevelOptIns(rawParsed: unknown, validated: OcxCon
|
|
|
142
143
|
if (desktopCompatibilityConfigError(rawParsed)) console.warn("Invalid desktopCompatibility startup preference ignored; no desktop compatibility service will start automatically.");
|
|
143
144
|
if (blockedModelRedirectsError(rawParsed)) console.warn("⚠️ invalid blockedModelRedirects ignored; provider routing remains available");
|
|
144
145
|
if (mainAccountHardLockFallbackError(rawParsed)) console.warn("⚠️ invalid codexMainAccountHardLockFallback ignored; the main-account hard lock still refuses while blocked");
|
|
146
|
+
if (fallbackPolicyError(rawParsed)) console.warn("⚠️ invalid fallback leaves ignored; those scopes keep today's fallback behavior");
|
|
145
147
|
const chatgptDesktop = chatgptDesktopConfigIssue(rawParsed);
|
|
146
148
|
if (chatgptDesktop) console.warn(`⚠️ config.json ${chatgptDesktop} — the whole chatgptDesktop block is ignored, so the ChatGPT desktop integration reads as off`);
|
|
147
149
|
warnDegradedStreamMode(rawParsed, validated);
|
|
@@ -8,6 +8,7 @@ import { nativeReasoningRetentionSchema } from "./native-reasoning-retention";
|
|
|
8
8
|
import { desktopCompatibilitySchema } from "./desktop-compatibility";
|
|
9
9
|
import { blockedModelRedirectsSchema } from "./blocked-model-redirects";
|
|
10
10
|
import { mainAccountHardLockFallbackSchema } from "./main-account-hard-lock-fallback";
|
|
11
|
+
import { fallbackPolicySchema } from "./fallback-policy";
|
|
11
12
|
import {
|
|
12
13
|
agentTaskRecoverySchema,
|
|
13
14
|
catalogAutoRefreshSchema,
|
|
@@ -241,6 +242,8 @@ export const configSchema = z.object({
|
|
|
241
242
|
// A malformed fallback section disables only the reroute, never the lock's refusal
|
|
242
243
|
// behavior; the management write boundary still rejects the bad value.
|
|
243
244
|
codexMainAccountHardLockFallback: mainAccountHardLockFallbackSchema.optional().catch(undefined),
|
|
245
|
+
// OCX-11: a malformed section reads as absent, which keeps today's fallback behavior.
|
|
246
|
+
fallback: fallbackPolicySchema.optional().catch(undefined),
|
|
244
247
|
// #2999: a malformed hand edit falls back to auto detection rather than rejecting the config.
|
|
245
248
|
nativeMainRefresh: z.enum(["codex", "opencodex"]).optional().catch(undefined),
|
|
246
249
|
// Future versions remain opaque through passthrough-compatible whole-config saves.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read schema of `fallback` (OCX-11). A malformed leaf degrades to absent, which is today's
|
|
5
|
+
* behavior, and config diagnostics name it; the management write boundary rejects it instead.
|
|
6
|
+
* Map keys are checked by the resolver's normalization, so one bad key never drops its siblings.
|
|
7
|
+
*/
|
|
8
|
+
const switchValue = z.boolean().optional().catch(undefined);
|
|
9
|
+
const switchesSchema = z.object({ model: switchValue, provider: switchValue });
|
|
10
|
+
const deviceSchema = switchesSchema.extend({ localFallback: switchValue });
|
|
11
|
+
|
|
12
|
+
export const fallbackPolicySchema = z.object({
|
|
13
|
+
model: switchValue,
|
|
14
|
+
provider: switchValue,
|
|
15
|
+
providers: z.record(z.string(), switchesSchema.catch({})).optional().catch(undefined),
|
|
16
|
+
routes: z.record(z.string(), switchesSchema.catch({})).optional().catch(undefined),
|
|
17
|
+
devices: z.record(z.string(), deviceSchema.catch({})).optional().catch(undefined),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const FALLBACK_DEVICE_ID = /^(?:lnk_[0-9a-f]{16}|[A-Za-z0-9][A-Za-z0-9_.:-]{0,255})$/;
|
|
21
|
+
export const FALLBACK_SELECTOR = /^[^\s]{1,256}$/;
|
|
22
|
+
|
|
23
|
+
const strictSwitches = z.object({ model: z.boolean().optional(), provider: z.boolean().optional() }).strict();
|
|
24
|
+
const strictPolicy = z.object({
|
|
25
|
+
model: z.boolean().optional(),
|
|
26
|
+
provider: z.boolean().optional(),
|
|
27
|
+
providers: z.record(z.string().regex(FALLBACK_SELECTOR), strictSwitches).optional(),
|
|
28
|
+
routes: z.record(z.string().regex(FALLBACK_SELECTOR), strictSwitches).optional(),
|
|
29
|
+
devices: z.record(z.string().regex(FALLBACK_DEVICE_ID), strictSwitches.extend({ localFallback: z.boolean().optional() }).strict()).optional(),
|
|
30
|
+
}).strict();
|
|
31
|
+
|
|
32
|
+
/** Diagnostics text for a section the read schema would partly ignore, or undefined. */
|
|
33
|
+
export function fallbackPolicyError(rawConfig: unknown): string | undefined {
|
|
34
|
+
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) return undefined;
|
|
35
|
+
const raw = (rawConfig as Record<string, unknown>).fallback;
|
|
36
|
+
if (raw === undefined) return undefined;
|
|
37
|
+
return strictPolicy.safeParse(raw).success
|
|
38
|
+
? undefined
|
|
39
|
+
: "schema_invalid: fallback accepts boolean model/provider switches, providers/routes/devices maps of them, and devices.<id>.localFallback";
|
|
40
|
+
}
|