@openclaw/codex 2026.9.1-beta.1 → 2026.9.1
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/dist/api.js +5 -6
- package/dist/{attempt-client-cleanup-bfsmcQ6m.js → attempt-client-cleanup-DYHcRQAa.js} +31 -45
- package/dist/attempt-context-DmQUNWwT.js +634 -0
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-BMvPX73o.js → binding-connection-E6uDsPlx.js} +2 -2
- package/dist/{bounded-turn-B7iBUcuP.js → bounded-turn-wzJrwKKe.js} +15 -20
- package/dist/{capabilities-BRMh0aIq.js → capabilities-dIjNVCYH.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-DEsIufkt.js → command-formatters-CLHhEB1Q.js} +5 -4
- package/dist/{command-handlers-D_-1_qRp.js → command-handlers-CTGb2csu.js} +124 -101
- package/dist/{compact-BglNFZrQ.js → compact-_t0HQrUS.js} +38 -29
- package/dist/{config-giW8X0QA.js → config-BhmfC1s6.js} +294 -282
- package/dist/{context-compaction-activity-BOeJf7yo.js → context-compaction-activity-CMla5FPJ.js} +4 -1
- package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
- package/dist/doctor-contract-api.js +143 -12
- package/dist/{dynamic-tools-Dnlfa--w.js → dynamic-tools-BU9tmlYm.js} +599 -655
- package/dist/{effective-mcp-catalog-CTeGrnfO.js → effective-mcp-catalog-DzYBW4h1.js} +2 -2
- package/dist/{event-projector-assistant-message-C5-Ds8mA.js → event-projector-assistant-message-DHRFXKbS.js} +4 -4
- package/dist/{event-projector-usage-Bk1I90Bg.js → event-projector-usage-C5mcrGjp.js} +15 -148
- package/dist/{harness-Csz0F-DK.js → harness-DXVZ5II5.js} +42 -52
- package/dist/harness.js +1 -1
- package/dist/index.js +458 -404
- package/dist/{isolated-completion-Cv6FqygM.js → isolated-completion-kg9kv4iH.js} +4 -4
- package/dist/launch-args-RXQwn8zV.js +90 -0
- package/dist/{managed-binary-DFYK4DWq.js → managed-binary-4-Vjz5GH.js} +14 -9
- package/dist/media-understanding-provider.js +1 -1
- package/dist/model-catalog-CUM68Hkl.js +101 -0
- package/dist/{models-TS3HBU-q.js → models-sYnEc0gd.js} +25 -28
- package/dist/{native-subagent-monitor-4Mfq2HDs.js → native-subagent-monitor-CnH147jH.js} +55 -115
- package/dist/{node-exec-server.runtime-BpWqJO1V.js → node-exec-server.runtime-CstNHCmC.js} +9 -6
- package/dist/{plugin-approval-roundtrip-bUm777tR.js → plugin-approval-roundtrip-CNe-Xrjx.js} +30 -3
- package/dist/{plugin-marketplace-discovery-B9DvaAG-.js → plugin-marketplace-discovery-CfFlKqDl.js} +15 -14
- package/dist/{plugin-metadata-cache-CTCT3w5L.js → plugin-metadata-cache-BFrPhb2c.js} +6 -6
- package/dist/provider-capabilities-DW5p4k9w.js +101 -0
- package/dist/{rate-limits-C5_D8Gmb.js → rate-limits-CawQJfUS.js} +3 -2
- package/dist/{sandbox-guard-kuWTn9C5.js → request-DYAI5FQE.js} +195 -2
- package/dist/{run-attempt-DYc0QCBF.js → run-attempt-D1hJO4fX.js} +828 -2100
- package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-C3jVimFn.js} +21 -14
- package/dist/{session-binding-Bcynfd-_.js → session-binding-BHuTCRZQ.js} +198 -127
- package/dist/{session-catalog-DaLKVtpH.js → session-catalog-yyvTWFOw.js} +564 -408
- package/dist/{session-cli-DMc4oS2w.js → session-cli-CmFEXMAM.js} +1 -1
- package/dist/session-history-C5J1AKzG.js +87 -0
- package/dist/session-initialization-BeWzjGiR.js +74 -0
- package/dist/{session-permission-policy-BrNH1bjy.js → session-permission-policy-DeWVTCMj.js} +2 -2
- package/dist/session-retirement-BujDjXVF.js +97 -0
- package/dist/{session-upstream-marker-BIkusb95.js → session-upstream-marker-C351-5Qw.js} +19 -4
- package/dist/settled-turn-context-D3SNWtUn.js +268 -0
- package/dist/settled-turn-finalizer-BVJx4yoc.js +104 -0
- package/dist/{shared-client-DKz23hHY.js → shared-client-DxcfF9KX.js} +3480 -679
- package/dist/{side-question-DjA_jsNe.js → side-question-BTZAII4l.js} +108 -70
- package/dist/{thread-lifecycle-L7oEkTlq.js → thread-lifecycle-DAcEJ_Om.js} +2188 -1915
- package/dist/{thread-ownership-DZeuKH1j.js → thread-ownership-zGokd8i1.js} +25 -14
- package/dist/thread-policy-g4KbJPzp.js +54 -0
- package/dist/{plugin-app-cache-key-C1CAdfcP.js → thread-resume-C7pyVKeW.js} +59 -7
- package/dist/{transcript-mirror-DsCMWBca.js → transcript-mirror-DTUxFWa_.js} +79 -17
- package/dist/transport-stdio-CyPldczm.js +726 -0
- package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
- package/dist/upstream-session-fork-CYlBIGVt.js +966 -0
- package/dist/{usage-ROIaW3wo.js → usage-Bj-rrzkR.js} +3 -3
- package/dist/{web-search-provider.runtime-ClaNPV7N.js → web-search-provider.runtime-D2FWSK4w.js} +3 -3
- package/openclaw.plugin.json +1 -30
- package/package.json +6 -6
- package/dist/command-rpc-CCeCkf_v.js +0 -90
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/model-catalog-i9rNBthX.js +0 -48
- package/dist/protocol-validators-VeJxxJ0U.js +0 -2421
- package/dist/request-DXXGHko0.js +0 -157
- package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
- package/dist/session-retirement-CcNC3YSY.js +0 -36
- package/dist/settled-turn-finalizer-Dc3ApjU4.js +0 -328
- package/dist/thread-resume-BE9qNEW0.js +0 -30
- package/dist/transport-stdio-DhoGy33Z.js +0 -99
- package/dist/upstream-session-fork-DlaHxSLC.js +0 -326
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./session-catalog-
|
|
1
|
+
import "./session-catalog-yyvTWFOw.js";
|
|
2
2
|
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
4
4
|
import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { n as sanitizeCodexHistoryImagePayloads } from "./image-payload-sanitizer-CnfoUPCE.js";
|
|
2
|
+
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import { getSessionEntry, parseSqliteSessionFileMarker, resolveTranscriptSessionKeyBySessionId } from "openclaw/plugin-sdk/session-store-runtime";
|
|
5
|
+
import { SessionManager, buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
|
|
6
|
+
//#region extensions/codex/src/app-server/session-history.ts
|
|
7
|
+
/** Reads model context separately from full-fidelity Codex mirror evidence. */
|
|
8
|
+
/** Returns sanitized session-context messages for consumers that need an owned array. */
|
|
9
|
+
async function readCodexMirroredSessionHistoryMessages(target, admission, view = "native-evidence") {
|
|
10
|
+
return readCodexMirroredSessionHistory(target, (messages) => Array.from(messages), admission, view);
|
|
11
|
+
}
|
|
12
|
+
/** The synchronous consumer can reject before further SQLite message payloads are acquired. */
|
|
13
|
+
async function readCodexMirroredSessionHistory(target, read, admission, view = "native-evidence") {
|
|
14
|
+
const consume = (messages, header, imageLabel = "codex mirrored history") => {
|
|
15
|
+
if (!isRecord(header) || header.type !== "session") return read([]);
|
|
16
|
+
if (typeof header.id !== "string") return;
|
|
17
|
+
if (header.id !== target.sessionId) return read([]);
|
|
18
|
+
return read((function* () {
|
|
19
|
+
for (const message of messages) yield sanitizeCodexHistoryImagePayloads(message, imageLabel);
|
|
20
|
+
})());
|
|
21
|
+
};
|
|
22
|
+
const readTarget = (transcriptTarget) => {
|
|
23
|
+
if (view === "native-evidence") return SessionManager.readSessionContext(transcriptTarget, consume, { admission });
|
|
24
|
+
const loaded = SessionManager.openModelContext(transcriptTarget, { admission });
|
|
25
|
+
return consume(loaded.buildSessionContext().messages, loaded.getHeader(), "codex mirrored model context");
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
if (target.sessionTarget) {
|
|
29
|
+
const { agentId, sessionId, sessionKey, storePath } = target.sessionTarget;
|
|
30
|
+
if (!agentId || !sessionId || !sessionKey || !storePath || sessionId !== target.sessionId || target.agentId !== void 0 && agentId !== target.agentId || target.sessionKey !== void 0 && sessionKey !== target.sessionKey) return read([]);
|
|
31
|
+
return readTarget({
|
|
32
|
+
agentId,
|
|
33
|
+
sessionId,
|
|
34
|
+
sessionKey,
|
|
35
|
+
storePath
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const sqliteMarker = parseSqliteSessionFileMarker(target.sessionFile);
|
|
39
|
+
if (sqliteMarker) {
|
|
40
|
+
if (sqliteMarker.sessionId !== target.sessionId || target.agentId !== void 0 && sqliteMarker.agentId !== target.agentId) return read([]);
|
|
41
|
+
const sessionKey = resolveSqliteMarkerSessionKey(target, sqliteMarker);
|
|
42
|
+
if (!sessionKey) return read([]);
|
|
43
|
+
return readTarget({
|
|
44
|
+
agentId: sqliteMarker.agentId,
|
|
45
|
+
sessionId: sqliteMarker.sessionId,
|
|
46
|
+
sessionKey,
|
|
47
|
+
storePath: sqliteMarker.storePath
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (admission) {
|
|
51
|
+
if (admission.sessionId !== target.sessionId || target.agentId !== void 0 && admission.agentId !== target.agentId || target.sessionKey !== void 0 && admission.sessionKey !== target.sessionKey) return read([]);
|
|
52
|
+
return readTarget({
|
|
53
|
+
agentId: admission.agentId,
|
|
54
|
+
sessionId: admission.sessionId,
|
|
55
|
+
sessionKey: admission.sessionKey,
|
|
56
|
+
storePath: admission.storePath
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const entries = parseSessionEntries(await fs.readFile(target.sessionFile, "utf-8"));
|
|
60
|
+
return consume((function* () {
|
|
61
|
+
migrateSessionEntries(entries);
|
|
62
|
+
const sessionEntries = entries.filter((entry) => isRecord(entry) && entry.type !== "session");
|
|
63
|
+
yield* buildSessionContext(sessionEntries).messages;
|
|
64
|
+
})(), entries[0]);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (isRecord(error) && error.code === "ENOENT") return read([]);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function resolveSqliteMarkerSessionKey(target, marker) {
|
|
71
|
+
const explicitSessionKey = target.sessionKey?.trim();
|
|
72
|
+
if (explicitSessionKey) {
|
|
73
|
+
const explicitEntry = getSessionEntry({
|
|
74
|
+
agentId: marker.agentId,
|
|
75
|
+
sessionKey: explicitSessionKey,
|
|
76
|
+
storePath: marker.storePath
|
|
77
|
+
});
|
|
78
|
+
if (explicitEntry) return explicitEntry.sessionId === marker.sessionId ? explicitSessionKey : void 0;
|
|
79
|
+
}
|
|
80
|
+
return resolveTranscriptSessionKeyBySessionId({
|
|
81
|
+
agentId: marker.agentId,
|
|
82
|
+
sessionId: marker.sessionId,
|
|
83
|
+
storePath: marker.storePath
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
export { readCodexMirroredSessionHistoryMessages as n, readCodexMirroredSessionHistory as t };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { p as validateBindingForWrite } from "./session-binding-BHuTCRZQ.js";
|
|
2
|
+
import { isDeepStrictEqual } from "node:util";
|
|
3
|
+
import { deleteSessionUpstreamLink, upsertSessionUpstreamLink } from "openclaw/plugin-sdk/session-catalog";
|
|
4
|
+
//#region extensions/codex/src/app-server/session-initialization.ts
|
|
5
|
+
const initializations = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
/** Associate the host's exact handle before any potentially committing plugin write. */
|
|
7
|
+
function prepareCodexSessionInitialization(params) {
|
|
8
|
+
const { initialization, bindingStore, identity } = params;
|
|
9
|
+
initialization.assertCurrent();
|
|
10
|
+
let link;
|
|
11
|
+
const ownership = {
|
|
12
|
+
store: bindingStore,
|
|
13
|
+
identity: structuredClone(identity),
|
|
14
|
+
assertCleanupAllowed: params.assertCleanupAllowed,
|
|
15
|
+
cleanup: async () => {
|
|
16
|
+
initialization.assertRollbackCurrent();
|
|
17
|
+
if (link && deleteSessionUpstreamLink(link.sessionKey, link.agentId, {
|
|
18
|
+
expected: link,
|
|
19
|
+
assertCommitAllowed: initialization.assertRollbackCurrent
|
|
20
|
+
}) === "changed") throw new Error("Codex initialization link changed before cleanup");
|
|
21
|
+
initialization.assertRollbackCurrent();
|
|
22
|
+
await cleanup?.(initialization.assertRollbackCurrent);
|
|
23
|
+
initialization.assertRollbackCurrent();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
initializations.set(initialization, ownership);
|
|
27
|
+
const cleanup = params.prepareCleanup?.();
|
|
28
|
+
return {
|
|
29
|
+
assertCurrent: initialization.assertCurrent,
|
|
30
|
+
async bind(binding) {
|
|
31
|
+
initialization.assertCurrent();
|
|
32
|
+
ownership.binding = validateBindingForWrite(binding);
|
|
33
|
+
if (!await bindingStore.mutate(identity, {
|
|
34
|
+
kind: "set",
|
|
35
|
+
if: { kind: "absent" },
|
|
36
|
+
binding: ownership.binding
|
|
37
|
+
}, initialization.assertCurrent)) {
|
|
38
|
+
ownership.binding = void 0;
|
|
39
|
+
throw new Error("Codex session binding changed during initialization");
|
|
40
|
+
}
|
|
41
|
+
initialization.assertCurrent();
|
|
42
|
+
},
|
|
43
|
+
link(input) {
|
|
44
|
+
initialization.assertCurrent();
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
link = structuredClone({
|
|
47
|
+
...input,
|
|
48
|
+
createdAt: now,
|
|
49
|
+
updatedAt: now
|
|
50
|
+
});
|
|
51
|
+
if (!upsertSessionUpstreamLink(input, {
|
|
52
|
+
now,
|
|
53
|
+
ifAbsent: true,
|
|
54
|
+
assertCommitAllowed: initialization.assertCurrent
|
|
55
|
+
})) {
|
|
56
|
+
link = void 0;
|
|
57
|
+
throw new Error("Codex initialization link could not be persisted");
|
|
58
|
+
}
|
|
59
|
+
initialization.assertCurrent();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function getCodexSessionInitializationRollback(store, params, identity, binding) {
|
|
64
|
+
const handle = params.initialization;
|
|
65
|
+
if (!handle) return;
|
|
66
|
+
handle.assertRollbackCurrent();
|
|
67
|
+
const ownership = initializations.get(handle);
|
|
68
|
+
if (!ownership && !binding) return;
|
|
69
|
+
if (!ownership || ownership.store !== store || !isDeepStrictEqual(ownership.identity, identity) || binding && !isDeepStrictEqual(ownership.binding, binding)) throw new Error("Codex initialization binding owner changed before rollback");
|
|
70
|
+
ownership.assertCleanupAllowed?.();
|
|
71
|
+
return ownership.cleanup;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { prepareCodexSessionInitialization as n, getCodexSessionInitializationRollback as t };
|
package/dist/{session-permission-policy-BrNH1bjy.js → session-permission-policy-DeWVTCMj.js}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { hostname } from "node:os";
|
|
1
|
+
import { S as selectUserApprovalsReviewer, _ as parseAllowedApprovalsReviewersFromCodexRequirements, b as selectGuardianApprovalPolicy, g as parseAllowedApprovalPoliciesFromCodexRequirements, k as selectGuardianSandbox, m as canUseCodexModelBackedApprovalsReviewerForModel, u as resolveCodexAppServerNetworkProxy, v as parseAllowedSandboxModesFromCodexRequirements, x as selectGuardianApprovalsReviewer } from "./config-BhmfC1s6.js";
|
|
3
2
|
import { isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
|
|
3
|
+
import { hostname } from "node:os";
|
|
4
4
|
//#region extensions/codex/src/app-server/app-server-policy.ts
|
|
5
5
|
function resolveCodexAppServerForModelProvider(params) {
|
|
6
6
|
const explicitProvider = normalizeModelBackedReviewerProvider(params.provider);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Et as isCodexAppServerLiveThreadClaimed, _ as retainSharedCodexAppServerClientByInstanceId, kt as releaseCodexAppServerLiveThread, wt as hasCodexAppServerLiveThread } from "./shared-client-DxcfF9KX.js";
|
|
2
|
+
import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-DYHcRQAa.js";
|
|
3
|
+
import { l as isIncognitoSessionKey, o as withCodexAppServerThreadMutation, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-zGokd8i1.js";
|
|
4
|
+
import { t as getCodexSessionInitializationRollback } from "./session-initialization-BeWzjGiR.js";
|
|
5
|
+
import { t as codexNativeSubagentMonitorRuntime } from "./native-subagent-monitor-CnH147jH.js";
|
|
6
|
+
//#region extensions/codex/src/app-server/session-retirement.ts
|
|
7
|
+
async function releaseSessionSubscription(client, binding, sessionKey, assertCurrent) {
|
|
8
|
+
assertCurrent?.();
|
|
9
|
+
codexNativeSubagentMonitorRuntime.retireParent(client, binding.threadId);
|
|
10
|
+
const released = await releaseCodexAppServerLiveThread(client, binding.threadId, assertCurrent);
|
|
11
|
+
assertCurrent?.();
|
|
12
|
+
if (!released && isIncognitoSessionKey(sessionKey)) {
|
|
13
|
+
const unsubscribed = await unsubscribeCodexThreadBestEffort(client, {
|
|
14
|
+
threadId: binding.threadId,
|
|
15
|
+
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS,
|
|
16
|
+
assertCurrent
|
|
17
|
+
});
|
|
18
|
+
assertCurrent?.();
|
|
19
|
+
if (!unsubscribed) {
|
|
20
|
+
await closeCodexStartupClientBestEffort(client);
|
|
21
|
+
throw new CodexAppServerUnsafeSubscriptionError(`Codex retired session subscription could not be released: ${binding.threadId}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Prepare exact binding deletion before the session owner commits either database. */
|
|
26
|
+
async function withCodexAppServerSessionDeletion(bindingStore, params, run) {
|
|
27
|
+
const { assertCurrent } = params;
|
|
28
|
+
const identity = {
|
|
29
|
+
kind: "session",
|
|
30
|
+
agentId: params.agentId,
|
|
31
|
+
sessionKey: params.sessionKey,
|
|
32
|
+
sessionId: params.sessionId
|
|
33
|
+
};
|
|
34
|
+
const remove = () => bindingStore.withSessionDeletion(identity, assertCurrent, async (binding, mutation) => {
|
|
35
|
+
assertCurrent();
|
|
36
|
+
const rollbackInitialization = getCodexSessionInitializationRollback(bindingStore, params, identity, binding);
|
|
37
|
+
if (binding?.connectionScope === "supervision" && !rollbackInitialization) throw new Error("Cannot delete a session while its Codex binding is owned by supervision");
|
|
38
|
+
const clientLease = binding?.clientId ? retainSharedCodexAppServerClientByInstanceId(binding.clientId) : void 0;
|
|
39
|
+
const assertUnclaimed = () => {
|
|
40
|
+
assertCurrent();
|
|
41
|
+
if (clientLease && binding && isCodexAppServerLiveThreadClaimed(clientLease.client, binding.threadId)) throw new Error("Cannot delete a session while its Codex thread is claimed by active work");
|
|
42
|
+
};
|
|
43
|
+
let committed = false;
|
|
44
|
+
try {
|
|
45
|
+
assertUnclaimed();
|
|
46
|
+
return await run({
|
|
47
|
+
commit() {
|
|
48
|
+
assertUnclaimed();
|
|
49
|
+
mutation.commit();
|
|
50
|
+
committed = true;
|
|
51
|
+
},
|
|
52
|
+
rollback() {
|
|
53
|
+
mutation.rollback();
|
|
54
|
+
committed = false;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
} finally {
|
|
58
|
+
try {
|
|
59
|
+
if (committed && rollbackInitialization) {
|
|
60
|
+
assertCurrent();
|
|
61
|
+
await rollbackInitialization();
|
|
62
|
+
}
|
|
63
|
+
if (committed && binding && clientLease) await withCodexAppServerThreadMutation(binding.threadId, async () => {
|
|
64
|
+
assertCurrent();
|
|
65
|
+
if (!hasCodexAppServerLiveThread(clientLease.client, binding.threadId) && !isIncognitoSessionKey(params.sessionKey)) return;
|
|
66
|
+
if (await bindingStore.hasOtherThreadOwner(binding.threadId)) return;
|
|
67
|
+
await releaseSessionSubscription(clientLease.client, binding, params.sessionKey, assertUnclaimed);
|
|
68
|
+
});
|
|
69
|
+
} finally {
|
|
70
|
+
clientLease?.release();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return params.initialization ? await bindingStore.withThreadArchiveFence(remove) : await remove();
|
|
75
|
+
}
|
|
76
|
+
/** Retire binding and native subscription under the same generation/physical-client ownership fence. */
|
|
77
|
+
async function retireCodexAppServerSessionGeneration(params) {
|
|
78
|
+
const retireGeneration = () => params.mode === "reset" ? params.bindingStore.resetSessionGeneration(params.identity) : params.bindingStore.retireSessionGeneration(params.identity);
|
|
79
|
+
const expectedBinding = await params.bindingStore.read(params.identity);
|
|
80
|
+
if (!expectedBinding) return await retireGeneration();
|
|
81
|
+
return await withCodexAppServerThreadMutation(expectedBinding.threadId, () => params.bindingStore.withLease(params.identity, async () => {
|
|
82
|
+
const binding = await params.bindingStore.read(params.identity);
|
|
83
|
+
if (!binding || !isSameCodexAppServerThreadOwner(binding, expectedBinding)) return "conflict";
|
|
84
|
+
const result = await retireGeneration();
|
|
85
|
+
if (result !== "applied" || !binding?.clientId) return result;
|
|
86
|
+
const clientLease = retainSharedCodexAppServerClientByInstanceId(binding.clientId);
|
|
87
|
+
if (!clientLease) return result;
|
|
88
|
+
try {
|
|
89
|
+
await releaseSessionSubscription(clientLease.client, binding, params.identity.sessionKey);
|
|
90
|
+
} finally {
|
|
91
|
+
clientLease.release();
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { retireCodexAppServerSessionGeneration, withCodexAppServerSessionDeletion };
|
|
@@ -1,20 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as sessionBindingIdentity } from "./session-binding-BHuTCRZQ.js";
|
|
2
|
+
import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-DTUxFWa_.js";
|
|
3
|
+
import { n as prepareCodexSessionInitialization } from "./session-initialization-BeWzjGiR.js";
|
|
2
4
|
import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
3
5
|
//#region extensions/codex/src/app-server/session-history-import.ts
|
|
4
6
|
/** Creates a session whose transcript is derived from one verified Codex thread snapshot. */
|
|
5
7
|
async function createImportedCodexSession(params) {
|
|
6
|
-
const label = params.thread.name?.trim() || void 0;
|
|
7
8
|
const spawnedCwd = params.thread.cwd?.trim() || void 0;
|
|
8
9
|
const createParams = {
|
|
9
10
|
cfg: params.config,
|
|
10
11
|
key: params.key,
|
|
11
12
|
agentId: params.agentId,
|
|
12
|
-
...
|
|
13
|
+
...params.displayName !== void 0 ? { displayName: params.displayName } : {},
|
|
13
14
|
...spawnedCwd ? { spawnedCwd } : {},
|
|
14
15
|
initialEntry: params.initialEntry,
|
|
15
16
|
afterCreate: async (entry) => {
|
|
17
|
+
if (!entry.initialization) throw new Error("Codex history initialization requires host creation authority");
|
|
18
|
+
const initialization = prepareCodexSessionInitialization({
|
|
19
|
+
initialization: entry.initialization,
|
|
20
|
+
bindingStore: params.bindingStore,
|
|
21
|
+
identity: sessionBindingIdentity({
|
|
22
|
+
agentId: entry.agentId,
|
|
23
|
+
sessionId: entry.sessionId,
|
|
24
|
+
sessionKey: entry.key,
|
|
25
|
+
config: params.config
|
|
26
|
+
}),
|
|
27
|
+
prepareCleanup: params.prepareCleanup
|
|
28
|
+
});
|
|
16
29
|
const storePath = resolveStorePath(params.config.session?.store, { agentId: entry.agentId });
|
|
17
30
|
await importCodexThreadHistoryToTranscript({
|
|
31
|
+
assertCurrent: entry.initialization.assertCurrent,
|
|
18
32
|
thread: params.thread,
|
|
19
33
|
throughTurnId: params.throughTurnId,
|
|
20
34
|
storePath,
|
|
@@ -25,7 +39,8 @@ async function createImportedCodexSession(params) {
|
|
|
25
39
|
modelProvider: params.thread.modelProvider,
|
|
26
40
|
config: params.config
|
|
27
41
|
});
|
|
28
|
-
|
|
42
|
+
entry.initialization.assertCurrent();
|
|
43
|
+
return await params.afterImport(entry, initialization);
|
|
29
44
|
}
|
|
30
45
|
};
|
|
31
46
|
return params.recoverMatchingInitialEntry ? await params.runtime.agent.session.createSessionEntry({
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { d as serializeCodexMirrorSourceEvidence } from "./transcript-mirror-DTUxFWa_.js";
|
|
2
|
+
import { i as readUpstreamUserText, r as readMirrorIdentity } from "./upstream-prompt-provenance-LphB8slG.js";
|
|
3
|
+
import { t as readCodexMirroredSessionHistory } from "./session-history-C5J1AKzG.js";
|
|
4
|
+
import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import { embeddedAgentLog, formatErrorMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
6
|
+
import { Buffer } from "node:buffer";
|
|
7
|
+
//#region extensions/codex/src/app-server/settled-turn-projection.ts
|
|
8
|
+
const MAX_RESPONSE_ITEMS = 200;
|
|
9
|
+
const MAX_PROJECTION_BYTES = 524288;
|
|
10
|
+
const MAX_TEXT_BYTES = 65536;
|
|
11
|
+
const TOOL_NAME_PATTERN = /^[a-zA-Z0-9._-]{1,128}$/u;
|
|
12
|
+
const TOOL_ERROR_STATUS_PREFIX = "[Tool result status: error]\n";
|
|
13
|
+
function readBoundedText(value, label, maxBytes = MAX_TEXT_BYTES) {
|
|
14
|
+
if (typeof value !== "string" || !value.trim()) return;
|
|
15
|
+
if (Buffer.byteLength(value, "utf8") > maxBytes) throw new Error(`Codex settled-turn projection found oversized ${label}`);
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function requireBoundedText(value, label, maxBytes = MAX_TEXT_BYTES) {
|
|
19
|
+
const text = readBoundedText(value, label, maxBytes);
|
|
20
|
+
if (!text) throw new Error(`Codex settled-turn projection found empty ${label}`);
|
|
21
|
+
return text;
|
|
22
|
+
}
|
|
23
|
+
function responseItemBytes(item) {
|
|
24
|
+
return Buffer.byteLength(JSON.stringify(item), "utf8");
|
|
25
|
+
}
|
|
26
|
+
function requireCallId(value) {
|
|
27
|
+
const callId = normalizeOptionalString(value);
|
|
28
|
+
if (!callId || callId.length > 256) throw new Error("Codex settled-turn projection found an invalid tool call id");
|
|
29
|
+
return callId;
|
|
30
|
+
}
|
|
31
|
+
function requireToolName(value) {
|
|
32
|
+
const name = normalizeOptionalString(value);
|
|
33
|
+
if (!name || !TOOL_NAME_PATTERN.test(name)) throw new Error(`Codex settled-turn projection found an invalid tool name${name ? `: ${name.slice(0, 64)}` : ""}`);
|
|
34
|
+
return name;
|
|
35
|
+
}
|
|
36
|
+
function serializeToolArguments(value) {
|
|
37
|
+
if (typeof value === "string") {
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(value);
|
|
41
|
+
} catch {
|
|
42
|
+
throw new Error("Codex settled-turn projection found invalid JSON tool arguments");
|
|
43
|
+
}
|
|
44
|
+
if (!isRecord(parsed)) throw new Error("Codex settled-turn projection requires object tool arguments");
|
|
45
|
+
return requireBoundedText(value, "tool arguments");
|
|
46
|
+
}
|
|
47
|
+
if (!isRecord(value)) throw new Error("Codex settled-turn projection requires object tool arguments");
|
|
48
|
+
let serialized;
|
|
49
|
+
try {
|
|
50
|
+
serialized = JSON.stringify(value);
|
|
51
|
+
} catch {
|
|
52
|
+
throw new Error("Codex settled-turn projection found unserializable tool arguments");
|
|
53
|
+
}
|
|
54
|
+
return requireBoundedText(serialized, "tool arguments");
|
|
55
|
+
}
|
|
56
|
+
function projectUserMessage(message) {
|
|
57
|
+
const upstreamUserText = readUpstreamUserText(message);
|
|
58
|
+
if (typeof message.content === "string") return {
|
|
59
|
+
type: "message",
|
|
60
|
+
role: "user",
|
|
61
|
+
content: [{
|
|
62
|
+
type: "input_text",
|
|
63
|
+
text: upstreamUserText ? requireBoundedText(upstreamUserText, "upstream user text", MAX_PROJECTION_BYTES) : requireBoundedText(message.content, "user message")
|
|
64
|
+
}]
|
|
65
|
+
};
|
|
66
|
+
if (!Array.isArray(message.content)) throw new Error("Codex settled-turn projection found unsupported user content");
|
|
67
|
+
const content = [];
|
|
68
|
+
let bytes = responseItemBytes({
|
|
69
|
+
type: "message",
|
|
70
|
+
role: "user",
|
|
71
|
+
content
|
|
72
|
+
});
|
|
73
|
+
for (const value of message.content) {
|
|
74
|
+
if (!isRecord(value)) throw new Error("Codex settled-turn projection found malformed user content");
|
|
75
|
+
if (value.type !== "text") throw new Error(`Codex settled-turn projection does not support user content ${value.type}`);
|
|
76
|
+
const text = readBoundedText(value.text, "user text");
|
|
77
|
+
if (text) {
|
|
78
|
+
const part = {
|
|
79
|
+
type: "input_text",
|
|
80
|
+
text
|
|
81
|
+
};
|
|
82
|
+
bytes += responseItemBytes(part) + (content.length > 0 ? 1 : 0);
|
|
83
|
+
if (bytes > MAX_PROJECTION_BYTES) throw new Error("Codex settled-turn projection exceeds the byte limit");
|
|
84
|
+
content.push(part);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (content.length === 0) throw new Error("Codex settled-turn projection found an empty user message");
|
|
88
|
+
return {
|
|
89
|
+
type: "message",
|
|
90
|
+
role: "user",
|
|
91
|
+
content
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function* projectAssistantMessage(message) {
|
|
95
|
+
const values = typeof message.content === "string" ? [{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: message.content
|
|
98
|
+
}] : message.content;
|
|
99
|
+
if (!Array.isArray(values)) throw new Error("Codex settled-turn projection found unsupported assistant content");
|
|
100
|
+
for (const value of values) {
|
|
101
|
+
if (!isRecord(value)) throw new Error("Codex settled-turn projection found malformed assistant content");
|
|
102
|
+
if (value.type === "text") {
|
|
103
|
+
const text = readBoundedText(value.text, "assistant text");
|
|
104
|
+
if (text) yield { item: {
|
|
105
|
+
type: "message",
|
|
106
|
+
role: "assistant",
|
|
107
|
+
content: [{
|
|
108
|
+
type: "output_text",
|
|
109
|
+
text
|
|
110
|
+
}]
|
|
111
|
+
} };
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (value.type === "toolCall") {
|
|
115
|
+
const id = requireCallId(value.id ?? value.toolCallId);
|
|
116
|
+
const name = requireToolName(value.name ?? value.toolName);
|
|
117
|
+
yield {
|
|
118
|
+
call: {
|
|
119
|
+
id,
|
|
120
|
+
name
|
|
121
|
+
},
|
|
122
|
+
item: {
|
|
123
|
+
type: "function_call",
|
|
124
|
+
call_id: id,
|
|
125
|
+
name,
|
|
126
|
+
arguments: serializeToolArguments(value.arguments ?? value.input)
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (value.type === "thinking" || value.type === "reasoning") continue;
|
|
132
|
+
throw new Error(`Codex settled-turn projection does not support assistant content ${String(value.type)}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function projectToolResult(message) {
|
|
136
|
+
const id = requireCallId(message.toolCallId);
|
|
137
|
+
const name = requireToolName(message.toolName);
|
|
138
|
+
if (!Array.isArray(message.content)) throw new Error("Codex settled-turn projection found unsupported tool result content");
|
|
139
|
+
const isErrorValue = message.isError;
|
|
140
|
+
if (isErrorValue !== void 0 && typeof isErrorValue !== "boolean") throw new Error("Codex settled-turn projection found invalid tool result status");
|
|
141
|
+
const isError = isErrorValue === true;
|
|
142
|
+
const parts = [];
|
|
143
|
+
let bytes = 0;
|
|
144
|
+
const appendText = (text) => {
|
|
145
|
+
bytes += Buffer.byteLength(text, "utf8") + (parts.length > 0 ? 1 : 0);
|
|
146
|
+
if (bytes > MAX_TEXT_BYTES) throw new Error("Codex settled-turn projection found oversized tool result output");
|
|
147
|
+
parts.push(text);
|
|
148
|
+
};
|
|
149
|
+
for (const value of message.content) {
|
|
150
|
+
if (!isRecord(value)) throw new Error("Codex settled-turn projection found malformed tool result content");
|
|
151
|
+
if (value.type === "image") {
|
|
152
|
+
appendText(`[Image tool result: ${normalizeOptionalString(value.mimeType) ?? "unknown type"}]`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (value.type !== "text" && value.type !== "toolResult") throw new Error("Codex settled-turn projection found malformed tool result content");
|
|
156
|
+
const text = value.type === "text" ? readBoundedText(value.text, "tool result text") : readBoundedText(value.content ?? value.text, "tool result text");
|
|
157
|
+
if (text) appendText(text);
|
|
158
|
+
}
|
|
159
|
+
const resultText = parts.join("\n") || (isError ? "Tool failed without textual output." : "Tool completed without textual output.");
|
|
160
|
+
const output = requireBoundedText(isError ? `${TOOL_ERROR_STATUS_PREFIX}${resultText}` : resultText, "tool result output", isError ? MAX_TEXT_BYTES + Buffer.byteLength(TOOL_ERROR_STATUS_PREFIX, "utf8") : MAX_TEXT_BYTES);
|
|
161
|
+
return {
|
|
162
|
+
result: {
|
|
163
|
+
id,
|
|
164
|
+
name
|
|
165
|
+
},
|
|
166
|
+
item: {
|
|
167
|
+
type: "function_call_output",
|
|
168
|
+
call_id: id,
|
|
169
|
+
output
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function* projectMessage(message) {
|
|
174
|
+
if (message.role === "user") yield { item: projectUserMessage(message) };
|
|
175
|
+
else if (message.role === "assistant") yield* projectAssistantMessage(message);
|
|
176
|
+
else if (message.role === "toolResult") yield projectToolResult(message);
|
|
177
|
+
else throw new Error(`Codex settled-turn projection does not support role ${message.role}`);
|
|
178
|
+
}
|
|
179
|
+
/** Consumes complete evidence or rejects at the existing limits, never truncating its history. */
|
|
180
|
+
function projectSettledCodexMessages(messages) {
|
|
181
|
+
const items = [];
|
|
182
|
+
const calls = /* @__PURE__ */ new Map();
|
|
183
|
+
const results = /* @__PURE__ */ new Set();
|
|
184
|
+
let bytes = 0;
|
|
185
|
+
for (const message of messages) for (const { item, call, result } of projectMessage(message)) {
|
|
186
|
+
if (call) {
|
|
187
|
+
if (calls.has(call.id)) throw new Error("Codex settled-turn projection found a duplicate tool call");
|
|
188
|
+
calls.set(call.id, call.name);
|
|
189
|
+
}
|
|
190
|
+
if (result) {
|
|
191
|
+
if (calls.get(result.id) !== result.name || results.has(result.id)) throw new Error("Codex settled-turn projection found an ambiguous tool transcript");
|
|
192
|
+
results.add(result.id);
|
|
193
|
+
}
|
|
194
|
+
if (items.length === MAX_RESPONSE_ITEMS) throw new Error("Codex settled-turn projection exceeds the item limit");
|
|
195
|
+
bytes += responseItemBytes(item);
|
|
196
|
+
if (bytes > MAX_PROJECTION_BYTES) throw new Error("Codex settled-turn projection exceeds the byte limit");
|
|
197
|
+
items.push(item);
|
|
198
|
+
}
|
|
199
|
+
if (calls.size !== results.size) throw new Error("Codex settled-turn projection found an incomplete tool transcript");
|
|
200
|
+
if (results.size === 0) throw new Error("Codex settled-turn projection found no completed tool result");
|
|
201
|
+
return items;
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region extensions/codex/src/app-server/settled-turn-context.ts
|
|
205
|
+
function freezeProjection(value) {
|
|
206
|
+
if (value !== null && typeof value === "object") {
|
|
207
|
+
for (const child of Object.values(value)) freezeProjection(child);
|
|
208
|
+
Object.freeze(value);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/** Only the Codex owner interprets this bounded, detached replay projection. */
|
|
212
|
+
var CodexSettledTurnContext = class {
|
|
213
|
+
constructor(data) {
|
|
214
|
+
this.data = data;
|
|
215
|
+
this.source = "harness";
|
|
216
|
+
freezeProjection(data);
|
|
217
|
+
Object.freeze(this);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
function rejectEvidence() {
|
|
221
|
+
throw new Error("Codex settled-turn transcript does not match the settled turn");
|
|
222
|
+
}
|
|
223
|
+
/** Yields only the settled prefix, but exhausts suffix identity checks before accepting it. */
|
|
224
|
+
function* verifiedSettledMessages(history, params) {
|
|
225
|
+
const promptIdentity = `${params.turnId}:prompt`;
|
|
226
|
+
const boundaryIndex = params.settledMessages.findLastIndex((message) => message.role === "toolResult");
|
|
227
|
+
const boundary = params.settledMessages[boundaryIndex];
|
|
228
|
+
const boundaryIdentity = boundary && readMirrorIdentity(boundary);
|
|
229
|
+
const requiredIds = params.settledMessages.slice(0, boundaryIndex + 1).flatMap((message) => readMirrorIdentity(message) ?? []);
|
|
230
|
+
if (!boundaryIdentity?.startsWith(`${params.turnId}:tool:`) || requiredIds.length !== boundaryIndex + 1 || new Set(requiredIds).size !== requiredIds.length || !requiredIds.includes(promptIdentity)) rejectEvidence();
|
|
231
|
+
const mirrored = params.mirroredMessages;
|
|
232
|
+
const mirroredIds = mirrored.flatMap((message) => readMirrorIdentity(message) ?? []);
|
|
233
|
+
const mirroredBoundaryIndex = mirrored.findIndex((message) => readMirrorIdentity(message) === boundaryIdentity);
|
|
234
|
+
if (new Set(mirroredIds).size !== mirroredIds.length || mirroredBoundaryIndex + 1 !== requiredIds.length || requiredIds.some((id, index) => readMirrorIdentity(mirrored[index]) !== id)) rejectEvidence();
|
|
235
|
+
const required = new Map(requiredIds.map((id, index) => [id, mirrored[index]]));
|
|
236
|
+
const seen = /* @__PURE__ */ new Set();
|
|
237
|
+
let matched = 0;
|
|
238
|
+
let throughBoundary = false;
|
|
239
|
+
for (const message of history) {
|
|
240
|
+
const identity = readMirrorIdentity(message);
|
|
241
|
+
if (identity) {
|
|
242
|
+
if (seen.has(identity)) rejectEvidence();
|
|
243
|
+
seen.add(identity);
|
|
244
|
+
const expected = required.get(identity);
|
|
245
|
+
if (expected) {
|
|
246
|
+
if (identity !== requiredIds[matched] || serializeCodexMirrorSourceEvidence(message) !== serializeCodexMirrorSourceEvidence(expected)) rejectEvidence();
|
|
247
|
+
matched += 1;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (!throughBoundary) yield message;
|
|
251
|
+
throughBoundary ||= identity === boundaryIdentity;
|
|
252
|
+
}
|
|
253
|
+
if (!throughBoundary || matched !== requiredIds.length) rejectEvidence();
|
|
254
|
+
}
|
|
255
|
+
/** Verifies and freezes a complete replay projection while reading the active branch. */
|
|
256
|
+
async function captureCodexSettledTurnFinalizationContext(params) {
|
|
257
|
+
try {
|
|
258
|
+
return await readCodexMirroredSessionHistory(params, (messages) => new CodexSettledTurnContext(projectSettledCodexMessages(verifiedSettledMessages(messages, params))));
|
|
259
|
+
} catch (error) {
|
|
260
|
+
embeddedAgentLog.warn("codex settled-turn finalization context capture failed", {
|
|
261
|
+
error: formatErrorMessage(error),
|
|
262
|
+
turnId: params.turnId
|
|
263
|
+
});
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
//#endregion
|
|
268
|
+
export { captureCodexSettledTurnFinalizationContext as n, CodexSettledTurnContext as t };
|