@wrongstack/core 0.9.19 → 0.9.20
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-DMVOX0cF.d.ts → agent-bridge-Dti3KXGk.d.ts} +1 -1
- package/dist/{agent-subagent-runner-C4qt9e5Y.d.ts → agent-subagent-runner-U-rs7kk7.d.ts} +3 -4
- package/dist/compactor-D7X96RLZ.d.ts +41 -0
- package/dist/{config-CWva0qoL.d.ts → config-CLXMDOSs.d.ts} +1 -1
- package/dist/{context-BRNbHmRM.d.ts → context-zkZeILpr.d.ts} +46 -0
- package/dist/coordination/index.d.ts +13 -13
- package/dist/coordination/index.js +660 -146
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +20 -20
- package/dist/defaults/index.js +918 -350
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-CiG9qUM_.d.ts → events-DH-9r-_C.d.ts} +42 -1
- package/dist/execution/index.d.ts +41 -30
- package/dist/execution/index.js +358 -112
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/extension/index.js.map +1 -1
- package/dist/{index-aizK8olO.d.ts → index-BIHJ4uII.d.ts} +11 -8
- package/dist/{index-p95HQ22A.d.ts → index-CFO9QmJo.d.ts} +8 -8
- package/dist/index.d.ts +311 -35
- package/dist/index.js +1933 -512
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/infrastructure/index.js +36 -0
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +9 -9
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-BkVEqkRe.d.ts → mcp-servers-DkESgh0G.d.ts} +25 -3
- package/dist/models/index.d.ts +2 -2
- package/dist/models/index.js +1 -1
- package/dist/models/index.js.map +1 -1
- package/dist/{multi-agent-3ZnTB1aT.d.ts → multi-agent-DNp6lAzg.d.ts} +35 -23
- package/dist/{multi-agent-coordinator-bRaI_aD1.d.ts → multi-agent-coordinator-CAhsegPz.d.ts} +20 -2
- package/dist/{null-fleet-bus-DKM3Iy9d.d.ts → null-fleet-bus-Dnl19vmf.d.ts} +411 -110
- package/dist/observability/index.d.ts +2 -2
- package/dist/{path-resolver-TcJfc29Y.d.ts → path-resolver-CHiBL0DD.d.ts} +2 -2
- package/dist/{permission-bPuzAy4x.d.ts → permission-H35s9Evv.d.ts} +1 -1
- package/dist/{permission-policy-BUQSutpl.d.ts → permission-policy-CT-nRmTn.d.ts} +2 -2
- package/dist/{plan-templates-fkQTyz3U.d.ts → plan-templates-Bs8iRwi6.d.ts} +4 -4
- package/dist/{provider-runner-BEpikbbN.d.ts → provider-runner-BZdDrWrS.d.ts} +3 -3
- package/dist/{retry-policy-BYkq0ugs.d.ts → retry-policy-J9N_PM40.d.ts} +1 -1
- package/dist/sdd/index.d.ts +9 -10
- package/dist/sdd/index.js +224 -68
- package/dist/sdd/index.js.map +1 -1
- package/dist/security/index.d.ts +3 -3
- package/dist/{selector-pox8abg0.d.ts → selector-CFTh3Z6p.d.ts} +1 -1
- package/dist/{session-reader-CSWcb5Ga.d.ts → session-reader-C7JJlxOw.d.ts} +2 -2
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.js +1 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +390 -6
- package/dist/storage/index.js +672 -35
- package/dist/storage/index.js.map +1 -1
- package/dist/{system-prompt-Bs-Wliab.d.ts → system-prompt-CneIxVip.d.ts} +1 -1
- package/dist/{tool-executor-Boo3dekH.d.ts → tool-executor-flTuxsqO.d.ts} +9 -4
- package/dist/types/index.d.ts +14 -14
- package/dist/types/index.js +60 -0
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +18 -6
- package/dist/utils/index.js +61 -56
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/compactor-DVTKL7XD.d.ts +0 -23
package/dist/execution/index.js
CHANGED
|
@@ -39,6 +39,54 @@ function estimateToolResultTokens(content) {
|
|
|
39
39
|
function estimateTextTokens(text) {
|
|
40
40
|
return RoughTokenEstimate(text);
|
|
41
41
|
}
|
|
42
|
+
function estimateToolDefTokens(tool) {
|
|
43
|
+
return RoughTokenEstimate(tool.name) + RoughTokenEstimate(tool.description ?? "") + RoughTokenEstimate(JSON.stringify(tool.inputSchema));
|
|
44
|
+
}
|
|
45
|
+
function estimateRequestTokens(messages, systemPrompt, tools) {
|
|
46
|
+
let messagesTokens = 0;
|
|
47
|
+
if (typeof messages === "string") {
|
|
48
|
+
messagesTokens = RoughTokenEstimate(messages);
|
|
49
|
+
} else if (Array.isArray(messages)) {
|
|
50
|
+
for (const m of messages) {
|
|
51
|
+
if (typeof m === "object" && m !== null && "content" in m) {
|
|
52
|
+
const content = m.content;
|
|
53
|
+
if (typeof content === "string") {
|
|
54
|
+
messagesTokens += RoughTokenEstimate(content);
|
|
55
|
+
} else if (Array.isArray(content)) {
|
|
56
|
+
for (const b of content) {
|
|
57
|
+
if (typeof b === "object" && b !== null) {
|
|
58
|
+
if (b.type === "text") {
|
|
59
|
+
messagesTokens += RoughTokenEstimate(b.text);
|
|
60
|
+
} else {
|
|
61
|
+
messagesTokens += RoughTokenEstimate(JSON.stringify(b));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let systemTokens = 0;
|
|
70
|
+
if (typeof systemPrompt === "string") {
|
|
71
|
+
systemTokens = RoughTokenEstimate(systemPrompt);
|
|
72
|
+
} else if (Array.isArray(systemPrompt)) {
|
|
73
|
+
for (const b of systemPrompt) {
|
|
74
|
+
if (typeof b === "object" && b !== null && b.type === "text") {
|
|
75
|
+
systemTokens += RoughTokenEstimate(b.text);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
let toolsTokens = 0;
|
|
80
|
+
for (const t of tools) {
|
|
81
|
+
toolsTokens += estimateToolDefTokens(t);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
messages: messagesTokens,
|
|
85
|
+
systemPrompt: systemTokens,
|
|
86
|
+
tools: toolsTokens,
|
|
87
|
+
total: messagesTokens + systemTokens + toolsTokens
|
|
88
|
+
};
|
|
89
|
+
}
|
|
42
90
|
|
|
43
91
|
// src/utils/message-invariants.ts
|
|
44
92
|
function repairToolUseAdjacency(messages) {
|
|
@@ -144,6 +192,7 @@ var HybridCompactor = class {
|
|
|
144
192
|
}
|
|
145
193
|
async compact(ctx, opts = {}) {
|
|
146
194
|
const beforeTokens = this.estimateMessages(ctx.messages);
|
|
195
|
+
const beforeFull = this.estimateFullRequest(ctx);
|
|
147
196
|
const reductions = [];
|
|
148
197
|
const policy = readContextWindowPolicy(ctx);
|
|
149
198
|
const preserveK = policy?.preserveK ?? this.preserveK;
|
|
@@ -159,9 +208,12 @@ var HybridCompactor = class {
|
|
|
159
208
|
ctx.state.replaceMessages(repaired.messages);
|
|
160
209
|
}
|
|
161
210
|
const afterTokens = this.estimateMessages(ctx.messages);
|
|
211
|
+
const afterFull = this.estimateFullRequest(ctx);
|
|
162
212
|
return {
|
|
163
213
|
before: beforeTokens,
|
|
164
214
|
after: afterTokens,
|
|
215
|
+
fullRequestTokensBefore: beforeFull,
|
|
216
|
+
fullRequestTokensAfter: afterFull,
|
|
165
217
|
reductions,
|
|
166
218
|
repaired: repaired.report.changed ? {
|
|
167
219
|
removedToolUses: repaired.report.removedToolUses,
|
|
@@ -170,6 +222,14 @@ var HybridCompactor = class {
|
|
|
170
222
|
} : void 0
|
|
171
223
|
};
|
|
172
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Estimate the full API request token count: messages + systemPrompt + toolDefs.
|
|
227
|
+
* This is the accurate figure for context-window pressure monitoring.
|
|
228
|
+
*/
|
|
229
|
+
estimateFullRequest(ctx) {
|
|
230
|
+
const breakdown = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []);
|
|
231
|
+
return breakdown.total;
|
|
232
|
+
}
|
|
173
233
|
eliseOldToolResults(ctx, preserveK = this.preserveK, eliseThreshold = this.eliseThreshold) {
|
|
174
234
|
const messages = ctx.messages;
|
|
175
235
|
let pairCount = 0;
|
|
@@ -315,8 +375,9 @@ var IntelligentCompactor = class {
|
|
|
315
375
|
}
|
|
316
376
|
async compact(ctx, opts = {}) {
|
|
317
377
|
const beforeTokens = this.estimateTokens(ctx.messages);
|
|
378
|
+
const beforeFull = this.estimateFullRequest(ctx);
|
|
318
379
|
const reductions = [];
|
|
319
|
-
const load =
|
|
380
|
+
const load = beforeFull / this.maxContext;
|
|
320
381
|
const aggressive = load >= this.hardThreshold ? true : opts.aggressive ?? load >= this.softThreshold;
|
|
321
382
|
const saved1 = this.eliseOldToolResults(ctx);
|
|
322
383
|
if (saved1 > 0) reductions.push({ phase: "elision", saved: saved1 });
|
|
@@ -330,9 +391,12 @@ var IntelligentCompactor = class {
|
|
|
330
391
|
const repaired = repairToolUseAdjacency(ctx.messages);
|
|
331
392
|
if (repaired.report.changed) ctx.state.replaceMessages(repaired.messages);
|
|
332
393
|
const afterTokens = this.estimateTokens(ctx.messages);
|
|
394
|
+
const afterFull = this.estimateFullRequest(ctx);
|
|
333
395
|
return {
|
|
334
396
|
before: beforeTokens,
|
|
335
397
|
after: afterTokens,
|
|
398
|
+
fullRequestTokensBefore: beforeFull,
|
|
399
|
+
fullRequestTokensAfter: afterFull,
|
|
336
400
|
reductions,
|
|
337
401
|
repaired: repaired.report.changed ? {
|
|
338
402
|
removedToolUses: repaired.report.removedToolUses,
|
|
@@ -341,6 +405,14 @@ var IntelligentCompactor = class {
|
|
|
341
405
|
} : void 0
|
|
342
406
|
};
|
|
343
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Estimate the full API request token count: messages + systemPrompt + toolDefs.
|
|
410
|
+
* This is the accurate figure for context-window pressure monitoring.
|
|
411
|
+
*/
|
|
412
|
+
estimateFullRequest(ctx) {
|
|
413
|
+
const breakdown = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []);
|
|
414
|
+
return breakdown.total;
|
|
415
|
+
}
|
|
344
416
|
async summarizeAncientTurns(ctx) {
|
|
345
417
|
const messages = ctx.messages;
|
|
346
418
|
const cutoff = Math.max(0, messages.length - this.preserveK * 2);
|
|
@@ -353,29 +425,26 @@ var IntelligentCompactor = class {
|
|
|
353
425
|
try {
|
|
354
426
|
summaryText = await this.callSummarizer(toSummarize, ctx);
|
|
355
427
|
} catch {
|
|
356
|
-
const
|
|
357
|
-
const filePaths = /* @__PURE__ */ new Set();
|
|
358
|
-
let userTurns = 0;
|
|
359
|
-
let assistantTurns = 0;
|
|
428
|
+
const preservedMessages = [];
|
|
360
429
|
for (const m of toSummarize) {
|
|
361
|
-
if (m.role === "
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
430
|
+
if (m.role === "system") continue;
|
|
431
|
+
if (typeof m.content === "string") {
|
|
432
|
+
preservedMessages.push(m);
|
|
433
|
+
} else if (Array.isArray(m.content)) {
|
|
434
|
+
const textParts = m.content.filter(isTextBlock);
|
|
435
|
+
const toolParts = m.content.filter((b) => b.type === "tool_use" || b.type === "tool_result");
|
|
436
|
+
const next = {
|
|
437
|
+
role: m.role,
|
|
438
|
+
content: [
|
|
439
|
+
...textParts,
|
|
440
|
+
...toolParts.length > 0 ? [{ type: "text", text: `[${toolParts.length} tool call(s) omitted]` }] : []
|
|
441
|
+
]
|
|
442
|
+
};
|
|
443
|
+
preservedMessages.push(next);
|
|
369
444
|
}
|
|
370
|
-
const text = typeof m.content === "string" ? m.content : "";
|
|
371
|
-
const matches = text.matchAll(/(?:[\w.,\-/@]+\/)*[\w.,\-/@]+\.\w+/g);
|
|
372
|
-
for (const m_ of matches) filePaths.add(m_[0]);
|
|
373
445
|
}
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
if (filePaths.size > 0) parts.push(`files: ${[...filePaths].slice(0, 10).join(", ")}`);
|
|
377
|
-
summaryText = parts.join(" | ");
|
|
378
|
-
if (!summaryText) summaryText = `${toSummarize.length} earlier turns omitted`;
|
|
446
|
+
summaryText = preservedMessages.map((m) => `[${m.role}]: ${typeof m.content === "string" ? m.content : m.content.filter(isTextBlock).map((b) => b.text).join(" ")}`).join("\n");
|
|
447
|
+
if (!summaryText) summaryText = `${toSummarize.length} earlier turns (semantic content preserved)`;
|
|
379
448
|
}
|
|
380
449
|
const summaryMsg = {
|
|
381
450
|
role: "system",
|
|
@@ -621,7 +690,7 @@ IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiv
|
|
|
621
690
|
const res = await this.provider.complete(req, { signal: ac.signal });
|
|
622
691
|
const textBlocks = res.content.filter(isTextBlock);
|
|
623
692
|
raw = textBlocks.map((b) => b.text).join("\n").trim();
|
|
624
|
-
} catch (
|
|
693
|
+
} catch (_err) {
|
|
625
694
|
return this.fallbackSelect(messages, effectiveBudget);
|
|
626
695
|
}
|
|
627
696
|
return this.parseSelectorOutput(raw, messages.length);
|
|
@@ -713,15 +782,24 @@ var SelectiveCompactor = class {
|
|
|
713
782
|
}
|
|
714
783
|
async compact(ctx, opts = {}) {
|
|
715
784
|
const beforeTokens = this.estimateTokens(ctx.messages);
|
|
785
|
+
const beforeFull = this.estimateFullRequest(ctx);
|
|
716
786
|
const reductions = [];
|
|
717
|
-
const load =
|
|
787
|
+
const load = beforeFull / this.maxContext;
|
|
718
788
|
const shouldCompact = load >= this.warnThreshold || opts.aggressive;
|
|
719
789
|
if (!shouldCompact) {
|
|
720
790
|
const saved = this.eliseOldToolResults(ctx);
|
|
721
791
|
if (saved > 0) reductions.push({ phase: "elision", saved });
|
|
722
792
|
const repair2 = this.repairProtocolAdjacency(ctx);
|
|
723
793
|
const afterTokens2 = this.estimateTokens(ctx.messages);
|
|
724
|
-
|
|
794
|
+
const afterFull2 = this.estimateFullRequest(ctx);
|
|
795
|
+
return {
|
|
796
|
+
before: beforeTokens,
|
|
797
|
+
after: afterTokens2,
|
|
798
|
+
fullRequestTokensBefore: beforeFull,
|
|
799
|
+
fullRequestTokensAfter: afterFull2,
|
|
800
|
+
reductions,
|
|
801
|
+
repaired: repair2
|
|
802
|
+
};
|
|
725
803
|
}
|
|
726
804
|
const savedElision = this.eliseOldToolResults(ctx);
|
|
727
805
|
if (savedElision > 0) reductions.push({ phase: "elision", saved: savedElision });
|
|
@@ -733,7 +811,23 @@ var SelectiveCompactor = class {
|
|
|
733
811
|
}
|
|
734
812
|
const repair = this.repairProtocolAdjacency(ctx);
|
|
735
813
|
const afterTokens = this.estimateTokens(ctx.messages);
|
|
736
|
-
|
|
814
|
+
const afterFull = this.estimateFullRequest(ctx);
|
|
815
|
+
return {
|
|
816
|
+
before: beforeTokens,
|
|
817
|
+
after: afterTokens,
|
|
818
|
+
fullRequestTokensBefore: beforeFull,
|
|
819
|
+
fullRequestTokensAfter: afterFull,
|
|
820
|
+
reductions,
|
|
821
|
+
repaired: repair
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Estimate the full API request token count: messages + systemPrompt + toolDefs.
|
|
826
|
+
* This is the accurate figure for context-window pressure monitoring.
|
|
827
|
+
*/
|
|
828
|
+
estimateFullRequest(ctx) {
|
|
829
|
+
const breakdown = estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []);
|
|
830
|
+
return breakdown.total;
|
|
737
831
|
}
|
|
738
832
|
repairProtocolAdjacency(ctx) {
|
|
739
833
|
const repaired = repairToolUseAdjacency(ctx.messages);
|
|
@@ -1008,7 +1102,8 @@ var LEVEL_RANK = { warn: 0, soft: 1, hard: 2 };
|
|
|
1008
1102
|
var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
1009
1103
|
name = "AutoCompaction";
|
|
1010
1104
|
compactor;
|
|
1011
|
-
|
|
1105
|
+
/** Deprecated. Kept for backward compat with tests that pass simpleEstimator. */
|
|
1106
|
+
_estimator;
|
|
1012
1107
|
warnThreshold;
|
|
1013
1108
|
softThreshold;
|
|
1014
1109
|
hardThreshold;
|
|
@@ -1018,19 +1113,6 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
1018
1113
|
events;
|
|
1019
1114
|
failureMode;
|
|
1020
1115
|
policyProvider;
|
|
1021
|
-
/**
|
|
1022
|
-
* Calibration factor applied to the estimator output. The estimator is now
|
|
1023
|
-
* expected to already include messages + system prompt + tool definitions
|
|
1024
|
-
* (see `estimateRequestTokens.total`), so no overhead boost is needed. Kept
|
|
1025
|
-
* as a constant so a future calibration against real provider tokenization
|
|
1026
|
-
* (BPE vs the chars/3.5 rough estimator) can dial this without touching the
|
|
1027
|
-
* threshold-check math.
|
|
1028
|
-
*
|
|
1029
|
-
* Historical note: was 1.3 when the estimator only counted messages — that
|
|
1030
|
-
* double-counted system+tools once the estimator was upgraded, firing
|
|
1031
|
-
* compaction ~30% earlier than intended (e.g. real 56% load showed as 73%).
|
|
1032
|
-
*/
|
|
1033
|
-
static OVERHEAD_FACTOR = 1;
|
|
1034
1116
|
/**
|
|
1035
1117
|
* Once a compaction attempt reduces nothing (preserveK protects everything,
|
|
1036
1118
|
* no oversized tool_results remain to elide), retrying on every iteration
|
|
@@ -1043,8 +1125,11 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
1043
1125
|
lastNoopAttempt = null;
|
|
1044
1126
|
/**
|
|
1045
1127
|
* @param compactor Compactor to use for compaction.
|
|
1046
|
-
* @param maxContext
|
|
1047
|
-
* @param
|
|
1128
|
+
* @param maxContext Provider's max context window in tokens.
|
|
1129
|
+
* @param _estimator Deprecated parameter kept for backward compatibility.
|
|
1130
|
+
* The middleware now uses `estimateRequestTokens` internally
|
|
1131
|
+
* for accurate full-request token counting (messages +
|
|
1132
|
+
* systemPrompt + toolDefs).
|
|
1048
1133
|
* @param thresholds Threshold fractions (0-1) of maxContext.
|
|
1049
1134
|
* @param opts Optional behavior. By default, failures at the
|
|
1050
1135
|
* hard threshold throw AGENT_CONTEXT_OVERFLOW so
|
|
@@ -1052,11 +1137,11 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
1052
1137
|
* provider context overflow. Warn/soft failures
|
|
1053
1138
|
* still emit compaction.failed and continue.
|
|
1054
1139
|
*/
|
|
1055
|
-
constructor(compactor, maxContext,
|
|
1140
|
+
constructor(compactor, maxContext, _estimator, thresholds, optsOrAggressiveOn = {}, events) {
|
|
1056
1141
|
const opts = typeof optsOrAggressiveOn === "string" ? { aggressiveOn: optsOrAggressiveOn, events } : optsOrAggressiveOn;
|
|
1057
1142
|
this.compactor = compactor;
|
|
1058
1143
|
this._maxContext = maxContext;
|
|
1059
|
-
this.
|
|
1144
|
+
this._estimator = _estimator;
|
|
1060
1145
|
this.warnThreshold = thresholds.warn;
|
|
1061
1146
|
this.softThreshold = thresholds.soft;
|
|
1062
1147
|
this.hardThreshold = thresholds.hard;
|
|
@@ -1072,8 +1157,7 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
1072
1157
|
}
|
|
1073
1158
|
handler() {
|
|
1074
1159
|
return async (ctx, next) => {
|
|
1075
|
-
const
|
|
1076
|
-
const tokens = Math.ceil(rawTokens * _AutoCompactionMiddleware.OVERHEAD_FACTOR);
|
|
1160
|
+
const tokens = this._estimator ? this._estimator(ctx) : estimateRequestTokens(ctx.messages, ctx.systemPrompt, ctx.tools ?? []).total;
|
|
1077
1161
|
const load = tokens / this._maxContext;
|
|
1078
1162
|
const policy = this.policyProvider?.(ctx);
|
|
1079
1163
|
const thresholds = policy?.thresholds ?? {
|
|
@@ -1108,7 +1192,7 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
1108
1192
|
return delta < _AutoCompactionMiddleware.NOOP_RETRY_DELTA_TOKENS;
|
|
1109
1193
|
}
|
|
1110
1194
|
recordAttempt(level, tokens, report) {
|
|
1111
|
-
const reduced = report.before > report.after;
|
|
1195
|
+
const reduced = (report.fullRequestTokensBefore ?? report.before) > (report.fullRequestTokensAfter ?? report.after);
|
|
1112
1196
|
const repaired = !!report.repaired;
|
|
1113
1197
|
if (reduced || repaired) {
|
|
1114
1198
|
this.lastNoopAttempt = null;
|
|
@@ -2449,17 +2533,7 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
2449
2533
|
startTime = null;
|
|
2450
2534
|
_onThreshold;
|
|
2451
2535
|
/**
|
|
2452
|
-
*
|
|
2453
|
-
* in flight. While a kind is here, further `checkLimit` calls for the
|
|
2454
|
-
* same kind are no-ops — without this dedup, every `recordIteration`
|
|
2455
|
-
* after the limit is reached spawns a fresh decision Promise (until
|
|
2456
|
-
* the first one lands and patches limits), flooding the FleetBus
|
|
2457
|
-
* with redundant threshold events. Cleared in `negotiateExtension`'s
|
|
2458
|
-
* `finally`.
|
|
2459
|
-
*/
|
|
2460
|
-
pendingExtensions = /* @__PURE__ */ new Set();
|
|
2461
|
-
/**
|
|
2462
|
-
* Hard cap on how long `negotiateExtension` waits for the coordinator to
|
|
2536
|
+
* Hard cap on how long `_negotiateExtension` waits for the coordinator to
|
|
2463
2537
|
* respond before defaulting to 'stop'. Without this fallback an absent
|
|
2464
2538
|
* or hung listener (Director not built / event filter detached mid-run)
|
|
2465
2539
|
* leaves the budget over-limit and never enforces anything.
|
|
@@ -2521,38 +2595,83 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
2521
2595
|
* - `mode === 'auto'` + no listener → throw `BudgetExceededError` (hard stop; no one to ask)
|
|
2522
2596
|
* - `mode === 'auto'` + listener → throw `BudgetThresholdSignal` with async decision promise
|
|
2523
2597
|
*/
|
|
2524
|
-
|
|
2598
|
+
/**
|
|
2599
|
+
* Collects all exceeded budget kinds into a single NOOP-free negotiation.
|
|
2600
|
+
* Called by recordIteration / recordToolCall / recordUsage — each may call
|
|
2601
|
+
* this for its own kind. The first call starts the negotiation and stores
|
|
2602
|
+
* the Promise in _pendingNegotiation. Subsequent calls for DIFFERENT
|
|
2603
|
+
* kinds (while a negotiation is in flight) are NOOPs — they don't start
|
|
2604
|
+
* new conversations with the coordinator. This prevents an EventBus flood
|
|
2605
|
+
* when multiple budget kinds are exceeded simultaneously in one iteration.
|
|
2606
|
+
*
|
|
2607
|
+
* Returns the kinds that were found to be exceeded (for logging/debugging).
|
|
2608
|
+
*/
|
|
2609
|
+
checkLimits(elapsedMs) {
|
|
2610
|
+
const exceeded = [];
|
|
2611
|
+
if (this.limits.maxIterations !== void 0 && this.iterations > this.limits.maxIterations) {
|
|
2612
|
+
exceeded.push({ kind: "iterations", used: this.iterations, limit: this.limits.maxIterations });
|
|
2613
|
+
}
|
|
2614
|
+
if (this.limits.maxToolCalls !== void 0 && this.toolCalls > this.limits.maxToolCalls) {
|
|
2615
|
+
exceeded.push({ kind: "tool_calls", used: this.toolCalls, limit: this.limits.maxToolCalls });
|
|
2616
|
+
}
|
|
2617
|
+
const totalTokens = this.tokenInput + this.tokenOutput;
|
|
2618
|
+
if (this.limits.maxTokens !== void 0 && totalTokens > this.limits.maxTokens) {
|
|
2619
|
+
exceeded.push({ kind: "tokens", used: totalTokens, limit: this.limits.maxTokens });
|
|
2620
|
+
}
|
|
2621
|
+
if (this.limits.maxCostUsd !== void 0 && this.costUsd > this.limits.maxCostUsd) {
|
|
2622
|
+
exceeded.push({ kind: "cost", used: this.costUsd, limit: this.limits.maxCostUsd });
|
|
2623
|
+
}
|
|
2624
|
+
if (elapsedMs !== void 0 && this.limits.timeoutMs !== void 0 && elapsedMs > this.limits.timeoutMs) {
|
|
2625
|
+
exceeded.push({ kind: "timeout", used: elapsedMs, limit: this.limits.timeoutMs });
|
|
2626
|
+
}
|
|
2627
|
+
if (exceeded.length === 0) return [];
|
|
2525
2628
|
if (!this._onThreshold) {
|
|
2526
|
-
|
|
2629
|
+
const first2 = exceeded[0];
|
|
2630
|
+
throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
|
|
2527
2631
|
}
|
|
2528
2632
|
if (this._mode === "sync") {
|
|
2529
|
-
|
|
2633
|
+
const first2 = exceeded[0];
|
|
2634
|
+
throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
|
|
2530
2635
|
}
|
|
2531
2636
|
const bus = this._events;
|
|
2532
2637
|
if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
|
|
2533
|
-
|
|
2638
|
+
const first2 = exceeded[0];
|
|
2639
|
+
throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
|
|
2534
2640
|
}
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2641
|
+
for (const entry of exceeded) {
|
|
2642
|
+
if (this._pendingNegotiations.has(entry.kind)) continue;
|
|
2643
|
+
const decision2 = this._negotiateExtension(entry.kind, exceeded);
|
|
2644
|
+
this._pendingNegotiations.set(entry.kind, decision2);
|
|
2645
|
+
}
|
|
2646
|
+
const first = exceeded[0];
|
|
2647
|
+
const decision = this._pendingNegotiations.get(first.kind);
|
|
2648
|
+
throw new BudgetThresholdSignal(first.kind, first.limit, first.used, decision);
|
|
2539
2649
|
}
|
|
2650
|
+
/**
|
|
2651
|
+
* Per-kind in-flight negotiation Promises. Each budget kind can have its
|
|
2652
|
+
* own concurrent negotiation — e.g. iterations and timeout can both
|
|
2653
|
+
* be exceeded simultaneously without blocking each other. The same kind
|
|
2654
|
+
* cannot start two concurrent negotiations (dedup guard).
|
|
2655
|
+
* Cleared in `_negotiateExtension`'s `finally` block.
|
|
2656
|
+
*/
|
|
2657
|
+
_pendingNegotiations = /* @__PURE__ */ new Map();
|
|
2540
2658
|
/**
|
|
2541
2659
|
* Drive the threshold handler to a decision. Resolves with `'stop'`
|
|
2542
2660
|
* (signal the runner to abort) or `{ extend: ... }` (limits already
|
|
2543
|
-
* patched in-place; the runner should not abort).
|
|
2544
|
-
*
|
|
2661
|
+
* patched in-place; the runner should not abort). Clears the
|
|
2662
|
+
* per-kind slot in `_pendingNegotiations` in `finally`.
|
|
2545
2663
|
*
|
|
2546
2664
|
* The 'continue' return from a sync handler is treated as
|
|
2547
2665
|
* `{ extend: {} }` — keep going without patching; next overrun fires
|
|
2548
2666
|
* a fresh signal.
|
|
2549
2667
|
*/
|
|
2550
|
-
async
|
|
2668
|
+
async _negotiateExtension(kind, exceeded) {
|
|
2551
2669
|
try {
|
|
2670
|
+
const first = exceeded[0];
|
|
2552
2671
|
const result = this._onThreshold({
|
|
2553
|
-
kind,
|
|
2554
|
-
used,
|
|
2555
|
-
limit,
|
|
2672
|
+
kind: first.kind,
|
|
2673
|
+
used: first.used,
|
|
2674
|
+
limit: first.limit,
|
|
2556
2675
|
requestDecision: () => {
|
|
2557
2676
|
const bus = this._events;
|
|
2558
2677
|
if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
|
|
@@ -2569,20 +2688,22 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
2569
2688
|
() => respond("stop"),
|
|
2570
2689
|
_SubagentBudget.DECISION_TIMEOUT_MS
|
|
2571
2690
|
);
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2691
|
+
for (const { kind: kind2, used, limit } of exceeded) {
|
|
2692
|
+
bus.emit("budget.threshold_reached", {
|
|
2693
|
+
kind: kind2,
|
|
2694
|
+
used,
|
|
2695
|
+
limit,
|
|
2696
|
+
timeoutMs: _SubagentBudget.DECISION_TIMEOUT_MS,
|
|
2697
|
+
extend: (extra) => {
|
|
2698
|
+
clearTimeout(fallback);
|
|
2699
|
+
respond({ extend: extra });
|
|
2700
|
+
},
|
|
2701
|
+
deny: () => {
|
|
2702
|
+
clearTimeout(fallback);
|
|
2703
|
+
respond("stop");
|
|
2704
|
+
}
|
|
2705
|
+
});
|
|
2706
|
+
}
|
|
2586
2707
|
});
|
|
2587
2708
|
}
|
|
2588
2709
|
});
|
|
@@ -2608,47 +2729,39 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
2608
2729
|
}
|
|
2609
2730
|
return decision;
|
|
2610
2731
|
} finally {
|
|
2611
|
-
this.
|
|
2732
|
+
this._pendingNegotiations.delete(kind);
|
|
2612
2733
|
}
|
|
2613
2734
|
}
|
|
2614
2735
|
recordIteration() {
|
|
2615
2736
|
this.iterations++;
|
|
2616
|
-
|
|
2617
|
-
void this.checkLimit("iterations", this.iterations, this.limits.maxIterations);
|
|
2618
|
-
}
|
|
2737
|
+
void this.checkLimits();
|
|
2619
2738
|
}
|
|
2620
2739
|
recordToolCall() {
|
|
2621
2740
|
this.toolCalls++;
|
|
2622
|
-
|
|
2623
|
-
void this.checkLimit("tool_calls", this.toolCalls, this.limits.maxToolCalls);
|
|
2624
|
-
}
|
|
2741
|
+
void this.checkLimits();
|
|
2625
2742
|
}
|
|
2626
2743
|
recordUsage(usage, costUsd = 0) {
|
|
2627
2744
|
this.tokenInput += usage.input;
|
|
2628
2745
|
this.tokenOutput += usage.output;
|
|
2629
2746
|
this.costUsd += costUsd;
|
|
2630
|
-
|
|
2631
|
-
if (this.limits.maxTokens !== void 0 && totalTokens > this.limits.maxTokens) {
|
|
2632
|
-
void this.checkLimit("tokens", totalTokens, this.limits.maxTokens);
|
|
2633
|
-
}
|
|
2634
|
-
if (this.limits.maxCostUsd !== void 0 && this.costUsd > this.limits.maxCostUsd) {
|
|
2635
|
-
void this.checkLimit("cost", this.costUsd, this.limits.maxCostUsd);
|
|
2636
|
-
}
|
|
2747
|
+
void this.checkLimits();
|
|
2637
2748
|
}
|
|
2638
2749
|
/**
|
|
2639
|
-
* Wall-clock budget check. Unlike other limits, timeout
|
|
2640
|
-
*
|
|
2641
|
-
*
|
|
2642
|
-
*
|
|
2643
|
-
*
|
|
2644
|
-
*
|
|
2750
|
+
* Wall-clock budget check. Unlike other limits, timeout is always a hard stop
|
|
2751
|
+
* — wall-clock time cannot be "extended" by the coordinator, so it throws
|
|
2752
|
+
* synchronously rather than entering the negotiation flow.
|
|
2753
|
+
*
|
|
2754
|
+
* Decision table:
|
|
2755
|
+
* - no `onThreshold` handler → throw `BudgetExceededError`
|
|
2756
|
+
* - `mode === 'sync'` → throw `BudgetExceededError`
|
|
2757
|
+
* - `mode === 'auto'` + no listener → throw `BudgetExceededError`
|
|
2758
|
+
* - `mode === 'auto'` + listener → throw `BudgetExceededError` (timeout is not extendable)
|
|
2645
2759
|
*/
|
|
2646
2760
|
checkTimeout() {
|
|
2647
2761
|
if (this.startTime === null || this.limits.timeoutMs === void 0) return;
|
|
2648
2762
|
const elapsed = Date.now() - this.startTime;
|
|
2649
|
-
if (elapsed
|
|
2650
|
-
|
|
2651
|
-
}
|
|
2763
|
+
if (elapsed <= this.limits.timeoutMs) return;
|
|
2764
|
+
void this.checkLimits(elapsed);
|
|
2652
2765
|
}
|
|
2653
2766
|
/** Returns true if a timeout has occurred without throwing. Useful for races. */
|
|
2654
2767
|
isTimedOut() {
|
|
@@ -5258,6 +5371,107 @@ FLEET_ROSTER_BUDGETS["goose"] = { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations:
|
|
|
5258
5371
|
...Object.fromEntries(ACP_AGENTS.map((a) => [a.role, a]))
|
|
5259
5372
|
});
|
|
5260
5373
|
|
|
5374
|
+
// src/coordination/subagent-nicknames.ts
|
|
5375
|
+
var NICKNAME_POOL = {
|
|
5376
|
+
// Physics & fundamental sciences
|
|
5377
|
+
"einstein": { name: "Einstein", domain: "physics" },
|
|
5378
|
+
"newton": { name: "Newton", domain: "physics" },
|
|
5379
|
+
"feynman": { name: "Feynman", domain: "physics" },
|
|
5380
|
+
"dirac": { name: "Dirac", domain: "physics" },
|
|
5381
|
+
"bohr": { name: "Bohr", domain: "physics" },
|
|
5382
|
+
"planck": { name: "Planck", domain: "physics" },
|
|
5383
|
+
"curie": { name: "Curie", domain: "physics" },
|
|
5384
|
+
"fermi": { name: "Fermi", domain: "physics" },
|
|
5385
|
+
"heisenberg": { name: "Heisenberg", domain: "physics" },
|
|
5386
|
+
"schrodinger": { name: "Schr\xF6dinger", domain: "physics" },
|
|
5387
|
+
// Mathematics
|
|
5388
|
+
"euclid": { name: "Euclid", domain: "math" },
|
|
5389
|
+
"gauss": { name: "Gauss", domain: "math" },
|
|
5390
|
+
"turing": { name: "Turing", domain: "math" },
|
|
5391
|
+
"poincare": { name: "Poincar\xE9", domain: "math" },
|
|
5392
|
+
"riemann": { name: "Riemann", domain: "math" },
|
|
5393
|
+
"hilbert": { name: "Hilbert", domain: "math" },
|
|
5394
|
+
"pythagoras": { name: "Pythagoras", domain: "math" },
|
|
5395
|
+
// Computing & information theory
|
|
5396
|
+
"von-neumann": { name: "Von Neumann", domain: "computing" },
|
|
5397
|
+
"shannon": { name: "Shannon", domain: "computing" },
|
|
5398
|
+
"hopper": { name: "Hopper", domain: "computing" },
|
|
5399
|
+
"backus": { name: "Backus", domain: "computing" },
|
|
5400
|
+
"knuth": { name: "Knuth", domain: "computing" },
|
|
5401
|
+
"torvalds": { name: "Torvalds", domain: "computing" },
|
|
5402
|
+
"stallman": { name: "Stallman", domain: "computing" },
|
|
5403
|
+
"berners-lee": { name: "Berners-Lee", domain: "computing" },
|
|
5404
|
+
"babbage": { name: "Babbage", domain: "computing" },
|
|
5405
|
+
"lovelace": { name: "Lovelace", domain: "computing" },
|
|
5406
|
+
"klein": { name: "Klein", domain: "computing" },
|
|
5407
|
+
// Electronics & electrical engineering
|
|
5408
|
+
"edison": { name: "Edison", domain: "ee" },
|
|
5409
|
+
"tesla": { name: "Tesla", domain: "ee" },
|
|
5410
|
+
"faraday": { name: "Faraday", domain: "ee" },
|
|
5411
|
+
"maxwell": { name: "Maxwell", domain: "ee" },
|
|
5412
|
+
"ohm": { name: "Ohm", domain: "ee" },
|
|
5413
|
+
"bell": { name: "Bell", domain: "ee" },
|
|
5414
|
+
"marconi": { name: "Marconi", domain: "ee" },
|
|
5415
|
+
"lamarr": { name: "Lamarr", domain: "ee" },
|
|
5416
|
+
// General science / multi-disciplinary
|
|
5417
|
+
"darwin": { name: "Darwin", domain: "biology" },
|
|
5418
|
+
"mendel": { name: "Mendel", domain: "biology" },
|
|
5419
|
+
"pasteur": { name: "Pasteur", domain: "biology" },
|
|
5420
|
+
"hawking": { name: "Hawking", domain: "cosmology" },
|
|
5421
|
+
"sagan": { name: "Sagan", domain: "cosmology" },
|
|
5422
|
+
// Chemistry / materials
|
|
5423
|
+
"lavoisier": { name: "Lavoisier", domain: "chemistry" },
|
|
5424
|
+
"mendeleev": { name: "Mendeleev", domain: "chemistry" }
|
|
5425
|
+
};
|
|
5426
|
+
var ALL_NICKNAMES = Object.values(NICKNAME_POOL);
|
|
5427
|
+
var DOMAIN_PREFERENCES = {
|
|
5428
|
+
"security": ["shannon", "turing", "lamarr", "stallman"],
|
|
5429
|
+
"bug-hunter": ["darwin", "curie", "feynman", "fermi"],
|
|
5430
|
+
"refactor": ["gauss", "hilbert", "euclid", "planck"],
|
|
5431
|
+
"audit-log": ["sagan", "hawking", "poincare", "newton"],
|
|
5432
|
+
"planner": ["hilbert", "gauss", "turing", "euclid"],
|
|
5433
|
+
"researcher": ["sagan", "hawking", "darwin", "pasteur"],
|
|
5434
|
+
"explorer": ["marconi", "bell", "columbus", "polo"],
|
|
5435
|
+
"testing": ["pasteur", "curie", "fermi", "bohr"],
|
|
5436
|
+
"frontend": ["lovelace", "hopper", "babbage", "backus"],
|
|
5437
|
+
"backend": ["torvalds", "stallman", "von-neumann", "backus"],
|
|
5438
|
+
"database": ["turing", "shannon", "backus", "knuth"],
|
|
5439
|
+
"devops": ["tesla", "edison", "faraday", "bell"],
|
|
5440
|
+
"security-scanner": ["shannon", "turing", "lamarr", "stallman"],
|
|
5441
|
+
"refactor-planner": ["gauss", "hilbert", "planck", "newton"],
|
|
5442
|
+
"architect": ["von-neumann", "turing", "gauss", "hilbert"],
|
|
5443
|
+
"critic": ["einstein", "feynman", "dirac", "bohr"],
|
|
5444
|
+
"e2e": ["hopper", "bell", "marconi", "tesla"],
|
|
5445
|
+
"performance": ["knuth", "gauss", "planck", "feynman"],
|
|
5446
|
+
"chaos": ["tesla", "edison", "curie", "fermi"],
|
|
5447
|
+
"cost": ["ohm", "bell", "marconi", "tesla"],
|
|
5448
|
+
// default fallback
|
|
5449
|
+
"default": ["einstein", "newton", "curie", "tesla", "edison", "turing", "shannon", "hopper", "knuth", "stallman"]
|
|
5450
|
+
};
|
|
5451
|
+
function assignNickname(role, used) {
|
|
5452
|
+
const preferences = [
|
|
5453
|
+
...DOMAIN_PREFERENCES[role] ?? [],
|
|
5454
|
+
...DOMAIN_PREFERENCES["default"] ?? []
|
|
5455
|
+
];
|
|
5456
|
+
for (const key of preferences) {
|
|
5457
|
+
const entry = NICKNAME_POOL[key];
|
|
5458
|
+
if (entry && !used.has(key)) {
|
|
5459
|
+
return `${entry.name} (${formatRole(role)})`;
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
for (const entry of ALL_NICKNAMES) {
|
|
5463
|
+
const key = Object.entries(NICKNAME_POOL).find(([, v]) => v.name === entry.name)?.[0];
|
|
5464
|
+
if (key && !used.has(key)) {
|
|
5465
|
+
return `${entry.name} (${formatRole(role)})`;
|
|
5466
|
+
}
|
|
5467
|
+
}
|
|
5468
|
+
const counter = used.size + 1;
|
|
5469
|
+
return `Scientist #${counter} (${formatRole(role)})`;
|
|
5470
|
+
}
|
|
5471
|
+
function formatRole(role) {
|
|
5472
|
+
return role.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
5473
|
+
}
|
|
5474
|
+
|
|
5261
5475
|
// src/coordination/multi-agent-coordinator.ts
|
|
5262
5476
|
var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
5263
5477
|
coordinatorId;
|
|
@@ -5265,6 +5479,15 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
5265
5479
|
runner;
|
|
5266
5480
|
fleetBus;
|
|
5267
5481
|
subagents = /* @__PURE__ */ new Map();
|
|
5482
|
+
/**
|
|
5483
|
+
* Base nickname keys already handed out this run (e.g. `einstein`, `tesla`).
|
|
5484
|
+
* Prevents two workers sharing a name. Direct `coordinator.spawn()` callers
|
|
5485
|
+
* (parallel/eternal engine, SDD parallel run) don't go through
|
|
5486
|
+
* `Director.spawn()` where nicknames are normally assigned, so the
|
|
5487
|
+
* coordinator upgrades placeholder names ("Executor", "slot-ab12cd", role
|
|
5488
|
+
* names) to memorable ones here — that's what surfaces in the fleet monitor.
|
|
5489
|
+
*/
|
|
5490
|
+
usedNicknames = /* @__PURE__ */ new Set();
|
|
5268
5491
|
pendingTasks = [];
|
|
5269
5492
|
completedResults = [];
|
|
5270
5493
|
totalIterations = 0;
|
|
@@ -5313,7 +5536,26 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
5313
5536
|
this.config.maxConcurrent = Math.floor(n);
|
|
5314
5537
|
this.tryDispatchNext();
|
|
5315
5538
|
}
|
|
5539
|
+
/**
|
|
5540
|
+
* Upgrade a placeholder/role-derived name to a memorable scientist nickname
|
|
5541
|
+
* (e.g. "Einstein (Executor)"). A name is treated as a placeholder when it is
|
|
5542
|
+
* empty, equals the role (case-insensitive), is a generic default
|
|
5543
|
+
* ("subagent"/"adhoc"/"generic"), or is an auto-generated `slot-…` id.
|
|
5544
|
+
* Explicit, human-chosen names — including nicknames already assigned by
|
|
5545
|
+
* `Director.spawn()` — are left untouched, so this never double-assigns.
|
|
5546
|
+
*/
|
|
5547
|
+
withNickname(subagent) {
|
|
5548
|
+
const role = subagent.role ?? "subagent";
|
|
5549
|
+
const name = subagent.name?.trim() ?? "";
|
|
5550
|
+
const isPlaceholder = name === "" || name.toLowerCase() === role.toLowerCase() || name === "subagent" || name === "adhoc" || name === "generic" || /^slot-/.test(name);
|
|
5551
|
+
if (!isPlaceholder) return subagent;
|
|
5552
|
+
const nickname = assignNickname(role, this.usedNicknames);
|
|
5553
|
+
const baseKey = nickname.split(" ")[0].toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
5554
|
+
this.usedNicknames.add(baseKey);
|
|
5555
|
+
return { ...subagent, name: nickname };
|
|
5556
|
+
}
|
|
5316
5557
|
async spawn(subagent) {
|
|
5558
|
+
subagent = this.withNickname(subagent);
|
|
5317
5559
|
const id = subagent.id || randomUUID();
|
|
5318
5560
|
if (this.subagents.has(id)) {
|
|
5319
5561
|
throw new Error(`Subagent id "${id}" already exists \u2014 refusing to overwrite`);
|
|
@@ -5907,12 +6149,12 @@ var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
|
|
|
5907
6149
|
var ParallelEternalEngine = class {
|
|
5908
6150
|
constructor(opts) {
|
|
5909
6151
|
this.opts = opts;
|
|
5910
|
-
this.goalPath = goalFilePath(opts.projectRoot);
|
|
6152
|
+
this.goalPath = opts.goalPath ?? goalFilePath(opts.projectRoot);
|
|
5911
6153
|
this.slots = Math.min(16, Math.max(1, opts.parallelSlots ?? 4));
|
|
5912
6154
|
this.timeoutMs = opts.iterationTimeoutMs ?? 3e5;
|
|
5913
6155
|
this.dispatchEnabled = opts.dispatch !== false;
|
|
5914
6156
|
this.dispatchClassifier = opts.dispatchClassifier;
|
|
5915
|
-
this.agentFactory = opts.subagentFactory ?? (async (
|
|
6157
|
+
this.agentFactory = opts.subagentFactory ?? (async (_config) => ({
|
|
5916
6158
|
agent: this.opts.agent,
|
|
5917
6159
|
events: this.opts.agent.events
|
|
5918
6160
|
}));
|
|
@@ -6006,7 +6248,6 @@ var ParallelEternalEngine = class {
|
|
|
6006
6248
|
}
|
|
6007
6249
|
const tasks = await this.decomposeGoal(goal);
|
|
6008
6250
|
if (!tasks || tasks.length === 0) {
|
|
6009
|
-
await sleep2(5e3);
|
|
6010
6251
|
return false;
|
|
6011
6252
|
}
|
|
6012
6253
|
const fanOut = await this.fanOut(goal, tasks);
|
|
@@ -6027,6 +6268,7 @@ var ParallelEternalEngine = class {
|
|
|
6027
6268
|
});
|
|
6028
6269
|
if (fanOut.goalComplete) {
|
|
6029
6270
|
this.stopRequested = true;
|
|
6271
|
+
this.state = "stopped";
|
|
6030
6272
|
return true;
|
|
6031
6273
|
}
|
|
6032
6274
|
await this.maybeCompact();
|
|
@@ -6207,7 +6449,11 @@ ${lastFew}` : "No prior iterations.",
|
|
|
6207
6449
|
} finally {
|
|
6208
6450
|
clearTimeout(timer);
|
|
6209
6451
|
}
|
|
6210
|
-
} catch {
|
|
6452
|
+
} catch (err) {
|
|
6453
|
+
this.opts.onError?.(
|
|
6454
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
6455
|
+
this.consecutiveFailures
|
|
6456
|
+
);
|
|
6211
6457
|
return [];
|
|
6212
6458
|
}
|
|
6213
6459
|
}
|