@bitkyc08/opencodex 2.54.0-preview.20260914 → 2.55.0-preview.20260914
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/{index-B4VYfZcY.js → index-DH2PUHqr.js} +10 -10
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic-image-codec.ts +57 -0
- package/src/adapters/anthropic-image-normalize.ts +28 -1
- package/src/adapters/anthropic.ts +68 -6
- package/src/adapters/base.ts +8 -0
- package/src/adapters/coding-agent/protocol.ts +41 -16
- package/src/adapters/cursor/cursor-errors.ts +1 -1
- package/src/adapters/cursor/live-transport.ts +5 -1
- package/src/adapters/cursor/native-exec-fs.ts +10 -10
- package/src/adapters/cursor/native-exec-network.ts +2 -2
- package/src/adapters/cursor/native-exec-shell.ts +13 -12
- package/src/adapters/cursor/native-exec.ts +51 -10
- package/src/adapters/cursor/policy-error.ts +75 -0
- package/src/adapters/cursor/protobuf-request.ts +105 -1
- package/src/adapters/devin/cloud-direct/catalog.ts +34 -2
- package/src/adapters/devin/live-models.ts +33 -2
- package/src/adapters/google-wire-compiler.ts +8 -0
- package/src/adapters/google.ts +46 -0
- package/src/adapters/input-media-guard.ts +45 -0
- package/src/adapters/kiro/adapter.ts +8 -0
- package/src/adapters/kiro/payload.ts +28 -6
- package/src/adapters/kiro-events.ts +25 -6
- package/src/adapters/kiro-images.ts +30 -0
- package/src/adapters/kiro-retry.ts +8 -0
- package/src/adapters/openai-chat.ts +33 -4
- package/src/adapters/openai-responses.ts +26 -0
- package/src/adapters/registry.ts +4 -0
- package/src/bridge.ts +163 -116
- package/src/chat/image-parts.ts +151 -0
- package/src/chat/inbound.ts +70 -33
- package/src/cli/connect.ts +30 -9
- package/src/cli/dispatch.ts +7 -3
- package/src/cli/index.ts +3 -0
- package/src/cli/runtime-api.ts +25 -0
- package/src/cli/status.ts +21 -19
- package/src/cli/system-restart-client.ts +25 -0
- package/src/clients/config-export.ts +14 -4
- package/src/codex/app-server-processes.ts +25 -0
- package/src/codex/auth-context.ts +8 -0
- package/src/codex/autostart-health.ts +36 -2
- package/src/codex/catalog/provider-fetch.ts +41 -0
- package/src/codex/catalog-auto-refresh.ts +182 -0
- package/src/codex/catalog-refresh-status.ts +93 -0
- package/src/codex/history-provider.ts +55 -0
- package/src/codex/model-entitlements.ts +78 -0
- package/src/codex/native-profile-processes.ts +114 -15
- package/src/codex/prompt-text-probe.ts +274 -41
- package/src/codex/routing-adoption.ts +189 -0
- package/src/codex/routing.ts +520 -48
- package/src/codex/runtime.ts +249 -7
- package/src/combos/failover.ts +45 -0
- package/src/config.ts +124 -4
- package/src/generated/compatibility-version.json +110 -74
- package/src/generated/model-metadata.ts +1 -0
- package/src/lib/request-execution-budget.ts +202 -0
- package/src/lib/upstream-retry.ts +95 -8
- package/src/lib/workflow-budget.ts +172 -0
- package/src/oauth/devin.ts +57 -12
- package/src/providers/quota.ts +37 -6
- package/src/providers/registry.ts +53 -6
- package/src/responses/input-media.ts +65 -0
- package/src/responses/parser-content.ts +42 -0
- package/src/responses/schema.ts +12 -2
- package/src/server/audio-live.ts +1 -2
- package/src/server/audio-transcriptions.ts +1 -2
- package/src/server/auth-cors.ts +1 -1
- package/src/server/background-lifecycle.ts +18 -0
- package/src/server/chat-completions.ts +23 -8
- package/src/server/chat-native.ts +17 -17
- package/src/server/index.ts +24 -0
- package/src/server/management/request-history-routes.ts +5 -0
- package/src/server/request-log.ts +8 -2
- package/src/server/responses/compact.ts +51 -3
- package/src/server/responses/core.ts +238 -28
- package/src/server/search.ts +7 -9
- package/src/types/config.ts +51 -6
- package/src/usage/log.ts +37 -0
- package/src/vision/eligibility.ts +37 -4
- package/src/vision/index.ts +1 -0
- package/src/vision/plan.ts +45 -10
- package/src/web-search/alpha-search.ts +324 -0
- package/src/web-search/index.ts +13 -22
- package/src/web-search/passthrough-bridge.ts +195 -22
- package/src/web-search/sidecar-providers.ts +22 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { readProcessStartMsBatch } from "./app-server-processes";
|
|
3
|
+
import type { CodexRoutingKind } from "./inject";
|
|
4
|
+
import { JOURNAL_PATH } from "./journal";
|
|
5
|
+
import {
|
|
6
|
+
listCodexClientProcesses,
|
|
7
|
+
type CodexClientProcessList,
|
|
8
|
+
} from "./native-profile-processes";
|
|
9
|
+
|
|
10
|
+
export type RoutingAdoption = "not-applicable" | "adopted" | "pending-client-restart" | "unknown";
|
|
11
|
+
|
|
12
|
+
export interface RoutingAdoptionEvidence {
|
|
13
|
+
adoption: RoutingAdoption;
|
|
14
|
+
injectedAtMs: number | null;
|
|
15
|
+
staleClients: Array<{ pid: number; startedAtMs: number }>;
|
|
16
|
+
observedClients: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface CollectRoutingAdoptionOptions {
|
|
20
|
+
routingKind: CodexRoutingKind;
|
|
21
|
+
platform?: NodeJS.Platform;
|
|
22
|
+
listClients?: () => CodexClientProcessList;
|
|
23
|
+
readStartMsBatch?: (pids: readonly number[], platform: NodeJS.Platform) => Map<number, number | null>;
|
|
24
|
+
injectedAtMs?: number | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Infer whether running Codex clients had an opportunity to read the
|
|
29
|
+
* injected opencodex-local route (#4550).
|
|
30
|
+
*
|
|
31
|
+
* "adopted" is not an observation of live traffic. It means every matched
|
|
32
|
+
* running Codex client started after the route was written. That is the
|
|
33
|
+
* inference the operator needed, and it is also the overclaim we must not
|
|
34
|
+
* make. Known sources of a false adopted this evidence does not cover:
|
|
35
|
+
* a client the matcher does not recognise; a restored or resumed thread
|
|
36
|
+
* that keeps an already-open direct WebSocket even though the process
|
|
37
|
+
* started after injection; OPENAI_BASE_URL / profile overrides in the
|
|
38
|
+
* client's own environment; a start time in the SAME second as the
|
|
39
|
+
* injection, which we deliberately treat as not stale; an empty match
|
|
40
|
+
* set, which is vacuously adopted; a client running against a different
|
|
41
|
+
* CODEX_HOME or config path than the journal we read; and Codex surfaces
|
|
42
|
+
* the CLI predicate does not match at all, such as codex-code-mode-host,
|
|
43
|
+
* Electron helpers, and VS Code extension hosts. Anything that cannot
|
|
44
|
+
* be verified is "unknown", never a clean bill of health — matching the
|
|
45
|
+
* #476 restart contract where enumeration failure means no verified
|
|
46
|
+
* targets.
|
|
47
|
+
*/
|
|
48
|
+
export function deriveRoutingAdoption(inputs: {
|
|
49
|
+
routingKind: CodexRoutingKind;
|
|
50
|
+
injectedAtMs: number | null;
|
|
51
|
+
clients: ReadonlyArray<{ pid: number; startedAtMs: number | null }>;
|
|
52
|
+
enumerationFailed?: boolean;
|
|
53
|
+
}): RoutingAdoptionEvidence {
|
|
54
|
+
const observedClients = inputs.clients.length;
|
|
55
|
+
if (inputs.routingKind !== "opencodex-local") {
|
|
56
|
+
return { adoption: "not-applicable", injectedAtMs: null, staleClients: [], observedClients: 0 };
|
|
57
|
+
}
|
|
58
|
+
if (inputs.enumerationFailed) {
|
|
59
|
+
return { adoption: "unknown", injectedAtMs: inputs.injectedAtMs, staleClients: [], observedClients };
|
|
60
|
+
}
|
|
61
|
+
if (inputs.injectedAtMs === null) {
|
|
62
|
+
return { adoption: "unknown", injectedAtMs: null, staleClients: [], observedClients };
|
|
63
|
+
}
|
|
64
|
+
const injectedAtMs = inputs.injectedAtMs;
|
|
65
|
+
const staleClients: Array<{ pid: number; startedAtMs: number }> = [];
|
|
66
|
+
let unreadableStart = false;
|
|
67
|
+
for (const client of inputs.clients) {
|
|
68
|
+
if (client.startedAtMs === null) {
|
|
69
|
+
unreadableStart = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (startedBeforeInjection(client.startedAtMs, injectedAtMs)) {
|
|
73
|
+
staleClients.push({ pid: client.pid, startedAtMs: client.startedAtMs });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
staleClients.sort((left, right) => left.pid - right.pid);
|
|
77
|
+
if (staleClients.length > 0) {
|
|
78
|
+
return { adoption: "pending-client-restart", injectedAtMs, staleClients, observedClients };
|
|
79
|
+
}
|
|
80
|
+
if (unreadableStart) {
|
|
81
|
+
return { adoption: "unknown", injectedAtMs, staleClients: [], observedClients };
|
|
82
|
+
}
|
|
83
|
+
return { adoption: "adopted", injectedAtMs, staleClients: [], observedClients };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* ps lstart is second-granularity; app-server-processes.ts uses <= for catalog
|
|
88
|
+
* staleness for the opposite reason (a rewrite in the same second may be unseen).
|
|
89
|
+
* Here a start in the same wall-clock second as the injection cannot be proven
|
|
90
|
+
* to predate it, so a rounding artifact must not produce a false pending-restart
|
|
91
|
+
* warning (#4550). Truncate both sides to seconds; strictly earlier seconds are
|
|
92
|
+
* stale.
|
|
93
|
+
*/
|
|
94
|
+
function startedBeforeInjection(startedAtMs: number, injectedAtMs: number): boolean {
|
|
95
|
+
return Math.floor(startedAtMs / 1000) < Math.floor(injectedAtMs / 1000);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Gather journal + process evidence for deriveRoutingAdoption.
|
|
100
|
+
*
|
|
101
|
+
* Injection time is the newer of the journal timestamp and JOURNAL_PATH mtime:
|
|
102
|
+
* writeJournal records the native snapshot time and then no-ops, while
|
|
103
|
+
* markJournalInjectedState rewrites the file (mtime moves) without touching
|
|
104
|
+
* timestamp. The journal is parsed here instead of through readJournal, which
|
|
105
|
+
* can delete a corrupt file; a status read must never mutate state. Ownership
|
|
106
|
+
* matches journaledInjectedOpenaiBaseUrl plus journalOwner: we only bound a
|
|
107
|
+
* route we recorded writing.
|
|
108
|
+
*/
|
|
109
|
+
export function collectRoutingAdoption(options: CollectRoutingAdoptionOptions): RoutingAdoptionEvidence {
|
|
110
|
+
const { routingKind } = options;
|
|
111
|
+
if (routingKind !== "opencodex-local") {
|
|
112
|
+
return deriveRoutingAdoption({ routingKind, injectedAtMs: null, clients: [] });
|
|
113
|
+
}
|
|
114
|
+
const injectedAtMs = options.injectedAtMs !== undefined
|
|
115
|
+
? options.injectedAtMs
|
|
116
|
+
: readOwnedInjectionBoundMs();
|
|
117
|
+
let listed: CodexClientProcessList;
|
|
118
|
+
try {
|
|
119
|
+
listed = (options.listClients ?? (() => listCodexClientProcesses({ platform: options.platform })))();
|
|
120
|
+
} catch {
|
|
121
|
+
listed = { status: "unavailable" };
|
|
122
|
+
}
|
|
123
|
+
if (listed.status === "unavailable") {
|
|
124
|
+
return deriveRoutingAdoption({
|
|
125
|
+
routingKind,
|
|
126
|
+
injectedAtMs,
|
|
127
|
+
clients: [],
|
|
128
|
+
enumerationFailed: true,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const platform = options.platform ?? process.platform;
|
|
132
|
+
const pids = listed.processes.map(proc => proc.pid);
|
|
133
|
+
let starts: Map<number, number | null>;
|
|
134
|
+
try {
|
|
135
|
+
starts = pids.length === 0
|
|
136
|
+
? new Map()
|
|
137
|
+
: (options.readStartMsBatch ?? readProcessStartMsBatch)(pids, platform);
|
|
138
|
+
} catch {
|
|
139
|
+
starts = new Map(pids.map(pid => [pid, null]));
|
|
140
|
+
}
|
|
141
|
+
const clients = listed.processes.map(proc => ({
|
|
142
|
+
pid: proc.pid,
|
|
143
|
+
startedAtMs: starts.get(proc.pid) ?? null,
|
|
144
|
+
}));
|
|
145
|
+
return deriveRoutingAdoption({ routingKind, injectedAtMs, clients });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function readOwnedInjectionBoundMs(): number | null {
|
|
149
|
+
try {
|
|
150
|
+
if (!existsSync(JOURNAL_PATH)) return null;
|
|
151
|
+
const journal = JSON.parse(readFileSync(JOURNAL_PATH, "utf-8")) as {
|
|
152
|
+
version?: unknown;
|
|
153
|
+
timestamp?: unknown;
|
|
154
|
+
injectedOpenaiBaseUrl?: unknown;
|
|
155
|
+
owner?: { kind?: unknown; pid?: unknown; apiKeyId?: unknown };
|
|
156
|
+
pid?: unknown;
|
|
157
|
+
};
|
|
158
|
+
if (journal === null || typeof journal !== "object" || journal.version !== 1) return null;
|
|
159
|
+
const injectedUrl = typeof journal.injectedOpenaiBaseUrl === "string"
|
|
160
|
+
? journal.injectedOpenaiBaseUrl
|
|
161
|
+
: "";
|
|
162
|
+
if (!injectedUrl) return null;
|
|
163
|
+
if (!journalHasOwner(journal)) return null;
|
|
164
|
+
const recordedMs = typeof journal.timestamp === "string" ? Date.parse(journal.timestamp) : Number.NaN;
|
|
165
|
+
let mtimeMs = Number.NaN;
|
|
166
|
+
try {
|
|
167
|
+
mtimeMs = statSync(JOURNAL_PATH).mtimeMs;
|
|
168
|
+
} catch {
|
|
169
|
+
mtimeMs = Number.NaN;
|
|
170
|
+
}
|
|
171
|
+
const bound = Math.max(
|
|
172
|
+
Number.isFinite(recordedMs) ? recordedMs : Number.NEGATIVE_INFINITY,
|
|
173
|
+
Number.isFinite(mtimeMs) ? mtimeMs : Number.NEGATIVE_INFINITY,
|
|
174
|
+
);
|
|
175
|
+
return Number.isFinite(bound) ? bound : null;
|
|
176
|
+
} catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function journalHasOwner(journal: {
|
|
182
|
+
owner?: { kind?: unknown; pid?: unknown; apiKeyId?: unknown };
|
|
183
|
+
pid?: unknown;
|
|
184
|
+
}): boolean {
|
|
185
|
+
const owner = journal.owner;
|
|
186
|
+
if (owner?.kind === "client" && typeof owner.apiKeyId === "string" && owner.apiKeyId) return true;
|
|
187
|
+
if (owner?.kind === "process" && Number.isSafeInteger(owner.pid) && Number(owner.pid) > 0) return true;
|
|
188
|
+
return Number.isSafeInteger(journal.pid) && Number(journal.pid) > 0;
|
|
189
|
+
}
|