

























@@ -48,7 +48,7 @@ function threadStartResult() {
4848serviceTier: null,
4949cwd: "/tmp/openclaw-agent",
5050instructionSources: [],
51-approvalPolicy: "never",
51+approvalPolicy: "on-request",
5252approvalsReviewer: "user",
5353sandbox: { type: "dangerFullAccess" },
5454permissionProfile: null,
@@ -74,9 +74,12 @@ function createFakeClient(options?: {
7474inputModalities?: string[];
7575completeWithItems?: boolean;
7676notifyError?: string;
77+approvalRequestMethod?: string;
7778}) {
7879const notifications = new Set<(notification: CodexServerNotification) => void>();
80+const requestHandlers = new Set<(request: { method: string }) => JsonValue | undefined>();
7981const requests: Array<{ method: string; params?: JsonValue }> = [];
82+const approvalResponses: JsonValue[] = [];
8083const request = vi.fn(async (method: string, params?: JsonValue) => {
8184requests.push({ method, params });
8285if (method === "model/list") {
@@ -89,6 +92,14 @@ function createFakeClient(options?: {
8992return threadStartResult();
9093}
9194if (method === "turn/start") {
95+if (options?.approvalRequestMethod) {
96+for (const handler of requestHandlers) {
97+const response = handler({ method: options.approvalRequestMethod });
98+if (response !== undefined) {
99+approvalResponses.push(response);
100+}
101+}
102+}
92103if (options?.notifyError) {
93104for (const notify of notifications) {
94105notify({
@@ -150,9 +161,13 @@ function createFakeClient(options?: {
150161notifications.add(handler);
151162return () => notifications.delete(handler);
152163},
164+addRequestHandler(handler: (request: { method: string }) => JsonValue | undefined) {
165+requestHandlers.add(handler);
166+return () => requestHandlers.delete(handler);
167+},
153168} as unknown as CodexAppServerClient;
154169155-return { client, requests };
170+return { client, requests, approvalResponses };
156171}
157172158173describe("codex media understanding provider", () => {
@@ -183,15 +198,15 @@ describe("codex media understanding provider", () => {
183198expect(requests[1]?.params).toMatchObject({
184199model: "gpt-5.4",
185200modelProvider: "openai",
186-approvalPolicy: "never",
201+approvalPolicy: "on-request",
187202sandbox: "read-only",
188203dynamicTools: [],
189204ephemeral: true,
190205persistExtendedHistory: false,
191206});
192207expect(requests[2]?.params).toMatchObject({
193208threadId: "thread-1",
194-approvalPolicy: "never",
209+approvalPolicy: "on-request",
195210model: "gpt-5.4",
196211input: [
197212{ type: "text", text: "Describe briefly.", text_elements: [] },
@@ -200,6 +215,29 @@ describe("codex media understanding provider", () => {
200215});
201216});
202217218+it("declines approval requests during image understanding", async () => {
219+const { client, approvalResponses } = createFakeClient({
220+approvalRequestMethod: "item/permissions/requestApproval",
221+});
222+const provider = buildCodexMediaUnderstandingProvider({
223+clientFactory: async () => client,
224+});
225+226+await provider.describeImage?.({
227+buffer: Buffer.from("image-bytes"),
228+fileName: "image.png",
229+mime: "image/png",
230+provider: "codex",
231+model: "gpt-5.4",
232+prompt: "Describe briefly.",
233+timeoutMs: 30_000,
234+cfg: {},
235+agentDir: "/tmp/openclaw-agent",
236+});
237+238+expect(approvalResponses).toEqual([{ permissions: {}, scope: "turn" }]);
239+});
240+203241it("extracts text from terminal turn items", async () => {
204242const { client } = createFakeClient({ completeWithItems: true });
205243const provider = buildCodexMediaUnderstandingProvider({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。