mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 18:04:45 +00:00
fix(codex): inject app-server client factories
Co-authored-by: Benjamin Badejo <ben@benbadejo.com>
This commit is contained in:
@@ -32,6 +32,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Codex app-server: inject native client factories per run and compaction attempt instead of using module-scope test state, avoiding temporal-dead-zone reads during cyclic startup. (#81148) Thanks @bdjben.
|
||||
- Plugin skills: replace generated Windows plugin-skill directories before publishing the current skill link, avoiding repeated `EINVAL` warnings from stale non-symlink entries. Fixes #81432. (#81446) Thanks @hclsys and @vincentkoc.
|
||||
- Channels/config: treat channel entries with only `enabled: true` as configured state so plugin-backed channels can auto-enable from an explicit on switch. Fixes #81323. (#81331) Thanks @EvanYao826 and @vincentkoc.
|
||||
- CLI/update: add an update finalization path for externally swapped core runtimes, running update-time doctor repair and plugin convergence from post-doctor config and install-record state before reporting completion. Thanks @shakkernerd.
|
||||
|
||||
@@ -7,10 +7,36 @@ import {
|
||||
} from "openclaw/plugin-sdk/agent-harness";
|
||||
import { AUTH_PROFILE_RUNTIME_CONTRACT } from "openclaw/plugin-sdk/agent-runtime-test-contracts";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { runCodexAppServerAttempt, __testing } from "./run-attempt.js";
|
||||
import type { CodexAppServerClientFactory } from "./client-factory.js";
|
||||
import { runCodexAppServerAttempt as runCodexAppServerAttemptImpl } from "./run-attempt.js";
|
||||
import { readCodexAppServerBinding, writeCodexAppServerBinding } from "./session-binding.js";
|
||||
import { createCodexTestModel } from "./test-support.js";
|
||||
|
||||
let codexAppServerClientFactoryForTest: CodexAppServerClientFactory | undefined;
|
||||
|
||||
type RunCodexAppServerAttemptOptions = NonNullable<
|
||||
Parameters<typeof runCodexAppServerAttemptImpl>[1]
|
||||
>;
|
||||
|
||||
function setCodexAppServerClientFactoryForTest(factory: CodexAppServerClientFactory): void {
|
||||
codexAppServerClientFactoryForTest = factory;
|
||||
}
|
||||
|
||||
function resetCodexAppServerClientFactoryForTest(): void {
|
||||
codexAppServerClientFactoryForTest = undefined;
|
||||
}
|
||||
|
||||
function runCodexAppServerAttempt(
|
||||
params: EmbeddedRunAttemptParams,
|
||||
options: RunCodexAppServerAttemptOptions = {},
|
||||
) {
|
||||
const clientFactory = options.clientFactory ?? codexAppServerClientFactoryForTest;
|
||||
return runCodexAppServerAttemptImpl(
|
||||
params,
|
||||
clientFactory ? { ...options, clientFactory } : options,
|
||||
);
|
||||
}
|
||||
|
||||
function createParams(sessionFile: string, workspaceDir: string): EmbeddedRunAttemptParams {
|
||||
return {
|
||||
prompt: AUTH_PROFILE_RUNTIME_CONTRACT.workspacePrompt,
|
||||
@@ -85,29 +111,27 @@ function createCodexAuthProfileHarness(params: { startMethod: "thread/start" | "
|
||||
const seenAgentDirs: Array<string | undefined> = [];
|
||||
const requests: Array<{ method: string; params: unknown }> = [];
|
||||
let notify: (notification: unknown) => Promise<void> = async () => undefined;
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
async (_startOptions, authProfileId, agentDir) => {
|
||||
seenAuthProfileIds.push(authProfileId);
|
||||
seenAgentDirs.push(agentDir);
|
||||
return {
|
||||
request: vi.fn(async (method: string, requestParams?: unknown) => {
|
||||
requests.push({ method, params: requestParams });
|
||||
if (method === params.startMethod) {
|
||||
return threadStartResult();
|
||||
}
|
||||
if (method === "turn/start") {
|
||||
return turnStartResult();
|
||||
}
|
||||
throw new Error(`unexpected method: ${method}`);
|
||||
}),
|
||||
addNotificationHandler: (handler: (notification: unknown) => Promise<void>) => {
|
||||
notify = handler;
|
||||
return () => undefined;
|
||||
},
|
||||
addRequestHandler: () => () => undefined,
|
||||
} as never;
|
||||
},
|
||||
);
|
||||
setCodexAppServerClientFactoryForTest(async (_startOptions, authProfileId, agentDir) => {
|
||||
seenAuthProfileIds.push(authProfileId);
|
||||
seenAgentDirs.push(agentDir);
|
||||
return {
|
||||
request: vi.fn(async (method: string, requestParams?: unknown) => {
|
||||
requests.push({ method, params: requestParams });
|
||||
if (method === params.startMethod) {
|
||||
return threadStartResult();
|
||||
}
|
||||
if (method === "turn/start") {
|
||||
return turnStartResult();
|
||||
}
|
||||
throw new Error(`unexpected method: ${method}`);
|
||||
}),
|
||||
addNotificationHandler: (handler: (notification: unknown) => Promise<void>) => {
|
||||
notify = handler;
|
||||
return () => undefined;
|
||||
},
|
||||
addRequestHandler: () => () => undefined,
|
||||
} as never;
|
||||
});
|
||||
return {
|
||||
seenAuthProfileIds,
|
||||
seenAgentDirs,
|
||||
@@ -138,7 +162,7 @@ describe("Auth profile runtime contract - Codex app-server adapter", () => {
|
||||
|
||||
afterEach(async () => {
|
||||
abortAgentHarnessRun(AUTH_PROFILE_RUNTIME_CONTRACT.sessionId);
|
||||
__testing.resetCodexAppServerClientFactoryForTests();
|
||||
resetCodexAppServerClientFactoryForTest();
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
|
||||
@@ -22,16 +22,3 @@ export const defaultCodexAppServerClientFactory: CodexAppServerClientFactory = (
|
||||
import("./shared-client.js").then(({ getSharedCodexAppServerClient }) =>
|
||||
getSharedCodexAppServerClient({ startOptions, authProfileId, agentDir, config }),
|
||||
);
|
||||
|
||||
export function createCodexAppServerClientFactoryTestHooks(
|
||||
setFactory: (factory: CodexAppServerClientFactory) => void,
|
||||
) {
|
||||
return {
|
||||
setCodexAppServerClientFactoryForTests(factory: CodexAppServerClientFactory): void {
|
||||
setFactory(factory);
|
||||
},
|
||||
resetCodexAppServerClientFactoryForTests(): void {
|
||||
setFactory(defaultCodexAppServerClientFactory);
|
||||
},
|
||||
} as const;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,35 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import type { HarnessContextEngine as ContextEngine } from "openclaw/plugin-sdk/agent-harness-runtime";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { CodexAppServerClientFactory } from "./client-factory.js";
|
||||
import type { CodexAppServerClient } from "./client.js";
|
||||
import { maybeCompactCodexAppServerSession, __testing } from "./compact.js";
|
||||
import { maybeCompactCodexAppServerSession as maybeCompactCodexAppServerSessionImpl } from "./compact.js";
|
||||
import type { CodexServerNotification } from "./protocol.js";
|
||||
import { writeCodexAppServerBinding } from "./session-binding.js";
|
||||
|
||||
let tempDir: string;
|
||||
let codexAppServerClientFactoryForTest: CodexAppServerClientFactory | undefined;
|
||||
|
||||
type MaybeCompactOptions = NonNullable<Parameters<typeof maybeCompactCodexAppServerSessionImpl>[1]>;
|
||||
|
||||
function setCodexAppServerClientFactoryForTest(factory: CodexAppServerClientFactory): void {
|
||||
codexAppServerClientFactoryForTest = factory;
|
||||
}
|
||||
|
||||
function resetCodexAppServerClientFactoryForTest(): void {
|
||||
codexAppServerClientFactoryForTest = undefined;
|
||||
}
|
||||
|
||||
function maybeCompactCodexAppServerSession(
|
||||
params: Parameters<typeof maybeCompactCodexAppServerSessionImpl>[0],
|
||||
options: MaybeCompactOptions = {},
|
||||
) {
|
||||
const clientFactory = options.clientFactory ?? codexAppServerClientFactoryForTest;
|
||||
return maybeCompactCodexAppServerSessionImpl(
|
||||
params,
|
||||
clientFactory ? { ...options, clientFactory } : options,
|
||||
);
|
||||
}
|
||||
|
||||
async function writeTestBinding(options: { authProfileId?: string } = {}): Promise<string> {
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
@@ -49,13 +72,13 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
__testing.resetCodexAppServerClientFactoryForTests();
|
||||
resetCodexAppServerClientFactoryForTest();
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("waits for native app-server compaction before reporting success", async () => {
|
||||
const fake = createFakeCodexClient();
|
||||
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
|
||||
setCodexAppServerClientFactoryForTest(async () => fake.client);
|
||||
const sessionFile = await writeTestBinding();
|
||||
|
||||
const pendingResult = startCompaction(sessionFile, { currentTokenCount: 123 });
|
||||
@@ -88,7 +111,7 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
|
||||
it("accepts native context-compaction item completion as success", async () => {
|
||||
const fake = createFakeCodexClient();
|
||||
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
|
||||
setCodexAppServerClientFactoryForTest(async () => fake.client);
|
||||
const sessionFile = await writeTestBinding();
|
||||
|
||||
const pendingResult = startCompaction(sessionFile);
|
||||
@@ -115,7 +138,7 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
it("reuses the bound auth profile for native compaction", async () => {
|
||||
const fake = createFakeCodexClient();
|
||||
let seenAuthProfileId: string | undefined;
|
||||
__testing.setCodexAppServerClientFactoryForTests(async (_startOptions, authProfileId) => {
|
||||
setCodexAppServerClientFactoryForTest(async (_startOptions, authProfileId) => {
|
||||
seenAuthProfileId = authProfileId;
|
||||
return fake.client;
|
||||
});
|
||||
@@ -137,7 +160,7 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
it("fails closed when the persisted binding auth profile disagrees with the runtime request", async () => {
|
||||
const fake = createFakeCodexClient();
|
||||
const factory = vi.fn(async () => fake.client);
|
||||
__testing.setCodexAppServerClientFactoryForTests(factory);
|
||||
setCodexAppServerClientFactoryForTest(factory);
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
await writeCodexAppServerBinding(sessionFile, {
|
||||
threadId: "thread-1",
|
||||
@@ -163,7 +186,7 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
|
||||
it("prefers owning context-engine compaction and records native status separately", async () => {
|
||||
const fake = createFakeCodexClient();
|
||||
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
|
||||
setCodexAppServerClientFactoryForTest(async () => fake.client);
|
||||
const sessionFile = await writeTestBinding();
|
||||
const compact = vi.fn(async (_params: unknown) => ({
|
||||
ok: true,
|
||||
@@ -260,7 +283,7 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
|
||||
it("still runs native compaction when context-engine maintenance fails", async () => {
|
||||
const fake = createFakeCodexClient();
|
||||
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
|
||||
setCodexAppServerClientFactoryForTest(async () => fake.client);
|
||||
const sessionFile = await writeTestBinding();
|
||||
const contextEngine: ContextEngine = {
|
||||
info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
|
||||
@@ -307,7 +330,7 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
|
||||
it("records native compaction status when primary compaction has no result payload", async () => {
|
||||
const fake = createFakeCodexClient();
|
||||
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
|
||||
setCodexAppServerClientFactoryForTest(async () => fake.client);
|
||||
const sessionFile = await writeTestBinding();
|
||||
const contextEngine: ContextEngine = {
|
||||
info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
|
||||
@@ -350,7 +373,7 @@ describe("maybeCompactCodexAppServerSession", () => {
|
||||
|
||||
it("reports context-engine compaction errors without skipping native compaction", async () => {
|
||||
const fake = createFakeCodexClient();
|
||||
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
|
||||
setCodexAppServerClientFactoryForTest(async () => fake.client);
|
||||
const sessionFile = await writeTestBinding();
|
||||
const contextEngine: ContextEngine = {
|
||||
info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
type EmbeddedPiCompactResult,
|
||||
} from "openclaw/plugin-sdk/agent-harness-runtime";
|
||||
import {
|
||||
createCodexAppServerClientFactoryTestHooks,
|
||||
defaultCodexAppServerClientFactory,
|
||||
type CodexAppServerClientFactory,
|
||||
} from "./client-factory.js";
|
||||
import type { CodexAppServerClient, CodexServerNotificationHandler } from "./client.js";
|
||||
import { resolveCodexAppServerRuntimeOptions } from "./config.js";
|
||||
@@ -30,11 +30,9 @@ type ContextEngineCompactResult = Awaited<
|
||||
|
||||
const DEFAULT_CODEX_COMPACTION_WAIT_TIMEOUT_MS = 5 * 60 * 1000;
|
||||
|
||||
let clientFactory = defaultCodexAppServerClientFactory;
|
||||
|
||||
export async function maybeCompactCodexAppServerSession(
|
||||
params: CompactEmbeddedPiSessionParams,
|
||||
options: { pluginConfig?: unknown } = {},
|
||||
options: { pluginConfig?: unknown; clientFactory?: CodexAppServerClientFactory } = {},
|
||||
): Promise<EmbeddedPiCompactResult | undefined> {
|
||||
const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine)
|
||||
? params.contextEngine
|
||||
@@ -107,7 +105,7 @@ export async function maybeCompactCodexAppServerSession(
|
||||
|
||||
async function compactCodexNativeThread(
|
||||
params: CompactEmbeddedPiSessionParams,
|
||||
options: { pluginConfig?: unknown } = {},
|
||||
options: { pluginConfig?: unknown; clientFactory?: CodexAppServerClientFactory } = {},
|
||||
): Promise<EmbeddedPiCompactResult | undefined> {
|
||||
const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig: options.pluginConfig });
|
||||
const binding = await readCodexAppServerBinding(params.sessionFile, { config: params.config });
|
||||
@@ -123,6 +121,7 @@ async function compactCodexNativeThread(
|
||||
return { ok: false, compacted: false, reason: "auth profile mismatch for session binding" };
|
||||
}
|
||||
|
||||
const clientFactory = options.clientFactory ?? defaultCodexAppServerClientFactory;
|
||||
const client = await clientFactory(
|
||||
appServer.start,
|
||||
requestedAuthProfileId ?? binding.authProfileId,
|
||||
@@ -370,7 +369,3 @@ function formatCompactionError(error: unknown): string {
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
|
||||
export const __testing = createCodexAppServerClientFactoryTestHooks((factory) => {
|
||||
clientFactory = factory;
|
||||
});
|
||||
|
||||
@@ -9,12 +9,37 @@ import {
|
||||
type HarnessContextEngine as ContextEngine,
|
||||
} from "openclaw/plugin-sdk/agent-harness-runtime";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { CodexAppServerClientFactory } from "./client-factory.js";
|
||||
import type { CodexServerNotification } from "./protocol.js";
|
||||
import { runCodexAppServerAttempt, __testing } from "./run-attempt.js";
|
||||
import { runCodexAppServerAttempt as runCodexAppServerAttemptImpl } from "./run-attempt.js";
|
||||
import { readCodexAppServerBinding, writeCodexAppServerBinding } from "./session-binding.js";
|
||||
import { createCodexTestModel } from "./test-support.js";
|
||||
|
||||
let tempDir: string;
|
||||
let codexAppServerClientFactoryForTest: CodexAppServerClientFactory | undefined;
|
||||
|
||||
type RunCodexAppServerAttemptOptions = NonNullable<
|
||||
Parameters<typeof runCodexAppServerAttemptImpl>[1]
|
||||
>;
|
||||
|
||||
function setCodexAppServerClientFactoryForTest(factory: CodexAppServerClientFactory): void {
|
||||
codexAppServerClientFactoryForTest = factory;
|
||||
}
|
||||
|
||||
function resetCodexAppServerClientFactoryForTest(): void {
|
||||
codexAppServerClientFactoryForTest = undefined;
|
||||
}
|
||||
|
||||
function runCodexAppServerAttempt(
|
||||
params: EmbeddedRunAttemptParams,
|
||||
options: RunCodexAppServerAttemptOptions = {},
|
||||
) {
|
||||
const clientFactory = options.clientFactory ?? codexAppServerClientFactoryForTest;
|
||||
return runCodexAppServerAttemptImpl(
|
||||
params,
|
||||
clientFactory ? { ...options, clientFactory } : options,
|
||||
);
|
||||
}
|
||||
|
||||
function createParams(sessionFile: string, workspaceDir: string): EmbeddedRunAttemptParams {
|
||||
return {
|
||||
@@ -133,7 +158,7 @@ function createStartedThreadHarness(
|
||||
return {};
|
||||
});
|
||||
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -258,7 +283,7 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
__testing.resetCodexAppServerClientFactoryForTests();
|
||||
resetCodexAppServerClientFactoryForTest();
|
||||
vi.restoreAllMocks();
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@ function queueActiveRunMessageForTest(
|
||||
import { CODEX_GPT5_BEHAVIOR_CONTRACT } from "../../prompt-overlay.js";
|
||||
import { defaultCodexAppInventoryCache } from "./app-inventory-cache.js";
|
||||
import { resolveCodexAppServerEnvApiKeyCacheKey } from "./auth-bridge.js";
|
||||
import type { CodexAppServerClientFactory } from "./client-factory.js";
|
||||
import { readCodexPluginConfig, resolveCodexAppServerRuntimeOptions } from "./config.js";
|
||||
import {
|
||||
CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
|
||||
@@ -39,7 +40,10 @@ import {
|
||||
} from "./plugin-app-cache-key.js";
|
||||
import type { CodexServerNotification } from "./protocol.js";
|
||||
import { rememberCodexRateLimits, resetCodexRateLimitCacheForTests } from "./rate-limit-cache.js";
|
||||
import { runCodexAppServerAttempt, __testing } from "./run-attempt.js";
|
||||
import {
|
||||
runCodexAppServerAttempt as runCodexAppServerAttemptImpl,
|
||||
__testing,
|
||||
} from "./run-attempt.js";
|
||||
import { readCodexAppServerBinding, writeCodexAppServerBinding } from "./session-binding.js";
|
||||
import { createCodexTestModel } from "./test-support.js";
|
||||
import {
|
||||
@@ -50,6 +54,30 @@ import {
|
||||
} from "./thread-lifecycle.js";
|
||||
|
||||
let tempDir: string;
|
||||
let codexAppServerClientFactoryForTest: CodexAppServerClientFactory | undefined;
|
||||
|
||||
type RunCodexAppServerAttemptOptions = NonNullable<
|
||||
Parameters<typeof runCodexAppServerAttemptImpl>[1]
|
||||
>;
|
||||
|
||||
function setCodexAppServerClientFactoryForTest(factory: CodexAppServerClientFactory): void {
|
||||
codexAppServerClientFactoryForTest = factory;
|
||||
}
|
||||
|
||||
function resetCodexAppServerClientFactoryForTest(): void {
|
||||
codexAppServerClientFactoryForTest = undefined;
|
||||
}
|
||||
|
||||
function runCodexAppServerAttempt(
|
||||
params: EmbeddedRunAttemptParams,
|
||||
options: RunCodexAppServerAttemptOptions = {},
|
||||
) {
|
||||
const clientFactory = options.clientFactory ?? codexAppServerClientFactoryForTest;
|
||||
return runCodexAppServerAttemptImpl(
|
||||
params,
|
||||
clientFactory ? { ...options, clientFactory } : options,
|
||||
);
|
||||
}
|
||||
|
||||
function createParams(sessionFile: string, workspaceDir: string): EmbeddedRunAttemptParams {
|
||||
return {
|
||||
@@ -212,22 +240,20 @@ function createAppServerHarness(
|
||||
return requestImpl(method, params);
|
||||
});
|
||||
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
async (_startOptions, authProfileId, agentDir) => {
|
||||
options.onStart?.(authProfileId, agentDir);
|
||||
return {
|
||||
request,
|
||||
addNotificationHandler: (handler: typeof notify) => {
|
||||
notify = handler;
|
||||
return () => undefined;
|
||||
},
|
||||
addRequestHandler: (handler: AppServerRequestHandler) => {
|
||||
handleServerRequest = handler;
|
||||
return () => undefined;
|
||||
},
|
||||
} as never;
|
||||
},
|
||||
);
|
||||
setCodexAppServerClientFactoryForTest(async (_startOptions, authProfileId, agentDir) => {
|
||||
options.onStart?.(authProfileId, agentDir);
|
||||
return {
|
||||
request,
|
||||
addNotificationHandler: (handler: typeof notify) => {
|
||||
notify = handler;
|
||||
return () => undefined;
|
||||
},
|
||||
addRequestHandler: (handler: AppServerRequestHandler) => {
|
||||
handleServerRequest = handler;
|
||||
return () => undefined;
|
||||
},
|
||||
} as never;
|
||||
});
|
||||
|
||||
const waitForServerRequestHandler = async () => {
|
||||
await vi.waitFor(() => expect(handleServerRequest).toBeTypeOf("function"), {
|
||||
@@ -555,7 +581,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
__testing.resetCodexAppServerClientFactoryForTests();
|
||||
resetCodexAppServerClientFactoryForTest();
|
||||
__testing.resetOpenClawCodingToolsFactoryForTests();
|
||||
resetCodexRateLimitCacheForTests();
|
||||
nativeHookRelayTesting.clearNativeHookRelaysForTests();
|
||||
@@ -1333,7 +1359,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -1417,7 +1443,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -1464,7 +1490,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -1542,7 +1568,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -1633,7 +1659,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -1726,7 +1752,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -1904,7 +1930,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -1979,7 +2005,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -2062,7 +2088,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -2153,7 +2179,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -2233,7 +2259,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -2297,7 +2323,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -3590,7 +3616,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -3968,7 +3994,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -4027,7 +4053,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -4208,7 +4234,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -4579,7 +4605,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
});
|
||||
|
||||
it("times out app-server startup before thread setup can hang forever", async () => {
|
||||
__testing.setCodexAppServerClientFactoryForTests(() => new Promise<never>(() => undefined));
|
||||
setCodexAppServerClientFactoryForTest(() => new Promise<never>(() => undefined));
|
||||
const params = createParams(
|
||||
path.join(tempDir, "session.jsonl"),
|
||||
path.join(tempDir, "workspace"),
|
||||
@@ -4636,7 +4662,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
return {};
|
||||
},
|
||||
);
|
||||
__testing.setCodexAppServerClientFactoryForTests(
|
||||
setCodexAppServerClientFactoryForTest(
|
||||
async () =>
|
||||
({
|
||||
request,
|
||||
@@ -5009,7 +5035,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
const requests: string[][] = [];
|
||||
let starts = 0;
|
||||
let notify: (notification: CodexServerNotification) => Promise<void> = async () => undefined;
|
||||
__testing.setCodexAppServerClientFactoryForTests(async () => {
|
||||
setCodexAppServerClientFactoryForTest(async () => {
|
||||
const startIndex = starts++;
|
||||
const methods: string[] = [];
|
||||
requests.push(methods);
|
||||
@@ -5058,7 +5084,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
const requests: string[][] = [];
|
||||
let starts = 0;
|
||||
let notify: (notification: CodexServerNotification) => Promise<void> = async () => undefined;
|
||||
__testing.setCodexAppServerClientFactoryForTests(async () => {
|
||||
setCodexAppServerClientFactoryForTest(async () => {
|
||||
const startIndex = starts++;
|
||||
const methods: string[] = [];
|
||||
requests.push(methods);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { AsyncLocalStorage } from "node:async_hooks";
|
||||
import { createHash } from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
@@ -182,14 +181,8 @@ type CodexSystemPromptReport = NonNullable<EmbeddedRunAttemptResult["systemPromp
|
||||
type CodexToolReportEntry = CodexSystemPromptReport["tools"]["entries"][number];
|
||||
type CodexWorkspaceBootstrapContext = CodexBootstrapContext & { instructions?: string };
|
||||
|
||||
const testClientFactoryStorage = new AsyncLocalStorage<CodexAppServerClientFactory | undefined>();
|
||||
const clientFactory = defaultCodexAppServerClientFactory;
|
||||
let openClawCodingToolsFactoryForTests: OpenClawCodingToolsFactory | undefined;
|
||||
|
||||
function resolveCodexAppServerClientFactory(): CodexAppServerClientFactory {
|
||||
return testClientFactoryStorage.getStore() ?? clientFactory;
|
||||
}
|
||||
|
||||
function emitCodexAppServerEvent(
|
||||
params: EmbeddedRunAttemptParams,
|
||||
event: Parameters<NonNullable<EmbeddedRunAttemptParams["onAgentEvent"]>>[0],
|
||||
@@ -443,10 +436,11 @@ export async function runCodexAppServerAttempt(
|
||||
turnCompletionIdleTimeoutMs?: number;
|
||||
turnAssistantCompletionIdleTimeoutMs?: number;
|
||||
turnTerminalIdleTimeoutMs?: number;
|
||||
clientFactory?: CodexAppServerClientFactory;
|
||||
} = {},
|
||||
): Promise<EmbeddedRunAttemptResult> {
|
||||
const attemptStartedAt = Date.now();
|
||||
const attemptClientFactory = resolveCodexAppServerClientFactory();
|
||||
const attemptClientFactory = options.clientFactory ?? defaultCodexAppServerClientFactory;
|
||||
const pluginConfig = readCodexPluginConfig(options.pluginConfig);
|
||||
const configuredAppServer = resolveCodexAppServerRuntimeOptions({ pluginConfig });
|
||||
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
|
||||
@@ -3264,10 +3258,4 @@ export const __testing = {
|
||||
resetOpenClawCodingToolsFactoryForTests(): void {
|
||||
openClawCodingToolsFactoryForTests = undefined;
|
||||
},
|
||||
setCodexAppServerClientFactoryForTests(factory: CodexAppServerClientFactory): void {
|
||||
testClientFactoryStorage.enterWith(factory);
|
||||
},
|
||||
resetCodexAppServerClientFactoryForTests(): void {
|
||||
testClientFactoryStorage.enterWith(undefined);
|
||||
},
|
||||
} as const;
|
||||
|
||||
Reference in New Issue
Block a user