@openclaw/codex 2026.7.2-beta.7 → 2026.7.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -27
- package/dist/{command-formatters-C336eRVS.js → .setup/app-server-policy-C_qTMEMy.mjs} +51 -9
- package/dist/{attempt-notifications-AP-a-Q5k.js → .setup/attempt-notifications-F8krwWL4.mjs} +6 -3
- package/dist/{command-handlers-DAHUSry9.js → .setup/command-handlers-DSRFfor4.mjs} +1156 -1319
- package/dist/.setup/command-rpc-BvYsfQ7G.mjs +786 -0
- package/dist/{compact-D_uvHurS.js → .setup/compact-BNgh7I4t.mjs} +10 -40
- package/dist/.setup/computer-use-C3QkmSO3.mjs +377 -0
- package/dist/.setup/config-CYEDnLJ2.mjs +1138 -0
- package/dist/{conversation-binding-data-BHRpYbX3.js → .setup/conversation-binding-data-CrRxtDBu.mjs} +1 -1
- package/dist/{bounded-turn-D2ZAgZVz.js → .setup/media-understanding-provider-EbJCyDqe.mjs} +203 -109
- package/dist/{models-BBMKU4jA.js → .setup/models-C_aZk03A.mjs} +11 -6
- package/dist/.setup/notification-correlation-iYs4WieS.mjs +35 -0
- package/dist/.setup/plugin-app-cache-key-DR8jV9oS.mjs +99 -0
- package/dist/.setup/protocol-2POPqAY4.mjs +13 -0
- package/dist/{transcript-mirror-DzsdNCf5.js → .setup/protocol-validators-dZQ-UTOa.mjs} +112 -922
- package/dist/{rate-limits-CU-gVCCS.js → .setup/provider-DGxDs6g8.mjs} +269 -13
- package/dist/{dynamic-tools-D2gYkSBO.js → .setup/provider-capabilities-DS2N_zc1.mjs} +5632 -3953
- package/dist/.setup/request-DFR0JyoV.mjs +36 -0
- package/dist/.setup/run-attempt-C7xEKFVB.mjs +8180 -0
- package/dist/{sandbox-guard-NuhpXmPB.js → .setup/sandbox-guard-DA2TQfZW.mjs} +1 -14
- package/dist/.setup/session-binding-DuihlMJc.mjs +628 -0
- package/dist/.setup/shared-client-B2KmLPRw.mjs +1854 -0
- package/dist/{side-question-_ulBk1AL.js → .setup/side-question-Cv6JXWCS.mjs} +84 -159
- package/dist/.setup/thread-lifecycle-u6CZdOOH.mjs +2593 -0
- package/dist/{web-search-provider.runtime-CCFhg2z5.js → .setup/web-search-provider.runtime-Ce2zOHxW.mjs} +3 -3
- package/dist/doctor-contract-api.js +122 -88
- package/dist/harness.js +20 -89
- package/dist/index.js +436 -1615
- package/dist/media-understanding-provider.js +1 -173
- package/dist/prompt-overlay.js +15 -0
- package/dist/provider-catalog.js +79 -0
- package/dist/provider-discovery.js +34 -0
- package/dist/provider.js +2 -0
- package/dist/web-search-contract-api.js +1 -1
- package/openclaw.plugin.json +178 -221
- package/package.json +8 -9
- package/dist/app-server-policy-BSaO2JIT.js +0 -49
- package/dist/auth-binding-B4FfbcCg.js +0 -62
- package/dist/capabilities-BFDTVYr4.js +0 -36
- package/dist/cli-metadata.js +0 -20
- package/dist/computer-use-CYEc8U3w.js +0 -693
- package/dist/conversation-control-xsIeXbo4.js +0 -287
- package/dist/effective-mcp-catalog-Bbd98Inw.js +0 -114
- package/dist/event-projector-assistant-message-DTgnPPVF.js +0 -101
- package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/notification-correlation-CU6_AnOb.js +0 -67
- package/dist/plugin-app-cache-key-DztPafOA.js +0 -408
- package/dist/request-qKh331yu.js +0 -157
- package/dist/run-attempt-CY9WlDLc.js +0 -12413
- package/dist/runtime-artifact-CmtG_t1L.js +0 -554
- package/dist/session-binding-BXpo9ymA.js +0 -2214
- package/dist/session-catalog-DyOgR4WH.js +0 -2668
- package/dist/session-cli-2PZaFLRh.js +0 -175
- package/dist/session-upstream-marker-B6U7tLw5.js +0 -82
- package/dist/settled-turn-finalizer-CXY2Z9dT.js +0 -316
- package/dist/shared-client-DTbvH-XV.js +0 -3069
- package/dist/thread-lifecycle-DF53ogiA.js +0 -3987
- package/dist/transport-stdio-DXgGZ7Ib.js +0 -88
- package/dist/upstream-session-fork-Dy4Xvuoj.js +0 -320
- package/dist/usage-CQ6GhD5-.js +0 -25
- /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
- /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
- /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
package/dist/{conversation-binding-data-BHRpYbX3.js → .setup/conversation-binding-data-CrRxtDBu.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
2
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
3
|
import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import process from "node:process";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { r as
|
|
1
|
+
import { CODEX_PROVIDER_ID, FALLBACK_CODEX_MODELS } from "../provider-catalog.js";
|
|
2
|
+
import { r as isJsonObject } from "./protocol-2POPqAY4.mjs";
|
|
3
|
+
import { _ as readCodexNotificationItem } from "./attempt-notifications-F8krwWL4.mjs";
|
|
4
|
+
import { d as resolveCodexAppServerRuntimeOptions } from "./config-CYEDnLJ2.mjs";
|
|
5
|
+
import { i as assertCodexTurnStartResponse, l as readCodexTurnCompletedNotification, o as readCodexErrorNotification, r as assertCodexThreadStartResponse } from "./protocol-validators-dZQ-UTOa.mjs";
|
|
6
|
+
import { i as readModelListResult } from "./models-C_aZk03A.mjs";
|
|
7
|
+
import { H as mergeCodexThreadConfigs, r as buildCodexRuntimeThreadConfig } from "./thread-lifecycle-u6CZdOOH.mjs";
|
|
8
|
+
import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
|
|
8
9
|
import fs from "node:fs/promises";
|
|
9
10
|
import path from "node:path";
|
|
10
11
|
import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
@@ -15,7 +16,7 @@ const CODEX_PRIVATE_STDIO_ARGS = [
|
|
|
15
16
|
"--listen",
|
|
16
17
|
"stdio://"
|
|
17
18
|
];
|
|
18
|
-
const
|
|
19
|
+
const OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR = "OPENCLAW_CODEX_APP_SERVER_ARGS";
|
|
19
20
|
const CODEX_BOUNDED_THREAD_CONFIG = {
|
|
20
21
|
"features.multi_agent": false,
|
|
21
22
|
"features.apps": false,
|
|
@@ -28,22 +29,8 @@ const CODEX_PRIVATE_BOUNDED_THREAD_CONFIG = {
|
|
|
28
29
|
"features.hooks": false,
|
|
29
30
|
notify: []
|
|
30
31
|
};
|
|
31
|
-
const CODEX_SETTLED_FINALIZER_THREAD_CONFIG = {
|
|
32
|
-
"skills.include_instructions": false,
|
|
33
|
-
include_environment_context: false
|
|
34
|
-
};
|
|
35
|
-
var CodexBoundedTurnTimeoutError = class extends Error {
|
|
36
|
-
constructor(taskLabel, timeoutMs) {
|
|
37
|
-
const bound = timeoutMs % 1e3 === 0 ? `${timeoutMs / 1e3}s` : `${timeoutMs}ms`;
|
|
38
|
-
super(`codex app-server ${taskLabel} turn timed out after ${bound}`);
|
|
39
|
-
this.name = "TimeoutError";
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
32
|
async function runBoundedCodexAppServerTurn(params) {
|
|
43
|
-
const appServer = resolveCodexAppServerRuntimeOptions({
|
|
44
|
-
pluginConfig: params.options.pluginConfig,
|
|
45
|
-
managedCommandOrder: params.isolation === "private-stdio" ? "package-first" : void 0
|
|
46
|
-
});
|
|
33
|
+
const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.options.pluginConfig });
|
|
47
34
|
if (params.isolation === "configured-transport") return await runBoundedCodexAppServerTurnInWorkspace(params, appServer, { cwd: params.agentDir?.trim() || process.cwd() });
|
|
48
35
|
if (appServer.start.transport !== "stdio") throw new Error("Bounded Codex turns require stdio transport so native tools can be isolated.");
|
|
49
36
|
return await withTempWorkspace({
|
|
@@ -59,12 +46,8 @@ async function runBoundedCodexAppServerTurn(params) {
|
|
|
59
46
|
});
|
|
60
47
|
});
|
|
61
48
|
}
|
|
62
|
-
async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace
|
|
63
|
-
const
|
|
64
|
-
const timeoutError = new CodexBoundedTurnTimeoutError(params.taskLabel, totalTimeoutMs);
|
|
65
|
-
const deadline = timing?.deadline ?? Date.now() + totalTimeoutMs;
|
|
66
|
-
const timeoutMs = deadline - Date.now();
|
|
67
|
-
if (timeoutMs <= 0) throw timeoutError;
|
|
49
|
+
async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace) {
|
|
50
|
+
const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, 100, 100);
|
|
68
51
|
const agentDir = params.agentDir?.trim() || void 0;
|
|
69
52
|
const startOptions = workspace.codexHome ? buildPrivateCodexAppServerStartOptions(appServer.start, workspace.codexHome) : appServer.start;
|
|
70
53
|
const ownsClient = !params.options.clientFactory;
|
|
@@ -73,41 +56,21 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
|
|
|
73
56
|
authProfileId: params.profile,
|
|
74
57
|
agentDir,
|
|
75
58
|
config: params.config,
|
|
76
|
-
timeoutMs
|
|
77
|
-
|
|
78
|
-
}) : await import("./shared-client-DTbvH-XV.js").then((n) => n.m).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
|
|
59
|
+
timeoutMs
|
|
60
|
+
}) : await import("./shared-client-B2KmLPRw.mjs").then((n) => n.c).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
|
|
79
61
|
startOptions,
|
|
80
62
|
timeoutMs,
|
|
81
63
|
authProfileId: params.profile,
|
|
82
64
|
agentDir,
|
|
83
65
|
authProfileStore: params.authProfileStore,
|
|
84
|
-
config: params.config
|
|
85
|
-
...params.signal ? { abandonSignal: params.signal } : {}
|
|
66
|
+
config: params.config
|
|
86
67
|
}));
|
|
87
68
|
const abortController = new AbortController();
|
|
88
|
-
|
|
89
|
-
let activeTurnId = "";
|
|
90
|
-
let interruptPromise;
|
|
91
|
-
const requestInterrupt = () => {
|
|
92
|
-
if (!activeThreadId || interruptPromise) return;
|
|
93
|
-
interruptPromise = interruptCodexTurnAndWaitBestEffort(client, {
|
|
94
|
-
threadId: activeThreadId,
|
|
95
|
-
turnId: activeTurnId,
|
|
96
|
-
timeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS
|
|
97
|
-
});
|
|
98
|
-
};
|
|
99
|
-
const abortRun = (reason) => {
|
|
100
|
-
abortController.abort(reason);
|
|
101
|
-
requestInterrupt();
|
|
102
|
-
};
|
|
103
|
-
const abortFromCaller = () => abortRun(params.signal?.reason ?? "aborted");
|
|
69
|
+
const abortFromCaller = () => abortController.abort(params.signal?.reason ?? "aborted");
|
|
104
70
|
if (params.signal?.aborted) abortFromCaller();
|
|
105
71
|
else params.signal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
106
|
-
const
|
|
107
|
-
if (remainingRunMs <= 0) abortRun(timeoutError);
|
|
108
|
-
const timeout = setTimeout(() => abortRun(timeoutError), Math.max(1, remainingRunMs));
|
|
72
|
+
const timeout = setTimeout(() => abortController.abort("timeout"), timeoutMs);
|
|
109
73
|
timeout.unref?.();
|
|
110
|
-
let retrySelection = false;
|
|
111
74
|
try {
|
|
112
75
|
const model = await resolveCodexBoundedTurnModel({
|
|
113
76
|
client,
|
|
@@ -116,8 +79,6 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
|
|
|
116
79
|
timeoutMs,
|
|
117
80
|
signal: abortController.signal
|
|
118
81
|
});
|
|
119
|
-
const inheritedMcpServerNames = params.requireNoExternalCapabilities ? await readCodexInheritedMcpServerNames(client, workspace.cwd, abortController.signal) : [];
|
|
120
|
-
if (params.requireNoExternalCapabilities) await assertCodexRingZeroHasNoManagedHooks(client, abortController.signal);
|
|
121
82
|
const thread = assertCodexThreadStartResponse(await client.request("thread/start", {
|
|
122
83
|
model,
|
|
123
84
|
modelProvider: "openai",
|
|
@@ -125,9 +86,8 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
|
|
|
125
86
|
approvalPolicy: "on-request",
|
|
126
87
|
sandbox: "read-only",
|
|
127
88
|
serviceName: "OpenClaw",
|
|
128
|
-
...params.requireNoExternalCapabilities ? { baseInstructions: "" } : {},
|
|
129
89
|
developerInstructions: params.developerInstructions,
|
|
130
|
-
config: buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace
|
|
90
|
+
config: buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace), { nativeCodeModeEnabled: false }),
|
|
131
91
|
environments: [],
|
|
132
92
|
dynamicTools: [],
|
|
133
93
|
experimentalRawEvents: true,
|
|
@@ -136,16 +96,6 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
|
|
|
136
96
|
timeoutMs,
|
|
137
97
|
signal: abortController.signal
|
|
138
98
|
}));
|
|
139
|
-
activeThreadId = thread.thread.id;
|
|
140
|
-
if (abortController.signal.aborted) requestInterrupt();
|
|
141
|
-
if (params.requireNoExternalCapabilities) await attestCodexRingZeroThreadHasNoMcpServers(client, thread.thread.id, abortController.signal);
|
|
142
|
-
if (params.historyItems?.length) await client.request("thread/inject_items", {
|
|
143
|
-
threadId: thread.thread.id,
|
|
144
|
-
items: params.historyItems
|
|
145
|
-
}, {
|
|
146
|
-
timeoutMs,
|
|
147
|
-
signal: abortController.signal
|
|
148
|
-
});
|
|
149
99
|
const collector = createCodexBoundedTurnCollector(thread.thread.id, params.taskLabel);
|
|
150
100
|
const cleanup = client.addNotificationHandler(collector.handleNotification);
|
|
151
101
|
const requestCleanup = client.addRequestHandler(createCodexBoundedApprovalHandler(params.taskLabel));
|
|
@@ -161,12 +111,10 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
|
|
|
161
111
|
timeoutMs,
|
|
162
112
|
signal: abortController.signal
|
|
163
113
|
}));
|
|
164
|
-
activeTurnId = turn.turn.id;
|
|
165
|
-
if (abortController.signal.aborted) requestInterrupt();
|
|
166
114
|
return {
|
|
167
115
|
...await collector.collect(turn.turn, {
|
|
168
|
-
|
|
169
|
-
|
|
116
|
+
timeoutMs,
|
|
117
|
+
signal: abortController.signal
|
|
170
118
|
}),
|
|
171
119
|
model
|
|
172
120
|
};
|
|
@@ -174,33 +122,21 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
|
|
|
174
122
|
requestCleanup();
|
|
175
123
|
cleanup();
|
|
176
124
|
}
|
|
177
|
-
} catch (error) {
|
|
178
|
-
if (abortController.signal.aborted) throw resolveCodexBoundedTurnAbortError(abortController.signal, params.taskLabel, timeoutError);
|
|
179
|
-
if (ownsClient && isCodexAppServerStartSelectionChangedError(error) && selectionAttempt === 0) retrySelection = true;
|
|
180
|
-
else throw error;
|
|
181
125
|
} finally {
|
|
182
126
|
clearTimeout(timeout);
|
|
183
127
|
params.signal?.removeEventListener("abort", abortFromCaller);
|
|
184
|
-
await interruptPromise;
|
|
185
128
|
if (ownsClient) client.close();
|
|
186
129
|
}
|
|
187
|
-
if (retrySelection) return await runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace, selectionAttempt + 1, {
|
|
188
|
-
deadline,
|
|
189
|
-
timeoutMs: totalTimeoutMs
|
|
190
|
-
});
|
|
191
|
-
throw new Error("Codex bounded turn selection retry exited unexpectedly");
|
|
192
130
|
}
|
|
193
|
-
function resolveBoundedThreadConfig(params, workspace
|
|
131
|
+
function resolveBoundedThreadConfig(params, workspace) {
|
|
194
132
|
const boundedConfig = mergeCodexThreadConfigs(CODEX_BOUNDED_THREAD_CONFIG, params.threadConfig) ?? CODEX_BOUNDED_THREAD_CONFIG;
|
|
195
|
-
|
|
196
|
-
if (!params.requireNoExternalCapabilities) return privateConfig;
|
|
197
|
-
return mergeCodexThreadConfigs(privateConfig, CODEX_SETTLED_FINALIZER_THREAD_CONFIG, buildCodexRingZeroThreadConfigPatch({ toolsAllow: ["openclaw"] }, true, inheritedMcpServerNames)) ?? privateConfig;
|
|
133
|
+
return workspace.codexHome ? mergeCodexThreadConfigs(boundedConfig, CODEX_PRIVATE_BOUNDED_THREAD_CONFIG) ?? boundedConfig : boundedConfig;
|
|
198
134
|
}
|
|
199
135
|
function buildPrivateCodexAppServerStartOptions(start, codexHome) {
|
|
200
|
-
const privateEnv = Object.fromEntries(Object.entries(start.env ?? {}).filter(([name]) => name.trim().toUpperCase() !==
|
|
136
|
+
const privateEnv = Object.fromEntries(Object.entries(start.env ?? {}).filter(([name]) => name.trim().toUpperCase() !== OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR));
|
|
201
137
|
const clearEnv = (start.clearEnv ?? []).filter((name) => {
|
|
202
138
|
const normalized = name.trim().toUpperCase();
|
|
203
|
-
return normalized !== "CODEX_HOME" && normalized !==
|
|
139
|
+
return normalized !== "CODEX_HOME" && normalized !== OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR;
|
|
204
140
|
});
|
|
205
141
|
return {
|
|
206
142
|
...start,
|
|
@@ -209,7 +145,7 @@ function buildPrivateCodexAppServerStartOptions(start, codexHome) {
|
|
|
209
145
|
...privateEnv,
|
|
210
146
|
CODEX_HOME: codexHome
|
|
211
147
|
},
|
|
212
|
-
clearEnv: [...clearEnv,
|
|
148
|
+
clearEnv: [...clearEnv, OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR]
|
|
213
149
|
};
|
|
214
150
|
}
|
|
215
151
|
function createCodexBoundedApprovalHandler(taskLabel) {
|
|
@@ -230,14 +166,15 @@ function createCodexBoundedApprovalHandler(taskLabel) {
|
|
|
230
166
|
};
|
|
231
167
|
}
|
|
232
168
|
async function resolveCodexBoundedTurnModel(params) {
|
|
233
|
-
const
|
|
169
|
+
const result = await params.client.request("model/list", {
|
|
234
170
|
limit: null,
|
|
235
171
|
cursor: null,
|
|
236
172
|
includeHidden: false
|
|
237
173
|
}, {
|
|
238
174
|
timeoutMs: Math.min(params.timeoutMs, 5e3),
|
|
239
175
|
signal: params.signal
|
|
240
|
-
})
|
|
176
|
+
});
|
|
177
|
+
const listed = readModelListResult(result).models;
|
|
241
178
|
if (params.selection.mode === "live-default") {
|
|
242
179
|
const supported = listed.filter((entry) => params.requiredModalities.every((modality) => entry.inputModalities.includes(modality)));
|
|
243
180
|
const selected = supported.find((entry) => entry.isDefault) ?? supported[0];
|
|
@@ -255,7 +192,6 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
|
|
|
255
192
|
let turnId;
|
|
256
193
|
let completedTurn;
|
|
257
194
|
let promptError;
|
|
258
|
-
let responseUsage;
|
|
259
195
|
const pending = [];
|
|
260
196
|
const completedItems = /* @__PURE__ */ new Map();
|
|
261
197
|
const assistantTextByItem = /* @__PURE__ */ new Map();
|
|
@@ -291,18 +227,12 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
|
|
|
291
227
|
rememberAssistantText(itemId, `${assistantTextByItem.get(itemId) ?? ""}${delta}`);
|
|
292
228
|
return;
|
|
293
229
|
}
|
|
294
|
-
if (notification.method === "rawResponse/completed") {
|
|
295
|
-
const usage = isJsonObject(params.usage) ? params.usage : void 0;
|
|
296
|
-
responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
230
|
if (notification.method === "turn/completed") {
|
|
300
231
|
completedTurn = readCodexTurnCompletedNotification(notification.params)?.turn ?? completedTurn;
|
|
301
232
|
resolveCompletion?.();
|
|
302
233
|
return;
|
|
303
234
|
}
|
|
304
235
|
if (notification.method === "error") {
|
|
305
|
-
if (isRetryableErrorNotification(notification.params)) return;
|
|
306
236
|
promptError = readCodexErrorNotification(notification.params)?.error.message ?? `codex app-server ${taskLabel} turn failed`;
|
|
307
237
|
resolveCompletion?.();
|
|
308
238
|
}
|
|
@@ -315,13 +245,12 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
|
|
|
315
245
|
for (const notification of pending.splice(0)) handleNotification(notification);
|
|
316
246
|
if (!completedTurn && !promptError) await waitForTurnCompletion({
|
|
317
247
|
completion,
|
|
248
|
+
timeoutMs: options.timeoutMs,
|
|
318
249
|
signal: options.signal,
|
|
319
|
-
taskLabel
|
|
320
|
-
timeoutError: options.timeoutError
|
|
250
|
+
taskLabel
|
|
321
251
|
});
|
|
322
252
|
if (promptError) throw new Error(promptError);
|
|
323
253
|
if (completedTurn?.status === "failed") throw new Error(completedTurn.error?.message ?? `codex app-server ${taskLabel} turn failed`);
|
|
324
|
-
if (completedTurn?.status !== "completed") throw new Error(`codex app-server ${taskLabel} turn ended with status ${completedTurn?.status ?? "unknown"}`);
|
|
325
254
|
const items = collectCompletedItems(completedTurn?.items, completedItems);
|
|
326
255
|
const itemText = collectAssistantTextFromItems(items);
|
|
327
256
|
const deltaText = assistantItemOrder.map((itemId) => assistantTextByItem.get(itemId)?.trim()).filter((text) => Boolean(text)).join("\n\n").trim();
|
|
@@ -329,8 +258,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
|
|
|
329
258
|
if (!text) throw new Error(`Codex app-server ${taskLabel} turn returned no text.`);
|
|
330
259
|
return {
|
|
331
260
|
text,
|
|
332
|
-
items
|
|
333
|
-
...responseUsage ? { usage: responseUsage } : {}
|
|
261
|
+
items
|
|
334
262
|
};
|
|
335
263
|
}
|
|
336
264
|
};
|
|
@@ -341,21 +269,22 @@ function collectCompletedItems(turnItems, notificationItems) {
|
|
|
341
269
|
return [...items.values()];
|
|
342
270
|
}
|
|
343
271
|
async function waitForTurnCompletion(params) {
|
|
344
|
-
if (params.signal.aborted) throw
|
|
272
|
+
if (params.signal.aborted) throw new Error(`codex app-server ${params.taskLabel} turn aborted`);
|
|
273
|
+
let timeout;
|
|
345
274
|
let cleanupAbort;
|
|
346
275
|
try {
|
|
347
276
|
await Promise.race([params.completion, new Promise((_, reject) => {
|
|
348
|
-
|
|
277
|
+
timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(`codex app-server ${params.taskLabel} turn timed out`)), params.timeoutMs);
|
|
278
|
+
timeout.unref?.();
|
|
279
|
+
const abortListener = () => reject(/* @__PURE__ */ new Error(`codex app-server ${params.taskLabel} turn aborted`));
|
|
349
280
|
params.signal.addEventListener("abort", abortListener, { once: true });
|
|
350
281
|
cleanupAbort = () => params.signal.removeEventListener("abort", abortListener);
|
|
351
282
|
})]);
|
|
352
283
|
} finally {
|
|
284
|
+
if (timeout) clearTimeout(timeout);
|
|
353
285
|
cleanupAbort?.();
|
|
354
286
|
}
|
|
355
287
|
}
|
|
356
|
-
function resolveCodexBoundedTurnAbortError(signal, taskLabel, timeoutError) {
|
|
357
|
-
return signal.reason === timeoutError ? timeoutError : /* @__PURE__ */ new Error(`codex app-server ${taskLabel} turn aborted`);
|
|
358
|
-
}
|
|
359
288
|
function collectAssistantTextFromItems(items) {
|
|
360
289
|
return (items ?? []).filter((item) => item.type === "agentMessage").map((item) => item.text.trim()).filter(Boolean).join("\n\n").trim();
|
|
361
290
|
}
|
|
@@ -372,4 +301,169 @@ function isTerminalTurn(turn) {
|
|
|
372
301
|
return turn.status === "completed" || turn.status === "interrupted" || turn.status === "failed";
|
|
373
302
|
}
|
|
374
303
|
//#endregion
|
|
375
|
-
|
|
304
|
+
//#region extensions/codex/media-understanding-provider.ts
|
|
305
|
+
/**
|
|
306
|
+
* Codex-backed media understanding provider for bounded image description and
|
|
307
|
+
* structured extraction turns.
|
|
308
|
+
*/
|
|
309
|
+
const DEFAULT_CODEX_IMAGE_MODEL = FALLBACK_CODEX_MODELS.find((model) => model.inputModalities.includes("image"))?.id ?? FALLBACK_CODEX_MODELS[0]?.id;
|
|
310
|
+
const DEFAULT_CODEX_IMAGE_PROMPT = "Describe the image.";
|
|
311
|
+
/**
|
|
312
|
+
* Builds the media-understanding provider that delegates image tasks to an
|
|
313
|
+
* isolated Codex app-server session.
|
|
314
|
+
*/
|
|
315
|
+
function buildCodexMediaUnderstandingProvider(options = {}) {
|
|
316
|
+
return {
|
|
317
|
+
id: CODEX_PROVIDER_ID,
|
|
318
|
+
capabilities: ["image"],
|
|
319
|
+
...DEFAULT_CODEX_IMAGE_MODEL ? { defaultModels: { image: DEFAULT_CODEX_IMAGE_MODEL } } : {},
|
|
320
|
+
describeImage: async (req) => describeCodexImages({
|
|
321
|
+
images: [{
|
|
322
|
+
buffer: req.buffer,
|
|
323
|
+
fileName: req.fileName,
|
|
324
|
+
mime: req.mime
|
|
325
|
+
}],
|
|
326
|
+
provider: req.provider,
|
|
327
|
+
model: req.model,
|
|
328
|
+
prompt: req.prompt,
|
|
329
|
+
maxTokens: req.maxTokens,
|
|
330
|
+
timeoutMs: req.timeoutMs,
|
|
331
|
+
profile: req.profile,
|
|
332
|
+
preferredProfile: req.preferredProfile,
|
|
333
|
+
authStore: req.authStore,
|
|
334
|
+
agentDir: req.agentDir,
|
|
335
|
+
cfg: req.cfg
|
|
336
|
+
}, options),
|
|
337
|
+
describeImages: async (req) => describeCodexImages(req, options),
|
|
338
|
+
extractStructured: async (req) => extractCodexStructured(req, options)
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
async function describeCodexImages(req, options) {
|
|
342
|
+
const model = req.model.trim();
|
|
343
|
+
if (!model) throw new Error("Codex image understanding requires model id.");
|
|
344
|
+
const { text } = await runBoundedCodexAppServerTurn({
|
|
345
|
+
config: req.cfg,
|
|
346
|
+
model: {
|
|
347
|
+
mode: "required",
|
|
348
|
+
id: model
|
|
349
|
+
},
|
|
350
|
+
profile: req.profile,
|
|
351
|
+
timeoutMs: req.timeoutMs,
|
|
352
|
+
agentDir: req.agentDir,
|
|
353
|
+
authProfileStore: req.authStore,
|
|
354
|
+
options,
|
|
355
|
+
taskLabel: "image understanding",
|
|
356
|
+
developerInstructions: "You are OpenClaw's bounded image-understanding worker. Describe only the provided image content. Do not call tools, edit files, or ask follow-up questions.",
|
|
357
|
+
input: [{
|
|
358
|
+
type: "text",
|
|
359
|
+
text: buildCodexImagePrompt(req),
|
|
360
|
+
text_elements: []
|
|
361
|
+
}, ...req.images.map((image) => ({
|
|
362
|
+
type: "image",
|
|
363
|
+
url: `data:${image.mime ?? "image/png"};base64,${image.buffer.toString("base64")}`
|
|
364
|
+
}))],
|
|
365
|
+
requiredModalities: ["text", "image"],
|
|
366
|
+
isolation: "configured-transport"
|
|
367
|
+
});
|
|
368
|
+
return {
|
|
369
|
+
text,
|
|
370
|
+
model
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
async function extractCodexStructured(req, options) {
|
|
374
|
+
const model = req.model.trim();
|
|
375
|
+
if (!model) throw new Error("Codex structured extraction requires model id.");
|
|
376
|
+
if (!req.instructions.trim()) throw new Error("Codex structured extraction requires instructions.");
|
|
377
|
+
if (req.input.length === 0) throw new Error("Codex structured extraction requires at least one input.");
|
|
378
|
+
if (!req.input.some((entry) => entry.type === "image")) throw new Error("Codex structured extraction requires at least one image input.");
|
|
379
|
+
const { text } = await runBoundedCodexAppServerTurn({
|
|
380
|
+
config: req.cfg,
|
|
381
|
+
model: {
|
|
382
|
+
mode: "required",
|
|
383
|
+
id: model
|
|
384
|
+
},
|
|
385
|
+
profile: req.profile,
|
|
386
|
+
timeoutMs: req.timeoutMs,
|
|
387
|
+
agentDir: req.agentDir,
|
|
388
|
+
authProfileStore: req.authStore,
|
|
389
|
+
options,
|
|
390
|
+
taskLabel: "structured extraction",
|
|
391
|
+
developerInstructions: "You are OpenClaw's bounded structured-extraction worker. Return only the requested extraction. Do not call tools, edit files, ask follow-up questions, or include secrets.",
|
|
392
|
+
input: buildCodexStructuredInput(req),
|
|
393
|
+
requiredModalities: requiredStructuredModalities(),
|
|
394
|
+
isolation: "configured-transport"
|
|
395
|
+
});
|
|
396
|
+
return normalizeStructuredExtractionResult({
|
|
397
|
+
text,
|
|
398
|
+
model,
|
|
399
|
+
provider: req.provider,
|
|
400
|
+
req
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
function buildCodexImagePrompt(req) {
|
|
404
|
+
const prompt = req.prompt?.trim() || DEFAULT_CODEX_IMAGE_PROMPT;
|
|
405
|
+
if (req.images.length <= 1) return prompt;
|
|
406
|
+
return `${prompt}\n\nAnalyze all ${req.images.length} images together.`;
|
|
407
|
+
}
|
|
408
|
+
function requiredStructuredModalities() {
|
|
409
|
+
return ["text", "image"];
|
|
410
|
+
}
|
|
411
|
+
function buildCodexStructuredInput(req) {
|
|
412
|
+
return [{
|
|
413
|
+
type: "text",
|
|
414
|
+
text: buildStructuredExtractionPrompt(req),
|
|
415
|
+
text_elements: []
|
|
416
|
+
}, ...req.input.map((entry) => {
|
|
417
|
+
if (entry.type === "text") return {
|
|
418
|
+
type: "text",
|
|
419
|
+
text: entry.text,
|
|
420
|
+
text_elements: []
|
|
421
|
+
};
|
|
422
|
+
return {
|
|
423
|
+
type: "image",
|
|
424
|
+
url: `data:${entry.mime ?? "image/png"};base64,${entry.buffer.toString("base64")}`
|
|
425
|
+
};
|
|
426
|
+
})];
|
|
427
|
+
}
|
|
428
|
+
function buildStructuredExtractionPrompt(req) {
|
|
429
|
+
return [
|
|
430
|
+
req.instructions.trim(),
|
|
431
|
+
req.schemaName ? `Schema name: ${req.schemaName}` : void 0,
|
|
432
|
+
req.jsonSchema ? `JSON schema:\n${JSON.stringify(req.jsonSchema)}` : void 0,
|
|
433
|
+
req.jsonMode === false ? "Return the extraction as concise text." : "Return valid JSON only. Do not wrap the JSON in Markdown fences."
|
|
434
|
+
].filter((part) => Boolean(part)).join("\n\n");
|
|
435
|
+
}
|
|
436
|
+
function isJsonSchemaObject(value) {
|
|
437
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
438
|
+
}
|
|
439
|
+
function normalizeStructuredExtractionResult(params) {
|
|
440
|
+
const result = {
|
|
441
|
+
text: params.text,
|
|
442
|
+
model: params.model,
|
|
443
|
+
provider: params.provider,
|
|
444
|
+
contentType: params.req.jsonMode === false ? "text" : "json"
|
|
445
|
+
};
|
|
446
|
+
if (params.req.jsonMode !== false) {
|
|
447
|
+
try {
|
|
448
|
+
result.parsed = JSON.parse(params.text);
|
|
449
|
+
} catch {
|
|
450
|
+
throw new Error("Codex structured extraction returned invalid JSON.");
|
|
451
|
+
}
|
|
452
|
+
if (isJsonSchemaObject(params.req.jsonSchema)) {
|
|
453
|
+
const validation = validateJsonSchemaValue({
|
|
454
|
+
schema: params.req.jsonSchema,
|
|
455
|
+
cacheKey: "codex.media-understanding.extractStructured",
|
|
456
|
+
value: result.parsed,
|
|
457
|
+
cache: false
|
|
458
|
+
});
|
|
459
|
+
if (!validation.ok) {
|
|
460
|
+
const message = validation.errors.map((error) => error.text).join("; ") || "invalid";
|
|
461
|
+
throw new Error(`Codex structured extraction JSON did not match schema: ${message}`);
|
|
462
|
+
}
|
|
463
|
+
result.parsed = validation.value;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return result;
|
|
467
|
+
}
|
|
468
|
+
//#endregion
|
|
469
|
+
export { runBoundedCodexAppServerTurn as n, buildCodexMediaUnderstandingProvider as t };
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
2
|
+
import { s as readCodexModelListResponse } from "./protocol-validators-dZQ-UTOa.mjs";
|
|
2
3
|
import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
4
|
//#region extensions/codex/src/app-server/models.ts
|
|
4
5
|
/**
|
|
5
6
|
* Lists and normalizes models exposed by the Codex app-server `model/list`
|
|
6
7
|
* endpoint, including pagination and shared-client lease handling.
|
|
7
8
|
*/
|
|
9
|
+
var models_exports = /* @__PURE__ */ __exportAll({
|
|
10
|
+
listAllCodexAppServerModels: () => listAllCodexAppServerModels,
|
|
11
|
+
listCodexAppServerModels: () => listCodexAppServerModels,
|
|
12
|
+
readModelListResult: () => readModelListResult
|
|
13
|
+
});
|
|
8
14
|
/** Lists one Codex app-server model page using the configured auth/client options. */
|
|
9
15
|
async function listCodexAppServerModels(options = {}) {
|
|
10
16
|
return await withCodexAppServerModelClient(options, async ({ client, timeoutMs }) => requestModelListPage(client, {
|
|
@@ -40,19 +46,17 @@ async function listAllCodexAppServerModels(options = {}) {
|
|
|
40
46
|
async function withCodexAppServerModelClient(options, run) {
|
|
41
47
|
const timeoutMs = options.timeoutMs ?? 2500;
|
|
42
48
|
const useSharedClient = options.sharedClient !== false;
|
|
43
|
-
const { createIsolatedCodexAppServerClient, getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient } = await import("./shared-client-
|
|
49
|
+
const { createIsolatedCodexAppServerClient, getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient } = await import("./shared-client-B2KmLPRw.mjs").then((n) => n.c);
|
|
44
50
|
const client = useSharedClient ? await getLeasedSharedCodexAppServerClient({
|
|
45
51
|
startOptions: options.startOptions,
|
|
46
52
|
timeoutMs,
|
|
47
53
|
authProfileId: options.authProfileId,
|
|
48
|
-
authRequirement: options.authRequirement,
|
|
49
54
|
agentDir: options.agentDir,
|
|
50
55
|
config: options.config
|
|
51
56
|
}) : await createIsolatedCodexAppServerClient({
|
|
52
57
|
startOptions: options.startOptions,
|
|
53
58
|
timeoutMs,
|
|
54
59
|
authProfileId: options.authProfileId,
|
|
55
|
-
authRequirement: options.authRequirement,
|
|
56
60
|
agentDir: options.agentDir,
|
|
57
61
|
config: options.config
|
|
58
62
|
});
|
|
@@ -101,7 +105,8 @@ function readCodexModel(value) {
|
|
|
101
105
|
};
|
|
102
106
|
}
|
|
103
107
|
function readReasoningEfforts(value) {
|
|
104
|
-
|
|
108
|
+
const efforts = value.map((entry) => readNonEmptyString(entry.reasoningEffort)).filter((entry) => entry !== void 0);
|
|
109
|
+
return uniqueStrings(efforts);
|
|
105
110
|
}
|
|
106
111
|
function readNonEmptyString(value) {
|
|
107
112
|
if (typeof value !== "string") return;
|
|
@@ -111,4 +116,4 @@ function normalizeMaxPages(value) {
|
|
|
111
116
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : 20;
|
|
112
117
|
}
|
|
113
118
|
//#endregion
|
|
114
|
-
export { listCodexAppServerModels as n,
|
|
119
|
+
export { readModelListResult as i, listCodexAppServerModels as n, models_exports as r, listAllCodexAppServerModels as t };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { r as isJsonObject } from "./protocol-2POPqAY4.mjs";
|
|
2
|
+
//#region extensions/codex/src/app-server/notification-correlation.ts
|
|
3
|
+
/**
|
|
4
|
+
* Correlates Codex app-server notifications with the active thread/turn so
|
|
5
|
+
* projectors can ignore global or stale events without losing diagnostics.
|
|
6
|
+
*/
|
|
7
|
+
/** Returns true when a notification payload belongs to the exact active thread and turn. */
|
|
8
|
+
function isCodexNotificationForTurn(value, threadId, turnId) {
|
|
9
|
+
if (!isJsonObject(value)) return false;
|
|
10
|
+
return readCodexNotificationThreadId(value) === threadId && readCodexNotificationTurnId(value) === turnId;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Reads a thread id from canonical top-level or nested thread payloads.
|
|
14
|
+
* The generated v2 schemas require top-level `threadId` on turn/item-scoped
|
|
15
|
+
* notifications and define `Turn` without one, so `turn.threadId` is not a
|
|
16
|
+
* wire shape and is deliberately not read here.
|
|
17
|
+
*/
|
|
18
|
+
function readCodexNotificationThreadId(record) {
|
|
19
|
+
const thread = isJsonObject(record.thread) ? record.thread : void 0;
|
|
20
|
+
return readString(record, "threadId") ?? (thread ? readString(thread, "id") : void 0);
|
|
21
|
+
}
|
|
22
|
+
/** Reads a turn id from either top-level notification params or nested turn payloads. */
|
|
23
|
+
function readCodexNotificationTurnId(record) {
|
|
24
|
+
return readNestedTurnId(record) ?? readString(record, "turnId");
|
|
25
|
+
}
|
|
26
|
+
function readNestedTurnId(record) {
|
|
27
|
+
const turn = record.turn;
|
|
28
|
+
return isJsonObject(turn) ? readString(turn, "id") : void 0;
|
|
29
|
+
}
|
|
30
|
+
function readString(record, key) {
|
|
31
|
+
const value = record[key];
|
|
32
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { readCodexNotificationThreadId as n, readCodexNotificationTurnId as r, isCodexNotificationForTurn as t };
|