





















@@ -258,17 +258,21 @@ async function writeLiveGatewayConfig(params: {
258258async function requestAgentTextWithEvents(params: {
259259client: GatewayClient;
260260eventPrefix?: string;
261+eventPrefixes?: string[];
261262includeAllSessions?: boolean;
262263message: string;
263264sessionKey: string;
264265}): Promise<{ text: string; events: CapturedAgentEvent[] }> {
265266const { extractPayloadText } = await import("./test-helpers.agent-results.js");
266267const { onAgentEvent } = await import("../infra/agent-events.js");
267268const events: CapturedAgentEvent[] = [];
268-const eventPrefix = params.eventPrefix ?? "codex_app_server.guardian";
269+const eventPrefixes = params.eventPrefixes ?? [
270+params.eventPrefix ?? "codex_app_server.guardian",
271+"approval",
272+];
269273const unsubscribe = onAgentEvent((event) => {
270274if (
271-!event.stream.startsWith(eventPrefix) ||
275+!eventPrefixes.some((prefix) => event.stream.startsWith(prefix)) ||
272276(!params.includeAllSessions && event.sessionKey && event.sessionKey !== params.sessionKey)
273277) {
274278return;
@@ -643,6 +647,22 @@ function findGuardianReviewStatus(events: CapturedAgentEvent[]): "approved" | "d
643647return status === "approved" || status === "denied" ? status : undefined;
644648}
645649650+function findAppServerApprovalStatus(
651+events: CapturedAgentEvent[],
652+): "approved" | "denied" | undefined {
653+const status = events.findLast(
654+(event) =>
655+event.stream === "approval" &&
656+event.data?.phase === "resolved" &&
657+event.data?.kind === "exec",
658+)?.data?.status;
659+return status === "approved" || status === "denied" ? status : undefined;
660+}
661+662+function hasGuardianReviewEvents(events: CapturedAgentEvent[]): boolean {
663+return events.some((event) => event.stream === "codex_app_server.guardian");
664+}
665+646666function assertGuardianReviewCompleted(params: {
647667events: CapturedAgentEvent[];
648668label: string;
@@ -664,6 +684,27 @@ function assertGuardianReviewCompleted(params: {
664684return completedEvents.at(-1);
665685}
666686687+function assertAppServerApprovalResolved(params: {
688+events: CapturedAgentEvent[];
689+expectedStatus: "approved" | "denied";
690+label: string;
691+}): CapturedAgentEvent {
692+const approvalEvent = params.events.findLast(
693+(event) =>
694+event.stream === "approval" &&
695+event.data?.phase === "resolved" &&
696+event.data?.kind === "exec",
697+);
698+expect(
699+approvalEvent,
700+`${params.label} expected an OpenClaw app-server approval resolution; events=${JSON.stringify(
701+ params.events,
702+ )}`,
703+).toBeDefined();
704+expect(approvalEvent?.data?.status).toBe(params.expectedStatus);
705+return approvalEvent as CapturedAgentEvent;
706+}
707+667708async function verifyCodexGuardianProbe(params: {
668709client: GatewayClient;
669710setPluginApprovalDecision?: (decision: GuardianPluginApprovalDecision | undefined) => void;
@@ -687,6 +728,7 @@ async function verifyCodexGuardianProbe(params: {
687728const allowReview = assertGuardianReviewCompleted({
688729events: allowResult.events,
689730label: "allow probe",
731+requireEvents: false,
690732});
691733const allowStatus = findGuardianReviewStatus(allowResult.events);
692734if (allowStatus === "denied") {
@@ -696,8 +738,21 @@ async function verifyCodexGuardianProbe(params: {
696738expect(allowResult.text.toLowerCase()).toMatch(/approv|permission|guardian|reject|denied/);
697739expect(allowReview?.data?.status).toBe("denied");
698740} else {
741+if (!allowReview) {
742+expect(
743+hasGuardianReviewEvents(allowResult.events),
744+`allow probe emitted Guardian review events without a completed event; events=${JSON.stringify(
745+ allowResult.events,
746+ )}`,
747+).toBe(false);
748+assertAppServerApprovalResolved({
749+events: allowResult.events,
750+expectedStatus: "approved",
751+label: "allow probe",
752+});
753+}
699754expect(allowResult.text).toContain(allowToken);
700-expect(allowStatus ?? "approved").toBe("approved");
755+expect(allowStatus ?? findAppServerApprovalStatus(allowResult.events)).toBe("approved");
701756}
702757703758const askBackToken = `OPENCLAW-GUARDIAN-ASK-BACK-${randomBytes(3).toString("hex").toUpperCase()}`;
@@ -1064,11 +1119,7 @@ describeLive("gateway live (Codex harness)", () => {
10641119}
10651120resolvedGuardianPluginApprovalIds.add(approvalId);
10661121void approvalClient
1067-.request(
1068-"plugin.approval.resolve",
1069-{ id: approvalId, decision },
1070-{ timeoutMs: 30_000 },
1071-)
1122+.request("plugin.approval.resolve", { id: approvalId, decision }, { timeoutMs: 30_000 })
10721123.then(() => {
10731124logCodexLiveStep("guardian-plugin-approval:resolved", { approvalId, decision });
10741125})
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。