@mrrlin-dev/mcp 0.3.60 → 0.3.62
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/bin.cjs +984 -153
- package/package.json +3 -3
package/dist/bin.cjs
CHANGED
|
@@ -6543,7 +6543,7 @@ var require_truncate = __commonJS({
|
|
|
6543
6543
|
var parse5 = require_parse2();
|
|
6544
6544
|
var constants = require_constants2();
|
|
6545
6545
|
var SemVer = require_semver();
|
|
6546
|
-
var
|
|
6546
|
+
var truncate3 = (version2, truncation, options) => {
|
|
6547
6547
|
if (!constants.RELEASE_TYPES.includes(truncation)) {
|
|
6548
6548
|
return null;
|
|
6549
6549
|
}
|
|
@@ -6573,7 +6573,7 @@ var require_truncate = __commonJS({
|
|
|
6573
6573
|
var isPrerelease = (type) => {
|
|
6574
6574
|
return type.startsWith("pre");
|
|
6575
6575
|
};
|
|
6576
|
-
module2.exports =
|
|
6576
|
+
module2.exports = truncate3;
|
|
6577
6577
|
}
|
|
6578
6578
|
});
|
|
6579
6579
|
|
|
@@ -7611,7 +7611,7 @@ var require_semver2 = __commonJS({
|
|
|
7611
7611
|
var lte = require_lte();
|
|
7612
7612
|
var cmp = require_cmp();
|
|
7613
7613
|
var coerce = require_coerce();
|
|
7614
|
-
var
|
|
7614
|
+
var truncate3 = require_truncate();
|
|
7615
7615
|
var Comparator = require_comparator();
|
|
7616
7616
|
var Range = require_range();
|
|
7617
7617
|
var satisfies = require_satisfies();
|
|
@@ -7650,7 +7650,7 @@ var require_semver2 = __commonJS({
|
|
|
7650
7650
|
lte,
|
|
7651
7651
|
cmp,
|
|
7652
7652
|
coerce,
|
|
7653
|
-
truncate:
|
|
7653
|
+
truncate: truncate3,
|
|
7654
7654
|
Comparator,
|
|
7655
7655
|
Range,
|
|
7656
7656
|
satisfies,
|
|
@@ -36432,6 +36432,13 @@ var openApiOperationIds = {
|
|
|
36432
36432
|
restartExecutionRun: "restartExecutionRun",
|
|
36433
36433
|
resolveHandoff: "resolveHandoff",
|
|
36434
36434
|
touchExecutionRun: "touchExecutionRun",
|
|
36435
|
+
getTaskState: "getTaskState",
|
|
36436
|
+
upsertTaskState: "upsertTaskState",
|
|
36437
|
+
retireThread: "retireThread",
|
|
36438
|
+
// Run-scoped, model-facing half of the resume contract (D8). Distinct from upsertTaskState:
|
|
36439
|
+
// that one is the server's own write (whole record, explicit lastRunSeq), this one is the
|
|
36440
|
+
// executor reporting narrative only, with the ordering value derived server-side from the run.
|
|
36441
|
+
reportTaskState: "reportTaskState",
|
|
36435
36442
|
issueAgentCredential: "issueAgentCredential",
|
|
36436
36443
|
listAgentCredentials: "listAgentCredentials",
|
|
36437
36444
|
revokeAgentCredential: "revokeAgentCredential",
|
|
@@ -37463,7 +37470,55 @@ var mrrlinExecutionRunSchema = external_exports.object({
|
|
|
37463
37470
|
status: mrrlinExecutionRunStatusSchema,
|
|
37464
37471
|
taskId: mrrlinTaskIdSchema,
|
|
37465
37472
|
updatedAt: external_exports.string().datetime(),
|
|
37466
|
-
worktreeId: external_exports.string().min(1).nullable()
|
|
37473
|
+
worktreeId: external_exports.string().min(1).nullable(),
|
|
37474
|
+
stateSeq: external_exports.number().int(),
|
|
37475
|
+
promptBytes: external_exports.number().int().nullable(),
|
|
37476
|
+
turnCount: external_exports.number().int().nullable(),
|
|
37477
|
+
inputTokens: external_exports.number().int().nullable(),
|
|
37478
|
+
cachedInputTokens: external_exports.number().int().nullable(),
|
|
37479
|
+
outputTokens: external_exports.number().int().nullable(),
|
|
37480
|
+
effort: external_exports.enum(["none", "minimal", "low", "medium", "high", "xhigh"]).nullable(),
|
|
37481
|
+
effortEscalationReason: external_exports.string().min(1).nullable()
|
|
37482
|
+
});
|
|
37483
|
+
var mrrlinTaskStateSchema = external_exports.object({
|
|
37484
|
+
projectSlug: mrrlinProjectSlugSchema,
|
|
37485
|
+
taskId: mrrlinTaskIdSchema,
|
|
37486
|
+
goal: external_exports.string().min(1).nullable(),
|
|
37487
|
+
acceptedRequirements: external_exports.string().min(1).nullable(),
|
|
37488
|
+
decisions: external_exports.string().min(1).nullable(),
|
|
37489
|
+
relevantFiles: external_exports.string().min(1).nullable(),
|
|
37490
|
+
filesChanged: external_exports.string().min(1).nullable(),
|
|
37491
|
+
latestVerification: external_exports.string().min(1).nullable(),
|
|
37492
|
+
openProblems: external_exports.string().min(1).nullable(),
|
|
37493
|
+
nextActions: external_exports.string().min(1).nullable(),
|
|
37494
|
+
lastRunSeq: external_exports.number().int(),
|
|
37495
|
+
threadRunCount: external_exports.number().int(),
|
|
37496
|
+
retiredThreadId: external_exports.string().min(1).nullable(),
|
|
37497
|
+
updatedAt: external_exports.string().datetime()
|
|
37498
|
+
});
|
|
37499
|
+
var mrrlinTaskStateUpsertSchema = external_exports.object({
|
|
37500
|
+
goal: external_exports.string().min(1).nullable(),
|
|
37501
|
+
acceptedRequirements: external_exports.string().min(1).nullable(),
|
|
37502
|
+
decisions: external_exports.string().min(1).nullable(),
|
|
37503
|
+
relevantFiles: external_exports.string().min(1).nullable(),
|
|
37504
|
+
filesChanged: external_exports.string().min(1).nullable(),
|
|
37505
|
+
latestVerification: external_exports.string().min(1).nullable(),
|
|
37506
|
+
openProblems: external_exports.string().min(1).nullable(),
|
|
37507
|
+
nextActions: external_exports.string().min(1).nullable(),
|
|
37508
|
+
lastRunSeq: external_exports.number().int()
|
|
37509
|
+
});
|
|
37510
|
+
var mrrlinTaskStateReportSchema = external_exports.object({
|
|
37511
|
+
goal: external_exports.string().min(1).nullish(),
|
|
37512
|
+
acceptedRequirements: external_exports.string().min(1).nullish(),
|
|
37513
|
+
decisions: external_exports.string().min(1).nullish(),
|
|
37514
|
+
openProblems: external_exports.string().min(1).nullish(),
|
|
37515
|
+
nextActions: external_exports.string().min(1).nullish()
|
|
37516
|
+
});
|
|
37517
|
+
var taskStateResponseSchema = external_exports.object({
|
|
37518
|
+
data: mrrlinTaskStateSchema.nullable()
|
|
37519
|
+
});
|
|
37520
|
+
var retireThreadResponseSchema = external_exports.object({
|
|
37521
|
+
data: external_exports.object({ retiredThreadId: external_exports.string().min(1).nullable() })
|
|
37467
37522
|
});
|
|
37468
37523
|
var mrrlinExecutionRunCreateSchema = external_exports.object({
|
|
37469
37524
|
actor: external_exports.string().min(1),
|
|
@@ -37495,7 +37550,18 @@ var mrrlinExecutionRunUpdateSchema = external_exports.object({
|
|
|
37495
37550
|
prodWorkflowId: external_exports.number().int().positive().nullable().optional(),
|
|
37496
37551
|
pullRequestUrl: external_exports.string().min(1).nullable().optional(),
|
|
37497
37552
|
status: mrrlinExecutionRunStatusSchema.optional(),
|
|
37498
|
-
worktreeId: external_exports.string().min(1).nullable().optional()
|
|
37553
|
+
worktreeId: external_exports.string().min(1).nullable().optional(),
|
|
37554
|
+
// Slice 6 (cost telemetry) + Slice 7 (effort). All nullable and optional: per D6, NULL means
|
|
37555
|
+
// "not measured" and must never be confused with a measured zero, so a disabled slice omits its
|
|
37556
|
+
// fields entirely rather than writing 0. `nonnegative` rather than `positive` because a real
|
|
37557
|
+
// measured zero is legitimate here (a turn can genuinely produce 0 output tokens).
|
|
37558
|
+
promptBytes: external_exports.number().int().nonnegative().nullable().optional(),
|
|
37559
|
+
turnCount: external_exports.number().int().nonnegative().nullable().optional(),
|
|
37560
|
+
inputTokens: external_exports.number().int().nonnegative().nullable().optional(),
|
|
37561
|
+
cachedInputTokens: external_exports.number().int().nonnegative().nullable().optional(),
|
|
37562
|
+
outputTokens: external_exports.number().int().nonnegative().nullable().optional(),
|
|
37563
|
+
effort: external_exports.enum(["none", "minimal", "low", "medium", "high", "xhigh"]).nullable().optional(),
|
|
37564
|
+
effortEscalationReason: external_exports.string().min(1).nullable().optional()
|
|
37499
37565
|
}).refine((value) => Object.keys(value).length > 0, {
|
|
37500
37566
|
message: "ExecutionRunUpdate requires at least one field"
|
|
37501
37567
|
});
|
|
@@ -38274,6 +38340,117 @@ function applyHistoricalBudgetIfNeeded(input) {
|
|
|
38274
38340
|
droppedHandles
|
|
38275
38341
|
};
|
|
38276
38342
|
}
|
|
38343
|
+
function renderTaskStateSection(state) {
|
|
38344
|
+
const rows = [
|
|
38345
|
+
["goal", state.goal],
|
|
38346
|
+
["accepted requirements", state.acceptedRequirements],
|
|
38347
|
+
["decisions (and why)", state.decisions],
|
|
38348
|
+
["relevant files", state.relevantFiles],
|
|
38349
|
+
["files changed", state.filesChanged],
|
|
38350
|
+
["latest verification", state.latestVerification],
|
|
38351
|
+
["open problems", state.openProblems],
|
|
38352
|
+
["next actions", state.nextActions]
|
|
38353
|
+
];
|
|
38354
|
+
const present = rows.filter(([, value]) => typeof value === "string" && value.trim().length > 0);
|
|
38355
|
+
if (present.length === 0) {
|
|
38356
|
+
return "## Task state (normative)\n(no state recorded yet \u2014 establish it before ending your turn)";
|
|
38357
|
+
}
|
|
38358
|
+
const lines2 = ["## Task state (normative)"];
|
|
38359
|
+
for (const [label, value] of present) {
|
|
38360
|
+
lines2.push(`${label}: ${value}`);
|
|
38361
|
+
}
|
|
38362
|
+
return lines2.join("\n");
|
|
38363
|
+
}
|
|
38364
|
+
function renderRunDelta(input) {
|
|
38365
|
+
const sections = [
|
|
38366
|
+
renderDeltaTaskStatus(input.task),
|
|
38367
|
+
renderDeltaRuns(input.newlyFinishedRuns),
|
|
38368
|
+
renderDeltaArtifacts(input.newArtifacts, input.omittedArtifactCount ?? 0)
|
|
38369
|
+
];
|
|
38370
|
+
return sections.join("\n\n");
|
|
38371
|
+
}
|
|
38372
|
+
function renderDeltaArtifacts(artifacts, omittedCount) {
|
|
38373
|
+
if (artifacts.length === 0 && omittedCount === 0)
|
|
38374
|
+
return "## New artifacts since your last turn\n(none)";
|
|
38375
|
+
const lines2 = ["## New artifacts since your last turn"];
|
|
38376
|
+
if (omittedCount > 0) {
|
|
38377
|
+
lines2.push(`(+${omittedCount} older artifact${omittedCount === 1 ? "" : "s"} omitted)`);
|
|
38378
|
+
}
|
|
38379
|
+
for (const artifact of artifacts) {
|
|
38380
|
+
if (artifact.kind === "file") {
|
|
38381
|
+
const p = artifact.payload;
|
|
38382
|
+
if (p.filename && p.stableUrl) {
|
|
38383
|
+
lines2.push(`- ${artifact.createdAt} [file] ${p.filename} (${p.class ?? "?"}, ${p.sizeBytes ?? "?"} bytes) ${p.stableUrl}`);
|
|
38384
|
+
continue;
|
|
38385
|
+
}
|
|
38386
|
+
}
|
|
38387
|
+
lines2.push(`- ${artifact.createdAt} [${artifact.kind}] run=${artifact.runId} ${JSON.stringify(artifact.payload)}`);
|
|
38388
|
+
}
|
|
38389
|
+
return lines2.join("\n");
|
|
38390
|
+
}
|
|
38391
|
+
function renderDeltaTaskStatus(task) {
|
|
38392
|
+
const lines2 = ["## Since your last turn", `task ${task.id} status: ${task.status}`];
|
|
38393
|
+
if (task.latestJudgement) {
|
|
38394
|
+
lines2.push(`latest judgement (${task.latestJudgementKind ?? "unknown"}): ${task.latestJudgement}`);
|
|
38395
|
+
}
|
|
38396
|
+
return lines2.join("\n");
|
|
38397
|
+
}
|
|
38398
|
+
function renderDeltaRuns(runs) {
|
|
38399
|
+
if (runs.length === 0)
|
|
38400
|
+
return "## Runs completed since your last turn\n(none)";
|
|
38401
|
+
const lines2 = ["## Runs completed since your last turn"];
|
|
38402
|
+
for (const run3 of runs) {
|
|
38403
|
+
lines2.push(`- ${run3.id} [${run3.status}] finished ${run3.finishedAt ?? run3.createdAt}`);
|
|
38404
|
+
}
|
|
38405
|
+
return lines2.join("\n");
|
|
38406
|
+
}
|
|
38407
|
+
|
|
38408
|
+
// ../../packages/codex-client/dist/token-usage.js
|
|
38409
|
+
var TOKEN_USAGE_NOTIFICATION_METHOD = "thread/tokenUsage/updated";
|
|
38410
|
+
function readCount(source, key) {
|
|
38411
|
+
const value = source[key];
|
|
38412
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
38413
|
+
}
|
|
38414
|
+
function extractTurnTokenUsage(method, params) {
|
|
38415
|
+
if (method !== TOKEN_USAGE_NOTIFICATION_METHOD)
|
|
38416
|
+
return null;
|
|
38417
|
+
if (params === null || typeof params !== "object")
|
|
38418
|
+
return null;
|
|
38419
|
+
const usage = params.tokenUsage;
|
|
38420
|
+
if (usage === null || typeof usage !== "object")
|
|
38421
|
+
return null;
|
|
38422
|
+
const last = usage.last;
|
|
38423
|
+
if (last === null || typeof last !== "object")
|
|
38424
|
+
return null;
|
|
38425
|
+
const block = last;
|
|
38426
|
+
const extracted = {
|
|
38427
|
+
inputTokens: readCount(block, "inputTokens"),
|
|
38428
|
+
cachedInputTokens: readCount(block, "cachedInputTokens"),
|
|
38429
|
+
outputTokens: readCount(block, "outputTokens")
|
|
38430
|
+
};
|
|
38431
|
+
if (extracted.inputTokens === null && extracted.cachedInputTokens === null && extracted.outputTokens === null) {
|
|
38432
|
+
return null;
|
|
38433
|
+
}
|
|
38434
|
+
return extracted;
|
|
38435
|
+
}
|
|
38436
|
+
function addTurnTokenUsage(total, turn) {
|
|
38437
|
+
if (turn === null)
|
|
38438
|
+
return total;
|
|
38439
|
+
if (total === null)
|
|
38440
|
+
return { ...turn };
|
|
38441
|
+
const add2 = (a, b) => {
|
|
38442
|
+
if (a === null)
|
|
38443
|
+
return b;
|
|
38444
|
+
if (b === null)
|
|
38445
|
+
return a;
|
|
38446
|
+
return a + b;
|
|
38447
|
+
};
|
|
38448
|
+
return {
|
|
38449
|
+
inputTokens: add2(total.inputTokens, turn.inputTokens),
|
|
38450
|
+
cachedInputTokens: add2(total.cachedInputTokens, turn.cachedInputTokens),
|
|
38451
|
+
outputTokens: add2(total.outputTokens, turn.outputTokens)
|
|
38452
|
+
};
|
|
38453
|
+
}
|
|
38277
38454
|
|
|
38278
38455
|
// ../../packages/client/dist/agent-token-provider.js
|
|
38279
38456
|
var AgentTokenProviderError = class extends Error {
|
|
@@ -38998,6 +39175,34 @@ function createMrrlinClient(config2) {
|
|
|
38998
39175
|
throw error51;
|
|
38999
39176
|
}
|
|
39000
39177
|
},
|
|
39178
|
+
async getTaskState(projectSlug, taskId) {
|
|
39179
|
+
const body = await request(`${projectPath(projectSlug)}/tasks/${encodeURIComponent(taskId)}/state`);
|
|
39180
|
+
return taskStateResponseSchema.parse(body).data;
|
|
39181
|
+
},
|
|
39182
|
+
async upsertTaskState(projectSlug, taskId, input) {
|
|
39183
|
+
const body = await request(`${projectPath(projectSlug)}/tasks/${encodeURIComponent(taskId)}/state`, {
|
|
39184
|
+
body: JSON.stringify(mrrlinTaskStateUpsertSchema.parse(input)),
|
|
39185
|
+
headers: { "content-type": "application/json" },
|
|
39186
|
+
method: "PUT"
|
|
39187
|
+
});
|
|
39188
|
+
return taskStateResponseSchema.parse(body).data;
|
|
39189
|
+
},
|
|
39190
|
+
async retireThread(projectSlug, taskId, newThreadId) {
|
|
39191
|
+
const body = await request(`${projectPath(projectSlug)}/tasks/${encodeURIComponent(taskId)}/retire-thread`, {
|
|
39192
|
+
body: JSON.stringify({ newThreadId }),
|
|
39193
|
+
headers: { "content-type": "application/json" },
|
|
39194
|
+
method: "POST"
|
|
39195
|
+
});
|
|
39196
|
+
return retireThreadResponseSchema.parse(body).data.retiredThreadId;
|
|
39197
|
+
},
|
|
39198
|
+
async reportTaskState(projectSlug, runId, report) {
|
|
39199
|
+
const body = await request(`${projectPath(projectSlug)}/execution-runs/${encodeURIComponent(runId)}/task-state`, {
|
|
39200
|
+
body: JSON.stringify(mrrlinTaskStateReportSchema.parse(report)),
|
|
39201
|
+
headers: { "content-type": "application/json" },
|
|
39202
|
+
method: "POST"
|
|
39203
|
+
});
|
|
39204
|
+
return taskStateResponseSchema.parse(body).data;
|
|
39205
|
+
},
|
|
39001
39206
|
async resolveHandoff(projectSlug, runId, input) {
|
|
39002
39207
|
const body = await request(`${projectPath(projectSlug)}/execution-runs/${encodeURIComponent(runId)}/resolve-handoff`, {
|
|
39003
39208
|
body: JSON.stringify(input),
|
|
@@ -39201,6 +39406,36 @@ function createMrrlinClient(config2) {
|
|
|
39201
39406
|
};
|
|
39202
39407
|
}
|
|
39203
39408
|
|
|
39409
|
+
// src/describe-error.ts
|
|
39410
|
+
var MAX_DETAIL_CHARS = 200;
|
|
39411
|
+
function truncate(value) {
|
|
39412
|
+
return value.length > MAX_DETAIL_CHARS ? value.slice(0, MAX_DETAIL_CHARS) : value;
|
|
39413
|
+
}
|
|
39414
|
+
function codeAndMessage(value) {
|
|
39415
|
+
if (!value || typeof value !== "object") return null;
|
|
39416
|
+
const obj = value;
|
|
39417
|
+
const code = typeof obj.code === "string" ? obj.code : null;
|
|
39418
|
+
const message = typeof obj.message === "string" ? obj.message : null;
|
|
39419
|
+
if (code) return message ? `${code}: ${message}` : code;
|
|
39420
|
+
return message;
|
|
39421
|
+
}
|
|
39422
|
+
function detailFromCause(cause) {
|
|
39423
|
+
if (!cause || typeof cause !== "object") return null;
|
|
39424
|
+
const direct = codeAndMessage(cause);
|
|
39425
|
+
const errors = cause.errors;
|
|
39426
|
+
const hasCode = typeof cause.code === "string";
|
|
39427
|
+
if (!hasCode && Array.isArray(errors) && errors.length > 0) {
|
|
39428
|
+
const fromFirst = codeAndMessage(errors[0]);
|
|
39429
|
+
if (fromFirst) return fromFirst;
|
|
39430
|
+
}
|
|
39431
|
+
return direct;
|
|
39432
|
+
}
|
|
39433
|
+
function describeError(error51) {
|
|
39434
|
+
if (!(error51 instanceof Error)) return String(error51);
|
|
39435
|
+
const detail = detailFromCause(error51.cause);
|
|
39436
|
+
return detail ? `${error51.message} (${truncate(detail)})` : error51.message;
|
|
39437
|
+
}
|
|
39438
|
+
|
|
39204
39439
|
// src/token-refresher.ts
|
|
39205
39440
|
function createTokenRefresher(opts) {
|
|
39206
39441
|
const setIntervalFn = opts.setIntervalFn ?? setInterval;
|
|
@@ -39217,7 +39452,7 @@ function createTokenRefresher(opts) {
|
|
|
39217
39452
|
opts.onOk?.();
|
|
39218
39453
|
} catch (error51) {
|
|
39219
39454
|
process.stderr.write(
|
|
39220
|
-
`[mrrlin-mcp director-bridge] token refresh failed (will retry next tick): ${
|
|
39455
|
+
`[mrrlin-mcp director-bridge] token refresh failed (will retry next tick): ${describeError(error51)}
|
|
39221
39456
|
`
|
|
39222
39457
|
);
|
|
39223
39458
|
opts.onError?.(error51);
|
|
@@ -39256,29 +39491,117 @@ function createServiceHealth() {
|
|
|
39256
39491
|
}
|
|
39257
39492
|
|
|
39258
39493
|
// src/turn-lock.ts
|
|
39494
|
+
var CHAT_LIMIT = 5;
|
|
39495
|
+
var AUTONOMOUS_LIMIT = 10;
|
|
39259
39496
|
function createTurnLock() {
|
|
39260
|
-
let
|
|
39261
|
-
let
|
|
39262
|
-
|
|
39263
|
-
|
|
39264
|
-
|
|
39265
|
-
|
|
39266
|
-
|
|
39267
|
-
|
|
39268
|
-
|
|
39269
|
-
|
|
39270
|
-
|
|
39271
|
-
|
|
39272
|
-
|
|
39273
|
-
|
|
39274
|
-
|
|
39275
|
-
|
|
39497
|
+
let chatTotalActive = 0;
|
|
39498
|
+
let autonomousTotalActive = 0;
|
|
39499
|
+
let chatRunning = 0;
|
|
39500
|
+
let autonomousRunning = 0;
|
|
39501
|
+
const chatQueue = [];
|
|
39502
|
+
const execQueue = [];
|
|
39503
|
+
const asyncQueue = [];
|
|
39504
|
+
let lastServed = null;
|
|
39505
|
+
let autonomousBound = false;
|
|
39506
|
+
const logBound = (queued) => {
|
|
39507
|
+
console.warn(
|
|
39508
|
+
`[mrrlin-mcp director-bridge] warn autonomous_ceiling_bound {"limit":${AUTONOMOUS_LIMIT},"queued":${queued}}`
|
|
39509
|
+
);
|
|
39510
|
+
};
|
|
39511
|
+
const maybeEnterBound = () => {
|
|
39512
|
+
if (!autonomousBound && autonomousRunning === AUTONOMOUS_LIMIT && execQueue.length + asyncQueue.length > 0) {
|
|
39513
|
+
autonomousBound = true;
|
|
39514
|
+
logBound(execQueue.length + asyncQueue.length);
|
|
39515
|
+
}
|
|
39516
|
+
};
|
|
39517
|
+
const maybeLeaveBound = () => {
|
|
39518
|
+
if (autonomousBound && (autonomousRunning < AUTONOMOUS_LIMIT || execQueue.length + asyncQueue.length === 0)) {
|
|
39519
|
+
autonomousBound = false;
|
|
39520
|
+
logBound(execQueue.length + asyncQueue.length);
|
|
39521
|
+
}
|
|
39522
|
+
};
|
|
39523
|
+
const acquire = (lane, startRunner) => {
|
|
39524
|
+
if (lane === "chat") {
|
|
39525
|
+
if (chatRunning < CHAT_LIMIT) {
|
|
39526
|
+
chatRunning += 1;
|
|
39527
|
+
startRunner();
|
|
39528
|
+
} else {
|
|
39529
|
+
chatQueue.push(startRunner);
|
|
39530
|
+
}
|
|
39531
|
+
} else {
|
|
39532
|
+
if (autonomousRunning < AUTONOMOUS_LIMIT) {
|
|
39533
|
+
autonomousRunning += 1;
|
|
39534
|
+
startRunner();
|
|
39535
|
+
} else {
|
|
39536
|
+
if (lane === "exec") {
|
|
39537
|
+
execQueue.push(startRunner);
|
|
39538
|
+
} else {
|
|
39539
|
+
asyncQueue.push(startRunner);
|
|
39276
39540
|
}
|
|
39277
|
-
|
|
39278
|
-
|
|
39279
|
-
}
|
|
39280
|
-
|
|
39541
|
+
maybeEnterBound();
|
|
39542
|
+
}
|
|
39543
|
+
}
|
|
39544
|
+
};
|
|
39545
|
+
const release = (lane) => {
|
|
39546
|
+
if (lane === "chat") {
|
|
39547
|
+
chatRunning -= 1;
|
|
39548
|
+
const next = chatQueue.shift();
|
|
39549
|
+
if (next) {
|
|
39550
|
+
chatRunning += 1;
|
|
39551
|
+
next();
|
|
39552
|
+
}
|
|
39553
|
+
} else {
|
|
39554
|
+
autonomousRunning -= 1;
|
|
39555
|
+
const execWait = execQueue.length > 0;
|
|
39556
|
+
const asyncWait = asyncQueue.length > 0;
|
|
39557
|
+
if (execWait || asyncWait) {
|
|
39558
|
+
let serveLane;
|
|
39559
|
+
if (execWait && !asyncWait) {
|
|
39560
|
+
serveLane = "exec";
|
|
39561
|
+
} else if (!execWait && asyncWait) {
|
|
39562
|
+
serveLane = "async";
|
|
39563
|
+
} else {
|
|
39564
|
+
serveLane = lastServed === "exec" ? "async" : "exec";
|
|
39565
|
+
}
|
|
39566
|
+
const queue = serveLane === "exec" ? execQueue : asyncQueue;
|
|
39567
|
+
const next = queue.shift();
|
|
39568
|
+
if (next) {
|
|
39569
|
+
autonomousRunning += 1;
|
|
39570
|
+
lastServed = serveLane;
|
|
39571
|
+
next();
|
|
39572
|
+
}
|
|
39573
|
+
}
|
|
39574
|
+
maybeLeaveBound();
|
|
39575
|
+
}
|
|
39281
39576
|
};
|
|
39577
|
+
const run3 = async (lane, fn) => {
|
|
39578
|
+
if (lane === "chat") {
|
|
39579
|
+
chatTotalActive += 1;
|
|
39580
|
+
} else {
|
|
39581
|
+
autonomousTotalActive += 1;
|
|
39582
|
+
}
|
|
39583
|
+
return new Promise((resolve, reject) => {
|
|
39584
|
+
const start = () => {
|
|
39585
|
+
let bodyPromise;
|
|
39586
|
+
try {
|
|
39587
|
+
bodyPromise = fn();
|
|
39588
|
+
} catch (e) {
|
|
39589
|
+
bodyPromise = Promise.reject(e);
|
|
39590
|
+
}
|
|
39591
|
+
bodyPromise.then((v) => resolve(v)).catch((e) => reject(e)).finally(() => {
|
|
39592
|
+
if (lane === "chat") {
|
|
39593
|
+
chatTotalActive -= 1;
|
|
39594
|
+
} else {
|
|
39595
|
+
autonomousTotalActive -= 1;
|
|
39596
|
+
}
|
|
39597
|
+
release(lane);
|
|
39598
|
+
});
|
|
39599
|
+
};
|
|
39600
|
+
acquire(lane, start);
|
|
39601
|
+
});
|
|
39602
|
+
};
|
|
39603
|
+
const activeCount = () => chatTotalActive + autonomousTotalActive;
|
|
39604
|
+
return { run: run3, activeCount };
|
|
39282
39605
|
}
|
|
39283
39606
|
|
|
39284
39607
|
// src/self-update.ts
|
|
@@ -39642,7 +39965,7 @@ function startCodexProbe(deps = {}) {
|
|
|
39642
39965
|
}
|
|
39643
39966
|
|
|
39644
39967
|
// src/_generated/version.ts
|
|
39645
|
-
var PKG_VERSION = "0.3.
|
|
39968
|
+
var PKG_VERSION = "0.3.62";
|
|
39646
39969
|
|
|
39647
39970
|
// src/api-base-url-migrate.ts
|
|
39648
39971
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
@@ -40142,7 +40465,7 @@ async function attemptSchedulerTick(deps) {
|
|
|
40142
40465
|
return { nextWakeAt: typeof data.nextWakeAt === "string" ? data.nextWakeAt : null, failed: false };
|
|
40143
40466
|
} catch (error51) {
|
|
40144
40467
|
process.stderr.write(
|
|
40145
|
-
`[mrrlin-mcp director-bridge] scheduler tick failed: ${
|
|
40468
|
+
`[mrrlin-mcp director-bridge] scheduler tick failed: ${describeError(error51)}
|
|
40146
40469
|
`
|
|
40147
40470
|
);
|
|
40148
40471
|
bridgeHealth?.recordFailure("schedulerTick", error51);
|
|
@@ -41831,6 +42154,11 @@ function renderMilestone(m, ctx) {
|
|
|
41831
42154
|
return "Autodeploy is enabled, but this task has nothing deployable \u2014 skipping";
|
|
41832
42155
|
case "daily_limit_reached":
|
|
41833
42156
|
return "Daily autonomous operations limit reached \u2014 I will continue tomorrow";
|
|
42157
|
+
case "thread_retired": {
|
|
42158
|
+
if (ctx.reason === "bounded_no_state")
|
|
42159
|
+
return "Started a fresh conversation for this task \u2014 the previous one grew too long and no progress notes were saved, so some earlier reasoning may be lost";
|
|
42160
|
+
return "Started a fresh conversation for this task \u2014 the previous one grew too long, so I carried the saved progress notes over";
|
|
42161
|
+
}
|
|
41834
42162
|
}
|
|
41835
42163
|
}
|
|
41836
42164
|
|
|
@@ -41854,6 +42182,82 @@ async function postRunFeed(client, projectSlug, runId, taskId, milestone, ctx =
|
|
|
41854
42182
|
}
|
|
41855
42183
|
}
|
|
41856
42184
|
|
|
42185
|
+
// src/output-projection.ts
|
|
42186
|
+
var FAILURE_PATTERNS = [
|
|
42187
|
+
/^\s*(?:E|FAIL|ERROR|ERR!)\b/i,
|
|
42188
|
+
/\bTraceback \(most recent call last\)/,
|
|
42189
|
+
/^\s*at\s+.+:\d+:\d+/,
|
|
42190
|
+
// stack frames
|
|
42191
|
+
/\bAssertionError\b|\bexpected\b.*\breceived\b|\bexpected:\b/i,
|
|
42192
|
+
/\berror\b[:\s]|\bfailed\b[:\s]|\bfailure\b[:\s]/i,
|
|
42193
|
+
/^\s*not ok\b/,
|
|
42194
|
+
// TAP
|
|
42195
|
+
/\b(?:SyntaxError|TypeError|ReferenceError|RangeError)\b/,
|
|
42196
|
+
/^\s*✕|^\s*✗|^\s*×/,
|
|
42197
|
+
/\bexit(?:ed)? (?:code|status)\s*[:=]?\s*[1-9]/i
|
|
42198
|
+
];
|
|
42199
|
+
var DEFAULT_OUTPUT_PROJECTION_MAX_CHARS = 2e3;
|
|
42200
|
+
function projectCommandOutput(output3, options = {}) {
|
|
42201
|
+
const maxChars = options.maxChars ?? DEFAULT_OUTPUT_PROJECTION_MAX_CHARS;
|
|
42202
|
+
const exitStatus = options.exitStatus ?? null;
|
|
42203
|
+
const fullOutputRef = options.fullOutputRef ?? null;
|
|
42204
|
+
const label = options.label ?? "command output";
|
|
42205
|
+
const lines2 = output3.split(/\r?\n/);
|
|
42206
|
+
const matched = [];
|
|
42207
|
+
for (let index = 0; index < lines2.length; index += 1) {
|
|
42208
|
+
const line = lines2[index] ?? "";
|
|
42209
|
+
if (FAILURE_PATTERNS.some((pattern) => pattern.test(line))) matched.push(index);
|
|
42210
|
+
}
|
|
42211
|
+
const candidates = matched.length > 0 ? matched : lines2.map((_, index) => index);
|
|
42212
|
+
const kept = [];
|
|
42213
|
+
let used = 0;
|
|
42214
|
+
for (let cursor = candidates.length - 1; cursor >= 0; cursor -= 1) {
|
|
42215
|
+
const index = candidates[cursor];
|
|
42216
|
+
if (index === void 0) continue;
|
|
42217
|
+
let text = lines2[index] ?? "";
|
|
42218
|
+
if (text.trim().length === 0) continue;
|
|
42219
|
+
if (text.length > maxChars) {
|
|
42220
|
+
text = `${text.slice(0, Math.max(0, maxChars - 14))}\u2026[line cut]`;
|
|
42221
|
+
}
|
|
42222
|
+
const cost = text.length + 1;
|
|
42223
|
+
if (used + cost > maxChars) break;
|
|
42224
|
+
kept.push({ index, text });
|
|
42225
|
+
used += cost;
|
|
42226
|
+
}
|
|
42227
|
+
kept.sort((a, b) => a.index - b.index);
|
|
42228
|
+
const failureLines = kept.map((entry) => entry.text);
|
|
42229
|
+
const carried = failureLines.reduce((total, line) => total + line.length + 1, 0);
|
|
42230
|
+
const omittedChars = Math.max(0, output3.length - carried);
|
|
42231
|
+
const parts = [`${label}:`];
|
|
42232
|
+
parts.push(exitStatus === null ? "exit status unknown" : `exit status ${exitStatus}`);
|
|
42233
|
+
parts.push(
|
|
42234
|
+
matched.length > 0 ? `${failureLines.length} of ${matched.length} failure-bearing line(s) shown` : `no failure markers found; showing the tail (${failureLines.length} line(s))`
|
|
42235
|
+
);
|
|
42236
|
+
if (omittedChars > 0) {
|
|
42237
|
+
parts.push(
|
|
42238
|
+
fullOutputRef ? `${omittedChars} chars omitted \u2014 retrieve ${fullOutputRef} for the full output` : `${omittedChars} chars omitted`
|
|
42239
|
+
);
|
|
42240
|
+
}
|
|
42241
|
+
return {
|
|
42242
|
+
exitStatus,
|
|
42243
|
+
failureLines,
|
|
42244
|
+
summary: parts.join(" "),
|
|
42245
|
+
omittedChars,
|
|
42246
|
+
fullOutputRef,
|
|
42247
|
+
usedTailFallback: matched.length === 0
|
|
42248
|
+
};
|
|
42249
|
+
}
|
|
42250
|
+
function renderOutputProjection(projection) {
|
|
42251
|
+
const lines2 = [projection.summary];
|
|
42252
|
+
if (projection.failureLines.length > 0) {
|
|
42253
|
+
lines2.push(...projection.failureLines);
|
|
42254
|
+
}
|
|
42255
|
+
return lines2.join("\n");
|
|
42256
|
+
}
|
|
42257
|
+
function outputProjectionDisabled(env = process.env) {
|
|
42258
|
+
return (env.MRRLIN_EXEC_OUTPUT_PROJECTION_DISABLE ?? "").trim() === "1";
|
|
42259
|
+
}
|
|
42260
|
+
|
|
41857
42261
|
// src/deploy-gate.ts
|
|
41858
42262
|
var DEFAULT_DEPLOY_POLL_BUDGET_SECONDS = 1200;
|
|
41859
42263
|
var DEFAULT_PROD_GRACE_SECONDS = 900;
|
|
@@ -42209,10 +42613,48 @@ async function runDeployGateTick(deps, projectSlug, run3, task) {
|
|
|
42209
42613
|
task,
|
|
42210
42614
|
run: run3
|
|
42211
42615
|
});
|
|
42616
|
+
const verificationAttempt = attemptIndex(artifacts, env, "verification") + 1;
|
|
42617
|
+
let outputRef = null;
|
|
42618
|
+
if (verdict.fullOutput && !outputProjectionDisabled()) {
|
|
42619
|
+
outputRef = `EA-veroutput-${env}-${verificationAttempt}`;
|
|
42620
|
+
const stored = await deps.client.appendExecutionArtifact(projectSlug, run3.id, {
|
|
42621
|
+
id: outputRef,
|
|
42622
|
+
kind: "command_output",
|
|
42623
|
+
payload: { env, source: "verification-turn", output: verdict.fullOutput }
|
|
42624
|
+
}).then(() => true).catch(() => false);
|
|
42625
|
+
if (!stored) outputRef = null;
|
|
42626
|
+
}
|
|
42627
|
+
const projection = verdict.fullOutput && !outputProjectionDisabled() ? projectCommandOutput(verdict.fullOutput, {
|
|
42628
|
+
// A model turn reports no exit code; claiming 0 would assert a success never observed.
|
|
42629
|
+
exitStatus: null,
|
|
42630
|
+
fullOutputRef: outputRef,
|
|
42631
|
+
label: `verification (${env})`
|
|
42632
|
+
}) : null;
|
|
42633
|
+
if (projection?.usedTailFallback) {
|
|
42634
|
+
console.warn(
|
|
42635
|
+
JSON.stringify({
|
|
42636
|
+
event: "output_projection_tail_fallback",
|
|
42637
|
+
projectSlug,
|
|
42638
|
+
runId: run3.id,
|
|
42639
|
+
env,
|
|
42640
|
+
detail: "no failure marker matched; the projection carries the tail instead"
|
|
42641
|
+
})
|
|
42642
|
+
);
|
|
42643
|
+
}
|
|
42212
42644
|
await deps.client.appendExecutionArtifact(projectSlug, run3.id, {
|
|
42213
|
-
id: `EA-verification-${env}-${
|
|
42645
|
+
id: `EA-verification-${env}-${verificationAttempt}`,
|
|
42214
42646
|
kind: "verification",
|
|
42215
|
-
payload: {
|
|
42647
|
+
payload: {
|
|
42648
|
+
env,
|
|
42649
|
+
verdict: verdict.verdict,
|
|
42650
|
+
summary: verdict.summary,
|
|
42651
|
+
turnRef: verdict.turnRef,
|
|
42652
|
+
...projection ? {
|
|
42653
|
+
projection: renderOutputProjection(projection),
|
|
42654
|
+
fullOutputArtifactId: projection.fullOutputRef,
|
|
42655
|
+
omittedChars: projection.omittedChars
|
|
42656
|
+
} : {}
|
|
42657
|
+
}
|
|
42216
42658
|
});
|
|
42217
42659
|
if (verdict.verdict === "fail") {
|
|
42218
42660
|
if (env === "prod" && task.autonomyLevel === "auto") {
|
|
@@ -42524,6 +42966,112 @@ function buildPullRequestBody(input) {
|
|
|
42524
42966
|
${lines2.join("\n")}`;
|
|
42525
42967
|
}
|
|
42526
42968
|
|
|
42969
|
+
// src/context-compact/policy.ts
|
|
42970
|
+
var DEFAULT_THRESHOLD_CHARS = 12e3;
|
|
42971
|
+
var DEFAULT_MAX_ITEMS = 25;
|
|
42972
|
+
function readPositiveInt(value, fallback) {
|
|
42973
|
+
const raw = (value ?? "").trim();
|
|
42974
|
+
if (!raw) return fallback;
|
|
42975
|
+
const parsed = Number.parseInt(raw, 10);
|
|
42976
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
42977
|
+
}
|
|
42978
|
+
function readCompactPolicy(env = process.env) {
|
|
42979
|
+
const disabled = (env.MRRLIN_MCP_COMPACT_DISABLE ?? "").trim() === "1";
|
|
42980
|
+
return {
|
|
42981
|
+
enabled: !disabled,
|
|
42982
|
+
thresholdChars: readPositiveInt(env.MRRLIN_MCP_COMPACT_THRESHOLD_CHARS, DEFAULT_THRESHOLD_CHARS),
|
|
42983
|
+
maxItems: readPositiveInt(env.MRRLIN_MCP_COMPACT_MAX_ITEMS, DEFAULT_MAX_ITEMS),
|
|
42984
|
+
debug: (env.MRRLIN_MCP_COMPACT_DEBUG ?? "").trim() === "1",
|
|
42985
|
+
retrievalBudgetDisable: (env.MRRLIN_RETRIEVAL_BUDGET_DISABLE ?? "").trim() === "1"
|
|
42986
|
+
};
|
|
42987
|
+
}
|
|
42988
|
+
function warmDeltaDisabled(env = process.env) {
|
|
42989
|
+
return (env.MRRLIN_EXEC_WARM_DELTA_DISABLE ?? "").trim() === "1";
|
|
42990
|
+
}
|
|
42991
|
+
var DEFAULT_THREAD_MAX_RUNS = 12;
|
|
42992
|
+
var THREAD_MAX_RUNS_MIN = 4;
|
|
42993
|
+
var THREAD_MAX_RUNS_MAX = 50;
|
|
42994
|
+
var DEFAULT_THREAD_RETIRE_GRACE_RUNS = 6;
|
|
42995
|
+
var warnedOutOfRange = /* @__PURE__ */ new Set();
|
|
42996
|
+
function readBoundedInt(name, raw, fallback, min, max) {
|
|
42997
|
+
const trimmed = (raw ?? "").trim();
|
|
42998
|
+
if (!trimmed) return fallback;
|
|
42999
|
+
const parsed = Number.parseInt(trimmed, 10);
|
|
43000
|
+
if (Number.isInteger(parsed) && parsed >= min && parsed <= max) return parsed;
|
|
43001
|
+
if (!warnedOutOfRange.has(name)) {
|
|
43002
|
+
warnedOutOfRange.add(name);
|
|
43003
|
+
console.warn(
|
|
43004
|
+
JSON.stringify({
|
|
43005
|
+
event: "thread_retirement_bound_out_of_range",
|
|
43006
|
+
variable: name,
|
|
43007
|
+
provided: trimmed,
|
|
43008
|
+
accepted: `${min}-${max}`,
|
|
43009
|
+
usingDefault: fallback
|
|
43010
|
+
})
|
|
43011
|
+
);
|
|
43012
|
+
}
|
|
43013
|
+
return fallback;
|
|
43014
|
+
}
|
|
43015
|
+
function threadMaxRuns(env = process.env) {
|
|
43016
|
+
return readBoundedInt(
|
|
43017
|
+
"MRRLIN_EXEC_THREAD_MAX_RUNS",
|
|
43018
|
+
env.MRRLIN_EXEC_THREAD_MAX_RUNS,
|
|
43019
|
+
DEFAULT_THREAD_MAX_RUNS,
|
|
43020
|
+
THREAD_MAX_RUNS_MIN,
|
|
43021
|
+
THREAD_MAX_RUNS_MAX
|
|
43022
|
+
);
|
|
43023
|
+
}
|
|
43024
|
+
function threadRetireGraceRuns(env = process.env) {
|
|
43025
|
+
return readBoundedInt(
|
|
43026
|
+
"MRRLIN_EXEC_THREAD_RETIRE_GRACE_RUNS",
|
|
43027
|
+
env.MRRLIN_EXEC_THREAD_RETIRE_GRACE_RUNS,
|
|
43028
|
+
DEFAULT_THREAD_RETIRE_GRACE_RUNS,
|
|
43029
|
+
0,
|
|
43030
|
+
THREAD_MAX_RUNS_MAX
|
|
43031
|
+
);
|
|
43032
|
+
}
|
|
43033
|
+
function threadRetireDisabled(env = process.env) {
|
|
43034
|
+
return (env.MRRLIN_EXEC_THREAD_RETIRE_DISABLE ?? "").trim() === "1";
|
|
43035
|
+
}
|
|
43036
|
+
|
|
43037
|
+
// src/thread-retirement.ts
|
|
43038
|
+
function decideThreadRetirement(input) {
|
|
43039
|
+
if (input.disabled) return { retire: false };
|
|
43040
|
+
if (input.threadRunCount < input.maxRuns) return { retire: false };
|
|
43041
|
+
if (input.hasNarrative) return { retire: true, reason: "bounded_run_count" };
|
|
43042
|
+
if (input.threadRunCount >= input.maxRuns + input.graceRuns) {
|
|
43043
|
+
return { retire: true, reason: "bounded_no_state" };
|
|
43044
|
+
}
|
|
43045
|
+
return { retire: false };
|
|
43046
|
+
}
|
|
43047
|
+
function hasNarrativeContent(state) {
|
|
43048
|
+
if (!state) return false;
|
|
43049
|
+
return [state.goal, state.acceptedRequirements, state.decisions, state.openProblems, state.nextActions].some(
|
|
43050
|
+
(field) => typeof field === "string" && field.trim().length > 0
|
|
43051
|
+
);
|
|
43052
|
+
}
|
|
43053
|
+
|
|
43054
|
+
// src/effort-tier.ts
|
|
43055
|
+
var DEFAULT_EFFORT_LEVEL = "medium";
|
|
43056
|
+
var MECHANICAL_EFFORT_LEVEL = "low";
|
|
43057
|
+
var ESCALATED_EFFORT_LEVEL = "high";
|
|
43058
|
+
function deriveEffort(input) {
|
|
43059
|
+
if (input.disabled) return null;
|
|
43060
|
+
if (input.impact === "high") {
|
|
43061
|
+
return {
|
|
43062
|
+
level: ESCALATED_EFFORT_LEVEL,
|
|
43063
|
+
escalationReason: "task impact is high (operator-set)"
|
|
43064
|
+
};
|
|
43065
|
+
}
|
|
43066
|
+
if (input.impact === "low") {
|
|
43067
|
+
return { level: MECHANICAL_EFFORT_LEVEL, escalationReason: null };
|
|
43068
|
+
}
|
|
43069
|
+
return { level: DEFAULT_EFFORT_LEVEL, escalationReason: null };
|
|
43070
|
+
}
|
|
43071
|
+
function effortDisabled(env = process.env) {
|
|
43072
|
+
return (env.MRRLIN_EXEC_EFFORT_DISABLE ?? "").trim() === "1";
|
|
43073
|
+
}
|
|
43074
|
+
|
|
42527
43075
|
// src/execution-consumer.ts
|
|
42528
43076
|
var DEFAULT_STALE_SECONDS = 300;
|
|
42529
43077
|
var DEFAULT_MAX_LEASE_RECLAIMS = 3;
|
|
@@ -42688,6 +43236,18 @@ var BASE_INSTRUCTIONS_PREFIX = [
|
|
|
42688
43236
|
" ## Result \u2014 what was accomplished, key findings or metrics, follow-up tasks created.",
|
|
42689
43237
|
" Do NOT remove earlier sections \u2014 they remain useful for context.",
|
|
42690
43238
|
" Adapt depth to the task: a one-line fix needs one sentence, not four headings.",
|
|
43239
|
+
"",
|
|
43240
|
+
// Slice 4 of token-efficient-execution-runs (D8). This is the ONLY way the reasoning behind a
|
|
43241
|
+
// decision survives past this conversation: a thread is retired once it has accumulated too many
|
|
43242
|
+
// runs, and the next run then starts from this record plus the repository. Everything else the
|
|
43243
|
+
// next run receives (spec, run history, artifacts) is reconstructed from the database anyway —
|
|
43244
|
+
// what only the model holds is why it chose what it chose, and what it intended to do next.
|
|
43245
|
+
"BEFORE you end your turn, call `update_task_state` to record where this task now stands: the",
|
|
43246
|
+
"goal as you understand it, decisions you made AND WHY, problems still open, and the next",
|
|
43247
|
+
"concrete actions. A later run may start from a FRESH conversation that has none of this turn's",
|
|
43248
|
+
"context \u2014 that record is what it will read. A decision without its reason is the thing most",
|
|
43249
|
+
"often lost, so state the reason. Omit any field you learned nothing new about; an omitted field",
|
|
43250
|
+
"keeps its previous value. Do not restate the spec or the file list \u2014 the next run gets those.",
|
|
42691
43251
|
""
|
|
42692
43252
|
];
|
|
42693
43253
|
var CONSUMER_BASE_INSTRUCTIONS = [
|
|
@@ -42923,13 +43483,15 @@ async function runHasLease(deps, projectSlug, runId, leaseId) {
|
|
|
42923
43483
|
return false;
|
|
42924
43484
|
}
|
|
42925
43485
|
}
|
|
42926
|
-
async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inputText, overallMs, phase) {
|
|
43486
|
+
async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inputText, overallMs, phase, effort) {
|
|
42927
43487
|
const mapper = new CodexBridgeEventMapper();
|
|
42928
43488
|
mapper.reset();
|
|
42929
43489
|
let turnError = null;
|
|
42930
43490
|
let interruptFailed = false;
|
|
42931
43491
|
let touch = () => {
|
|
42932
43492
|
};
|
|
43493
|
+
let turnUsage = null;
|
|
43494
|
+
const promptBytes = Buffer.byteLength(inputText, "utf8");
|
|
42933
43495
|
const turnStartedAt = Date.now();
|
|
42934
43496
|
let lastActivityAt = turnStartedAt;
|
|
42935
43497
|
const persist = async (event) => {
|
|
@@ -42945,7 +43507,7 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
42945
43507
|
} catch {
|
|
42946
43508
|
}
|
|
42947
43509
|
};
|
|
42948
|
-
return deps.
|
|
43510
|
+
return deps.run("exec", async () => {
|
|
42949
43511
|
const pending = [];
|
|
42950
43512
|
let resolveTurnEnded = null;
|
|
42951
43513
|
const turnEnded = new Promise((resolve) => {
|
|
@@ -42958,6 +43520,8 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
42958
43520
|
lastActivityAt = Date.now();
|
|
42959
43521
|
touch();
|
|
42960
43522
|
}
|
|
43523
|
+
const usage = !notifThreadId || notifThreadId === threadId ? extractTurnTokenUsage(method, params) : null;
|
|
43524
|
+
if (usage) turnUsage = usage;
|
|
42961
43525
|
const events = mapper.mapNotification(
|
|
42962
43526
|
{ method, params },
|
|
42963
43527
|
threadId
|
|
@@ -42983,7 +43547,8 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
42983
43547
|
touch = activity.touch;
|
|
42984
43548
|
const accepted = await codex.turn.start({
|
|
42985
43549
|
threadId,
|
|
42986
|
-
input: [{ type: "text", text: inputText }]
|
|
43550
|
+
input: [{ type: "text", text: inputText }],
|
|
43551
|
+
...effort === void 0 ? {} : { effort }
|
|
42987
43552
|
});
|
|
42988
43553
|
acceptedTurnId = accepted?.turn?.id ?? null;
|
|
42989
43554
|
await turnEnded;
|
|
@@ -43018,7 +43583,8 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
43018
43583
|
clearInterval(touchTimer);
|
|
43019
43584
|
unsub();
|
|
43020
43585
|
}
|
|
43021
|
-
|
|
43586
|
+
const telemetry = { promptBytes, usage: turnUsage };
|
|
43587
|
+
return turnError ? { ok: false, error: turnError, interruptFailed, telemetry } : { ok: true, telemetry };
|
|
43022
43588
|
});
|
|
43023
43589
|
}
|
|
43024
43590
|
async function driveRun(deps, projectSlug, runId) {
|
|
@@ -43088,6 +43654,47 @@ async function driveRun(deps, projectSlug, runId) {
|
|
|
43088
43654
|
} : context
|
|
43089
43655
|
);
|
|
43090
43656
|
bundle += await deployWorkflowReverifyNotice(deps.client, projectSlug);
|
|
43657
|
+
const runTelemetry = {
|
|
43658
|
+
promptBytes: 0,
|
|
43659
|
+
turnCount: 0,
|
|
43660
|
+
usage: null
|
|
43661
|
+
};
|
|
43662
|
+
const recordTurn = (outcome) => {
|
|
43663
|
+
runTelemetry.promptBytes += outcome.telemetry.promptBytes;
|
|
43664
|
+
runTelemetry.turnCount += 1;
|
|
43665
|
+
runTelemetry.usage = addTurnTokenUsage(runTelemetry.usage, outcome.telemetry.usage);
|
|
43666
|
+
return outcome;
|
|
43667
|
+
};
|
|
43668
|
+
const effortDecision = deriveEffort({
|
|
43669
|
+
impact: task.impact,
|
|
43670
|
+
type: task.type,
|
|
43671
|
+
disabled: effortDisabled()
|
|
43672
|
+
});
|
|
43673
|
+
const taskState = await deps.client.getTaskState(projectSlug, task.id).catch(() => null);
|
|
43674
|
+
const retirement = decideThreadRetirement({
|
|
43675
|
+
threadRunCount: taskState?.threadRunCount ?? 0,
|
|
43676
|
+
hasNarrative: hasNarrativeContent(taskState),
|
|
43677
|
+
disabled: threadRetireDisabled(),
|
|
43678
|
+
maxRuns: threadMaxRuns(),
|
|
43679
|
+
graceRuns: threadRetireGraceRuns()
|
|
43680
|
+
});
|
|
43681
|
+
const threadIdForAcquire = retirement.retire ? null : task.directorThreadId;
|
|
43682
|
+
if (retirement.retire) {
|
|
43683
|
+
console.warn(
|
|
43684
|
+
JSON.stringify({
|
|
43685
|
+
event: "thread_retirement_triggered",
|
|
43686
|
+
projectSlug,
|
|
43687
|
+
runId,
|
|
43688
|
+
taskId: task.id,
|
|
43689
|
+
reason: retirement.reason,
|
|
43690
|
+
threadRunCount: taskState?.threadRunCount ?? 0,
|
|
43691
|
+
retiringThreadId: task.directorThreadId
|
|
43692
|
+
})
|
|
43693
|
+
);
|
|
43694
|
+
}
|
|
43695
|
+
if (taskState) bundle += `
|
|
43696
|
+
|
|
43697
|
+
${renderTaskStateSection(taskState)}`;
|
|
43091
43698
|
const checkout = deps.checkoutRegistry?.get(projectSlug) ?? null;
|
|
43092
43699
|
let sandbox = "read-only";
|
|
43093
43700
|
let turnCwd = deps.codexCwd ?? null;
|
|
@@ -43163,7 +43770,7 @@ async function driveRun(deps, projectSlug, runId) {
|
|
|
43163
43770
|
const pushFn = deps.pushRunBranch ?? pushRunBranch;
|
|
43164
43771
|
try {
|
|
43165
43772
|
const { threadId, resumed } = await acquireThread(codex, {
|
|
43166
|
-
threadId:
|
|
43773
|
+
threadId: threadIdForAcquire,
|
|
43167
43774
|
startParams: {
|
|
43168
43775
|
cwd: turnCwd,
|
|
43169
43776
|
approvalPolicy: "never",
|
|
@@ -43179,9 +43786,36 @@ async function driveRun(deps, projectSlug, runId) {
|
|
|
43179
43786
|
},
|
|
43180
43787
|
onThreadIdChanged: async (newId) => {
|
|
43181
43788
|
if (!await runHasLease(deps, projectSlug, runId, leaseId)) return;
|
|
43789
|
+
if (retirement.retire) return;
|
|
43182
43790
|
await deps.client.updateTask(projectSlug, task.id, { directorThreadId: newId });
|
|
43183
43791
|
}
|
|
43184
43792
|
});
|
|
43793
|
+
if (retirement.retire && await runHasLease(deps, projectSlug, runId, leaseId)) {
|
|
43794
|
+
let persisted = true;
|
|
43795
|
+
const retiredThreadId = await deps.client.retireThread(projectSlug, task.id, threadId).catch(() => {
|
|
43796
|
+
persisted = false;
|
|
43797
|
+
return null;
|
|
43798
|
+
});
|
|
43799
|
+
if (persisted) {
|
|
43800
|
+
await postRunFeed(deps.client, projectSlug, runId, task.id, "thread_retired", {
|
|
43801
|
+
reason: retirement.reason
|
|
43802
|
+
});
|
|
43803
|
+
}
|
|
43804
|
+
console.warn(
|
|
43805
|
+
JSON.stringify({
|
|
43806
|
+
event: persisted ? "thread_retired" : "thread_retirement_write_failed",
|
|
43807
|
+
projectSlug,
|
|
43808
|
+
runId,
|
|
43809
|
+
taskId: task.id,
|
|
43810
|
+
reason: retirement.reason,
|
|
43811
|
+
retiredThreadId,
|
|
43812
|
+
newThreadId: threadId,
|
|
43813
|
+
// Says out loud what an unpersisted retirement costs, so the log line is actionable
|
|
43814
|
+
// rather than merely present.
|
|
43815
|
+
...persisted ? {} : { impact: "counter not reset and task still on the old thread; later runs will re-retire until this write succeeds" }
|
|
43816
|
+
})
|
|
43817
|
+
);
|
|
43818
|
+
}
|
|
43185
43819
|
if (!resumed) {
|
|
43186
43820
|
const primingBudgetMs = remainingTurnBudgetMs();
|
|
43187
43821
|
if (primingBudgetMs <= 0) {
|
|
@@ -43196,14 +43830,52 @@ async function driveRun(deps, projectSlug, runId) {
|
|
|
43196
43830
|
);
|
|
43197
43831
|
return;
|
|
43198
43832
|
}
|
|
43199
|
-
const primed =
|
|
43833
|
+
const primed = recordTurn(
|
|
43834
|
+
await driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, bundle, primingBudgetMs, "priming", effortDecision?.level)
|
|
43835
|
+
);
|
|
43200
43836
|
if (!primed.ok) {
|
|
43837
|
+
if (retirement.retire && task.directorThreadId) {
|
|
43838
|
+
await deps.client.updateTask(projectSlug, task.id, { directorThreadId: task.directorThreadId }).catch(() => {
|
|
43839
|
+
});
|
|
43840
|
+
console.warn(
|
|
43841
|
+
JSON.stringify({
|
|
43842
|
+
event: "thread_retirement_reverted",
|
|
43843
|
+
projectSlug,
|
|
43844
|
+
runId,
|
|
43845
|
+
taskId: task.id,
|
|
43846
|
+
reason: retirement.reason,
|
|
43847
|
+
restoredThreadId: task.directorThreadId,
|
|
43848
|
+
detail: "re-prime failed; predecessor thread restored"
|
|
43849
|
+
})
|
|
43850
|
+
);
|
|
43851
|
+
}
|
|
43201
43852
|
await resetWedgedThread(deps, projectSlug, task.id, primed.interruptFailed);
|
|
43202
43853
|
await failRun(deps, projectSlug, task, runId, leaseId, primed.error);
|
|
43203
43854
|
return;
|
|
43204
43855
|
}
|
|
43205
43856
|
}
|
|
43206
|
-
const
|
|
43857
|
+
const priorRuns = context.runs.filter((r) => r.id !== runId);
|
|
43858
|
+
const priorRun = priorRuns[priorRuns.length - 1] ?? null;
|
|
43859
|
+
const useDelta = resumed && !warmDeltaDisabled() && priorRun !== null;
|
|
43860
|
+
let resumeContent;
|
|
43861
|
+
if (useDelta) {
|
|
43862
|
+
const cutoffTime = priorRun.finishedAt ?? priorRun.createdAt;
|
|
43863
|
+
const newArtifacts = context.artifacts.filter((a) => a.createdAt > cutoffTime);
|
|
43864
|
+
resumeContent = renderRunDelta({
|
|
43865
|
+
task: {
|
|
43866
|
+
id: task.id,
|
|
43867
|
+
status: task.status,
|
|
43868
|
+
latestJudgement: task.latestJudgement,
|
|
43869
|
+
latestJudgementKind: task.latestJudgementKind
|
|
43870
|
+
},
|
|
43871
|
+
newlyFinishedRuns: [priorRun],
|
|
43872
|
+
newArtifacts,
|
|
43873
|
+
omittedArtifactCount: context.omittedArtifactCount
|
|
43874
|
+
});
|
|
43875
|
+
} else {
|
|
43876
|
+
resumeContent = bundle;
|
|
43877
|
+
}
|
|
43878
|
+
const executionPrompt = resumed ? `${resumeContent}
|
|
43207
43879
|
|
|
43208
43880
|
Continue executing task ${task.id}. Make the next concrete increment of progress and record artifacts/judgements via MCP tools.` : `Continue executing task ${task.id}. Make the next concrete increment of progress and record artifacts/judgements via MCP tools.`;
|
|
43209
43881
|
const workBudgetMs = remainingTurnBudgetMs();
|
|
@@ -43219,7 +43891,9 @@ Continue executing task ${task.id}. Make the next concrete increment of progress
|
|
|
43219
43891
|
);
|
|
43220
43892
|
return;
|
|
43221
43893
|
}
|
|
43222
|
-
const outcome =
|
|
43894
|
+
const outcome = recordTurn(
|
|
43895
|
+
await driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, executionPrompt, workBudgetMs, "work", effortDecision?.level)
|
|
43896
|
+
);
|
|
43223
43897
|
if (!outcome.ok) {
|
|
43224
43898
|
await resetWedgedThread(deps, projectSlug, task.id, outcome.interruptFailed);
|
|
43225
43899
|
await failRun(deps, projectSlug, task, runId, leaseId, outcome.error);
|
|
@@ -43243,16 +43917,19 @@ Continue executing task ${task.id}. Make the next concrete increment of progress
|
|
|
43243
43917
|
})
|
|
43244
43918
|
);
|
|
43245
43919
|
const completionPrompt = buildCompletionTurnPrompt(task.id, readiness.task.status);
|
|
43246
|
-
const completionOutcome =
|
|
43247
|
-
|
|
43248
|
-
|
|
43249
|
-
|
|
43250
|
-
|
|
43251
|
-
|
|
43252
|
-
|
|
43253
|
-
|
|
43254
|
-
|
|
43255
|
-
|
|
43920
|
+
const completionOutcome = recordTurn(
|
|
43921
|
+
await driveTurn(
|
|
43922
|
+
deps,
|
|
43923
|
+
codex,
|
|
43924
|
+
projectSlug,
|
|
43925
|
+
runId,
|
|
43926
|
+
leaseId,
|
|
43927
|
+
threadId,
|
|
43928
|
+
completionPrompt,
|
|
43929
|
+
completionBudget,
|
|
43930
|
+
"completion",
|
|
43931
|
+
effortDecision?.level
|
|
43932
|
+
)
|
|
43256
43933
|
);
|
|
43257
43934
|
if (!completionOutcome.ok) {
|
|
43258
43935
|
await resetWedgedThread(deps, projectSlug, task.id, completionOutcome.interruptFailed);
|
|
@@ -43431,9 +44108,97 @@ Continue executing task ${task.id}. Make the next concrete increment of progress
|
|
|
43431
44108
|
error51 instanceof Error ? error51.message : String(error51)
|
|
43432
44109
|
);
|
|
43433
44110
|
} finally {
|
|
44111
|
+
await deps.client.updateExecutionRun(projectSlug, runId, {
|
|
44112
|
+
promptBytes: runTelemetry.promptBytes,
|
|
44113
|
+
turnCount: runTelemetry.turnCount,
|
|
44114
|
+
inputTokens: runTelemetry.usage?.inputTokens ?? null,
|
|
44115
|
+
cachedInputTokens: runTelemetry.usage?.cachedInputTokens ?? null,
|
|
44116
|
+
outputTokens: runTelemetry.usage?.outputTokens ?? null,
|
|
44117
|
+
// Slice 7 (7.4): record the level actually used and, when it was an escalation, what caused
|
|
44118
|
+
// it — so "why did this run cost that much?" is answerable after the fact. NULL when the
|
|
44119
|
+
// slice is disabled, which per D6 reads as "not set" rather than a level we chose.
|
|
44120
|
+
effort: effortDecision?.level ?? null,
|
|
44121
|
+
effortEscalationReason: effortDecision?.escalationReason ?? null
|
|
44122
|
+
}).catch((error51) => {
|
|
44123
|
+
console.warn(
|
|
44124
|
+
JSON.stringify({
|
|
44125
|
+
event: "run_telemetry_write_failed",
|
|
44126
|
+
projectSlug,
|
|
44127
|
+
runId,
|
|
44128
|
+
detail: error51 instanceof Error ? error51.message : String(error51)
|
|
44129
|
+
})
|
|
44130
|
+
);
|
|
44131
|
+
});
|
|
44132
|
+
await writeServerOwnedTaskState(deps, projectSlug, task.id, runId, leaseId).catch((error51) => {
|
|
44133
|
+
console.warn(
|
|
44134
|
+
JSON.stringify({
|
|
44135
|
+
event: "task_state_server_write_failed",
|
|
44136
|
+
projectSlug,
|
|
44137
|
+
runId,
|
|
44138
|
+
taskId: task.id,
|
|
44139
|
+
detail: error51 instanceof Error ? error51.message : String(error51)
|
|
44140
|
+
})
|
|
44141
|
+
);
|
|
44142
|
+
});
|
|
43434
44143
|
disposeCodex();
|
|
43435
44144
|
}
|
|
43436
44145
|
}
|
|
44146
|
+
async function writeServerOwnedTaskState(deps, projectSlug, taskId, runId, leaseId) {
|
|
44147
|
+
const run3 = await deps.client.getExecutionRun(projectSlug, runId).catch(() => null);
|
|
44148
|
+
if (!run3) {
|
|
44149
|
+
console.warn(
|
|
44150
|
+
JSON.stringify({
|
|
44151
|
+
event: "task_state_server_write_skipped",
|
|
44152
|
+
projectSlug,
|
|
44153
|
+
runId,
|
|
44154
|
+
taskId,
|
|
44155
|
+
detail: "could not read the run's state_seq; skipped rather than writing a defaulted ordering value"
|
|
44156
|
+
})
|
|
44157
|
+
);
|
|
44158
|
+
return;
|
|
44159
|
+
}
|
|
44160
|
+
if (run3.leaseId !== null && run3.leaseId !== leaseId) {
|
|
44161
|
+
console.warn(
|
|
44162
|
+
JSON.stringify({
|
|
44163
|
+
event: "task_state_server_write_skipped",
|
|
44164
|
+
projectSlug,
|
|
44165
|
+
runId,
|
|
44166
|
+
taskId,
|
|
44167
|
+
detail: "the run is held by another lease (reclaimed); refusing to write state for a run we no longer own"
|
|
44168
|
+
})
|
|
44169
|
+
);
|
|
44170
|
+
return;
|
|
44171
|
+
}
|
|
44172
|
+
let artifacts = null;
|
|
44173
|
+
try {
|
|
44174
|
+
artifacts = await deps.client.listExecutionArtifacts(projectSlug, runId);
|
|
44175
|
+
} catch {
|
|
44176
|
+
artifacts = null;
|
|
44177
|
+
}
|
|
44178
|
+
let changed = null;
|
|
44179
|
+
if (artifacts !== null) {
|
|
44180
|
+
const summaries = artifacts.filter((artifact) => artifact.kind === "diff_summary").map((artifact) => JSON.stringify(artifact.payload));
|
|
44181
|
+
changed = summaries.length > 0 ? summaries.join("\n") : NO_FILE_CHANGES_THIS_RUN;
|
|
44182
|
+
}
|
|
44183
|
+
let latestVerification = null;
|
|
44184
|
+
if (artifacts !== null) {
|
|
44185
|
+
const verifications = artifacts.filter((artifact) => artifact.kind === "verification").map((artifact) => JSON.stringify(artifact.payload));
|
|
44186
|
+
latestVerification = verifications[verifications.length - 1] ?? NO_VERIFICATION_THIS_RUN;
|
|
44187
|
+
}
|
|
44188
|
+
await deps.client.upsertTaskState(projectSlug, taskId, {
|
|
44189
|
+
goal: null,
|
|
44190
|
+
acceptedRequirements: null,
|
|
44191
|
+
decisions: null,
|
|
44192
|
+
openProblems: null,
|
|
44193
|
+
nextActions: null,
|
|
44194
|
+
relevantFiles: null,
|
|
44195
|
+
filesChanged: changed,
|
|
44196
|
+
latestVerification,
|
|
44197
|
+
lastRunSeq: run3.stateSeq
|
|
44198
|
+
});
|
|
44199
|
+
}
|
|
44200
|
+
var NO_FILE_CHANGES_THIS_RUN = "no file changes recorded in this run";
|
|
44201
|
+
var NO_VERIFICATION_THIS_RUN = "not run in this run";
|
|
43437
44202
|
function buildDeliverableAuthorPrompt(task, specMarkdown) {
|
|
43438
44203
|
return [
|
|
43439
44204
|
`Produce the deliverable for the task below. Write the FULL deliverable content as markdown.`,
|
|
@@ -43963,7 +44728,8 @@ async function driveAsyncJob(deps, projectSlug, jobId) {
|
|
|
43963
44728
|
break;
|
|
43964
44729
|
}
|
|
43965
44730
|
try {
|
|
43966
|
-
outcome = await deps.
|
|
44731
|
+
outcome = await deps.run(
|
|
44732
|
+
"async",
|
|
43967
44733
|
() => descriptor2.run(
|
|
43968
44734
|
{ client: deps.client, cwd: deps.cwd, codexExecutable: deps.codexExecutable },
|
|
43969
44735
|
input
|
|
@@ -44038,7 +44804,7 @@ async function runAsyncBackstopSweep(deps, drive = (slug, jobId) => driveAsyncJo
|
|
|
44038
44804
|
} catch {
|
|
44039
44805
|
queued = [];
|
|
44040
44806
|
}
|
|
44041
|
-
|
|
44807
|
+
await Promise.all(queued.map((job) => drive(slug, job.id)));
|
|
44042
44808
|
}
|
|
44043
44809
|
}
|
|
44044
44810
|
|
|
@@ -44506,13 +45272,16 @@ function createInactivityWatchdog(opts) {
|
|
|
44506
45272
|
const clearT = opts.clearTimeoutFn ?? clearTimeout;
|
|
44507
45273
|
const now = opts.now ?? Date.now;
|
|
44508
45274
|
const suspended = opts.suspendedMs ?? (() => 0);
|
|
45275
|
+
const excluded = opts.idleExcludedMs ?? (() => 0);
|
|
44509
45276
|
let idleTimer = null;
|
|
44510
45277
|
let maxTimer = null;
|
|
44511
45278
|
let done = false;
|
|
44512
45279
|
const startAt = now();
|
|
44513
45280
|
const suspendedAtStart = suspended();
|
|
45281
|
+
const excludedAtStart = excluded();
|
|
44514
45282
|
let lastPokeAt = startAt;
|
|
44515
45283
|
let suspendedAtLastPoke = suspendedAtStart;
|
|
45284
|
+
let excludedAtLastPoke = excludedAtStart;
|
|
44516
45285
|
const expire = (reason) => {
|
|
44517
45286
|
if (done) return;
|
|
44518
45287
|
done = true;
|
|
@@ -44530,7 +45299,7 @@ function createInactivityWatchdog(opts) {
|
|
|
44530
45299
|
};
|
|
44531
45300
|
const onIdleDeadline = () => {
|
|
44532
45301
|
if (done) return;
|
|
44533
|
-
const awakeSilence = now() - lastPokeAt - (suspended() - suspendedAtLastPoke);
|
|
45302
|
+
const awakeSilence = now() - lastPokeAt - (suspended() - suspendedAtLastPoke) - (excluded() - excludedAtLastPoke);
|
|
44534
45303
|
if (awakeSilence < opts.idleMs) {
|
|
44535
45304
|
armIdle(opts.idleMs - awakeSilence);
|
|
44536
45305
|
return;
|
|
@@ -44554,6 +45323,7 @@ function createInactivityWatchdog(opts) {
|
|
|
44554
45323
|
if (idleTimer) clearT(idleTimer);
|
|
44555
45324
|
lastPokeAt = now();
|
|
44556
45325
|
suspendedAtLastPoke = suspended();
|
|
45326
|
+
excludedAtLastPoke = excluded();
|
|
44557
45327
|
armIdle(opts.idleMs);
|
|
44558
45328
|
},
|
|
44559
45329
|
cancel: () => {
|
|
@@ -44563,8 +45333,8 @@ function createInactivityWatchdog(opts) {
|
|
|
44563
45333
|
}
|
|
44564
45334
|
};
|
|
44565
45335
|
}
|
|
44566
|
-
var DEFAULT_CHAT_TURN_IDLE_SECONDS =
|
|
44567
|
-
var DEFAULT_CHAT_TURN_MAX_SECONDS =
|
|
45336
|
+
var DEFAULT_CHAT_TURN_IDLE_SECONDS = 300;
|
|
45337
|
+
var DEFAULT_CHAT_TURN_MAX_SECONDS = 2700;
|
|
44568
45338
|
function readPositiveSeconds(name, fallback) {
|
|
44569
45339
|
const raw = (process.env[name] ?? "").trim();
|
|
44570
45340
|
const parsed = Number.parseInt(raw, 10);
|
|
@@ -44577,6 +45347,64 @@ function chatTurnMaxMs() {
|
|
|
44577
45347
|
return readPositiveSeconds("MRRLIN_DIRECTOR_BRIDGE_CHAT_TURN_MAX_SECONDS", DEFAULT_CHAT_TURN_MAX_SECONDS) * 1e3;
|
|
44578
45348
|
}
|
|
44579
45349
|
|
|
45350
|
+
// src/tool-busy.ts
|
|
45351
|
+
function createToolBusyClock(opts) {
|
|
45352
|
+
const now = opts?.now ?? Date.now;
|
|
45353
|
+
const open = /* @__PURE__ */ new Set();
|
|
45354
|
+
let total = 0;
|
|
45355
|
+
let segmentStart = null;
|
|
45356
|
+
function start(itemId) {
|
|
45357
|
+
if (!open.has(itemId)) {
|
|
45358
|
+
open.add(itemId);
|
|
45359
|
+
if (open.size === 1) {
|
|
45360
|
+
segmentStart = now();
|
|
45361
|
+
}
|
|
45362
|
+
}
|
|
45363
|
+
}
|
|
45364
|
+
function end(itemId) {
|
|
45365
|
+
if (open.has(itemId)) {
|
|
45366
|
+
open.delete(itemId);
|
|
45367
|
+
if (open.size === 0) {
|
|
45368
|
+
const nowVal = now();
|
|
45369
|
+
if (segmentStart !== null) {
|
|
45370
|
+
total += nowVal - segmentStart;
|
|
45371
|
+
segmentStart = null;
|
|
45372
|
+
}
|
|
45373
|
+
}
|
|
45374
|
+
}
|
|
45375
|
+
}
|
|
45376
|
+
function endAll() {
|
|
45377
|
+
if (open.size > 0) {
|
|
45378
|
+
const nowVal = now();
|
|
45379
|
+
if (segmentStart !== null) {
|
|
45380
|
+
total += nowVal - segmentStart;
|
|
45381
|
+
segmentStart = null;
|
|
45382
|
+
}
|
|
45383
|
+
open.clear();
|
|
45384
|
+
}
|
|
45385
|
+
}
|
|
45386
|
+
function ms() {
|
|
45387
|
+
const nowVal = now();
|
|
45388
|
+
if (open.size > 0 && segmentStart !== null) {
|
|
45389
|
+
return total + (nowVal - segmentStart);
|
|
45390
|
+
}
|
|
45391
|
+
return total;
|
|
45392
|
+
}
|
|
45393
|
+
return { start, end, endAll, ms };
|
|
45394
|
+
}
|
|
45395
|
+
var TOOL_ITEM_TYPES = /* @__PURE__ */ new Set(["commandExecution", "mcpToolCall", "fileChange"]);
|
|
45396
|
+
function applyToolBusyNotification(clock, method, params) {
|
|
45397
|
+
if (method !== "item/started" && method !== "item/completed") return;
|
|
45398
|
+
if (typeof params !== "object" || params === null) return;
|
|
45399
|
+
const p = params;
|
|
45400
|
+
const item = typeof p.item === "object" && p.item !== null ? p.item : void 0;
|
|
45401
|
+
if (typeof item?.type !== "string" || !TOOL_ITEM_TYPES.has(item.type)) return;
|
|
45402
|
+
const id = typeof item.id === "string" ? item.id : typeof p.itemId === "string" ? p.itemId : void 0;
|
|
45403
|
+
if (id === void 0) return;
|
|
45404
|
+
if (method === "item/started") clock.start(id);
|
|
45405
|
+
else clock.end(id);
|
|
45406
|
+
}
|
|
45407
|
+
|
|
44580
45408
|
// src/worker-token.ts
|
|
44581
45409
|
var import_node_crypto7 = require("node:crypto");
|
|
44582
45410
|
var import_node_fs9 = require("node:fs");
|
|
@@ -48581,11 +49409,16 @@ function parseVerdict2(text) {
|
|
|
48581
49409
|
let last = null;
|
|
48582
49410
|
while ((match = re.exec(text)) !== null) last = match;
|
|
48583
49411
|
if (!last) {
|
|
48584
|
-
return {
|
|
49412
|
+
return {
|
|
49413
|
+
verdict: "fail",
|
|
49414
|
+
summary: "no parseable VERDICT line in verification output",
|
|
49415
|
+
turnRef: null,
|
|
49416
|
+
fullOutput: text
|
|
49417
|
+
};
|
|
48585
49418
|
}
|
|
48586
49419
|
const verdict = (last[1] ?? "").toLowerCase() === "pass" ? "pass" : "fail";
|
|
48587
49420
|
const summary = (last[2] ?? "").trim() || `verification ${verdict}`;
|
|
48588
|
-
return { verdict, summary, turnRef: null };
|
|
49421
|
+
return { verdict, summary, turnRef: null, fullOutput: text };
|
|
48589
49422
|
}
|
|
48590
49423
|
function isBlockedVerificationHost(hostname3) {
|
|
48591
49424
|
const h = hostname3.toLowerCase().replace(/^\[|\]$/g, "");
|
|
@@ -50685,7 +51518,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
50685
51518
|
}
|
|
50686
51519
|
};
|
|
50687
51520
|
try {
|
|
50688
|
-
await deps.
|
|
51521
|
+
await deps.run("chat", async () => {
|
|
50689
51522
|
if (currentReplayBuf.state === "interrupted" || currentReplayBuf.state === "completed") {
|
|
50690
51523
|
logCtx?.logger.logOut({
|
|
50691
51524
|
spanId,
|
|
@@ -50714,7 +51547,9 @@ function createBridgeMessageHandler(deps) {
|
|
|
50714
51547
|
outputEvents += 1;
|
|
50715
51548
|
sendInTurn({ type: "event", directorSessionId, event });
|
|
50716
51549
|
};
|
|
51550
|
+
const toolBusy = createToolBusyClock();
|
|
50717
51551
|
const unsub = codexClient.onNotification((method, params) => {
|
|
51552
|
+
applyToolBusyNotification(toolBusy, method, params);
|
|
50718
51553
|
pokeActivity();
|
|
50719
51554
|
if (method === "account/rateLimits/updated") {
|
|
50720
51555
|
const snapshot = params?.rateLimits ?? null;
|
|
@@ -50742,6 +51577,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
50742
51577
|
idleMs,
|
|
50743
51578
|
maxMs,
|
|
50744
51579
|
...deps.suspendedMs ? { suspendedMs: deps.suspendedMs } : {},
|
|
51580
|
+
idleExcludedMs: () => toolBusy.ms(),
|
|
50745
51581
|
onExpire: (reason) => {
|
|
50746
51582
|
rejectWatchdog?.(
|
|
50747
51583
|
new Error(
|
|
@@ -50845,6 +51681,7 @@ ${effectiveText}` : effectiveText;
|
|
|
50845
51681
|
}
|
|
50846
51682
|
watchdog.cancel();
|
|
50847
51683
|
unsub();
|
|
51684
|
+
toolBusy.endAll();
|
|
50848
51685
|
thread.cancel = null;
|
|
50849
51686
|
}
|
|
50850
51687
|
});
|
|
@@ -50964,8 +51801,8 @@ async function startDirectorBridge() {
|
|
|
50964
51801
|
const turnLock = createTurnLock();
|
|
50965
51802
|
let lastTurnEndedAt = Date.now();
|
|
50966
51803
|
const wrappedTurnLock = {
|
|
50967
|
-
|
|
50968
|
-
return turnLock.
|
|
51804
|
+
run(lane, fn) {
|
|
51805
|
+
return turnLock.run(lane, async () => {
|
|
50969
51806
|
try {
|
|
50970
51807
|
return await fn();
|
|
50971
51808
|
} finally {
|
|
@@ -51008,7 +51845,11 @@ async function startDirectorBridge() {
|
|
|
51008
51845
|
}
|
|
51009
51846
|
});
|
|
51010
51847
|
const codexProbeHandle = startCodexProbe();
|
|
51011
|
-
const consumerState = {
|
|
51848
|
+
const consumerState = {
|
|
51849
|
+
inFlightRunIds: /* @__PURE__ */ new Set(),
|
|
51850
|
+
lastClaimedRunId: null,
|
|
51851
|
+
lastClaimAt: null
|
|
51852
|
+
};
|
|
51012
51853
|
const health = createServiceHealth();
|
|
51013
51854
|
try {
|
|
51014
51855
|
migrateRetiredApiBaseUrls();
|
|
@@ -51087,7 +51928,7 @@ async function startDirectorBridge() {
|
|
|
51087
51928
|
// handle returned by acquireExecutorCodex (Fix A + G), so there is no shared
|
|
51088
51929
|
// mutable `activeExecutorClient` slot to race a concurrent chat/bootstrap turn.
|
|
51089
51930
|
releaseCodex: () => codexKeepalive.release(),
|
|
51090
|
-
|
|
51931
|
+
run: wrappedTurnLock.run,
|
|
51091
51932
|
staleSeconds,
|
|
51092
51933
|
touchIntervalMs: Math.min(DEFAULT_TOUCH_INTERVAL_MS, Math.floor(staleSeconds * 1e3 / 2)),
|
|
51093
51934
|
codexCwd: config2.codexCwd,
|
|
@@ -51114,7 +51955,7 @@ async function startDirectorBridge() {
|
|
|
51114
51955
|
// ADR 0007 self-review: critique the committed diff on the executor's own client before
|
|
51115
51956
|
// push/PR. Reuses the verification turn-runner (acquireThread + collect assistant text).
|
|
51116
51957
|
selfReviewTurn: createSelfReviewTurn({
|
|
51117
|
-
runTurn: (codexClient, cwd, prompt) => runCollectedCodexTurn(codexClient, prompt, cwd, SELF_REVIEW_BASE_INSTRUCTIONS)
|
|
51958
|
+
runTurn: (codexClient, cwd, prompt) => wrappedTurnLock.run("chat", () => runCollectedCodexTurn(codexClient, prompt, cwd, SELF_REVIEW_BASE_INSTRUCTIONS))
|
|
51118
51959
|
}),
|
|
51119
51960
|
// ADR 0015 deploy gate: after a pushed run reaches dev_deploy/prod_deploy, the backstop sweep
|
|
51120
51961
|
// dispatches the deploy + polls + runs a verification turn against the deployed env URL in a
|
|
@@ -51153,7 +51994,7 @@ async function startDirectorBridge() {
|
|
|
51153
51994
|
}
|
|
51154
51995
|
};
|
|
51155
51996
|
},
|
|
51156
|
-
runTurn: (codexClient, prompt, cwd) => runCollectedCodexTurn(codexClient, prompt, cwd, VERIFICATION_BASE_INSTRUCTIONS)
|
|
51997
|
+
runTurn: (codexClient, prompt, cwd) => wrappedTurnLock.run("chat", () => runCollectedCodexTurn(codexClient, prompt, cwd, VERIFICATION_BASE_INSTRUCTIONS))
|
|
51157
51998
|
}),
|
|
51158
51999
|
budgetSeconds: deployPollBudgetSeconds()
|
|
51159
52000
|
},
|
|
@@ -51178,7 +52019,7 @@ async function startDirectorBridge() {
|
|
|
51178
52019
|
const bridgeInstanceId = (0, import_node_crypto8.randomUUID)();
|
|
51179
52020
|
const asyncConsumerDeps = {
|
|
51180
52021
|
client,
|
|
51181
|
-
|
|
52022
|
+
run: wrappedTurnLock.run,
|
|
51182
52023
|
cwd: config2.codexCwd ?? process.cwd(),
|
|
51183
52024
|
codexExecutable: config2.codexExecutable,
|
|
51184
52025
|
staleSeconds,
|
|
@@ -51194,40 +52035,34 @@ async function startDirectorBridge() {
|
|
|
51194
52035
|
sink({ type: "async-result", directorSessionId, projectSlug: slug, deliveryKind, body });
|
|
51195
52036
|
}
|
|
51196
52037
|
};
|
|
51197
|
-
|
|
51198
|
-
|
|
51199
|
-
|
|
51200
|
-
};
|
|
51201
|
-
const driveTracked = (slug, runId) => enqueueRun(async () => {
|
|
51202
|
-
consumerState.inFlightRunId = runId;
|
|
52038
|
+
const driveTracked = (slug, runId) => {
|
|
52039
|
+
consumerState.inFlightRunIds.add(runId);
|
|
52040
|
+
consumerState.lastClaimedRunId = runId;
|
|
51203
52041
|
consumerState.lastClaimAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
51204
|
-
|
|
51205
|
-
await driveRun(consumerDeps, slug, runId);
|
|
51206
|
-
} catch (error51) {
|
|
52042
|
+
void driveRun(consumerDeps, slug, runId).catch((error51) => {
|
|
51207
52043
|
process.stderr.write(`[mrrlin-mcp director-bridge] drive failed for ${slug}/${runId}: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
51208
52044
|
`);
|
|
51209
|
-
}
|
|
51210
|
-
consumerState.
|
|
51211
|
-
}
|
|
51212
|
-
}
|
|
52045
|
+
}).finally(() => {
|
|
52046
|
+
consumerState.inFlightRunIds.delete(runId);
|
|
52047
|
+
});
|
|
52048
|
+
};
|
|
51213
52049
|
const driveRunNow = (slug, runId) => {
|
|
51214
|
-
consumerState.
|
|
52050
|
+
consumerState.inFlightRunIds.add(runId);
|
|
52051
|
+
consumerState.lastClaimedRunId = runId;
|
|
51215
52052
|
consumerState.lastClaimAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
51216
52053
|
void driveRun(consumerDeps, slug, runId).catch((error51) => {
|
|
51217
52054
|
process.stderr.write(`[mrrlin-mcp director-bridge] drive failed for ${slug}/${runId}: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
51218
52055
|
`);
|
|
51219
52056
|
}).finally(() => {
|
|
51220
|
-
consumerState.
|
|
52057
|
+
consumerState.inFlightRunIds.delete(runId);
|
|
51221
52058
|
});
|
|
51222
52059
|
};
|
|
51223
|
-
const driveAsyncTracked = (slug, jobId) =>
|
|
51224
|
-
|
|
51225
|
-
await driveAsyncJob(asyncConsumerDeps, slug, jobId);
|
|
51226
|
-
} catch (error51) {
|
|
52060
|
+
const driveAsyncTracked = (slug, jobId) => {
|
|
52061
|
+
void driveAsyncJob(asyncConsumerDeps, slug, jobId).catch((error51) => {
|
|
51227
52062
|
process.stderr.write(`[mrrlin-mcp director-bridge] async drive failed for ${slug}/${jobId}: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
51228
52063
|
`);
|
|
51229
|
-
}
|
|
51230
|
-
}
|
|
52064
|
+
});
|
|
52065
|
+
};
|
|
51231
52066
|
const driveAsyncNow = (slug, jobId) => {
|
|
51232
52067
|
void driveAsyncJob(asyncConsumerDeps, slug, jobId).catch((error51) => {
|
|
51233
52068
|
process.stderr.write(`[mrrlin-mcp director-bridge] async drive failed for ${slug}/${jobId}: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
@@ -51240,7 +52075,15 @@ async function startDirectorBridge() {
|
|
|
51240
52075
|
port: config2.port,
|
|
51241
52076
|
token: config2.token,
|
|
51242
52077
|
allowedOrigins: config2.allowedOrigins,
|
|
51243
|
-
getHealth: () => ({
|
|
52078
|
+
getHealth: () => ({
|
|
52079
|
+
ok: true,
|
|
52080
|
+
// Most recently claimed run, or null once nothing is in flight — kept for existing consumers.
|
|
52081
|
+
inFlightRunId: consumerState.inFlightRunIds.size > 0 ? consumerState.lastClaimedRunId : null,
|
|
52082
|
+
inFlightRunIds: Array.from(consumerState.inFlightRunIds),
|
|
52083
|
+
inFlightCount: consumerState.inFlightRunIds.size,
|
|
52084
|
+
lastClaimAt: consumerState.lastClaimAt,
|
|
52085
|
+
service: health.snapshot()
|
|
52086
|
+
})
|
|
51244
52087
|
})
|
|
51245
52088
|
);
|
|
51246
52089
|
const threads = /* @__PURE__ */ new Map();
|
|
@@ -51303,7 +52146,7 @@ async function startDirectorBridge() {
|
|
|
51303
52146
|
const sharedHandlerDeps = {
|
|
51304
52147
|
acquireCodex: () => codexKeepalive.acquire(),
|
|
51305
52148
|
releaseCodex: () => codexKeepalive.release(),
|
|
51306
|
-
|
|
52149
|
+
run: wrappedTurnLock.run,
|
|
51307
52150
|
suspendedMs: () => suspensionDetector.suspendedMs(),
|
|
51308
52151
|
buildStartParams: (msg, desiredModel) => buildThreadStartParams(msg, config2, desiredModel),
|
|
51309
52152
|
turnInactivity: () => ({ idleMs: chatTurnIdleMs(), maxMs: chatTurnMaxMs() }),
|
|
@@ -51449,7 +52292,7 @@ async function startDirectorBridge() {
|
|
|
51449
52292
|
await bridgeHealth.recordSuccess();
|
|
51450
52293
|
} catch (error51) {
|
|
51451
52294
|
process.stderr.write(
|
|
51452
|
-
`[mrrlin-mcp director-bridge] ${label} failed: ${
|
|
52295
|
+
`[mrrlin-mcp director-bridge] ${label} failed: ${describeError(error51)}
|
|
51453
52296
|
`
|
|
51454
52297
|
);
|
|
51455
52298
|
bridgeHealth.recordFailure(id, error51);
|
|
@@ -51461,34 +52304,28 @@ async function startDirectorBridge() {
|
|
|
51461
52304
|
const scheduleClaimLoop = () => {
|
|
51462
52305
|
if (claimLoopStopped) return;
|
|
51463
52306
|
claimTimer = setTimeout(() => {
|
|
51464
|
-
|
|
51465
|
-
|
|
51466
|
-
|
|
51467
|
-
|
|
51468
|
-
(
|
|
51469
|
-
|
|
51470
|
-
|
|
51471
|
-
})
|
|
51472
|
-
)
|
|
51473
|
-
);
|
|
51474
|
-
enqueueRun(
|
|
51475
|
-
() => runTrackedSweep(
|
|
51476
|
-
"asyncSweep",
|
|
51477
|
-
"async sweep",
|
|
51478
|
-
() => runAsyncBackstopSweep(asyncConsumerDeps, (slug, jobId) => {
|
|
51479
|
-
driveAsyncTracked(slug, jobId);
|
|
51480
|
-
return Promise.resolve();
|
|
51481
|
-
})
|
|
51482
|
-
)
|
|
52307
|
+
void runTrackedSweep(
|
|
52308
|
+
"claimSweep",
|
|
52309
|
+
"claim sweep",
|
|
52310
|
+
() => runBackstopSweep(consumerDeps, (slug, runId) => {
|
|
52311
|
+
driveTracked(slug, runId);
|
|
52312
|
+
return Promise.resolve();
|
|
52313
|
+
})
|
|
51483
52314
|
);
|
|
51484
|
-
|
|
51485
|
-
|
|
51486
|
-
|
|
51487
|
-
|
|
51488
|
-
|
|
52315
|
+
void runTrackedSweep(
|
|
52316
|
+
"asyncSweep",
|
|
52317
|
+
"async sweep",
|
|
52318
|
+
() => runAsyncBackstopSweep(asyncConsumerDeps, (slug, jobId) => {
|
|
52319
|
+
driveAsyncTracked(slug, jobId);
|
|
52320
|
+
return Promise.resolve();
|
|
51489
52321
|
})
|
|
51490
52322
|
);
|
|
51491
|
-
|
|
52323
|
+
void runOrphanWorktreeSweep(client, {
|
|
52324
|
+
checkoutRegistry,
|
|
52325
|
+
worktreeRoot: import_node_path18.default.join(config2.stateDir, "worktrees"),
|
|
52326
|
+
locksDir: import_node_path18.default.join(config2.stateDir, "locks")
|
|
52327
|
+
});
|
|
52328
|
+
{
|
|
51492
52329
|
const { retainedBuffers, retainedBytes, tombstonesRemoved } = sweepReplayBuffers(threads, tombstones, {
|
|
51493
52330
|
now: Date.now(),
|
|
51494
52331
|
suspendedMs: () => suspensionDetector.suspendedMs(),
|
|
@@ -51526,7 +52363,7 @@ async function startDirectorBridge() {
|
|
|
51526
52363
|
payload: { removed: tombstonesRemoved }
|
|
51527
52364
|
});
|
|
51528
52365
|
}
|
|
51529
|
-
}
|
|
52366
|
+
}
|
|
51530
52367
|
scheduleClaimLoop();
|
|
51531
52368
|
}, claimIntervalMs());
|
|
51532
52369
|
claimTimer.unref?.();
|
|
@@ -51564,7 +52401,7 @@ async function startDirectorBridge() {
|
|
|
51564
52401
|
agentPoolLoopHandle = startAgentPoolLoop({
|
|
51565
52402
|
push: (snapshot) => client.putOperatorAgentPool(snapshot),
|
|
51566
52403
|
onError: (err) => process.stderr.write(
|
|
51567
|
-
`[mrrlin-mcp director-bridge] agent-pool snapshot push failed: ${
|
|
52404
|
+
`[mrrlin-mcp director-bridge] agent-pool snapshot push failed: ${describeError(err)}
|
|
51568
52405
|
`
|
|
51569
52406
|
)
|
|
51570
52407
|
});
|
|
@@ -56500,31 +57337,12 @@ var mcpToolNames = {
|
|
|
56500
57337
|
restartExecutionRun: "restart_execution_run",
|
|
56501
57338
|
resolveHandoff: "resolve_handoff",
|
|
56502
57339
|
recordProducedUrl: "record_produced_url",
|
|
57340
|
+
updateTaskState: "update_task_state",
|
|
56503
57341
|
registerLocalCheckout: "register_local_checkout",
|
|
56504
57342
|
/** Compact-context retrieval: rehydrate a mrrlin:// handle into the canonical full record. */
|
|
56505
57343
|
retrieveContext: "retrieve_context"
|
|
56506
57344
|
};
|
|
56507
57345
|
|
|
56508
|
-
// src/context-compact/policy.ts
|
|
56509
|
-
var DEFAULT_THRESHOLD_CHARS = 12e3;
|
|
56510
|
-
var DEFAULT_MAX_ITEMS = 25;
|
|
56511
|
-
function readPositiveInt(value, fallback) {
|
|
56512
|
-
const raw = (value ?? "").trim();
|
|
56513
|
-
if (!raw) return fallback;
|
|
56514
|
-
const parsed = Number.parseInt(raw, 10);
|
|
56515
|
-
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
56516
|
-
}
|
|
56517
|
-
function readCompactPolicy(env = process.env) {
|
|
56518
|
-
const disabled = (env.MRRLIN_MCP_COMPACT_DISABLE ?? "").trim() === "1";
|
|
56519
|
-
return {
|
|
56520
|
-
enabled: !disabled,
|
|
56521
|
-
thresholdChars: readPositiveInt(env.MRRLIN_MCP_COMPACT_THRESHOLD_CHARS, DEFAULT_THRESHOLD_CHARS),
|
|
56522
|
-
maxItems: readPositiveInt(env.MRRLIN_MCP_COMPACT_MAX_ITEMS, DEFAULT_MAX_ITEMS),
|
|
56523
|
-
debug: (env.MRRLIN_MCP_COMPACT_DEBUG ?? "").trim() === "1",
|
|
56524
|
-
retrievalBudgetDisable: (env.MRRLIN_RETRIEVAL_BUDGET_DISABLE ?? "").trim() === "1"
|
|
56525
|
-
};
|
|
56526
|
-
}
|
|
56527
|
-
|
|
56528
57346
|
// src/context-compact/handles.ts
|
|
56529
57347
|
var MRRLIN_HANDLE_SCHEME = "mrrlin://";
|
|
56530
57348
|
var SLUG_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/;
|
|
@@ -56599,7 +57417,7 @@ function parseMrrlinHandle(value) {
|
|
|
56599
57417
|
var NOTES_EXCERPT_CHARS = 200;
|
|
56600
57418
|
var TITLE_TRUNCATE_CHARS = 160;
|
|
56601
57419
|
var EXCERPT_TRUNCATE_CHARS = 240;
|
|
56602
|
-
function
|
|
57420
|
+
function truncate2(value, maxChars) {
|
|
56603
57421
|
if (value.length <= maxChars) return value;
|
|
56604
57422
|
return `${value.slice(0, Math.max(0, maxChars - 1))}\u2026`;
|
|
56605
57423
|
}
|
|
@@ -56615,7 +57433,7 @@ function compactTaskList(projectSlug, tasks, maxItems) {
|
|
|
56615
57433
|
const slice = tasks.slice(0, included);
|
|
56616
57434
|
const items = slice.map((t) => ({
|
|
56617
57435
|
id: t.id,
|
|
56618
|
-
title:
|
|
57436
|
+
title: truncate2(t.title, TITLE_TRUNCATE_CHARS),
|
|
56619
57437
|
status: t.status,
|
|
56620
57438
|
type: t.type,
|
|
56621
57439
|
category: t.category,
|
|
@@ -56626,8 +57444,8 @@ function compactTaskList(projectSlug, tasks, maxItems) {
|
|
|
56626
57444
|
assignee: t.assignee,
|
|
56627
57445
|
planId: t.planId,
|
|
56628
57446
|
specWikiPageId: t.specWikiPageId,
|
|
56629
|
-
notesExcerpt: t.notes ?
|
|
56630
|
-
latestJudgementExcerpt: t.latestJudgement ?
|
|
57447
|
+
notesExcerpt: t.notes ? truncate2(t.notes, NOTES_EXCERPT_CHARS) : null,
|
|
57448
|
+
latestJudgementExcerpt: t.latestJudgement ? truncate2(t.latestJudgement, NOTES_EXCERPT_CHARS) : null,
|
|
56631
57449
|
handle: formatTaskHandle(projectSlug, t.id)
|
|
56632
57450
|
}));
|
|
56633
57451
|
const handles = slice.map((t) => ({
|
|
@@ -56648,7 +57466,7 @@ function compactWikiPageList(projectSlug, pages, maxItems) {
|
|
|
56648
57466
|
const slice = pages.slice(0, included);
|
|
56649
57467
|
const items = slice.map((p) => ({
|
|
56650
57468
|
id: p.id,
|
|
56651
|
-
title:
|
|
57469
|
+
title: truncate2(p.title, TITLE_TRUNCATE_CHARS),
|
|
56652
57470
|
folder: p.folder,
|
|
56653
57471
|
path: p.path,
|
|
56654
57472
|
updatedAt: p.updatedAt,
|
|
@@ -56675,7 +57493,7 @@ function compactWikiSearch(projectSlug, results, maxItems) {
|
|
|
56675
57493
|
const slice = results.slice(0, included);
|
|
56676
57494
|
const items = slice.map((r) => ({
|
|
56677
57495
|
pageId: r.id,
|
|
56678
|
-
title:
|
|
57496
|
+
title: truncate2(r.title, TITLE_TRUNCATE_CHARS),
|
|
56679
57497
|
folder: r.folder,
|
|
56680
57498
|
path: r.path,
|
|
56681
57499
|
rank: r.rank,
|
|
@@ -56683,7 +57501,7 @@ function compactWikiSearch(projectSlug, results, maxItems) {
|
|
|
56683
57501
|
ageDays: r.ageDays,
|
|
56684
57502
|
memoryClass: r.memoryClass,
|
|
56685
57503
|
precedence: r.precedence,
|
|
56686
|
-
snippet:
|
|
57504
|
+
snippet: truncate2(r.snippet, EXCERPT_TRUNCATE_CHARS),
|
|
56687
57505
|
handle: formatWikiHandle(projectSlug, r.id)
|
|
56688
57506
|
}));
|
|
56689
57507
|
const handles = slice.map((r) => ({
|
|
@@ -56712,7 +57530,7 @@ function compactProjectSnapshot(projectSlug, snapshot, maxItems) {
|
|
|
56712
57530
|
}
|
|
56713
57531
|
const compactPlans = snapshot.plans.map((p) => ({
|
|
56714
57532
|
id: p.id,
|
|
56715
|
-
name:
|
|
57533
|
+
name: truncate2(p.name, TITLE_TRUNCATE_CHARS),
|
|
56716
57534
|
status: p.status,
|
|
56717
57535
|
taskCount: p.taskCount,
|
|
56718
57536
|
closedTaskCount: p.closedTaskCount,
|
|
@@ -56784,7 +57602,7 @@ function compactArtifactPayload(artifact) {
|
|
|
56784
57602
|
cwd,
|
|
56785
57603
|
exitCode,
|
|
56786
57604
|
firstError,
|
|
56787
|
-
tail:
|
|
57605
|
+
tail: truncate2(tail2, ARTIFACT_PAYLOAD_BUDGET),
|
|
56788
57606
|
totalLines: lines2.length
|
|
56789
57607
|
};
|
|
56790
57608
|
}
|
|
@@ -56792,7 +57610,7 @@ function compactArtifactPayload(artifact) {
|
|
|
56792
57610
|
return {
|
|
56793
57611
|
status: payload.status ?? null,
|
|
56794
57612
|
command: payload.command ?? null,
|
|
56795
|
-
summary: typeof payload.summary === "string" ?
|
|
57613
|
+
summary: typeof payload.summary === "string" ? truncate2(payload.summary, ARTIFACT_PAYLOAD_BUDGET) : null,
|
|
56796
57614
|
failed: Array.isArray(payload.failedTests) ? payload.failedTests.slice(0, 25) : null
|
|
56797
57615
|
};
|
|
56798
57616
|
}
|
|
@@ -56810,7 +57628,7 @@ function compactArtifactPayload(artifact) {
|
|
|
56810
57628
|
case "checkpoint":
|
|
56811
57629
|
default: {
|
|
56812
57630
|
const flattened = JSON.stringify(payload);
|
|
56813
|
-
return { excerpt:
|
|
57631
|
+
return { excerpt: truncate2(flattened, ARTIFACT_PAYLOAD_BUDGET) };
|
|
56814
57632
|
}
|
|
56815
57633
|
}
|
|
56816
57634
|
}
|
|
@@ -56849,7 +57667,7 @@ function compactTaskEvents(projectSlug, taskId, events, maxItems) {
|
|
|
56849
57667
|
createdAt: e.createdAt,
|
|
56850
57668
|
autonomyLevel: e.autonomyLevel,
|
|
56851
57669
|
autonomyReason: e.autonomyReason,
|
|
56852
|
-
bodyExcerpt: e.body ?
|
|
57670
|
+
bodyExcerpt: e.body ? truncate2(e.body, NOTES_EXCERPT_CHARS) : null
|
|
56853
57671
|
}));
|
|
56854
57672
|
const handles = [
|
|
56855
57673
|
{
|
|
@@ -56871,7 +57689,7 @@ function compactGeneric(value, maxItems, projectSlug) {
|
|
|
56871
57689
|
const included = Math.min(total, maxItems);
|
|
56872
57690
|
const slice = value.slice(0, included).map((entry) => {
|
|
56873
57691
|
const text2 = typeof entry === "string" ? entry : JSON.stringify(entry);
|
|
56874
|
-
return
|
|
57692
|
+
return truncate2(text2, ARTIFACT_PAYLOAD_BUDGET);
|
|
56875
57693
|
});
|
|
56876
57694
|
return {
|
|
56877
57695
|
summary: `Compact array view: ${total} entries, ${included} included.`,
|
|
@@ -56902,7 +57720,7 @@ function compactGeneric(value, maxItems, projectSlug) {
|
|
|
56902
57720
|
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
56903
57721
|
return {
|
|
56904
57722
|
summary: "Compact scalar view.",
|
|
56905
|
-
items: [
|
|
57723
|
+
items: [truncate2(text, ARTIFACT_PAYLOAD_BUDGET)],
|
|
56906
57724
|
handles: [],
|
|
56907
57725
|
counts: { total: 1, included: 1, omitted: 0 }
|
|
56908
57726
|
};
|
|
@@ -57072,6 +57890,7 @@ var updateExecutionRunInputSchema = runScopedSchema.merge(mrrlinExecutionRunUpda
|
|
|
57072
57890
|
var listExecutionArtifactsInputSchema = runScopedSchema;
|
|
57073
57891
|
var appendExecutionArtifactInputSchema = runScopedSchema.merge(mrrlinExecutionArtifactCreateSchema);
|
|
57074
57892
|
var recordProducedUrlInputSchema = runScopedSchema.merge(mrrlinProducedUrlPayloadSchema);
|
|
57893
|
+
var updateTaskStateInputSchema = runScopedSchema.merge(mrrlinTaskStateReportSchema);
|
|
57075
57894
|
var getProjectSchedulerPolicyInputSchema = projectScopedSchema;
|
|
57076
57895
|
var upsertProjectSchedulerPolicyInputSchema = projectScopedSchema.merge(mrrlinProjectSchedulerPolicyUpsertSchema);
|
|
57077
57896
|
var recordDeployWorkflowInputSchema = projectScopedSchema.extend({
|
|
@@ -57184,6 +58003,7 @@ var mcpToolInputSchemas = {
|
|
|
57184
58003
|
[mcpToolNames.restartExecutionRun]: restartExecutionRunInputSchema,
|
|
57185
58004
|
[mcpToolNames.resolveHandoff]: resolveHandoffInputSchema,
|
|
57186
58005
|
[mcpToolNames.recordProducedUrl]: recordProducedUrlInputSchema,
|
|
58006
|
+
[mcpToolNames.updateTaskState]: updateTaskStateInputSchema,
|
|
57187
58007
|
[mcpToolNames.registerLocalCheckout]: registerLocalCheckoutInputSchema,
|
|
57188
58008
|
[mcpToolNames.retrieveContext]: retrieveContextInputSchema
|
|
57189
58009
|
};
|
|
@@ -57235,6 +58055,7 @@ var mcpToolOperationIds = {
|
|
|
57235
58055
|
[mcpToolNames.recordDeployWorkflow]: openApiOperationIds.upsertProjectDeployWorkflow,
|
|
57236
58056
|
[mcpToolNames.updatePlan]: openApiOperationIds.updatePlan,
|
|
57237
58057
|
[mcpToolNames.updateTask]: openApiOperationIds.updateTask,
|
|
58058
|
+
[mcpToolNames.updateTaskState]: openApiOperationIds.reportTaskState,
|
|
57238
58059
|
[mcpToolNames.resetDirectorThread]: openApiOperationIds.resetDirectorThread,
|
|
57239
58060
|
[mcpToolNames.archiveTask]: openApiOperationIds.archiveTask,
|
|
57240
58061
|
[mcpToolNames.unarchiveTask]: openApiOperationIds.unarchiveTask,
|
|
@@ -57295,6 +58116,7 @@ var mcpToolDescriptions = {
|
|
|
57295
58116
|
[mcpToolNames.runCodeReviewerGate]: `Review the current branch's code diff (vs baseRef) with a Code Reviewer gate \u2014 independent reviewers iterate review\u2192fix\u2192re-check (checkpoint, scope-limited reviser edits, typecheck/build fast-gate, rollback) until the diff converges or is blocked. Run before opening a PR. Pass extraHeads: ["security-analyst"] for sensitive diffs (auth, secrets, input handling, new endpoints).`,
|
|
57296
58117
|
[mcpToolNames.appendExecutionArtifact]: "Append a durable artifact (plan, checkpoint, command output, test result, diff summary, self-review, error, deploy attempt, or handoff judgement) to an execution run.",
|
|
57297
58118
|
[mcpToolNames.recordProducedUrl]: 'Call this after publishing each web page produced by the task, so the UI link opens the page itself instead of the deployed site root. Pass the page\'s full https URL (for external pages, e.g. "https://dev.to/<slug>") OR a path starting with "/" for the deploy environment (e.g. "/blog/<slug>") \u2014 paths are resolved against the run\'s deployed env URL at render time. Optional `label` (\u226440 chars) is shown next to the link; omit and the UI defaults to the page title. Call once per page; multiple calls dedupe by resolved URL in the UI.',
|
|
58119
|
+
[mcpToolNames.updateTaskState]: "Record where this task actually stands, in your own words, BEFORE you end your turn. This is the handoff the next run reads: it survives even when this conversation does not, because a thread is retired once it has accumulated too many runs and the next run then starts from this record plus the repository. Report what only you know \u2014 the goal as you now understand it, decisions you made AND WHY (a decision without its reason is the thing most often lost), problems still open, and the next concrete actions. Omit any field you learned nothing new about; an omitted field keeps its previous value rather than being cleared. Use one entry per line for decisions/next actions. Do not restate the spec or the file list \u2014 the next run gets those anyway.",
|
|
57298
58120
|
[mcpToolNames.createExecutionRun]: 'Create a durable Director execution run for a task. Persists status, branch/SHA, workflow ids, and checkpoint cursor outside the chat transcript. For tasks that require a browser (login flows, UI verification, scraping), set prerequisites:[{mcp:"mrrlin-browser",reason:"<why a browser is needed>"}] so any resulting handoff offers a one-click "Launch browser & resume". When actually driving the browser inside the run, invoke tools from the `mrrlin-browser` MCP server ONLY (browser_navigate/browser_click/browser_snapshot/browser_type/etc.) \u2014 never from `playwright`, `chrome-devtools`, `puppeteer`, or any other browser MCP that may also be connected on the operator\'s box. Only `mrrlin-browser` uses the dedicated Chromium + persistent operator profile.',
|
|
57299
58121
|
[mcpToolNames.getExecutionRun]: "Fetch a single execution run by id.",
|
|
57300
58122
|
[mcpToolNames.listExecutionArtifacts]: "List artifacts captured during an execution run, in chronological order.",
|
|
@@ -57892,6 +58714,13 @@ function createMrrlinTools(options) {
|
|
|
57892
58714
|
"Unable to append execution artifact.",
|
|
57893
58715
|
async (c, { projectSlug, runId, ...input }) => await c.appendExecutionArtifact(projectSlug, runId, input)
|
|
57894
58716
|
),
|
|
58717
|
+
[mcpToolNames.updateTaskState]: makeTool(
|
|
58718
|
+
client,
|
|
58719
|
+
mcpToolNames.updateTaskState,
|
|
58720
|
+
"TASK_STATE_REPORT_FAILED",
|
|
58721
|
+
"Unable to record task state.",
|
|
58722
|
+
async (c, { projectSlug, runId, ...report }) => await c.reportTaskState(projectSlug, runId, report)
|
|
58723
|
+
),
|
|
57895
58724
|
[mcpToolNames.recordProducedUrl]: makeTool(
|
|
57896
58725
|
client,
|
|
57897
58726
|
mcpToolNames.recordProducedUrl,
|
|
@@ -58553,11 +59382,13 @@ Usage:
|
|
|
58553
59382
|
- MRRLIN_WORKER_PORT (dispatch listener, default 8792)
|
|
58554
59383
|
- MRRLIN_DIRECTOR_BRIDGE_CLAIM_INTERVAL_SECONDS (default 30)
|
|
58555
59384
|
- MRRLIN_DIRECTOR_BRIDGE_STALE_SECONDS (default 300)
|
|
58556
|
-
- MRRLIN_DIRECTOR_BRIDGE_CHAT_TURN_IDLE_SECONDS (default
|
|
59385
|
+
- MRRLIN_DIRECTOR_BRIDGE_CHAT_TURN_IDLE_SECONDS (default 300;
|
|
58557
59386
|
a chat turn is cut only after this long with NO codex
|
|
58558
|
-
signal at all \u2014 long-but-active
|
|
58559
|
-
|
|
58560
|
-
|
|
59387
|
+
signal at all AND no tool call in flight \u2014 long-but-active
|
|
59388
|
+
turns, and long single tool calls, keep running)
|
|
59389
|
+
- MRRLIN_DIRECTOR_BRIDGE_CHAT_TURN_MAX_SECONDS (default 2700;
|
|
59390
|
+
absolute ceiling for one chat turn regardless of activity;
|
|
59391
|
+
the only guard against a genuinely hung tool call)
|
|
58561
59392
|
- MRRLIN_DIRECTOR_BRIDGE_CODEX_IDLE_SECONDS (default 300;
|
|
58562
59393
|
how long the warm codex app-server is kept alive
|
|
58563
59394
|
between turns before it is released)
|