@yansigit/opencodex 2.31.3 → 2.33.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 +2 -2
- package/bin/ocx.mjs +99 -70
- package/gui/dist/assets/index-DKLr4LTE.js +102 -0
- package/gui/dist/assets/index-DrSQdTRd.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +6 -5
- package/src/adapters/anthropic.ts +25 -13
- package/src/adapters/azure.ts +20 -4
- package/src/adapters/base.ts +5 -1
- package/src/adapters/command-code.ts +42 -10
- package/src/adapters/cursor/live-models.ts +8 -0
- package/src/adapters/cursor/live-transport.ts +1 -1
- package/src/adapters/cursor/native-exec-desktop.ts +16 -0
- package/src/adapters/cursor/protobuf-events.ts +158 -7
- package/src/adapters/cursor/protobuf-request.ts +33 -15
- package/src/adapters/cursor/request-builder.ts +4 -3
- package/src/adapters/cursor/tool-definitions.ts +27 -1
- package/src/adapters/cursor/types.ts +4 -3
- package/src/adapters/cursor.ts +9 -0
- package/src/adapters/google-antigravity-replay.ts +2 -2
- package/src/adapters/google-antigravity-wire.ts +7 -0
- package/src/adapters/google-errors.ts +6 -2
- package/src/adapters/google-http.ts +30 -7
- package/src/adapters/google-truncation.ts +5 -0
- package/src/adapters/google-wire-compiler.ts +38 -6
- package/src/adapters/google.ts +154 -33
- package/src/adapters/kiro-tools.ts +20 -9
- package/src/adapters/kiro.ts +0 -3
- package/src/adapters/openai-chat.ts +9 -0
- package/src/adapters/openai-responses.ts +4 -1
- package/src/adapters/tool-catalog-nudge.ts +1 -1
- package/src/adapters/xai-web-search.ts +7 -2
- package/src/bridge.ts +133 -24
- package/src/claude/context-windows.ts +16 -9
- package/src/cli/dispatch.ts +50 -2
- package/src/cli/doctor.ts +26 -13
- package/src/cli/help.ts +4 -3
- package/src/cli/index.ts +20 -6
- package/src/cli/models.ts +13 -3
- package/src/cli/observe.ts +20 -5
- package/src/cli/provider.ts +8 -1
- package/src/cli/registry.ts +7 -5
- package/src/cli/status.ts +25 -1
- package/src/cli/system-restart-client.ts +1 -1
- package/src/cli/usage-report.ts +134 -0
- package/src/codex/app-server-processes.ts +3 -1
- package/src/codex/auth-api.ts +4 -2
- package/src/codex/autostart-health.ts +16 -0
- package/src/codex/catalog/aggregation.ts +12 -0
- package/src/codex/catalog/effort.ts +42 -12
- package/src/codex/catalog/metadata.ts +27 -1
- package/src/codex/catalog/model-metadata.ts +593 -0
- package/src/codex/catalog/parsing.ts +71 -27
- package/src/codex/catalog/provider-fetch.ts +189 -33
- package/src/codex/catalog/sync.ts +6 -5
- package/src/codex/convergence.ts +5 -0
- package/src/codex/desktop-app-restart.ts +342 -0
- package/src/codex/history-job.ts +32 -3
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +5 -5
- package/src/codex/history-provider.ts +825 -247
- package/src/codex/history-worker.ts +8 -5
- package/src/codex/inject.ts +49 -21
- package/src/codex/injected-marker.ts +1 -1
- package/src/codex/internal/history-writer.ts +4 -3
- package/src/codex/native-profile-startup.ts +157 -27
- package/src/codex/native-residue.ts +26 -33
- package/src/codex/shim.ts +56 -3
- package/src/combos/failover.ts +27 -0
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +81 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +308 -0
- package/src/config/provider-validation.ts +214 -0
- package/src/config.ts +153 -814
- package/src/generated/compatibility-version.json +232 -148
- package/src/images/loop.ts +37 -6
- package/src/images/plan.ts +5 -4
- package/src/integrations/ownership-policy.ts +141 -0
- package/src/integrations/ownership.ts +10 -0
- package/src/integrations/state.ts +44 -5
- package/src/integrations/writer.ts +6 -0
- package/src/lib/azure-identity.ts +154 -0
- package/src/lib/bounded-body.ts +14 -2
- package/src/lib/debug.ts +42 -0
- package/src/lib/errors.ts +14 -0
- package/src/lib/process-control.ts +2 -1
- package/src/lib/provider-outbound.ts +45 -33
- package/src/lib/provider-tls-profile.ts +309 -0
- package/src/lib/proxy-env.ts +49 -0
- package/src/lib/redact.ts +10 -1
- package/src/lib/state-store-registrations.ts +2 -0
- package/src/lib/tool-argument-integers.ts +56 -5
- package/src/oauth/antigravity-routing.ts +282 -236
- package/src/oauth/callback-server.ts +22 -2
- package/src/oauth/command-code.ts +5 -16
- package/src/oauth/google-antigravity.ts +42 -5
- package/src/oauth/health.ts +1 -1
- package/src/oauth/index.ts +15 -3
- package/src/oauth/kimi.ts +9 -1
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +6 -0
- package/src/providers/antigravity-quota.ts +3 -1
- package/src/providers/api-keys.ts +2 -1
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/derive.ts +4 -0
- package/src/providers/key-failover.ts +5 -1
- package/src/providers/openai-tiers.ts +5 -0
- package/src/providers/provider-id-rewrite.ts +1 -0
- package/src/providers/quota.ts +59 -13
- package/src/providers/registry.ts +4 -2
- package/src/providers/request-pacing.ts +33 -6
- package/src/providers/xai-transport.ts +21 -0
- package/src/reasoning-effort.ts +19 -2
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/custom-tool-compat.ts +132 -38
- package/src/responses/google-provider-options.ts +36 -0
- package/src/responses/namespace-tool-compat.ts +84 -4
- package/src/responses/parser.ts +14 -2
- package/src/responses/provider-opaque-metadata.ts +3 -3
- package/src/responses/reasoning-replay-cache.ts +81 -3
- package/src/responses/schema.ts +37 -0
- package/src/responses/state.ts +94 -4
- package/src/router.ts +8 -2
- package/src/server/auth-cors.ts +37 -7
- package/src/server/images.ts +19 -35
- package/src/server/index.ts +102 -21
- package/src/server/local-management-read-client.ts +1 -1
- package/src/server/local-provider-reload-client.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +206 -16
- package/src/server/management/combo-routes.ts +6 -0
- package/src/server/management/config-routes.ts +35 -6
- package/src/server/management/context.ts +1 -1
- package/src/server/management/logs-usage-routes.ts +27 -6
- package/src/server/management/model-routes.ts +8 -4
- package/src/server/management/model-rows.ts +4 -0
- package/src/server/management/native-integration-routes.ts +2 -1
- package/src/server/management/oauth-account-routes.ts +25 -4
- package/src/server/management/provider-capability-config.ts +1 -1
- package/src/server/management/provider-routes.ts +113 -15
- package/src/server/management/routing-profile-routes.ts +3 -0
- package/src/server/management/system-restart.ts +1 -1
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/proxy-liveness.ts +2 -1
- package/src/server/request-log-conversation.ts +30 -0
- package/src/server/request-log.ts +21 -0
- package/src/server/responses/agent-task-recovery.ts +1 -1
- package/src/server/responses/codex-auth-error.ts +55 -0
- package/src/server/responses/combo-stream-preflight.ts +171 -0
- package/src/server/responses/compact.ts +36 -22
- package/src/server/responses/core.ts +584 -247
- package/src/server/responses/empty-completion-guard.ts +35 -6
- package/src/server/responses/fetch-helpers.ts +20 -102
- package/src/server/responses/v2-native-parent-override.ts +59 -0
- package/src/server/responses/ws-upstream.ts +75 -2
- package/src/server/responses-custom-tool-repair.ts +41 -5
- package/src/server/responses-undeclared-tool-guard.ts +241 -18
- package/src/service.ts +9 -5
- package/src/types/config.ts +16 -1
- package/src/types/provider.ts +16 -0
- package/src/types/request.ts +34 -1
- package/src/types/tools.ts +114 -11
- package/src/types.ts +7 -1
- package/src/update/index.ts +5 -4
- package/src/update/job.ts +3 -1
- package/src/update/transactional-install.mjs +8 -1
- package/src/usage/log.ts +16 -8
- package/src/usage/summary.ts +201 -8
- package/src/vision/describe.ts +18 -13
- package/src/web-search/executor.ts +10 -3
- package/src/web-search/gemini-executor.ts +6 -4
- package/src/web-search/loop.ts +42 -6
- package/gui/dist/assets/index-CGoDO3uO.css +0 -1
- package/gui/dist/assets/index-Cxt5fZMP.js +0 -102
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { isCanonicalOpenAiForwardProvider } from "../providers/openai-tiers";
|
|
2
|
+
import { modelRecordValue } from "../reasoning-effort";
|
|
3
|
+
import {
|
|
4
|
+
isWirePinnedModel,
|
|
5
|
+
MODEL_ADAPTER_OVERRIDE_ALLOWED,
|
|
6
|
+
REASONING_SUMMARY_DELIVERY_VALUES,
|
|
7
|
+
UPSTREAM_HTTP_VERSION_VALUES,
|
|
8
|
+
type OcxProviderConfig,
|
|
9
|
+
} from "../types";
|
|
10
|
+
|
|
11
|
+
const HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
12
|
+
const SENSITIVE_PROVIDER_HEADERS = new Set([
|
|
13
|
+
"authorization",
|
|
14
|
+
"api-key",
|
|
15
|
+
"cookie",
|
|
16
|
+
"set-cookie",
|
|
17
|
+
"proxy-authorization",
|
|
18
|
+
"x-api-key",
|
|
19
|
+
"x-goog-api-key",
|
|
20
|
+
"x-amz-security-token",
|
|
21
|
+
]);
|
|
22
|
+
const REASONING_SUMMARY_DELIVERY_SET = new Set<string>(REASONING_SUMMARY_DELIVERY_VALUES);
|
|
23
|
+
const AZURE_ADAPTERS = new Set(["azure", "azure-openai"]);
|
|
24
|
+
|
|
25
|
+
export function isAzureIdentityProvider(provider: Pick<OcxProviderConfig, "adapter" | "azureCredential">): boolean {
|
|
26
|
+
return AZURE_ADAPTERS.has(provider.adapter) && provider.azureCredential?.type === "default-azure-credential";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Shared semantic boundary for Azure's exact keyless identity mode. */
|
|
30
|
+
export function azureCredentialConfigError(provider: {
|
|
31
|
+
adapter?: unknown;
|
|
32
|
+
azureCredential?: unknown;
|
|
33
|
+
apiKey?: unknown;
|
|
34
|
+
apiKeyPool?: unknown;
|
|
35
|
+
authMode?: unknown;
|
|
36
|
+
}): string | null {
|
|
37
|
+
const credential = provider.azureCredential;
|
|
38
|
+
if (credential === undefined) return null;
|
|
39
|
+
if (!AZURE_ADAPTERS.has(provider.adapter as string)) return "azureCredential is supported only by azure adapters";
|
|
40
|
+
if (!credential || typeof credential !== "object" || Array.isArray(credential)) {
|
|
41
|
+
return "azureCredential must be an object";
|
|
42
|
+
}
|
|
43
|
+
const record = credential as Record<string, unknown>;
|
|
44
|
+
for (const key of Object.keys(record)) {
|
|
45
|
+
if (key !== "type" && key !== "managedIdentityClientId") return "azureCredential has an unrecognized field";
|
|
46
|
+
}
|
|
47
|
+
if (record.type !== "default-azure-credential") return 'azureCredential.type must be "default-azure-credential"';
|
|
48
|
+
if (Object.hasOwn(record, "managedIdentityClientId")
|
|
49
|
+
&& (typeof record.managedIdentityClientId !== "string" || !record.managedIdentityClientId.trim())) {
|
|
50
|
+
return "azureCredential.managedIdentityClientId must be a non-empty string";
|
|
51
|
+
}
|
|
52
|
+
if (Object.hasOwn(provider, "apiKey")) return "azureCredential conflicts with apiKey";
|
|
53
|
+
if (Object.hasOwn(provider, "apiKeyPool")) return "azureCredential conflicts with apiKeyPool";
|
|
54
|
+
if (provider.authMode !== undefined && provider.authMode !== "key") {
|
|
55
|
+
return "azureCredential requires authMode key or omitted";
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Validate a provider destination without coupling DTO callers to config persistence. */
|
|
61
|
+
export function providerBaseUrlConfigError(baseUrl: string): string | null {
|
|
62
|
+
try {
|
|
63
|
+
const parsed = new URL(baseUrl.trim());
|
|
64
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return "baseUrl must be an http(s) URL";
|
|
65
|
+
if (parsed.username || parsed.password) return "baseUrl must not include embedded credentials";
|
|
66
|
+
if (parsed.search || parsed.hash) return "baseUrl must not include query strings or fragments";
|
|
67
|
+
} catch {
|
|
68
|
+
return "baseUrl must be a valid URL";
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Validate user-configured provider headers while keeping auth headers on owned fields. */
|
|
74
|
+
export function providerHeadersConfigError(headers: unknown): string | null {
|
|
75
|
+
if (headers === undefined) return null;
|
|
76
|
+
if (!headers || typeof headers !== "object" || Array.isArray(headers)) return "headers must be an object";
|
|
77
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
78
|
+
const normalized = name.trim().toLowerCase();
|
|
79
|
+
if (!normalized || !HEADER_NAME_PATTERN.test(name)) return "headers must use valid HTTP header names";
|
|
80
|
+
if (SENSITIVE_PROVIDER_HEADERS.has(normalized)) return `headers must not include sensitive header "${name}"; use apiKey/authMode instead`;
|
|
81
|
+
if (typeof value !== "string") return `header "${name}" value must be a string`;
|
|
82
|
+
if (/[\r\n]/.test(value)) return `header "${name}" value must not include line breaks`;
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Keep the configured API-key header style scoped to Anthropic-compatible key auth. */
|
|
88
|
+
export function apiKeyTransportConfigError(
|
|
89
|
+
provider: Pick<OcxProviderConfig, "adapter" | "authMode" | "apiKeyTransport">,
|
|
90
|
+
): string | null {
|
|
91
|
+
if (provider.apiKeyTransport === undefined) return null;
|
|
92
|
+
if (provider.apiKeyTransport !== "x-api-key" && provider.apiKeyTransport !== "bearer") {
|
|
93
|
+
return 'apiKeyTransport must be "x-api-key" or "bearer"';
|
|
94
|
+
}
|
|
95
|
+
if (provider.adapter !== "anthropic") {
|
|
96
|
+
return "apiKeyTransport is supported only by the anthropic adapter";
|
|
97
|
+
}
|
|
98
|
+
if (provider.authMode === "oauth" || provider.authMode === "forward" || provider.authMode === "local") {
|
|
99
|
+
return "apiKeyTransport requires Anthropic API-key authentication";
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Shared strict boundary for the per-provider upstream HTTP-version pin. */
|
|
105
|
+
export function upstreamHttpVersionConfigError(value: unknown): string | null {
|
|
106
|
+
if (value === undefined || value === null) return null;
|
|
107
|
+
if (typeof value !== "string" || !(UPSTREAM_HTTP_VERSION_VALUES as readonly string[]).includes(value)) {
|
|
108
|
+
return 'upstreamHttpVersion must be one of "auto", "http1.1", "h1", "http2", "h2", or null to clear';
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function positiveIntegerRecordConfigError(value: unknown, field: string): string | null {
|
|
114
|
+
if (value === undefined) return null;
|
|
115
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return `${field} must be a plain object`;
|
|
116
|
+
const prototype = Object.getPrototypeOf(value);
|
|
117
|
+
if (prototype !== Object.prototype && prototype !== null) return `${field} must be a plain object with own properties`;
|
|
118
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
119
|
+
if (!key.trim()) return `${field} keys must be nonblank model ids`;
|
|
120
|
+
if (typeof entry !== "number" || !Number.isFinite(entry) || !Number.isInteger(entry) || entry <= 0) {
|
|
121
|
+
return `${field}.${key} must be a positive finite integer`;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function positiveIntegerConfigError(value: unknown, field: string): string | null {
|
|
128
|
+
if (value === undefined) return null;
|
|
129
|
+
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
|
|
130
|
+
return `${field} must be a positive finite integer`;
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function nonBlankStringArrayConfigError(value: unknown, field: string): string | null {
|
|
136
|
+
if (value === undefined) return null;
|
|
137
|
+
if (!Array.isArray(value)) return `${field} must be an array`;
|
|
138
|
+
for (const [index, entry] of value.entries()) {
|
|
139
|
+
if (typeof entry !== "string" || !entry.trim()) {
|
|
140
|
+
return `${field}.${index} must be a nonblank model id`;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Normalize only after validation so whitespace-only entries cannot silently disappear. */
|
|
147
|
+
export function normalizeNonBlankStringArray(value: readonly string[]): string[] {
|
|
148
|
+
return [...new Set(value.map(entry => entry.trim()))];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function booleanRecordConfigError(value: unknown, field: string): string | null {
|
|
152
|
+
if (value === undefined) return null;
|
|
153
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return `${field} must be a plain object`;
|
|
154
|
+
const prototype = Object.getPrototypeOf(value);
|
|
155
|
+
if (prototype !== Object.prototype && prototype !== null) return `${field} must be a plain object with own properties`;
|
|
156
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
157
|
+
if (!key.trim()) return `${field} keys must be nonblank model ids`;
|
|
158
|
+
if (typeof entry !== "boolean") return `${field}.${key} must be a boolean`;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function reasoningSummaryDeliveryRecordConfigError(
|
|
164
|
+
value: unknown,
|
|
165
|
+
supportsReasoningSummaries: unknown,
|
|
166
|
+
field = "modelReasoningSummaryDelivery",
|
|
167
|
+
): string | null {
|
|
168
|
+
if (value === undefined) return null;
|
|
169
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return `${field} must be a plain object`;
|
|
170
|
+
const prototype = Object.getPrototypeOf(value);
|
|
171
|
+
if (prototype !== Object.prototype && prototype !== null) return `${field} must be a plain object with own properties`;
|
|
172
|
+
|
|
173
|
+
const supports = booleanRecordConfigError(supportsReasoningSummaries, "modelSupportsReasoningSummaries") === null
|
|
174
|
+
&& supportsReasoningSummaries && typeof supportsReasoningSummaries === "object"
|
|
175
|
+
? supportsReasoningSummaries as Record<string, boolean>
|
|
176
|
+
: undefined;
|
|
177
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
178
|
+
if (!key.trim()) return `${field} keys must be nonblank model ids`;
|
|
179
|
+
if (typeof entry !== "string" || !REASONING_SUMMARY_DELIVERY_SET.has(entry)) {
|
|
180
|
+
return `${field}.${key} must be one of: ${REASONING_SUMMARY_DELIVERY_VALUES.join(", ")}`;
|
|
181
|
+
}
|
|
182
|
+
if (modelRecordValue(supports, key) === false) {
|
|
183
|
+
return `${field}.${key} conflicts with modelSupportsReasoningSummaries=false`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Validate a provider's per-model wire override map against runtime routing rules. */
|
|
190
|
+
export function modelAdapterRecordConfigError(
|
|
191
|
+
value: unknown,
|
|
192
|
+
field: string,
|
|
193
|
+
providerName: string,
|
|
194
|
+
provider: { adapter?: unknown; authMode?: unknown; baseUrl?: unknown },
|
|
195
|
+
): string | null {
|
|
196
|
+
if (value === undefined) return null;
|
|
197
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return `${field} must be a plain object`;
|
|
198
|
+
const prototype = Object.getPrototypeOf(value);
|
|
199
|
+
if (prototype !== Object.prototype && prototype !== null) return `${field} must be a plain object with own properties`;
|
|
200
|
+
const entries = Object.entries(value);
|
|
201
|
+
if (entries.length > 0 && isCanonicalOpenAiForwardProvider(provider as OcxProviderConfig)) {
|
|
202
|
+
return `${field} is not supported on the canonical ChatGPT forward provider`;
|
|
203
|
+
}
|
|
204
|
+
for (const [key, entry] of entries) {
|
|
205
|
+
if (!key.trim()) return `${field} keys must be nonblank model ids`;
|
|
206
|
+
if (typeof entry !== "string" || !MODEL_ADAPTER_OVERRIDE_ALLOWED.has(entry)) {
|
|
207
|
+
return `${field}.${key} must be one of: ${[...MODEL_ADAPTER_OVERRIDE_ALLOWED].join(", ")}`;
|
|
208
|
+
}
|
|
209
|
+
if (isWirePinnedModel(providerName, key.trim())) {
|
|
210
|
+
return `${field}.${key} cannot be overridden: the upstream only speaks one wire for this model`;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|