orkestrator 2.34.4-beta → 2.34.5-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/README.md +12 -0
- package/bin/orkestrator-launcher.js +42 -3
- package/dist/client.js +1800 -147
- package/dist/main.js +180427 -168862
- package/package.json +4 -4
- package/resources/acp-bridge/dist/index.js +22719 -0
- package/resources/claude-bridge/dist/index.js +140 -27
- package/resources/codex-bridge/dist/index.js +558 -48
- package/resources/cursor-bridge/dist/index.js +36696 -0
- package/resources/cursor-bridge/runtime/bun.lock +40 -0
- package/resources/cursor-bridge/runtime/install.json +4 -0
- package/resources/cursor-bridge/runtime/package.json +11 -0
- package/resources/cursor-bridge/runtime/patches/@cursor%2Fsdk@1.2.0.patch +19 -0
- package/resources/pi-bridge/dist/index.js +36035 -0
- package/resources/pi-bridge/runtime/bun.lock +259 -0
- package/resources/pi-bridge/runtime/install.json +4 -0
- package/resources/pi-bridge/runtime/package.json +10 -0
|
@@ -3752,6 +3752,66 @@ function structuredOutputFailure(provider, code, message, options = {}) {
|
|
|
3752
3752
|
};
|
|
3753
3753
|
}
|
|
3754
3754
|
|
|
3755
|
+
// ../protocol/src/agent-platforms.ts
|
|
3756
|
+
var AGENT_PLATFORMS = Object.freeze([
|
|
3757
|
+
"claude",
|
|
3758
|
+
"codex",
|
|
3759
|
+
"cursor",
|
|
3760
|
+
"grok",
|
|
3761
|
+
"opencode",
|
|
3762
|
+
"pi"
|
|
3763
|
+
]);
|
|
3764
|
+
var AGENT_PLATFORM_LABELS = Object.freeze({
|
|
3765
|
+
claude: "Claude Code",
|
|
3766
|
+
codex: "Codex",
|
|
3767
|
+
cursor: "Cursor Agent",
|
|
3768
|
+
grok: "Grok Build",
|
|
3769
|
+
opencode: "OpenCode",
|
|
3770
|
+
pi: "Pi"
|
|
3771
|
+
});
|
|
3772
|
+
var LEGACY_ENABLED_AGENT_PLATFORMS = Object.freeze([
|
|
3773
|
+
"claude",
|
|
3774
|
+
"codex",
|
|
3775
|
+
"opencode"
|
|
3776
|
+
]);
|
|
3777
|
+
|
|
3778
|
+
// ../protocol/src/native-agent-goal.ts
|
|
3779
|
+
var NATIVE_AGENT_GOAL_LIMITS = Object.freeze({
|
|
3780
|
+
objectiveMaxChars: 4000,
|
|
3781
|
+
checkMaxBytes: 4 * 1024,
|
|
3782
|
+
reportMessageMaxBytes: 2 * 1024,
|
|
3783
|
+
checkOutputMaxBytes: 8 * 1024,
|
|
3784
|
+
statusDetailMaxBytes: 1024,
|
|
3785
|
+
maxIterationsDefault: 20,
|
|
3786
|
+
maxIterationsLimit: 100,
|
|
3787
|
+
noProgressLimit: 3,
|
|
3788
|
+
checkTimeoutDefaultMs: 10 * 60000,
|
|
3789
|
+
checkTimeoutMaxMs: 30 * 60000,
|
|
3790
|
+
verifierModelMaxChars: 200,
|
|
3791
|
+
verifierTimeoutDefaultMs: 30 * 60000,
|
|
3792
|
+
verdictSummaryMaxBytes: 2 * 1024,
|
|
3793
|
+
verdictReasonsMax: 16,
|
|
3794
|
+
verdictReasonMaxBytes: 512,
|
|
3795
|
+
historyLimit: 5
|
|
3796
|
+
});
|
|
3797
|
+
var AGENT_GOAL_TOOL_NAMES = Object.freeze(["report_goal"]);
|
|
3798
|
+
var GOAL_QUALIFIED_PLATFORMS = Object.freeze([
|
|
3799
|
+
"claude",
|
|
3800
|
+
"codex",
|
|
3801
|
+
"opencode",
|
|
3802
|
+
"cursor",
|
|
3803
|
+
"grok",
|
|
3804
|
+
"pi"
|
|
3805
|
+
]);
|
|
3806
|
+
var GOAL_TOKEN_BUDGET_PLATFORMS = Object.freeze([
|
|
3807
|
+
"claude",
|
|
3808
|
+
"codex",
|
|
3809
|
+
"opencode",
|
|
3810
|
+
"cursor",
|
|
3811
|
+
"grok",
|
|
3812
|
+
"pi"
|
|
3813
|
+
]);
|
|
3814
|
+
|
|
3755
3815
|
// ../protocol/src/permission-rules.ts
|
|
3756
3816
|
var PERMISSION_RULE_KINDS = [
|
|
3757
3817
|
"command-prefix",
|
|
@@ -4153,29 +4213,6 @@ var JOURNAL_ENVELOPE_BYTES = serializedBytes({
|
|
|
4153
4213
|
entries: []
|
|
4154
4214
|
});
|
|
4155
4215
|
|
|
4156
|
-
// ../protocol/src/agent-platforms.ts
|
|
4157
|
-
var AGENT_PLATFORMS = Object.freeze([
|
|
4158
|
-
"claude",
|
|
4159
|
-
"codex",
|
|
4160
|
-
"cursor",
|
|
4161
|
-
"grok",
|
|
4162
|
-
"opencode",
|
|
4163
|
-
"pi"
|
|
4164
|
-
]);
|
|
4165
|
-
var AGENT_PLATFORM_LABELS = Object.freeze({
|
|
4166
|
-
claude: "Claude Code",
|
|
4167
|
-
codex: "Codex",
|
|
4168
|
-
cursor: "Cursor Agent",
|
|
4169
|
-
grok: "Grok Build",
|
|
4170
|
-
opencode: "OpenCode",
|
|
4171
|
-
pi: "Pi"
|
|
4172
|
-
});
|
|
4173
|
-
var LEGACY_ENABLED_AGENT_PLATFORMS = Object.freeze([
|
|
4174
|
-
"claude",
|
|
4175
|
-
"codex",
|
|
4176
|
-
"opencode"
|
|
4177
|
-
]);
|
|
4178
|
-
|
|
4179
4216
|
// ../protocol/src/native-agent-transcript-patch.ts
|
|
4180
4217
|
var FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
4181
4218
|
|
|
@@ -4542,6 +4579,7 @@ var PROJECTION_FIELD_SET = new Set([
|
|
|
4542
4579
|
"queue",
|
|
4543
4580
|
"asyncQuestionResponses",
|
|
4544
4581
|
"contextUsage",
|
|
4582
|
+
"goal",
|
|
4545
4583
|
"rateLimits",
|
|
4546
4584
|
"runtime",
|
|
4547
4585
|
"runtimeHealthAuthoritative",
|
|
@@ -4566,6 +4604,7 @@ var OPTIONAL_PROJECTION_FIELD_SET = new Set([
|
|
|
4566
4604
|
"queue",
|
|
4567
4605
|
"asyncQuestionResponses",
|
|
4568
4606
|
"contextUsage",
|
|
4607
|
+
"goal",
|
|
4569
4608
|
"rateLimits",
|
|
4570
4609
|
"runtime",
|
|
4571
4610
|
"runtimeHealthAuthoritative",
|
|
@@ -5522,7 +5561,7 @@ function parseSessionActivityObservation(value) {
|
|
|
5522
5561
|
if (!isRecord(value))
|
|
5523
5562
|
return;
|
|
5524
5563
|
const { activity, readyForInput, completionPending, asyncQuestionItemIds, closing } = value;
|
|
5525
|
-
const { contentRevision } = value;
|
|
5564
|
+
const { contentRevision, turnFailed } = value;
|
|
5526
5565
|
if (typeof activity !== "string" || !SESSION_ACTIVITY_STATES.has(activity))
|
|
5527
5566
|
return;
|
|
5528
5567
|
if (readyForInput !== undefined && typeof readyForInput !== "boolean")
|
|
@@ -5531,6 +5570,8 @@ function parseSessionActivityObservation(value) {
|
|
|
5531
5570
|
return;
|
|
5532
5571
|
if (closing !== undefined && typeof closing !== "boolean")
|
|
5533
5572
|
return;
|
|
5573
|
+
if (turnFailed !== undefined && typeof turnFailed !== "boolean")
|
|
5574
|
+
return;
|
|
5534
5575
|
if (contentRevision !== undefined && !isContentRevision(contentRevision))
|
|
5535
5576
|
return;
|
|
5536
5577
|
let itemIds;
|
|
@@ -5546,6 +5587,7 @@ function parseSessionActivityObservation(value) {
|
|
|
5546
5587
|
...completionPending !== undefined ? { completionPending } : {},
|
|
5547
5588
|
...itemIds !== undefined ? { asyncQuestionItemIds: itemIds } : {},
|
|
5548
5589
|
...closing !== undefined ? { closing } : {},
|
|
5590
|
+
...turnFailed === true ? { turnFailed } : {},
|
|
5549
5591
|
...contentRevision !== undefined ? { contentRevision } : {}
|
|
5550
5592
|
};
|
|
5551
5593
|
}
|
|
@@ -12074,6 +12116,7 @@ function unconfirmedTurnId(requestId) {
|
|
|
12074
12116
|
class TurnAccumulator {
|
|
12075
12117
|
threadId;
|
|
12076
12118
|
requestId;
|
|
12119
|
+
providerRequestId;
|
|
12077
12120
|
expectsStructuredOutput;
|
|
12078
12121
|
assistantMessageId;
|
|
12079
12122
|
startedAt;
|
|
@@ -12083,6 +12126,7 @@ class TurnAccumulator {
|
|
|
12083
12126
|
phase = "starting";
|
|
12084
12127
|
cancelRequested = false;
|
|
12085
12128
|
stoppedByShutdown = false;
|
|
12129
|
+
capacityRetry;
|
|
12086
12130
|
error;
|
|
12087
12131
|
finalDiff;
|
|
12088
12132
|
completedAt;
|
|
@@ -12362,12 +12406,22 @@ class TurnAccumulator {
|
|
|
12362
12406
|
if (error)
|
|
12363
12407
|
this.error = error;
|
|
12364
12408
|
this.completedAt = new Date().toISOString();
|
|
12409
|
+
this.settleEndedAttempt();
|
|
12410
|
+
}
|
|
12411
|
+
settleEndedAttempt() {
|
|
12365
12412
|
this.interruptOpenAgentMessages();
|
|
12366
12413
|
for (const accumulator of this.items.values()) {
|
|
12367
12414
|
if (!accumulator.completed && !accumulator.interrupted)
|
|
12368
12415
|
this.touch(accumulator);
|
|
12369
12416
|
}
|
|
12370
12417
|
}
|
|
12418
|
+
recordRetryCard(id, text, state) {
|
|
12419
|
+
this.onItemCompleted({ id, type: "retry", text, state });
|
|
12420
|
+
}
|
|
12421
|
+
retryCardState(id) {
|
|
12422
|
+
const item = this.items.get(id)?.item;
|
|
12423
|
+
return item?.type === "retry" ? item.state : undefined;
|
|
12424
|
+
}
|
|
12371
12425
|
recordProviderFailure(error) {
|
|
12372
12426
|
this.onItemCompleted({
|
|
12373
12427
|
id: turnFailureItemId(this.turnId),
|
|
@@ -12820,6 +12874,8 @@ async function itemToParts(item, cwd, fileChangeContext) {
|
|
|
12820
12874
|
...item.severity ? { severity: item.severity } : {}
|
|
12821
12875
|
}
|
|
12822
12876
|
];
|
|
12877
|
+
case "retry":
|
|
12878
|
+
return [{ type: "retry", content: item.text, toolState: item.state }];
|
|
12823
12879
|
default: {
|
|
12824
12880
|
const unknown = item;
|
|
12825
12881
|
const name = typeof unknown.type === "string" ? unknown.type : "unknown";
|
|
@@ -13012,16 +13068,19 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
13012
13068
|
"add_ticket_comment",
|
|
13013
13069
|
"address_multi_review",
|
|
13014
13070
|
"adopt_workflow",
|
|
13071
|
+
"answer_worker_question",
|
|
13015
13072
|
"cancel_build_pipeline",
|
|
13016
13073
|
"cancel_graph_run",
|
|
13017
13074
|
"cancel_multi_review",
|
|
13018
13075
|
"cancel_schedule",
|
|
13076
|
+
"clear_worker_goal",
|
|
13019
13077
|
"compare_project_files",
|
|
13020
13078
|
"create_pr",
|
|
13021
13079
|
"create_schedule",
|
|
13022
13080
|
"create_ticket",
|
|
13023
13081
|
"custom_fix_multi_review",
|
|
13024
13082
|
"edit_worker_tab",
|
|
13083
|
+
"fork_worker",
|
|
13025
13084
|
"get_build_pipeline",
|
|
13026
13085
|
"get_environment",
|
|
13027
13086
|
"get_feature_plan",
|
|
@@ -13034,6 +13093,9 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
13034
13093
|
"get_tab_state",
|
|
13035
13094
|
"get_tab_transcript",
|
|
13036
13095
|
"get_ticket",
|
|
13096
|
+
"get_usage_limits",
|
|
13097
|
+
"get_worker_changes",
|
|
13098
|
+
"get_worker_goal",
|
|
13037
13099
|
"launch_environment",
|
|
13038
13100
|
"launch_feature_plan",
|
|
13039
13101
|
"launch_graph",
|
|
@@ -13048,14 +13110,18 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
13048
13110
|
"list_node_environments",
|
|
13049
13111
|
"list_nodes",
|
|
13050
13112
|
"list_projects",
|
|
13113
|
+
"list_provider_accounts",
|
|
13051
13114
|
"list_schedules",
|
|
13052
13115
|
"list_tabs",
|
|
13053
13116
|
"list_tickets",
|
|
13117
|
+
"list_worker_commands",
|
|
13054
13118
|
"list_workflows",
|
|
13055
13119
|
"open_multi_review",
|
|
13056
13120
|
"open_multi_review_fix",
|
|
13057
13121
|
"open_worker_browser",
|
|
13058
13122
|
"pause_build_pipeline",
|
|
13123
|
+
"pause_schedule",
|
|
13124
|
+
"pause_worker_goal",
|
|
13059
13125
|
"propose_agents_md_update",
|
|
13060
13126
|
"read_messages",
|
|
13061
13127
|
"read_node_environment",
|
|
@@ -13064,18 +13130,25 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
13064
13130
|
"request_project_file_update",
|
|
13065
13131
|
"request_project_on_node",
|
|
13066
13132
|
"request_root_changes",
|
|
13133
|
+
"resolve_conflicts",
|
|
13067
13134
|
"resume_build_pipeline",
|
|
13135
|
+
"resume_schedule",
|
|
13136
|
+
"run_worker_command",
|
|
13068
13137
|
"send_message",
|
|
13069
13138
|
"send_node_message",
|
|
13070
13139
|
"send_prompt_to_node_tab",
|
|
13071
13140
|
"send_prompt_to_tab",
|
|
13141
|
+
"set_worker_goal",
|
|
13072
13142
|
"start_build_pipeline",
|
|
13073
13143
|
"start_environment",
|
|
13074
13144
|
"start_multi_review",
|
|
13075
13145
|
"start_node_environment",
|
|
13076
13146
|
"stop_environment",
|
|
13077
13147
|
"stop_node_environment",
|
|
13148
|
+
"stop_worker_turn",
|
|
13149
|
+
"switch_provider_account",
|
|
13078
13150
|
"transfer_files",
|
|
13151
|
+
"update_schedule",
|
|
13079
13152
|
"update_ticket"
|
|
13080
13153
|
]);
|
|
13081
13154
|
var COORDINATOR_CONTEXT_OPEN_TAG = "<orkestrator-coordinator-context>";
|
|
@@ -13089,6 +13162,78 @@ function stripCoordinatorContext(text) {
|
|
|
13089
13162
|
return text.slice(end + COORDINATOR_CONTEXT_CLOSE_TAG.length).replace(/^\s+/, "");
|
|
13090
13163
|
}
|
|
13091
13164
|
|
|
13165
|
+
// ../protocol/src/capacity-retry.ts
|
|
13166
|
+
var DEFAULT_CAPACITY_RETRY_POLICY = {
|
|
13167
|
+
maxAttempts: 5,
|
|
13168
|
+
baseDelayMs: 2000,
|
|
13169
|
+
multiplier: 3,
|
|
13170
|
+
maxDelayMs: 60000
|
|
13171
|
+
};
|
|
13172
|
+
function capacityRetryDelayMs(policy, nextAttempt, random = Math.random) {
|
|
13173
|
+
const retryIndex = Math.max(0, nextAttempt - 2);
|
|
13174
|
+
const nominal = Math.min(policy.maxDelayMs, policy.baseDelayMs * policy.multiplier ** retryIndex);
|
|
13175
|
+
const unit = Math.min(1, Math.max(0, random()));
|
|
13176
|
+
return Math.round(nominal / 2 + nominal / 2 * unit);
|
|
13177
|
+
}
|
|
13178
|
+
function formatRetryDelay(delayMs) {
|
|
13179
|
+
return `${Math.max(1, Math.round(delayMs / 1000))} s`;
|
|
13180
|
+
}
|
|
13181
|
+
|
|
13182
|
+
// ../../bridges/codex-bridge/src/sessions/capacity-retry.ts
|
|
13183
|
+
var CODEX_SERVER_OVERLOADED_MESSAGE = "Selected model is at capacity. Please try a different model.";
|
|
13184
|
+
var CODEX_POLICY_CAPACITY_UNAVAILABLE_MESSAGE = "Policy-restricted capacity is unavailable. Please try again later.";
|
|
13185
|
+
var CAPACITY_CODES = new Set(["serverOverloaded", "policyCapacityUnavailable"]);
|
|
13186
|
+
var CAPACITY_MESSAGES = new Set([
|
|
13187
|
+
CODEX_SERVER_OVERLOADED_MESSAGE,
|
|
13188
|
+
CODEX_POLICY_CAPACITY_UNAVAILABLE_MESSAGE
|
|
13189
|
+
]);
|
|
13190
|
+
function isModelCapacityError(error) {
|
|
13191
|
+
if (!error)
|
|
13192
|
+
return false;
|
|
13193
|
+
if (error.httpStatusCode === 401 || error.httpStatusCode === 403)
|
|
13194
|
+
return false;
|
|
13195
|
+
if (error.code !== undefined)
|
|
13196
|
+
return CAPACITY_CODES.has(error.code);
|
|
13197
|
+
return CAPACITY_MESSAGES.has(error.message.trim());
|
|
13198
|
+
}
|
|
13199
|
+
function capacityRetryWaitingText(delayMs, nextAttempt, maxAttempts) {
|
|
13200
|
+
return `Model at capacity, retrying in ${formatRetryDelay(delayMs)} (attempt ${nextAttempt} of ${maxAttempts})`;
|
|
13201
|
+
}
|
|
13202
|
+
function capacityRetryStartedText(nextAttempt, maxAttempts) {
|
|
13203
|
+
return `Model at capacity, retried automatically (attempt ${nextAttempt} of ${maxAttempts})`;
|
|
13204
|
+
}
|
|
13205
|
+
var CAPACITY_RETRY_CANCELLED_TEXT = "Model at capacity, automatic retry cancelled";
|
|
13206
|
+
var CAPACITY_RETRY_START_FAILED_TEXT = "Model at capacity, automatic retry could not be started";
|
|
13207
|
+
function capacityRetriesExhaustedError(error, attempts) {
|
|
13208
|
+
return {
|
|
13209
|
+
...error,
|
|
13210
|
+
message: `${error.message} Automatic retries exhausted after ${attempts} attempts.`
|
|
13211
|
+
};
|
|
13212
|
+
}
|
|
13213
|
+
function capacityRetryItemId(requestId, nextAttempt) {
|
|
13214
|
+
return `capacity-retry:${requestId}:${nextAttempt}`;
|
|
13215
|
+
}
|
|
13216
|
+
function capacityRetryClientId(requestId, nextAttempt) {
|
|
13217
|
+
return `${requestId}:capacity-retry:${nextAttempt}`;
|
|
13218
|
+
}
|
|
13219
|
+
var CAPACITY_RETRY_CONTINUATION_MARKER = "[Orkestrator automatic retry]";
|
|
13220
|
+
function capacityRetryContinuationText(nextAttempt, maxAttempts) {
|
|
13221
|
+
return [
|
|
13222
|
+
`${CAPACITY_RETRY_CONTINUATION_MARKER} attempt ${nextAttempt} of ${maxAttempts}.`,
|
|
13223
|
+
"The previous attempt of this turn ended because the model was at capacity. This message was sent automatically, not by the user.",
|
|
13224
|
+
"Continue the original request from where it stopped. Do not repeat work or tool calls that already completed; check the conversation so far and finish the request."
|
|
13225
|
+
].join(`
|
|
13226
|
+
`);
|
|
13227
|
+
}
|
|
13228
|
+
function parseCapacityRetryContinuation(text) {
|
|
13229
|
+
if (!text.startsWith(CAPACITY_RETRY_CONTINUATION_MARKER))
|
|
13230
|
+
return;
|
|
13231
|
+
const match = /^ attempt (\d+) of (\d+)\./.exec(text.slice(CAPACITY_RETRY_CONTINUATION_MARKER.length));
|
|
13232
|
+
if (!match)
|
|
13233
|
+
return;
|
|
13234
|
+
return { attempt: Number(match[1]), maxAttempts: Number(match[2]) };
|
|
13235
|
+
}
|
|
13236
|
+
|
|
13092
13237
|
// ../../bridges/codex-bridge/src/history/rollout.ts
|
|
13093
13238
|
function getCodexHomeDir() {
|
|
13094
13239
|
return process.env.CODEX_HOME || join11(homedir(), ".codex");
|
|
@@ -14126,6 +14271,20 @@ async function replayPersistedRollout(threadId, snapshot, meta, structuredTurns)
|
|
|
14126
14271
|
assistantMessage.parts.push({ type: "text", content: displayText });
|
|
14127
14272
|
return;
|
|
14128
14273
|
}
|
|
14274
|
+
const continuation = parseCapacityRetryContinuation(text);
|
|
14275
|
+
if (continuation) {
|
|
14276
|
+
const previous = messages.at(-1);
|
|
14277
|
+
const row = previous?.role === "assistant" ? previous : ensureAssistantMessage(timestamp);
|
|
14278
|
+
const last = row.parts.at(-1);
|
|
14279
|
+
if (last?.type === "status" && last.severity === "error")
|
|
14280
|
+
row.parts.pop();
|
|
14281
|
+
row.parts.push({
|
|
14282
|
+
type: "retry",
|
|
14283
|
+
content: capacityRetryStartedText(continuation.attempt, continuation.maxAttempts),
|
|
14284
|
+
toolState: "success"
|
|
14285
|
+
});
|
|
14286
|
+
return;
|
|
14287
|
+
}
|
|
14129
14288
|
closeAssistantRow();
|
|
14130
14289
|
messages.push({
|
|
14131
14290
|
id: nextRowId("user"),
|
|
@@ -18650,7 +18809,7 @@ function isPersistedRecord(value) {
|
|
|
18650
18809
|
if (!value || typeof value !== "object")
|
|
18651
18810
|
return false;
|
|
18652
18811
|
const record = value;
|
|
18653
|
-
if (typeof record.requestId !== "string" || record.requestId.length === 0 || typeof record.bridgeSessionId !== "string" || record.threadId !== null && typeof record.threadId !== "string" || !isOptionalString(record.turnId) || !DISPATCH_STATES.has(record.state) || !isTimestamp(record.createdAt) || !isTimestamp(record.updatedAt) || record.quarantined !== undefined && record.quarantined !== true) {
|
|
18812
|
+
if (typeof record.requestId !== "string" || record.requestId.length === 0 || typeof record.bridgeSessionId !== "string" || record.threadId !== null && typeof record.threadId !== "string" || !isOptionalString(record.turnId) || !isOptionalString(record.providerRequestId) || !DISPATCH_STATES.has(record.state) || !isTimestamp(record.createdAt) || !isTimestamp(record.updatedAt) || record.quarantined !== undefined && record.quarantined !== true) {
|
|
18654
18813
|
return false;
|
|
18655
18814
|
}
|
|
18656
18815
|
if (record.state === "accepted") {
|
|
@@ -18858,6 +19017,21 @@ class DispatchJournal {
|
|
|
18858
19017
|
await this.flush({ failClosed: true });
|
|
18859
19018
|
return record;
|
|
18860
19019
|
}
|
|
19020
|
+
async markContinuation(requestId, providerRequestId) {
|
|
19021
|
+
if (this.integrityError)
|
|
19022
|
+
throw new DispatchJournalIntegrityError(this.integrityError);
|
|
19023
|
+
const existing = this.records.get(requestId);
|
|
19024
|
+
if (!existing || existing.quarantined) {
|
|
19025
|
+
throw new DispatchJournalIntegrityError(`Dispatch ${requestId} is unavailable`);
|
|
19026
|
+
}
|
|
19027
|
+
this.records.set(requestId, {
|
|
19028
|
+
...existing,
|
|
19029
|
+
providerRequestId,
|
|
19030
|
+
updatedAt: new Date(this.now()).toISOString(),
|
|
19031
|
+
sequence: ++this.nextSequence
|
|
19032
|
+
});
|
|
19033
|
+
await this.flush({ failClosed: true });
|
|
19034
|
+
}
|
|
18861
19035
|
async markAccepted(requestId, options) {
|
|
18862
19036
|
if (this.integrityError)
|
|
18863
19037
|
throw new DispatchJournalIntegrityError(this.integrityError);
|
|
@@ -18868,6 +19042,7 @@ class DispatchJournal {
|
|
|
18868
19042
|
const timestamp = new Date(this.now()).toISOString();
|
|
18869
19043
|
this.records.set(requestId, {
|
|
18870
19044
|
requestId,
|
|
19045
|
+
providerRequestId: existing?.providerRequestId,
|
|
18871
19046
|
bridgeSessionId: existing?.bridgeSessionId ?? "",
|
|
18872
19047
|
threadId: options.threadId,
|
|
18873
19048
|
turnId: options.turnId,
|
|
@@ -18887,6 +19062,7 @@ class DispatchJournal {
|
|
|
18887
19062
|
const timestamp = new Date(this.now()).toISOString();
|
|
18888
19063
|
this.records.set(requestId, {
|
|
18889
19064
|
requestId,
|
|
19065
|
+
providerRequestId: existing?.providerRequestId,
|
|
18890
19066
|
bridgeSessionId: existing?.bridgeSessionId ?? "",
|
|
18891
19067
|
threadId: options.threadId ?? existing?.threadId ?? null,
|
|
18892
19068
|
turnId: options.turnId ?? existing?.turnId,
|
|
@@ -18908,6 +19084,7 @@ class DispatchJournal {
|
|
|
18908
19084
|
const timestamp = new Date(this.now()).toISOString();
|
|
18909
19085
|
this.records.set(requestId, {
|
|
18910
19086
|
requestId,
|
|
19087
|
+
providerRequestId: existing?.providerRequestId,
|
|
18911
19088
|
bridgeSessionId: existing?.bridgeSessionId ?? "",
|
|
18912
19089
|
threadId: existing?.threadId ?? null,
|
|
18913
19090
|
state: "retryable",
|
|
@@ -19543,7 +19720,8 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
19543
19720
|
const overrides = {
|
|
19544
19721
|
"agents.max_concurrent_threads_per_session": String(childLimit),
|
|
19545
19722
|
"features.multi_agent_v2.max_concurrent_threads_per_session": String(childLimit + 1),
|
|
19546
|
-
"features.incremental_tools": "false"
|
|
19723
|
+
"features.incremental_tools": "false",
|
|
19724
|
+
"features.goals": "false"
|
|
19547
19725
|
};
|
|
19548
19726
|
const rawUrl = env[ORKESTRATOR_AGENT_MCP_URL_ENV]?.trim();
|
|
19549
19727
|
const token = env[ORKESTRATOR_AGENT_MCP_TOKEN_ENV]?.trim();
|
|
@@ -19613,7 +19791,11 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
19613
19791
|
if (isCoordinatorReadOnlyEnvironment(env)) {
|
|
19614
19792
|
overrides["mcp_servers.orkestrator.default_tools_approval_mode"] = JSON.stringify("approve");
|
|
19615
19793
|
} else {
|
|
19616
|
-
for (const name of [
|
|
19794
|
+
for (const name of [
|
|
19795
|
+
...AGENT_MAIL_TOOL_NAMES,
|
|
19796
|
+
...ARTIFACT_TOOL_NAMES,
|
|
19797
|
+
...AGENT_GOAL_TOOL_NAMES
|
|
19798
|
+
]) {
|
|
19617
19799
|
overrides[`mcp_servers.orkestrator.tools.${name}.approval_mode`] = JSON.stringify("approve");
|
|
19618
19800
|
}
|
|
19619
19801
|
}
|
|
@@ -19781,7 +19963,7 @@ var APP_SERVER_CAPABILITIES = {
|
|
|
19781
19963
|
};
|
|
19782
19964
|
|
|
19783
19965
|
// ../../bridges/codex-bridge/src/engine/app-server-engine.ts
|
|
19784
|
-
var AGENT_MAIL_TOOL_APPROVALS = Object.fromEntries([...AGENT_MAIL_TOOL_NAMES, ...ARTIFACT_TOOL_NAMES].map((name) => [
|
|
19966
|
+
var AGENT_MAIL_TOOL_APPROVALS = Object.fromEntries([...AGENT_MAIL_TOOL_NAMES, ...ARTIFACT_TOOL_NAMES, ...AGENT_GOAL_TOOL_NAMES].map((name) => [
|
|
19785
19967
|
name,
|
|
19786
19968
|
{ approval_mode: "approve" }
|
|
19787
19969
|
]));
|
|
@@ -21226,7 +21408,11 @@ class AppServerEngine {
|
|
|
21226
21408
|
return {
|
|
21227
21409
|
id: String(turn.id ?? ""),
|
|
21228
21410
|
status: turn.status ?? "completed",
|
|
21229
|
-
items:
|
|
21411
|
+
items: items.flatMap((item) => {
|
|
21412
|
+
const adapted = adaptAppServerItem(item).item;
|
|
21413
|
+
return adapted ? [adapted] : [];
|
|
21414
|
+
}),
|
|
21415
|
+
...turn.error ? { error: toTurnError(turn.error) } : {},
|
|
21230
21416
|
clientId: clientIds[0] ?? null,
|
|
21231
21417
|
clientIds,
|
|
21232
21418
|
reconciliationItems,
|
|
@@ -21377,7 +21563,13 @@ class AppServerEngine {
|
|
|
21377
21563
|
clientId
|
|
21378
21564
|
}))
|
|
21379
21565
|
}));
|
|
21380
|
-
|
|
21566
|
+
const outcome = reconcileFromThreadTurns(turns, requestId);
|
|
21567
|
+
const matched = thread?.turns?.find((turn) => turn.id === outcome.turnId);
|
|
21568
|
+
return {
|
|
21569
|
+
...outcome,
|
|
21570
|
+
...matched?.items.length ? { items: matched.items } : {},
|
|
21571
|
+
...matched?.error ? { error: matched.error } : {}
|
|
21572
|
+
};
|
|
21381
21573
|
}
|
|
21382
21574
|
classifyFailure(error) {
|
|
21383
21575
|
return {
|
|
@@ -22725,8 +22917,10 @@ class CodexRuntimeSessions {
|
|
|
22725
22917
|
const session = this.ctx.registry.getSession(sessionId);
|
|
22726
22918
|
if (!session)
|
|
22727
22919
|
return { activity: "missing" };
|
|
22920
|
+
const turnFailed = activity === "idle" && (this.ctx.registry.getThreadForSession(sessionId)?.phase ?? (session.restartFailure ? "failed" : "idle")) === "failed";
|
|
22728
22921
|
return {
|
|
22729
22922
|
activity,
|
|
22923
|
+
...turnFailed ? { turnFailed: true } : {},
|
|
22730
22924
|
...session.asyncQuestionItemIds.length > 0 ? { asyncQuestionItemIds: [...session.asyncQuestionItemIds] } : {},
|
|
22731
22925
|
contentRevision: `${ACTIVITY_PROCESS}:${session.contentEpoch}.${session.messageRevision}:${session.asyncQuestionItemIds.length}`
|
|
22732
22926
|
};
|
|
@@ -22771,9 +22965,11 @@ class CodexRuntimeSessions {
|
|
|
22771
22965
|
const context = this.ctx.registry.getThreadForSession(sessionId);
|
|
22772
22966
|
const turn = context?.activeTurn;
|
|
22773
22967
|
if (context && turn && context.bridgeSessionIds.size === 1) {
|
|
22774
|
-
await this.
|
|
22775
|
-
|
|
22776
|
-
|
|
22968
|
+
if (!await this.lifecycle.capacityRetry.cancelForClose(context, turn)) {
|
|
22969
|
+
await this.ctx.options.engine.interruptTurn(context.engineHandle, turn.turnId).catch(() => {
|
|
22970
|
+
return;
|
|
22971
|
+
});
|
|
22972
|
+
}
|
|
22777
22973
|
}
|
|
22778
22974
|
this.retiredSessions.add(session);
|
|
22779
22975
|
try {
|
|
@@ -24371,6 +24567,256 @@ class UpdateCoalescer {
|
|
|
24371
24567
|
}
|
|
24372
24568
|
}
|
|
24373
24569
|
|
|
24570
|
+
// ../../bridges/codex-bridge/src/app-server-runtime-capacity-retry.ts
|
|
24571
|
+
import { stat as stat8 } from "node:fs/promises";
|
|
24572
|
+
class CodexCapacityRetry {
|
|
24573
|
+
ctx;
|
|
24574
|
+
lifecycle;
|
|
24575
|
+
pending = new Map;
|
|
24576
|
+
constructor(ctx, lifecycle) {
|
|
24577
|
+
this.ctx = ctx;
|
|
24578
|
+
this.lifecycle = lifecycle;
|
|
24579
|
+
}
|
|
24580
|
+
policy() {
|
|
24581
|
+
return { ...DEFAULT_CAPACITY_RETRY_POLICY, ...this.ctx.options.capacityRetry };
|
|
24582
|
+
}
|
|
24583
|
+
isPending(turn) {
|
|
24584
|
+
return this.pending.has(turn);
|
|
24585
|
+
}
|
|
24586
|
+
onTurnFailed(context, turn, error) {
|
|
24587
|
+
const plan = turn.capacityRetry;
|
|
24588
|
+
if (!plan || !turn.requestId || !isModelCapacityError(error))
|
|
24589
|
+
return { retrying: false };
|
|
24590
|
+
const policy = this.policy();
|
|
24591
|
+
if (plan.attempt >= policy.maxAttempts) {
|
|
24592
|
+
return {
|
|
24593
|
+
retrying: false,
|
|
24594
|
+
...plan.attempt > 1 ? { error: capacityRetriesExhaustedError(error, plan.attempt) } : {}
|
|
24595
|
+
};
|
|
24596
|
+
}
|
|
24597
|
+
if (this.ctx.stopping || turn.cancelRequested || turn.stoppedByShutdown || context.phase !== "running" || context.bridgeSessionIds.size === 0) {
|
|
24598
|
+
return { retrying: false };
|
|
24599
|
+
}
|
|
24600
|
+
const attempt = plan.attempt + 1;
|
|
24601
|
+
const delayMs = capacityRetryDelayMs(policy, attempt, this.ctx.options.capacityRetryRandom);
|
|
24602
|
+
const itemId = capacityRetryItemId(turn.requestId, attempt);
|
|
24603
|
+
turn.settleEndedAttempt();
|
|
24604
|
+
turn.error = undefined;
|
|
24605
|
+
turn.recordRetryCard(itemId, capacityRetryWaitingText(delayMs, attempt, policy.maxAttempts), "pending");
|
|
24606
|
+
const entry = { attempt, itemId, error, stage: "waiting" };
|
|
24607
|
+
entry.timer = setTimeout(() => this.fire(context, turn), delayMs);
|
|
24608
|
+
entry.timer.unref?.();
|
|
24609
|
+
this.pending.set(turn, entry);
|
|
24610
|
+
this.publish(context);
|
|
24611
|
+
return { retrying: true };
|
|
24612
|
+
}
|
|
24613
|
+
stop(context, turn) {
|
|
24614
|
+
const entry = this.pending.get(turn);
|
|
24615
|
+
if (!entry)
|
|
24616
|
+
return false;
|
|
24617
|
+
turn.markCancelling();
|
|
24618
|
+
this.ctx.registry.setPhase(context, "cancelling");
|
|
24619
|
+
this.lifecycle.emitStatus(context);
|
|
24620
|
+
if (entry.stage === "starting") {
|
|
24621
|
+
entry.stopAfterStart = true;
|
|
24622
|
+
return true;
|
|
24623
|
+
}
|
|
24624
|
+
this.end(context, turn, "interrupted");
|
|
24625
|
+
return true;
|
|
24626
|
+
}
|
|
24627
|
+
async cancelForClose(context, turn) {
|
|
24628
|
+
const entry = this.pending.get(turn);
|
|
24629
|
+
if (!entry || !this.stop(context, turn))
|
|
24630
|
+
return false;
|
|
24631
|
+
await entry.work;
|
|
24632
|
+
if (!turn.isTerminal()) {
|
|
24633
|
+
await this.ctx.options.engine.waitForTurnTerminal(context.engineHandle, turn.turnId, {
|
|
24634
|
+
allowRestart: true
|
|
24635
|
+
});
|
|
24636
|
+
if (!turn.isTerminal()) {
|
|
24637
|
+
turn.complete("interrupted");
|
|
24638
|
+
await this.lifecycle.runFinalization(context, turn);
|
|
24639
|
+
}
|
|
24640
|
+
}
|
|
24641
|
+
return true;
|
|
24642
|
+
}
|
|
24643
|
+
endForParentExit(context, turn) {
|
|
24644
|
+
const entry = this.pending.get(turn);
|
|
24645
|
+
if (!entry || entry.stage !== "waiting")
|
|
24646
|
+
return false;
|
|
24647
|
+
turn.stoppedByShutdown = true;
|
|
24648
|
+
this.clear(turn, entry, CAPACITY_RETRY_CANCELLED_TEXT);
|
|
24649
|
+
this.lifecycle.completeRecoveredTurn(turn, "interrupted");
|
|
24650
|
+
this.lifecycle.runFinalization(context, turn);
|
|
24651
|
+
return true;
|
|
24652
|
+
}
|
|
24653
|
+
dispose() {
|
|
24654
|
+
for (const [turn, entry] of Array.from(this.pending)) {
|
|
24655
|
+
if (entry.stage !== "waiting")
|
|
24656
|
+
continue;
|
|
24657
|
+
const context = this.ctx.registry.getThread(turn.threadId);
|
|
24658
|
+
if (!context || context.activeTurn !== turn) {
|
|
24659
|
+
this.clear(turn, entry, CAPACITY_RETRY_CANCELLED_TEXT);
|
|
24660
|
+
continue;
|
|
24661
|
+
}
|
|
24662
|
+
this.end(context, turn, "failed", entry.error, CAPACITY_RETRY_CANCELLED_TEXT);
|
|
24663
|
+
}
|
|
24664
|
+
}
|
|
24665
|
+
discard(turn) {
|
|
24666
|
+
const entry = this.pending.get(turn);
|
|
24667
|
+
if (entry)
|
|
24668
|
+
this.clear(turn, entry, CAPACITY_RETRY_CANCELLED_TEXT);
|
|
24669
|
+
}
|
|
24670
|
+
fire(context, turn) {
|
|
24671
|
+
const entry = this.pending.get(turn);
|
|
24672
|
+
if (!entry || entry.stage !== "waiting")
|
|
24673
|
+
return;
|
|
24674
|
+
entry.timer = undefined;
|
|
24675
|
+
if (!this.owns(context, turn)) {
|
|
24676
|
+
if (context.activeTurn === turn && !turn.isTerminal()) {
|
|
24677
|
+
this.end(context, turn, "failed", entry.error, CAPACITY_RETRY_CANCELLED_TEXT);
|
|
24678
|
+
} else
|
|
24679
|
+
this.clear(turn, entry, CAPACITY_RETRY_CANCELLED_TEXT);
|
|
24680
|
+
return;
|
|
24681
|
+
}
|
|
24682
|
+
entry.stage = "starting";
|
|
24683
|
+
const work = this.startContinuation(context, turn, entry).catch((error) => {
|
|
24684
|
+
console.error(`[codex-bridge] Capacity retry of turn ${turn.turnId} failed:`, error instanceof Error ? error.message : error);
|
|
24685
|
+
if (this.pending.get(turn) === entry && context.activeTurn === turn && !turn.isTerminal()) {
|
|
24686
|
+
this.end(context, turn, "failed", entry.error, CAPACITY_RETRY_START_FAILED_TEXT);
|
|
24687
|
+
}
|
|
24688
|
+
});
|
|
24689
|
+
entry.work = work;
|
|
24690
|
+
this.ctx.pendingFinalizations.add(work);
|
|
24691
|
+
work.finally(() => this.ctx.pendingFinalizations.delete(work));
|
|
24692
|
+
}
|
|
24693
|
+
owns(context, turn) {
|
|
24694
|
+
return !this.ctx.stopping && this.ctx.registry.getThread(context.threadId) === context && context.activeTurn === turn && !turn.isTerminal() && !turn.cancelRequested && context.phase === "running" && context.bridgeSessionIds.size > 0 && turn.engineGeneration === this.ctx.options.engine.info().generation;
|
|
24695
|
+
}
|
|
24696
|
+
async startContinuation(context, turn, entry) {
|
|
24697
|
+
const plan = turn.capacityRetry;
|
|
24698
|
+
const requestId = turn.requestId;
|
|
24699
|
+
const policy = this.policy();
|
|
24700
|
+
const clientId = capacityRetryClientId(requestId, entry.attempt);
|
|
24701
|
+
const engine = this.ctx.options.engine;
|
|
24702
|
+
const previousTurnId = turn.turnId;
|
|
24703
|
+
turn.providerRequestId = clientId;
|
|
24704
|
+
turn.turnId = unconfirmedTurnId(clientId);
|
|
24705
|
+
await this.ctx.journal.markContinuation(requestId, clientId);
|
|
24706
|
+
plan.attempt = entry.attempt;
|
|
24707
|
+
const path = engine.rolloutPath(context.threadId);
|
|
24708
|
+
const offset = path ? await stat8(path).then((stats) => stats.size, () => {
|
|
24709
|
+
return;
|
|
24710
|
+
}) : undefined;
|
|
24711
|
+
this.lifecycle.stateFor(context.threadId).refusedCellOffset = offset;
|
|
24712
|
+
let started;
|
|
24713
|
+
let reconciled;
|
|
24714
|
+
try {
|
|
24715
|
+
started = await engine.startTurn({
|
|
24716
|
+
handle: context.engineHandle,
|
|
24717
|
+
input: [
|
|
24718
|
+
{ type: "text", text: capacityRetryContinuationText(entry.attempt, policy.maxAttempts) }
|
|
24719
|
+
],
|
|
24720
|
+
config: plan.config,
|
|
24721
|
+
requestId: clientId,
|
|
24722
|
+
outputSchema: plan.outputSchema
|
|
24723
|
+
});
|
|
24724
|
+
} catch (error) {
|
|
24725
|
+
const failure = engine.classifyFailure(error);
|
|
24726
|
+
if (!this.ctx.stopping && failure.class !== "rejected" && !failure.retryImmediately) {
|
|
24727
|
+
const outcome = await engine.reconcileRequest(context.threadId, clientId).catch(() => {
|
|
24728
|
+
return;
|
|
24729
|
+
});
|
|
24730
|
+
if (outcome && outcome.result !== "absent" && outcome.turnId) {
|
|
24731
|
+
started = { turnId: outcome.turnId, engineGeneration: engine.info().generation };
|
|
24732
|
+
reconciled = outcome;
|
|
24733
|
+
} else if (!outcome) {
|
|
24734
|
+
this.clear(turn, entry, CAPACITY_RETRY_START_FAILED_TEXT);
|
|
24735
|
+
this.ctx.registry.setPhase(context, "recovering");
|
|
24736
|
+
this.lifecycle.emitStatus(context);
|
|
24737
|
+
this.ctx.callbacks.scheduleRecoveryBackstop(context);
|
|
24738
|
+
return;
|
|
24739
|
+
}
|
|
24740
|
+
}
|
|
24741
|
+
if (!started) {
|
|
24742
|
+
turn.turnId = previousTurnId;
|
|
24743
|
+
this.end(context, turn, entry.stopAfterStart ? "interrupted" : "failed", entry.error, CAPACITY_RETRY_START_FAILED_TEXT);
|
|
24744
|
+
return;
|
|
24745
|
+
}
|
|
24746
|
+
}
|
|
24747
|
+
if (this.pending.get(turn) !== entry || context.activeTurn !== turn || turn.isTerminal()) {
|
|
24748
|
+
await engine.interruptTurn(context.engineHandle, started.turnId).catch(() => {
|
|
24749
|
+
return;
|
|
24750
|
+
});
|
|
24751
|
+
return;
|
|
24752
|
+
}
|
|
24753
|
+
await this.ctx.journal.markAccepted(requestId, { threadId: context.threadId, turnId: started.turnId }).catch((error) => console.warn(`[codex-bridge] Could not journal capacity retry of ${requestId}:`, error instanceof Error ? error.message : error));
|
|
24754
|
+
if (plan.outputSchema) {
|
|
24755
|
+
const ledger = this.ctx.registry.recordStructuredOutputTurn(context.threadId, started.turnId, false);
|
|
24756
|
+
await Promise.all(ledger.map((session) => this.ctx.callbacks.persistSession(session)));
|
|
24757
|
+
}
|
|
24758
|
+
turn.turnId = started.turnId;
|
|
24759
|
+
turn.engineGeneration = started.engineGeneration;
|
|
24760
|
+
context.engineGeneration = started.engineGeneration;
|
|
24761
|
+
if (entry.stopAfterStart)
|
|
24762
|
+
this.clear(turn, entry, CAPACITY_RETRY_CANCELLED_TEXT);
|
|
24763
|
+
else {
|
|
24764
|
+
this.clear(turn, entry, capacityRetryStartedText(entry.attempt, policy.maxAttempts), "success");
|
|
24765
|
+
}
|
|
24766
|
+
if (reconciled?.items) {
|
|
24767
|
+
for (const item of reconciled.items)
|
|
24768
|
+
turn.onItemCompleted(item);
|
|
24769
|
+
}
|
|
24770
|
+
this.publish(context);
|
|
24771
|
+
this.lifecycle.drainPendingEvents(context, started.turnId);
|
|
24772
|
+
if (reconciled?.result === "terminal" && context.activeTurn === turn && !turn.isTerminal() && !this.isPending(turn)) {
|
|
24773
|
+
this.lifecycle.applyEvent(context, {
|
|
24774
|
+
kind: "turn.completed",
|
|
24775
|
+
threadId: context.threadId,
|
|
24776
|
+
turnId: started.turnId,
|
|
24777
|
+
engineGeneration: started.engineGeneration,
|
|
24778
|
+
status: reconciled.status ?? "completed",
|
|
24779
|
+
error: reconciled.error
|
|
24780
|
+
});
|
|
24781
|
+
}
|
|
24782
|
+
if (entry.stopAfterStart && !turn.isTerminal()) {
|
|
24783
|
+
const sessionId = context.bridgeSessionIds.values().next().value;
|
|
24784
|
+
if (sessionId)
|
|
24785
|
+
await this.ctx.callbacks.abort(sessionId);
|
|
24786
|
+
else
|
|
24787
|
+
await engine.interruptTurn(context.engineHandle, started.turnId).catch(() => {
|
|
24788
|
+
return;
|
|
24789
|
+
});
|
|
24790
|
+
}
|
|
24791
|
+
}
|
|
24792
|
+
end(context, turn, status, error, cardText = CAPACITY_RETRY_CANCELLED_TEXT) {
|
|
24793
|
+
const entry = this.pending.get(turn);
|
|
24794
|
+
if (entry)
|
|
24795
|
+
this.clear(turn, entry, cardText);
|
|
24796
|
+
if (status === "failed" && error) {
|
|
24797
|
+
turn.complete("failed", error);
|
|
24798
|
+
turn.recordProviderFailure(error);
|
|
24799
|
+
} else
|
|
24800
|
+
turn.complete(status);
|
|
24801
|
+
const work = this.lifecycle.runFinalization(context, turn);
|
|
24802
|
+
if (entry)
|
|
24803
|
+
entry.work = work;
|
|
24804
|
+
}
|
|
24805
|
+
clear(turn, entry, cardText, state = "failure") {
|
|
24806
|
+
if (entry.timer)
|
|
24807
|
+
clearTimeout(entry.timer);
|
|
24808
|
+
entry.timer = undefined;
|
|
24809
|
+
this.pending.delete(turn);
|
|
24810
|
+
if (turn.retryCardState(entry.itemId) === "pending") {
|
|
24811
|
+
turn.recordRetryCard(entry.itemId, cardText, state);
|
|
24812
|
+
}
|
|
24813
|
+
}
|
|
24814
|
+
publish(context) {
|
|
24815
|
+
this.lifecycle.stateFor(context.threadId).coalescer.flushNow();
|
|
24816
|
+
this.lifecycle.emitStatus(context);
|
|
24817
|
+
}
|
|
24818
|
+
}
|
|
24819
|
+
|
|
24374
24820
|
// ../../bridges/codex-bridge/src/app-server-runtime-lifecycle.ts
|
|
24375
24821
|
function artifactConnectionToken(value) {
|
|
24376
24822
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -24381,8 +24827,10 @@ function artifactConnectionToken(value) {
|
|
|
24381
24827
|
|
|
24382
24828
|
class CodexRuntimeLifecycle {
|
|
24383
24829
|
ctx;
|
|
24830
|
+
capacityRetry;
|
|
24384
24831
|
constructor(ctx) {
|
|
24385
24832
|
this.ctx = ctx;
|
|
24833
|
+
this.capacityRetry = new CodexCapacityRetry(ctx, this);
|
|
24386
24834
|
}
|
|
24387
24835
|
async start() {
|
|
24388
24836
|
if (this.ctx.started)
|
|
@@ -24464,6 +24912,7 @@ class CodexRuntimeLifecycle {
|
|
|
24464
24912
|
clearTimeout(timer);
|
|
24465
24913
|
this.ctx.recoveryBackstops.clear();
|
|
24466
24914
|
this.ctx.commandCatalogue.dispose();
|
|
24915
|
+
this.capacityRetry.dispose();
|
|
24467
24916
|
this.ctx.callbacks.notifyThreadActivity();
|
|
24468
24917
|
await this.ctx.options.engine.stop();
|
|
24469
24918
|
await this.drainPendingWork();
|
|
@@ -25144,12 +25593,23 @@ class CodexRuntimeLifecycle {
|
|
|
25144
25593
|
this.setThreadAuthNotice(context, refusedLoginNotice(context.authNotice, this.ctx.options.engine.getAccountLoginKind(), () => crypto.randomUUID()));
|
|
25145
25594
|
}
|
|
25146
25595
|
this.discardOutlivingCommandWindows(turn);
|
|
25596
|
+
let failure = event.error;
|
|
25597
|
+
if (event.status === "failed") {
|
|
25598
|
+
const decision = this.capacityRetry.onTurnFailed(context, turn, event.error);
|
|
25599
|
+
if (decision.retrying) {
|
|
25600
|
+
this.ctx.options.changeEvidence?.turn(this.evidenceSource(context, turn), "failed");
|
|
25601
|
+
this.takeRefusedCellTail(threadId, turn)?.close();
|
|
25602
|
+
return;
|
|
25603
|
+
}
|
|
25604
|
+
if (decision.error)
|
|
25605
|
+
failure = decision.error;
|
|
25606
|
+
}
|
|
25147
25607
|
if (turn.stoppedByShutdown && event.status === "interrupted")
|
|
25148
25608
|
this.completeRecoveredTurn(turn, event.status);
|
|
25149
25609
|
else {
|
|
25150
|
-
turn.complete(event.status,
|
|
25151
|
-
if (event.status === "failed" &&
|
|
25152
|
-
turn.recordProviderFailure(
|
|
25610
|
+
turn.complete(event.status, failure);
|
|
25611
|
+
if (event.status === "failed" && failure)
|
|
25612
|
+
turn.recordProviderFailure(failure);
|
|
25153
25613
|
}
|
|
25154
25614
|
this.ctx.options.changeEvidence?.turn(this.evidenceSource(context, turn), event.status);
|
|
25155
25615
|
const finalize = () => this.runFinalization(context, turn).catch((error) => {
|
|
@@ -25627,8 +26087,14 @@ class CodexRuntimeLifecycle {
|
|
|
25627
26087
|
this.emitStatus(context);
|
|
25628
26088
|
continue;
|
|
25629
26089
|
}
|
|
25630
|
-
const outcome = await this.ctx.options.engine.reconcileRequest(context.threadId, turn.requestId);
|
|
26090
|
+
const outcome = await this.ctx.options.engine.reconcileRequest(context.threadId, turn.providerRequestId ?? turn.requestId);
|
|
25631
26091
|
if (outcome.result === "terminal") {
|
|
26092
|
+
if (outcome.turnId)
|
|
26093
|
+
turn.turnId = outcome.turnId;
|
|
26094
|
+
for (const item of outcome.items ?? [])
|
|
26095
|
+
turn.onItemCompleted(item);
|
|
26096
|
+
if (outcome.error)
|
|
26097
|
+
turn.onError(outcome.error);
|
|
25632
26098
|
this.completeRecoveredTurn(turn, outcome.status ?? "completed");
|
|
25633
26099
|
await this.runFinalization(context, turn);
|
|
25634
26100
|
continue;
|
|
@@ -25678,6 +26144,7 @@ class CodexRuntimeLifecycle {
|
|
|
25678
26144
|
turn.complete(status);
|
|
25679
26145
|
}
|
|
25680
26146
|
async finalizeTurn(context, turn) {
|
|
26147
|
+
this.capacityRetry.discard(turn);
|
|
25681
26148
|
const state = this.stateFor(context.threadId);
|
|
25682
26149
|
const structuredResult = turn.expectsStructuredOutput ? parseCodexStructuredOutput(turn) : undefined;
|
|
25683
26150
|
const structuredSessions = structuredResult ? [...context.bridgeSessionIds].map((sessionId) => this.ctx.registry.getSession(sessionId)).filter((session) => session?.structuredOutputRequestId === turn.requestId) : [];
|
|
@@ -25940,7 +26407,7 @@ function requiredCoordinatorPermissionProfile() {
|
|
|
25940
26407
|
}
|
|
25941
26408
|
|
|
25942
26409
|
// ../../bridges/codex-bridge/src/app-server-runtime-prompt.ts
|
|
25943
|
-
import { stat as
|
|
26410
|
+
import { stat as stat9 } from "node:fs/promises";
|
|
25944
26411
|
function commandRefusal(message) {
|
|
25945
26412
|
return { ok: false, status: 422, error: message, kind: "command-unavailable" };
|
|
25946
26413
|
}
|
|
@@ -26043,7 +26510,7 @@ class CodexRuntimePrompt {
|
|
|
26043
26510
|
};
|
|
26044
26511
|
}
|
|
26045
26512
|
if (decision.action === "reconcile" && decision.record?.threadId) {
|
|
26046
|
-
const outcome = await this.ctx.options.engine.reconcileRequest(decision.record.threadId, requestId);
|
|
26513
|
+
const outcome = await this.ctx.options.engine.reconcileRequest(decision.record.threadId, decision.record.providerRequestId ?? requestId);
|
|
26047
26514
|
if (outcome.result === "terminal") {
|
|
26048
26515
|
await this.ctx.journal.markTerminal(requestId, outcome.status ?? "completed", {
|
|
26049
26516
|
threadId: decision.record.threadId,
|
|
@@ -26307,7 +26774,7 @@ class CodexRuntimePrompt {
|
|
|
26307
26774
|
let refusedCellOffset;
|
|
26308
26775
|
const startTurn = async () => {
|
|
26309
26776
|
const path = this.ctx.options.engine.rolloutPath(context.threadId);
|
|
26310
|
-
refusedCellOffset = path ? await
|
|
26777
|
+
refusedCellOffset = path ? await stat9(path).then((stats) => stats.size, (error) => error.code === "ENOENT" ? 0 : undefined) : undefined;
|
|
26311
26778
|
return this.ctx.options.engine.startTurn({
|
|
26312
26779
|
handle: context.engineHandle,
|
|
26313
26780
|
input: engineInput,
|
|
@@ -26464,6 +26931,11 @@ class CodexRuntimePrompt {
|
|
|
26464
26931
|
startedAt: context.turnStartedAt
|
|
26465
26932
|
});
|
|
26466
26933
|
accumulator.markRunning();
|
|
26934
|
+
accumulator.capacityRetry = {
|
|
26935
|
+
config: turnConfig,
|
|
26936
|
+
...input.outputSchema ? { outputSchema: input.outputSchema } : {},
|
|
26937
|
+
attempt: 1
|
|
26938
|
+
};
|
|
26467
26939
|
context.activeTurn = accumulator;
|
|
26468
26940
|
context.engineGeneration = turn.engineGeneration;
|
|
26469
26941
|
context.dispatchInFlight = false;
|
|
@@ -26590,10 +27062,11 @@ class CodexRuntimePrompt {
|
|
|
26590
27062
|
...recoveredModelId ? { modelId: recoveredModelId } : {}
|
|
26591
27063
|
});
|
|
26592
27064
|
}
|
|
27065
|
+
accumulator.providerRequestId = this.ctx.journal.get(requestId)?.providerRequestId ?? requestId;
|
|
26593
27066
|
this.scheduleRecoveryBackstop(context);
|
|
26594
27067
|
let outcome;
|
|
26595
27068
|
try {
|
|
26596
|
-
outcome = await this.ctx.options.engine.reconcileRequest(context.threadId,
|
|
27069
|
+
outcome = await this.ctx.options.engine.reconcileRequest(context.threadId, accumulator.providerRequestId);
|
|
26597
27070
|
} catch (error) {
|
|
26598
27071
|
console.warn(`[codex-bridge] Could not reconcile ${requestId} on thread ${context.threadId}:`, error instanceof Error ? error.message : error);
|
|
26599
27072
|
return "recovering";
|
|
@@ -26915,6 +27388,8 @@ class CodexRuntimeTail {
|
|
|
26915
27388
|
const turn = context.activeTurn;
|
|
26916
27389
|
if (!turn || turn.isTerminal() || turn.isUnconfirmed())
|
|
26917
27390
|
continue;
|
|
27391
|
+
if (this.lifecycle.capacityRetry.endForParentExit(context, turn))
|
|
27392
|
+
continue;
|
|
26918
27393
|
turn.stoppedByShutdown = true;
|
|
26919
27394
|
const { engineHandle } = context;
|
|
26920
27395
|
stopping.push(this.ctx.options.engine.interruptTurn(engineHandle, turn.turnId).then(() => this.ctx.options.engine.waitForTurnTerminal(engineHandle, turn.turnId, {
|
|
@@ -26950,6 +27425,9 @@ class CodexRuntimeTail {
|
|
|
26950
27425
|
phase: context?.phase ?? "idle"
|
|
26951
27426
|
};
|
|
26952
27427
|
}
|
|
27428
|
+
if (this.lifecycle.capacityRetry.stop(context, turn)) {
|
|
27429
|
+
return { status: "cancelling", phase: "cancelling" };
|
|
27430
|
+
}
|
|
26953
27431
|
this.ctx.threadState.get(context.threadId)?.refusedCellTail?.tail.close();
|
|
26954
27432
|
turn.markCancelling();
|
|
26955
27433
|
this.ctx.registry.setPhase(context, "cancelling");
|
|
@@ -27051,9 +27529,10 @@ class CodexRuntimeTail {
|
|
|
27051
27529
|
const windows = accountUsageFromLimits(limits);
|
|
27052
27530
|
return windows.length > 0 ? windows : undefined;
|
|
27053
27531
|
}
|
|
27054
|
-
async listSessions() {
|
|
27532
|
+
async listSessions(options = {}) {
|
|
27055
27533
|
const cwd = getWorkingDirectory(this.ctx.options.cwd);
|
|
27056
27534
|
const merged = new Map;
|
|
27535
|
+
const archivedRows = new Map;
|
|
27057
27536
|
try {
|
|
27058
27537
|
const { threads } = await this.ctx.options.engine.listThreads({ cwd });
|
|
27059
27538
|
for (const thread of threads) {
|
|
@@ -27078,9 +27557,16 @@ class CodexRuntimeTail {
|
|
|
27078
27557
|
onlyArchived: true,
|
|
27079
27558
|
...cursor ? { cursor } : {}
|
|
27080
27559
|
});
|
|
27081
|
-
for (const thread of page.threads)
|
|
27082
|
-
if (thread.id)
|
|
27083
|
-
|
|
27560
|
+
for (const thread of page.threads) {
|
|
27561
|
+
if (!thread.id)
|
|
27562
|
+
continue;
|
|
27563
|
+
archived.add(thread.id);
|
|
27564
|
+
archivedRows.set(thread.id, {
|
|
27565
|
+
id: thread.id,
|
|
27566
|
+
title: thread.name ?? thread.preview ?? undefined,
|
|
27567
|
+
updatedAt: thread.updatedAt ?? new Date(this.ctx.now()).toISOString()
|
|
27568
|
+
});
|
|
27569
|
+
}
|
|
27084
27570
|
cursor = page.nextCursor ?? undefined;
|
|
27085
27571
|
} while (cursor);
|
|
27086
27572
|
} catch {}
|
|
@@ -27105,6 +27591,9 @@ class CodexRuntimeTail {
|
|
|
27105
27591
|
for (const meta of persisted) {
|
|
27106
27592
|
if (isArchived(meta)) {
|
|
27107
27593
|
merged.delete(meta.id);
|
|
27594
|
+
if (!archivedRows.has(meta.id)) {
|
|
27595
|
+
archivedRows.set(meta.id, { id: meta.id, title: meta.title, updatedAt: meta.updatedAt });
|
|
27596
|
+
}
|
|
27108
27597
|
continue;
|
|
27109
27598
|
}
|
|
27110
27599
|
const existing = merged.get(meta.id);
|
|
@@ -27117,14 +27606,18 @@ class CodexRuntimeTail {
|
|
|
27117
27606
|
}
|
|
27118
27607
|
try {
|
|
27119
27608
|
const generated = generatedTitles ?? await readPersistedSessionTitleEntries(this.ctx.options.codexHome);
|
|
27120
|
-
for (const session of merged.values()) {
|
|
27609
|
+
for (const session of [...merged.values(), ...archivedRows.values()]) {
|
|
27121
27610
|
const entry = generated.get(session.id);
|
|
27122
27611
|
if (entry)
|
|
27123
27612
|
session.title = entry.title;
|
|
27124
27613
|
}
|
|
27125
27614
|
} catch {}
|
|
27615
|
+
const byActivity = (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
|
|
27126
27616
|
return {
|
|
27127
|
-
sessions: [
|
|
27617
|
+
sessions: [
|
|
27618
|
+
...boundedResumeRows([...merged.values()].sort(byActivity)),
|
|
27619
|
+
...options.includeArchived ? boundedResumeRows([...archivedRows.values()].filter((row) => !merged.has(row.id)).sort(byActivity).map((row) => ({ ...row, archived: true }))) : []
|
|
27620
|
+
],
|
|
27128
27621
|
cwd
|
|
27129
27622
|
};
|
|
27130
27623
|
}
|
|
@@ -27160,6 +27653,21 @@ class CodexRuntimeTail {
|
|
|
27160
27653
|
};
|
|
27161
27654
|
}
|
|
27162
27655
|
}
|
|
27656
|
+
function boundedResumeRows(rows) {
|
|
27657
|
+
const result = [];
|
|
27658
|
+
let remaining = 900 * 1024;
|
|
27659
|
+
for (const row of rows) {
|
|
27660
|
+
if (result.length >= 512)
|
|
27661
|
+
break;
|
|
27662
|
+
const bounded = { ...row, title: row.title?.slice(0, 512) };
|
|
27663
|
+
const bytes = Buffer.byteLength(JSON.stringify(bounded), "utf8") + 1;
|
|
27664
|
+
if (bytes > remaining)
|
|
27665
|
+
continue;
|
|
27666
|
+
remaining -= bytes;
|
|
27667
|
+
result.push(bounded);
|
|
27668
|
+
}
|
|
27669
|
+
return result;
|
|
27670
|
+
}
|
|
27163
27671
|
|
|
27164
27672
|
// ../../bridges/codex-bridge/src/app-server-runtime.ts
|
|
27165
27673
|
class AppServerRuntime {
|
|
@@ -28536,7 +29044,9 @@ app.post("/session/:id/commands/refresh", async (c) => {
|
|
|
28536
29044
|
return c.json(await appServerRuntime.refreshCommandCatalogue(c.req.param("id")));
|
|
28537
29045
|
});
|
|
28538
29046
|
app.get("/session/list", async (c) => {
|
|
28539
|
-
return c.json(await appServerRuntime.listSessions(
|
|
29047
|
+
return c.json(await appServerRuntime.listSessions({
|
|
29048
|
+
includeArchived: c.req.query("includeArchived") === "1"
|
|
29049
|
+
}));
|
|
28540
29050
|
});
|
|
28541
29051
|
for (const action of ["archive", "unarchive"]) {
|
|
28542
29052
|
app.post(`/session/list/:threadId/${action}`, async (c) => {
|