@openclaw/codex 2026.9.3 → 2026.9.4
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 +26 -18
- package/dist/{apply-B6el6hdO.js → apply-CvT8tW5i.js} +11 -12
- package/dist/{attempt-client-cleanup-D6cR54TV.js → attempt-client-cleanup-DKHzbwt5.js} +8 -204
- package/dist/{attempt-context-AO4DSjE0.js → attempt-context-D44yeDII.js} +3 -3
- package/dist/{attempt-notifications--H8zXR5-.js → attempt-notifications-C9XufG6l.js} +1 -1
- package/dist/{auth-binding-Co2Vfcf_.js → auth-binding-CWlKVccJ.js} +1 -1
- package/dist/{auth-cache-key-Kq6oerr6.js → auth-cache-key-7orQae_j.js} +2 -2
- package/dist/{binding-connection-QqgcPCgk.js → binding-connection-D3udKbIE.js} +3 -3
- package/dist/{bounded-turn-lRpmZHFv.js → bounded-turn-C_Hneydj.js} +12 -12
- package/dist/{build-state-6RL6qohz.js → build-state-BCmg9-5p.js} +1 -1
- package/dist/{capabilities-BeqLPbtM.js → capabilities-8vx68WLH.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{client-BEKu4yDx.js → client-B57KWPQx.js} +27 -5
- package/dist/{command-dispatch-CisT9Jqq.js → command-dispatch-BpduNGVf.js} +3 -3
- package/dist/{command-formatters-DeTfrapr.js → command-formatters-lxlkNZgU.js} +4 -3
- package/dist/{command-handlers-BfIsJEuA.js → command-handlers-tiL9iWj7.js} +783 -140
- package/dist/{command-rpc-BMqRQOFX.js → command-rpc-CR5EOEZX.js} +26 -19
- package/dist/{compact-CGJZ2rlb.js → compact-B_H3AOd7.js} +14 -14
- package/dist/{config-JDfTI4VI.js → config-oIORaQ5T.js} +4 -4
- package/dist/{config-options-jnIFvwxD.js → config-options-CXMq1T-C.js} +5 -5
- package/dist/{config-runtime-BWf6JLWG.js → config-runtime-D0zGNIHu.js} +1 -1
- package/dist/{config-utils-C57JiJrU.js → config-utils-DujwEnhg.js} +2 -4
- package/dist/{conversation-binding-CxOlHiix.js → conversation-binding-DsB4-O7U.js} +53 -42
- package/dist/{conversation-control-CUCrSIQI.js → conversation-control-CtUu1b3m.js} +8 -8
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{dynamic-tools-D-JBoaLt.js → dynamic-tools-CmN5RAip.js} +76 -15
- package/dist/{effective-mcp-catalog-J_5Ep5Um.js → effective-mcp-catalog-Bd73bqA8.js} +3 -3
- package/dist/{ephemeral-turn-DSwzP8YY.js → ephemeral-turn-D78_VmzO.js} +5 -5
- package/dist/event-projector-items-5VhsECCO.js +200 -0
- package/dist/{event-projector-usage-CIyrYYid.js → event-projector-usage-BfXmpOec.js} +1 -1
- package/dist/{harness-FR6eQgyO.js → harness-C7rRa7bm.js} +33 -16
- package/dist/harness.js +1 -1
- package/dist/index.js +39 -84
- package/dist/inference-context-Dr_mzvk4.js +94 -0
- package/dist/inference-proxy-HGXKUIre.js +311 -0
- package/dist/{isolated-completion-DHBefrzg.js → isolated-completion-DWVb5U2J.js} +6 -6
- package/dist/{managed-binary-DrjjRRUD.js → managed-binary-D22rNEcR.js} +10 -1
- package/dist/media-understanding-provider.js +2 -2
- package/dist/migration-provider-api.js +2 -0
- package/dist/{model-catalog-B_6M04Wo.js → model-catalog-Dq2n8f_p.js} +6 -6
- package/dist/{models-P9k2qAof.js → models-PCKOim-h.js} +3 -3
- package/dist/native-subagent-history-DjtPloaU.js +140 -0
- package/dist/native-subagent-history-owner-Pcp7JuVF.js +34 -0
- package/dist/{native-subagent-monitor-BbCUKRwC.js → native-subagent-monitor-fQ7eIXEf.js} +52 -424
- package/dist/native-subagent-task-ids-BzTdT0Uw.js +387 -0
- package/dist/{node-cli-sessions-rj0ysJwM.js → node-cli-sessions-DKaOmVUh.js} +1 -1
- package/dist/{node-exec-server.runtime-BY_ctYnT.js → node-exec-server.runtime-Cl2vapEi.js} +3 -3
- package/dist/{plan-BMJdMOEF.js → plan-7uG-Fp36.js} +288 -52
- package/dist/{plugin-activation-BQK-f5sV.js → plugin-activation-BYQculil.js} +24 -19
- package/dist/{plugin-app-cache-key-CdSQzWyX.js → plugin-app-cache-key-d0eKxy7b.js} +1 -1
- package/dist/{plugin-approval-roundtrip-DeW95wB5.js → plugin-approval-roundtrip-Bz3FT8W5.js} +1 -1
- package/dist/{plugin-inventory-CoRCzWW4.js → plugin-inventory-oL4Na1ZG.js} +7 -4
- package/dist/{plugin-marketplace-discovery-3akBizzF.js → plugin-marketplace-discovery-P-Vndfqq.js} +18 -15
- package/dist/{plugin-metadata-cache-DgNfRAGA.js → plugin-metadata-cache-ClPJpRio.js} +13 -9
- package/dist/{protocol-CAAcVIKF.js → protocol-5bh1G-H7.js} +1 -1
- package/dist/provider-MQ8PVkuE.js +50 -0
- package/dist/{provider-capabilities-W4tfK5Y5.js → provider-capabilities-BvCUL69A.js} +2 -2
- package/dist/{rate-limits-Bqnx1N4z.js → rate-limits-CBMmWBr9.js} +1 -1
- package/dist/{request-CGvGOpeR.js → request-B7hEkBGq.js} +72 -58
- package/dist/rpc-error-ttN_QjEm.js +30 -0
- package/dist/{run-attempt-DwKds3DN.js → run-attempt-CvsAAGa0.js} +108 -37
- package/dist/{runtime-artifact-T-NwqeSH.js → runtime-artifact-BJ0rXBZ_.js} +1 -1
- package/dist/{sandbox-guard-BcT66fWy.js → sandbox-guard-BxgyoM8M.js} +2 -1
- package/dist/{session-binding-CKSepwIC.js → session-binding-CI8UuilT.js} +3 -3
- package/dist/{session-binding-record-CaZjYwNS.js → session-binding-record-Bcvslnhf.js} +1 -1
- package/dist/{session-catalog-adoption-BKLtSrwi.js → session-catalog-adoption-tcZi1IfX.js} +5 -5
- package/dist/{session-catalog-archive-D0i2pGj2.js → session-catalog-archive-CwKg8Xz2.js} +6 -6
- package/dist/{session-catalog-HaDcp7Sv.js → session-catalog-ct-AH01I.js} +31 -87
- package/dist/session-catalog-home-id-CwhLdC03.js +18 -0
- package/dist/{session-catalog-node-adoption-BUuDYY8R.js → session-catalog-node-adoption-B1tgDW-m.js} +2 -2
- package/dist/{session-catalog-node-continue-CBtc4wkI.js → session-catalog-node-continue-Ci-DXyJP.js} +4 -4
- package/dist/{session-catalog-provenance-DkJHo735.js → session-catalog-provenance-D-dIfRAH.js} +2 -30
- package/dist/{session-cli-CbgaHh0f.js → session-cli-DNN_jhGc.js} +2 -2
- package/dist/{session-history-import-DFN7sWRU.js → session-history-import-DwyijFI6.js} +4 -4
- package/dist/session-history-worker-runtime.js +1 -1
- package/dist/{session-history.worker-CNEvGaU5.js → session-history.worker-BeK1YOyT.js} +187 -83
- package/dist/session-history.worker.js +1 -1
- package/dist/{session-initialization-Jo86C60I.js → session-initialization-Ct0_Hzmg.js} +2 -2
- package/dist/{session-permission-policy-B22InTp_.js → session-permission-policy-BBmXA8Eg.js} +2 -2
- package/dist/{session-retirement-BSNG_mhf.js → session-retirement-B2YfbAAT.js} +5 -5
- package/dist/{settled-turn-finalizer-BuLUrZl2.js → settled-turn-finalizer-Dn91stmc.js} +5 -5
- package/dist/{shared-client-CVhez2Uo.js → shared-client-CscigXXL.js} +228 -30
- package/dist/{side-question-DLbr2vUU.js → side-question-BGMJQf4U.js} +18 -18
- package/dist/{source-Da-h6f7e.js → source-CElXU0Oy.js} +12 -12
- package/dist/{thread-archive-guard-D1bP04Tf.js → thread-archive-guard-DfpBr-Sz.js} +1 -1
- package/dist/{session-catalog-parsing-CdD3JhdM.js → thread-history-page-D0JIp48V.js} +83 -2
- package/dist/{thread-lifecycle-D1pzRwHB.js → thread-lifecycle-DXl1-I6b.js} +96 -44
- package/dist/{thread-ownership-D6oASVRu.js → thread-ownership-BsDRTsyp.js} +2 -2
- package/dist/{thread-policy-D8kI7yAO.js → thread-policy-BuEQfE0g.js} +3 -3
- package/dist/{thread-resume-T5cveyxA.js → thread-resume-DsDOZpFg.js} +5 -5
- package/dist/{session-catalog-home-id-D7-aLiNt.js → transcript-history-projection-v17wXgdK.js} +66 -18
- package/dist/{transcript-mirror-t5TOccct.js → transcript-mirror-C5CKgNy6.js} +1 -1
- package/dist/{upstream-session-fork-De-sLJ2r.js → upstream-session-fork-BZerMte_.js} +20 -20
- package/dist/{usage-CPPTmBvZ.js → usage-tCk-mg_x.js} +4 -4
- package/dist/{web-search-provider.runtime-CSVgQL0w.js → web-search-provider.runtime-B7bGbGWq.js} +3 -3
- package/openclaw.plugin.json +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { o as isJsonObject } from "./protocol-5bh1G-H7.js";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
//#region extensions/codex/src/app-server/inference-context.ts
|
|
4
|
+
const MAX_CONTEXT_BYTES = 262144;
|
|
5
|
+
const MAX_ACTIVE_ROOTS = 64;
|
|
6
|
+
const CODEX_INFERENCE_GENERATION_KEY = "openclaw_inference_generation";
|
|
7
|
+
/** One physical inference transport owns these confidential, nonpersistent snapshots. */
|
|
8
|
+
function createCodexInferenceContext(assertClientCurrent) {
|
|
9
|
+
const roots = /* @__PURE__ */ new Map();
|
|
10
|
+
let closed = false;
|
|
11
|
+
const assertOpen = () => {
|
|
12
|
+
if (closed) throw new Error("Codex parent-local inference transport is closed");
|
|
13
|
+
assertClientCurrent();
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
register(params) {
|
|
17
|
+
assertOpen();
|
|
18
|
+
params.signal.throwIfAborted();
|
|
19
|
+
params.assertCurrent();
|
|
20
|
+
if (Buffer.byteLength(params.text) > MAX_CONTEXT_BYTES) throw new Error("Codex parent-local context exceeds the 256 KiB inference limit");
|
|
21
|
+
if (!roots.has(params.threadId) && roots.size >= MAX_ACTIVE_ROOTS) throw new Error("Codex parent-local inference root limit reached");
|
|
22
|
+
roots.get(params.threadId)?.release();
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
const registration = {
|
|
25
|
+
generation: randomUUID(),
|
|
26
|
+
text: params.text,
|
|
27
|
+
controller,
|
|
28
|
+
assertCurrent: () => {
|
|
29
|
+
assertOpen();
|
|
30
|
+
controller.signal.throwIfAborted();
|
|
31
|
+
params.signal.throwIfAborted();
|
|
32
|
+
params.assertCurrent();
|
|
33
|
+
if (roots.get(params.threadId) !== registration) throw new Error("Codex parent-local inference generation was replaced");
|
|
34
|
+
},
|
|
35
|
+
release: () => {
|
|
36
|
+
if (roots.get(params.threadId) === registration) roots.delete(params.threadId);
|
|
37
|
+
registration.text = "";
|
|
38
|
+
controller.abort();
|
|
39
|
+
params.signal.removeEventListener("abort", registration.release);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
roots.set(params.threadId, registration);
|
|
43
|
+
params.signal.addEventListener("abort", registration.release, { once: true });
|
|
44
|
+
return {
|
|
45
|
+
generation: registration.generation,
|
|
46
|
+
release: registration.release
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
/** Caller must authenticate its private transport before parsing any model request. */
|
|
50
|
+
prepare(body) {
|
|
51
|
+
assertOpen();
|
|
52
|
+
const metadata = isJsonObject(body.client_metadata) ? body.client_metadata : void 0;
|
|
53
|
+
const raw = metadata?.["x-codex-turn-metadata"];
|
|
54
|
+
if (typeof raw !== "string" || Buffer.byteLength(raw) > 1048576) throw new Error("Codex inference request is missing bounded native metadata");
|
|
55
|
+
const value = JSON.parse(raw);
|
|
56
|
+
if (!isJsonObject(value)) throw new Error("Codex inference request has invalid native metadata");
|
|
57
|
+
const threadId = value.thread_id;
|
|
58
|
+
if (metadata?.thread_id != null && threadId != null && metadata.thread_id !== threadId) throw new Error("Codex inference thread metadata disagrees");
|
|
59
|
+
const child = Boolean(value.parent_thread_id || value.subagent_kind || metadata?.["x-openai-subagent"] || metadata?.["x-codex-parent-thread-id"]);
|
|
60
|
+
const kind = value.request_kind;
|
|
61
|
+
if (child || kind === "compaction" || kind === "memory") return {
|
|
62
|
+
body,
|
|
63
|
+
assertCurrent: assertOpen,
|
|
64
|
+
signal: void 0
|
|
65
|
+
};
|
|
66
|
+
if (kind !== "turn" && kind !== "prewarm") throw new Error("Codex inference request has an unsupported native purpose");
|
|
67
|
+
const registration = typeof threadId === "string" ? roots.get(threadId) : void 0;
|
|
68
|
+
const generation = value[CODEX_INFERENCE_GENERATION_KEY];
|
|
69
|
+
if (kind === "prewarm" && body.generate === false && generation == null) return {
|
|
70
|
+
body,
|
|
71
|
+
assertCurrent: assertOpen,
|
|
72
|
+
signal: void 0
|
|
73
|
+
};
|
|
74
|
+
if (!registration || generation !== registration.generation) throw new Error("Codex inference has no current admitted parent generation");
|
|
75
|
+
registration.assertCurrent();
|
|
76
|
+
const instructions = body.instructions;
|
|
77
|
+
if (instructions !== void 0 && typeof instructions !== "string") throw new Error("Codex inference request has invalid top-level instructions");
|
|
78
|
+
return {
|
|
79
|
+
body: registration.text ? {
|
|
80
|
+
...body,
|
|
81
|
+
instructions: instructions === void 0 ? registration.text : instructions + "\n\n" + registration.text
|
|
82
|
+
} : body,
|
|
83
|
+
assertCurrent: registration.assertCurrent,
|
|
84
|
+
signal: registration.controller.signal
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
close() {
|
|
88
|
+
closed = true;
|
|
89
|
+
for (const registration of roots.values()) registration.release();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { createCodexInferenceContext as n, CODEX_INFERENCE_GENERATION_KEY as t };
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { o as isJsonObject } from "./protocol-5bh1G-H7.js";
|
|
2
|
+
import { n as createCodexInferenceContext } from "./inference-context-Dr_mzvk4.js";
|
|
3
|
+
import { zstdCompress, zstdDecompress } from "node:zlib";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { Writable } from "node:stream";
|
|
6
|
+
import WebSocket, { WebSocketServer } from "ws";
|
|
7
|
+
import { createServer } from "node:http";
|
|
8
|
+
import { createNodeProxyAgent } from "openclaw/plugin-sdk/fetch-runtime";
|
|
9
|
+
import { generateSecureToken } from "openclaw/plugin-sdk/secure-random-runtime";
|
|
10
|
+
import { fetchWithSsrFGuard, isBlockedHostnameOrIp, resolvePinnedHostnameWithPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
11
|
+
//#region extensions/codex/src/app-server/inference-proxy.ts
|
|
12
|
+
const MAX_BODY_BYTES = 33554432;
|
|
13
|
+
const MAX_ERROR_BODY_BYTES = 1048576;
|
|
14
|
+
const MAX_CONNECTIONS = 16;
|
|
15
|
+
const compress = promisify(zstdCompress);
|
|
16
|
+
const decompress = promisify(zstdDecompress);
|
|
17
|
+
const HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
18
|
+
"connection",
|
|
19
|
+
"keep-alive",
|
|
20
|
+
"proxy-authenticate",
|
|
21
|
+
"proxy-authorization",
|
|
22
|
+
"te",
|
|
23
|
+
"trailer",
|
|
24
|
+
"transfer-encoding",
|
|
25
|
+
"upgrade",
|
|
26
|
+
"host",
|
|
27
|
+
"content-length"
|
|
28
|
+
]);
|
|
29
|
+
const FAILURE = "Codex parent-local inference transport failed; retry on a fresh connection.";
|
|
30
|
+
/** Private, fixed-destination relay. No upstream credentials or model content are retained. */
|
|
31
|
+
async function createCodexInferenceProxy(params) {
|
|
32
|
+
const upstream = new URL(params.upstream);
|
|
33
|
+
if (upstream.protocol !== "https:" || upstream.username || upstream.password || upstream.hash) throw new Error("Codex inference requires a credential-free HTTPS upstream URL");
|
|
34
|
+
const lifetime = new AbortController();
|
|
35
|
+
const assertCurrent = () => {
|
|
36
|
+
lifetime.signal.throwIfAborted();
|
|
37
|
+
params.assertCurrent();
|
|
38
|
+
};
|
|
39
|
+
const context = createCodexInferenceContext(assertCurrent);
|
|
40
|
+
const pathPrefix = "/" + generateSecureToken({
|
|
41
|
+
bytes: 32,
|
|
42
|
+
redact: true
|
|
43
|
+
}) + upstream.pathname.replace(/\/$/, "");
|
|
44
|
+
const active = /* @__PURE__ */ new Set();
|
|
45
|
+
const sockets = /* @__PURE__ */ new Set();
|
|
46
|
+
const wss = new WebSocketServer({
|
|
47
|
+
noServer: true,
|
|
48
|
+
maxPayload: MAX_BODY_BYTES,
|
|
49
|
+
perMessageDeflate: false
|
|
50
|
+
});
|
|
51
|
+
const handshakeHeaders = /* @__PURE__ */ new WeakMap();
|
|
52
|
+
wss.on("headers", (headers, request) => {
|
|
53
|
+
for (const [key, value] of Object.entries(handshakeHeaders.get(request) ?? {})) if (!key.startsWith("sec-websocket-")) headers.push(key + ": " + value);
|
|
54
|
+
handshakeHeaders.delete(request);
|
|
55
|
+
});
|
|
56
|
+
const resolveTarget = (request) => {
|
|
57
|
+
assertCurrent();
|
|
58
|
+
if (request.headers.origin || !request.url?.startsWith(pathPrefix + "/") || isBlockedHostnameOrIp(upstream.hostname)) throw new Error(FAILURE);
|
|
59
|
+
const suffix = request.url.slice(pathPrefix.length);
|
|
60
|
+
if (suffix.startsWith("//") || suffix.includes("\\") || /%2e|%2f|%5c|(?:^|\/)\.\.?(?:\/|\?|$)/i.test(suffix)) throw new Error(FAILURE);
|
|
61
|
+
const target = new URL(upstream);
|
|
62
|
+
const incoming = new URL(suffix, "http://localhost");
|
|
63
|
+
target.pathname = upstream.pathname.replace(/\/$/, "") + incoming.pathname;
|
|
64
|
+
for (const [key, value] of incoming.searchParams) target.searchParams.append(key, value);
|
|
65
|
+
return {
|
|
66
|
+
target,
|
|
67
|
+
sampling: incoming.pathname === "/responses"
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
const prepare = (bytes, sampling) => {
|
|
71
|
+
assertCurrent();
|
|
72
|
+
if (!sampling) return {
|
|
73
|
+
bytes,
|
|
74
|
+
assertCurrent,
|
|
75
|
+
signal: void 0
|
|
76
|
+
};
|
|
77
|
+
const value = JSON.parse(bytes.toString("utf8"));
|
|
78
|
+
if (!isJsonObject(value)) throw new Error(FAILURE);
|
|
79
|
+
const prepared = context.prepare(value);
|
|
80
|
+
const rewritten = Buffer.from(JSON.stringify(prepared.body));
|
|
81
|
+
if (rewritten.length > MAX_BODY_BYTES) throw new Error(FAILURE);
|
|
82
|
+
return {
|
|
83
|
+
...prepared,
|
|
84
|
+
bytes: rewritten
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
const server = createServer((req, res) => {
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
let guarded;
|
|
90
|
+
const abort = () => controller.abort();
|
|
91
|
+
req.once("aborted", abort);
|
|
92
|
+
res.once("close", abort);
|
|
93
|
+
(async () => {
|
|
94
|
+
try {
|
|
95
|
+
const { target, sampling } = resolveTarget(req);
|
|
96
|
+
if (req.method !== "POST" || active.size >= MAX_CONNECTIONS) throw new Error(FAILURE);
|
|
97
|
+
active.add(controller);
|
|
98
|
+
const wire = await readProxyBody(req, MAX_BODY_BYTES);
|
|
99
|
+
const encoding = req.headers["content-encoding"];
|
|
100
|
+
if (encoding && encoding !== "identity" && encoding !== "zstd") throw new Error(FAILURE);
|
|
101
|
+
const decoded = encoding === "zstd" ? await decompress(wire, { maxOutputLength: MAX_BODY_BYTES }) : wire;
|
|
102
|
+
assertCurrent();
|
|
103
|
+
const prepared = prepare(decoded, sampling);
|
|
104
|
+
const body = Buffer.from(encoding === "zstd" ? await compress(prepared.bytes) : prepared.bytes);
|
|
105
|
+
prepared.assertCurrent();
|
|
106
|
+
const signal = AbortSignal.any([
|
|
107
|
+
lifetime.signal,
|
|
108
|
+
controller.signal,
|
|
109
|
+
...prepared.signal ? [prepared.signal] : []
|
|
110
|
+
]);
|
|
111
|
+
guarded = await fetchWithSsrFGuard({
|
|
112
|
+
url: target.toString(),
|
|
113
|
+
init: {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: relayHeaders(req.headers),
|
|
116
|
+
body,
|
|
117
|
+
signal
|
|
118
|
+
},
|
|
119
|
+
signal,
|
|
120
|
+
beforeRequest: prepared.assertCurrent,
|
|
121
|
+
requireHttps: true,
|
|
122
|
+
maxRedirects: 0,
|
|
123
|
+
capture: false,
|
|
124
|
+
mode: "trusted_env_proxy",
|
|
125
|
+
auditContext: "codex-parent-local-inference"
|
|
126
|
+
});
|
|
127
|
+
prepared.assertCurrent();
|
|
128
|
+
const headers = Object.fromEntries(guarded.response.headers);
|
|
129
|
+
delete headers["content-encoding"];
|
|
130
|
+
res.writeHead(guarded.response.status, relayHeaders(headers));
|
|
131
|
+
if (!guarded.response.body) res.end();
|
|
132
|
+
else await guarded.response.body.pipeTo(Writable.toWeb(res), { signal });
|
|
133
|
+
} catch {
|
|
134
|
+
if (!res.headersSent && !res.destroyed) res.writeHead(502, { "content-type": "text/plain" }).end(FAILURE);
|
|
135
|
+
else res.destroy();
|
|
136
|
+
} finally {
|
|
137
|
+
active.delete(controller);
|
|
138
|
+
req.off("aborted", abort);
|
|
139
|
+
res.off("close", abort);
|
|
140
|
+
await guarded?.release().catch(() => void 0);
|
|
141
|
+
}
|
|
142
|
+
})();
|
|
143
|
+
});
|
|
144
|
+
server.maxConnections = MAX_CONNECTIONS;
|
|
145
|
+
server.requestTimeout = 3e4;
|
|
146
|
+
server.headersTimeout = 1e4;
|
|
147
|
+
server.on("upgrade", (req, socket, head) => {
|
|
148
|
+
(async () => {
|
|
149
|
+
let remote;
|
|
150
|
+
let local;
|
|
151
|
+
let proxyAgent;
|
|
152
|
+
const controller = new AbortController();
|
|
153
|
+
const close = () => {
|
|
154
|
+
controller.abort();
|
|
155
|
+
active.delete(controller);
|
|
156
|
+
remote?.terminate();
|
|
157
|
+
local?.terminate();
|
|
158
|
+
proxyAgent?.destroy();
|
|
159
|
+
if (remote) sockets.delete(remote);
|
|
160
|
+
if (local) sockets.delete(local);
|
|
161
|
+
socket.destroy();
|
|
162
|
+
};
|
|
163
|
+
try {
|
|
164
|
+
const { target, sampling } = resolveTarget(req);
|
|
165
|
+
if (!sampling || active.size >= MAX_CONNECTIONS) throw new Error(FAILURE);
|
|
166
|
+
active.add(controller);
|
|
167
|
+
socket.once("close", close);
|
|
168
|
+
socket.once("error", close);
|
|
169
|
+
const signal = AbortSignal.any([lifetime.signal, controller.signal]);
|
|
170
|
+
proxyAgent = createNodeProxyAgent({
|
|
171
|
+
mode: "env",
|
|
172
|
+
targetUrl: target.href
|
|
173
|
+
});
|
|
174
|
+
const lookup = proxyAgent ? void 0 : (await resolvePinnedHostnameWithPolicy(target.hostname, { signal })).lookup;
|
|
175
|
+
assertCurrent();
|
|
176
|
+
signal.throwIfAborted();
|
|
177
|
+
target.protocol = "wss:";
|
|
178
|
+
const headers = relayHeaders(req.headers);
|
|
179
|
+
for (const key of Object.keys(headers)) if (key.startsWith("sec-websocket-")) delete headers[key];
|
|
180
|
+
remote = new WebSocket(target, {
|
|
181
|
+
headers,
|
|
182
|
+
...proxyAgent ? { agent: proxyAgent } : { lookup },
|
|
183
|
+
followRedirects: false,
|
|
184
|
+
perMessageDeflate: false,
|
|
185
|
+
maxPayload: MAX_BODY_BYTES,
|
|
186
|
+
handshakeTimeout: 1e4
|
|
187
|
+
});
|
|
188
|
+
sockets.add(remote);
|
|
189
|
+
remote.once("upgrade", (response) => {
|
|
190
|
+
handshakeHeaders.set(req, relayHeaders(response.headers));
|
|
191
|
+
});
|
|
192
|
+
remote.once("error", close);
|
|
193
|
+
remote.once("close", close);
|
|
194
|
+
remote.once("unexpected-response", (_request, response) => {
|
|
195
|
+
(async () => {
|
|
196
|
+
try {
|
|
197
|
+
const body = await readProxyBody(response, MAX_ERROR_BODY_BYTES);
|
|
198
|
+
assertCurrent();
|
|
199
|
+
signal.throwIfAborted();
|
|
200
|
+
const failureHeaders = Object.entries(relayHeaders(response.headers)).map(([key, value]) => key + ": " + value);
|
|
201
|
+
failureHeaders.push("Connection: close", "Content-Length: " + body.length);
|
|
202
|
+
const status = "HTTP/1.1 " + response.statusCode + " " + (response.statusMessage ?? "Upstream refused");
|
|
203
|
+
socket.end(Buffer.concat([Buffer.from(status + "\r\n" + failureHeaders.join("\r\n") + "\r\n\r\n"), body]), close);
|
|
204
|
+
} catch {
|
|
205
|
+
close();
|
|
206
|
+
}
|
|
207
|
+
})();
|
|
208
|
+
});
|
|
209
|
+
remote.once("open", () => {
|
|
210
|
+
try {
|
|
211
|
+
assertCurrent();
|
|
212
|
+
signal.throwIfAborted();
|
|
213
|
+
wss.handleUpgrade(req, socket, head, (accepted) => {
|
|
214
|
+
local = accepted;
|
|
215
|
+
sockets.add(accepted);
|
|
216
|
+
accepted.once("error", close);
|
|
217
|
+
accepted.once("close", close);
|
|
218
|
+
let releaseFrame = () => {};
|
|
219
|
+
accepted.on("message", (data, binary) => {
|
|
220
|
+
try {
|
|
221
|
+
if (binary) throw new Error(FAILURE);
|
|
222
|
+
const prepared = prepare(rawBytes(data), true);
|
|
223
|
+
prepared.assertCurrent();
|
|
224
|
+
releaseFrame();
|
|
225
|
+
const onAbort = () => close();
|
|
226
|
+
prepared.signal?.addEventListener("abort", onAbort, { once: true });
|
|
227
|
+
releaseFrame = () => prepared.signal?.removeEventListener("abort", onAbort);
|
|
228
|
+
if (!remote || remote.readyState !== WebSocket.OPEN || remote.bufferedAmount + prepared.bytes.length > MAX_BODY_BYTES) throw new Error(FAILURE);
|
|
229
|
+
remote.send(prepared.bytes, { binary: false }, (error) => {
|
|
230
|
+
if (error) close();
|
|
231
|
+
});
|
|
232
|
+
} catch {
|
|
233
|
+
close();
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
accepted.once("close", () => releaseFrame());
|
|
237
|
+
remote.on("message", (data, binary) => {
|
|
238
|
+
if (accepted.readyState !== WebSocket.OPEN || accepted.bufferedAmount + rawBytes(data).length > MAX_BODY_BYTES) {
|
|
239
|
+
close();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
accepted.send(data, { binary }, (error) => {
|
|
243
|
+
if (error) close();
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
} catch {
|
|
248
|
+
close();
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
} catch {
|
|
252
|
+
close();
|
|
253
|
+
}
|
|
254
|
+
})();
|
|
255
|
+
});
|
|
256
|
+
const close = () => {
|
|
257
|
+
lifetime.abort();
|
|
258
|
+
context.close();
|
|
259
|
+
for (const controller of active) controller.abort();
|
|
260
|
+
for (const socket of sockets) socket.terminate();
|
|
261
|
+
server.close();
|
|
262
|
+
server.closeAllConnections();
|
|
263
|
+
wss.close();
|
|
264
|
+
};
|
|
265
|
+
try {
|
|
266
|
+
await new Promise((resolve, reject) => {
|
|
267
|
+
server.once("error", reject);
|
|
268
|
+
server.listen(0, "127.0.0.1", () => {
|
|
269
|
+
server.off("error", reject);
|
|
270
|
+
resolve();
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
assertCurrent();
|
|
274
|
+
server.on("error", close);
|
|
275
|
+
const address = server.address();
|
|
276
|
+
if (!address || typeof address === "string") throw new Error(FAILURE);
|
|
277
|
+
return {
|
|
278
|
+
context,
|
|
279
|
+
upstream: upstream.toString(),
|
|
280
|
+
baseUrl: "http://127.0.0.1:" + address.port + pathPrefix,
|
|
281
|
+
assertCurrent,
|
|
282
|
+
close
|
|
283
|
+
};
|
|
284
|
+
} catch (error) {
|
|
285
|
+
close();
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function readProxyBody(stream, maxBytes) {
|
|
290
|
+
const chunks = [];
|
|
291
|
+
let size = 0;
|
|
292
|
+
for await (const chunk of stream) {
|
|
293
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
294
|
+
size += bytes.length;
|
|
295
|
+
if (size > maxBytes) throw new Error(FAILURE);
|
|
296
|
+
chunks.push(bytes);
|
|
297
|
+
}
|
|
298
|
+
return Buffer.concat(chunks);
|
|
299
|
+
}
|
|
300
|
+
function rawBytes(data) {
|
|
301
|
+
return Array.isArray(data) ? Buffer.concat(data) : Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
302
|
+
}
|
|
303
|
+
function relayHeaders(input) {
|
|
304
|
+
const excluded = new Set(HOP_HEADERS);
|
|
305
|
+
for (const token of (input.connection ?? "").split(",")) excluded.add(token.trim().toLowerCase());
|
|
306
|
+
const output = {};
|
|
307
|
+
for (const [key, value] of Object.entries(input)) if (value !== void 0 && !excluded.has(key.toLowerCase())) output[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
|
|
308
|
+
return output;
|
|
309
|
+
}
|
|
310
|
+
//#endregion
|
|
311
|
+
export { createCodexInferenceProxy };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { i as resolveCodexAppServerHomeScope } from "./config-options-
|
|
2
|
-
import { x as readCodexPluginConfig } from "./protocol-
|
|
3
|
-
import { g as assertCodexPassiveTurnItems } from "./client-
|
|
4
|
-
import "./config-
|
|
5
|
-
import {
|
|
6
|
-
import { runBoundedCodexAppServerTurn } from "./bounded-turn-
|
|
1
|
+
import { i as resolveCodexAppServerHomeScope } from "./config-options-CXMq1T-C.js";
|
|
2
|
+
import { x as readCodexPluginConfig } from "./protocol-5bh1G-H7.js";
|
|
3
|
+
import { g as assertCodexPassiveTurnItems } from "./client-B57KWPQx.js";
|
|
4
|
+
import "./config-oIORaQ5T.js";
|
|
5
|
+
import { tt as resolveCodexAppServerPreparedAuthHandoff } from "./shared-client-CscigXXL.js";
|
|
6
|
+
import { runBoundedCodexAppServerTurn } from "./bounded-turn-C_Hneydj.js";
|
|
7
7
|
import { a as createAttributedCodexAssistantMessage } from "./event-projector-assistant-message-BmBM4qBV.js";
|
|
8
8
|
//#region extensions/codex/src/app-server/isolated-completion.ts
|
|
9
9
|
/** Runs prompt-only Codex inference on an ephemeral, ring-zero native thread. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
1
2
|
import { n as MANAGED_CODEX_APP_SERVER_PACKAGE } from "./version-omm6IPI3.js";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { constants, existsSync, realpathSync } from "node:fs";
|
|
@@ -47,6 +48,14 @@ function resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath(params = {}
|
|
|
47
48
|
* Resolves the managed Codex app-server binary shipped with or installed beside
|
|
48
49
|
* the Codex plugin before stdio startup.
|
|
49
50
|
*/
|
|
51
|
+
var managed_binary_exports = /* @__PURE__ */ __exportAll({
|
|
52
|
+
isManagedCodexDesktopCommand: () => isManagedCodexDesktopCommand,
|
|
53
|
+
resolveManagedCodexAppServerStartOptions: () => resolveManagedCodexAppServerStartOptions,
|
|
54
|
+
resolveManagedCodexNativeCommand: () => resolveManagedCodexNativeCommand,
|
|
55
|
+
resolveManagedCodexPackageEntrypoint: () => resolveManagedCodexPackageEntrypoint,
|
|
56
|
+
resolvePackagedCodexNativeCommand: () => resolvePackagedCodexNativeCommand,
|
|
57
|
+
setManagedCodexPluginRoot: () => setManagedCodexPluginRoot
|
|
58
|
+
});
|
|
50
59
|
const registeredCodexPlugin = resolveGlobalSingleton(Symbol.for("openclaw.codexManagedPluginRoot"), () => ({}));
|
|
51
60
|
/** Records the process-stable plugin root prepared by OpenClaw's plugin loader. */
|
|
52
61
|
function setManagedCodexPluginRoot(pluginRoot) {
|
|
@@ -183,4 +192,4 @@ async function commandPathExists(filePath, platform) {
|
|
|
183
192
|
}
|
|
184
193
|
}
|
|
185
194
|
//#endregion
|
|
186
|
-
export {
|
|
195
|
+
export { resolvePackagedCodexNativeCommand as a, resolveMacOSDesktopCodexAppPathCandidates as c, resolveManagedCodexNativeCommand as i, resolveMacOSDesktopCodexBundledMarketplaceCandidates as l, managed_binary_exports as n, setManagedCodexPluginRoot as o, resolveManagedCodexAppServerStartOptions as r, resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath as s, isManagedCodexDesktopCommand as t, resolveMacOSDesktopCodexComputerUseServiceAppCandidates as u };
|
|
@@ -43,7 +43,7 @@ async function describeCodexImages(req, options) {
|
|
|
43
43
|
const model = req.model.trim();
|
|
44
44
|
if (!model) throw new Error("Codex image understanding requires model id.");
|
|
45
45
|
req.signal?.throwIfAborted();
|
|
46
|
-
const { runBoundedCodexAppServerTurn } = await import("./bounded-turn-
|
|
46
|
+
const { runBoundedCodexAppServerTurn } = await import("./bounded-turn-C_Hneydj.js");
|
|
47
47
|
req.signal?.throwIfAborted();
|
|
48
48
|
const { text } = await runBoundedCodexAppServerTurn({
|
|
49
49
|
config: req.cfg,
|
|
@@ -83,7 +83,7 @@ async function extractCodexStructured(req, options) {
|
|
|
83
83
|
if (req.input.length === 0) throw new Error("Codex structured extraction requires at least one input.");
|
|
84
84
|
if (!req.input.some((entry) => entry.type === "image")) throw new Error("Codex structured extraction requires at least one image input.");
|
|
85
85
|
req.signal?.throwIfAborted();
|
|
86
|
-
const { runBoundedCodexAppServerTurn } = await import("./bounded-turn-
|
|
86
|
+
const { runBoundedCodexAppServerTurn } = await import("./bounded-turn-C_Hneydj.js");
|
|
87
87
|
req.signal?.throwIfAborted();
|
|
88
88
|
const { text } = await runBoundedCodexAppServerTurn({
|
|
89
89
|
config: req.cfg,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { r as buildCodexRuntimeModelParams } from "./harness-
|
|
2
|
-
import { o as isJsonObject, x as readCodexPluginConfig } from "./protocol-
|
|
3
|
-
import { o as withCodexAppServerJsonClient } from "./request-
|
|
4
|
-
import { n as resolveCodexAppServerRuntimeOptions } from "./config-runtime-
|
|
5
|
-
import { r as captureSharedCodexAppServerCatalogLifetime } from "./shared-client-
|
|
6
|
-
import { t as listAllCodexAppServerModels } from "./models-
|
|
1
|
+
import { r as buildCodexRuntimeModelParams } from "./harness-C7rRa7bm.js";
|
|
2
|
+
import { o as isJsonObject, x as readCodexPluginConfig } from "./protocol-5bh1G-H7.js";
|
|
3
|
+
import { o as withCodexAppServerJsonClient } from "./request-B7hEkBGq.js";
|
|
4
|
+
import { n as resolveCodexAppServerRuntimeOptions } from "./config-runtime-D0zGNIHu.js";
|
|
5
|
+
import { r as captureSharedCodexAppServerCatalogLifetime } from "./shared-client-CscigXXL.js";
|
|
6
|
+
import { t as listAllCodexAppServerModels } from "./models-PCKOim-h.js";
|
|
7
7
|
//#region extensions/codex/src/app-server/model-catalog.ts
|
|
8
8
|
const DEFAULT_MODEL_DISCOVERY_TIMEOUT_MS = 2500;
|
|
9
9
|
const INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h as assertCodexModelListResponse } from "./client-
|
|
1
|
+
import { h as assertCodexModelListResponse } from "./client-B57KWPQx.js";
|
|
2
2
|
import { normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
3
|
//#region extensions/codex/src/app-server/models.ts
|
|
4
4
|
/**
|
|
@@ -37,8 +37,8 @@ async function withCodexAppServerModelRequest(options, run) {
|
|
|
37
37
|
if (options.request) return await run(options.request);
|
|
38
38
|
const timeoutMs = options.timeoutMs ?? 2500;
|
|
39
39
|
const useSharedClient = options.sharedClient !== false;
|
|
40
|
-
const { createIsolatedCodexAppServerClient, getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient } = await import("./shared-client-
|
|
41
|
-
const { requestCodexAppServerClientJson } = await import("./request-
|
|
40
|
+
const { createIsolatedCodexAppServerClient, getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient } = await import("./shared-client-CscigXXL.js").then((n) => n.y);
|
|
41
|
+
const { requestCodexAppServerClientJson } = await import("./request-B7hEkBGq.js").then((n) => n.a);
|
|
42
42
|
const client = await (useSharedClient ? getLeasedSharedCodexAppServerClient : createIsolatedCodexAppServerClient)({
|
|
43
43
|
startOptions: options.startOptions,
|
|
44
44
|
timeoutMs,
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { l as sessionBindingIdentity } from "./session-binding-record-Bcvslnhf.js";
|
|
2
|
+
import { t as readCodexThreadHistoryPage } from "./thread-history-page-D0JIp48V.js";
|
|
3
|
+
import { r as readMirrorIdentity } from "./upstream-prompt-provenance-LphB8slG.js";
|
|
4
|
+
import { r as projectCodexThreadHistoryItem } from "./transcript-history-projection-v17wXgdK.js";
|
|
5
|
+
import { n as buildCodexAppServerRuntimeFingerprint, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-d0eKxy7b.js";
|
|
6
|
+
import { i as resolveCodexBindingAppServerConnection } from "./binding-connection-D3udKbIE.js";
|
|
7
|
+
import { c as getLeasedSharedCodexAppServerClient, h as releaseLeasedSharedCodexAppServerClient } from "./shared-client-CscigXXL.js";
|
|
8
|
+
import { c as itemToolArgs, d as itemTranscriptResultText, n as CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX } from "./native-subagent-task-ids-BzTdT0Uw.js";
|
|
9
|
+
import { r as readCodexNativeSubagentHistoryOwner, t as codexNativeSubagentHistoryConnectionFingerprint } from "./native-subagent-history-owner-Pcp7JuVF.js";
|
|
10
|
+
import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
11
|
+
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
12
|
+
//#region extensions/codex/src/app-server/native-subagent-history.ts
|
|
13
|
+
const MAX_SUBAGENT_ANCESTRY_READS = 32;
|
|
14
|
+
const taskHistoryToolItems = {
|
|
15
|
+
itemToolArgs,
|
|
16
|
+
itemTranscriptResultText
|
|
17
|
+
};
|
|
18
|
+
function parentThreadId(thread) {
|
|
19
|
+
const source = thread.source;
|
|
20
|
+
const spawn = source && typeof source === "object" && "subAgent" in source && typeof source.subAgent === "object" && "thread_spawn" in source.subAgent ? source.subAgent.thread_spawn : void 0;
|
|
21
|
+
return thread.parentThreadId?.trim() ?? spawn?.parent_thread_id.trim();
|
|
22
|
+
}
|
|
23
|
+
/** Resolves history from the parent binding's native store without adopting the child. */
|
|
24
|
+
async function readCodexNativeSubagentHistory(params, options) {
|
|
25
|
+
params.assertCurrent();
|
|
26
|
+
const { task, cfg } = params;
|
|
27
|
+
const sessionKey = task.requesterSessionKey;
|
|
28
|
+
const agentId = task.agentId;
|
|
29
|
+
const threadId = task.runId?.startsWith("codex-thread:") ? task.runId.slice(CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX.length) : void 0;
|
|
30
|
+
if (task.taskKind !== "codex-native" || !sessionKey || !agentId || !threadId) throw new Error("Subagent transcript owner is unavailable.");
|
|
31
|
+
const storePath = resolveStorePath(cfg.session?.store, { agentId });
|
|
32
|
+
const readSession = () => getSessionEntry({
|
|
33
|
+
agentId,
|
|
34
|
+
sessionKey,
|
|
35
|
+
storePath,
|
|
36
|
+
hydrateSkillPromptRefs: false,
|
|
37
|
+
readConsistency: "latest"
|
|
38
|
+
});
|
|
39
|
+
const session = readSession();
|
|
40
|
+
if (!session?.sessionId) throw new Error("Subagent parent session is unavailable.");
|
|
41
|
+
const sessionId = session.sessionId;
|
|
42
|
+
const lifecycleRevision = session.lifecycleRevision;
|
|
43
|
+
const historyOwner = readCodexNativeSubagentHistoryOwner(task.detail);
|
|
44
|
+
if (historyOwner && (historyOwner.lifecycleRevision ? historyOwner.lifecycleRevision !== lifecycleRevision : historyOwner.sessionId !== sessionId)) throw new Error("Subagent history owner changed; reconnect its parent session.");
|
|
45
|
+
const identity = sessionBindingIdentity({
|
|
46
|
+
agentId,
|
|
47
|
+
sessionId,
|
|
48
|
+
sessionKey,
|
|
49
|
+
config: cfg
|
|
50
|
+
});
|
|
51
|
+
const binding = options.bindingStore.read(identity);
|
|
52
|
+
if (!binding || binding.pendingSupervisionBranch) throw new Error("Subagent parent thread is unavailable.");
|
|
53
|
+
if (historyOwner && historyOwner.connectionFingerprint !== codexNativeSubagentHistoryConnectionFingerprint(binding)) throw new Error("Subagent history owner changed; reconnect its parent session.");
|
|
54
|
+
const historyParentThreadId = historyOwner?.parentThreadId ?? binding.threadId;
|
|
55
|
+
const assertCurrent = () => {
|
|
56
|
+
params.assertCurrent();
|
|
57
|
+
const currentSession = readSession();
|
|
58
|
+
const current = options.bindingStore.read(identity);
|
|
59
|
+
if (currentSession?.sessionId !== sessionId || currentSession?.lifecycleRevision !== lifecycleRevision || current?.threadId !== binding.threadId || current?.appServerRuntimeFingerprint !== binding.appServerRuntimeFingerprint || current?.connectionScope !== binding.connectionScope || current?.authProfileId !== binding.authProfileId) throw new Error("Subagent parent changed; refresh its transcript.");
|
|
60
|
+
};
|
|
61
|
+
const agentDir = resolveAgentDir(cfg, agentId);
|
|
62
|
+
const connection = resolveCodexBindingAppServerConnection({
|
|
63
|
+
binding,
|
|
64
|
+
pluginConfig: options.pluginConfig,
|
|
65
|
+
agentDir,
|
|
66
|
+
authProfileId: binding.authProfileId
|
|
67
|
+
});
|
|
68
|
+
const client = await getLeasedSharedCodexAppServerClient({
|
|
69
|
+
startOptions: connection.appServer.start,
|
|
70
|
+
timeoutMs: connection.appServer.requestTimeoutMs,
|
|
71
|
+
authProfileId: connection.clientAuthProfileId,
|
|
72
|
+
agentDir,
|
|
73
|
+
config: cfg,
|
|
74
|
+
assertCurrent
|
|
75
|
+
});
|
|
76
|
+
try {
|
|
77
|
+
assertCurrent();
|
|
78
|
+
const fingerprint = binding.connectionScope === "supervision" ? buildCodexAppServerConnectionFingerprint(connection.appServer, agentDir) : buildCodexAppServerRuntimeFingerprint({
|
|
79
|
+
appServer: connection.appServer,
|
|
80
|
+
appServerVersion: client.getServerVersion(),
|
|
81
|
+
runtimeIdentity: client.getRuntimeIdentity()
|
|
82
|
+
});
|
|
83
|
+
if (!binding.appServerRuntimeFingerprint || fingerprint !== binding.appServerRuntimeFingerprint) throw new Error("Subagent connection changed; reconnect its parent session.");
|
|
84
|
+
const { thread } = await client.request("thread/read", {
|
|
85
|
+
threadId,
|
|
86
|
+
includeTurns: false
|
|
87
|
+
}, { assertCurrent });
|
|
88
|
+
assertCurrent();
|
|
89
|
+
if (thread.id !== threadId || threadId === historyParentThreadId) throw new Error("Subagent transcript does not belong to this parent session.");
|
|
90
|
+
const visited = /* @__PURE__ */ new Set([threadId]);
|
|
91
|
+
let ancestor = thread;
|
|
92
|
+
for (;;) {
|
|
93
|
+
const parentId = parentThreadId(ancestor);
|
|
94
|
+
if (parentId === historyParentThreadId) break;
|
|
95
|
+
if (!parentId || visited.has(parentId) || visited.size >= MAX_SUBAGENT_ANCESTRY_READS) throw new Error("Subagent transcript does not belong to this parent session.");
|
|
96
|
+
visited.add(parentId);
|
|
97
|
+
const response = await client.request("thread/read", {
|
|
98
|
+
threadId: parentId,
|
|
99
|
+
includeTurns: false
|
|
100
|
+
}, { assertCurrent });
|
|
101
|
+
assertCurrent();
|
|
102
|
+
if (response.thread.id !== parentId) throw new Error("Subagent transcript does not belong to this parent session.");
|
|
103
|
+
ancestor = response.thread;
|
|
104
|
+
}
|
|
105
|
+
const page = await readCodexThreadHistoryPage({
|
|
106
|
+
listItemPage: async (request) => {
|
|
107
|
+
assertCurrent();
|
|
108
|
+
const result = await client.request("thread/items/list", request, { assertCurrent });
|
|
109
|
+
assertCurrent();
|
|
110
|
+
return result;
|
|
111
|
+
},
|
|
112
|
+
listTurnPage: async (request) => {
|
|
113
|
+
assertCurrent();
|
|
114
|
+
const result = await client.request("thread/turns/list", request, { assertCurrent });
|
|
115
|
+
assertCurrent();
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
}, thread, {
|
|
119
|
+
threadId,
|
|
120
|
+
cursor: params.cursor,
|
|
121
|
+
limit: Math.max(1, Math.floor(Math.min(params.limit, 200) / 2))
|
|
122
|
+
}, {
|
|
123
|
+
project: (entries) => entries.map((entry) => projectCodexThreadHistoryItem(thread, entry, taskHistoryToolItems).map((message) => {
|
|
124
|
+
const messageIdentity = readMirrorIdentity(message);
|
|
125
|
+
if (!messageIdentity) throw new Error("Subagent history message is missing its native identity.");
|
|
126
|
+
return Object.assign(message, { messageId: JSON.stringify([threadId, messageIdentity]) });
|
|
127
|
+
})),
|
|
128
|
+
fits: (result) => Buffer.byteLength(JSON.stringify(result), "utf8") <= 524288
|
|
129
|
+
});
|
|
130
|
+
assertCurrent();
|
|
131
|
+
return {
|
|
132
|
+
messages: page.items.toReversed().flat(),
|
|
133
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {}
|
|
134
|
+
};
|
|
135
|
+
} finally {
|
|
136
|
+
releaseLeasedSharedCodexAppServerClient(client);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//#endregion
|
|
140
|
+
export { readCodexNativeSubagentHistory };
|