orkestrator 2.26.3-beta → 2.28.0-beta
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/client.js +508 -209
- package/dist/main.js +16148 -10171
- package/package.json +4 -4
- package/resources/claude-bridge/dist/index.js +132 -25
- package/resources/codex-bridge/dist/index.js +266 -31
|
@@ -4060,6 +4060,7 @@ var NATIVE_AGENT_APPROVAL_MODES = Object.freeze({
|
|
|
4060
4060
|
}
|
|
4061
4061
|
]
|
|
4062
4062
|
});
|
|
4063
|
+
var NATIVE_AGENT_RETIRED_DISPATCH_TTL_MS = 24 * 60 * 60 * 1000;
|
|
4063
4064
|
var SUPPRESSED_COMPOSER_PARAMETERS = Object.freeze({
|
|
4064
4065
|
claude: Object.freeze(["parameter:thinking", "parameter:context1m"]),
|
|
4065
4066
|
codex: Object.freeze(["parameter:summary"]),
|
|
@@ -4191,6 +4192,7 @@ var PROJECTION_FIELD_SET = new Set([
|
|
|
4191
4192
|
"runtimeHealthAuthoritative",
|
|
4192
4193
|
"notices",
|
|
4193
4194
|
"recoverableDispatch",
|
|
4195
|
+
"retiredDispatch",
|
|
4194
4196
|
"backgroundTasks",
|
|
4195
4197
|
"suggestedPrompt",
|
|
4196
4198
|
"completionBlockedByBackgroundTasks",
|
|
@@ -4214,6 +4216,7 @@ var OPTIONAL_PROJECTION_FIELD_SET = new Set([
|
|
|
4214
4216
|
"runtimeHealthAuthoritative",
|
|
4215
4217
|
"notices",
|
|
4216
4218
|
"recoverableDispatch",
|
|
4219
|
+
"retiredDispatch",
|
|
4217
4220
|
"backgroundTasks",
|
|
4218
4221
|
"suggestedPrompt",
|
|
4219
4222
|
"completionBlockedByBackgroundTasks",
|
|
@@ -5089,6 +5092,7 @@ var SESSION_ACTIVITY_BATCH_LIMITS = {
|
|
|
5089
5092
|
maxResponseBytes: 512 * 1024,
|
|
5090
5093
|
maxAsyncQuestionItemIds: 64,
|
|
5091
5094
|
maxAsyncQuestionItemIdLength: 2048,
|
|
5095
|
+
maxContentRevisionLength: 256,
|
|
5092
5096
|
readConcurrency: 4
|
|
5093
5097
|
};
|
|
5094
5098
|
var SESSION_ACTIVITY_STATES = new Set(["idle", "working", "waiting", "missing"]);
|
|
@@ -5103,6 +5107,7 @@ function parseSessionActivityObservation(value) {
|
|
|
5103
5107
|
if (!isRecord(value))
|
|
5104
5108
|
return;
|
|
5105
5109
|
const { activity, readyForInput, completionPending, asyncQuestionItemIds, closing } = value;
|
|
5110
|
+
const { contentRevision } = value;
|
|
5106
5111
|
if (typeof activity !== "string" || !SESSION_ACTIVITY_STATES.has(activity))
|
|
5107
5112
|
return;
|
|
5108
5113
|
if (readyForInput !== undefined && typeof readyForInput !== "boolean")
|
|
@@ -5111,6 +5116,8 @@ function parseSessionActivityObservation(value) {
|
|
|
5111
5116
|
return;
|
|
5112
5117
|
if (closing !== undefined && typeof closing !== "boolean")
|
|
5113
5118
|
return;
|
|
5119
|
+
if (contentRevision !== undefined && !isContentRevision(contentRevision))
|
|
5120
|
+
return;
|
|
5114
5121
|
let itemIds;
|
|
5115
5122
|
if (asyncQuestionItemIds !== undefined) {
|
|
5116
5123
|
if (!Array.isArray(asyncQuestionItemIds) || asyncQuestionItemIds.length > SESSION_ACTIVITY_BATCH_LIMITS.maxAsyncQuestionItemIds || !asyncQuestionItemIds.every((itemId) => typeof itemId === "string" && itemId.length > 0 && itemId.length <= SESSION_ACTIVITY_BATCH_LIMITS.maxAsyncQuestionItemIdLength)) {
|
|
@@ -5123,9 +5130,13 @@ function parseSessionActivityObservation(value) {
|
|
|
5123
5130
|
...readyForInput !== undefined ? { readyForInput } : {},
|
|
5124
5131
|
...completionPending !== undefined ? { completionPending } : {},
|
|
5125
5132
|
...itemIds !== undefined ? { asyncQuestionItemIds: itemIds } : {},
|
|
5126
|
-
...closing !== undefined ? { closing } : {}
|
|
5133
|
+
...closing !== undefined ? { closing } : {},
|
|
5134
|
+
...contentRevision !== undefined ? { contentRevision } : {}
|
|
5127
5135
|
};
|
|
5128
5136
|
}
|
|
5137
|
+
function isContentRevision(value) {
|
|
5138
|
+
return typeof value === "string" && value.length > 0 && value.length <= SESSION_ACTIVITY_BATCH_LIMITS.maxContentRevisionLength;
|
|
5139
|
+
}
|
|
5129
5140
|
function parseSessionActivityBatchRequest(value) {
|
|
5130
5141
|
if (!isRecord(value))
|
|
5131
5142
|
return { ok: false, error: "Expected a JSON object" };
|
|
@@ -10815,6 +10826,7 @@ var STRONG_REFUSAL_MARKERS = [
|
|
|
10815
10826
|
"read-only file system"
|
|
10816
10827
|
];
|
|
10817
10828
|
var SCRIPT_FAILED = "script failed";
|
|
10829
|
+
var INTERRUPTED_CELL = /^aborted by user\b/i;
|
|
10818
10830
|
var MAX_PENDING_CELLS = 256;
|
|
10819
10831
|
var MAX_CELL_TEXT_CHARS = 64 * 1024;
|
|
10820
10832
|
var ROLLOUT_POLL_INTERVAL_MS = 200;
|
|
@@ -10846,7 +10858,12 @@ function reportsRefusal(output) {
|
|
|
10846
10858
|
}
|
|
10847
10859
|
function codeModeCellOutcome(output) {
|
|
10848
10860
|
const refused = reportsRefusal(output);
|
|
10849
|
-
|
|
10861
|
+
const trimmed = output.trimStart();
|
|
10862
|
+
return {
|
|
10863
|
+
refused,
|
|
10864
|
+
failed: refused || trimmed.toLowerCase().startsWith(SCRIPT_FAILED),
|
|
10865
|
+
interrupted: !refused && INTERRUPTED_CELL.test(trimmed)
|
|
10866
|
+
};
|
|
10850
10867
|
}
|
|
10851
10868
|
function defaultWatch(_path, onChange) {
|
|
10852
10869
|
const timer = setInterval(onChange, ROLLOUT_POLL_INTERVAL_MS);
|
|
@@ -10975,7 +10992,9 @@ class RefusedCellTail {
|
|
|
10975
10992
|
this.pending.delete(callId);
|
|
10976
10993
|
const output = cellOutputText(payload.output);
|
|
10977
10994
|
const completedAtMs = recordTimeMs(record, payload);
|
|
10978
|
-
const { refused, failed } = codeModeCellOutcome(output);
|
|
10995
|
+
const { refused, failed, interrupted } = codeModeCellOutcome(output);
|
|
10996
|
+
if (interrupted)
|
|
10997
|
+
return;
|
|
10979
10998
|
const unseen = !Number.isFinite(cell.startedAtMs) || !Number.isFinite(completedAtMs) || !this.options.itemStartedBetween(cell.startedAtMs, completedAtMs);
|
|
10980
10999
|
if (!refused && !unseen)
|
|
10981
11000
|
return;
|
|
@@ -10992,6 +11011,7 @@ class RefusedCellTail {
|
|
|
10992
11011
|
}
|
|
10993
11012
|
|
|
10994
11013
|
// ../../bridges/codex-bridge/src/app-server/item-adapter.ts
|
|
11014
|
+
import { isAbsolute as isAbsolute5 } from "node:path";
|
|
10995
11015
|
function isRecord5(value) {
|
|
10996
11016
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
10997
11017
|
}
|
|
@@ -11004,6 +11024,20 @@ function durationMs(value) {
|
|
|
11004
11024
|
function strArray(value) {
|
|
11005
11025
|
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
11006
11026
|
}
|
|
11027
|
+
var MAX_IMAGE_GENERATION_INPUTS = 8;
|
|
11028
|
+
function imageGenerationInputPaths(value) {
|
|
11029
|
+
if (!Array.isArray(value))
|
|
11030
|
+
return [];
|
|
11031
|
+
const paths = new Set;
|
|
11032
|
+
for (const entry of value) {
|
|
11033
|
+
if (paths.size >= MAX_IMAGE_GENERATION_INPUTS)
|
|
11034
|
+
break;
|
|
11035
|
+
const path = isRecord5(entry) ? str(entry.path) : undefined;
|
|
11036
|
+
if (path && isAbsolute5(path))
|
|
11037
|
+
paths.add(path);
|
|
11038
|
+
}
|
|
11039
|
+
return [...paths];
|
|
11040
|
+
}
|
|
11007
11041
|
var MAX_ASYNC_QUESTIONS = 16;
|
|
11008
11042
|
var MAX_ASYNC_OPTIONS = 32;
|
|
11009
11043
|
var MAX_ASYNC_TEXT_LENGTH = 16384;
|
|
@@ -11265,13 +11299,15 @@ function adaptAppServerItem(raw) {
|
|
|
11265
11299
|
}
|
|
11266
11300
|
case "imageGeneration": {
|
|
11267
11301
|
const path = str(raw.savedPath);
|
|
11302
|
+
const inputPaths = imageGenerationInputPaths(raw.inputImages);
|
|
11268
11303
|
return {
|
|
11269
11304
|
item: {
|
|
11270
11305
|
id,
|
|
11271
11306
|
type: "image",
|
|
11272
11307
|
text: str(raw.revisedPrompt) ?? "Generated image",
|
|
11273
11308
|
...path ? { path } : {},
|
|
11274
|
-
source: "generated"
|
|
11309
|
+
source: "generated",
|
|
11310
|
+
...inputPaths.length > 0 ? { input_paths: inputPaths } : {}
|
|
11275
11311
|
}
|
|
11276
11312
|
};
|
|
11277
11313
|
}
|
|
@@ -12074,6 +12110,13 @@ async function itemToParts(item, cwd, fileChangeContext) {
|
|
|
12074
12110
|
return [];
|
|
12075
12111
|
case "image":
|
|
12076
12112
|
return [
|
|
12113
|
+
...(item.input_paths ?? []).map((path) => ({
|
|
12114
|
+
type: "image",
|
|
12115
|
+
content: path.split(/[\\/]/).pop() || "Image",
|
|
12116
|
+
fileUrl: `file://${path}`,
|
|
12117
|
+
filename: path,
|
|
12118
|
+
imageSource: "viewed"
|
|
12119
|
+
})),
|
|
12077
12120
|
{
|
|
12078
12121
|
type: "image",
|
|
12079
12122
|
content: item.text,
|
|
@@ -12370,11 +12413,8 @@ async function walkJsonlFiles(dir) {
|
|
|
12370
12413
|
}
|
|
12371
12414
|
return files;
|
|
12372
12415
|
}
|
|
12373
|
-
async function listTranscriptPaths() {
|
|
12374
|
-
const searchRoots = [
|
|
12375
|
-
join8(getCodexHomeDir(), "sessions"),
|
|
12376
|
-
join8(getCodexHomeDir(), "archived_sessions")
|
|
12377
|
-
];
|
|
12416
|
+
async function listTranscriptPaths(codexHome = getCodexHomeDir()) {
|
|
12417
|
+
const searchRoots = [join8(codexHome, "sessions"), join8(codexHome, "archived_sessions")];
|
|
12378
12418
|
return (await Promise.all(searchRoots.map((root) => walkJsonlFiles(root)))).flat();
|
|
12379
12419
|
}
|
|
12380
12420
|
var cachedTranscriptPaths = new Map;
|
|
@@ -12999,6 +13039,18 @@ async function replayPersistedRollout(threadId, snapshot, meta, structuredTurns)
|
|
|
12999
13039
|
const settleCodeModeCell = (cell, output) => {
|
|
13000
13040
|
openCells.delete(cell.callId);
|
|
13001
13041
|
const outcome = output === undefined ? undefined : codeModeCellOutcome(cellOutputText(output));
|
|
13042
|
+
if (outcome?.interrupted) {
|
|
13043
|
+
const { toolState: _claimed, ...stopped } = cell.message.parts[cell.execPartIndex];
|
|
13044
|
+
cell.message.parts[cell.execPartIndex] = stopped;
|
|
13045
|
+
if (!cell.keepExecRow) {
|
|
13046
|
+
dropPart(cell.message, cell.execPartIndex);
|
|
13047
|
+
for (const call of cell.sourceCalls) {
|
|
13048
|
+
if (!call.replaced)
|
|
13049
|
+
dropPart(cell.message, call.partIndex);
|
|
13050
|
+
}
|
|
13051
|
+
return;
|
|
13052
|
+
}
|
|
13053
|
+
}
|
|
13002
13054
|
if (cell.sawMcpRecord) {
|
|
13003
13055
|
for (const call of cell.sourceCalls) {
|
|
13004
13056
|
if (!call.replaced)
|
|
@@ -14024,7 +14076,7 @@ async function publishAssistantRows(context, state, turn, options) {
|
|
|
14024
14076
|
}
|
|
14025
14077
|
|
|
14026
14078
|
// ../../bridges/codex-bridge/src/app-server-runtime-sessions.ts
|
|
14027
|
-
import { createHash as createHash9 } from "node:crypto";
|
|
14079
|
+
import { createHash as createHash9, randomUUID as randomUUID6 } from "node:crypto";
|
|
14028
14080
|
|
|
14029
14081
|
// ../protocol/src/agent-mail.ts
|
|
14030
14082
|
var AGENT_MAIL_MAX_BODY_BYTES = 32 * 1024;
|
|
@@ -14087,9 +14139,9 @@ var ORKESTRATOR_ARTIFACT_MCP_SERVER_NAME = "orkestrator-artifacts";
|
|
|
14087
14139
|
var ORKESTRATOR_ARTIFACT_MCP_PATH = "/artifact-mcp";
|
|
14088
14140
|
|
|
14089
14141
|
// ../../bridges/codex-bridge/src/engine/app-server-engine.ts
|
|
14090
|
-
import { open as
|
|
14142
|
+
import { open as open6 } from "node:fs/promises";
|
|
14091
14143
|
import { createHash as createHash8 } from "node:crypto";
|
|
14092
|
-
import { isAbsolute as
|
|
14144
|
+
import { isAbsolute as isAbsolute7, join as join13 } from "node:path";
|
|
14093
14145
|
|
|
14094
14146
|
// ../../bridges/codex-bridge/src/app-server/process-supervisor.ts
|
|
14095
14147
|
import { execFile as execFile3, spawn as spawn3 } from "node:child_process";
|
|
@@ -16724,6 +16776,7 @@ var IGNORED_METHODS = new Set([
|
|
|
16724
16776
|
"thread/project/updated",
|
|
16725
16777
|
"thread/queue/changed",
|
|
16726
16778
|
"thread/prediction/updated",
|
|
16779
|
+
"thread/readState/changed",
|
|
16727
16780
|
"autoApprovalReview/strictReviewRequired",
|
|
16728
16781
|
"mcpServer/event/stream/notification",
|
|
16729
16782
|
"thread/reverted",
|
|
@@ -16828,6 +16881,7 @@ function reduceNotification(notification, generation, handle) {
|
|
|
16828
16881
|
turns: [
|
|
16829
16882
|
{
|
|
16830
16883
|
turnId,
|
|
16884
|
+
at: new Date().toISOString(),
|
|
16831
16885
|
inputTokens: num(last.inputTokens),
|
|
16832
16886
|
outputTokens: num(last.outputTokens),
|
|
16833
16887
|
cacheReadTokens: num(last.cachedInputTokens),
|
|
@@ -18019,7 +18073,7 @@ function coordinatorCapabilityPolicy(mode) {
|
|
|
18019
18073
|
|
|
18020
18074
|
// ../../bridges/codex-bridge/src/codex-config.ts
|
|
18021
18075
|
import { realpathSync } from "node:fs";
|
|
18022
|
-
import { isAbsolute as
|
|
18076
|
+
import { isAbsolute as isAbsolute6 } from "node:path";
|
|
18023
18077
|
var CODEX_MAX_CONCURRENT_THREADS_ENV = "CODEX_MAX_CONCURRENT_THREADS_PER_SESSION";
|
|
18024
18078
|
var DEFAULT_CODEX_MAX_CONCURRENT_THREADS = 5;
|
|
18025
18079
|
var ORKESTRATOR_AGENT_MCP_URL_ENV = "ORKESTRATOR_AGENT_MCP_URL";
|
|
@@ -18039,7 +18093,7 @@ function codexNetworkDeniedConfig(policy) {
|
|
|
18039
18093
|
};
|
|
18040
18094
|
}
|
|
18041
18095
|
function codexProjectTrustConfig(policy, cwd) {
|
|
18042
|
-
if (!policy || policy.projectResources || !cwd || !
|
|
18096
|
+
if (!policy || policy.projectResources || !cwd || !isAbsolute6(cwd))
|
|
18043
18097
|
return {};
|
|
18044
18098
|
const roots = new Set([cwd]);
|
|
18045
18099
|
try {
|
|
@@ -18062,7 +18116,7 @@ function codexProjectSkillsConfig(listed) {
|
|
|
18062
18116
|
const { path, scope, enabled } = skill ?? {};
|
|
18063
18117
|
if (enabled === true && typeof scope === "string" && KEPT_SKILL_SCOPES.has(scope))
|
|
18064
18118
|
continue;
|
|
18065
|
-
if (typeof path !== "string" || !
|
|
18119
|
+
if (typeof path !== "string" || !isAbsolute6(path)) {
|
|
18066
18120
|
throw new Error("Codex listed a project skill without a path it can be disabled by");
|
|
18067
18121
|
}
|
|
18068
18122
|
disabled.add(path);
|
|
@@ -18089,6 +18143,14 @@ function codexReadOnlyTurnPolicy(policy) {
|
|
|
18089
18143
|
const denied = base.capabilityPolicy?.deny ?? [];
|
|
18090
18144
|
return { ...base, capabilityPolicy: { deny: [...denied, "network"] } };
|
|
18091
18145
|
}
|
|
18146
|
+
function codexToolHistoryGaps(config) {
|
|
18147
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
18148
|
+
return ["config/read returned no configuration"];
|
|
18149
|
+
}
|
|
18150
|
+
const features = config.features;
|
|
18151
|
+
const value = features && typeof features === "object" && !Array.isArray(features) ? features.incremental_tools : undefined;
|
|
18152
|
+
return value === false ? [] : [`features.incremental_tools is ${JSON.stringify(value ?? null)}, not false`];
|
|
18153
|
+
}
|
|
18092
18154
|
function codexHostedNetworkLockGaps(config, expected = "disabled") {
|
|
18093
18155
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
18094
18156
|
return ["config/read returned no configuration"];
|
|
@@ -18102,6 +18164,7 @@ function codexHostedNetworkLockGaps(config, expected = "disabled") {
|
|
|
18102
18164
|
if (features && typeof features === "object" && features.standalone_web_search === true) {
|
|
18103
18165
|
gaps.push("features.standalone_web_search is on");
|
|
18104
18166
|
}
|
|
18167
|
+
gaps.push(...codexToolHistoryGaps(config));
|
|
18105
18168
|
return gaps;
|
|
18106
18169
|
}
|
|
18107
18170
|
function isCoordinatorReadOnlyEnvironment(env) {
|
|
@@ -18128,7 +18191,8 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
18128
18191
|
const childLimit = resolveCodexMaxConcurrentThreads(env[CODEX_MAX_CONCURRENT_THREADS_ENV]);
|
|
18129
18192
|
const overrides = {
|
|
18130
18193
|
"agents.max_concurrent_threads_per_session": String(childLimit),
|
|
18131
|
-
"features.multi_agent_v2.max_concurrent_threads_per_session": String(childLimit + 1)
|
|
18194
|
+
"features.multi_agent_v2.max_concurrent_threads_per_session": String(childLimit + 1),
|
|
18195
|
+
"features.incremental_tools": "false"
|
|
18132
18196
|
};
|
|
18133
18197
|
const rawUrl = env[ORKESTRATOR_AGENT_MCP_URL_ENV]?.trim();
|
|
18134
18198
|
const token = env[ORKESTRATOR_AGENT_MCP_TOKEN_ENV]?.trim();
|
|
@@ -18137,11 +18201,11 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
18137
18201
|
const readableRuntimeRoot = env.CODEX_BRIDGE_READABLE_RUNTIME_ROOT?.trim();
|
|
18138
18202
|
const projectRoot = env.CWD?.trim();
|
|
18139
18203
|
const attachmentRoot = env[BRIDGE_ATTACHMENT_ROOT_ENV]?.trim();
|
|
18140
|
-
if (!permissionProfile || !/^[A-Za-z0-9_-]+$/.test(permissionProfile) || !readableRuntimeRoot || !
|
|
18204
|
+
if (!permissionProfile || !/^[A-Za-z0-9_-]+$/.test(permissionProfile) || !readableRuntimeRoot || !isAbsolute6(readableRuntimeRoot) || !projectRoot || !isAbsolute6(projectRoot)) {
|
|
18141
18205
|
throw new Error("Coordinator Codex permission profile configuration is invalid");
|
|
18142
18206
|
}
|
|
18143
18207
|
overrides.default_permissions = JSON.stringify(permissionProfile);
|
|
18144
|
-
overrides[`permissions.${permissionProfile}.filesystem`] = `{ ":root" = "deny", ":minimal" = "read", ":tmpdir" = "deny", ` + `":slash_tmp" = "deny", ${JSON.stringify(readableRuntimeRoot)} = "read", ` + (attachmentRoot &&
|
|
18208
|
+
overrides[`permissions.${permissionProfile}.filesystem`] = `{ ":root" = "deny", ":minimal" = "read", ":tmpdir" = "deny", ` + `":slash_tmp" = "deny", ${JSON.stringify(readableRuntimeRoot)} = "read", ` + (attachmentRoot && isAbsolute6(attachmentRoot) ? `${JSON.stringify(attachmentRoot)} = "read", ` : "") + `":workspace_roots" = { "." = "read" } }`;
|
|
18145
18209
|
overrides[`permissions.${permissionProfile}.network.enabled`] = "false";
|
|
18146
18210
|
overrides.web_search = JSON.stringify(codexNetworkDeniedSearchMode(codexCoordinatorPolicy(env)));
|
|
18147
18211
|
overrides["features.standalone_web_search"] = "false";
|
|
@@ -18207,6 +18271,106 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
18207
18271
|
return overrides;
|
|
18208
18272
|
}
|
|
18209
18273
|
|
|
18274
|
+
// ../../bridges/codex-bridge/src/sessions/tool-history-guard.ts
|
|
18275
|
+
import { open as open5 } from "node:fs/promises";
|
|
18276
|
+
var TOOL_HISTORY_MARKER = '"type":"additional_tools"';
|
|
18277
|
+
var MAX_TOOL_HISTORY_LINEAGE_DEPTH = 32;
|
|
18278
|
+
async function rolloutDeclaresToolHistory(path, end) {
|
|
18279
|
+
const handle = await open5(path, "r");
|
|
18280
|
+
try {
|
|
18281
|
+
const size = (await handle.stat()).size;
|
|
18282
|
+
const limit = end === undefined ? size : Math.min(end, size);
|
|
18283
|
+
const marker = Buffer.from(TOOL_HISTORY_MARKER);
|
|
18284
|
+
const buffer = Buffer.allocUnsafe(ROLLOUT_CHUNK_BYTES + marker.length);
|
|
18285
|
+
let carried = 0;
|
|
18286
|
+
for (let position = 0;position < limit; ) {
|
|
18287
|
+
const length = Math.min(ROLLOUT_CHUNK_BYTES, limit - position);
|
|
18288
|
+
const { bytesRead } = await handle.read(buffer, carried, length, position);
|
|
18289
|
+
if (bytesRead <= 0)
|
|
18290
|
+
break;
|
|
18291
|
+
const filled = carried + bytesRead;
|
|
18292
|
+
if (buffer.subarray(0, filled).includes(marker))
|
|
18293
|
+
return true;
|
|
18294
|
+
position += bytesRead;
|
|
18295
|
+
carried = Math.min(marker.length - 1, filled);
|
|
18296
|
+
buffer.copy(buffer, 0, filled - carried, filled);
|
|
18297
|
+
}
|
|
18298
|
+
return false;
|
|
18299
|
+
} finally {
|
|
18300
|
+
await handle.close();
|
|
18301
|
+
}
|
|
18302
|
+
}
|
|
18303
|
+
async function historyBase(path) {
|
|
18304
|
+
const handle = await open5(path, "r");
|
|
18305
|
+
try {
|
|
18306
|
+
const chunks = [];
|
|
18307
|
+
let filled = 0;
|
|
18308
|
+
let complete = false;
|
|
18309
|
+
while (filled < MAX_ROLLOUT_RECORD_BYTES) {
|
|
18310
|
+
const chunk = Buffer.allocUnsafe(ROLLOUT_CHUNK_BYTES);
|
|
18311
|
+
const { bytesRead } = await handle.read(chunk, 0, chunk.length, filled);
|
|
18312
|
+
if (bytesRead <= 0) {
|
|
18313
|
+
complete = true;
|
|
18314
|
+
break;
|
|
18315
|
+
}
|
|
18316
|
+
const newline = chunk.subarray(0, bytesRead).indexOf(10);
|
|
18317
|
+
chunks.push(chunk.subarray(0, newline >= 0 ? newline : bytesRead));
|
|
18318
|
+
filled += bytesRead;
|
|
18319
|
+
if (newline >= 0) {
|
|
18320
|
+
complete = true;
|
|
18321
|
+
break;
|
|
18322
|
+
}
|
|
18323
|
+
}
|
|
18324
|
+
if (!complete)
|
|
18325
|
+
return "unreadable";
|
|
18326
|
+
const line = Buffer.concat(chunks).toString("utf8");
|
|
18327
|
+
if (!line.trim())
|
|
18328
|
+
return null;
|
|
18329
|
+
let record;
|
|
18330
|
+
try {
|
|
18331
|
+
record = JSON.parse(line);
|
|
18332
|
+
} catch {
|
|
18333
|
+
return "unreadable";
|
|
18334
|
+
}
|
|
18335
|
+
if (record.type !== "session_meta" || !record.payload)
|
|
18336
|
+
return null;
|
|
18337
|
+
const base = record.payload.history_base;
|
|
18338
|
+
if (base && typeof base === "object") {
|
|
18339
|
+
if (typeof base.thread_id !== "string")
|
|
18340
|
+
return "unreadable";
|
|
18341
|
+
return {
|
|
18342
|
+
threadId: base.thread_id,
|
|
18343
|
+
...typeof base.end_byte_offset === "number" ? { endByte: base.end_byte_offset } : {}
|
|
18344
|
+
};
|
|
18345
|
+
}
|
|
18346
|
+
return null;
|
|
18347
|
+
} finally {
|
|
18348
|
+
await handle.close();
|
|
18349
|
+
}
|
|
18350
|
+
}
|
|
18351
|
+
async function threadToolHistoryVerdict(rolloutPath, resolveRollout) {
|
|
18352
|
+
let path = rolloutPath;
|
|
18353
|
+
let end;
|
|
18354
|
+
for (let depth = 0;depth <= MAX_TOOL_HISTORY_LINEAGE_DEPTH; depth += 1) {
|
|
18355
|
+
if (!path)
|
|
18356
|
+
return "unknown";
|
|
18357
|
+
try {
|
|
18358
|
+
if (await rolloutDeclaresToolHistory(path, end))
|
|
18359
|
+
return "declares";
|
|
18360
|
+
const base = await historyBase(path);
|
|
18361
|
+
if (base === "unreadable")
|
|
18362
|
+
return "unknown";
|
|
18363
|
+
if (!base)
|
|
18364
|
+
return "clean";
|
|
18365
|
+
end = base.endByte;
|
|
18366
|
+
path = await resolveRollout(base.threadId);
|
|
18367
|
+
} catch {
|
|
18368
|
+
return "unknown";
|
|
18369
|
+
}
|
|
18370
|
+
}
|
|
18371
|
+
return "unknown";
|
|
18372
|
+
}
|
|
18373
|
+
|
|
18210
18374
|
// ../../bridges/codex-bridge/src/engine/mcp-tool-availability.ts
|
|
18211
18375
|
var MCP_TOOL_AVAILABILITY_TIMEOUT_MS = 5000;
|
|
18212
18376
|
var MCP_TOOL_AVAILABILITY_POLL_MS = 100;
|
|
@@ -18627,7 +18791,7 @@ function signedOutAccountRead(error) {
|
|
|
18627
18791
|
}
|
|
18628
18792
|
async function readStoredLoginFingerprint(codexHome) {
|
|
18629
18793
|
try {
|
|
18630
|
-
const file = await
|
|
18794
|
+
const file = await open6(join13(codexHome, "auth.json"), "r");
|
|
18631
18795
|
let raw;
|
|
18632
18796
|
try {
|
|
18633
18797
|
const bytes = Buffer.alloc(65537);
|
|
@@ -18676,6 +18840,9 @@ var MAX_UNKNOWN_METHODS = 16;
|
|
|
18676
18840
|
var MAX_UNKNOWN_METHOD_LENGTH = 128;
|
|
18677
18841
|
var MAX_ACCOUNT_PROOF_TURNS = 1024;
|
|
18678
18842
|
var MAX_ACCOUNT_PROOF_ID_LENGTH = 256;
|
|
18843
|
+
function deniesHostedSearch(config) {
|
|
18844
|
+
return Object.keys(codexNetworkDeniedConfig(config.policy)).length > 0 && codexNetworkDeniedSearchMode(config.policy) === "disabled";
|
|
18845
|
+
}
|
|
18679
18846
|
|
|
18680
18847
|
class AppServerEngine {
|
|
18681
18848
|
options;
|
|
@@ -18702,6 +18869,7 @@ class AppServerEngine {
|
|
|
18702
18869
|
accountProofInvalidatedSequence = 0;
|
|
18703
18870
|
accountProofTurns = new Map;
|
|
18704
18871
|
hostedNetworkLockVerifiedGeneration = null;
|
|
18872
|
+
toolHistoryLockVerifiedGeneration = null;
|
|
18705
18873
|
accountReloadFingerprint;
|
|
18706
18874
|
pendingAccountReloadFingerprint;
|
|
18707
18875
|
accountCheckSequence = 0;
|
|
@@ -18742,6 +18910,7 @@ class AppServerEngine {
|
|
|
18742
18910
|
this.clearPendingSignIn();
|
|
18743
18911
|
this.loginSequence++;
|
|
18744
18912
|
this.hostedNetworkLockVerifiedGeneration = null;
|
|
18913
|
+
this.toolHistoryLockVerifiedGeneration = null;
|
|
18745
18914
|
this.rejectAllWaiters();
|
|
18746
18915
|
this.router.abandonGeneration(generation);
|
|
18747
18916
|
}
|
|
@@ -19179,8 +19348,47 @@ class AppServerEngine {
|
|
|
19179
19348
|
this.hostedNetworkLockVerifiedGeneration = generation;
|
|
19180
19349
|
return generation;
|
|
19181
19350
|
}
|
|
19351
|
+
async assertToolHistoryLock(generation, config) {
|
|
19352
|
+
if (!deniesHostedSearch(config) || config.permissionProfile)
|
|
19353
|
+
return;
|
|
19354
|
+
if (this.toolHistoryLockVerifiedGeneration === generation)
|
|
19355
|
+
return;
|
|
19356
|
+
const result = await this.supervisor.requestOnGeneration(generation, "config/read", { cwd: config.cwd ?? this.options.cwd });
|
|
19357
|
+
const gaps = codexToolHistoryGaps(result?.config);
|
|
19358
|
+
if (gaps.length > 0) {
|
|
19359
|
+
throw new Error(`Codex did not confirm that tool declarations stay out of thread history (${gaps.join("; ")}), so this session, which has web search off, was refused`);
|
|
19360
|
+
}
|
|
19361
|
+
if (!this.supervisor.isReady() || this.supervisor.getGeneration() !== generation) {
|
|
19362
|
+
throw new Error("Codex exited during tool history verification");
|
|
19363
|
+
}
|
|
19364
|
+
this.toolHistoryLockVerifiedGeneration = generation;
|
|
19365
|
+
}
|
|
19366
|
+
async assertNoToolHistory(threadId, config, release) {
|
|
19367
|
+
if (!deniesHostedSearch(config))
|
|
19368
|
+
return;
|
|
19369
|
+
const verdict = await (this.options.toolHistoryVerdict ?? ((id) => this.readToolHistory(id)))(threadId).catch(() => "unknown");
|
|
19370
|
+
if (verdict === "clean")
|
|
19371
|
+
return;
|
|
19372
|
+
if (release) {
|
|
19373
|
+
for (const [handle, binding] of this.bindings) {
|
|
19374
|
+
if (binding.threadId === threadId)
|
|
19375
|
+
this.bindings.delete(handle);
|
|
19376
|
+
}
|
|
19377
|
+
await this.supervisor.request("thread/unsubscribe", { threadId }).catch(() => {
|
|
19378
|
+
return;
|
|
19379
|
+
});
|
|
19380
|
+
}
|
|
19381
|
+
throw new Error(verdict === "declares" ? "This Codex thread was offered web search in an earlier turn and still declares it in its history, so a turn with web search off was refused. Start a new session for it." : "Could not confirm that this Codex thread's history declares no web search, so a turn with web search off was refused.");
|
|
19382
|
+
}
|
|
19383
|
+
async readToolHistory(threadId) {
|
|
19384
|
+
const codexHome = this.options.codexHome;
|
|
19385
|
+
const resolve = async (id) => this.rolloutPaths.get(id) ?? findTranscriptPath(id, () => listTranscriptPaths(codexHome), { allowNegativeCache: false });
|
|
19386
|
+
const path = await resolve(threadId);
|
|
19387
|
+
return path ? threadToolHistoryVerdict(path, resolve) : "unknown";
|
|
19388
|
+
}
|
|
19182
19389
|
async startThread(options) {
|
|
19183
19390
|
const generation = await this.assertHostedNetworkLock(options.config);
|
|
19391
|
+
await this.assertToolHistoryLock(generation, options.config);
|
|
19184
19392
|
const extra = await this.projectResourceThreadConfig(generation, options.config);
|
|
19185
19393
|
const response = await this.supervisor.requestOnGeneration(generation, "thread/start", this.toThreadParams(options.config, extra));
|
|
19186
19394
|
this.assertPermissionProfile(response.activePermissionProfile, options.config);
|
|
@@ -19188,10 +19396,12 @@ class AppServerEngine {
|
|
|
19188
19396
|
}
|
|
19189
19397
|
async resumeThread(threadId, options) {
|
|
19190
19398
|
const generation = await this.assertHostedNetworkLock(options.config);
|
|
19399
|
+
await this.assertToolHistoryLock(generation, options.config);
|
|
19191
19400
|
const extra = await this.projectResourceThreadConfig(generation, options.config);
|
|
19192
19401
|
const response = await this.supervisor.requestOnGeneration(generation, "thread/resume", { threadId, ...this.toThreadParams(options.config, extra) });
|
|
19193
19402
|
this.assertPermissionProfile(response.activePermissionProfile, options.config);
|
|
19194
19403
|
const thread = this.bindThread(response.thread, options.config, response.model);
|
|
19404
|
+
await this.assertNoToolHistory(thread.id ?? threadId, options.config, true);
|
|
19195
19405
|
thread.turns = this.extractTurns(response.thread);
|
|
19196
19406
|
return thread;
|
|
19197
19407
|
}
|
|
@@ -19207,6 +19417,8 @@ class AppServerEngine {
|
|
|
19207
19417
|
}
|
|
19208
19418
|
async forkThread(threadId, config, lastTurnId) {
|
|
19209
19419
|
const generation = await this.assertHostedNetworkLock(config);
|
|
19420
|
+
await this.assertToolHistoryLock(generation, config);
|
|
19421
|
+
await this.assertNoToolHistory(threadId, config, false);
|
|
19210
19422
|
const extra = await this.projectResourceThreadConfig(generation, config);
|
|
19211
19423
|
const response = await this.supervisor.requestOnGeneration(generation, "thread/fork", {
|
|
19212
19424
|
threadId,
|
|
@@ -19484,7 +19696,7 @@ class AppServerEngine {
|
|
|
19484
19696
|
thread.model = confirmedModel.trim();
|
|
19485
19697
|
}
|
|
19486
19698
|
if (thread.id) {
|
|
19487
|
-
if (typeof raw.path === "string" &&
|
|
19699
|
+
if (typeof raw.path === "string" && isAbsolute7(raw.path)) {
|
|
19488
19700
|
this.rolloutPaths.set(thread.id, raw.path);
|
|
19489
19701
|
}
|
|
19490
19702
|
this.bindings.set(thread.id, {
|
|
@@ -20092,6 +20304,7 @@ class ThreadRegistry {
|
|
|
20092
20304
|
|
|
20093
20305
|
// ../../bridges/codex-bridge/src/app-server-runtime-sessions.ts
|
|
20094
20306
|
var SESSION_CLOSING_ERROR = "Session is closing";
|
|
20307
|
+
var ACTIVITY_PROCESS = randomUUID6();
|
|
20095
20308
|
|
|
20096
20309
|
class CodexRuntimeSessions {
|
|
20097
20310
|
ctx;
|
|
@@ -20949,7 +21162,8 @@ class CodexRuntimeSessions {
|
|
|
20949
21162
|
return { activity: "missing" };
|
|
20950
21163
|
return {
|
|
20951
21164
|
activity,
|
|
20952
|
-
...session.asyncQuestionItemIds.length > 0 ? { asyncQuestionItemIds: [...session.asyncQuestionItemIds] } : {}
|
|
21165
|
+
...session.asyncQuestionItemIds.length > 0 ? { asyncQuestionItemIds: [...session.asyncQuestionItemIds] } : {},
|
|
21166
|
+
contentRevision: `${ACTIVITY_PROCESS}:${session.contentEpoch}.${session.messageRevision}:${session.asyncQuestionItemIds.length}`
|
|
20953
21167
|
};
|
|
20954
21168
|
}
|
|
20955
21169
|
hasParkedInput(session) {
|
|
@@ -21440,7 +21654,7 @@ function parseCommandToken(text, sigils = ["/"]) {
|
|
|
21440
21654
|
|
|
21441
21655
|
// ../../bridges/codex-bridge/src/prompts/template-discovery.ts
|
|
21442
21656
|
import { createHash as createHash10 } from "node:crypto";
|
|
21443
|
-
import { open as
|
|
21657
|
+
import { open as open7, readdir as readdir3, stat as stat7 } from "node:fs/promises";
|
|
21444
21658
|
import { join as join14 } from "node:path";
|
|
21445
21659
|
|
|
21446
21660
|
// ../../bridges/codex-bridge/src/prompts/template-format.ts
|
|
@@ -21595,7 +21809,7 @@ function isReservedName(name) {
|
|
|
21595
21809
|
var metadataCache = new Map;
|
|
21596
21810
|
var METADATA_CACHE_MAX = 1024;
|
|
21597
21811
|
async function readBounded(absolutePath, maxBytes) {
|
|
21598
|
-
const handle = await
|
|
21812
|
+
const handle = await open7(absolutePath, "r");
|
|
21599
21813
|
try {
|
|
21600
21814
|
const info = await handle.stat();
|
|
21601
21815
|
if (!info.isFile())
|
|
@@ -21842,7 +22056,7 @@ async function loadTemplateBody(entry, limits = TEMPLATE_LIMITS) {
|
|
|
21842
22056
|
}
|
|
21843
22057
|
|
|
21844
22058
|
// ../../bridges/codex-bridge/src/commands/skill-inventory.ts
|
|
21845
|
-
import { isAbsolute as
|
|
22059
|
+
import { isAbsolute as isAbsolute8 } from "node:path";
|
|
21846
22060
|
var SKILL_INVENTORY_LIMITS = Object.freeze({
|
|
21847
22061
|
maxSkills: 512,
|
|
21848
22062
|
maxDescriptionBytes: 1000,
|
|
@@ -21892,7 +22106,7 @@ function normalizeSkillsList(raw, context) {
|
|
|
21892
22106
|
}
|
|
21893
22107
|
const name = nonEmpty(candidate.name);
|
|
21894
22108
|
const path = typeof candidate.path === "string" ? candidate.path : undefined;
|
|
21895
|
-
if (!name || !usableSkillName(name) || !path || !
|
|
22109
|
+
if (!name || !usableSkillName(name) || !path || !isAbsolute8(path)) {
|
|
21896
22110
|
truncated = true;
|
|
21897
22111
|
continue;
|
|
21898
22112
|
}
|
|
@@ -26082,6 +26296,21 @@ var codexPathOverride = process.env.CODEX_PATH || "codex";
|
|
|
26082
26296
|
var BRIDGE_VERSION = "1.0.0";
|
|
26083
26297
|
var execFile4 = promisify2(execFileCallback2);
|
|
26084
26298
|
var subscribers = new Set;
|
|
26299
|
+
var observers = new Set;
|
|
26300
|
+
function observationFrameData(sessionId) {
|
|
26301
|
+
return JSON.stringify(sessionId === undefined ? {} : { sessionId });
|
|
26302
|
+
}
|
|
26303
|
+
function notifyObservers(event, revision) {
|
|
26304
|
+
for (const observer of observers) {
|
|
26305
|
+
try {
|
|
26306
|
+
Promise.resolve(observer(event, revision, "{}")).catch((error) => {
|
|
26307
|
+
console.error("[codex-bridge] Failed to notify SSE observer:", error);
|
|
26308
|
+
});
|
|
26309
|
+
} catch (error) {
|
|
26310
|
+
console.error("[codex-bridge] Failed to notify SSE observer:", error);
|
|
26311
|
+
}
|
|
26312
|
+
}
|
|
26313
|
+
}
|
|
26085
26314
|
var MAX_REPLAY_SSE_BYTES = 4 * 1024 * 1024;
|
|
26086
26315
|
var REPLAY_IDLE_RETENTION_MS = 60000;
|
|
26087
26316
|
var SUPERSEDED_FRAME_BYTES = 64;
|
|
@@ -26349,7 +26578,7 @@ function retainedMessageId(type, payload) {
|
|
|
26349
26578
|
}
|
|
26350
26579
|
function emit(event) {
|
|
26351
26580
|
if (!replayRetentionEnabled) {
|
|
26352
|
-
eventRing.advance();
|
|
26581
|
+
notifyObservers(event, eventRing.advance());
|
|
26353
26582
|
return;
|
|
26354
26583
|
}
|
|
26355
26584
|
const sessionId = event.sessionId;
|
|
@@ -26376,6 +26605,7 @@ function emit(event) {
|
|
|
26376
26605
|
serialize: () => eager ?? serializeSseEventData({ sessionId, data: payload }),
|
|
26377
26606
|
bytes
|
|
26378
26607
|
});
|
|
26608
|
+
notifyObservers(event, revision);
|
|
26379
26609
|
for (const subscriber of subscribers) {
|
|
26380
26610
|
try {
|
|
26381
26611
|
Promise.resolve(subscriber(event, revision, eager ?? "{}")).catch((error) => {
|
|
@@ -26704,7 +26934,7 @@ app.get("/global/health", (c) => {
|
|
|
26704
26934
|
notificationDepth: health.notificationQueueDepth,
|
|
26705
26935
|
notificationHighWaterMark: health.notificationQueueHighWaterMark
|
|
26706
26936
|
},
|
|
26707
|
-
events: { ...eventRing.getStats(), subscribers: subscribers.size }
|
|
26937
|
+
events: { ...eventRing.getStats(), subscribers: subscribers.size, observers: observers.size }
|
|
26708
26938
|
}, terminal ? 503 : 200);
|
|
26709
26939
|
});
|
|
26710
26940
|
app.get("/global/auth-check", (c) => {
|
|
@@ -27219,6 +27449,7 @@ app.delete("/session/:id", async (c) => {
|
|
|
27219
27449
|
app.get("/event/subscribe", (c) => {
|
|
27220
27450
|
const cursor = parseEventCursor(c.req.query("since")) ?? parseEventCursor(c.req.header("last-event-id"));
|
|
27221
27451
|
const sessionFilter = c.req.query("sessionId")?.trim() || null;
|
|
27452
|
+
const observe = c.req.query("observe") === "1";
|
|
27222
27453
|
return streamSSE(c, async (stream) => {
|
|
27223
27454
|
let open = true;
|
|
27224
27455
|
let resolveConnectionClosed;
|
|
@@ -27244,10 +27475,10 @@ app.get("/event/subscribe", (c) => {
|
|
|
27244
27475
|
return {
|
|
27245
27476
|
event: event.type,
|
|
27246
27477
|
id: String(revision),
|
|
27247
|
-
data: serializeData()
|
|
27478
|
+
data: observe ? observationFrameData(event.sessionId) : serializeData()
|
|
27248
27479
|
};
|
|
27249
27480
|
};
|
|
27250
|
-
const releaseReplayRetention = acquireReplayRetention();
|
|
27481
|
+
const releaseReplayRetention = observe ? () => {} : acquireReplayRetention();
|
|
27251
27482
|
const anchorRevision = cursor ?? eventRing.latestRevision;
|
|
27252
27483
|
let buffered = [];
|
|
27253
27484
|
let highestSent = anchorRevision;
|
|
@@ -27269,7 +27500,7 @@ app.get("/event/subscribe", (c) => {
|
|
|
27269
27500
|
highestSent = revision;
|
|
27270
27501
|
await writeWhileOpen(frameFor(event, revision, () => serializedData));
|
|
27271
27502
|
};
|
|
27272
|
-
subscribers.add(listener);
|
|
27503
|
+
(observe ? observers : subscribers).add(listener);
|
|
27273
27504
|
let keepalive;
|
|
27274
27505
|
try {
|
|
27275
27506
|
if (sseRouteTestHooks?.afterSubscriberRegistered) {
|
|
@@ -27283,7 +27514,8 @@ app.get("/event/subscribe", (c) => {
|
|
|
27283
27514
|
status: "connected",
|
|
27284
27515
|
timestamp: new Date().toISOString(),
|
|
27285
27516
|
revision: replay?.latestRevision ?? anchorRevision,
|
|
27286
|
-
replayed: replay?.complete === true ? replay.events.length : 0
|
|
27517
|
+
replayed: replay?.complete === true ? replay.events.length : 0,
|
|
27518
|
+
...observe ? { observe: true } : {}
|
|
27287
27519
|
})
|
|
27288
27520
|
});
|
|
27289
27521
|
if (replay && !replay.complete) {
|
|
@@ -27329,6 +27561,8 @@ app.get("/event/subscribe", (c) => {
|
|
|
27329
27561
|
}
|
|
27330
27562
|
buffered = null;
|
|
27331
27563
|
keepalive = startSseKeepalive(writeWhileOpen, 5000, () => {
|
|
27564
|
+
if (observe)
|
|
27565
|
+
return false;
|
|
27332
27566
|
if (!sessionFilter)
|
|
27333
27567
|
return true;
|
|
27334
27568
|
const activity = appServerRuntime.getActivity(sessionFilter);
|
|
@@ -27348,6 +27582,7 @@ app.get("/event/subscribe", (c) => {
|
|
|
27348
27582
|
if (keepalive)
|
|
27349
27583
|
clearInterval(keepalive);
|
|
27350
27584
|
subscribers.delete(listener);
|
|
27585
|
+
observers.delete(listener);
|
|
27351
27586
|
releaseReplayRetention();
|
|
27352
27587
|
}
|
|
27353
27588
|
});
|