@openclaw/codex 2026.7.2-beta.5 → 2026.8.1-beta.2

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 (59) hide show
  1. package/README.md +2 -0
  2. package/dist/{app-server-policy-BmDgseo_.js → app-server-policy-zcBDc1JU.js} +1 -1
  3. package/dist/attempt-client-cleanup-DMLXUfa8.js +735 -0
  4. package/dist/binding-connection-I5Bo-AsX.js +33 -0
  5. package/dist/{bounded-turn-FEbUXoYT.js → bounded-turn-qgZmzy_4.js} +71 -63
  6. package/dist/{capabilities-BHRSI6Cn.js → capabilities-CybGI1oz.js} +8 -2
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-ico4ZFnk.js → command-formatters-B1AEz8ZA.js} +18 -18
  9. package/dist/{command-handlers-CRmnwI2N.js → command-handlers-Db8pu_ds.js} +484 -95
  10. package/dist/{compact-dEN49UH6.js → compact-LspQaGfl.js} +213 -199
  11. package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
  12. package/dist/doctor-contract-api.js +40 -43
  13. package/dist/{dynamic-tools-LIt9ojep.js → dynamic-tools-BVdyWkUD.js} +2984 -1221
  14. package/dist/effective-mcp-catalog-DIIhAtOZ.js +119 -0
  15. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  16. package/dist/{attempt-notifications-CMR2_fmR.js → event-projector-usage-e5huIQWu.js} +113 -29
  17. package/dist/harness.js +83 -13
  18. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  19. package/dist/index.js +703 -329
  20. package/dist/isolated-completion-C58NbL40.js +75 -0
  21. package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
  22. package/dist/media-understanding-provider.js +5 -5
  23. package/dist/{models-BA01NEez.js → models-BFlpn1Ex.js} +12 -17
  24. package/dist/native-subagent-monitor-DyTGmTUx.js +3111 -0
  25. package/dist/{plugin-app-cache-key-DSXX-rXO.js → plugin-app-cache-key-C3H2CVp6.js} +135 -42
  26. package/dist/plugin-marketplace-discovery-CzrGJdCR.js +385 -0
  27. package/dist/{computer-use-BjGylO-E.js → plugin-metadata-cache-CNJPj4_b.js} +211 -113
  28. package/dist/protocol-validators-B4F7L8Rf.js +2346 -0
  29. package/dist/{rate-limits-S_PXs0ul.js → rate-limits-DZXmOL8-.js} +17 -35
  30. package/dist/{request-CXpPennK.js → request-BRl5_UfX.js} +4 -4
  31. package/dist/{run-attempt-C5GTPJOE.js → run-attempt-P8BdxC1I.js} +1996 -5728
  32. package/dist/{runtime-artifact-C2ITXdhM.js → runtime-artifact-BVSPdd6g.js} +91 -40
  33. package/dist/{sandbox-guard-D1Wky__S.js → sandbox-guard-Cmwc9eIk.js} +10 -13
  34. package/dist/{session-binding-DlVQ-Pxs.js → session-binding-DPxIvMgE.js} +305 -271
  35. package/dist/{session-catalog-CP2oCcEb.js → session-catalog-xwNi_SDM.js} +418 -144
  36. package/dist/{session-cli-CqZ0Fp2a.js → session-cli-7hgXZDV7.js} +1 -1
  37. package/dist/session-retirement-DoMMJFKm.js +36 -0
  38. package/dist/{session-upstream-marker-QE-m5QFG.js → session-upstream-marker-CrIFX06J.js} +1 -1
  39. package/dist/{settled-turn-finalizer-CA_2QXIE.js → settled-turn-finalizer-BRWBO4MO.js} +36 -15
  40. package/dist/{shared-client-BVKE40c-.js → shared-client-kIBbGjk4.js} +721 -240
  41. package/dist/{side-question-CO12sHxo.js → side-question-9HAL26l9.js} +102 -53
  42. package/dist/{thread-lifecycle-DRg_FdzC.js → thread-lifecycle-Bu1BTDXr.js} +1355 -660
  43. package/dist/thread-ownership-6kOQHlyC.js +92 -0
  44. package/dist/thread-resume-CPrJNQVM.js +30 -0
  45. package/dist/{transcript-mirror-uKA-A4tB.js → transcript-mirror-B9gGgnJS.js} +202 -182
  46. package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DIImwDVS.js} +11 -0
  47. package/dist/upstream-prompt-provenance-ClRBije0.js +41 -0
  48. package/dist/{upstream-session-fork-_Vrz4WJr.js → upstream-session-fork-CE-_LdnP.js} +5 -5
  49. package/dist/{usage-UpVbdX5G.js → usage-CHlV0e-o.js} +3 -3
  50. package/dist/{web-search-provider.runtime-CaQMYDbp.js → web-search-provider.runtime-DRw2Vl42.js} +8 -9
  51. package/openclaw.plugin.json +18 -3
  52. package/package.json +6 -7
  53. package/dist/attempt-client-cleanup-Ia52yRWc.js +0 -127
  54. package/dist/conversation-control-DE7d9DOj.js +0 -287
  55. package/dist/event-projector-usage-tvgb1NCX.js +0 -69
  56. package/dist/notification-correlation-Bj_Ak_jI.js +0 -67
  57. package/dist/protocol-validators-Dm4eXZmt.js +0 -6337
  58. package/dist/realtime-voice-api-BPcA1uN9.js +0 -494
  59. package/dist/realtime-voice-api.js +0 -2
