@openclaw/codex 2026.5.20-beta.2 → 2026.5.22

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.
Files changed (27) hide show
  1. package/dist/{client-Ab4Fw77C.js → client-D3SUwPFl.js} +14 -8
  2. package/dist/{client-factory-BbesECdh.js → client-factory-DdrIY1lw.js} +1 -1
  3. package/dist/{command-handlers-Gceg_rBZ.js → command-handlers-DsB0GYd2.js} +64 -7
  4. package/dist/{compact-BaSDurdH.js → compact-BwQn7jKq.js} +186 -40
  5. package/dist/{computer-use-B4iTog6z.js → computer-use-BMMwWwno.js} +2 -2
  6. package/dist/{config-DqIp6oTk.js → config-DDMrwfJl.js} +21 -2
  7. package/dist/dynamic-tools-DA42no4X.js +497 -0
  8. package/dist/harness.js +15 -5
  9. package/dist/index.js +10 -9
  10. package/dist/media-understanding-provider.js +6 -3
  11. package/dist/{models-C8MdOXGD.js → models-B_uo1pf5.js} +1 -1
  12. package/dist/{node-cli-sessions-T1olB1SH.js → node-cli-sessions-yVCifOyG.js} +23 -9
  13. package/dist/{command-formatters-BVBnEgyA.js → notification-correlation-qKY_sgga.js} +66 -15
  14. package/dist/provider.js +3 -3
  15. package/dist/{request-BePR77QD.js → request-NklFaHM4.js} +12 -3
  16. package/dist/{run-attempt-CRHVB240.js → run-attempt-DzlLXP5Y.js} +3750 -1409
  17. package/dist/sandbox-guard-CTnEWuor.js +233 -0
  18. package/dist/{session-binding-DEiYHgJ_.js → session-binding-Bw_mfIW2.js} +4 -2
  19. package/dist/{shared-client-DCxJx5QU.js → shared-client-C_RbGxW8.js} +2 -2
  20. package/dist/{side-question-DlJAUYst.js → side-question-DzP1wClA.js} +20 -15
  21. package/dist/test-api.js +3 -2
  22. package/dist/{thread-lifecycle-Cgi62SSl.js → thread-lifecycle-4Ul7RoW4.js} +606 -589
  23. package/dist/{vision-tools-B2wt6ecs.js → vision-tools-DOnxzH2y.js} +7 -3
  24. package/npm-shrinkwrap.json +1934 -0
  25. package/openclaw.plugin.json +29 -0
  26. package/package.json +8 -6
  27. package/dist/plugin-activation-BkQkPLOY.js +0 -452
