@wrongstack/core 0.10.3 → 0.31.1
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-subagent-runner-DuRtZmhl.d.ts → agent-subagent-runner-DpZTLdBe.d.ts} +1 -1
- package/dist/{config-CJXBka2r.d.ts → config-BUEGM4JP.d.ts} +2 -0
- package/dist/coordination/index.d.ts +6 -6
- package/dist/coordination/index.js +414 -71
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +8 -8
- package/dist/defaults/index.js +388 -57
- package/dist/defaults/index.js.map +1 -1
- package/dist/execution/index.d.ts +5 -5
- package/dist/execution/index.js +47 -5
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +2 -2
- package/dist/{index-DnBHrz2y.d.ts → index-pXJdVLe0.d.ts} +1 -1
- package/dist/{index-DAHEM_II.d.ts → index-ysfO_DlX.d.ts} +1 -1
- package/dist/index.d.ts +13 -13
- package/dist/index.js +635 -242
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +2 -2
- package/dist/infrastructure/index.js +2 -1
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +2 -2
- package/dist/{mcp-servers-BgINZzuo.d.ts → mcp-servers-BzB3r7_c.d.ts} +1 -1
- package/dist/{multi-agent-coordinator-CjG-FZKj.d.ts → multi-agent-coordinator-DOXSgtom.d.ts} +5 -1
- package/dist/{null-fleet-bus-B3WdVY9i.d.ts → null-fleet-bus-CAQDGsKc.d.ts} +59 -3
- package/dist/{plan-templates-BUP4o-ds.d.ts → plan-templates-BZMi-VpU.d.ts} +1 -1
- package/dist/sdd/index.d.ts +3 -3
- package/dist/sdd/index.js +40 -3
- package/dist/sdd/index.js.map +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/{tool-executor-D87-_5Of.d.ts → tool-executor-BAi4WI2d.d.ts} +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +2 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +76 -1
- package/dist/utils/index.js +171 -5
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID, randomBytes } from 'crypto';
|
|
2
|
-
import * as
|
|
2
|
+
import * as fsp6 from 'fs/promises';
|
|
3
3
|
import * as path4 from 'path';
|
|
4
|
+
import { isAbsolute, resolve } from 'path';
|
|
4
5
|
import { EventEmitter } from 'events';
|
|
5
6
|
|
|
6
7
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
@@ -11,16 +12,16 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
11
12
|
});
|
|
12
13
|
async function atomicWrite(targetPath, content, opts = {}) {
|
|
13
14
|
const dir = path4.dirname(targetPath);
|
|
14
|
-
await
|
|
15
|
+
await fsp6.mkdir(dir, { recursive: true });
|
|
15
16
|
const tmp = path4.join(dir, `.${path4.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
16
17
|
try {
|
|
17
18
|
if (typeof content === "string") {
|
|
18
|
-
await
|
|
19
|
+
await fsp6.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
19
20
|
} else {
|
|
20
|
-
await
|
|
21
|
+
await fsp6.writeFile(tmp, content, { flag: "wx" });
|
|
21
22
|
}
|
|
22
23
|
try {
|
|
23
|
-
const fh = await
|
|
24
|
+
const fh = await fsp6.open(tmp, "r+");
|
|
24
25
|
try {
|
|
25
26
|
await fh.sync();
|
|
26
27
|
} finally {
|
|
@@ -30,37 +31,37 @@ async function atomicWrite(targetPath, content, opts = {}) {
|
|
|
30
31
|
}
|
|
31
32
|
let mode;
|
|
32
33
|
try {
|
|
33
|
-
const
|
|
34
|
-
mode =
|
|
34
|
+
const stat4 = await fsp6.stat(targetPath);
|
|
35
|
+
mode = stat4.mode & 511;
|
|
35
36
|
} catch {
|
|
36
37
|
mode = opts.mode;
|
|
37
38
|
}
|
|
38
39
|
if (mode !== void 0) {
|
|
39
|
-
await
|
|
40
|
+
await fsp6.chmod(tmp, mode);
|
|
40
41
|
}
|
|
41
42
|
await renameWithRetry(tmp, targetPath);
|
|
42
43
|
} catch (err) {
|
|
43
44
|
try {
|
|
44
|
-
await
|
|
45
|
+
await fsp6.unlink(tmp);
|
|
45
46
|
} catch {
|
|
46
47
|
}
|
|
47
48
|
throw err;
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
async function ensureDir(dir) {
|
|
51
|
-
await
|
|
52
|
+
await fsp6.mkdir(dir, { recursive: true });
|
|
52
53
|
}
|
|
53
54
|
var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
|
|
54
55
|
async function renameWithRetry(from, to) {
|
|
55
56
|
if (process.platform !== "win32") {
|
|
56
|
-
await
|
|
57
|
+
await fsp6.rename(from, to);
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
const delays = [10, 25, 60, 120, 250];
|
|
60
61
|
let lastErr;
|
|
61
62
|
for (let i = 0; i <= delays.length; i++) {
|
|
62
63
|
try {
|
|
63
|
-
await
|
|
64
|
+
await fsp6.rename(from, to);
|
|
64
65
|
return;
|
|
65
66
|
} catch (err) {
|
|
66
67
|
lastErr = err;
|
|
@@ -68,15 +69,89 @@ async function renameWithRetry(from, to) {
|
|
|
68
69
|
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
69
70
|
throw err;
|
|
70
71
|
}
|
|
71
|
-
await new Promise((
|
|
72
|
+
await new Promise((resolve2) => setTimeout(resolve2, delays[i]));
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
throw lastErr;
|
|
75
76
|
}
|
|
77
|
+
|
|
78
|
+
// src/coordination/large-answer-store.ts
|
|
79
|
+
var LargeAnswerStore = class {
|
|
80
|
+
/**
|
|
81
|
+
* Responses above this size (in characters) are stored out-of-context.
|
|
82
|
+
* Below this, the full answer is returned inline (no overhead).
|
|
83
|
+
* Default: 2000 chars ≈ 400-600 tokens.
|
|
84
|
+
*/
|
|
85
|
+
sizeThreshold;
|
|
86
|
+
store = /* @__PURE__ */ new Map();
|
|
87
|
+
constructor(sizeThreshold = 2e3) {
|
|
88
|
+
this.sizeThreshold = sizeThreshold;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Store a value, returning a summary + key for inline use.
|
|
92
|
+
* If the value is below sizeThreshold, returns it as-is (no store entry).
|
|
93
|
+
*/
|
|
94
|
+
storeAnswer(value) {
|
|
95
|
+
if (value === void 0 || value === null) {
|
|
96
|
+
return { summary: String(value), inline: true };
|
|
97
|
+
}
|
|
98
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
99
|
+
const size = serialized.length;
|
|
100
|
+
if (size <= this.sizeThreshold) {
|
|
101
|
+
return { summary: serialized.slice(0, 500), inline: true };
|
|
102
|
+
}
|
|
103
|
+
const key = `a-${hashStr(serialized)}`;
|
|
104
|
+
this.store.set(key, {
|
|
105
|
+
key,
|
|
106
|
+
value,
|
|
107
|
+
size,
|
|
108
|
+
storedAt: Date.now()
|
|
109
|
+
});
|
|
110
|
+
return {
|
|
111
|
+
key,
|
|
112
|
+
summary: `[stored: ${size} chars \u2014 use roll_up or ask_result tool to retrieve, key=${key}]`,
|
|
113
|
+
inline: false
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Retrieve a previously stored answer by its key.
|
|
118
|
+
* Returns undefined if the key is unknown or the store was cleared.
|
|
119
|
+
*/
|
|
120
|
+
retrieveAnswer(key) {
|
|
121
|
+
return this.store.get(key)?.value;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Check if a key exists in the store.
|
|
125
|
+
*/
|
|
126
|
+
hasAnswer(key) {
|
|
127
|
+
return this.store.has(key);
|
|
128
|
+
}
|
|
129
|
+
/** Number of stored entries. */
|
|
130
|
+
get size() {
|
|
131
|
+
return this.store.size;
|
|
132
|
+
}
|
|
133
|
+
/** Total characters stored. */
|
|
134
|
+
get totalChars() {
|
|
135
|
+
let total = 0;
|
|
136
|
+
for (const e of this.store.values()) total += e.size;
|
|
137
|
+
return total;
|
|
138
|
+
}
|
|
139
|
+
/** Clear all stored entries. Call at the end of a director run. */
|
|
140
|
+
clear() {
|
|
141
|
+
this.store.clear();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
function hashStr(s) {
|
|
145
|
+
let h = 5381;
|
|
146
|
+
for (let i = 0; i < s.length; i++) {
|
|
147
|
+
h = h * 33 ^ s.charCodeAt(i);
|
|
148
|
+
}
|
|
149
|
+
return (h >>> 0).toString(36);
|
|
150
|
+
}
|
|
76
151
|
async function acquireDirectorStateLock(lockPath, processId = process.pid) {
|
|
77
152
|
let existing;
|
|
78
153
|
try {
|
|
79
|
-
existing = await
|
|
154
|
+
existing = await fsp6.readFile(lockPath, "utf8");
|
|
80
155
|
} catch {
|
|
81
156
|
}
|
|
82
157
|
if (existing) {
|
|
@@ -100,7 +175,7 @@ async function acquireDirectorStateLock(lockPath, processId = process.pid) {
|
|
|
100
175
|
}
|
|
101
176
|
async function releaseDirectorStateLock(lockPath) {
|
|
102
177
|
try {
|
|
103
|
-
await
|
|
178
|
+
await fsp6.unlink(lockPath);
|
|
104
179
|
} catch {
|
|
105
180
|
}
|
|
106
181
|
}
|
|
@@ -334,7 +409,7 @@ var InMemoryAgentBridge = class {
|
|
|
334
409
|
);
|
|
335
410
|
}
|
|
336
411
|
this.inflightGuards.add(correlationId);
|
|
337
|
-
return new Promise((
|
|
412
|
+
return new Promise((resolve2, reject) => {
|
|
338
413
|
const timer = setTimeout(() => {
|
|
339
414
|
this.inflightGuards.delete(correlationId);
|
|
340
415
|
this.pendingRequests.delete(correlationId);
|
|
@@ -346,7 +421,7 @@ var InMemoryAgentBridge = class {
|
|
|
346
421
|
return;
|
|
347
422
|
}
|
|
348
423
|
this.pendingRequests.set(correlationId, {
|
|
349
|
-
resolve,
|
|
424
|
+
resolve: resolve2,
|
|
350
425
|
reject,
|
|
351
426
|
timer
|
|
352
427
|
});
|
|
@@ -707,6 +782,10 @@ var NICKNAME_POOL = {
|
|
|
707
782
|
"pasteur": { name: "Pasteur", domain: "biology" },
|
|
708
783
|
"hawking": { name: "Hawking", domain: "cosmology" },
|
|
709
784
|
"sagan": { name: "Sagan", domain: "cosmology" },
|
|
785
|
+
// Exploration & navigation
|
|
786
|
+
"columbus": { name: "Columbus", domain: "exploration" },
|
|
787
|
+
"polo": { name: "Polo", domain: "exploration" },
|
|
788
|
+
"magellan": { name: "Magellan", domain: "exploration" },
|
|
710
789
|
// Chemistry / materials
|
|
711
790
|
"lavoisier": { name: "Lavoisier", domain: "chemistry" },
|
|
712
791
|
"mendeleev": { name: "Mendeleev", domain: "chemistry" }
|
|
@@ -1083,12 +1162,12 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
1083
1162
|
if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
|
|
1084
1163
|
return Promise.resolve("stop");
|
|
1085
1164
|
}
|
|
1086
|
-
return new Promise((
|
|
1165
|
+
return new Promise((resolve2) => {
|
|
1087
1166
|
let resolved = false;
|
|
1088
1167
|
const respond = (d) => {
|
|
1089
1168
|
if (resolved) return;
|
|
1090
1169
|
resolved = true;
|
|
1091
|
-
|
|
1170
|
+
resolve2(d);
|
|
1092
1171
|
};
|
|
1093
1172
|
const fallback = setTimeout(
|
|
1094
1173
|
() => respond("stop"),
|
|
@@ -3686,7 +3765,7 @@ var FLEET_ROSTER_WITHACP = {
|
|
|
3686
3765
|
};
|
|
3687
3766
|
|
|
3688
3767
|
// src/coordination/multi-agent-coordinator.ts
|
|
3689
|
-
var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
3768
|
+
var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends EventEmitter {
|
|
3690
3769
|
coordinatorId;
|
|
3691
3770
|
config;
|
|
3692
3771
|
runner;
|
|
@@ -3701,8 +3780,12 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
3701
3780
|
* names) to memorable ones here — that's what surfaces in the fleet monitor.
|
|
3702
3781
|
*/
|
|
3703
3782
|
usedNicknames = /* @__PURE__ */ new Set();
|
|
3783
|
+
/** Maps subagentId → nickname key (e.g. 'einstein'). Used to free the slot on remove(). */
|
|
3784
|
+
subagentNicknames = /* @__PURE__ */ new Map();
|
|
3704
3785
|
pendingTasks = [];
|
|
3705
3786
|
completedResults = [];
|
|
3787
|
+
/** Prevents completedResults from growing unbounded in long-running coordinators. */
|
|
3788
|
+
static MAX_COMPLETED_RESULTS = 1e4;
|
|
3706
3789
|
totalIterations = 0;
|
|
3707
3790
|
inFlight = 0;
|
|
3708
3791
|
/**
|
|
@@ -3757,7 +3840,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
3757
3840
|
* Explicit, human-chosen names — including nicknames already assigned by
|
|
3758
3841
|
* `Director.spawn()` — are left untouched, so this never double-assigns.
|
|
3759
3842
|
*/
|
|
3760
|
-
withNickname(subagent) {
|
|
3843
|
+
withNickname(subagent, subagentId) {
|
|
3761
3844
|
const role = subagent.role ?? "subagent";
|
|
3762
3845
|
const name = subagent.name?.trim() ?? "";
|
|
3763
3846
|
const isPlaceholder = name === "" || name.toLowerCase() === role.toLowerCase() || name === "subagent" || name === "adhoc" || name === "generic" || /^slot-/.test(name);
|
|
@@ -3765,11 +3848,12 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
3765
3848
|
const nickname = assignNickname(role, this.usedNicknames);
|
|
3766
3849
|
const baseKey = nickname.split(" ")[0].toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
3767
3850
|
this.usedNicknames.add(baseKey);
|
|
3851
|
+
this.subagentNicknames.set(subagentId, baseKey);
|
|
3768
3852
|
return { ...subagent, name: nickname };
|
|
3769
3853
|
}
|
|
3770
3854
|
async spawn(subagent) {
|
|
3771
|
-
subagent = this.withNickname(subagent);
|
|
3772
3855
|
const id = subagent.id || randomUUID();
|
|
3856
|
+
subagent = this.withNickname(subagent, id);
|
|
3773
3857
|
if (this.subagents.has(id)) {
|
|
3774
3858
|
throw new Error(`Subagent id "${id}" already exists \u2014 refusing to overwrite`);
|
|
3775
3859
|
}
|
|
@@ -3913,7 +3997,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
3913
3997
|
taskIds.map((id) => {
|
|
3914
3998
|
const cached = this.completedResults.find((r) => r.taskId === id);
|
|
3915
3999
|
if (cached) return cached;
|
|
3916
|
-
return new Promise((
|
|
4000
|
+
return new Promise((resolve2, reject) => {
|
|
3917
4001
|
const timeout = setTimeout(() => {
|
|
3918
4002
|
this.off("task.completed", handler);
|
|
3919
4003
|
reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
|
|
@@ -3922,7 +4006,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
3922
4006
|
if (result.taskId === id) {
|
|
3923
4007
|
clearTimeout(timeout);
|
|
3924
4008
|
this.off("task.completed", handler);
|
|
3925
|
-
|
|
4009
|
+
resolve2(result);
|
|
3926
4010
|
}
|
|
3927
4011
|
};
|
|
3928
4012
|
this.on("task.completed", handler);
|
|
@@ -4211,6 +4295,12 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
4211
4295
|
}
|
|
4212
4296
|
recordCompletion(result) {
|
|
4213
4297
|
this.completedResults.push(result);
|
|
4298
|
+
if (this.completedResults.length > _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS) {
|
|
4299
|
+
this.completedResults.splice(
|
|
4300
|
+
0,
|
|
4301
|
+
this.completedResults.length - _DefaultMultiAgentCoordinator.MAX_COMPLETED_RESULTS
|
|
4302
|
+
);
|
|
4303
|
+
}
|
|
4214
4304
|
this.totalIterations += result.iterations;
|
|
4215
4305
|
if (this.inFlight > 0) {
|
|
4216
4306
|
this.inFlight--;
|
|
@@ -4280,7 +4370,29 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
|
|
|
4280
4370
|
}
|
|
4281
4371
|
this.subagents.delete(subagentId);
|
|
4282
4372
|
this.terminating.delete(subagentId);
|
|
4373
|
+
const nicknameKey = this.subagentNicknames.get(subagentId);
|
|
4374
|
+
if (nicknameKey) {
|
|
4375
|
+
this.usedNicknames.delete(nicknameKey);
|
|
4376
|
+
this.subagentNicknames.delete(subagentId);
|
|
4377
|
+
}
|
|
4378
|
+
const orphaned = this.pendingTasks.filter((t) => t.subagentId === subagentId);
|
|
4283
4379
|
this.pendingTasks = this.pendingTasks.filter((t) => t.subagentId !== subagentId);
|
|
4380
|
+
for (const t of orphaned) {
|
|
4381
|
+
const synthetic = {
|
|
4382
|
+
subagentId,
|
|
4383
|
+
taskId: t.id,
|
|
4384
|
+
status: "stopped",
|
|
4385
|
+
error: {
|
|
4386
|
+
kind: "aborted_by_parent",
|
|
4387
|
+
message: `Subagent "${subagentId}" was removed while task "${t.id}" was pending`,
|
|
4388
|
+
retryable: false
|
|
4389
|
+
},
|
|
4390
|
+
iterations: 0,
|
|
4391
|
+
toolCalls: 0,
|
|
4392
|
+
durationMs: 0
|
|
4393
|
+
};
|
|
4394
|
+
this.recordCompletion(synthetic);
|
|
4395
|
+
}
|
|
4284
4396
|
this.fleetBus?.emit({
|
|
4285
4397
|
subagentId,
|
|
4286
4398
|
ts: Date.now(),
|
|
@@ -4528,9 +4640,12 @@ function makeSpawnTool(director, roster) {
|
|
|
4528
4640
|
provider: { type: "string", description: 'Provider id (e.g. "anthropic", "openai"). Defaults to the leader provider when omitted.' },
|
|
4529
4641
|
model: { type: "string", description: "Model id within the provider. Defaults to the leader model when omitted." },
|
|
4530
4642
|
systemPromptOverride: { type: "string", description: "Extra prompt text appended after the role-base prompt." },
|
|
4531
|
-
maxIterations: { type: "number" },
|
|
4532
|
-
maxToolCalls: { type: "number" },
|
|
4533
|
-
maxCostUsd: { type: "number" }
|
|
4643
|
+
maxIterations: { type: "number", minimum: 1 },
|
|
4644
|
+
maxToolCalls: { type: "number", minimum: 1 },
|
|
4645
|
+
maxCostUsd: { type: "number", minimum: 0 },
|
|
4646
|
+
timeoutMs: { type: "number", minimum: 1, description: "Hard wall-clock cap in milliseconds. Defaults to none (idle timeout is the default reaper)." },
|
|
4647
|
+
idleTimeoutMs: { type: "number", minimum: 1, description: "Idle timeout in ms: reap the subagent after this long with no activity. Resets on every iteration/tool call. Default is role/coordinator-specific." },
|
|
4648
|
+
maxTokens: { type: "number", minimum: 1, description: "Maximum total tokens (input + output) the subagent may use." }
|
|
4534
4649
|
},
|
|
4535
4650
|
required: []
|
|
4536
4651
|
};
|
|
@@ -4576,6 +4691,9 @@ function makeSpawnTool(director, roster) {
|
|
|
4576
4691
|
if (typeof i.maxIterations === "number") cfg.maxIterations = i.maxIterations;
|
|
4577
4692
|
if (typeof i.maxToolCalls === "number") cfg.maxToolCalls = i.maxToolCalls;
|
|
4578
4693
|
if (typeof i.maxCostUsd === "number") cfg.maxCostUsd = i.maxCostUsd;
|
|
4694
|
+
if (typeof i.timeoutMs === "number") cfg.timeoutMs = i.timeoutMs;
|
|
4695
|
+
if (typeof i.idleTimeoutMs === "number") cfg.idleTimeoutMs = i.idleTimeoutMs;
|
|
4696
|
+
if (typeof i.maxTokens === "number") cfg.maxTokens = i.maxTokens;
|
|
4579
4697
|
try {
|
|
4580
4698
|
const subagentId = await director.spawn(cfg);
|
|
4581
4699
|
return { subagentId, provider: cfg.provider, model: cfg.model, name: cfg.name, role: cfg.role };
|
|
@@ -4603,10 +4721,10 @@ function makeAssignTool(director) {
|
|
|
4603
4721
|
const inputSchema = {
|
|
4604
4722
|
type: "object",
|
|
4605
4723
|
properties: {
|
|
4606
|
-
subagentId: { type: "string", description: "Target subagent id. Required." },
|
|
4607
|
-
description: { type: "string", description: "The task in natural language \u2014 what you want this subagent to do." },
|
|
4608
|
-
maxToolCalls: { type: "number", description: "Optional per-task tool-call budget override." },
|
|
4609
|
-
timeoutMs: { type: "number", description: "Optional per-task timeout in ms." }
|
|
4724
|
+
subagentId: { type: "string", minLength: 1, description: "Target subagent id. Required." },
|
|
4725
|
+
description: { type: "string", minLength: 1, description: "The task in natural language \u2014 what you want this subagent to do." },
|
|
4726
|
+
maxToolCalls: { type: "number", minimum: 1, description: "Optional per-task tool-call budget override." },
|
|
4727
|
+
timeoutMs: { type: "number", minimum: 1, description: "Optional per-task timeout in ms." }
|
|
4610
4728
|
},
|
|
4611
4729
|
required: ["subagentId", "description"]
|
|
4612
4730
|
};
|
|
@@ -4647,9 +4765,9 @@ function makeAskTool(director) {
|
|
|
4647
4765
|
inputSchema: {
|
|
4648
4766
|
type: "object",
|
|
4649
4767
|
properties: {
|
|
4650
|
-
subagentId: { type: "string", description: "Subagent to ask. Must be a previously spawned id." },
|
|
4651
|
-
question: { type: "string", description: "The question or instruction." },
|
|
4652
|
-
timeoutMs: { type: "number", description: "Optional timeout in ms (default 30s)." }
|
|
4768
|
+
subagentId: { type: "string", minLength: 1, description: "Subagent to ask. Must be a previously spawned id." },
|
|
4769
|
+
question: { type: "string", minLength: 1, description: "The question or instruction." },
|
|
4770
|
+
timeoutMs: { type: "number", minimum: 1, description: "Optional timeout in ms (default 30s)." }
|
|
4653
4771
|
},
|
|
4654
4772
|
required: ["subagentId", "question"]
|
|
4655
4773
|
},
|
|
@@ -4657,13 +4775,49 @@ function makeAskTool(director) {
|
|
|
4657
4775
|
const i = input;
|
|
4658
4776
|
try {
|
|
4659
4777
|
const answer = await director.ask(i.subagentId, { question: i.question }, i.timeoutMs);
|
|
4660
|
-
|
|
4778
|
+
const stored = director.largeAnswerStore.storeAnswer(answer);
|
|
4779
|
+
if (stored.inline) {
|
|
4780
|
+
return { ok: true, answer: stored.summary };
|
|
4781
|
+
}
|
|
4782
|
+
return {
|
|
4783
|
+
ok: true,
|
|
4784
|
+
answer: stored.summary,
|
|
4785
|
+
_answerKey: stored.key,
|
|
4786
|
+
_hint: "Response was large and stored. Use ask_result with the key to retrieve it."
|
|
4787
|
+
};
|
|
4661
4788
|
} catch (err) {
|
|
4662
4789
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
4663
4790
|
}
|
|
4664
4791
|
}
|
|
4665
4792
|
};
|
|
4666
4793
|
}
|
|
4794
|
+
function makeAskResultTool(director) {
|
|
4795
|
+
return {
|
|
4796
|
+
name: "ask_result",
|
|
4797
|
+
description: "Retrieve a large `ask_subagent` response that was stored out-of-context (>2K chars). Returns the full stored value.",
|
|
4798
|
+
permission: "auto",
|
|
4799
|
+
mutating: false,
|
|
4800
|
+
inputSchema: {
|
|
4801
|
+
type: "object",
|
|
4802
|
+
properties: {
|
|
4803
|
+
key: {
|
|
4804
|
+
type: "string",
|
|
4805
|
+
minLength: 1,
|
|
4806
|
+
description: "The `_answerKey` returned by `ask_subagent` for a large response."
|
|
4807
|
+
}
|
|
4808
|
+
},
|
|
4809
|
+
required: ["key"]
|
|
4810
|
+
},
|
|
4811
|
+
async execute(input) {
|
|
4812
|
+
const i = input;
|
|
4813
|
+
const value = director.largeAnswerStore.retrieveAnswer(i.key);
|
|
4814
|
+
if (value === void 0) {
|
|
4815
|
+
return { ok: false, error: `No stored answer found for key "${i.key}" \u2014 it may have been cleared or the key is invalid.` };
|
|
4816
|
+
}
|
|
4817
|
+
return { ok: true, value };
|
|
4818
|
+
}
|
|
4819
|
+
};
|
|
4820
|
+
}
|
|
4667
4821
|
function makeRollUpTool(director) {
|
|
4668
4822
|
return {
|
|
4669
4823
|
name: "roll_up",
|
|
@@ -4817,6 +4971,7 @@ function makeCollabDebugTool(director) {
|
|
|
4817
4971
|
},
|
|
4818
4972
|
timeoutMs: {
|
|
4819
4973
|
type: "number",
|
|
4974
|
+
minimum: 1,
|
|
4820
4975
|
description: "Timeout in ms. Default: 600000 (10 minutes)."
|
|
4821
4976
|
}
|
|
4822
4977
|
},
|
|
@@ -4896,6 +5051,122 @@ function makeWorkCompleteTool(director) {
|
|
|
4896
5051
|
}
|
|
4897
5052
|
};
|
|
4898
5053
|
}
|
|
5054
|
+
var GLOB_CHARS = /* @__PURE__ */ new Set(["*", "?", "["]);
|
|
5055
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
5056
|
+
var SEP = IS_WINDOWS ? "\\" : "/";
|
|
5057
|
+
function isGlob(p) {
|
|
5058
|
+
for (const c of p) {
|
|
5059
|
+
if (GLOB_CHARS.has(c)) return true;
|
|
5060
|
+
}
|
|
5061
|
+
return false;
|
|
5062
|
+
}
|
|
5063
|
+
function globToRegex(pat) {
|
|
5064
|
+
let i = 0, re = "^";
|
|
5065
|
+
while (i < pat.length) {
|
|
5066
|
+
const c = pat[i];
|
|
5067
|
+
if (c === "*") {
|
|
5068
|
+
if (pat[i + 1] === "*") {
|
|
5069
|
+
re += ".*";
|
|
5070
|
+
i += 2;
|
|
5071
|
+
if (pat[i] === "/") i++;
|
|
5072
|
+
} else {
|
|
5073
|
+
re += "[^/\\\\]*";
|
|
5074
|
+
i++;
|
|
5075
|
+
}
|
|
5076
|
+
} else if (c === "?") {
|
|
5077
|
+
re += "[^/\\\\]";
|
|
5078
|
+
i++;
|
|
5079
|
+
} else if (c === "[") {
|
|
5080
|
+
let cls = "[";
|
|
5081
|
+
i++;
|
|
5082
|
+
if (pat[i] === "!" || pat[i] === "^") {
|
|
5083
|
+
cls += "^";
|
|
5084
|
+
i++;
|
|
5085
|
+
}
|
|
5086
|
+
while (i < pat.length && pat[i] !== "]") {
|
|
5087
|
+
const ch = pat[i] ?? "";
|
|
5088
|
+
if (ch === "\\") cls += "\\\\";
|
|
5089
|
+
else if (ch === "]" || ch === "^") cls += `\\${ch}`;
|
|
5090
|
+
else cls += ch;
|
|
5091
|
+
i++;
|
|
5092
|
+
}
|
|
5093
|
+
cls += "]";
|
|
5094
|
+
re += cls;
|
|
5095
|
+
i++;
|
|
5096
|
+
} else {
|
|
5097
|
+
re += c.replace(/[.+^${}()|\\]/g, "\\$&");
|
|
5098
|
+
i++;
|
|
5099
|
+
}
|
|
5100
|
+
}
|
|
5101
|
+
return new RegExp(re + "$");
|
|
5102
|
+
}
|
|
5103
|
+
function baseDir(pat) {
|
|
5104
|
+
let i = pat.length - 1;
|
|
5105
|
+
while (i >= 0 && !GLOB_CHARS.has(pat[i]) && pat[i] !== SEP && pat[i] !== "/") i--;
|
|
5106
|
+
const cut = i >= 0 ? pat.lastIndexOf(SEP, i) : pat.lastIndexOf("/", i);
|
|
5107
|
+
return cut < 0 ? "." : pat.slice(0, cut);
|
|
5108
|
+
}
|
|
5109
|
+
async function expandGlob(pattern) {
|
|
5110
|
+
if (!isGlob(pattern)) return [pattern];
|
|
5111
|
+
const results = /* @__PURE__ */ new Set();
|
|
5112
|
+
const abs = isAbsolute(pattern);
|
|
5113
|
+
const base = abs ? baseDir(pattern) : baseDir(pattern);
|
|
5114
|
+
const relPat = base === "." ? pattern : pattern.slice(base.length + 1);
|
|
5115
|
+
async function walk(dir, pat) {
|
|
5116
|
+
let entries;
|
|
5117
|
+
try {
|
|
5118
|
+
entries = await fsp6.readdir(dir);
|
|
5119
|
+
} catch {
|
|
5120
|
+
return;
|
|
5121
|
+
}
|
|
5122
|
+
const firstGlob = pat.search(/[*?[\[]/);
|
|
5123
|
+
if (firstGlob < 0) {
|
|
5124
|
+
const re = globToRegex(pat);
|
|
5125
|
+
for (const e of entries) {
|
|
5126
|
+
if (re.test(e)) {
|
|
5127
|
+
const full = `${dir}${SEP}${e}`;
|
|
5128
|
+
results.add(abs ? resolve(full) : full);
|
|
5129
|
+
}
|
|
5130
|
+
}
|
|
5131
|
+
return;
|
|
5132
|
+
}
|
|
5133
|
+
const before = pat.slice(0, firstGlob);
|
|
5134
|
+
const rest = pat.slice(firstGlob);
|
|
5135
|
+
if (before.endsWith("**")) {
|
|
5136
|
+
await walk(dir, rest);
|
|
5137
|
+
for (const e of entries) {
|
|
5138
|
+
const full = `${dir}${SEP}${e}`;
|
|
5139
|
+
try {
|
|
5140
|
+
const stat4 = await fsp6.stat(full);
|
|
5141
|
+
if (stat4.isDirectory()) await walk(full, rest);
|
|
5142
|
+
} catch {
|
|
5143
|
+
}
|
|
5144
|
+
}
|
|
5145
|
+
} else if (before === "") {
|
|
5146
|
+
const re = globToRegex(rest);
|
|
5147
|
+
for (const e of entries) {
|
|
5148
|
+
if (re.test(e)) {
|
|
5149
|
+
const full = `${dir}${SEP}${e}`;
|
|
5150
|
+
results.add(abs ? resolve(full) : full);
|
|
5151
|
+
}
|
|
5152
|
+
}
|
|
5153
|
+
} else {
|
|
5154
|
+
const seg = before.replace(/[*?[\]]/g, "").replace(/\/$/, "");
|
|
5155
|
+
if (entries.includes(seg)) {
|
|
5156
|
+
const full = `${dir}${SEP}${seg}`;
|
|
5157
|
+
try {
|
|
5158
|
+
const stat4 = await fsp6.stat(full);
|
|
5159
|
+
if (stat4.isDirectory()) await walk(full, rest);
|
|
5160
|
+
} catch {
|
|
5161
|
+
}
|
|
5162
|
+
}
|
|
5163
|
+
}
|
|
5164
|
+
}
|
|
5165
|
+
await walk(base === "." ? "." : base, relPat);
|
|
5166
|
+
return [...results];
|
|
5167
|
+
}
|
|
5168
|
+
|
|
5169
|
+
// src/coordination/collab-debug.ts
|
|
4899
5170
|
var DirectorAlertLevel = /* @__PURE__ */ ((DirectorAlertLevel2) => {
|
|
4900
5171
|
DirectorAlertLevel2["WARNING"] = "warning";
|
|
4901
5172
|
DirectorAlertLevel2["CRITICAL"] = "critical";
|
|
@@ -4960,9 +5231,9 @@ var CollabSession = class extends EventEmitter {
|
|
|
4960
5231
|
}
|
|
4961
5232
|
async buildSnapshot() {
|
|
4962
5233
|
if (this.snapshot.files.length > 0) return this.snapshot;
|
|
4963
|
-
for (const filePath of this.options.targetPaths) {
|
|
5234
|
+
for (const filePath of (await Promise.all(this.options.targetPaths.map((p) => expandGlob(p)))).flat()) {
|
|
4964
5235
|
try {
|
|
4965
|
-
const content = await
|
|
5236
|
+
const content = await fsp6.readFile(filePath, "utf8");
|
|
4966
5237
|
const ext = filePath.split(".").pop() ?? "";
|
|
4967
5238
|
const language = ext === "ts" || ext === "tsx" ? "typescript" : ext === "js" || ext === "jsx" ? "javascript" : ext === "md" ? "markdown" : ext === "json" ? "json" : void 0;
|
|
4968
5239
|
this.snapshot.files.push({ path: filePath, content, language });
|
|
@@ -5016,7 +5287,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
5016
5287
|
reject(new Error(`CollabSession timed out after ${this.timeoutMs}ms`));
|
|
5017
5288
|
}, this.timeoutMs);
|
|
5018
5289
|
});
|
|
5019
|
-
let results;
|
|
5290
|
+
let results = null;
|
|
5020
5291
|
try {
|
|
5021
5292
|
results = await Promise.race([
|
|
5022
5293
|
Promise.all([
|
|
@@ -5447,7 +5718,7 @@ var FleetContextOverflowError = class extends Error {
|
|
|
5447
5718
|
this.observed = observed;
|
|
5448
5719
|
}
|
|
5449
5720
|
};
|
|
5450
|
-
var Director = class {
|
|
5721
|
+
var Director = class _Director {
|
|
5451
5722
|
/** Alias for the ICoordinator contract. `id` is retained for backward compatibility. */
|
|
5452
5723
|
get coordinatorId() {
|
|
5453
5724
|
return this.id;
|
|
@@ -5505,6 +5776,8 @@ var Director = class {
|
|
|
5505
5776
|
* coordinator already fired the event — `awaitTasks(['t-1'])` after
|
|
5506
5777
|
* t-1 finished should resolve immediately, not hang. */
|
|
5507
5778
|
completed = /* @__PURE__ */ new Map();
|
|
5779
|
+
/** Prevents the completed Map from growing unbounded in long-running directors. */
|
|
5780
|
+
static MAX_COMPLETED = 1e4;
|
|
5508
5781
|
/** Per-subagent provider/model metadata, captured at spawn time so the
|
|
5509
5782
|
* FleetUsageAggregator's metaLookup can surface readable rows. */
|
|
5510
5783
|
subagentMeta = /* @__PURE__ */ new Map();
|
|
@@ -5584,6 +5857,8 @@ var Director = class {
|
|
|
5584
5857
|
_leaderBtwNotes = [];
|
|
5585
5858
|
/** Active collab sessions tracked by sessionId (see spawnCollab). */
|
|
5586
5859
|
_activeCollabSessions = /* @__PURE__ */ new Map();
|
|
5860
|
+
/** Prevents large `ask_subagent` answers from bloating the leader's context window. */
|
|
5861
|
+
largeAnswerStore;
|
|
5587
5862
|
constructor(opts) {
|
|
5588
5863
|
this.id = opts.config.coordinatorId || randomUUID();
|
|
5589
5864
|
this.manifestPath = opts.manifestPath;
|
|
@@ -5612,7 +5887,7 @@ var Director = class {
|
|
|
5612
5887
|
}, opts.checkpointDebounceMs ?? 250) : null;
|
|
5613
5888
|
this.fleetManager = opts.fleetManager;
|
|
5614
5889
|
if (this.sharedScratchpadPath) {
|
|
5615
|
-
void
|
|
5890
|
+
void fsp6.mkdir(this.sharedScratchpadPath, { recursive: true }).catch(
|
|
5616
5891
|
(err) => this.logShutdownError("shared_scratchpad_mkdir", err)
|
|
5617
5892
|
);
|
|
5618
5893
|
}
|
|
@@ -5644,6 +5919,11 @@ var Director = class {
|
|
|
5644
5919
|
this.taskCompletedListener = (payload) => {
|
|
5645
5920
|
const r = payload.result;
|
|
5646
5921
|
this.completed.set(r.taskId, r);
|
|
5922
|
+
if (this.completed.size > _Director.MAX_COMPLETED) {
|
|
5923
|
+
const toDelete = this.completed.size - _Director.MAX_COMPLETED;
|
|
5924
|
+
const keys = [...this.completed.keys()].slice(0, toDelete);
|
|
5925
|
+
for (const k of keys) this.completed.delete(k);
|
|
5926
|
+
}
|
|
5647
5927
|
const waiter = this.taskWaiters.get(r.taskId);
|
|
5648
5928
|
if (waiter) {
|
|
5649
5929
|
waiter.resolve(r);
|
|
@@ -5750,6 +6030,7 @@ var Director = class {
|
|
|
5750
6030
|
payload.extend(extra);
|
|
5751
6031
|
});
|
|
5752
6032
|
});
|
|
6033
|
+
this.largeAnswerStore = new LargeAnswerStore(2e3);
|
|
5753
6034
|
}
|
|
5754
6035
|
/**
|
|
5755
6036
|
* Record a granted budget extension and broadcast it on the FleetBus so
|
|
@@ -6115,7 +6396,7 @@ var Director = class {
|
|
|
6115
6396
|
})),
|
|
6116
6397
|
usage: this.usage.snapshot()
|
|
6117
6398
|
};
|
|
6118
|
-
await
|
|
6399
|
+
await fsp6.mkdir(path4.dirname(this.manifestPath), { recursive: true });
|
|
6119
6400
|
await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
|
|
6120
6401
|
return this.manifestPath;
|
|
6121
6402
|
}
|
|
@@ -6230,11 +6511,11 @@ var Director = class {
|
|
|
6230
6511
|
if (cached) return cached;
|
|
6231
6512
|
const existing = this.taskWaiters.get(id);
|
|
6232
6513
|
if (existing) return existing.promise;
|
|
6233
|
-
let
|
|
6514
|
+
let resolve2;
|
|
6234
6515
|
const promise = new Promise((res) => {
|
|
6235
|
-
|
|
6516
|
+
resolve2 = res;
|
|
6236
6517
|
});
|
|
6237
|
-
this.taskWaiters.set(id, { promise, resolve });
|
|
6518
|
+
this.taskWaiters.set(id, { promise, resolve: resolve2 });
|
|
6238
6519
|
return promise;
|
|
6239
6520
|
})
|
|
6240
6521
|
);
|
|
@@ -6247,7 +6528,24 @@ var Director = class {
|
|
|
6247
6528
|
}
|
|
6248
6529
|
async remove(subagentId) {
|
|
6249
6530
|
await this.coordinator.remove(subagentId);
|
|
6531
|
+
const bridge = this.subagentBridges.get(subagentId);
|
|
6532
|
+
if (bridge) {
|
|
6533
|
+
await bridge.stop();
|
|
6534
|
+
this.subagentBridges.delete(subagentId);
|
|
6535
|
+
}
|
|
6250
6536
|
this.usage.removeSubagent(subagentId);
|
|
6537
|
+
if (this.fleetManager) {
|
|
6538
|
+
this.fleetManager.removeSubagent(subagentId);
|
|
6539
|
+
} else {
|
|
6540
|
+
const entry = this.manifestEntries.get(subagentId);
|
|
6541
|
+
if (entry?.name) {
|
|
6542
|
+
const nicknameKey = entry.name.split(" ")[0].toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
6543
|
+
this._usedNicknames.delete(nicknameKey);
|
|
6544
|
+
}
|
|
6545
|
+
}
|
|
6546
|
+
this.manifestEntries.delete(subagentId);
|
|
6547
|
+
this.taskOwners.delete(subagentId);
|
|
6548
|
+
this.taskDescriptions.delete(subagentId);
|
|
6251
6549
|
}
|
|
6252
6550
|
status() {
|
|
6253
6551
|
const base = this.coordinator.getStatus();
|
|
@@ -6303,7 +6601,7 @@ var Director = class {
|
|
|
6303
6601
|
const filePath = path4.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
|
|
6304
6602
|
let raw;
|
|
6305
6603
|
try {
|
|
6306
|
-
raw = await
|
|
6604
|
+
raw = await fsp6.readFile(filePath, "utf8");
|
|
6307
6605
|
} catch {
|
|
6308
6606
|
return null;
|
|
6309
6607
|
}
|
|
@@ -6409,6 +6707,7 @@ var Director = class {
|
|
|
6409
6707
|
makeAssignTool(this),
|
|
6410
6708
|
makeAwaitTasksTool(this),
|
|
6411
6709
|
makeAskTool(this),
|
|
6710
|
+
makeAskResultTool(this),
|
|
6412
6711
|
makeRollUpTool(this),
|
|
6413
6712
|
makeTerminateTool(this),
|
|
6414
6713
|
makeTerminateAllTool(this),
|
|
@@ -6491,15 +6790,33 @@ function createDelegateTool(opts) {
|
|
|
6491
6790
|
},
|
|
6492
6791
|
timeoutMs: {
|
|
6493
6792
|
type: "number",
|
|
6793
|
+
minimum: 1,
|
|
6494
6794
|
description: `Wall-clock budget for this delegate in milliseconds. No hard cap \u2014 set as high as the task realistically needs (a monorepo audit can take hours, a single-file lint takes seconds). Default ${Math.round(defaultTimeoutMs / 1e3 / 60)} minutes.`
|
|
6495
6795
|
},
|
|
6496
6796
|
maxIterations: {
|
|
6497
6797
|
type: "number",
|
|
6798
|
+
minimum: 1,
|
|
6498
6799
|
description: "Maximum LLM iterations the subagent may take. Unset = use the role/coordinator default. Raise this for tasks with many tool-think-tool cycles (deep code analysis, multi-file refactors)."
|
|
6499
6800
|
},
|
|
6500
6801
|
maxToolCalls: {
|
|
6501
6802
|
type: "number",
|
|
6803
|
+
minimum: 1,
|
|
6502
6804
|
description: "Maximum number of tool invocations the subagent may make. Unset = use the role/coordinator default. Raise this for tasks that touch many files (large grep + read + report)."
|
|
6805
|
+
},
|
|
6806
|
+
idleTimeoutMs: {
|
|
6807
|
+
type: "number",
|
|
6808
|
+
minimum: 1,
|
|
6809
|
+
description: "Idle timeout in ms: reap the subagent after this long with no activity. Resets on every iteration/tool call. Unset = use the role/coordinator default."
|
|
6810
|
+
},
|
|
6811
|
+
maxTokens: {
|
|
6812
|
+
type: "number",
|
|
6813
|
+
minimum: 1,
|
|
6814
|
+
description: "Maximum total tokens (input + output) the subagent may use. Unset = use the role/coordinator default."
|
|
6815
|
+
},
|
|
6816
|
+
maxCostUsd: {
|
|
6817
|
+
type: "number",
|
|
6818
|
+
minimum: 0,
|
|
6819
|
+
description: "Maximum estimated USD cost the subagent may incur. Unset = use the role/coordinator default."
|
|
6503
6820
|
}
|
|
6504
6821
|
},
|
|
6505
6822
|
required: ["task"]
|
|
@@ -6557,12 +6874,21 @@ function createDelegateTool(opts) {
|
|
|
6557
6874
|
};
|
|
6558
6875
|
cfg = applyRosterBudget({ ...cfg, name: i.name });
|
|
6559
6876
|
}
|
|
6560
|
-
if (typeof i.maxIterations === "number"
|
|
6877
|
+
if (typeof i.maxIterations === "number") {
|
|
6561
6878
|
cfg.maxIterations = i.maxIterations;
|
|
6562
6879
|
}
|
|
6563
|
-
if (typeof i.maxToolCalls === "number"
|
|
6880
|
+
if (typeof i.maxToolCalls === "number") {
|
|
6564
6881
|
cfg.maxToolCalls = i.maxToolCalls;
|
|
6565
6882
|
}
|
|
6883
|
+
if (typeof i.idleTimeoutMs === "number") {
|
|
6884
|
+
cfg.idleTimeoutMs = i.idleTimeoutMs;
|
|
6885
|
+
}
|
|
6886
|
+
if (typeof i.maxTokens === "number") {
|
|
6887
|
+
cfg.maxTokens = i.maxTokens;
|
|
6888
|
+
}
|
|
6889
|
+
if (typeof i.maxCostUsd === "number") {
|
|
6890
|
+
cfg.maxCostUsd = i.maxCostUsd;
|
|
6891
|
+
}
|
|
6566
6892
|
const SUBAGENT_TIMEOUT_BUFFER_MS = opts.subagentTimeoutBufferMs ?? 6e4;
|
|
6567
6893
|
if (!cfg.timeoutMs) {
|
|
6568
6894
|
cfg.timeoutMs = Math.max(3e4, timeoutMs - SUBAGENT_TIMEOUT_BUFFER_MS);
|
|
@@ -6574,7 +6900,7 @@ function createDelegateTool(opts) {
|
|
|
6574
6900
|
subagentId
|
|
6575
6901
|
});
|
|
6576
6902
|
const dir = director;
|
|
6577
|
-
const result = await new Promise((
|
|
6903
|
+
const result = await new Promise((resolve2) => {
|
|
6578
6904
|
let settled = false;
|
|
6579
6905
|
let timer;
|
|
6580
6906
|
const finish = (value) => {
|
|
@@ -6584,7 +6910,7 @@ function createDelegateTool(opts) {
|
|
|
6584
6910
|
offTool();
|
|
6585
6911
|
offIter();
|
|
6586
6912
|
offProgress();
|
|
6587
|
-
|
|
6913
|
+
resolve2(value);
|
|
6588
6914
|
};
|
|
6589
6915
|
const arm = () => {
|
|
6590
6916
|
if (timer) clearTimeout(timer);
|
|
@@ -6731,7 +7057,7 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
6731
7057
|
candidates.push(path4.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
|
|
6732
7058
|
} else {
|
|
6733
7059
|
try {
|
|
6734
|
-
const entries = await
|
|
7060
|
+
const entries = await fsp6.readdir(opts.sessionsRoot, { withFileTypes: true });
|
|
6735
7061
|
for (const entry of entries) {
|
|
6736
7062
|
if (entry.isDirectory()) {
|
|
6737
7063
|
candidates.push(path4.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
|
|
@@ -6744,7 +7070,7 @@ async function readSubagentPartial(opts, subagentId) {
|
|
|
6744
7070
|
for (const file of candidates) {
|
|
6745
7071
|
let raw;
|
|
6746
7072
|
try {
|
|
6747
|
-
raw = await
|
|
7073
|
+
raw = await fsp6.readFile(file, "utf8");
|
|
6748
7074
|
} catch {
|
|
6749
7075
|
continue;
|
|
6750
7076
|
}
|
|
@@ -7063,7 +7389,7 @@ var DefaultSessionStore = class {
|
|
|
7063
7389
|
const file = path4.join(shardDir, `${id}.jsonl`);
|
|
7064
7390
|
let handle;
|
|
7065
7391
|
try {
|
|
7066
|
-
handle = await
|
|
7392
|
+
handle = await fsp6.open(file, "a", 384);
|
|
7067
7393
|
} catch (err) {
|
|
7068
7394
|
throw new Error(
|
|
7069
7395
|
`Failed to open session file: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -7087,7 +7413,7 @@ var DefaultSessionStore = class {
|
|
|
7087
7413
|
const data = await this.load(id);
|
|
7088
7414
|
let handle;
|
|
7089
7415
|
try {
|
|
7090
|
-
handle = await
|
|
7416
|
+
handle = await fsp6.open(file, "a", 384);
|
|
7091
7417
|
} catch (err) {
|
|
7092
7418
|
throw new Error(
|
|
7093
7419
|
`Failed to open session "${id}" for append: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -7116,7 +7442,7 @@ var DefaultSessionStore = class {
|
|
|
7116
7442
|
}
|
|
7117
7443
|
async load(id) {
|
|
7118
7444
|
const file = this.sessionPath(id, ".jsonl");
|
|
7119
|
-
const raw = await
|
|
7445
|
+
const raw = await fsp6.readFile(file, "utf8");
|
|
7120
7446
|
const lines = raw.split("\n").filter((l) => l.trim());
|
|
7121
7447
|
const events = [];
|
|
7122
7448
|
for (const line of lines) {
|
|
@@ -7151,7 +7477,7 @@ var DefaultSessionStore = class {
|
|
|
7151
7477
|
/** Recursively collect all session IDs from shard subdirectories. */
|
|
7152
7478
|
async collectSessionIds(dir) {
|
|
7153
7479
|
const ids = [];
|
|
7154
|
-
const entries = await
|
|
7480
|
+
const entries = await fsp6.readdir(dir, { withFileTypes: true });
|
|
7155
7481
|
for (const entry of entries) {
|
|
7156
7482
|
const full = path4.join(dir, entry.name);
|
|
7157
7483
|
if (entry.isDirectory()) {
|
|
@@ -7165,12 +7491,12 @@ var DefaultSessionStore = class {
|
|
|
7165
7491
|
async summaryFor(id) {
|
|
7166
7492
|
const manifest = this.sessionPath(id, ".summary.json");
|
|
7167
7493
|
try {
|
|
7168
|
-
const raw = await
|
|
7494
|
+
const raw = await fsp6.readFile(manifest, "utf8");
|
|
7169
7495
|
return JSON.parse(raw);
|
|
7170
7496
|
} catch {
|
|
7171
7497
|
const full = this.sessionPath(id, ".jsonl");
|
|
7172
|
-
const
|
|
7173
|
-
const summary = await this.summarize(id,
|
|
7498
|
+
const stat4 = await fsp6.stat(full);
|
|
7499
|
+
const summary = await this.summarize(id, stat4.mtime.toISOString());
|
|
7174
7500
|
await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
|
|
7175
7501
|
console.warn(
|
|
7176
7502
|
`[session-store] Failed to write manifest for "${id}":`,
|
|
@@ -7181,8 +7507,8 @@ var DefaultSessionStore = class {
|
|
|
7181
7507
|
}
|
|
7182
7508
|
}
|
|
7183
7509
|
async delete(id) {
|
|
7184
|
-
await
|
|
7185
|
-
await
|
|
7510
|
+
await fsp6.unlink(this.sessionPath(id, ".jsonl"));
|
|
7511
|
+
await fsp6.unlink(this.sessionPath(id, ".summary.json")).catch(() => void 0);
|
|
7186
7512
|
}
|
|
7187
7513
|
async clearHistory(id) {
|
|
7188
7514
|
await this.ensureShardDir(id);
|
|
@@ -7196,8 +7522,8 @@ var DefaultSessionStore = class {
|
|
|
7196
7522
|
provider: "unknown"
|
|
7197
7523
|
})}
|
|
7198
7524
|
`;
|
|
7199
|
-
await
|
|
7200
|
-
await
|
|
7525
|
+
await fsp6.writeFile(file, record, "utf8");
|
|
7526
|
+
await fsp6.unlink(meta).catch(() => void 0);
|
|
7201
7527
|
}
|
|
7202
7528
|
async summarize(id, mtime) {
|
|
7203
7529
|
try {
|
|
@@ -7383,7 +7709,7 @@ var FileSessionWriter = class {
|
|
|
7383
7709
|
`;
|
|
7384
7710
|
try {
|
|
7385
7711
|
if (this.filePath) {
|
|
7386
|
-
await
|
|
7712
|
+
await fsp6.writeFile(this.filePath, record, { flag: "a", mode: 384 });
|
|
7387
7713
|
}
|
|
7388
7714
|
} catch {
|
|
7389
7715
|
}
|
|
@@ -7476,7 +7802,7 @@ var FileSessionWriter = class {
|
|
|
7476
7802
|
}
|
|
7477
7803
|
async truncateToCheckpoint(targetPromptIndex) {
|
|
7478
7804
|
if (!this.filePath) return 0;
|
|
7479
|
-
const raw = await
|
|
7805
|
+
const raw = await fsp6.readFile(this.filePath, "utf8");
|
|
7480
7806
|
const lines = raw.split("\n");
|
|
7481
7807
|
const kept = [];
|
|
7482
7808
|
let removedCount = 0;
|
|
@@ -7514,13 +7840,13 @@ var FileSessionWriter = class {
|
|
|
7514
7840
|
}
|
|
7515
7841
|
const truncated = kept.join("\n");
|
|
7516
7842
|
const tmpPath = `${this.filePath}.rewind.tmp`;
|
|
7517
|
-
await
|
|
7843
|
+
await fsp6.writeFile(tmpPath, truncated + "\n", "utf8");
|
|
7518
7844
|
try {
|
|
7519
7845
|
await this.handle.close();
|
|
7520
|
-
await
|
|
7521
|
-
this.handle = await
|
|
7846
|
+
await fsp6.rename(tmpPath, this.filePath);
|
|
7847
|
+
this.handle = await fsp6.open(this.filePath, "a", 384);
|
|
7522
7848
|
} catch (err) {
|
|
7523
|
-
await
|
|
7849
|
+
await fsp6.unlink(tmpPath).catch(() => void 0);
|
|
7524
7850
|
throw err;
|
|
7525
7851
|
}
|
|
7526
7852
|
await this.append({
|
|
@@ -7546,7 +7872,7 @@ var FileSessionWriter = class {
|
|
|
7546
7872
|
provider: this.meta.provider ?? "unknown"
|
|
7547
7873
|
})}
|
|
7548
7874
|
`;
|
|
7549
|
-
await
|
|
7875
|
+
await fsp6.writeFile(this.filePath, record, "utf8");
|
|
7550
7876
|
}
|
|
7551
7877
|
/**
|
|
7552
7878
|
* Idea #1 — write an in-flight marker. The agent loop should call
|
|
@@ -7892,7 +8218,7 @@ var FleetManager = class {
|
|
|
7892
8218
|
})),
|
|
7893
8219
|
usage: this.usage.snapshot()
|
|
7894
8220
|
};
|
|
7895
|
-
await
|
|
8221
|
+
await fsp6.mkdir(path4.dirname(this.manifestPath), { recursive: true });
|
|
7896
8222
|
await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
|
|
7897
8223
|
return this.manifestPath;
|
|
7898
8224
|
}
|
|
@@ -8002,6 +8328,23 @@ var FleetManager = class {
|
|
|
8002
8328
|
}));
|
|
8003
8329
|
return { pending, live: [] };
|
|
8004
8330
|
}
|
|
8331
|
+
/**
|
|
8332
|
+
* Clean up all fleet-manager state associated with a removed subagent:
|
|
8333
|
+
* - Frees the nickname slot so the same name can be reused
|
|
8334
|
+
* - Removes any pending tasks for this subagent
|
|
8335
|
+
*/
|
|
8336
|
+
removeSubagent(subagentId) {
|
|
8337
|
+
const entry = this.manifestEntries.get(subagentId);
|
|
8338
|
+
if (entry?.name) {
|
|
8339
|
+
const nicknameKey = entry.name.split(" ")[0].toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
8340
|
+
this._usedNicknames.delete(nicknameKey);
|
|
8341
|
+
}
|
|
8342
|
+
for (const [taskId, task] of this.pendingTasks) {
|
|
8343
|
+
if (task.subagentId === subagentId) {
|
|
8344
|
+
this.pendingTasks.delete(taskId);
|
|
8345
|
+
}
|
|
8346
|
+
}
|
|
8347
|
+
}
|
|
8005
8348
|
/** Release all resources: clear the manifest debounce timer and dispose the usage aggregator. */
|
|
8006
8349
|
dispose() {
|
|
8007
8350
|
if (this.manifestTimer) {
|
|
@@ -8012,6 +8355,6 @@ var FleetManager = class {
|
|
|
8012
8355
|
}
|
|
8013
8356
|
};
|
|
8014
8357
|
|
|
8015
|
-
export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, BUG_HUNTER_AGENT, BUILD_AGENTS, BudgetExceededError, BudgetThresholdSignal, CollabSession, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, HEAVY_BUDGET, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, LIGHT_BUDGET, MEDIUM_BUDGET, META_AGENTS, NULL_FLEET_BUS, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, VERIFY_AGENTS, applyRosterBudget, attachAutoExtend, composeDirectorPrompt, composeSubagentPrompt, createDelegateTool, createMessage, dispatchAgent, getAgentDefinition, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, makeWorkCompleteTool, rosterSummaryFromConfigs, scoreAgents };
|
|
8358
|
+
export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, BUG_HUNTER_AGENT, BUILD_AGENTS, BudgetExceededError, BudgetThresholdSignal, CollabSession, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, HEAVY_BUDGET, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, LIGHT_BUDGET, LargeAnswerStore, MEDIUM_BUDGET, META_AGENTS, NULL_FLEET_BUS, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, VERIFY_AGENTS, applyRosterBudget, attachAutoExtend, composeDirectorPrompt, composeSubagentPrompt, createDelegateTool, createMessage, dispatchAgent, getAgentDefinition, makeAgentSubagentRunner, makeAskResultTool, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, makeWorkCompleteTool, rosterSummaryFromConfigs, scoreAgents };
|
|
8016
8359
|
//# sourceMappingURL=index.js.map
|
|
8017
8360
|
//# sourceMappingURL=index.js.map
|