mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 05:20:43 +00:00
* test: add pi codex runtime contract coverage * test: expand pi codex tool runtime contracts * test: tighten tool runtime contracts * test: reset tool contract param cache * test: document codex tool middleware fixture * test: type pi tool contract events * test: satisfy pi tool contract test types * test: cover tool media telemetry contracts * test: reset plugin runtime after tool contracts * test: add auth profile runtime contracts * test: strengthen auth profile runtime contracts * test: clarify auth profile contract fixtures * test: expand auth profile contract matrix * test: assert unrelated cli auth isolation * test: expand auth profile contract matrix * test: tighten auth profile contract expectations * test: add outcome fallback runtime contracts * test: strengthen outcome fallback contracts * test: isolate outcome fallback contracts * test: cover codex terminal outcome signals * test: expand terminal fallback contracts * test: add delivery no reply runtime contracts * test: document json no-reply delivery gap * test: align delivery contract fixtures * test: add transcript repair runtime contracts * test: tighten transcript repair contracts * test: add prompt overlay runtime contracts * test: tighten prompt overlay contract scope * test: type prompt overlay contracts * test: add schema normalization runtime contracts * test: clarify schema normalization contract gaps * test: simplify schema normalization contracts * test: tighten schema normalization contract gaps * test: cover compaction schema contract * test: satisfy schema contract lint * test: add transport params runtime contracts * test: tighten transport params contract scope * test: isolate transport params contracts * test: lock exact transport defaults * feat: add agent runtime plan foundation * fix: preserve codex harness auth profiles * fix: route followup delivery through runtime plan * fix: normalize parameter-free openai tool schemas * fix: satisfy runtime plan type checks * fix: narrow followup delivery runtime planning * fix: apply codex app-server auth profiles * fix: classify codex terminal outcomes * fix: prevent harness auth leakage into unrelated cli providers * feat: expand agent runtime plan policy contract * fix: route pi runtime policy through runtime plan * fix: route codex runtime policy through runtime plan * fix: route fallback outcome classification through runtime plan * refactor: make runtime plan contracts topology-safe * fix: restore runtime plan test type coverage * fix: align runtime plan schema contract assertions * fix: stabilize incomplete turn runtime tests * fix: stabilize codex native web search test * fix: preserve codex auth profile secret refs * fix: keep runtime resolved refs canonical * fix: preserve permissive nested openai schemas * fix: accept Codex auth provider aliases * test: update media-only groups mock * fix: resolve runtime plan rebase checks * fix: resolve runtime plan rebase checks --------- Co-authored-by: Eva <eva@100yen.org> Co-authored-by: Peter Steinberger <steipete@gmail.com>
132 lines
4.3 KiB
TypeScript
132 lines
4.3 KiB
TypeScript
import { resolveOpenClawAgentDir } from "openclaw/plugin-sdk/provider-auth";
|
|
import { applyCodexAppServerAuthProfile, bridgeCodexAppServerStartOptions } from "./auth-bridge.js";
|
|
import { CodexAppServerClient } from "./client.js";
|
|
import {
|
|
codexAppServerStartOptionsKey,
|
|
resolveCodexAppServerRuntimeOptions,
|
|
type CodexAppServerStartOptions,
|
|
} from "./config.js";
|
|
import { withTimeout } from "./timeout.js";
|
|
|
|
type SharedCodexAppServerClientState = {
|
|
client?: CodexAppServerClient;
|
|
promise?: Promise<CodexAppServerClient>;
|
|
key?: string;
|
|
};
|
|
|
|
const SHARED_CODEX_APP_SERVER_CLIENT_STATE = Symbol.for("openclaw.codexAppServerClientState");
|
|
|
|
function getSharedCodexAppServerClientState(): SharedCodexAppServerClientState {
|
|
const globalState = globalThis as typeof globalThis & {
|
|
[SHARED_CODEX_APP_SERVER_CLIENT_STATE]?: SharedCodexAppServerClientState;
|
|
};
|
|
globalState[SHARED_CODEX_APP_SERVER_CLIENT_STATE] ??= {};
|
|
return globalState[SHARED_CODEX_APP_SERVER_CLIENT_STATE];
|
|
}
|
|
|
|
export async function getSharedCodexAppServerClient(options?: {
|
|
startOptions?: CodexAppServerStartOptions;
|
|
timeoutMs?: number;
|
|
authProfileId?: string;
|
|
}): Promise<CodexAppServerClient> {
|
|
const state = getSharedCodexAppServerClientState();
|
|
const startOptions = await bridgeCodexAppServerStartOptions({
|
|
startOptions: options?.startOptions ?? resolveCodexAppServerRuntimeOptions().start,
|
|
agentDir: resolveOpenClawAgentDir(),
|
|
authProfileId: options?.authProfileId,
|
|
});
|
|
const key = codexAppServerStartOptionsKey(startOptions, {
|
|
authProfileId: options?.authProfileId,
|
|
});
|
|
if (state.key && state.key !== key) {
|
|
clearSharedCodexAppServerClient();
|
|
}
|
|
state.key = key;
|
|
const sharedPromise =
|
|
state.promise ??
|
|
(state.promise = (async () => {
|
|
const client = CodexAppServerClient.start(startOptions);
|
|
state.client = client;
|
|
client.addCloseHandler(clearSharedClientIfCurrent);
|
|
try {
|
|
await client.initialize();
|
|
await applyCodexAppServerAuthProfile({
|
|
client,
|
|
agentDir: resolveOpenClawAgentDir(),
|
|
authProfileId: options?.authProfileId,
|
|
});
|
|
return client;
|
|
} catch (error) {
|
|
// Startup failures happen before callers own the shared client, so close
|
|
// the child here instead of leaving a rejected daemon attached to stdio.
|
|
client.close();
|
|
throw error;
|
|
}
|
|
})());
|
|
try {
|
|
return await withTimeout(
|
|
sharedPromise,
|
|
options?.timeoutMs ?? 0,
|
|
"codex app-server initialize timed out",
|
|
);
|
|
} catch (error) {
|
|
if (state.promise === sharedPromise && state.key === key) {
|
|
clearSharedCodexAppServerClient();
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function createIsolatedCodexAppServerClient(options?: {
|
|
startOptions?: CodexAppServerStartOptions;
|
|
timeoutMs?: number;
|
|
authProfileId?: string;
|
|
}): Promise<CodexAppServerClient> {
|
|
const startOptions = await bridgeCodexAppServerStartOptions({
|
|
startOptions: options?.startOptions ?? resolveCodexAppServerRuntimeOptions().start,
|
|
agentDir: resolveOpenClawAgentDir(),
|
|
authProfileId: options?.authProfileId,
|
|
});
|
|
const client = CodexAppServerClient.start(startOptions);
|
|
const initialize = client.initialize();
|
|
try {
|
|
await withTimeout(initialize, options?.timeoutMs ?? 0, "codex app-server initialize timed out");
|
|
await applyCodexAppServerAuthProfile({
|
|
client,
|
|
agentDir: resolveOpenClawAgentDir(),
|
|
authProfileId: options?.authProfileId,
|
|
});
|
|
return client;
|
|
} catch (error) {
|
|
client.close();
|
|
void initialize.catch(() => undefined);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export function resetSharedCodexAppServerClientForTests(): void {
|
|
const state = getSharedCodexAppServerClientState();
|
|
state.client = undefined;
|
|
state.promise = undefined;
|
|
state.key = undefined;
|
|
}
|
|
|
|
export function clearSharedCodexAppServerClient(): void {
|
|
const state = getSharedCodexAppServerClientState();
|
|
const client = state.client;
|
|
state.client = undefined;
|
|
state.promise = undefined;
|
|
state.key = undefined;
|
|
client?.close();
|
|
}
|
|
|
|
function clearSharedClientIfCurrent(client: CodexAppServerClient): void {
|
|
const state = getSharedCodexAppServerClientState();
|
|
if (state.client !== client) {
|
|
return;
|
|
}
|
|
state.client = undefined;
|
|
state.promise = undefined;
|
|
state.key = undefined;
|
|
}
|