




















@@ -31,6 +31,7 @@ import {
3131} from "./live-agent-probes.js";
3232import { restoreLiveEnv, snapshotLiveEnv, type LiveEnvSnapshot } from "./live-env-test-helpers.js";
3333import { renderSolidColorPngBase64 } from "./live-image-probe.js";
34+import type { EventFrame } from "./protocol/index.js";
34353536const LIVE = isLiveTestEnabled();
3637const CODEX_HARNESS_LIVE = isTruthyEnvValue(process.env.OPENCLAW_LIVE_CODEX_HARNESS);
@@ -279,29 +280,31 @@ async function requestAgentText(params: {
279280async function requestCodexCommandText(params: {
280281client: GatewayClient;
281282command: string;
283+events: EventFrame[];
282284expectedText: string | string[];
283285isExpectedText?: (text: string) => boolean;
284286sessionKey: string;
285287}): Promise<string> {
286-const { extractPayloadText } = await import("./test-helpers.agent-results.js");
287-const payload = await params.client.request(
288-"agent",
288+const runId = `idem-${randomUUID()}-codex-command`;
289+const started = await params.client.request(
290+"chat.send",
289291{
290292sessionKey: params.sessionKey,
291-idempotencyKey: `idem-${randomUUID()}-codex-command`,
293+idempotencyKey: runId,
292294message: params.command,
293-deliver: false,
294-thinking: "low",
295-timeout: CODEX_HARNESS_AGENT_TIMEOUT_SECONDS,
296295},
297-{ expectFinal: true, timeoutMs: CODEX_HARNESS_REQUEST_TIMEOUT_MS },
296+{ timeoutMs: CODEX_HARNESS_REQUEST_TIMEOUT_MS },
298297);
299-if (payload?.status !== "ok") {
298+if (started?.status !== "started") {
300299throw new Error(
301-`codex command ${params.command} failed: status=${String(payload?.status)} payload=${JSON.stringify(payload)}`,
300+`codex command ${params.command} did not start correctly: ${JSON.stringify(started)}`,
302301);
303302}
304-const text = extractPayloadText(payload.result);
303+const text = await waitForChatFinalText({
304+events: params.events,
305+ runId,
306+timeoutMs: CODEX_HARNESS_REQUEST_TIMEOUT_MS,
307+});
305308const expectedTexts = Array.isArray(params.expectedText)
306309 ? params.expectedText
307310 : [params.expectedText];
@@ -314,6 +317,54 @@ async function requestCodexCommandText(params: {
314317return text;
315318}
316319320+async function waitForChatFinalText(params: {
321+events: EventFrame[];
322+runId: string;
323+timeoutMs: number;
324+}): Promise<string> {
325+const deadline = Date.now() + params.timeoutMs;
326+while (Date.now() < deadline) {
327+const text = params.events
328+.map((event) => extractChatFinalText(event, params.runId))
329+.find(Boolean);
330+if (text) {
331+return text;
332+}
333+await delay(50);
334+}
335+throw new Error(`timed out waiting for chat final for ${params.runId}`);
336+}
337+338+function extractChatFinalText(event: EventFrame, runId: string): string | undefined {
339+if (event.event !== "chat") {
340+return undefined;
341+}
342+const payload = event.payload;
343+if (!payload || typeof payload !== "object") {
344+return undefined;
345+}
346+const record = payload as Record<string, unknown>;
347+if (record.runId !== runId || record.state !== "final") {
348+return undefined;
349+}
350+const message = record.message;
351+if (!message || typeof message !== "object") {
352+return undefined;
353+}
354+const messageRecord = message as Record<string, unknown>;
355+if (typeof messageRecord.text === "string" && messageRecord.text.trim()) {
356+return messageRecord.text;
357+}
358+const content = Array.isArray(messageRecord.content) ? messageRecord.content : [];
359+return content
360+.map((entry) =>
361+entry && typeof entry === "object" ? (entry as Record<string, unknown>).text : undefined,
362+)
363+.filter((entry): entry is string => typeof entry === "string" && entry.trim().length > 0)
364+.join("\n")
365+.trim();
366+}
367+317368async function verifyCodexImageProbe(params: {
318369client: GatewayClient;
319370sessionKey: string;
@@ -752,6 +803,7 @@ describeLive("gateway live (Codex harness)", () => {
752803const deviceIdentity = await ensurePairedTestGatewayClientIdentity({
753804displayName: "vitest-codex-harness-live",
754805});
806+const gatewayEvents: EventFrame[] = [];
755807logCodexLiveStep("config-written", { configPath, modelKey, port });
756808757809const server = await startGatewayServer(port, {
@@ -766,6 +818,9 @@ describeLive("gateway live (Codex harness)", () => {
766818timeoutMs: GATEWAY_CONNECT_TIMEOUT_MS,
767819requestTimeoutMs: CODEX_HARNESS_REQUEST_TIMEOUT_MS,
768820clientDisplayName: "vitest-codex-harness-live",
821+onEvent: (event) => {
822+gatewayEvents.push(event);
823+},
769824});
770825logCodexLiveStep("client-connected");
771826@@ -811,6 +866,7 @@ describeLive("gateway live (Codex harness)", () => {
811866812867const statusText = await requestCodexCommandText({
813868 client,
869+events: gatewayEvents,
814870 sessionKey,
815871command: "/codex status",
816872expectedText: [...EXPECTED_CODEX_STATUS_COMMAND_TEXT],
@@ -820,6 +876,7 @@ describeLive("gateway live (Codex harness)", () => {
820876821877const modelsText = await requestCodexCommandText({
822878 client,
879+events: gatewayEvents,
823880 sessionKey,
824881command: "/codex models",
825882expectedText: [...EXPECTED_CODEX_MODELS_COMMAND_TEXT],
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。