@@ -0,0 +1,497 @@
1
+ import { C as sanitizeInlineImageDataUrl, x as invalidInlineImageText } from "./thread-lifecycle-4Ul7RoW4.js";
2
+ import { HEARTBEAT_RESPONSE_TOOL_NAME, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, extractToolResultMediaArtifact, filterToolResultMediaUrls, isMessagingTool, isMessagingToolSendAction, isToolWrappedWithBeforeToolCallHook, normalizeHeartbeatToolResponse, runAgentHarnessAfterToolCallHook, setBeforeToolCallDiagnosticsEnabled, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
3
+ import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
4
+ //#region extensions/codex/src/app-server/dynamic-tool-profile.ts
5
+ const CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES = [
6
+ "read",
7
+ "write",
8
+ "edit",
9
+ "apply_patch",
10
+ "exec",
11
+ "process",
12
+ "update_plan",
13
+ "tool_call",
14
+ "tool_describe",
15
+ "tool_search",
16
+ "tool_search_code"
17
+ ];
18
+ const DYNAMIC_TOOL_NAME_ALIASES = {
19
+ bash: "exec",
20
+ "apply-patch": "apply_patch"
21
+ };
22
+ function normalizeCodexDynamicToolName(name) {
23
+ const normalized = name.trim().toLowerCase();
24
+ return DYNAMIC_TOOL_NAME_ALIASES[normalized] ?? normalized;
25
+ }
26
+ function isForcedPrivateQaCodexRuntime(env = process.env) {
27
+ return env.OPENCLAW_BUILD_PRIVATE_QA === "1" && env.OPENCLAW_QA_FORCE_RUNTIME?.trim().toLowerCase() === "codex";
28
+ }
29
+ function resolveCodexDynamicToolsLoading(config, env = process.env) {
30
+ return isForcedPrivateQaCodexRuntime(env) ? "direct" : config.codexDynamicToolsLoading ?? "searchable";
31
+ }
32
+ function filterCodexDynamicTools(tools, config, env = process.env) {
33
+ const excludes = /* @__PURE__ */ new Set();
34
+ if (!isForcedPrivateQaCodexRuntime(env)) for (const name of CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES) excludes.add(name);
35
+ for (const name of config.codexDynamicToolsExclude ?? []) {
36
+ const trimmed = normalizeCodexDynamicToolName(name);
37
+ if (trimmed) excludes.add(trimmed);
38
+ }
39
+ return excludes.size === 0 ? tools : tools.filter((tool) => !excludes.has(normalizeCodexDynamicToolName(tool.name)));
40
+ }
41
+ //#endregion
42
+ //#region extensions/codex/src/app-server/dynamic-tools.ts
43
+ const CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE = "openclaw";
44
+ const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = new Set(["sessions_yield"]);
45
+ const DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS = 16e3;
46
+ function createCodexDynamicToolBridge(params) {
47
+ const toolResultHookContext = toToolResultHookContext(params.hookContext);
48
+ const toolResultMaxChars = resolveCodexDynamicToolResultMaxChars(params.hookContext);
49
+ const tools = params.tools.map((tool) => {
50
+ if (isToolWrappedWithBeforeToolCallHook(tool)) {
51
+ setBeforeToolCallDiagnosticsEnabled(tool, false);
52
+ return tool;
53
+ }
54
+ return wrapToolWithBeforeToolCallHook(tool, params.hookContext, { emitDiagnostics: false });
55
+ });
56
+ const toolMap = new Map(tools.map((tool) => [tool.name, tool]));
57
+ const registeredTools = params.registeredTools ?? tools;
58
+ const registeredToolNames = new Set(registeredTools.map((tool) => tool.name));
59
+ const telemetry = {
60
+ didSendViaMessagingTool: false,
61
+ messagingToolSentTexts: [],
62
+ messagingToolSentMediaUrls: [],
63
+ messagingToolSentTargets: [],
64
+ messagingToolSourceReplyPayloads: [],
65
+ toolMediaUrls: [],
66
+ toolAudioAsVoice: false
67
+ };
68
+ const middlewareRunner = createAgentToolResultMiddlewareRunner({
69
+ runtime: "codex",
70
+ ...toolResultHookContext
71
+ });
72
+ const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
73
+ const directToolNames = new Set([...ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES, ...params.directToolNames ?? []]);
74
+ return {
75
+ availableSpecs: tools.map((tool) => createCodexDynamicToolSpec({
76
+ tool,
77
+ loading: params.loading ?? "searchable",
78
+ directToolNames
79
+ })),
80
+ specs: registeredTools.map((tool) => createCodexDynamicToolSpec({
81
+ tool,
82
+ loading: params.loading ?? "searchable",
83
+ directToolNames
84
+ })),
85
+ telemetry,
86
+ handleToolCall: async (call, options) => {
87
+ const tool = toolMap.get(call.tool);
88
+ if (!tool) {
89
+ if (registeredToolNames.has(call.tool)) return {
90
+ contentItems: [{
91
+ type: "inputText",
92
+ text: `OpenClaw tool is not available for this turn: ${call.tool}`
93
+ }],
94
+ success: false
95
+ };
96
+ return {
97
+ contentItems: [{
98
+ type: "inputText",
99
+ text: `Unknown OpenClaw tool: ${call.tool}`
100
+ }],
101
+ success: false
102
+ };
103
+ }
104
+ const args = jsonObjectToRecord(call.arguments);
105
+ const startedAt = Date.now();
106
+ const signal = composeAbortSignals(params.signal, options?.signal);
107
+ let didStartExecution = false;
108
+ try {
109
+ const preparedArgs = tool.prepareArguments ? tool.prepareArguments(args) : args;
110
+ didStartExecution = true;
111
+ const rawResult = await tool.execute(call.callId, preparedArgs, signal);
112
+ const rawIsError = isToolResultError(rawResult);
113
+ const middlewareResult = await middlewareRunner.applyToolResultMiddleware({
114
+ threadId: call.threadId,
115
+ turnId: call.turnId,
116
+ toolCallId: call.callId,
117
+ toolName: tool.name,
118
+ args,
119
+ isError: rawIsError,
120
+ result: rawResult
121
+ });
122
+ const result = await legacyExtensionRunner.applyToolResultExtensions({
123
+ threadId: call.threadId,
124
+ turnId: call.turnId,
125
+ toolCallId: call.callId,
126
+ toolName: tool.name,
127
+ args,
128
+ result: middlewareResult
129
+ });
130
+ const resultIsError = rawIsError || isToolResultError(result);
131
+ collectToolTelemetry({
132
+ toolName: tool.name,
133
+ args,
134
+ result,
135
+ mediaTrustResult: rawResult,
136
+ telemetry,
137
+ isError: resultIsError
138
+ });
139
+ runAgentHarnessAfterToolCallHook({
140
+ toolName: tool.name,
141
+ toolCallId: call.callId,
142
+ runId: toolResultHookContext.runId,
143
+ agentId: toolResultHookContext.agentId,
144
+ sessionId: toolResultHookContext.sessionId,
145
+ sessionKey: toolResultHookContext.sessionKey,
146
+ channelId: toolResultHookContext.channelId,
147
+ startArgs: args,
148
+ result,
149
+ startedAt
150
+ });
151
+ const terminalType = inferToolResultDiagnosticTerminalType(result, resultIsError);
152
+ const response = withDiagnosticTerminalType({
153
+ contentItems: convertToolContents(result.content, toolResultMaxChars),
154
+ success: !resultIsError
155
+ }, terminalType);
156
+ withDynamicToolTermination(response, rawResult.terminate === true || result.terminate === true || isToolResultYield(rawResult) || isToolResultYield(result));
157
+ return withSideEffectEvidence(response, terminalType !== "blocked");
158
+ } catch (error) {
159
+ collectToolTelemetry({
160
+ toolName: tool.name,
161
+ args,
162
+ result: void 0,
163
+ telemetry,
164
+ isError: true
165
+ });
166
+ runAgentHarnessAfterToolCallHook({
167
+ toolName: tool.name,
168
+ toolCallId: call.callId,
169
+ runId: toolResultHookContext.runId,
170
+ agentId: toolResultHookContext.agentId,
171
+ sessionId: toolResultHookContext.sessionId,
172
+ sessionKey: toolResultHookContext.sessionKey,
173
+ channelId: toolResultHookContext.channelId,
174
+ startArgs: args,
175
+ error: error instanceof Error ? error.message : String(error),
176
+ startedAt
177
+ });
178
+ return withSideEffectEvidence(withDiagnosticTerminalType({
179
+ contentItems: [{
180
+ type: "inputText",
181
+ text: error instanceof Error ? error.message : String(error)
182
+ }],
183
+ success: false
184
+ }, "error"), didStartExecution);
185
+ }
186
+ }
187
+ };
188
+ }
189
+ function createCodexDynamicToolSpec(params) {
190
+ const base = {
191
+ name: params.tool.name,
192
+ description: params.tool.description,
193
+ inputSchema: toJsonValue(params.tool.parameters)
194
+ };
195
+ if (params.loading === "direct" || params.directToolNames.has(params.tool.name)) return base;
196
+ return {
197
+ ...base,
198
+ namespace: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
199
+ deferLoading: true
200
+ };
201
+ }
202
+ function toToolResultHookContext(ctx) {
203
+ const { agentId, sessionId, sessionKey, runId, channelId } = ctx ?? {};
204
+ return {
205
+ ...agentId && { agentId },
206
+ ...sessionId && { sessionId },
207
+ ...sessionKey && { sessionKey },
208
+ ...runId && { runId },
209
+ ...channelId && { channelId }
210
+ };
211
+ }
212
+ function resolveCodexDynamicToolResultMaxChars(ctx) {
213
+ return resolveAgentContextLimitValue({
214
+ config: ctx?.config,
215
+ agentId: ctx?.agentId,
216
+ key: "toolResultMaxChars"
217
+ }) ?? DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS;
218
+ }
219
+ function resolveAgentContextLimitValue(params) {
220
+ const agents = readRecord(params.config?.agents);
221
+ const defaultValue = readPositiveInteger(readRecord(readRecord(agents?.defaults)?.contextLimits)?.[params.key]);
222
+ if (!params.agentId) return defaultValue;
223
+ const list = agents?.list;
224
+ if (!Array.isArray(list)) return defaultValue;
225
+ const normalizedAgentId = normalizeAgentId(params.agentId);
226
+ return readPositiveInteger(readRecord(readRecord(list.find((entry) => {
227
+ const entryId = readRecord(entry)?.id;
228
+ return typeof entryId === "string" && normalizeAgentId(entryId) === normalizedAgentId;
229
+ }))?.contextLimits)?.[params.key]) ?? defaultValue;
230
+ }
231
+ function composeAbortSignals(...signals) {
232
+ const activeSignals = signals.filter((signal) => Boolean(signal));
233
+ if (activeSignals.length === 0) return new AbortController().signal;
234
+ if (activeSignals.length === 1) return activeSignals[0];
235
+ return AbortSignal.any(activeSignals);
236
+ }
237
+ function collectToolTelemetry(params) {
238
+ if (params.isError) return;
239
+ if (!params.isError && params.toolName === "cron" && isCronAddAction(params.args)) params.telemetry.successfulCronAdds = (params.telemetry.successfulCronAdds ?? 0) + 1;
240
+ if (!params.isError && params.toolName === HEARTBEAT_RESPONSE_TOOL_NAME) {
241
+ const response = normalizeHeartbeatToolResponse(params.result?.details);
242
+ if (response) params.telemetry.heartbeatToolResponse = response;
243
+ }
244
+ if (!params.isError && params.result) {
245
+ const media = extractToolResultMediaArtifact(params.result);
246
+ if (media) {
247
+ const mediaUrls = filterToolResultMediaUrls(params.toolName, media.mediaUrls, params.mediaTrustResult ?? params.result);
248
+ const seen = new Set(params.telemetry.toolMediaUrls);
249
+ for (const mediaUrl of mediaUrls) if (!seen.has(mediaUrl)) {
250
+ seen.add(mediaUrl);
251
+ params.telemetry.toolMediaUrls.push(mediaUrl);
252
+ }
253
+ if (media.audioAsVoice) params.telemetry.toolAudioAsVoice = true;
254
+ }
255
+ }
256
+ if (!isMessagingTool(params.toolName) || !isMessagingToolSendAction(params.toolName, params.args)) return;
257
+ params.telemetry.didSendViaMessagingTool = true;
258
+ const sourceReplyPayload = extractInternalSourceReplyPayload(params.result?.details);
259
+ if (sourceReplyPayload) {
260
+ params.telemetry.messagingToolSourceReplyPayloads.push(sourceReplyPayload);
261
+ return;
262
+ }
263
+ const text = readFirstString(params.args, [
264
+ "text",
265
+ "message",
266
+ "body",
267
+ "content"
268
+ ]);
269
+ if (text) params.telemetry.messagingToolSentTexts.push(text);
270
+ const mediaUrls = collectMediaUrls(params.args);
271
+ params.telemetry.messagingToolSentMediaUrls.push(...mediaUrls);
272
+ params.telemetry.messagingToolSentTargets.push({
273
+ tool: params.toolName,
274
+ provider: readFirstString(params.args, ["provider", "channel"]) ?? params.toolName,
275
+ accountId: readFirstString(params.args, ["accountId", "account_id"]),
276
+ to: readFirstString(params.args, [
277
+ "to",
278
+ "target",
279
+ "recipient"
280
+ ]),
281
+ threadId: readFirstString(params.args, [
282
+ "threadId",
283
+ "thread_id",
284
+ "messageThreadId"
285
+ ]),
286
+ ...text ? { text } : {},
287
+ ...mediaUrls.length > 0 ? { mediaUrls } : {}
288
+ });
289
+ }
290
+ function extractInternalSourceReplyPayload(details) {
291
+ if (!isRecord(details) || details.sourceReplySink !== "internal-ui") return;
292
+ const rawPayload = details.sourceReply;
293
+ if (!isRecord(rawPayload)) return;
294
+ const text = readFirstString(rawPayload, ["text", "message"]);
295
+ const mediaUrls = collectMediaUrls(rawPayload);
296
+ const mediaUrl = typeof rawPayload.mediaUrl === "string" && rawPayload.mediaUrl.trim() ? rawPayload.mediaUrl.trim() : mediaUrls[0];
297
+ const payload = {
298
+ ...text ? { text } : {},
299
+ ...mediaUrl ? { mediaUrl } : {},
300
+ ...mediaUrls.length > 0 ? { mediaUrls } : {},
301
+ ...rawPayload.audioAsVoice === true ? { audioAsVoice: true } : {},
302
+ ...isRecord(rawPayload.presentation) ? { presentation: rawPayload.presentation } : {},
303
+ ...isRecord(rawPayload.interactive) ? { interactive: rawPayload.interactive } : {},
304
+ ...isRecord(rawPayload.channelData) ? { channelData: rawPayload.channelData } : {},
305
+ ...typeof details.idempotencyKey === "string" && details.idempotencyKey.trim() ? { idempotencyKey: details.idempotencyKey.trim() } : {}
306
+ };
307
+ return text || mediaUrls.length > 0 || payload.presentation || payload.interactive ? payload : void 0;
308
+ }
309
+ function isRecord(value) {
310
+ return value !== null && typeof value === "object" && !Array.isArray(value);
311
+ }
312
+ function readRecord(value) {
313
+ return isRecord(value) ? value : void 0;
314
+ }
315
+ function readPositiveInteger(value) {
316
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return;
317
+ return Math.floor(value);
318
+ }
319
+ function isToolResultError(result) {
320
+ const details = result.details;
321
+ if (!isRecord(details)) return false;
322
+ if (details.timedOut === true) return true;
323
+ if (typeof details.exitCode === "number" && details.exitCode !== 0) return true;
324
+ if (typeof details.status !== "string") return false;
325
+ const status = details.status.trim().toLowerCase();
326
+ return status !== "" && status !== "0" && status !== "ok" && status !== "success" && status !== "completed" && status !== "recorded" && status !== "pending" && status !== "started" && status !== "running" && status !== "yielded";
327
+ }
328
+ function isToolResultYield(result) {
329
+ const details = result.details;
330
+ if (!isRecord(details) || typeof details.status !== "string") return false;
331
+ return details.status.trim().toLowerCase() === "yielded";
332
+ }
333
+ function inferToolResultDiagnosticTerminalType(result, isError) {
334
+ const details = result.details;
335
+ if (isRecord(details) && typeof details.status === "string") {
336
+ if (details.status.trim().toLowerCase() === "blocked") return "blocked";
337
+ }
338
+ return isError ? "error" : "completed";
339
+ }
340
+ function withDiagnosticTerminalType(response, terminalType) {
341
+ Object.defineProperty(response, "diagnosticTerminalType", {
342
+ configurable: true,
343
+ enumerable: false,
344
+ value: terminalType
345
+ });
346
+ return response;
347
+ }
348
+ function withSideEffectEvidence(response, sideEffectEvidence) {
349
+ if (!sideEffectEvidence) return response;
350
+ Object.defineProperty(response, "sideEffectEvidence", {
351
+ configurable: true,
352
+ enumerable: false,
353
+ value: true
354
+ });
355
+ return response;
356
+ }
357
+ function withDynamicToolTermination(response, terminate) {
358
+ if (!terminate) return response;
359
+ Object.defineProperty(response, "terminate", {
360
+ configurable: true,
361
+ enumerable: false,
362
+ value: true
363
+ });
364
+ return response;
365
+ }
366
+ function normalizeToolResultMaxChars(maxChars) {
367
+ return typeof maxChars === "number" && Number.isFinite(maxChars) && maxChars > 0 ? Math.floor(maxChars) : DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS;
368
+ }
369
+ function convertToolContents(content, toolResultMaxChars = DEFAULT_CODEX_DYNAMIC_TOOL_RESULT_MAX_CHARS) {
370
+ const maxChars = normalizeToolResultMaxChars(toolResultMaxChars);
371
+ const totalTextChars = content.reduce((total, item) => total + (item.type === "text" ? item.text.length : 0), 0);
372
+ if (totalTextChars <= maxChars) return content.flatMap(convertToolContent);
373
+ const noticeText = `...(OpenClaw truncated dynamic tool result: original ${totalTextChars} chars, showing ${maxChars}; rerun with narrower args.)`;
374
+ const notice = `\n${noticeText}`;
375
+ let remainingTextBudget = Math.max(0, maxChars - notice.length);
376
+ let appendedNotice = false;
377
+ const output = [];
378
+ for (const item of content) {
379
+ if (item.type !== "text") {
380
+ output.push(...convertToolContent(item));
381
+ continue;
382
+ }
383
+ if (appendedNotice) continue;
384
+ if (notice.length >= maxChars) {
385
+ output.push({
386
+ type: "inputText",
387
+ text: noticeText.slice(0, maxChars)
388
+ });
389
+ appendedNotice = true;
390
+ continue;
391
+ }
392
+ const sliceLength = Math.min(item.text.length, remainingTextBudget);
393
+ remainingTextBudget -= sliceLength;
394
+ const shouldAppendNotice = remainingTextBudget <= 0;
395
+ const text = item.text.slice(0, sliceLength);
396
+ if (shouldAppendNotice) {
397
+ output.push({
398
+ type: "inputText",
399
+ text: `${text.trimEnd()}${notice}`.slice(0, maxChars)
400
+ });
401
+ appendedNotice = true;
402
+ } else if (text.length > 0) output.push({
403
+ type: "inputText",
404
+ text
405
+ });
406
+ }
407
+ if (!appendedNotice) output.push({
408
+ type: "inputText",
409
+ text: noticeText.slice(0, maxChars)
410
+ });
411
+ return output;
412
+ }
413
+ function convertToolContent(content) {
414
+ if (content.type === "text") return [{
415
+ type: "inputText",
416
+ text: content.text
417
+ }];
418
+ const imageUrl = sanitizeInlineImageDataUrl(`data:${content.mimeType};base64,${content.data}`);
419
+ if (!imageUrl) return [{
420
+ type: "inputText",
421
+ text: invalidInlineImageText("codex dynamic tool")
422
+ }];
423
+ return [{
424
+ type: "inputImage",
425
+ imageUrl
426
+ }];
427
+ }
428
+ function toJsonValue(value) {
429
+ try {
430
+ const text = JSON.stringify(value);
431
+ if (!text) return {};
432
+ return JSON.parse(text);
433
+ } catch {
434
+ return {};
435
+ }
436
+ }
437
+ function jsonObjectToRecord(value) {
438
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
439
+ return value;
440
+ }
441
+ function readFirstString(record, keys) {
442
+ for (const key of keys) {
443
+ const value = record[key];
444
+ if (typeof value === "string" && value.trim()) return value.trim();
445
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
446
+ }
447
+ }
448
+ function collectMediaUrls(record) {
449
+ const urls = [];
450
+ const pushMediaUrl = (value) => {
451
+ if (typeof value === "string" && value.trim()) urls.push(value.trim());
452
+ };
453
+ const pushAttachment = (value) => {
454
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
455
+ const attachment = value;
456
+ for (const key of [
457
+ "media",
458
+ "mediaUrl",
459
+ "path",
460
+ "filePath",
461
+ "fileUrl",
462
+ "url"
463
+ ]) pushMediaUrl(attachment[key]);
464
+ };
465
+ for (const key of [
466
+ "media",
467
+ "mediaUrl",
468
+ "media_url",
469
+ "path",
470
+ "filePath",
471
+ "fileUrl",
472
+ "imageUrl",
473
+ "image_url"
474
+ ]) {
475
+ const value = record[key];
476
+ pushMediaUrl(value);
477
+ }
478
+ for (const key of [
479
+ "mediaUrls",
480
+ "media_urls",
481
+ "imageUrls",
482
+ "image_urls"
483
+ ]) {
484
+ const value = record[key];
485
+ if (!Array.isArray(value)) continue;
486
+ for (const entry of value) pushMediaUrl(entry);
487
+ }
488
+ const attachments = record.attachments;
489
+ if (Array.isArray(attachments)) for (const attachment of attachments) pushAttachment(attachment);
490
+ return urls;
491
+ }
492
+ function isCronAddAction(args) {
493
+ const action = args.action;
494
+ return typeof action === "string" && action.trim().toLowerCase() === "add";
495
+ }
496
+ //#endregion
497
+ export { resolveCodexDynamicToolsLoading as a, normalizeCodexDynamicToolName as i, filterCodexDynamicTools as n, isForcedPrivateQaCodexRuntime as r, createCodexDynamicToolBridge as t };
package/dist/harness.js CHANGED
@@ -1,10 +1,20 @@
1
1
  //#region extensions/codex/harness.ts
2
2
  const DEFAULT_CODEX_HARNESS_PROVIDER_IDS = new Set(["codex"]);
3
+ const CODEX_APP_SERVER_CONTEXT_ENGINE_HOST_CAPABILITIES = [
4
+ "bootstrap",
5
+ "assemble-before-prompt",
6
+ "after-turn",
7
+ "maintain",
8
+ "compact",
9
+ "runtime-llm-complete",
10
+ "thread-bootstrap-projection"
11
+ ];
3
12
  function createCodexAppServerAgentHarness(options) {
4
13
  const providerIds = new Set([...options?.providerIds ?? DEFAULT_CODEX_HARNESS_PROVIDER_IDS].map((id) => id.trim().toLowerCase()));
5
14
  return {
6
15
  id: options?.id ?? "codex",
7
16
  label: options?.label ?? "Codex agent harness",
17
+ contextEngineHostCapabilities: CODEX_APP_SERVER_CONTEXT_ENGINE_HOST_CAPABILITIES,
8
18
  deliveryDefaults: { sourceVisibleReplies: "message_tool" },
9
19
  supports: (ctx) => {
10
20
  const provider = ctx.provider.trim().toLowerCase();
@@ -18,31 +28,31 @@ function createCodexAppServerAgentHarness(options) {
18
28
  };
19
29
  },
20
30
  runAttempt: async (params) => {
21
- const { runCodexAppServerAttempt } = await import("./run-attempt-CRHVB240.js");
31
+ const { runCodexAppServerAttempt } = await import("./run-attempt-DzlLXP5Y.js");
22
32
  return runCodexAppServerAttempt(params, {
23
33
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
24
34
  nativeHookRelay: { enabled: true }
25
35
  });
26
36
  },
27
37
  runSideQuestion: async (params) => {
28
- const { runCodexAppServerSideQuestion } = await import("./side-question-DlJAUYst.js");
38
+ const { runCodexAppServerSideQuestion } = await import("./side-question-DzP1wClA.js");
29
39
  return runCodexAppServerSideQuestion(params, {
30
40
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
31
41
  nativeHookRelay: { enabled: true }
32
42
  });
33
43
  },
34
44
  compact: async (params) => {
35
- const { maybeCompactCodexAppServerSession } = await import("./compact-BaSDurdH.js");
45
+ const { maybeCompactCodexAppServerSession } = await import("./compact-BwQn7jKq.js");
36
46
  return maybeCompactCodexAppServerSession(params, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
37
47
  },
38
48
  reset: async (params) => {
39
49
  if (params.sessionFile) {
40
- const { clearCodexAppServerBinding } = await import("./session-binding-DEiYHgJ_.js").then((n) => n.a);
50
+ const { clearCodexAppServerBinding } = await import("./session-binding-Bw_mfIW2.js").then((n) => n.a);
41
51
  await clearCodexAppServerBinding(params.sessionFile);
42
52
  }
43
53
  },
44
54
  dispose: async () => {
45
- const { clearSharedCodexAppServerClientAndWait } = await import("./shared-client-DCxJx5QU.js").then((n) => n.a);
55
+ const { clearSharedCodexAppServerClientAndWait } = await import("./shared-client-C_RbGxW8.js").then((n) => n.a);
46
56
  await clearSharedCodexAppServerClientAndWait();
47
57
  }
48
58
  };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { createCodexAppServerAgentHarness } from "./harness.js";
2
- import { c as resolveCodexAppServerRuntimeOptions, s as readCodexPluginConfig, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-DqIp6oTk.js";
3
- import { buildCodexMediaUnderstandingProvider } from "./media-understanding-provider.js";
2
+ import { c as readCodexPluginConfig, l as resolveCodexAppServerRuntimeOptions, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-DDMrwfJl.js";
4
3
  import { buildCodexProvider } from "./provider.js";
5
- import { i as describeControlFailure, n as buildCodexPluginAppCacheKey, t as requestCodexAppServerJson } from "./request-BePR77QD.js";
6
- import { r as formatCodexDisplayText } from "./command-formatters-BVBnEgyA.js";
7
- import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, i as getSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndWait, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-DCxJx5QU.js";
8
- import { a as resolveCodexCliSessionForBindingOnNode, c as handleCodexConversationInboundClaim, i as listCodexCliSessionsOnNode, n as createCodexCliSessionNodeInvokePolicies, o as resumeCodexCliSessionOnNode, s as handleCodexConversationBindingResolved, t as createCodexCliSessionNodeHostCommands } from "./node-cli-sessions-T1olB1SH.js";
9
- import { a as defaultCodexAppInventoryCache, n as pluginReadParams, t as ensureCodexPluginActivation } from "./plugin-activation-BkQkPLOY.js";
4
+ import { _ as ensureCodexPluginActivation, b as defaultCodexAppInventoryCache, v as pluginReadParams } from "./thread-lifecycle-4Ul7RoW4.js";
5
+ import { buildCodexMediaUnderstandingProvider } from "./media-understanding-provider.js";
6
+ import { i as describeControlFailure, n as buildCodexPluginAppCacheKey, t as requestCodexAppServerJson } from "./request-NklFaHM4.js";
7
+ import { s as formatCodexDisplayText } from "./notification-correlation-qKY_sgga.js";
8
+ import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, i as getSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndWait, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-C_RbGxW8.js";
9
+ import { a as resolveCodexCliSessionForBindingOnNode, c as handleCodexConversationInboundClaim, i as listCodexCliSessionsOnNode, n as createCodexCliSessionNodeInvokePolicies, o as resumeCodexCliSessionOnNode, s as handleCodexConversationBindingResolved, t as createCodexCliSessionNodeHostCommands } from "./node-cli-sessions-yVCifOyG.js";
10
10
  import { mutateConfigFile } from "openclaw/plugin-sdk/config-mutation";
11
11
  import { resolveLivePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
12
12
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
@@ -25,7 +25,7 @@ function createCodexCommand(options) {
25
25
  description: "Inspect and control the Codex app-server harness",
26
26
  ownership: "reserved",
27
27
  agentPromptGuidance: [{
28
- text: "Native Codex app-server plugin is available (`/codex ...`). For Codex bind/control/thread/resume/steer/stop requests, prefer `/codex bind`, `/codex threads`, `/codex resume`, `/codex steer`, and `/codex stop` over ACP.",
28
+ text: "Native Codex app-server plugin is available (`/codex ...`). For Codex bind/control/thread/resume/steer/stop requests, prefer `/codex bind`, `/codex threads`, `/codex resume`, `/codex steer`, and `/codex stop` over ACP. When OpenClaw sandboxing is active, native Codex execution modes are unavailable; use normal Codex harness turns.",
29
29
  surfaces: ["pi_main"]
30
30
  }, {
31
31
  text: "Use ACP for Codex only when the user explicitly asks for ACP/acpx or wants to test the ACP path.",
@@ -45,7 +45,7 @@ async function handleCodexCommand(ctx, options = {}) {
45
45
  }
46
46
  }
47
47
  async function loadDefaultCodexSubcommandHandler() {
48
- const { handleCodexSubcommand } = await import("./command-handlers-Gceg_rBZ.js");
48
+ const { handleCodexSubcommand } = await import("./command-handlers-DsB0GYd2.js");
49
49
  return handleCodexSubcommand;
50
50
  }
51
51
  //#endregion
@@ -1158,6 +1158,7 @@ var codex_default = definePluginEntry({
1158
1158
  }
1159
1159
  }));
1160
1160
  api.on("inbound_claim", (event, ctx) => handleCodexConversationInboundClaim(event, ctx, {
1161
+ config: api.runtime.config?.current?.(),
1161
1162
  pluginConfig: resolveCurrentPluginConfig(),
1162
1163
  resumeCodexCliSessionOnNode: (params) => resumeCodexCliSessionOnNode({
1163
1164
  runtime: api.runtime,
@@ -1,8 +1,9 @@
1
1
  import { CODEX_PROVIDER_ID, FALLBACK_CODEX_MODELS } from "./provider-catalog.js";
2
- import { c as resolveCodexAppServerRuntimeOptions } from "./config-DqIp6oTk.js";
2
+ import { l as resolveCodexAppServerRuntimeOptions } from "./config-DDMrwfJl.js";
3
3
  import { i as assertCodexTurnStartResponse, l as readCodexTurnCompletedNotification, o as readCodexErrorNotification, r as assertCodexThreadStartResponse } from "./protocol-validators-_gKDcd0x.js";
4
- import { i as readModelListResult } from "./models-C8MdOXGD.js";
4
+ import { i as readModelListResult } from "./models-B_uo1pf5.js";
5
5
  import { t as isJsonObject } from "./protocol-oeJQu4rs.js";
6
+ import { n as buildCodexRuntimeThreadConfig } from "./thread-lifecycle-4Ul7RoW4.js";
6
7
  import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
7
8
  //#region extensions/codex/media-understanding-provider.ts
8
9
  const DEFAULT_CODEX_IMAGE_MODEL = FALLBACK_CODEX_MODELS.find((model) => model.inputModalities.includes("image"))?.id ?? FALLBACK_CODEX_MODELS[0]?.id;
@@ -62,7 +63,7 @@ async function runBoundedCodexVisionTurn(params) {
62
63
  const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.options.pluginConfig });
63
64
  const timeoutMs = Math.max(100, params.timeoutMs);
64
65
  const ownsClient = !params.options.clientFactory;
65
- const client = params.options.clientFactory ? await params.options.clientFactory(appServer.start, params.profile) : await import("./shared-client-DCxJx5QU.js").then((n) => n.a).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
66
+ const client = params.options.clientFactory ? await params.options.clientFactory(appServer.start, params.profile) : await import("./shared-client-C_RbGxW8.js").then((n) => n.a).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
66
67
  startOptions: appServer.start,
67
68
  timeoutMs,
68
69
  authProfileId: params.profile
@@ -86,6 +87,8 @@ async function runBoundedCodexVisionTurn(params) {
86
87
  sandbox: "read-only",
87
88
  serviceName: "OpenClaw",
88
89
  developerInstructions: params.developerInstructions,
90
+ config: buildCodexRuntimeThreadConfig(void 0, { nativeCodeModeEnabled: false }),
91
+ environments: [],
89
92
  dynamicTools: [],
90
93
  experimentalRawEvents: true,
91
94
  persistExtendedHistory: false,
@@ -39,7 +39,7 @@ async function listAllCodexAppServerModels(options = {}) {
39
39
  async function withCodexAppServerModelClient(options, run) {
40
40
  const timeoutMs = options.timeoutMs ?? 2500;
41
41
  const useSharedClient = options.sharedClient !== false;
42
- const { createIsolatedCodexAppServerClient, getSharedCodexAppServerClient } = await import("./shared-client-DCxJx5QU.js").then((n) => n.a);
42
+ const { createIsolatedCodexAppServerClient, getSharedCodexAppServerClient } = await import("./shared-client-C_RbGxW8.js").then((n) => n.a);
43
43
  const client = useSharedClient ? await getSharedCodexAppServerClient({
44
44
  startOptions: options.startOptions,
45
45
  timeoutMs,