@wrongstack/core 0.87.0 → 0.89.3
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/{agent-bridge-C9P_HPez.d.ts → agent-bridge-DbVe1dHT.d.ts} +1 -1
- package/dist/{agent-subagent-runner-2Aq0jOSj.d.ts → agent-subagent-runner-C6eqID1t.d.ts} +477 -476
- package/dist/{events-DnRqXaZ3.d.ts → brain-s9DyD_Vf.d.ts} +185 -92
- package/dist/{compactor-CJq7LQev.d.ts → compactor-DXLxLcmU.d.ts} +2 -2
- package/dist/{config-_DZ7dN-T.d.ts → config-84VaZpH6.d.ts} +45 -38
- package/dist/{context-ToHAp4-U.d.ts → context-CNRYfhUv.d.ts} +1 -1
- package/dist/coordination/index.d.ts +16 -17
- package/dist/coordination/index.js +208 -93
- package/dist/coordination/index.js.map +1 -1
- package/dist/{default-config-DEXI4jsl.d.ts → default-config-CXsDvOmP.d.ts} +3 -1
- package/dist/defaults/index.d.ts +32 -34
- package/dist/defaults/index.js +744 -274
- package/dist/defaults/index.js.map +1 -1
- package/dist/{director-state-CgIc30qi.d.ts → director-state-BfeCUbmk.d.ts} +1 -1
- package/dist/execution/index.d.ts +18 -19
- package/dist/execution/index.js +79 -64
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +9 -10
- package/dist/extension/index.js +8 -6
- package/dist/extension/index.js.map +1 -1
- package/dist/{index-BNOLadHw.d.ts → index-CqrroYcU.d.ts} +13 -15
- package/dist/{index-N0_c4bHQ.d.ts → index-D3Nax3YU.d.ts} +11 -10
- package/dist/index.d.ts +191 -178
- package/dist/index.js +1419 -526
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +9 -9
- package/dist/infrastructure/index.js +16 -5
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +14 -16
- package/dist/kernel/index.js +17 -0
- package/dist/kernel/index.js.map +1 -1
- package/dist/{logger-B72yyPc6.d.ts → logger-B63L5bTg.d.ts} +1 -1
- package/dist/{logger-C_27pj9i.d.ts → logger-B9J5puGM.d.ts} +1 -1
- package/dist/{mcp-servers-Dck3T85_.d.ts → mcp-servers-D3E5ixAR.d.ts} +3 -3
- package/dist/{mode-CHo2XtHs.d.ts → mode-ARA3HrkY.d.ts} +1 -1
- package/dist/models/index.d.ts +5 -5
- package/dist/models/index.js +8 -6
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-Be3osGt5.d.ts → models-registry-B6_KfS65.d.ts} +1 -1
- package/dist/{models-registry-Boz639EI.d.ts → models-registry-DU64QxQa.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-DllpCVkF.d.ts → multi-agent-coordinator-DHNrjPaA.d.ts} +2 -2
- package/dist/{null-fleet-bus-BY0AN-sr.d.ts → null-fleet-bus-BzzciAc4.d.ts} +39 -32
- package/dist/observability/index.d.ts +3 -3
- package/dist/{observability-CoSNZdhX.d.ts → observability-D-HZN_mF.d.ts} +1 -1
- package/dist/{parallel-eternal-engine-D402RASp.d.ts → parallel-eternal-engine-CTpcrb9O.d.ts} +34 -33
- package/dist/{path-resolver-UPFTsDyD.d.ts → path-resolver-B7hgMAVe.d.ts} +3 -3
- package/dist/{permission-14CChMmO.d.ts → permission-BDv7z0mk.d.ts} +7 -2
- package/dist/{permission-policy-gW5htOo1.d.ts → permission-policy-dF74EpDp.d.ts} +2 -2
- package/dist/{system-prompt-C0rLCeyn.d.ts → pipeline-C1Ad9OjI.d.ts} +73 -73
- package/dist/{plan-templates-DRvPgkfZ.d.ts → plan-templates-CNphsz0n.d.ts} +79 -11
- package/dist/{provider-runner-COAJM8tC.d.ts → provider-runner-cqvlB_oS.d.ts} +5 -5
- package/dist/{retry-policy-DSu6O6rD.d.ts → retry-policy-BcmuT_V0.d.ts} +2 -2
- package/dist/sdd/index.d.ts +12 -33
- package/dist/sdd/index.js +110 -50
- package/dist/sdd/index.js.map +1 -1
- package/dist/{secret-scrubber-yGBFQYju.d.ts → secret-vault-DrOhc2i5.d.ts} +7 -7
- package/dist/security/index.d.ts +4 -5
- package/dist/security/index.js +22 -4
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-11-fm95U.d.ts → selector-C7wcdqMA.d.ts} +1 -1
- package/dist/{session-event-bridge-D0u-x576.d.ts → session-event-bridge-IVzs2GpE.d.ts} +1 -1
- package/dist/{session-reader-BQU-toaN.d.ts → session-reader-DDz1Ek4V.d.ts} +2 -2
- package/dist/{skill-BJeF2DwY.d.ts → skill-BJxzIyyN.d.ts} +1 -1
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.js +3 -9
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +134 -14
- package/dist/storage/index.js +982 -248
- package/dist/storage/index.js.map +1 -1
- package/dist/{task-graph-CikNdRTG.d.ts → task-graph-DJBqO0EY.d.ts} +1 -1
- package/dist/types/index.d.ts +26 -28
- package/dist/types/index.js +62 -37
- package/dist/types/index.js.map +1 -1
- package/dist/utils/expect-defined.d.ts +7 -0
- package/dist/utils/expect-defined.js +11 -0
- package/dist/utils/expect-defined.js.map +1 -0
- package/dist/utils/index.d.ts +11 -20
- package/dist/utils/index.js +61 -43
- package/dist/utils/index.js.map +1 -1
- package/dist/{wstack-paths-BQMvEllz.d.ts → wstack-paths-_lqjzErq.d.ts} +1 -1
- package/package.json +5 -1
- package/dist/memory-CEXuo7sz.d.ts +0 -16
- package/dist/secret-scrubber-3MHDDAtm.d.ts +0 -6
|
@@ -2,15 +2,9 @@ import { randomUUID, randomBytes } from 'crypto';
|
|
|
2
2
|
import * as fsp6 from 'fs/promises';
|
|
3
3
|
import * as path4 from 'path';
|
|
4
4
|
import { isAbsolute, resolve } from 'path';
|
|
5
|
+
import { hostname } from 'os';
|
|
5
6
|
import { EventEmitter } from 'events';
|
|
6
7
|
|
|
7
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
-
}) : x)(function(x) {
|
|
10
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
8
|
// src/coordination/brain.ts
|
|
15
9
|
var ObservableBrainArbiter = class {
|
|
16
10
|
constructor(inner, events) {
|
|
@@ -172,8 +166,8 @@ async function atomicWrite(targetPath, content, opts = {}) {
|
|
|
172
166
|
}
|
|
173
167
|
let mode;
|
|
174
168
|
try {
|
|
175
|
-
const
|
|
176
|
-
mode =
|
|
169
|
+
const stat5 = await fsp6.stat(targetPath);
|
|
170
|
+
mode = stat5.mode & 511;
|
|
177
171
|
} catch {
|
|
178
172
|
mode = opts.mode;
|
|
179
173
|
}
|
|
@@ -236,7 +230,7 @@ async function acquireDirectorStateLock(lockPath, processId = process.pid) {
|
|
|
236
230
|
}
|
|
237
231
|
const lock = {
|
|
238
232
|
pid: processId,
|
|
239
|
-
hostname:
|
|
233
|
+
hostname: hostname(),
|
|
240
234
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
241
235
|
};
|
|
242
236
|
await atomicWrite(lockPath, JSON.stringify(lock), { mode: 384 });
|
|
@@ -381,6 +375,21 @@ var DirectorStateCheckpoint = class {
|
|
|
381
375
|
}
|
|
382
376
|
};
|
|
383
377
|
|
|
378
|
+
// src/utils/safe-json.ts
|
|
379
|
+
function safeParse(input, maxBytes = 5e6) {
|
|
380
|
+
if (input.length > maxBytes) {
|
|
381
|
+
return { ok: false, error: `Input exceeds limit (${maxBytes} bytes)` };
|
|
382
|
+
}
|
|
383
|
+
try {
|
|
384
|
+
return { ok: true, value: JSON.parse(input) };
|
|
385
|
+
} catch (err) {
|
|
386
|
+
return {
|
|
387
|
+
ok: false,
|
|
388
|
+
error: err instanceof Error ? err.message : String(err)
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
384
393
|
// src/coordination/in-memory-transport.ts
|
|
385
394
|
var InMemoryBridgeTransport = class {
|
|
386
395
|
subs = /* @__PURE__ */ new Map();
|
|
@@ -528,7 +537,9 @@ function createMessage(type, from, payload, to) {
|
|
|
528
537
|
priority: "normal"
|
|
529
538
|
};
|
|
530
539
|
}
|
|
531
|
-
|
|
540
|
+
|
|
541
|
+
// src/utils/expect-defined.ts
|
|
542
|
+
function expectDefined(value, label) {
|
|
532
543
|
if (value === null || value === void 0) {
|
|
533
544
|
throw new Error("Expected value to be defined");
|
|
534
545
|
}
|
|
@@ -621,8 +632,8 @@ async function expandGlob(pattern) {
|
|
|
621
632
|
for (const e of entries) {
|
|
622
633
|
const full = `${dir}${SEP}${e}`;
|
|
623
634
|
try {
|
|
624
|
-
const
|
|
625
|
-
if (
|
|
635
|
+
const stat5 = await fsp6.stat(full);
|
|
636
|
+
if (stat5.isDirectory()) await walk(full, rest);
|
|
626
637
|
} catch {
|
|
627
638
|
}
|
|
628
639
|
}
|
|
@@ -639,8 +650,8 @@ async function expandGlob(pattern) {
|
|
|
639
650
|
if (entries.includes(seg)) {
|
|
640
651
|
const full = `${dir}${SEP}${seg}`;
|
|
641
652
|
try {
|
|
642
|
-
const
|
|
643
|
-
if (
|
|
653
|
+
const stat5 = await fsp6.stat(full);
|
|
654
|
+
if (stat5.isDirectory()) await walk(full, rest);
|
|
644
655
|
} catch {
|
|
645
656
|
}
|
|
646
657
|
}
|
|
@@ -673,7 +684,9 @@ var CollabSession = class extends EventEmitter {
|
|
|
673
684
|
settled = false;
|
|
674
685
|
timeoutMs;
|
|
675
686
|
cancelled = false;
|
|
687
|
+
_raceResolved = false;
|
|
676
688
|
alerts = [];
|
|
689
|
+
snapshotWarnings = [];
|
|
677
690
|
/** Tracks tool call counts per subagent for progress-based timeout decisions. */
|
|
678
691
|
progressBySubagent = /* @__PURE__ */ new Map();
|
|
679
692
|
/** Last tool call count when a timeout warning was handled. */
|
|
@@ -743,10 +756,19 @@ var CollabSession = class extends EventEmitter {
|
|
|
743
756
|
}
|
|
744
757
|
for (const filePath of allFiles) {
|
|
745
758
|
try {
|
|
746
|
-
const content = await
|
|
759
|
+
const [content, stat5] = await Promise.all([
|
|
760
|
+
fsp6.readFile(filePath, "utf8"),
|
|
761
|
+
fsp6.stat(filePath)
|
|
762
|
+
]);
|
|
747
763
|
const ext = filePath.split(".").pop() ?? "";
|
|
748
764
|
const language = ext === "ts" || ext === "tsx" ? "typescript" : ext === "js" || ext === "jsx" ? "javascript" : ext === "md" ? "markdown" : ext === "json" ? "json" : void 0;
|
|
749
|
-
this.snapshot.files.push({
|
|
765
|
+
this.snapshot.files.push({
|
|
766
|
+
path: filePath,
|
|
767
|
+
content,
|
|
768
|
+
language,
|
|
769
|
+
snapshotMtimeMs: stat5.mtimeMs,
|
|
770
|
+
snapshotSizeBytes: stat5.size
|
|
771
|
+
});
|
|
750
772
|
} catch {
|
|
751
773
|
this.snapshot.files.push({ path: filePath, content: "", language: void 0 });
|
|
752
774
|
}
|
|
@@ -759,7 +781,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
759
781
|
* Safe to call multiple times (idempotent after first call).
|
|
760
782
|
*/
|
|
761
783
|
cancel(reason = "Director cancelled collab session") {
|
|
762
|
-
if (this.
|
|
784
|
+
if (this.cancelled) return;
|
|
763
785
|
this.cancelled = true;
|
|
764
786
|
if (this._timeoutTimer) {
|
|
765
787
|
clearTimeout(this._timeoutTimer);
|
|
@@ -769,7 +791,11 @@ var CollabSession = class extends EventEmitter {
|
|
|
769
791
|
subagentId: this.director.id,
|
|
770
792
|
ts: Date.now(),
|
|
771
793
|
type: "director.cancel_collab",
|
|
772
|
-
payload: {
|
|
794
|
+
payload: {
|
|
795
|
+
sessionId: this.sessionId,
|
|
796
|
+
reason,
|
|
797
|
+
cancelledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
798
|
+
}
|
|
773
799
|
});
|
|
774
800
|
this.fleetBus.emit({
|
|
775
801
|
subagentId: this.director.id,
|
|
@@ -793,6 +819,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
793
819
|
this.subagentIds.set("critic", criticId);
|
|
794
820
|
const timeout = new Promise((_, reject) => {
|
|
795
821
|
this._timeoutTimer = setTimeout(() => {
|
|
822
|
+
if (this._raceResolved) return;
|
|
796
823
|
this.cancel("Session-level timeout reached");
|
|
797
824
|
reject(new Error(`CollabSession timed out after ${this.timeoutMs}ms`));
|
|
798
825
|
}, this.timeoutMs);
|
|
@@ -808,6 +835,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
808
835
|
timeout
|
|
809
836
|
]);
|
|
810
837
|
} catch (err) {
|
|
838
|
+
this._raceResolved = true;
|
|
811
839
|
if (this._timeoutTimer) {
|
|
812
840
|
clearTimeout(this._timeoutTimer);
|
|
813
841
|
this._timeoutTimer = void 0;
|
|
@@ -820,7 +848,9 @@ var CollabSession = class extends EventEmitter {
|
|
|
820
848
|
for (const result of results?.flat() ?? []) {
|
|
821
849
|
await this.parseAndEmit(result);
|
|
822
850
|
}
|
|
851
|
+
this.snapshotWarnings = await this.checkSnapshotFreshness();
|
|
823
852
|
const report = this.assembleReport();
|
|
853
|
+
this._raceResolved = true;
|
|
824
854
|
this.cleanup();
|
|
825
855
|
this.emit("session.done", report);
|
|
826
856
|
return report;
|
|
@@ -883,7 +913,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
883
913
|
const defaults = {
|
|
884
914
|
"bug-hunter": { maxIterations: 2e3, maxToolCalls: 5e3, timeoutMs: 10 * 60 * 1e3 },
|
|
885
915
|
"refactor-planner": { maxIterations: 1500, maxToolCalls: 4e3, timeoutMs: 8 * 60 * 1e3 },
|
|
886
|
-
|
|
916
|
+
critic: { maxIterations: 1e3, maxToolCalls: 3e3, timeoutMs: 6 * 60 * 1e3 }
|
|
887
917
|
};
|
|
888
918
|
return defaults[role] ?? { maxIterations: 1500, maxToolCalls: 4e3, timeoutMs: 8 * 60 * 1e3 };
|
|
889
919
|
}
|
|
@@ -963,7 +993,10 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
963
993
|
}
|
|
964
994
|
wireFleetBus() {
|
|
965
995
|
const dTool = this.fleetBus.filter("tool.executed", (e) => {
|
|
966
|
-
this.progressBySubagent.set(
|
|
996
|
+
this.progressBySubagent.set(
|
|
997
|
+
e.subagentId,
|
|
998
|
+
(this.progressBySubagent.get(e.subagentId) ?? 0) + 1
|
|
999
|
+
);
|
|
967
1000
|
});
|
|
968
1001
|
this.disposers.push(dTool);
|
|
969
1002
|
const dBudget = this.fleetBus.filter("budget.threshold_reached", (e) => {
|
|
@@ -1002,7 +1035,10 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
1002
1035
|
return;
|
|
1003
1036
|
}
|
|
1004
1037
|
this.lastTimeoutProgress.set(e.subagentId, progress);
|
|
1005
|
-
const newLimit = Math.min(
|
|
1038
|
+
const newLimit = Math.min(
|
|
1039
|
+
Math.ceil((payload.timeoutMs ?? payload.limit) * 2),
|
|
1040
|
+
24 * 60 * 6e4
|
|
1041
|
+
);
|
|
1006
1042
|
setImmediate(() => {
|
|
1007
1043
|
payload.extend({ timeoutMs: newLimit });
|
|
1008
1044
|
});
|
|
@@ -1112,15 +1148,18 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
1112
1148
|
needs_revision: 1,
|
|
1113
1149
|
reject: 2
|
|
1114
1150
|
};
|
|
1115
|
-
const overallVerdict = evalList.reduce(
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1151
|
+
const overallVerdict = evalList.reduce((worst, eval_) => {
|
|
1152
|
+
const w = verdictOrder[worst];
|
|
1153
|
+
const c = verdictOrder[eval_.verdict];
|
|
1154
|
+
return c > w ? eval_.verdict : worst;
|
|
1155
|
+
}, "approve");
|
|
1156
|
+
const summary = this.buildMarkdownSummary(
|
|
1157
|
+
bugList,
|
|
1158
|
+
planList,
|
|
1159
|
+
evalList,
|
|
1160
|
+
overallVerdict,
|
|
1161
|
+
disposition
|
|
1122
1162
|
);
|
|
1123
|
-
const summary = this.buildMarkdownSummary(bugList, planList, evalList, overallVerdict, disposition);
|
|
1124
1163
|
return {
|
|
1125
1164
|
sessionId: this.sessionId,
|
|
1126
1165
|
startedAt: this.snapshot.createdAt,
|
|
@@ -1131,10 +1170,28 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
1131
1170
|
refactorPlans: planList,
|
|
1132
1171
|
evaluations: evalList,
|
|
1133
1172
|
alerts: [...this.alerts],
|
|
1173
|
+
...this.snapshotWarnings.length > 0 ? { snapshotWarnings: this.snapshotWarnings } : {},
|
|
1134
1174
|
overallVerdict,
|
|
1135
1175
|
summary
|
|
1136
1176
|
};
|
|
1137
1177
|
}
|
|
1178
|
+
async checkSnapshotFreshness() {
|
|
1179
|
+
const warnings = [];
|
|
1180
|
+
for (const file of this.snapshot.files) {
|
|
1181
|
+
if (file.snapshotMtimeMs === void 0 && file.snapshotSizeBytes === void 0) continue;
|
|
1182
|
+
try {
|
|
1183
|
+
const stat5 = await fsp6.stat(file.path);
|
|
1184
|
+
const mtimeChanged = file.snapshotMtimeMs !== void 0 && stat5.mtimeMs > file.snapshotMtimeMs + 1;
|
|
1185
|
+
const sizeChanged = file.snapshotSizeBytes !== void 0 && stat5.size !== file.snapshotSizeBytes;
|
|
1186
|
+
if (mtimeChanged || sizeChanged) {
|
|
1187
|
+
warnings.push(`${file.path} changed after the collab snapshot was captured.`);
|
|
1188
|
+
}
|
|
1189
|
+
} catch {
|
|
1190
|
+
warnings.push(`${file.path} could not be checked after the collab snapshot was captured.`);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
return warnings;
|
|
1194
|
+
}
|
|
1138
1195
|
buildMarkdownSummary(bugs, plans, evals, overallVerdict, disposition) {
|
|
1139
1196
|
const lines = [
|
|
1140
1197
|
`## Collaborative Debugging Report \u2014 ${this.sessionId}`,
|
|
@@ -1151,10 +1208,19 @@ Emit each evaluation immediately. Do not wait until you have read all reports.`;
|
|
|
1151
1208
|
}
|
|
1152
1209
|
lines.push("");
|
|
1153
1210
|
}
|
|
1211
|
+
if (this.snapshotWarnings.length > 0) {
|
|
1212
|
+
lines.push("### Snapshot Warnings", "");
|
|
1213
|
+
for (const warning of this.snapshotWarnings) {
|
|
1214
|
+
lines.push(`- ${warning}`);
|
|
1215
|
+
}
|
|
1216
|
+
lines.push("");
|
|
1217
|
+
}
|
|
1154
1218
|
if (bugs.length > 0) {
|
|
1155
1219
|
lines.push("### Bugs Found", "");
|
|
1156
1220
|
for (const b of bugs) {
|
|
1157
|
-
lines.push(
|
|
1221
|
+
lines.push(
|
|
1222
|
+
`- **[${b.severity.toUpperCase()}]** \`${b.location.file}:${b.location.line}\` \u2014 ${b.description}`
|
|
1223
|
+
);
|
|
1158
1224
|
}
|
|
1159
1225
|
lines.push("");
|
|
1160
1226
|
}
|
|
@@ -3579,16 +3645,17 @@ Do not add prose, markdown, or code fences.`;
|
|
|
3579
3645
|
const raw = (await complete(prompt)).trim();
|
|
3580
3646
|
const match = raw.match(/\{[\s\S]*\}/);
|
|
3581
3647
|
if (!match) return null;
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3648
|
+
const parsed = safeParse(
|
|
3649
|
+
match[0]
|
|
3650
|
+
);
|
|
3651
|
+
if (!parsed.ok || !parsed.value || typeof parsed.value.role !== "string") return null;
|
|
3652
|
+
const role = parsed.value.role.trim();
|
|
3653
|
+
const valid = candidates.some((c) => c.role === role);
|
|
3654
|
+
if (!valid) return null;
|
|
3655
|
+
return {
|
|
3656
|
+
role,
|
|
3657
|
+
reason: typeof parsed.value.reason === "string" ? parsed.value.reason : void 0
|
|
3658
|
+
};
|
|
3592
3659
|
};
|
|
3593
3660
|
}
|
|
3594
3661
|
|
|
@@ -4061,6 +4128,7 @@ var FleetBus = class {
|
|
|
4061
4128
|
set.add(handler);
|
|
4062
4129
|
return () => {
|
|
4063
4130
|
set.delete(handler);
|
|
4131
|
+
if (set.size === 0) this.byId.delete(subagentId);
|
|
4064
4132
|
};
|
|
4065
4133
|
}
|
|
4066
4134
|
/** Subscribe to one event type across all subagents. */
|
|
@@ -4073,6 +4141,7 @@ var FleetBus = class {
|
|
|
4073
4141
|
set.add(handler);
|
|
4074
4142
|
return () => {
|
|
4075
4143
|
set.delete(handler);
|
|
4144
|
+
if (set.size === 0) this.byType.delete(type);
|
|
4076
4145
|
};
|
|
4077
4146
|
}
|
|
4078
4147
|
/** Subscribe to literally everything. The fleet roll-up uses this. */
|
|
@@ -4106,6 +4175,11 @@ var FleetBus = class {
|
|
|
4106
4175
|
}
|
|
4107
4176
|
}
|
|
4108
4177
|
}
|
|
4178
|
+
clear() {
|
|
4179
|
+
this.byId.clear();
|
|
4180
|
+
this.byType.clear();
|
|
4181
|
+
this.any.clear();
|
|
4182
|
+
}
|
|
4109
4183
|
};
|
|
4110
4184
|
var FleetUsageAggregator = class {
|
|
4111
4185
|
constructor(bus, priceLookup, metaLookup) {
|
|
@@ -4301,6 +4375,7 @@ function resolveModelMatrix(matrix, role) {
|
|
|
4301
4375
|
}
|
|
4302
4376
|
|
|
4303
4377
|
// src/coordination/subagent-budget.ts
|
|
4378
|
+
var TIMEOUT_PREEMPT_FRACTION = 0.85;
|
|
4304
4379
|
var BudgetExceededError = class extends Error {
|
|
4305
4380
|
kind;
|
|
4306
4381
|
limit;
|
|
@@ -5704,15 +5779,38 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
5704
5779
|
}
|
|
5705
5780
|
const start = Date.now();
|
|
5706
5781
|
let timer = null;
|
|
5782
|
+
let preemptedForLimit = null;
|
|
5707
5783
|
const timeoutPromise = new Promise((_, reject) => {
|
|
5708
5784
|
const armFor = (ms) => {
|
|
5709
5785
|
if (timer) clearTimeout(timer);
|
|
5710
5786
|
timer = setTimeout(onTick, Math.max(0, ms));
|
|
5711
5787
|
};
|
|
5712
5788
|
const scheduleNext = () => {
|
|
5713
|
-
const
|
|
5789
|
+
const wallLimit = budget.limits.timeoutMs ?? initialTimeoutMs;
|
|
5790
|
+
const wallRemaining = initialTimeoutMs === void 0 ? Number.POSITIVE_INFINITY : wallLimit - (Date.now() - start);
|
|
5714
5791
|
const idleRemaining = idleLimitMs === void 0 ? Number.POSITIVE_INFINITY : (budget.limits.idleTimeoutMs ?? idleLimitMs) - budget.idleMs();
|
|
5715
|
-
|
|
5792
|
+
const preemptRemaining = initialTimeoutMs === void 0 || preemptedForLimit === wallLimit ? Number.POSITIVE_INFINITY : wallLimit * TIMEOUT_PREEMPT_FRACTION - (Date.now() - start);
|
|
5793
|
+
armFor(Math.max(25, Math.min(wallRemaining, idleRemaining, preemptRemaining)));
|
|
5794
|
+
};
|
|
5795
|
+
const negotiateTimeout = async (used, limit) => {
|
|
5796
|
+
const handler = budget.onThreshold;
|
|
5797
|
+
if (!handler) return "stop";
|
|
5798
|
+
const result = handler({
|
|
5799
|
+
kind: "timeout",
|
|
5800
|
+
used,
|
|
5801
|
+
limit,
|
|
5802
|
+
requestDecision: () => new Promise((resolveDecision) => {
|
|
5803
|
+
budget._events?.emit("budget.threshold_reached", {
|
|
5804
|
+
kind: "timeout",
|
|
5805
|
+
used,
|
|
5806
|
+
limit,
|
|
5807
|
+
timeoutMs: 6e4,
|
|
5808
|
+
extend: (extra) => resolveDecision({ extend: extra }),
|
|
5809
|
+
deny: () => resolveDecision("stop")
|
|
5810
|
+
});
|
|
5811
|
+
})
|
|
5812
|
+
});
|
|
5813
|
+
return typeof result === "string" ? result : await result;
|
|
5716
5814
|
};
|
|
5717
5815
|
const onTick = async () => {
|
|
5718
5816
|
const elapsed = Date.now() - start;
|
|
@@ -5725,6 +5823,21 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
5725
5823
|
reject(new BudgetExceededError("timeout", idleLimit ?? 0, budget.idleMs()));
|
|
5726
5824
|
return;
|
|
5727
5825
|
}
|
|
5826
|
+
if (wallLimit !== void 0 && !wallExceeded && budget.onThreshold && preemptedForLimit !== wallLimit && elapsed >= wallLimit * TIMEOUT_PREEMPT_FRACTION) {
|
|
5827
|
+
try {
|
|
5828
|
+
const decision = await negotiateTimeout(elapsed, wallLimit);
|
|
5829
|
+
if (typeof decision !== "string" && decision.extend.timeoutMs !== void 0) {
|
|
5830
|
+
budget.limits.timeoutMs = decision.extend.timeoutMs;
|
|
5831
|
+
preemptedForLimit = null;
|
|
5832
|
+
} else {
|
|
5833
|
+
preemptedForLimit = wallLimit;
|
|
5834
|
+
}
|
|
5835
|
+
} catch {
|
|
5836
|
+
preemptedForLimit = wallLimit;
|
|
5837
|
+
}
|
|
5838
|
+
scheduleNext();
|
|
5839
|
+
return;
|
|
5840
|
+
}
|
|
5728
5841
|
if (!wallExceeded) {
|
|
5729
5842
|
scheduleNext();
|
|
5730
5843
|
return;
|
|
@@ -5736,28 +5849,15 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
5736
5849
|
return;
|
|
5737
5850
|
}
|
|
5738
5851
|
try {
|
|
5739
|
-
const
|
|
5740
|
-
kind: "timeout",
|
|
5741
|
-
used: elapsed,
|
|
5742
|
-
limit,
|
|
5743
|
-
requestDecision: () => new Promise((resolveDecision) => {
|
|
5744
|
-
budget._events?.emit("budget.threshold_reached", {
|
|
5745
|
-
kind: "timeout",
|
|
5746
|
-
used: elapsed,
|
|
5747
|
-
limit,
|
|
5748
|
-
timeoutMs: 6e4,
|
|
5749
|
-
extend: (extra) => resolveDecision({ extend: extra }),
|
|
5750
|
-
deny: () => resolveDecision("stop")
|
|
5751
|
-
});
|
|
5752
|
-
})
|
|
5753
|
-
});
|
|
5754
|
-
const decision = typeof result === "string" ? result : await result;
|
|
5852
|
+
const decision = await negotiateTimeout(elapsed, limit);
|
|
5755
5853
|
if (decision === "continue" || decision === "throw" || decision === "stop") {
|
|
5854
|
+
preemptedForLimit = null;
|
|
5756
5855
|
armFor(Math.max(1e3, limit));
|
|
5757
5856
|
return;
|
|
5758
5857
|
}
|
|
5759
5858
|
if (decision.extend.timeoutMs !== void 0) {
|
|
5760
5859
|
budget.limits.timeoutMs = decision.extend.timeoutMs;
|
|
5860
|
+
preemptedForLimit = null;
|
|
5761
5861
|
scheduleNext();
|
|
5762
5862
|
return;
|
|
5763
5863
|
}
|
|
@@ -6925,7 +7025,9 @@ var Director = class _Director {
|
|
|
6925
7025
|
let toolUses = 0;
|
|
6926
7026
|
for (const line of targetLines) {
|
|
6927
7027
|
try {
|
|
6928
|
-
const
|
|
7028
|
+
const parsed = safeParse(line);
|
|
7029
|
+
if (!parsed.ok || !parsed.value) continue;
|
|
7030
|
+
const ev = parsed.value;
|
|
6929
7031
|
if (ev.type === "assistant" && typeof ev.text === "string") {
|
|
6930
7032
|
lastAssistantText = ev.text;
|
|
6931
7033
|
} else if (ev.type === "stop" && ev.stopReason) {
|
|
@@ -7239,7 +7341,7 @@ function createDelegateTool(opts) {
|
|
|
7239
7341
|
const offIter = dir.fleet.filter("iteration.started", bump);
|
|
7240
7342
|
const offProgress = dir.fleet.filter("tool.progress", bump);
|
|
7241
7343
|
arm();
|
|
7242
|
-
dir.awaitTasks([taskId]).then((r) => finish(r[0] ?? {
|
|
7344
|
+
dir.awaitTasks([taskId]).then((r) => finish(r[0] ?? { __emptyResult: true })).catch(() => finish({ __timeout: true }));
|
|
7243
7345
|
});
|
|
7244
7346
|
if ("__timeout" in result) {
|
|
7245
7347
|
const partial2 = await readSubagentPartial(opts, subagentId);
|
|
@@ -7264,6 +7366,29 @@ function createDelegateTool(opts) {
|
|
|
7264
7366
|
partial: partial2
|
|
7265
7367
|
};
|
|
7266
7368
|
}
|
|
7369
|
+
if ("__emptyResult" in result) {
|
|
7370
|
+
const partial2 = await readSubagentPartial(opts, subagentId);
|
|
7371
|
+
opts.events?.emit("delegate.completed", {
|
|
7372
|
+
target,
|
|
7373
|
+
task: i.task,
|
|
7374
|
+
ok: false,
|
|
7375
|
+
status: "empty_result",
|
|
7376
|
+
summary: `[${target}] completed without a task result`,
|
|
7377
|
+
durationMs: 0,
|
|
7378
|
+
iterations: partial2?.events ?? 0,
|
|
7379
|
+
toolCalls: partial2?.toolUsesObserved ?? 0,
|
|
7380
|
+
subagentId
|
|
7381
|
+
});
|
|
7382
|
+
return {
|
|
7383
|
+
ok: false,
|
|
7384
|
+
stopReason: "error",
|
|
7385
|
+
error: "Director returned no task result for the delegated task.",
|
|
7386
|
+
hint: "Check fleet state with /fleet status, then retry or reassign the task.",
|
|
7387
|
+
subagentId,
|
|
7388
|
+
taskId,
|
|
7389
|
+
partial: partial2
|
|
7390
|
+
};
|
|
7391
|
+
}
|
|
7267
7392
|
const baseStopReason = result.status === "success" ? "end_turn" : result.status === "timeout" ? "subagent_timeout" : result.status === "stopped" ? "aborted" : "budget_exhausted";
|
|
7268
7393
|
const partial = result.status === "success" ? void 0 : await readSubagentPartial(opts, subagentId);
|
|
7269
7394
|
const errorKind = result.error?.kind;
|
|
@@ -7436,7 +7561,9 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
7436
7561
|
let toolUses = 0;
|
|
7437
7562
|
for (const line of lines) {
|
|
7438
7563
|
try {
|
|
7439
|
-
const
|
|
7564
|
+
const parsed = safeParse(line);
|
|
7565
|
+
if (!parsed.ok || !parsed.value) continue;
|
|
7566
|
+
const ev = parsed.value;
|
|
7440
7567
|
if (ev.type === "tool_use") toolUses += 1;
|
|
7441
7568
|
if (ev.type === "llm_response") {
|
|
7442
7569
|
if (typeof ev.stopReason === "string") lastStopReason = ev.stopReason;
|
|
@@ -7471,15 +7598,7 @@ function makeAgentSubagentRunner(opts) {
|
|
|
7471
7598
|
let budgetError = null;
|
|
7472
7599
|
const onBudgetError = (err) => {
|
|
7473
7600
|
if (err instanceof BudgetThresholdSignal) {
|
|
7474
|
-
|
|
7475
|
-
if (decision === "stop") {
|
|
7476
|
-
budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
|
|
7477
|
-
aborter.abort();
|
|
7478
|
-
}
|
|
7479
|
-
}).catch(() => {
|
|
7480
|
-
budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
|
|
7481
|
-
aborter.abort();
|
|
7482
|
-
});
|
|
7601
|
+
budgetError = err;
|
|
7483
7602
|
return;
|
|
7484
7603
|
}
|
|
7485
7604
|
aborter.abort();
|
|
@@ -7587,15 +7706,23 @@ function makeAgentSubagentRunner(opts) {
|
|
|
7587
7706
|
}
|
|
7588
7707
|
if (budgetError) {
|
|
7589
7708
|
if ("decision" in budgetError) {
|
|
7590
|
-
|
|
7591
|
-
|
|
7709
|
+
try {
|
|
7710
|
+
const decision = await budgetError.decision;
|
|
7711
|
+
if (decision === "stop") {
|
|
7712
|
+
budgetError = new BudgetExceededError(
|
|
7713
|
+
budgetError.kind,
|
|
7714
|
+
budgetError.limit,
|
|
7715
|
+
budgetError.used
|
|
7716
|
+
);
|
|
7717
|
+
} else {
|
|
7718
|
+
budgetError = null;
|
|
7719
|
+
}
|
|
7720
|
+
} catch {
|
|
7592
7721
|
budgetError = new BudgetExceededError(
|
|
7593
7722
|
budgetError.kind,
|
|
7594
7723
|
budgetError.limit,
|
|
7595
7724
|
budgetError.used
|
|
7596
7725
|
);
|
|
7597
|
-
} else {
|
|
7598
|
-
budgetError = null;
|
|
7599
7726
|
}
|
|
7600
7727
|
}
|
|
7601
7728
|
if (budgetError) throw budgetError;
|
|
@@ -7629,12 +7756,6 @@ function defaultFormatTaskInput(task) {
|
|
|
7629
7756
|
}
|
|
7630
7757
|
|
|
7631
7758
|
// src/utils/message-invariants.ts
|
|
7632
|
-
function expectDefined2(value) {
|
|
7633
|
-
if (value === null || value === void 0) {
|
|
7634
|
-
throw new Error("Expected value to be defined");
|
|
7635
|
-
}
|
|
7636
|
-
return value;
|
|
7637
|
-
}
|
|
7638
7759
|
function repairToolUseAdjacency(messages) {
|
|
7639
7760
|
const removedToolUses = [];
|
|
7640
7761
|
const removedToolResults = [];
|
|
@@ -7642,7 +7763,7 @@ function repairToolUseAdjacency(messages) {
|
|
|
7642
7763
|
let changed = false;
|
|
7643
7764
|
const out = [];
|
|
7644
7765
|
for (let i = 0; i < messages.length; i++) {
|
|
7645
|
-
const original =
|
|
7766
|
+
const original = expectDefined(messages[i]);
|
|
7646
7767
|
let msg = original;
|
|
7647
7768
|
if (hasToolUse(msg)) {
|
|
7648
7769
|
const nextIds = toolResultIds(messages[i + 1]);
|
|
@@ -7727,12 +7848,6 @@ function isEmptyMessage(msg) {
|
|
|
7727
7848
|
}
|
|
7728
7849
|
|
|
7729
7850
|
// src/storage/session-store.ts
|
|
7730
|
-
function expectDefined3(value) {
|
|
7731
|
-
if (value === null || value === void 0) {
|
|
7732
|
-
throw new Error("Expected value to be defined");
|
|
7733
|
-
}
|
|
7734
|
-
return value;
|
|
7735
|
-
}
|
|
7736
7851
|
function sanitizeModel(model) {
|
|
7737
7852
|
return model.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
7738
7853
|
}
|
|
@@ -7998,8 +8113,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
7998
8113
|
return JSON.parse(raw);
|
|
7999
8114
|
} catch {
|
|
8000
8115
|
const full = this.sessionPath(id, ".jsonl");
|
|
8001
|
-
const
|
|
8002
|
-
const summary = await this.summarize(id,
|
|
8116
|
+
const stat5 = await fsp6.stat(full);
|
|
8117
|
+
const summary = await this.summarize(id, stat5.mtime.toISOString());
|
|
8003
8118
|
await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
|
|
8004
8119
|
console.warn(
|
|
8005
8120
|
`[session-store] Failed to write manifest for "${id}":`,
|
|
@@ -8047,8 +8162,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
8047
8162
|
if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
|
|
8048
8163
|
const jsonlPath = path4.join(dateDir, file.name);
|
|
8049
8164
|
try {
|
|
8050
|
-
const
|
|
8051
|
-
if (
|
|
8165
|
+
const stat5 = await fsp6.stat(jsonlPath);
|
|
8166
|
+
if (stat5.mtimeMs >= cutoff) continue;
|
|
8052
8167
|
} catch {
|
|
8053
8168
|
continue;
|
|
8054
8169
|
}
|
|
@@ -8443,7 +8558,7 @@ var FileSessionWriter = class {
|
|
|
8443
8558
|
let targetCheckpointLine = -1;
|
|
8444
8559
|
let afterTarget = false;
|
|
8445
8560
|
for (let i = 0; i < lines.length; i++) {
|
|
8446
|
-
const line =
|
|
8561
|
+
const line = expectDefined(lines[i]);
|
|
8447
8562
|
if (!line.trim()) continue;
|
|
8448
8563
|
let event;
|
|
8449
8564
|
try {
|