@@ -0,0 +1,92 @@
1
+ import { K as releaseCodexAppServerLiveThread, W as isCodexAppServerLiveThreadClaimed, d as retainSharedCodexAppServerClientByInstanceId, q as retainCodexAppServerLiveThread } from "./shared-client-kIBbGjk4.js";
2
+ import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-DMLXUfa8.js";
3
+ import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
4
+ //#region extensions/codex/src/app-server/thread-ownership.ts
5
+ const nativeThreadOwners = new KeyedAsyncQueue();
6
+ /** Codex subscriptions belong to a physical connection, not the native thread ID alone. */
7
+ function isSameCodexAppServerThreadOwner(current, expected) {
8
+ return current !== void 0 && expected !== void 0 && current.threadId === expected.threadId && current.clientId === expected.clientId;
9
+ }
10
+ /** Fences native subscription and commit together; Codex subscriptions are not reference-counted. */
11
+ async function withExclusiveCodexAppServerThread(params) {
12
+ return await nativeThreadOwners.enqueue(`thread:${params.threadId}`, async () => {
13
+ if (await params.bindingStore.hasOtherThreadOwner(params.threadId, params.identity)) throw new Error(`Codex thread ${params.threadId} is owned by another OpenClaw session or conversation.`);
14
+ return await params.run();
15
+ });
16
+ }
17
+ /** Serializes bound turns and retirement so detach cannot unsubscribe an active turn. */
18
+ async function withCodexConversationThreadActivity(bindingId, run) {
19
+ return await nativeThreadOwners.enqueue(`conversation:${bindingId}`, run);
20
+ }
21
+ /** Publishes one owned persistent subscription into the shared bounded idle registry. */
22
+ async function retainCodexAppServerBindingSubscription(client, threadId, ownership) {
23
+ return await retainCodexAppServerLiveThread(client, threadId, ownership?.release ?? (async (releasedThreadId) => {
24
+ if (!await unsubscribeCodexThreadBestEffort(client, {
25
+ threadId: releasedThreadId,
26
+ timeoutMs: 5e3
27
+ })) {
28
+ await closeCodexStartupClientBestEffort(client);
29
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex thread subscription could not be released: ${releasedThreadId}`);
30
+ }
31
+ }), ownership?.configFingerprint, ownership?.serviceTier);
32
+ }
33
+ /** Rolls back the exact subscription Codex created before its binding was committed. */
34
+ async function rollbackCodexAppServerBindingSubscription(client, threadId, retained) {
35
+ if (retained && await releaseCodexAppServerLiveThread(client, threadId)) return;
36
+ if (isCodexAppServerLiveThreadClaimed(client, threadId)) return;
37
+ if (!await unsubscribeCodexThreadBestEffort(client, {
38
+ threadId,
39
+ timeoutMs: 5e3
40
+ })) await closeCodexStartupClientBestEffort(client);
41
+ }
42
+ /** Releases only the physical client and native thread recorded by the displaced binding owner. */
43
+ async function releaseCodexAppServerBindingSubscription(binding, options = {}) {
44
+ const clientLease = retainSharedCodexAppServerClientByInstanceId(binding.clientId);
45
+ if (!clientLease) return;
46
+ try {
47
+ if (await releaseCodexAppServerLiveThread(clientLease.client, binding.threadId)) return;
48
+ if (isCodexAppServerLiveThreadClaimed(clientLease.client, binding.threadId)) throw new Error(`Codex thread ${binding.threadId} has an active run; stop it before changing its owner.`);
49
+ if (!options.allowUntracked) return;
50
+ if (!await unsubscribeCodexThreadBestEffort(clientLease.client, {
51
+ threadId: binding.threadId,
52
+ timeoutMs: 5e3
53
+ })) {
54
+ await closeCodexStartupClientBestEffort(clientLease.client);
55
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex retired thread subscription could not be released: ${binding.threadId}`);
56
+ }
57
+ } finally {
58
+ clientLease.release();
59
+ }
60
+ }
61
+ /** Clears and releases one exact conversation generation without touching its replacement. */
62
+ async function retireCodexConversationThreadBinding(params) {
63
+ const expected = await params.bindingStore.read(params.identity);
64
+ if (!expected || params.expectedThreadId && expected.threadId !== params.expectedThreadId) return false;
65
+ return await params.bindingStore.withLease(params.identity, async () => {
66
+ const current = await params.bindingStore.read(params.identity);
67
+ if (current?.threadId !== expected.threadId || params.expectedStartId && current.conversationStartId !== params.expectedStartId) return false;
68
+ await releaseCodexAppServerBindingSubscription(current, { allowUntracked: params.allowUntracked });
69
+ const cleared = await params.bindingStore.mutate(params.identity, {
70
+ kind: "clear",
71
+ threadId: current.threadId
72
+ });
73
+ if (!cleared || !params.afterClear) return cleared;
74
+ try {
75
+ await params.afterClear();
76
+ return true;
77
+ } catch (error) {
78
+ try {
79
+ if (!await params.bindingStore.mutate(params.identity, {
80
+ kind: "set",
81
+ binding: current,
82
+ if: { kind: "absent" }
83
+ })) throw new Error("the previous Codex binding generation could not be restored", { cause: error });
84
+ } catch (restorationError) {
85
+ throw new AggregateError([error, restorationError], `Codex conversation detachment failed and native thread ${current.threadId} could not be restored; run /codex resume ${current.threadId} to recover it`, { cause: restorationError });
86
+ }
87
+ throw error;
88
+ }
89
+ });
90
+ }
91
+ //#endregion
92
+ export { rollbackCodexAppServerBindingSubscription as a, retireCodexConversationThreadBinding as i, releaseCodexAppServerBindingSubscription as n, withCodexConversationThreadActivity as o, retainCodexAppServerBindingSubscription as r, withExclusiveCodexAppServerThread as s, isSameCodexAppServerThreadOwner as t };
@@ -0,0 +1,30 @@
1
+ import { F as isCodexAppServerPrewriteRequestCancellationError, s as isCodexAppServerStartSelectionChangedError, z as CodexAppServerRpcError } from "./shared-client-kIBbGjk4.js";
2
+ import { i as assertCodexThreadResumeSubscription, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-DMLXUfa8.js";
3
+ import { i as assertCodexThreadResumeResponse } from "./protocol-validators-B4F7L8Rf.js";
4
+ //#region extensions/codex/src/app-server/thread-resume.ts
5
+ /** Owns Codex thread/resume subscription safety. */
6
+ /** Resumes one thread and retires the physical client when acceptance is indeterminate. */
7
+ async function resumeCodexAppServerThread(params) {
8
+ const threadId = params.request.threadId;
9
+ let response;
10
+ try {
11
+ response = assertCodexThreadResumeResponse(await params.client.request("thread/resume", params.request, {
12
+ ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
13
+ ...params.signal ? { signal: params.signal } : {}
14
+ }));
15
+ assertCodexThreadResumeSubscription(threadId, response.thread.id);
16
+ } catch (error) {
17
+ if (isCodexAppServerStartSelectionChangedError(error) || isCodexAppServerPrewriteRequestCancellationError(error)) throw error;
18
+ if (error instanceof CodexAppServerRpcError) throw error;
19
+ try {
20
+ await params.abandonClient();
21
+ } catch (abandonError) {
22
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex thread/resume client could not be retired for ${threadId}`, { cause: abandonError });
23
+ }
24
+ if (error instanceof CodexAppServerUnsafeSubscriptionError) throw error;
25
+ throw new CodexAppServerUnsafeSubscriptionError(error instanceof Error ? error.message : `Codex thread/resume outcome is indeterminate for ${threadId}`, { cause: error });
26
+ }
27
+ return response;
28
+ }
29
+ //#endregion
30
+ export { resumeCodexAppServerThread as t };
@@ -1,137 +1,11 @@
1
+ import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-ClRBije0.js";
2
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
1
3
  import { embeddedAgentLog, formatErrorMessage, projectAgentHarnessTranscriptMessageForDisplay, runAgentHarnessBeforeMessageWriteHook } from "openclaw/plugin-sdk/agent-harness-runtime";
2
4
  import { createHash } from "node:crypto";
3
- import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
+ import { withCodexSessionTranscriptMirrorWriteLock } from "openclaw/plugin-sdk/codex-session-transcript-runtime";
6
+ import { publishSessionTranscriptUpdateByIdentity } from "openclaw/plugin-sdk/session-transcript-runtime";
4
7
  import { Buffer } from "node:buffer";
5
- import { publishSessionTranscriptUpdateByIdentity, withSessionTranscriptWriteLock } from "openclaw/plugin-sdk/session-transcript-runtime";
6
- //#region extensions/codex/src/app-server/upstream-prompt-provenance.ts
7
- const UPSTREAM_USER_TEXT_META_KEY = "upstreamUserText";
8
- const MIRROR_IDENTITY_META_KEY = "mirrorIdentity";
9
- function attachCodexMirrorIdentity(message, identity) {
10
- const record = message;
11
- const existing = record["__openclaw"];
12
- const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
13
- return {
14
- ...record,
15
- __openclaw: {
16
- ...baseMeta,
17
- [MIRROR_IDENTITY_META_KEY]: identity
18
- }
19
- };
20
- }
21
- function readMirrorIdentity(message) {
22
- const meta = message["__openclaw"];
23
- if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
24
- const id = meta[MIRROR_IDENTITY_META_KEY];
25
- return typeof id === "string" && id ? id : void 0;
26
- }
27
- function attachUpstreamUserText(message, text) {
28
- const record = message;
29
- const existing = record["__openclaw"];
30
- const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
31
- return {
32
- ...record,
33
- __openclaw: {
34
- ...baseMeta,
35
- [UPSTREAM_USER_TEXT_META_KEY]: text
36
- }
37
- };
38
- }
39
- function readUpstreamUserText(message) {
40
- const meta = message?.["__openclaw"];
41
- if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
42
- const text = meta[UPSTREAM_USER_TEXT_META_KEY];
43
- return typeof text === "string" && text ? text : void 0;
44
- }
45
- //#endregion
46
- //#region extensions/codex/src/app-server/transcript-mirror-attestation.ts
47
- const MIRROR_ORIGIN_META_KEY = "mirrorOrigin";
48
- const MIRROR_SOURCE_FINGERPRINT_META_KEY = "mirrorSourceFingerprint";
49
- const CODEX_APP_SERVER_MIRROR_ORIGIN = "codex-app-server";
50
- function attachCodexMirrorAttestation(message, sourceFingerprint) {
51
- const record = message;
52
- const existing = record["__openclaw"];
53
- const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
54
- return {
55
- ...record,
56
- __openclaw: {
57
- ...baseMeta,
58
- [MIRROR_ORIGIN_META_KEY]: CODEX_APP_SERVER_MIRROR_ORIGIN,
59
- ...sourceFingerprint ? { [MIRROR_SOURCE_FINGERPRINT_META_KEY]: sourceFingerprint } : {}
60
- }
61
- };
62
- }
63
- function readCodexMirrorSourceFingerprint(message) {
64
- const meta = message["__openclaw"];
65
- if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
66
- const value = meta[MIRROR_SOURCE_FINGERPRINT_META_KEY];
67
- return typeof value === "string" && value ? value : void 0;
68
- }
69
- function serializeCodexMirrorSourceEvidence(message) {
70
- const record = message;
71
- return JSON.stringify({
72
- role: message.role,
73
- content: record.content,
74
- ...message.role === "user" ? { upstreamUserText: readUpstreamUserText(message) } : {},
75
- ...message.role === "toolResult" ? {
76
- toolCallId: record.toolCallId,
77
- toolName: record.toolName,
78
- isError: record.isError === true
79
- } : {}
80
- });
81
- }
82
- function fingerprintCodexMirrorSourceMessage(message) {
83
- return createHash("sha256").update(serializeCodexMirrorSourceEvidence(message)).digest("hex").slice(0, 32);
84
- }
85
- //#endregion
86
- //#region extensions/codex/src/app-server/user-prompt-message.ts
87
- function buildSenderLabel(params) {
88
- const label = params.senderName ?? params.senderUsername ?? params.senderE164 ?? params.senderId;
89
- if (!label) return;
90
- return !params.senderId || label.includes(params.senderId) ? label : `${label} (${params.senderId})`;
91
- }
92
- function buildFromPrepared(params, preparedUserMessage) {
93
- const senderId = normalizeOptionalString(params.senderId);
94
- const senderName = normalizeOptionalString(params.senderName);
95
- const senderUsername = normalizeOptionalString(params.senderUsername);
96
- const senderE164 = normalizeOptionalString(params.senderE164);
97
- const senderLabel = buildSenderLabel({
98
- senderId,
99
- senderName,
100
- senderUsername,
101
- senderE164
102
- });
103
- const sourceChannel = normalizeOptionalString(params.inputProvenance?.sourceChannel ?? params.messageChannel ?? params.messageProvider);
104
- return {
105
- role: "user",
106
- timestamp: Date.now(),
107
- ...params.inputProvenance ? { provenance: params.inputProvenance } : {},
108
- ...sourceChannel ? { sourceChannel } : {},
109
- ...senderId ? { senderId } : {},
110
- ...senderName ? { senderName } : {},
111
- ...senderUsername ? { senderUsername } : {},
112
- ...senderE164 ? { senderE164 } : {},
113
- ...senderLabel ? { senderLabel } : {},
114
- ...preparedUserMessage ? preparedUserMessage : { content: params.prompt }
115
- };
116
- }
117
- function buildCodexUserPromptMessage(params) {
118
- return buildFromPrepared(params, params.userTurnTranscriptRecorder?.message);
119
- }
120
- function buildCodexUpstreamPromptMessage(params, identity, upstreamUserText) {
121
- const message = attachCodexMirrorIdentity(buildCodexUserPromptMessage(params), identity);
122
- return upstreamUserText ? attachUpstreamUserText(message, upstreamUserText) : message;
123
- }
124
- function promptSnapshot(params, turnId, upstreamUserText) {
125
- return params.suppressNextUserMessagePersistence ? [] : [buildCodexUpstreamPromptMessage(params, `${turnId}:prompt`, upstreamUserText)];
126
- }
127
- async function buildResolvedCodexUserPromptMessage(params) {
128
- return buildFromPrepared(params, await params.userTurnTranscriptRecorder?.resolveMessage() ?? params.userTurnTranscriptRecorder?.message);
129
- }
130
- //#endregion
131
- //#region extensions/codex/src/app-server/transcript-mirror.ts
132
- function isMirroredAgentMessage(message) {
133
- return message.role === "user" || message.role === "assistant" || message.role === "toolResult";
134
- }
8
+ //#region extensions/codex/src/app-server/transcript-history-projection.ts
135
9
  const CODEX_HISTORY_IMPORT_MAX_MESSAGES = 200;
136
10
  const CODEX_HISTORY_IMPORT_MAX_BYTES = 512 * 1024;
137
11
  const CODEX_HISTORY_IMPORT_MAX_MESSAGE_BYTES = 64 * 1024;
@@ -186,6 +60,7 @@ function projectCodexUserItemText(item) {
186
60
  parts.push("[Image attachment]");
187
61
  continue;
188
62
  }
63
+ if (input.type === "audio" || input.type === "localAudio" || input.type === "local_audio") parts.push("[Audio attachment]");
189
64
  if (input.type === "skill" || input.type === "mention") {
190
65
  const name = normalizeOptionalString(input.name);
191
66
  if (name) parts.push(`${input.type === "skill" ? "$" : "@"}${name}`);
@@ -226,7 +101,8 @@ function projectCodexThreadHistory(params) {
226
101
  provider: normalizeOptionalString(params.modelProvider) ?? normalizeOptionalString(params.thread.modelProvider) ?? CODEX_HISTORY_ASSISTANT_PROVIDER,
227
102
  model: CODEX_HISTORY_ASSISTANT_MODEL,
228
103
  usage: CODEX_HISTORY_ZERO_USAGE,
229
- stopReason: "stop",
104
+ stopReason: turn.status === "interrupted" ? "aborted" : turn.status === "failed" ? "error" : "stop",
105
+ ...turn.status === "failed" && turn.error?.message ? { errorMessage: turn.error.message } : {},
230
106
  timestamp
231
107
  }, identity) : attachCodexMirrorIdentity({
232
108
  role,
@@ -274,10 +150,124 @@ function projectBoundedCodexThreadHistory(params) {
274
150
  return {
275
151
  importedMessages: selected.length,
276
152
  omittedMessages: projected.length - selected.length,
277
- responseItems: selected.map(({ responseItem }) => responseItem),
153
+ responseItems: selected.filter(({ message }) => message.role !== "assistant" || message.stopReason !== "aborted" && message.stopReason !== "error").map(({ responseItem }) => responseItem),
278
154
  transcriptMessages: selected.map(({ message }) => message)
279
155
  };
280
156
  }
157
+ /** Projects only visible local user/assistant messages through the same bounded history policy. */
158
+ function projectBoundedCodexVisibleSessionHistory(entries) {
159
+ const projected = [];
160
+ for (const entry of entries) {
161
+ if (entry.role !== "user" && entry.role !== "assistant" || !("content" in entry.message)) continue;
162
+ if (entry.role === "assistant" && "stopReason" in entry.message && (entry.message.stopReason === "aborted" || entry.message.stopReason === "error")) continue;
163
+ const content = entry.message.content;
164
+ const text = normalizeImportedHistoryText(typeof content === "string" ? content : Array.isArray(content) ? content.flatMap((part) => part && typeof part === "object" && "text" in part && typeof part.text === "string" ? [part.text] : []).join("\n") : void 0);
165
+ if (!text) continue;
166
+ projected.push({
167
+ message: entry.message,
168
+ responseItem: {
169
+ type: "message",
170
+ role: entry.role,
171
+ content: [{
172
+ type: entry.role === "assistant" ? "output_text" : "input_text",
173
+ text
174
+ }]
175
+ },
176
+ textBytes: Buffer.byteLength(text, "utf8")
177
+ });
178
+ }
179
+ return selectBoundedCodexHistoryTail(projected).map(({ responseItem }) => responseItem);
180
+ }
181
+ //#endregion
182
+ //#region extensions/codex/src/app-server/transcript-mirror-attestation.ts
183
+ const MIRROR_ORIGIN_META_KEY = "mirrorOrigin";
184
+ const MIRROR_SOURCE_FINGERPRINT_META_KEY = "mirrorSourceFingerprint";
185
+ const CODEX_APP_SERVER_MIRROR_ORIGIN = "codex-app-server";
186
+ function attachCodexMirrorAttestation(message, sourceFingerprint) {
187
+ const record = message;
188
+ const existing = record["__openclaw"];
189
+ const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
190
+ return {
191
+ ...record,
192
+ __openclaw: {
193
+ ...baseMeta,
194
+ [MIRROR_ORIGIN_META_KEY]: CODEX_APP_SERVER_MIRROR_ORIGIN,
195
+ ...sourceFingerprint ? { [MIRROR_SOURCE_FINGERPRINT_META_KEY]: sourceFingerprint } : {}
196
+ }
197
+ };
198
+ }
199
+ function readCodexMirrorSourceFingerprint(message) {
200
+ const meta = message["__openclaw"];
201
+ if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
202
+ const value = meta[MIRROR_SOURCE_FINGERPRINT_META_KEY];
203
+ return typeof value === "string" && value ? value : void 0;
204
+ }
205
+ function serializeCodexMirrorSourceEvidence(message) {
206
+ const record = message;
207
+ return JSON.stringify({
208
+ role: message.role,
209
+ content: record.content,
210
+ ...message.role === "user" ? { upstreamUserText: readUpstreamUserText(message) } : {},
211
+ ...message.role === "toolResult" ? {
212
+ toolCallId: record.toolCallId,
213
+ toolName: record.toolName,
214
+ isError: record.isError === true
215
+ } : {}
216
+ });
217
+ }
218
+ function fingerprintCodexMirrorSourceMessage(message) {
219
+ return createHash("sha256").update(serializeCodexMirrorSourceEvidence(message)).digest("hex").slice(0, 32);
220
+ }
221
+ //#endregion
222
+ //#region extensions/codex/src/app-server/user-prompt-message.ts
223
+ function buildSenderLabel(params) {
224
+ const label = params.senderName ?? params.senderUsername ?? params.senderE164 ?? params.senderId;
225
+ if (!label) return;
226
+ return !params.senderId || label.includes(params.senderId) ? label : `${label} (${params.senderId})`;
227
+ }
228
+ function buildFromPrepared(params, preparedUserMessage) {
229
+ const senderId = normalizeOptionalString(params.senderId);
230
+ const senderName = normalizeOptionalString(params.senderName);
231
+ const senderUsername = normalizeOptionalString(params.senderUsername);
232
+ const senderE164 = normalizeOptionalString(params.senderE164);
233
+ const senderLabel = buildSenderLabel({
234
+ senderId,
235
+ senderName,
236
+ senderUsername,
237
+ senderE164
238
+ });
239
+ const sourceChannel = normalizeOptionalString(params.inputProvenance?.sourceChannel ?? params.messageChannel ?? params.messageProvider);
240
+ return {
241
+ role: "user",
242
+ timestamp: Date.now(),
243
+ ...params.inputProvenance ? { provenance: params.inputProvenance } : {},
244
+ ...sourceChannel ? { sourceChannel } : {},
245
+ ...senderId ? { senderId } : {},
246
+ ...senderName ? { senderName } : {},
247
+ ...senderUsername ? { senderUsername } : {},
248
+ ...senderE164 ? { senderE164 } : {},
249
+ ...senderLabel ? { senderLabel } : {},
250
+ ...preparedUserMessage ? preparedUserMessage : { content: params.prompt }
251
+ };
252
+ }
253
+ function buildCodexUserPromptMessage(params) {
254
+ return buildFromPrepared(params, params.userTurnTranscriptRecorder?.message);
255
+ }
256
+ function buildCodexUpstreamPromptMessage(params, identity, upstreamUserText) {
257
+ const message = attachCodexMirrorIdentity(buildCodexUserPromptMessage(params), identity);
258
+ return upstreamUserText ? attachUpstreamUserText(message, upstreamUserText) : message;
259
+ }
260
+ function promptSnapshot(params, turnId, upstreamUserText) {
261
+ return params.suppressNextUserMessagePersistence ? [] : [buildCodexUpstreamPromptMessage(params, `${turnId}:prompt`, upstreamUserText)];
262
+ }
263
+ async function buildResolvedCodexUserPromptMessage(params) {
264
+ return buildFromPrepared(params, await params.userTurnTranscriptRecorder?.resolveMessage() ?? params.userTurnTranscriptRecorder?.message);
265
+ }
266
+ //#endregion
267
+ //#region extensions/codex/src/app-server/transcript-mirror.ts
268
+ function isMirroredAgentMessage(message) {
269
+ return message.role === "user" || message.role === "assistant" || message.role === "toolResult";
270
+ }
281
271
  /** Imports a bounded, user-visible Codex history tail into a new OpenClaw transcript. */
282
272
  async function importCodexThreadHistoryToTranscript(params) {
283
273
  const projection = projectBoundedCodexThreadHistory({
@@ -302,6 +292,10 @@ async function importCodexThreadHistoryToTranscript(params) {
302
292
  };
303
293
  }
304
294
  async function mirrorBestEffort(params) {
295
+ if (!params.params.sessionTarget) return {
296
+ assistantTranscriptOwned: false,
297
+ mirroredMessages: []
298
+ };
305
299
  try {
306
300
  const messages = await resolveFinalCodexMirrorMessages({
307
301
  params: params.params,
@@ -318,8 +312,8 @@ async function mirrorBestEffort(params) {
318
312
  idempotencyScope: `codex-app-server:${params.threadId}`,
319
313
  config: params.params.config
320
314
  });
321
- for (const message of mirrorResult.userMessagesPresent) try {
322
- params.notifyUserMessagePersisted(message);
315
+ for (const receipt of mirrorResult.userMessageReceipts) try {
316
+ params.notifyUserMessagePersisted(receipt.message, receipt.anchor);
323
317
  } catch (error) {
324
318
  embeddedAgentLog.warn("failed to notify codex app-server user-message persistence", { error: formatErrorMessage(error) });
325
319
  }
@@ -335,13 +329,21 @@ async function mirrorBestEffort(params) {
335
329
  const assistantMirrorIdentity = `${params.turnId}:assistant`;
336
330
  const assistantTranscriptOwned = mirrorResult.assistantMirrorIdentitiesOwned.includes(assistantMirrorIdentity);
337
331
  const assistantTranscriptIdempotencyKey = normalizeOptionalString((assistantTranscriptOwned ? mirroredMessages.find((message) => readMirrorIdentity(message) === assistantMirrorIdentity) : void 0)?.idempotencyKey);
332
+ const terminalMessage = mirroredMessages.at(-1);
333
+ const terminalMirrorIdentity = terminalMessage ? readMirrorIdentity(terminalMessage) : void 0;
334
+ const terminalAnchor = (terminalMirrorIdentity ? mirrorResult.anchorsByMirrorIdentity.get(terminalMirrorIdentity) : void 0) ?? params.params.userTurnTranscriptRecorder?.getAdmissionReceipt();
338
335
  return {
339
336
  assistantTranscriptOwned,
340
337
  ...assistantTranscriptIdempotencyKey ? { assistantTranscriptIdempotencyKey } : {},
338
+ ...terminalAnchor ? { terminalAnchor } : {},
341
339
  mirroredMessages
342
340
  };
343
341
  } catch (error) {
344
- embeddedAgentLog.warn("failed to mirror codex app-server transcript", { error });
342
+ embeddedAgentLog.warn("failed to mirror codex app-server transcript", {
343
+ error: formatErrorMessage(error),
344
+ runId: params.params.runId,
345
+ sessionId: params.params.sessionId
346
+ });
345
347
  return {
346
348
  assistantTranscriptOwned: false,
347
349
  mirroredMessages: []
@@ -362,10 +364,10 @@ async function resolveFinalCodexMirrorMessages(params) {
362
364
  }
363
365
  function createCodexAppServerUserMessagePersistenceNotifier(runParams) {
364
366
  let notified = false;
365
- return (message) => {
367
+ return (message, anchor) => {
366
368
  if (notified) return;
367
369
  notified = true;
368
- runParams.userTurnTranscriptRecorder?.markRuntimePersisted(message);
370
+ runParams.userTurnTranscriptRecorder?.markRuntimePersisted(message, anchor);
369
371
  try {
370
372
  runParams.onUserMessagePersisted?.(message);
371
373
  } catch (error) {
@@ -374,7 +376,7 @@ function createCodexAppServerUserMessagePersistenceNotifier(runParams) {
374
376
  };
375
377
  }
376
378
  async function mirrorPromptAtTurnStartBestEffort(params) {
377
- if (params.params.suppressNextUserMessagePersistence) return;
379
+ if (params.params.suppressNextUserMessagePersistence || !params.params.sessionTarget) return;
378
380
  try {
379
381
  const mirrorPromise = (async () => {
380
382
  const userPromptMessage = projectAgentHarnessTranscriptMessageForDisplay({
@@ -391,12 +393,16 @@ async function mirrorPromptAtTurnStartBestEffort(params) {
391
393
  idempotencyScope: `codex-app-server:${params.threadId}`,
392
394
  config: params.params.config
393
395
  });
394
- for (const message of mirrorResult.userMessagesPresent) params.notifyUserMessagePersisted(message);
396
+ for (const receipt of mirrorResult.userMessageReceipts) params.notifyUserMessagePersisted(receipt.message, receipt.anchor);
395
397
  })();
396
398
  params.params.userTurnTranscriptRecorder?.markRuntimePersistencePending(mirrorPromise);
397
399
  await mirrorPromise;
398
400
  } catch (error) {
399
- embeddedAgentLog.warn("failed to mirror codex app-server prompt at turn start", { error });
401
+ embeddedAgentLog.warn("failed to mirror codex app-server prompt at turn start", {
402
+ error: formatErrorMessage(error),
403
+ runId: params.params.runId,
404
+ sessionId: params.params.sessionId
405
+ });
400
406
  }
401
407
  }
402
408
  function fingerprintMirrorMessageContent(message) {
@@ -415,33 +421,53 @@ async function mirror(params) {
415
421
  const messages = params.messages.filter(isMirroredAgentMessage);
416
422
  if (messages.length === 0) return {
417
423
  assistantMirrorIdentitiesOwned: [],
424
+ anchorsByMirrorIdentity: /* @__PURE__ */ new Map(),
418
425
  messagesPresent: [],
426
+ userMessageReceipts: [],
419
427
  userMessagesPresent: []
420
428
  };
429
+ const candidates = messages.map((message) => {
430
+ const dedupeIdentity = buildMirrorDedupeIdentity(message);
431
+ const sourceFingerprint = fingerprintCodexMirrorSourceMessage(message);
432
+ return {
433
+ dedupeIdentity,
434
+ idempotencyKey: (message.role === "user" ? normalizeOptionalString(message.idempotencyKey) : void 0) ?? (params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0),
435
+ message,
436
+ sourceFingerprint
437
+ };
438
+ });
439
+ const candidateIdempotencyKeys = candidates.flatMap(({ idempotencyKey }) => idempotencyKey ? [idempotencyKey] : []);
421
440
  const transcriptTarget = resolveCodexMirrorTranscriptTarget(params);
422
- const { appendedUpdates, assistantMirrorIdentitiesOwned, messagesPresent, userMessagesPresent } = await withSessionTranscriptWriteLock({
441
+ const { appendedUpdates, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
423
442
  ...transcriptTarget,
424
443
  config: params.config
425
444
  }, async (transcript) => {
426
445
  const nextAppendedUpdates = [];
427
446
  const nextAssistantMirrorIdentitiesOwned = /* @__PURE__ */ new Set();
447
+ const nextAnchorsByMirrorIdentity = /* @__PURE__ */ new Map();
428
448
  const nextMessagesPresent = [];
449
+ const nextUserMessageReceipts = [];
429
450
  const nextUserMessagesPresent = [];
430
- const mirrorState = readTranscriptMirrorState(await transcript.readEvents());
431
- let nextMessageSeq = mirrorState.messageCount;
432
- for (const message of messages) {
433
- const dedupeIdentity = buildMirrorDedupeIdentity(message);
434
- const sourceFingerprint = fingerprintCodexMirrorSourceMessage(message);
435
- const idempotencyKey = (message.role === "user" ? normalizeOptionalString(message.idempotencyKey) : void 0) ?? (params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0);
451
+ const mirrorFacts = await transcript.readMessageFacts({ idempotencyKeys: candidateIdempotencyKeys });
452
+ for (const { dedupeIdentity, idempotencyKey, message, sourceFingerprint } of candidates) {
436
453
  const transcriptMessage = {
437
454
  ...attachCodexMirrorAttestation(message, sourceFingerprint),
438
455
  ...idempotencyKey ? { idempotencyKey } : {}
439
456
  };
440
- if (idempotencyKey && mirrorState.idempotencyKeys.has(idempotencyKey)) {
441
- const persistedMessage = mirrorState.messagesByIdempotencyKey.get(idempotencyKey);
442
- if (persistedMessage) nextMessagesPresent.push(persistedMessage);
443
- const persistedUserMessage = persistedMessage?.role === "user" ? persistedMessage : void 0;
444
- if (persistedUserMessage) nextUserMessagesPresent.push(persistedUserMessage);
457
+ if (idempotencyKey && mirrorFacts.existingIdempotencyKeys.has(idempotencyKey)) {
458
+ const persistedMessage = mirrorFacts.messagesByIdempotencyKey.get(idempotencyKey);
459
+ const persistedAnchor = mirrorFacts.anchorsByIdempotencyKey.get(idempotencyKey);
460
+ if (persistedMessage && isMirroredAgentMessage(persistedMessage)) {
461
+ nextMessagesPresent.push(persistedMessage);
462
+ if (persistedMessage.role === "user") {
463
+ nextUserMessagesPresent.push(persistedMessage);
464
+ if (persistedAnchor) nextUserMessageReceipts.push({
465
+ anchor: persistedAnchor,
466
+ message: persistedMessage
467
+ });
468
+ }
469
+ }
470
+ if (persistedAnchor) nextAnchorsByMirrorIdentity.set(dedupeIdentity, persistedAnchor);
445
471
  if (message.role === "assistant") nextAssistantMirrorIdentitiesOwned.add(dedupeIdentity);
446
472
  continue;
447
473
  }
@@ -464,31 +490,42 @@ async function mirror(params) {
464
490
  hidden: message.display === false,
465
491
  message: messageToAppend
466
492
  });
467
- const appended = await transcript.appendMessage({
493
+ const { messageSeq, result: appended } = await transcript.appendMessageWithMessageSequence({
468
494
  message: messageToAppend,
469
- idempotencyLookup: idempotencyKey ? "caller-checked" : "scan",
495
+ idempotencyLookup: "scan",
470
496
  cwd: params.cwd
471
497
  });
472
498
  if (!appended) continue;
473
499
  const { messageId, message: appendedMessage } = appended;
474
500
  if (isMirroredAgentMessage(appendedMessage)) {
475
501
  nextMessagesPresent.push(appendedMessage);
476
- if (idempotencyKey) mirrorState.messagesByIdempotencyKey.set(idempotencyKey, appendedMessage);
502
+ if (idempotencyKey) mirrorFacts.messagesByIdempotencyKey.set(idempotencyKey, appendedMessage);
477
503
  }
478
504
  if (message.role === "assistant") nextAssistantMirrorIdentitiesOwned.add(dedupeIdentity);
479
- if (appendedMessage.role === "user") nextUserMessagesPresent.push(appendedMessage);
480
- nextMessageSeq += 1;
481
- nextAppendedUpdates.push({
505
+ if (appended.anchor) nextAnchorsByMirrorIdentity.set(dedupeIdentity, appended.anchor);
506
+ if (appendedMessage.role === "user" && appended.anchor) {
507
+ nextUserMessagesPresent.push(appendedMessage);
508
+ nextUserMessageReceipts.push({
509
+ anchor: appended.anchor,
510
+ message: appendedMessage
511
+ });
512
+ }
513
+ if (appended.appended) nextAppendedUpdates.push({
482
514
  messageId,
483
515
  message: appendedMessage,
484
- messageSeq: nextMessageSeq
516
+ ...messageSeq !== void 0 ? { messageSeq } : {}
485
517
  });
486
- if (idempotencyKey) mirrorState.idempotencyKeys.add(idempotencyKey);
518
+ if (idempotencyKey) {
519
+ mirrorFacts.existingIdempotencyKeys.add(idempotencyKey);
520
+ if (appended.anchor) mirrorFacts.anchorsByIdempotencyKey.set(idempotencyKey, appended.anchor);
521
+ }
487
522
  }
488
523
  return {
489
524
  appendedUpdates: nextAppendedUpdates,
490
525
  assistantMirrorIdentitiesOwned: [...nextAssistantMirrorIdentitiesOwned],
526
+ anchorsByMirrorIdentity: nextAnchorsByMirrorIdentity,
491
527
  messagesPresent: nextMessagesPresent,
528
+ userMessageReceipts: nextUserMessageReceipts,
492
529
  userMessagesPresent: nextUserMessagesPresent
493
530
  };
494
531
  });
@@ -499,7 +536,7 @@ async function mirror(params) {
499
536
  ...params.agentId ? { agentId: params.agentId } : {},
500
537
  message: update.message,
501
538
  messageId: update.messageId,
502
- messageSeq: update.messageSeq,
539
+ ...update.messageSeq !== void 0 ? { messageSeq: update.messageSeq } : {},
503
540
  sessionKey: transcriptTarget.sessionKey
504
541
  }
505
542
  });
@@ -508,7 +545,9 @@ async function mirror(params) {
508
545
  }
509
546
  return {
510
547
  assistantMirrorIdentitiesOwned,
548
+ anchorsByMirrorIdentity,
511
549
  messagesPresent,
550
+ userMessageReceipts,
512
551
  userMessagesPresent
513
552
  };
514
553
  }
@@ -527,24 +566,5 @@ function resolveCodexMirrorTranscriptTarget(params) {
527
566
  storePath
528
567
  };
529
568
  }
530
- function readTranscriptMirrorState(events) {
531
- const idempotencyKeys = /* @__PURE__ */ new Set();
532
- const messagesByIdempotencyKey = /* @__PURE__ */ new Map();
533
- let messageCount = 0;
534
- for (const event of events) {
535
- if (!event || typeof event !== "object" || Array.isArray(event)) continue;
536
- const parsed = event;
537
- if (parsed.type === "message") messageCount += 1;
538
- if (typeof parsed.message?.idempotencyKey === "string") {
539
- idempotencyKeys.add(parsed.message.idempotencyKey);
540
- if (isMirroredAgentMessage(parsed.message)) messagesByIdempotencyKey.set(parsed.message.idempotencyKey, parsed.message);
541
- }
542
- }
543
- return {
544
- idempotencyKeys,
545
- messagesByIdempotencyKey,
546
- messageCount
547
- };
548
- }
549
569
  //#endregion
550
- export { projectBoundedCodexThreadHistory as a, fingerprintCodexMirrorSourceMessage as c, attachCodexMirrorIdentity as d, readMirrorIdentity as f, mirrorPromptAtTurnStartBestEffort as i, readCodexMirrorSourceFingerprint as l, createCodexAppServerUserMessagePersistenceNotifier as n, buildCodexUserPromptMessage as o, readUpstreamUserText as p, importCodexThreadHistoryToTranscript as r, promptSnapshot as s, codexTranscriptMirrorRuntime as t, serializeCodexMirrorSourceEvidence as u };
570
+ export { buildCodexUserPromptMessage as a, readCodexMirrorSourceFingerprint as c, projectBoundedCodexVisibleSessionHistory as d, mirrorPromptAtTurnStartBestEffort as i, serializeCodexMirrorSourceEvidence as l, createCodexAppServerUserMessagePersistenceNotifier as n, promptSnapshot as o, importCodexThreadHistoryToTranscript as r, fingerprintCodexMirrorSourceMessage as s, codexTranscriptMirrorRuntime as t, projectBoundedCodexThreadHistory as u };