style(release): normalize post-freeze Codex paths (#8875)

This commit is contained in:
diegosouzapw
2026-08-23 18:09:06 -03:00
parent 7f59348785
commit 354b583f76
6 changed files with 87 additions and 60 deletions

View File

@@ -1,17 +1,15 @@
import {
bridgeToResponsesSSE,
buildResponseJSON,
} from "../vendor/codex-chatgpt-web/bridge.ts";
import { bridgeToResponsesSSE, buildResponseJSON } from "../vendor/codex-chatgpt-web/bridge.ts";
import { AsyncEventQueue } from "../vendor/codex-chatgpt-web/event-queue.ts";
import type { AdapterEvent } from "../vendor/codex-chatgpt-web/types.ts";
import { sanitizeErrorMessage } from "../utils/error.ts";
import { PROVIDERS } from "../config/constants.ts";
import { BaseExecutor, type ExecuteInput, type ExecutorExecuteResult } from "./base.ts";
import { CodexAppServerClient, type CodexAppServerClientOptions } from "./codex/appServerClient.ts";
import {
CodexAppServerClient,
type CodexAppServerClientOptions,
} from "./codex/appServerClient.ts";
import { resolveAppServerConfig, resolveThreadStartPolicy, type CodexAppServerConfig } from "./codex/appServerConfig.ts";
resolveAppServerConfig,
resolveThreadStartPolicy,
type CodexAppServerConfig,
} from "./codex/appServerConfig.ts";
import {
translateNotification,
translateToolCall,
@@ -283,9 +281,7 @@ export class CodexAppServerExecutor extends BaseExecutor {
// Harness function tools are advertised via thread/start's `dynamicTools`,
// which is an EXPERIMENTAL app-server field: opt into experimental API so
// codex accepts it (and can emit the item/tool/call ServerRequest).
capabilities: hasTools
? { experimentalApi: true, requestAttestation: false }
: null,
capabilities: hasTools ? { experimentalApi: true, requestAttestation: false } : null,
});
const threadResult = (await client.request("thread/start", {
cwd: config.cwd,
@@ -339,7 +335,9 @@ export class CodexAppServerExecutor extends BaseExecutor {
// request (the stateless-full-history contract every OmniRoute provider uses).
client.onToolCall((_id, params, api) => {
if (terminated) return;
const toolParams = (params && typeof params === "object" ? params : {}) as DynamicToolCallLike;
const toolParams = (
params && typeof params === "object" ? params : {}
) as DynamicToolCallLike;
translateToolCall(toolParams, (event) => events.push(event));
// Settle the app-server request so the socket does not stall. The router
// does not have the tool output (the harness will produce it next turn),

View File

@@ -53,8 +53,7 @@ const APPROVAL_REQUEST_METHODS = new Set<string>([
]);
const ROUTER_APPROVAL_NOTE = "router: harness-controlled execution";
const ROUTER_DENIAL_NOTE =
"router: denied by default (set codexAppServerAutoApprove to opt in)";
const ROUTER_DENIAL_NOTE = "router: denied by default (set codexAppServerAutoApprove to opt in)";
export interface CodexAppServerClientOptions {
/** Transport factory. Defaults to the shared wreq-js websocket() when omitted. */
@@ -137,7 +136,11 @@ export class CodexAppServerClient {
}
/** Send a ClientRequest and resolve when its id-matched response arrives. */
request<T = unknown>(method: string, params: unknown, timeoutMs = this.defaultTimeoutMs): Promise<T> {
request<T = unknown>(
method: string,
params: unknown,
timeoutMs = this.defaultTimeoutMs
): Promise<T> {
const id = this.nextId++;
return new Promise<T>((resolve, reject) => {
if (!this.ws || this.closed) {
@@ -216,7 +219,9 @@ export class CodexAppServerClient {
this.pending.delete(id);
if (msg.error) {
const err = msg.error as { code?: unknown; message?: unknown };
pending.reject(new Error(`${String(err.code ?? "error")}: ${String(err.message ?? "unknown")}`));
pending.reject(
new Error(`${String(err.code ?? "error")}: ${String(err.message ?? "unknown")}`)
);
} else {
pending.resolve(msg.result);
}

View File

@@ -156,7 +156,10 @@ export function isLocalAppServerHost(hostname: string): boolean {
* psd-sourced token may go anywhere: whoever wrote the psd already knows it.
*/
export function resolveAppServerConfig(psd: ProviderSpecificData): CodexAppServerConfig | null {
const urlRes = firstStringWithSource(psd?.codexAppServerUrl, process.env.OMNIROUTE_CODEX_APPSERVER_WS);
const urlRes = firstStringWithSource(
psd?.codexAppServerUrl,
process.env.OMNIROUTE_CODEX_APPSERVER_WS
);
if (!urlRes || !isWebSocketUrl(urlRes.value)) return null;
const tokenRes = resolveTokenWithSource(psd);
@@ -174,13 +177,21 @@ export function resolveAppServerConfig(psd: ProviderSpecificData): CodexAppServe
firstString(psd?.codexAppServerCwd, process.env.OMNIROUTE_CODEX_APPSERVER_CWD) ?? "/tmp";
const approvalPolicy =
firstString(psd?.codexAppServerApprovalPolicy, process.env.OMNIROUTE_CODEX_APPSERVER_APPROVAL) ??
undefined;
firstString(
psd?.codexAppServerApprovalPolicy,
process.env.OMNIROUTE_CODEX_APPSERVER_APPROVAL
) ?? undefined;
const sandbox =
firstString(psd?.codexAppServerSandbox, process.env.OMNIROUTE_CODEX_APPSERVER_SANDBOX) ??
undefined;
return { url, token, cwd, ...(approvalPolicy ? { approvalPolicy } : {}), ...(sandbox ? { sandbox } : {}) };
return {
url,
token,
cwd,
...(approvalPolicy ? { approvalPolicy } : {}),
...(sandbox ? { sandbox } : {}),
};
}
/**

View File

@@ -43,7 +43,8 @@ export type CodexAppServerHealth = {
export async function testCodexAppServerConnection(
connection: any
): Promise<CodexAppServerHealth | null> {
const psd = (connection?.providerSpecificData as Record<string, unknown> | undefined) || undefined;
const psd =
(connection?.providerSpecificData as Record<string, unknown> | undefined) || undefined;
// Fire the /readyz probe when EITHER (a) the connection opted into the
// app-server transport via the per-connection flag (a `codex` provider
// connection with codexTransport==="app-server"), OR (b) this is the
@@ -56,9 +57,8 @@ export async function testCodexAppServerConnection(
// Dynamic import (not a static top-level import) so this executor-config module
// stays behind the open-sse boundary the no-restricted-imports lint rule enforces.
const { resolveAppServerConfig } = await import(
"@omniroute/open-sse/executors/codex/appServerConfig.ts"
);
const { resolveAppServerConfig } =
await import("@omniroute/open-sse/executors/codex/appServerConfig.ts");
const config = resolveAppServerConfig(psd);
if (!config) {
// Also reached when the credential/URL binding refused (env token + remote
@@ -75,7 +75,9 @@ export async function testCodexAppServerConnection(
}
// ws://host:port → http://host:port/readyz ; wss:// → https://.
const httpBase = config.url.replace(/^ws(s?):\/\//i, (_m, s) => `http${s}://`).replace(/\/+$/, "");
const httpBase = config.url
.replace(/^ws(s?):\/\//i, (_m, s) => `http${s}://`)
.replace(/\/+$/, "");
const readyzUrl = `${httpBase}/readyz`;
const controller = new AbortController();
@@ -109,7 +111,11 @@ export async function testCodexAppServerConnection(
import("@omniroute/open-sse/executors/codex/appServerAuthProbe.ts"),
import("@omniroute/open-sse/executors/codex.ts"),
]);
authStatus = await probeCodexAppServerAuth(config, getCodexAppServerWebsocketTransport(), 8000);
authStatus = await probeCodexAppServerAuth(
config,
getCodexAppServerWebsocketTransport(),
8000
);
} catch (probeErr: any) {
// If the auth probe itself fails to load/run, don't fail the whole health
// check — the server IS reachable. Treat as unknown-but-reachable (valid).

View File

@@ -89,7 +89,7 @@
"tests/unit/auth-terminal-status.test.ts",
"tests/unit/authz/discovery-routes-local-only.test.ts",
"tests/unit/authz/oauth-autoimport-local-only.test.ts",
"tests/unit/quota-exhaustion-cutoff-opencode.test.ts",
"tests/unit/quota-exhaustion-cutoff-opencode.test.ts",
"tests/unit/authz/route-guard-local-prefix.test.ts",
"tests/unit/authz/route-guard-skills-collect.test.ts",
"tests/unit/authz/route-guard-version-get-exemption.test.ts",

View File

@@ -98,10 +98,7 @@ function makeExecuteInput(overrides: Partial<ExecuteInput> = {}): ExecuteInput {
// ── Gating ──────────────────────────────────────────────────────────────────
test("isCodexAppServerRequired: true only when codexTransport==='app-server' + configured", () => {
assert.equal(
isCodexAppServerRequired({ providerSpecificData: { ...APP_SERVER_PSD } }),
true
);
assert.equal(isCodexAppServerRequired({ providerSpecificData: { ...APP_SERVER_PSD } }), true);
// wrong transport
assert.equal(
isCodexAppServerRequired({
@@ -135,10 +132,7 @@ test("isCodexAppServerRequired: false when OMNIROUTE_CODEX_APP_SERVER_ENABLED=fa
const prev = process.env.OMNIROUTE_CODEX_APP_SERVER_ENABLED;
process.env.OMNIROUTE_CODEX_APP_SERVER_ENABLED = "false";
try {
assert.equal(
isCodexAppServerRequired({ providerSpecificData: { ...APP_SERVER_PSD } }),
false
);
assert.equal(isCodexAppServerRequired({ providerSpecificData: { ...APP_SERVER_PSD } }), false);
} finally {
if (prev === undefined) delete process.env.OMNIROUTE_CODEX_APP_SERVER_ENABLED;
else process.env.OMNIROUTE_CODEX_APP_SERVER_ENABLED = prev;
@@ -146,7 +140,10 @@ test("isCodexAppServerRequired: false when OMNIROUTE_CODEX_APP_SERVER_ENABLED=fa
});
test("resolveAppServerConfig: env fallback + token-file, ws-scheme validation", () => {
assert.equal(resolveAppServerConfig({ codexAppServerUrl: "http://x", codexAppServerToken: "t" }), null);
assert.equal(
resolveAppServerConfig({ codexAppServerUrl: "http://x", codexAppServerToken: "t" }),
null
);
const cfg = resolveAppServerConfig({ ...APP_SERVER_PSD });
assert.deepEqual(cfg, { url: "ws://ts-egress:1456", token: "deadbeef", cwd: "/tmp" });
});
@@ -157,14 +154,8 @@ test("translateNotification: maps deltas, done and error to AdapterEvents", () =
const events: AdapterEvent[] = [];
const push = (e: AdapterEvent) => events.push(e);
assert.equal(
translateNotification("item/agentMessage/delta", { delta: "Hel" }, push),
false
);
assert.equal(
translateNotification("item/reasoning/textDelta", { delta: "think" }, push),
false
);
assert.equal(translateNotification("item/agentMessage/delta", { delta: "Hel" }, push), false);
assert.equal(translateNotification("item/reasoning/textDelta", { delta: "think" }, push), false);
// terminal → returns true
assert.equal(
translateNotification(
@@ -186,10 +177,8 @@ test("translateNotification: maps deltas, done and error to AdapterEvents", () =
test("translateNotification: error notification maps to error event (terminal)", () => {
const events: AdapterEvent[] = [];
const isTerminal = translateNotification(
"error",
{ error: { message: "boom" } },
(e) => events.push(e)
const isTerminal = translateNotification("error", { error: { message: "boom" } }, (e) =>
events.push(e)
);
assert.equal(isTerminal, true);
assert.equal(events[0].type, "error");
@@ -343,7 +332,9 @@ async function runStreamingTurn(): Promise<{
test("CodexAppServerExecutor: streaming turn emits initialize → thread/start → turn/start in order", async () => {
const { sent } = await runStreamingTurn();
const methods = sent.filter((f) => typeof f.method === "string" && f.id != null).map((f) => f.method);
const methods = sent
.filter((f) => typeof f.method === "string" && f.id != null)
.map((f) => f.method);
const lifecycle = methods.filter(
(m) => m === "initialize" || m === "thread/start" || m === "turn/start"
);
@@ -639,7 +630,13 @@ test("CodexAppServerExecutor: async post-turn/start completion does not close th
const result = await Promise.race([
executor.execute(makeExecuteInput({ stream: false })),
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error("execute() hung: socket closed before async completion (BUG#3 regressed)")), 5000)
setTimeout(
() =>
reject(
new Error("execute() hung: socket closed before async completion (BUG#3 regressed)")
),
5000
)
),
]);
const response = "response" in result ? result.response : (result as Response);
@@ -648,7 +645,11 @@ test("CodexAppServerExecutor: async post-turn/start completion does not close th
status?: string;
output?: Array<{ content?: Array<{ text?: string }> }>;
};
assert.equal(body.status, "completed", "the turn completed after the async terminal notification");
assert.equal(
body.status,
"completed",
"the turn completed after the async terminal notification"
);
const text = body.output?.[0]?.content?.[0]?.text ?? "";
assert.equal(text, "ASYNC-OK", "the model output that arrived AFTER turn/start is present");
});
@@ -693,7 +694,10 @@ const AUTH_CONFIG = { url: "ws://ts-egress:1456", token: "deadbeef", cwd: "/tmp"
test("probeCodexAppServerAuth: account with email → authenticated", async () => {
const fn = fakeAuthTransport({
result: { account: { type: "chatgpt", email: "user@example.com", planType: "pro" }, requiresOpenaiAuth: true },
result: {
account: { type: "chatgpt", email: "user@example.com", planType: "pro" },
requiresOpenaiAuth: true,
},
});
const status = await probeCodexAppServerAuth(AUTH_CONFIG, fn, 3000);
assert.equal(status.state, "authenticated");
@@ -710,7 +714,9 @@ test("probeCodexAppServerAuth: no account → logged_out", async () => {
});
test("probeCodexAppServerAuth: auth-error on account/read → logged_out", async () => {
const fn = fakeAuthTransport({ error: { code: -32000, message: "AuthRequiredError: please login" } });
const fn = fakeAuthTransport({
error: { code: -32000, message: "AuthRequiredError: please login" },
});
const status = await probeCodexAppServerAuth(AUTH_CONFIG, fn, 3000);
assert.equal(status.state, "logged_out");
});
@@ -836,9 +842,8 @@ test("resolveAppServerConfig: env URL + env token pairs regardless of host", ()
// ── Health probe: redirect pinning + binding inheritance ────────────────────
test("testCodexAppServerConnection: readyz probe pins redirects (no token leak via 30x)", async () => {
const { testCodexAppServerConnection } = await import(
"../../src/app/api/providers/[id]/test/codexAppServerHealth.ts"
);
const { testCodexAppServerConnection } =
await import("../../src/app/api/providers/[id]/test/codexAppServerHealth.ts");
const originalFetch = globalThis.fetch;
const seen: Array<{ url: string; init?: RequestInit }> = [];
globalThis.fetch = (async (url: unknown, init?: RequestInit) => {
@@ -864,9 +869,8 @@ test("testCodexAppServerConnection: readyz probe pins redirects (no token leak v
});
test("testCodexAppServerConnection: env token + remote psd URL reports unconfigured, no network", async () => {
const { testCodexAppServerConnection } = await import(
"../../src/app/api/providers/[id]/test/codexAppServerHealth.ts"
);
const { testCodexAppServerConnection } =
await import("../../src/app/api/providers/[id]/test/codexAppServerHealth.ts");
const originalFetch = globalThis.fetch;
let fetched = false;
globalThis.fetch = (async () => {
@@ -881,7 +885,10 @@ test("testCodexAppServerConnection: env token + remote psd URL reports unconfigu
});
assert.ok(result);
assert.equal(result!.valid, false);
assert.match(String((result!.diagnosis as { code?: string })?.code), /app_server_unconfigured/);
assert.match(
String((result!.diagnosis as { code?: string })?.code),
/app_server_unconfigured/
);
});
assert.equal(fetched, false, "binding refusal must happen before any network call");
} finally {