@wrongstack/core 0.281.1 → 0.282.0
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-DyOSK2Wy.d.ts → agent-subagent-runner-Dksf0QVU.d.ts} +15 -4
- package/dist/{config-CN-vdDEI.d.ts → config-BCAEJicb.d.ts} +33 -1
- package/dist/coordination/index.d.ts +147 -48
- package/dist/coordination/index.js +1244 -274
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +18 -18
- package/dist/defaults/index.js +991 -173
- package/dist/defaults/index.js.map +1 -1
- package/dist/{director-state-BfeCUbmk.d.ts → director-state-B_GPa78Q.d.ts} +14 -0
- package/dist/{events-C5hLU0AT.d.ts → events-CovDylaH.d.ts} +2 -1
- package/dist/execution/index.d.ts +10 -10
- package/dist/execution/index.js +69 -3
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +4 -4
- package/dist/{global-mailbox-CHM1QkCi.d.ts → global-mailbox-CNfgvRw3.d.ts} +1 -1
- package/dist/{goal-store-BLGZq16t.d.ts → goal-store-CBd749M4.d.ts} +1 -1
- package/dist/hq/index.d.ts +4 -4
- package/dist/{index-C1E-_71T.d.ts → index-D5HB7WkV.d.ts} +4 -3
- package/dist/index.d.ts +3005 -2704
- package/dist/index.js +51869 -49930
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +3 -3
- package/dist/kernel/index.d.ts +7 -7
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-EKRAcJDi.d.ts → mcp-servers-DJYwZXyH.d.ts} +1 -1
- package/dist/models/index.d.ts +2 -2
- package/dist/models/index.js +111 -21
- package/dist/models/index.js.map +1 -1
- package/dist/{multi-agent-coordinator-IpHCuHUa.d.ts → multi-agent-coordinator-4DC31QWu.d.ts} +1 -1
- package/dist/{null-fleet-bus-ZBkKGR9j.d.ts → null-fleet-bus-DuvA8PIR.d.ts} +74 -6
- package/dist/observability/index.d.ts +1 -1
- package/dist/{parallel-eternal-engine-Cc2CNgmv.d.ts → parallel-eternal-engine-BwcA0bAt.d.ts} +4 -4
- package/dist/{pipeline-E7_jqGyV.d.ts → pipeline-DM-CPTUs.d.ts} +1 -1
- package/dist/{provider-model-resolve-KgIdiEQ6.d.ts → provider-model-resolve-hNUbewMd.d.ts} +1 -1
- package/dist/{provider-runner-DxWXNHL1.d.ts → provider-runner-Bz4GyUqo.d.ts} +1 -1
- package/dist/sdd/index.d.ts +6 -6
- package/dist/sdd/index.js +76 -2
- package/dist/sdd/index.js.map +1 -1
- package/dist/{session-event-bridge-vA2fLV58.d.ts → session-event-bridge-Bkp7ORfc.d.ts} +2 -2
- package/dist/skills/index.d.ts +84 -84
- package/dist/storage/index.d.ts +168 -168
- package/dist/storage/index.js +19 -7
- package/dist/storage/index.js.map +1 -1
- package/dist/{todos-checkpoint-B1QVkoa8.d.ts → todos-checkpoint-addCdQ9f.d.ts} +2 -2
- package/dist/{tool-executor-BWtYwuPI.d.ts → tool-executor-B3spV_Q6.d.ts} +7 -7
- package/dist/tools/index.d.ts +1 -1
- package/dist/types/index.d.ts +33 -33
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +113 -113
- package/dist/{worktree-manager-C6CIilTT.d.ts → worktree-manager-BBXdJq-Y.d.ts} +1 -1
- package/instructions/agents/reviewer.md +25 -0
- package/instructions/agents/verifier.md +24 -0
- package/instructions/coordination/director-preamble.md +24 -2
- package/instructions/coordination/subagent-baseline.md +8 -1
- package/package.json +1 -1
|
@@ -1855,6 +1855,34 @@ var BUILD_AGENTS = [
|
|
|
1855
1855
|
|
|
1856
1856
|
// src/coordination/agents/phase4-verify.ts
|
|
1857
1857
|
var VERIFY_AGENTS = [
|
|
1858
|
+
{
|
|
1859
|
+
config: {
|
|
1860
|
+
id: "verifier",
|
|
1861
|
+
name: "Verifier",
|
|
1862
|
+
role: "verifier",
|
|
1863
|
+
tools: [...TOOLS.inspect, "bash", "exec", "lint", "typecheck", "test", "git"],
|
|
1864
|
+
prompt: agentPrompt("verifier")
|
|
1865
|
+
},
|
|
1866
|
+
budget: HEAVY_BUDGET,
|
|
1867
|
+
capability: {
|
|
1868
|
+
phase: "verify",
|
|
1869
|
+
summary: "Independent verification gate: runs the relevant checks until they pass or returns exact failures that need another implementation pass.",
|
|
1870
|
+
keywords: [
|
|
1871
|
+
"verify",
|
|
1872
|
+
"verification",
|
|
1873
|
+
"quality gate",
|
|
1874
|
+
"prove it works",
|
|
1875
|
+
"run checks",
|
|
1876
|
+
"run tests until pass",
|
|
1877
|
+
"test pass",
|
|
1878
|
+
"green build",
|
|
1879
|
+
"typecheck",
|
|
1880
|
+
"lint",
|
|
1881
|
+
"regression check",
|
|
1882
|
+
"acceptance gate"
|
|
1883
|
+
]
|
|
1884
|
+
}
|
|
1885
|
+
},
|
|
1858
1886
|
{
|
|
1859
1887
|
config: {
|
|
1860
1888
|
id: "test",
|
|
@@ -2121,6 +2149,34 @@ var VERIFY_AGENTS = [
|
|
|
2121
2149
|
|
|
2122
2150
|
// src/coordination/agents/phase5-review.ts
|
|
2123
2151
|
var REVIEW_AGENTS = [
|
|
2152
|
+
{
|
|
2153
|
+
config: {
|
|
2154
|
+
id: "reviewer",
|
|
2155
|
+
name: "Reviewer",
|
|
2156
|
+
role: "reviewer",
|
|
2157
|
+
tools: [...TOOLS.inspect, "git"],
|
|
2158
|
+
prompt: agentPrompt("reviewer")
|
|
2159
|
+
},
|
|
2160
|
+
budget: MEDIUM_BUDGET,
|
|
2161
|
+
capability: {
|
|
2162
|
+
phase: "review",
|
|
2163
|
+
summary: "Independent AI reviewer: audits another agent's output, flags uncertainty, correlated-failure risk, and must-fix defects.",
|
|
2164
|
+
keywords: [
|
|
2165
|
+
"reviewer",
|
|
2166
|
+
"independent review",
|
|
2167
|
+
"ai review",
|
|
2168
|
+
"review agent",
|
|
2169
|
+
"quality review",
|
|
2170
|
+
"second opinion",
|
|
2171
|
+
"check another agent",
|
|
2172
|
+
"cross check",
|
|
2173
|
+
"uncertainty",
|
|
2174
|
+
"correlated error",
|
|
2175
|
+
"verify output",
|
|
2176
|
+
"quality control"
|
|
2177
|
+
]
|
|
2178
|
+
}
|
|
2179
|
+
},
|
|
2124
2180
|
{
|
|
2125
2181
|
config: {
|
|
2126
2182
|
id: "code-reviewer",
|
|
@@ -3977,6 +4033,28 @@ var FLEET_ROSTER_WITHACP = {
|
|
|
3977
4033
|
...Object.fromEntries(ACP_AGENTS.map((a) => [a.role, a]))
|
|
3978
4034
|
};
|
|
3979
4035
|
|
|
4036
|
+
// src/security/capabilities.ts
|
|
4037
|
+
var ToolCapabilities = {
|
|
4038
|
+
/** Can execute arbitrary commands in the user's shell (the `bash` tool). */
|
|
4039
|
+
SHELL_ARBITRARY: "shell.arbitrary",
|
|
4040
|
+
/** Can execute a restricted set of commands (the `exec` tool). */
|
|
4041
|
+
SHELL_RESTRICTED: "shell.restricted",
|
|
4042
|
+
/** Can run a restricted project formatter/linter-style command. */
|
|
4043
|
+
SHELL_EXEC: "shell.exec",
|
|
4044
|
+
/** Can write / modify / delete files inside the project. */
|
|
4045
|
+
FS_WRITE: "fs.write",
|
|
4046
|
+
/** Can write files outside the current project root (very high risk). */
|
|
4047
|
+
FS_WRITE_OUTSIDE_PROJECT: "fs.write.outside-project",
|
|
4048
|
+
/** Can spawn or manage subagents / multi-agent tasks. */
|
|
4049
|
+
SUBAGENT_SPAWN: "subagent.spawn",
|
|
4050
|
+
/** Can inspect fleet/subagent coordination state without mutating it. */
|
|
4051
|
+
COORDINATION_FLEET_READ: "coordination.fleet.read",
|
|
4052
|
+
/** Can read or write inter-agent mailbox messages. */
|
|
4053
|
+
COORDINATION_MAIL: "coordination.mail",
|
|
4054
|
+
/** Can install packages or run package managers with side effects. */
|
|
4055
|
+
PACKAGE_INSTALL: "package.install"
|
|
4056
|
+
};
|
|
4057
|
+
|
|
3980
4058
|
// src/coordination/delegate-tool.ts
|
|
3981
4059
|
function createDelegateTool(opts) {
|
|
3982
4060
|
const defaultTimeoutMs = opts.defaultTimeoutMs ?? 30 * 60 * 1e3;
|
|
@@ -4048,6 +4126,7 @@ function createDelegateTool(opts) {
|
|
|
4048
4126
|
usageHint: "Set `task` to a complete instruction. Either pick `role` from the roster (audit-log, bug-hunter, refactor-planner, security-scanner) or pass `name` to run a free-form coding agent. For non-trivial work, also pass `timeoutMs`, `maxIterations`, and `maxToolCalls`. Returns the subagent's `TaskResult` \u2014 including the textual `result`, iteration count, tool count, and duration. Auto-promotes the host into director mode on first call.",
|
|
4049
4127
|
permission: "auto",
|
|
4050
4128
|
mutating: false,
|
|
4129
|
+
capabilities: [ToolCapabilities.SUBAGENT_SPAWN],
|
|
4051
4130
|
inputSchema,
|
|
4052
4131
|
async execute(input) {
|
|
4053
4132
|
const sessionId = opts.directorRunId;
|
|
@@ -4647,9 +4726,24 @@ var DirectorStateCheckpoint = class {
|
|
|
4647
4726
|
recordTaskStatus(taskId, patch) {
|
|
4648
4727
|
this.snapshot = {
|
|
4649
4728
|
...this.snapshot,
|
|
4650
|
-
tasks: this.snapshot.tasks.map(
|
|
4651
|
-
|
|
4652
|
-
|
|
4729
|
+
tasks: this.snapshot.tasks.map((t) => t.taskId === taskId ? { ...t, ...patch } : t)
|
|
4730
|
+
};
|
|
4731
|
+
this.bumpUpdatedAt();
|
|
4732
|
+
this.schedule();
|
|
4733
|
+
}
|
|
4734
|
+
recordTaskWorktree(taskId, worktree) {
|
|
4735
|
+
const exists = this.snapshot.tasks.some((t) => t.taskId === taskId);
|
|
4736
|
+
this.snapshot = {
|
|
4737
|
+
...this.snapshot,
|
|
4738
|
+
tasks: exists ? this.snapshot.tasks.map((t) => t.taskId === taskId ? { ...t, worktree } : t) : [
|
|
4739
|
+
...this.snapshot.tasks,
|
|
4740
|
+
{
|
|
4741
|
+
taskId,
|
|
4742
|
+
subagentId: worktree.subagentId,
|
|
4743
|
+
status: "running",
|
|
4744
|
+
worktree
|
|
4745
|
+
}
|
|
4746
|
+
]
|
|
4653
4747
|
};
|
|
4654
4748
|
this.bumpUpdatedAt();
|
|
4655
4749
|
this.schedule();
|
|
@@ -4692,10 +4786,7 @@ var DirectorStateCheckpoint = class {
|
|
|
4692
4786
|
mode: 384
|
|
4693
4787
|
});
|
|
4694
4788
|
} catch (err) {
|
|
4695
|
-
console.warn(
|
|
4696
|
-
"[director-state] checkpoint write failed:",
|
|
4697
|
-
toErrorMessage(err)
|
|
4698
|
-
);
|
|
4789
|
+
console.warn("[director-state] checkpoint write failed:", toErrorMessage(err));
|
|
4699
4790
|
} finally {
|
|
4700
4791
|
this.writing = false;
|
|
4701
4792
|
if (this.rewriteRequested) {
|
|
@@ -4705,6 +4796,49 @@ var DirectorStateCheckpoint = class {
|
|
|
4705
4796
|
}
|
|
4706
4797
|
}
|
|
4707
4798
|
};
|
|
4799
|
+
|
|
4800
|
+
// src/coordination/director/director-errors.ts
|
|
4801
|
+
var FleetSpawnBudgetError = class extends Error {
|
|
4802
|
+
kind;
|
|
4803
|
+
limit;
|
|
4804
|
+
observed;
|
|
4805
|
+
constructor(kind, limit, observed, message) {
|
|
4806
|
+
const defaultMsg = kind === "max_spawns" ? `Director spawn budget exceeded: tried to spawn #${observed} but maxSpawns is ${limit}` : `Director spawn depth budget exceeded: this director is at depth ${observed} and maxSpawnDepth is ${limit}`;
|
|
4807
|
+
super(message ?? defaultMsg);
|
|
4808
|
+
this.name = "FleetSpawnBudgetError";
|
|
4809
|
+
this.kind = kind;
|
|
4810
|
+
this.limit = limit;
|
|
4811
|
+
this.observed = observed;
|
|
4812
|
+
}
|
|
4813
|
+
};
|
|
4814
|
+
var FleetCostCapError = class extends Error {
|
|
4815
|
+
kind;
|
|
4816
|
+
limit;
|
|
4817
|
+
observed;
|
|
4818
|
+
constructor(limit, observed) {
|
|
4819
|
+
super(
|
|
4820
|
+
`Director cost cap exceeded: total fleet spend ${observed.toFixed(4)} exceeds maxCostUsd ${limit.toFixed(4)}`
|
|
4821
|
+
);
|
|
4822
|
+
this.name = "FleetCostCapError";
|
|
4823
|
+
this.kind = "max_cost_usd";
|
|
4824
|
+
this.limit = limit;
|
|
4825
|
+
this.observed = observed;
|
|
4826
|
+
}
|
|
4827
|
+
};
|
|
4828
|
+
var FleetContextOverflowError = class extends Error {
|
|
4829
|
+
kind;
|
|
4830
|
+
limit;
|
|
4831
|
+
observed;
|
|
4832
|
+
constructor(limit, observed) {
|
|
4833
|
+
super(
|
|
4834
|
+
`Leader context overflow: leader has ${observed} tokens in flight (limit: ${limit}). Compact the leader context before spawning more subagents.`
|
|
4835
|
+
);
|
|
4836
|
+
this.name = "FleetContextOverflowError";
|
|
4837
|
+
this.kind = "max_context_load";
|
|
4838
|
+
this.limit = limit;
|
|
4839
|
+
this.observed = observed;
|
|
4840
|
+
}
|
|
4841
|
+
};
|
|
4708
4842
|
var textCache = /* @__PURE__ */ new Map();
|
|
4709
4843
|
var rootCandidates;
|
|
4710
4844
|
function readBundledInstructionText(relativePath) {
|
|
@@ -4929,32 +5063,57 @@ function makeLLMClassifier(complete) {
|
|
|
4929
5063
|
};
|
|
4930
5064
|
}
|
|
4931
5065
|
|
|
4932
|
-
// src/security/capabilities.ts
|
|
4933
|
-
var ToolCapabilities = {
|
|
4934
|
-
/** Can spawn or manage subagents / multi-agent tasks. */
|
|
4935
|
-
SUBAGENT_SPAWN: "subagent.spawn",
|
|
4936
|
-
/** Can inspect fleet/subagent coordination state without mutating it. */
|
|
4937
|
-
COORDINATION_FLEET_READ: "coordination.fleet.read",
|
|
4938
|
-
/** Can read or write inter-agent mailbox messages. */
|
|
4939
|
-
COORDINATION_MAIL: "coordination.mail"};
|
|
4940
|
-
|
|
4941
5066
|
// src/coordination/director-tools.ts
|
|
4942
5067
|
function makeSpawnTool(director, roster) {
|
|
4943
5068
|
const inputSchema = {
|
|
4944
5069
|
type: "object",
|
|
4945
5070
|
properties: {
|
|
4946
|
-
role: {
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
5071
|
+
role: {
|
|
5072
|
+
type: "string",
|
|
5073
|
+
description: "Roster role id. When set, the spawn uses the matching config from the roster and ignores other fields."
|
|
5074
|
+
},
|
|
5075
|
+
description: {
|
|
5076
|
+
type: "string",
|
|
5077
|
+
description: "Free-form task description. When `role` is not set, the director uses the smart dispatcher to route this to the best-matching catalog agent. Use this when you don't know the exact role name."
|
|
5078
|
+
},
|
|
5079
|
+
name: {
|
|
5080
|
+
type: "string",
|
|
5081
|
+
description: "Display name for the subagent. Used as a fallback when description-based dispatch does not resolve a role."
|
|
5082
|
+
},
|
|
5083
|
+
provider: {
|
|
5084
|
+
type: "string",
|
|
5085
|
+
description: 'Provider id (e.g. "anthropic", "openai"). Defaults to the leader provider when omitted.'
|
|
5086
|
+
},
|
|
5087
|
+
model: {
|
|
5088
|
+
type: "string",
|
|
5089
|
+
description: "Model id within the provider. Defaults to the leader model when omitted."
|
|
5090
|
+
},
|
|
5091
|
+
systemPromptOverride: {
|
|
5092
|
+
type: "string",
|
|
5093
|
+
description: "Extra prompt text appended after the role-base prompt."
|
|
5094
|
+
},
|
|
4952
5095
|
maxIterations: { type: "number", minimum: 1 },
|
|
4953
5096
|
maxToolCalls: { type: "number", minimum: 1 },
|
|
4954
5097
|
maxCostUsd: { type: "number", minimum: 0 },
|
|
4955
|
-
timeoutMs: {
|
|
4956
|
-
|
|
4957
|
-
|
|
5098
|
+
timeoutMs: {
|
|
5099
|
+
type: "number",
|
|
5100
|
+
minimum: 1,
|
|
5101
|
+
description: "Hard wall-clock cap in milliseconds. Defaults to none (idle timeout is the default reaper)."
|
|
5102
|
+
},
|
|
5103
|
+
idleTimeoutMs: {
|
|
5104
|
+
type: "number",
|
|
5105
|
+
minimum: 1,
|
|
5106
|
+
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."
|
|
5107
|
+
},
|
|
5108
|
+
maxTokens: {
|
|
5109
|
+
type: "number",
|
|
5110
|
+
minimum: 1,
|
|
5111
|
+
description: "Maximum total tokens (input + output) the subagent may use."
|
|
5112
|
+
},
|
|
5113
|
+
worktree: {
|
|
5114
|
+
anyOf: [{ type: "boolean" }, { type: "string", enum: ["auto", "required", "off"] }],
|
|
5115
|
+
description: 'Git-worktree isolation override. true/"required" requires an isolated worktree; false/"off" disables it; "auto" follows fleet policy.'
|
|
5116
|
+
}
|
|
4958
5117
|
},
|
|
4959
5118
|
required: []
|
|
4960
5119
|
};
|
|
@@ -4973,7 +5132,8 @@ function makeSpawnTool(director, roster) {
|
|
|
4973
5132
|
let cfg;
|
|
4974
5133
|
if (role && roster) {
|
|
4975
5134
|
const base = roster[role];
|
|
4976
|
-
if (!base)
|
|
5135
|
+
if (!base)
|
|
5136
|
+
return { error: `unknown role "${role}". roster has: ${Object.keys(roster).join(", ")}` };
|
|
4977
5137
|
cfg = instantiateRosterConfig2(role, base);
|
|
4978
5138
|
} else if (description && !role) {
|
|
4979
5139
|
const dispatchResult = await dispatchAgent(description, {
|
|
@@ -4997,16 +5157,26 @@ function makeSpawnTool(director, roster) {
|
|
|
4997
5157
|
if (typeof i.name === "string") cfg.name = i.name;
|
|
4998
5158
|
if (typeof i.provider === "string") cfg.provider = i.provider;
|
|
4999
5159
|
if (typeof i.model === "string") cfg.model = i.model;
|
|
5000
|
-
if (typeof i.systemPromptOverride === "string")
|
|
5160
|
+
if (typeof i.systemPromptOverride === "string")
|
|
5161
|
+
cfg.systemPromptOverride = i.systemPromptOverride;
|
|
5001
5162
|
if (typeof i.maxIterations === "number") cfg.maxIterations = i.maxIterations;
|
|
5002
5163
|
if (typeof i.maxToolCalls === "number") cfg.maxToolCalls = i.maxToolCalls;
|
|
5003
5164
|
if (typeof i.maxCostUsd === "number") cfg.maxCostUsd = i.maxCostUsd;
|
|
5004
5165
|
if (typeof i.timeoutMs === "number") cfg.timeoutMs = i.timeoutMs;
|
|
5005
5166
|
if (typeof i.idleTimeoutMs === "number") cfg.idleTimeoutMs = i.idleTimeoutMs;
|
|
5006
5167
|
if (typeof i.maxTokens === "number") cfg.maxTokens = i.maxTokens;
|
|
5168
|
+
if (typeof i.worktree === "boolean" || i.worktree === "auto" || i.worktree === "required" || i.worktree === "off") {
|
|
5169
|
+
cfg.worktree = i.worktree;
|
|
5170
|
+
}
|
|
5007
5171
|
try {
|
|
5008
5172
|
const subagentId = await director.spawn(cfg);
|
|
5009
|
-
return {
|
|
5173
|
+
return {
|
|
5174
|
+
subagentId,
|
|
5175
|
+
provider: cfg.provider,
|
|
5176
|
+
model: cfg.model,
|
|
5177
|
+
name: cfg.name,
|
|
5178
|
+
role: cfg.role
|
|
5179
|
+
};
|
|
5010
5180
|
} catch (err) {
|
|
5011
5181
|
if (err instanceof FleetSpawnBudgetError) {
|
|
5012
5182
|
return { error: err.message, kind: err.kind, limit: err.limit, observed: err.observed };
|
|
@@ -5027,13 +5197,402 @@ function instantiateRosterConfig2(role, base) {
|
|
|
5027
5197
|
id: `${role}-${randomUUID().slice(0, 8)}`
|
|
5028
5198
|
};
|
|
5029
5199
|
}
|
|
5200
|
+
function makeQualityGateTool(director, roster) {
|
|
5201
|
+
return {
|
|
5202
|
+
name: "quality_gate",
|
|
5203
|
+
description: "Run a first-class implementation quality gate. It can await implementer task ids, spawn independent verifier/reviewer agents, summarize their verdicts, and optionally send must-fix feedback back to an implementer until the gate passes or the repair-attempt limit is reached.",
|
|
5204
|
+
usageHint: "Use after code-changing work. Provide implementerTaskIds when available. Add repairSubagentId to iterate fixes automatically. Verdict only passes when every enabled reviewer/verifier explicitly passes.",
|
|
5205
|
+
permission: "auto",
|
|
5206
|
+
mutating: false,
|
|
5207
|
+
capabilities: [ToolCapabilities.SUBAGENT_SPAWN],
|
|
5208
|
+
inputSchema: {
|
|
5209
|
+
type: "object",
|
|
5210
|
+
properties: {
|
|
5211
|
+
task: {
|
|
5212
|
+
type: "string",
|
|
5213
|
+
description: "Original implementation task or acceptance goal being gated."
|
|
5214
|
+
},
|
|
5215
|
+
implementerTaskIds: {
|
|
5216
|
+
type: "array",
|
|
5217
|
+
items: { type: "string" },
|
|
5218
|
+
description: "Optional completed or in-flight implementer task ids to await and include as implementation evidence."
|
|
5219
|
+
},
|
|
5220
|
+
repairSubagentId: {
|
|
5221
|
+
type: "string",
|
|
5222
|
+
description: "Optional implementer subagent id. When set and the gate fails, quality_gate assigns a repair task with reviewer/verifier feedback and reruns the gate."
|
|
5223
|
+
},
|
|
5224
|
+
maxRepairAttempts: {
|
|
5225
|
+
type: "number",
|
|
5226
|
+
minimum: 0,
|
|
5227
|
+
maximum: 5,
|
|
5228
|
+
description: "Maximum automatic repair iterations. Default: 2 when repairSubagentId is set, otherwise 0."
|
|
5229
|
+
},
|
|
5230
|
+
targets: {
|
|
5231
|
+
type: "array",
|
|
5232
|
+
items: { type: "string" },
|
|
5233
|
+
description: "Files, packages, or paths that reviewer/verifier should focus on."
|
|
5234
|
+
},
|
|
5235
|
+
commands: {
|
|
5236
|
+
type: "array",
|
|
5237
|
+
items: { type: "string" },
|
|
5238
|
+
description: 'Verification commands that should pass, e.g. ["pnpm --filter @wrongstack/core typecheck"].'
|
|
5239
|
+
},
|
|
5240
|
+
expected: {
|
|
5241
|
+
type: "string",
|
|
5242
|
+
description: "Expected behavior or acceptance criteria."
|
|
5243
|
+
},
|
|
5244
|
+
evidence: {
|
|
5245
|
+
type: "string",
|
|
5246
|
+
description: "Known implementation notes, diff summary, or commands already run."
|
|
5247
|
+
},
|
|
5248
|
+
reviewer: {
|
|
5249
|
+
type: "boolean",
|
|
5250
|
+
description: "Whether to run the reviewer lane. Default true."
|
|
5251
|
+
},
|
|
5252
|
+
verifier: {
|
|
5253
|
+
type: "boolean",
|
|
5254
|
+
description: "Whether to run the verifier lane. Default true."
|
|
5255
|
+
},
|
|
5256
|
+
timeoutMs: {
|
|
5257
|
+
type: "number",
|
|
5258
|
+
minimum: 1,
|
|
5259
|
+
description: "Optional per reviewer/verifier/repair task timeout."
|
|
5260
|
+
},
|
|
5261
|
+
reviewerWorktree: {
|
|
5262
|
+
anyOf: [{ type: "boolean" }, { type: "string", enum: ["auto", "required", "off"] }],
|
|
5263
|
+
description: "Reviewer worktree override. Default off because reviewer is read-only."
|
|
5264
|
+
},
|
|
5265
|
+
verifierWorktree: {
|
|
5266
|
+
anyOf: [{ type: "boolean" }, { type: "string", enum: ["auto", "required", "off"] }],
|
|
5267
|
+
description: "Verifier worktree override. Default auto so test artifacts stay isolated when fleet policy wants it."
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
},
|
|
5271
|
+
async execute(input) {
|
|
5272
|
+
const i = normalizeQualityGateInput(input);
|
|
5273
|
+
const runReviewer = i.reviewer !== false;
|
|
5274
|
+
const runVerifier = i.verifier !== false;
|
|
5275
|
+
if (!runReviewer && !runVerifier) {
|
|
5276
|
+
return {
|
|
5277
|
+
verdict: "inconclusive",
|
|
5278
|
+
passed: false,
|
|
5279
|
+
error: "quality_gate requires reviewer, verifier, or both."
|
|
5280
|
+
};
|
|
5281
|
+
}
|
|
5282
|
+
const implementerResults = i.implementerTaskIds && i.implementerTaskIds.length > 0 ? await director.awaitTasks(i.implementerTaskIds) : [];
|
|
5283
|
+
const maxRepairAttempts = clampRepairAttempts(
|
|
5284
|
+
i.maxRepairAttempts ?? (i.repairSubagentId ? 2 : 0)
|
|
5285
|
+
);
|
|
5286
|
+
const repairResults = [];
|
|
5287
|
+
const attempts = [];
|
|
5288
|
+
for (let attempt = 1; ; attempt++) {
|
|
5289
|
+
const gateTaskIds = [];
|
|
5290
|
+
const taskRoleById = /* @__PURE__ */ new Map();
|
|
5291
|
+
if (runVerifier) {
|
|
5292
|
+
const subagentId = await director.spawn(
|
|
5293
|
+
makeQualityGateSubagentConfig("verifier", roster, i.verifierWorktree ?? "auto")
|
|
5294
|
+
);
|
|
5295
|
+
const taskId = await director.assign({
|
|
5296
|
+
id: randomUUID(),
|
|
5297
|
+
subagentId,
|
|
5298
|
+
description: buildVerifierTask(i, {
|
|
5299
|
+
attempt,
|
|
5300
|
+
implementerResults,
|
|
5301
|
+
repairResults,
|
|
5302
|
+
priorAttempts: attempts
|
|
5303
|
+
}),
|
|
5304
|
+
timeoutMs: i.timeoutMs
|
|
5305
|
+
});
|
|
5306
|
+
gateTaskIds.push(taskId);
|
|
5307
|
+
taskRoleById.set(taskId, "verifier");
|
|
5308
|
+
}
|
|
5309
|
+
if (runReviewer) {
|
|
5310
|
+
const subagentId = await director.spawn(
|
|
5311
|
+
makeQualityGateSubagentConfig("reviewer", roster, i.reviewerWorktree ?? "off")
|
|
5312
|
+
);
|
|
5313
|
+
const taskId = await director.assign({
|
|
5314
|
+
id: randomUUID(),
|
|
5315
|
+
subagentId,
|
|
5316
|
+
description: buildReviewerTask(i, {
|
|
5317
|
+
attempt,
|
|
5318
|
+
implementerResults,
|
|
5319
|
+
repairResults,
|
|
5320
|
+
priorAttempts: attempts
|
|
5321
|
+
}),
|
|
5322
|
+
timeoutMs: i.timeoutMs
|
|
5323
|
+
});
|
|
5324
|
+
gateTaskIds.push(taskId);
|
|
5325
|
+
taskRoleById.set(taskId, "reviewer");
|
|
5326
|
+
}
|
|
5327
|
+
const gateResults = await director.awaitTasks(gateTaskIds);
|
|
5328
|
+
const reports = gateResults.map((r) => assessRoleResult(taskRoleById.get(r.taskId), r));
|
|
5329
|
+
const assessment = assessQualityGate(reports);
|
|
5330
|
+
attempts.push({ attempt, reports, ...assessment });
|
|
5331
|
+
if (assessment.passed || !i.repairSubagentId || attempt > maxRepairAttempts) {
|
|
5332
|
+
return {
|
|
5333
|
+
verdict: assessment.verdict,
|
|
5334
|
+
passed: assessment.passed,
|
|
5335
|
+
attempts,
|
|
5336
|
+
repairAttemptsUsed: repairResults.length,
|
|
5337
|
+
implementerResults: implementerResults.map(summarizeTaskResult),
|
|
5338
|
+
nextAction: assessment.passed ? "accept" : i.repairSubagentId && attempt > maxRepairAttempts ? "manual_intervention_or_raise_repair_limit" : "inspect_failures"
|
|
5339
|
+
};
|
|
5340
|
+
}
|
|
5341
|
+
const repairTaskId = await director.assign({
|
|
5342
|
+
id: randomUUID(),
|
|
5343
|
+
subagentId: i.repairSubagentId,
|
|
5344
|
+
description: buildRepairTask(i, attempts[attempts.length - 1], attempt),
|
|
5345
|
+
timeoutMs: i.timeoutMs
|
|
5346
|
+
});
|
|
5347
|
+
const [repairResult] = await director.awaitTasks([repairTaskId]);
|
|
5348
|
+
if (repairResult) repairResults.push(repairResult);
|
|
5349
|
+
if (repairResult?.status !== "success") {
|
|
5350
|
+
return {
|
|
5351
|
+
verdict: "fail",
|
|
5352
|
+
passed: false,
|
|
5353
|
+
attempts,
|
|
5354
|
+
repairAttemptsUsed: repairResults.length,
|
|
5355
|
+
repairResult: repairResult ? summarizeTaskResult(repairResult) : void 0,
|
|
5356
|
+
implementerResults: implementerResults.map(summarizeTaskResult),
|
|
5357
|
+
nextAction: "repair_failed"
|
|
5358
|
+
};
|
|
5359
|
+
}
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
};
|
|
5363
|
+
}
|
|
5364
|
+
function normalizeQualityGateInput(input) {
|
|
5365
|
+
const raw = input ?? {};
|
|
5366
|
+
return {
|
|
5367
|
+
task: typeof raw.task === "string" ? raw.task : void 0,
|
|
5368
|
+
implementerTaskIds: stringArray(raw.implementerTaskIds),
|
|
5369
|
+
repairSubagentId: typeof raw.repairSubagentId === "string" && raw.repairSubagentId.trim() ? raw.repairSubagentId.trim() : void 0,
|
|
5370
|
+
maxRepairAttempts: typeof raw.maxRepairAttempts === "number" ? raw.maxRepairAttempts : void 0,
|
|
5371
|
+
targets: stringArray(raw.targets),
|
|
5372
|
+
commands: stringArray(raw.commands),
|
|
5373
|
+
expected: typeof raw.expected === "string" ? raw.expected : void 0,
|
|
5374
|
+
evidence: typeof raw.evidence === "string" ? raw.evidence : void 0,
|
|
5375
|
+
reviewer: typeof raw.reviewer === "boolean" ? raw.reviewer : void 0,
|
|
5376
|
+
verifier: typeof raw.verifier === "boolean" ? raw.verifier : void 0,
|
|
5377
|
+
timeoutMs: typeof raw.timeoutMs === "number" ? raw.timeoutMs : void 0,
|
|
5378
|
+
reviewerWorktree: normalizeWorktreeOverride(raw.reviewerWorktree),
|
|
5379
|
+
verifierWorktree: normalizeWorktreeOverride(raw.verifierWorktree)
|
|
5380
|
+
};
|
|
5381
|
+
}
|
|
5382
|
+
function stringArray(value) {
|
|
5383
|
+
if (!Array.isArray(value)) return void 0;
|
|
5384
|
+
const strings = value.filter((v) => typeof v === "string" && v.trim().length > 0);
|
|
5385
|
+
return strings.length > 0 ? strings : void 0;
|
|
5386
|
+
}
|
|
5387
|
+
function normalizeWorktreeOverride(value) {
|
|
5388
|
+
if (typeof value === "boolean") return value;
|
|
5389
|
+
if (value === "auto" || value === "required" || value === "off") return value;
|
|
5390
|
+
return void 0;
|
|
5391
|
+
}
|
|
5392
|
+
function clampRepairAttempts(value) {
|
|
5393
|
+
if (!Number.isFinite(value)) return 0;
|
|
5394
|
+
return Math.max(0, Math.min(5, Math.floor(value)));
|
|
5395
|
+
}
|
|
5396
|
+
function makeQualityGateSubagentConfig(role, roster, worktree) {
|
|
5397
|
+
const base = roster?.[role] ?? getAgentDefinition(role)?.config ?? { name: role, role };
|
|
5398
|
+
return {
|
|
5399
|
+
...instantiateRosterConfig2(role, base),
|
|
5400
|
+
worktree
|
|
5401
|
+
};
|
|
5402
|
+
}
|
|
5403
|
+
function buildVerifierTask(input, state) {
|
|
5404
|
+
return [
|
|
5405
|
+
"Run the independent verification gate for this implementation.",
|
|
5406
|
+
"Return Markdown with `## Verdict` and make the first verdict word exactly `pass`, `fail`, or `blocked`.",
|
|
5407
|
+
"Do not edit code. Run the smallest meaningful command set and include exact failures.",
|
|
5408
|
+
"",
|
|
5409
|
+
`Gate attempt: ${state.attempt}`,
|
|
5410
|
+
input.task ? `Original task:
|
|
5411
|
+
${input.task}` : void 0,
|
|
5412
|
+
input.targets?.length ? `Targets:
|
|
5413
|
+
${input.targets.map((t) => `- ${t}`).join("\n")}` : void 0,
|
|
5414
|
+
input.commands?.length ? `Required or suggested commands:
|
|
5415
|
+
${input.commands.map((c) => `- ${c}`).join("\n")}` : void 0,
|
|
5416
|
+
input.expected ? `Expected behavior:
|
|
5417
|
+
${input.expected}` : void 0,
|
|
5418
|
+
input.evidence ? `Known evidence:
|
|
5419
|
+
${input.evidence}` : void 0,
|
|
5420
|
+
taskResultsBlock("Implementer results", state.implementerResults),
|
|
5421
|
+
taskResultsBlock("Repair results so far", state.repairResults),
|
|
5422
|
+
priorAttemptsBlock(state.priorAttempts)
|
|
5423
|
+
].filter((part) => !!part).join("\n\n");
|
|
5424
|
+
}
|
|
5425
|
+
function buildReviewerTask(input, state) {
|
|
5426
|
+
return [
|
|
5427
|
+
"Run independent code review for this implementation.",
|
|
5428
|
+
"Return Markdown with `## Verdict` and make the first verdict phrase exactly `approve`, `request changes`, or `needs verification`.",
|
|
5429
|
+
"Do not edit code. Treat missing proof, vague tests, and uncertainty as blocking until verifier evidence exists.",
|
|
5430
|
+
"",
|
|
5431
|
+
`Gate attempt: ${state.attempt}`,
|
|
5432
|
+
input.task ? `Original task:
|
|
5433
|
+
${input.task}` : void 0,
|
|
5434
|
+
input.targets?.length ? `Targets:
|
|
5435
|
+
${input.targets.map((t) => `- ${t}`).join("\n")}` : void 0,
|
|
5436
|
+
input.expected ? `Expected behavior:
|
|
5437
|
+
${input.expected}` : void 0,
|
|
5438
|
+
input.evidence ? `Known evidence:
|
|
5439
|
+
${input.evidence}` : void 0,
|
|
5440
|
+
taskResultsBlock("Implementer results", state.implementerResults),
|
|
5441
|
+
taskResultsBlock("Repair results so far", state.repairResults),
|
|
5442
|
+
priorAttemptsBlock(state.priorAttempts)
|
|
5443
|
+
].filter((part) => !!part).join("\n\n");
|
|
5444
|
+
}
|
|
5445
|
+
function buildRepairTask(input, attempt, attemptNumber) {
|
|
5446
|
+
return [
|
|
5447
|
+
`Repair the implementation after quality gate attempt ${attemptNumber} failed.`,
|
|
5448
|
+
"Address every must-fix item. Run relevant checks before returning.",
|
|
5449
|
+
"Do not claim done unless verifier/reviewer feedback is resolved.",
|
|
5450
|
+
"",
|
|
5451
|
+
input.task ? `Original task:
|
|
5452
|
+
${input.task}` : void 0,
|
|
5453
|
+
input.targets?.length ? `Targets:
|
|
5454
|
+
${input.targets.map((t) => `- ${t}`).join("\n")}` : void 0,
|
|
5455
|
+
input.commands?.length ? `Commands expected to pass:
|
|
5456
|
+
${input.commands.map((c) => `- ${c}`).join("\n")}` : void 0,
|
|
5457
|
+
input.expected ? `Expected behavior:
|
|
5458
|
+
${input.expected}` : void 0,
|
|
5459
|
+
attempt.mustFix.length ? `Must fix:
|
|
5460
|
+
${attempt.mustFix.map((f) => `- ${f}`).join("\n")}` : void 0,
|
|
5461
|
+
attempt.uncertaintyFlags.length ? `Uncertainty flags to resolve:
|
|
5462
|
+
${attempt.uncertaintyFlags.map((f) => `- ${f}`).join("\n")}` : void 0,
|
|
5463
|
+
`Reviewer/verifier reports:
|
|
5464
|
+
${attempt.reports.map((r) => `### ${r.role} (${r.verdict})
|
|
5465
|
+
${r.summary}`).join("\n\n")}`
|
|
5466
|
+
].filter((part) => !!part).join("\n\n");
|
|
5467
|
+
}
|
|
5468
|
+
function taskResultsBlock(title, results) {
|
|
5469
|
+
if (results.length === 0) return void 0;
|
|
5470
|
+
return `${title}:
|
|
5471
|
+
${results.map((r) => `### ${r.subagentId}/${r.taskId}
|
|
5472
|
+
${summarizeTaskResult(r).summary}`).join("\n\n")}`;
|
|
5473
|
+
}
|
|
5474
|
+
function priorAttemptsBlock(attempts) {
|
|
5475
|
+
if (attempts.length === 0) return void 0;
|
|
5476
|
+
return `Prior quality gate attempts:
|
|
5477
|
+
${attempts.map(
|
|
5478
|
+
(a) => `### Attempt ${a.attempt}
|
|
5479
|
+
${a.reports.map((r) => `- ${r.role}: ${r.verdict}${r.error ? ` (${r.error})` : ""}`).join("\n")}`
|
|
5480
|
+
).join("\n\n")}`;
|
|
5481
|
+
}
|
|
5482
|
+
function summarizeTaskResult(result) {
|
|
5483
|
+
const text = typeof result.result === "string" ? result.result : result.result !== void 0 ? JSON.stringify(result.result, null, 2) : "";
|
|
5484
|
+
const error = result.error ? `${result.error.kind}: ${result.error.message}` : void 0;
|
|
5485
|
+
return {
|
|
5486
|
+
taskId: result.taskId,
|
|
5487
|
+
subagentId: result.subagentId,
|
|
5488
|
+
status: result.status,
|
|
5489
|
+
summary: excerpt(text || error || "(no output)", 4e3),
|
|
5490
|
+
error
|
|
5491
|
+
};
|
|
5492
|
+
}
|
|
5493
|
+
function assessRoleResult(role, result) {
|
|
5494
|
+
const resolvedRole = role ?? (result.subagentId.includes("review") ? "reviewer" : "verifier");
|
|
5495
|
+
const summary = summarizeTaskResult(result);
|
|
5496
|
+
const text = summary.summary;
|
|
5497
|
+
const uncertaintyFlags = extractSection(text, "Uncertainty Flags");
|
|
5498
|
+
if (result.status !== "success") {
|
|
5499
|
+
return {
|
|
5500
|
+
role: resolvedRole,
|
|
5501
|
+
subagentId: result.subagentId,
|
|
5502
|
+
taskId: result.taskId,
|
|
5503
|
+
status: result.status,
|
|
5504
|
+
verdict: "fail",
|
|
5505
|
+
summary: text,
|
|
5506
|
+
uncertaintyFlags,
|
|
5507
|
+
error: summary.error ?? result.status
|
|
5508
|
+
};
|
|
5509
|
+
}
|
|
5510
|
+
return {
|
|
5511
|
+
role: resolvedRole,
|
|
5512
|
+
subagentId: result.subagentId,
|
|
5513
|
+
taskId: result.taskId,
|
|
5514
|
+
status: result.status,
|
|
5515
|
+
verdict: parseQualityVerdict(resolvedRole, text),
|
|
5516
|
+
summary: text,
|
|
5517
|
+
uncertaintyFlags
|
|
5518
|
+
};
|
|
5519
|
+
}
|
|
5520
|
+
function assessQualityGate(reports) {
|
|
5521
|
+
const mustFix = [];
|
|
5522
|
+
const uncertaintyFlags = [];
|
|
5523
|
+
let hasFail = false;
|
|
5524
|
+
let hasInconclusive = false;
|
|
5525
|
+
for (const report of reports) {
|
|
5526
|
+
if (report.verdict === "fail") hasFail = true;
|
|
5527
|
+
if (report.verdict === "inconclusive") hasInconclusive = true;
|
|
5528
|
+
const blocking = extractSection(report.summary, "Must Fix") || extractSection(report.summary, "Failures") || extractSection(report.summary, "Verification Gaps");
|
|
5529
|
+
if (blocking) mustFix.push(`${report.role}: ${excerpt(blocking, 1e3)}`);
|
|
5530
|
+
if (report.uncertaintyFlags) {
|
|
5531
|
+
uncertaintyFlags.push(`${report.role}: ${excerpt(report.uncertaintyFlags, 1e3)}`);
|
|
5532
|
+
}
|
|
5533
|
+
if (report.error) mustFix.push(`${report.role}: ${report.error}`);
|
|
5534
|
+
}
|
|
5535
|
+
if (hasFail) return { verdict: "fail", passed: false, mustFix, uncertaintyFlags };
|
|
5536
|
+
if (hasInconclusive || reports.length === 0) {
|
|
5537
|
+
return { verdict: "inconclusive", passed: false, mustFix, uncertaintyFlags };
|
|
5538
|
+
}
|
|
5539
|
+
return { verdict: "pass", passed: true, mustFix, uncertaintyFlags };
|
|
5540
|
+
}
|
|
5541
|
+
function parseQualityVerdict(role, text) {
|
|
5542
|
+
const normalized = text.toLowerCase();
|
|
5543
|
+
const verdictBlock = normalized.match(/(?:^|\n)\s*(?:#+\s*)?verdict\b[^\n]*(?:\n|:|-)?([\s\S]{0,500})/)?.[0] ?? normalized.slice(0, 1e3);
|
|
5544
|
+
if (role === "reviewer") {
|
|
5545
|
+
if (/\b(request\s+changes|needs\s+verification|reject|rejected|fail|failed|blocked)\b/.test(
|
|
5546
|
+
verdictBlock
|
|
5547
|
+
)) {
|
|
5548
|
+
return "fail";
|
|
5549
|
+
}
|
|
5550
|
+
if (/\b(approve|approved|pass|passed)\b/.test(verdictBlock)) return "pass";
|
|
5551
|
+
if (sectionHasBlockingContent(text, "Must Fix") || sectionHasBlockingContent(text, "Verification Gaps")) {
|
|
5552
|
+
return "fail";
|
|
5553
|
+
}
|
|
5554
|
+
return "inconclusive";
|
|
5555
|
+
}
|
|
5556
|
+
if (/\b(fail|failed|blocked|red)\b/.test(verdictBlock)) return "fail";
|
|
5557
|
+
if (/\b(pass|passed|green|approve|approved)\b/.test(verdictBlock)) return "pass";
|
|
5558
|
+
if (sectionHasBlockingContent(text, "Failures")) return "fail";
|
|
5559
|
+
return "inconclusive";
|
|
5560
|
+
}
|
|
5561
|
+
function sectionHasBlockingContent(text, heading) {
|
|
5562
|
+
const section = extractSection(text, heading);
|
|
5563
|
+
if (!section) return false;
|
|
5564
|
+
return !/^\s*(none|n\/a|no\b|no issues|empty|\(none\))\s*\.?\s*$/i.test(section.trim());
|
|
5565
|
+
}
|
|
5566
|
+
function extractSection(text, heading) {
|
|
5567
|
+
const escaped = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5568
|
+
const pattern = new RegExp(
|
|
5569
|
+
`(?:^|\\n)\\s*#{1,6}\\s*${escaped}\\s*\\n([\\s\\S]*?)(?=\\n\\s*#{1,6}\\s+|$)`,
|
|
5570
|
+
"i"
|
|
5571
|
+
);
|
|
5572
|
+
const match = text.match(pattern);
|
|
5573
|
+
const body = match?.[1]?.trim();
|
|
5574
|
+
return body ? body : void 0;
|
|
5575
|
+
}
|
|
5576
|
+
function excerpt(text, max) {
|
|
5577
|
+
if (text.length <= max) return text;
|
|
5578
|
+
return `${text.slice(0, max - 20).trimEnd()}
|
|
5579
|
+
...(truncated)`;
|
|
5580
|
+
}
|
|
5030
5581
|
function makeAssignTool(director) {
|
|
5031
5582
|
const inputSchema = {
|
|
5032
5583
|
type: "object",
|
|
5033
5584
|
properties: {
|
|
5034
5585
|
subagentId: { type: "string", minLength: 1, description: "Target subagent id. Required." },
|
|
5035
|
-
description: {
|
|
5036
|
-
|
|
5586
|
+
description: {
|
|
5587
|
+
type: "string",
|
|
5588
|
+
minLength: 1,
|
|
5589
|
+
description: "The task in natural language \u2014 what you want this subagent to do."
|
|
5590
|
+
},
|
|
5591
|
+
maxToolCalls: {
|
|
5592
|
+
type: "number",
|
|
5593
|
+
minimum: 1,
|
|
5594
|
+
description: "Optional per-task tool-call budget override."
|
|
5595
|
+
},
|
|
5037
5596
|
timeoutMs: { type: "number", minimum: 1, description: "Optional per-task timeout in ms." }
|
|
5038
5597
|
},
|
|
5039
5598
|
required: ["subagentId", "description"]
|
|
@@ -5047,7 +5606,13 @@ function makeAssignTool(director) {
|
|
|
5047
5606
|
inputSchema,
|
|
5048
5607
|
async execute(input) {
|
|
5049
5608
|
const i = input;
|
|
5050
|
-
const task = {
|
|
5609
|
+
const task = {
|
|
5610
|
+
id: randomUUID(),
|
|
5611
|
+
description: i.description,
|
|
5612
|
+
subagentId: i.subagentId,
|
|
5613
|
+
maxToolCalls: i.maxToolCalls,
|
|
5614
|
+
timeoutMs: i.timeoutMs
|
|
5615
|
+
};
|
|
5051
5616
|
const taskId = await director.assign(task);
|
|
5052
5617
|
return { taskId, subagentId: i.subagentId };
|
|
5053
5618
|
}
|
|
@@ -5063,22 +5628,39 @@ function makeAwaitTasksTool(director) {
|
|
|
5063
5628
|
inputSchema: {
|
|
5064
5629
|
type: "object",
|
|
5065
5630
|
properties: {
|
|
5066
|
-
taskIds: {
|
|
5067
|
-
|
|
5068
|
-
|
|
5631
|
+
taskIds: {
|
|
5632
|
+
type: "array",
|
|
5633
|
+
items: { type: "string" },
|
|
5634
|
+
description: "One or more task ids returned by `assign_task`."
|
|
5635
|
+
},
|
|
5636
|
+
mode: {
|
|
5637
|
+
type: "string",
|
|
5638
|
+
enum: ["all", "any"],
|
|
5639
|
+
description: '"all" (default): block until every task completes. "any": return on the first completion with the rest listed as pending.'
|
|
5640
|
+
},
|
|
5641
|
+
timeoutMs: {
|
|
5642
|
+
type: "number",
|
|
5643
|
+
minimum: 1,
|
|
5644
|
+
description: 'mode:"any" only \u2014 return {timedOut:true, completed:[]} if nothing completes within this window instead of blocking.'
|
|
5645
|
+
}
|
|
5069
5646
|
},
|
|
5070
5647
|
required: ["taskIds"]
|
|
5071
5648
|
},
|
|
5072
5649
|
async execute(input) {
|
|
5073
5650
|
const i = input;
|
|
5074
5651
|
if (i.mode === "any") {
|
|
5075
|
-
const r = await director.awaitTasksAny(
|
|
5652
|
+
const r = await director.awaitTasksAny(
|
|
5653
|
+
i.taskIds,
|
|
5654
|
+
i.timeoutMs !== void 0 ? { timeoutMs: i.timeoutMs } : void 0
|
|
5655
|
+
);
|
|
5076
5656
|
return {
|
|
5077
5657
|
mode: "any",
|
|
5078
5658
|
completed: r.completed,
|
|
5079
5659
|
pending: r.pending,
|
|
5080
5660
|
...r.timedOut ? { timedOut: true } : {},
|
|
5081
|
-
...r.pending.length > 0 ? {
|
|
5661
|
+
...r.pending.length > 0 ? {
|
|
5662
|
+
hint: 'Handle the completed results now. Re-call await_tasks with the pending ids (mode:"any") for the next finisher \u2014 or assign new work to the now-idle subagent first.'
|
|
5663
|
+
} : {}
|
|
5082
5664
|
};
|
|
5083
5665
|
}
|
|
5084
5666
|
const results = await director.awaitTasks(i.taskIds);
|
|
@@ -5096,9 +5678,17 @@ function makeAskTool(director) {
|
|
|
5096
5678
|
inputSchema: {
|
|
5097
5679
|
type: "object",
|
|
5098
5680
|
properties: {
|
|
5099
|
-
subagentId: {
|
|
5681
|
+
subagentId: {
|
|
5682
|
+
type: "string",
|
|
5683
|
+
minLength: 1,
|
|
5684
|
+
description: "Subagent to ask. Must be a previously spawned id."
|
|
5685
|
+
},
|
|
5100
5686
|
question: { type: "string", minLength: 1, description: "The question or instruction." },
|
|
5101
|
-
timeoutMs: {
|
|
5687
|
+
timeoutMs: {
|
|
5688
|
+
type: "number",
|
|
5689
|
+
minimum: 1,
|
|
5690
|
+
description: "Optional timeout in ms (default 30s)."
|
|
5691
|
+
}
|
|
5102
5692
|
},
|
|
5103
5693
|
required: ["subagentId", "question"]
|
|
5104
5694
|
},
|
|
@@ -5144,7 +5734,10 @@ function makeAskResultTool(director) {
|
|
|
5144
5734
|
const i = input;
|
|
5145
5735
|
const value = director.largeAnswerStore.retrieveAnswer(i.key);
|
|
5146
5736
|
if (value === void 0) {
|
|
5147
|
-
return {
|
|
5737
|
+
return {
|
|
5738
|
+
ok: false,
|
|
5739
|
+
error: `No stored answer found for key "${i.key}" \u2014 it may have been cleared or the key is invalid.`
|
|
5740
|
+
};
|
|
5148
5741
|
}
|
|
5149
5742
|
return { ok: true, value };
|
|
5150
5743
|
}
|
|
@@ -5160,9 +5753,17 @@ function makeRollUpTool(director) {
|
|
|
5160
5753
|
inputSchema: {
|
|
5161
5754
|
type: "object",
|
|
5162
5755
|
properties: {
|
|
5163
|
-
taskIds: {
|
|
5164
|
-
|
|
5165
|
-
|
|
5756
|
+
taskIds: {
|
|
5757
|
+
type: "array",
|
|
5758
|
+
items: { type: "string" },
|
|
5759
|
+
description: "Completed task ids to aggregate."
|
|
5760
|
+
},
|
|
5761
|
+
style: {
|
|
5762
|
+
type: "string",
|
|
5763
|
+
enum: ["markdown", "json"],
|
|
5764
|
+
description: "Output flavor \u2014 markdown (default) or json."
|
|
5765
|
+
}
|
|
5766
|
+
},
|
|
5166
5767
|
required: ["taskIds"]
|
|
5167
5768
|
},
|
|
5168
5769
|
async execute(input) {
|
|
@@ -5179,7 +5780,11 @@ function makeTerminateTool(director) {
|
|
|
5179
5780
|
permission: "auto",
|
|
5180
5781
|
mutating: true,
|
|
5181
5782
|
capabilities: [ToolCapabilities.SUBAGENT_SPAWN],
|
|
5182
|
-
inputSchema: {
|
|
5783
|
+
inputSchema: {
|
|
5784
|
+
type: "object",
|
|
5785
|
+
properties: { subagentId: { type: "string", description: "Subagent to abort." } },
|
|
5786
|
+
required: ["subagentId"]
|
|
5787
|
+
},
|
|
5183
5788
|
async execute(input) {
|
|
5184
5789
|
const i = input;
|
|
5185
5790
|
await director.terminate(i.subagentId);
|
|
@@ -5197,7 +5802,10 @@ function makeTerminateAllTool(director) {
|
|
|
5197
5802
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
5198
5803
|
async execute() {
|
|
5199
5804
|
await director.terminateAll();
|
|
5200
|
-
return {
|
|
5805
|
+
return {
|
|
5806
|
+
ok: true,
|
|
5807
|
+
message: `Fleet shutdown complete \u2014 all subagents stopped, pending tasks drained.`
|
|
5808
|
+
};
|
|
5201
5809
|
}
|
|
5202
5810
|
};
|
|
5203
5811
|
}
|
|
@@ -5239,7 +5847,12 @@ function makeFleetTool(director) {
|
|
|
5239
5847
|
return {
|
|
5240
5848
|
action: "status",
|
|
5241
5849
|
subagents: base.subagents,
|
|
5242
|
-
coordinatorStats: stats ? {
|
|
5850
|
+
coordinatorStats: stats ? {
|
|
5851
|
+
total: stats.total,
|
|
5852
|
+
running: stats.running,
|
|
5853
|
+
idle: stats.idle,
|
|
5854
|
+
stopped: stats.stopped
|
|
5855
|
+
} : void 0,
|
|
5243
5856
|
pending: fleetStatus?.pending ?? [],
|
|
5244
5857
|
usage: fm?.snapshot()
|
|
5245
5858
|
};
|
|
@@ -5272,7 +5885,10 @@ function makeFleetTool(director) {
|
|
|
5272
5885
|
case "session": {
|
|
5273
5886
|
const subagentId = i.subagentId;
|
|
5274
5887
|
if (!subagentId) {
|
|
5275
|
-
return {
|
|
5888
|
+
return {
|
|
5889
|
+
action: "session",
|
|
5890
|
+
error: 'fleet: subagentId is required for action: "session"'
|
|
5891
|
+
};
|
|
5276
5892
|
}
|
|
5277
5893
|
const result = await director.readSession(subagentId, i.tail);
|
|
5278
5894
|
if (!result) {
|
|
@@ -5284,7 +5900,9 @@ function makeFleetTool(director) {
|
|
|
5284
5900
|
return { action: "session", ...result };
|
|
5285
5901
|
}
|
|
5286
5902
|
default:
|
|
5287
|
-
return {
|
|
5903
|
+
return {
|
|
5904
|
+
error: `fleet: unknown action "${action}". Valid: status, usage, health, session.`
|
|
5905
|
+
};
|
|
5288
5906
|
}
|
|
5289
5907
|
}
|
|
5290
5908
|
};
|
|
@@ -5728,6 +6346,31 @@ function providerStatusToCode(status, type) {
|
|
|
5728
6346
|
if (status >= 500) return ERROR_CODES.PROVIDER_SERVER_ERROR;
|
|
5729
6347
|
return ERROR_CODES.PROVIDER_INVALID_REQUEST;
|
|
5730
6348
|
}
|
|
6349
|
+
|
|
6350
|
+
// src/core/fallback-model.ts
|
|
6351
|
+
function parseModelRef(ref) {
|
|
6352
|
+
const trimmed = ref.trim();
|
|
6353
|
+
const slash = trimmed.indexOf("/");
|
|
6354
|
+
if (slash !== -1) {
|
|
6355
|
+
return {
|
|
6356
|
+
provider: trimmed.slice(0, slash) || void 0,
|
|
6357
|
+
model: trimmed.slice(slash + 1).trim()
|
|
6358
|
+
};
|
|
6359
|
+
}
|
|
6360
|
+
const parts = trimmed.split(/\s+/);
|
|
6361
|
+
if (parts.length >= 2) {
|
|
6362
|
+
return { provider: parts[0], model: parts.slice(1).join(" ") };
|
|
6363
|
+
}
|
|
6364
|
+
return { model: trimmed };
|
|
6365
|
+
}
|
|
6366
|
+
function fallbackProfileChain(config, profileName) {
|
|
6367
|
+
if (!profileName) return [];
|
|
6368
|
+
const chain = config.fallbackProfiles?.[profileName];
|
|
6369
|
+
return Array.isArray(chain) ? chain.filter((ref) => parseModelRef(ref).model) : [];
|
|
6370
|
+
}
|
|
6371
|
+
|
|
6372
|
+
// src/coordination/model-matrix.ts
|
|
6373
|
+
var MATRIX_PHASE_KEYS = Object.keys(AGENTS_BY_PHASE);
|
|
5731
6374
|
var ROLE_TO_PHASE = (() => {
|
|
5732
6375
|
const map = {};
|
|
5733
6376
|
for (const [phase, defs] of Object.entries(AGENTS_BY_PHASE)) {
|
|
@@ -5741,14 +6384,162 @@ var ROLE_TO_PHASE = (() => {
|
|
|
5741
6384
|
function phaseForRole(role) {
|
|
5742
6385
|
return role ? ROLE_TO_PHASE[role] : void 0;
|
|
5743
6386
|
}
|
|
5744
|
-
function
|
|
6387
|
+
function resolveModelMatrixResolution(matrix, role) {
|
|
5745
6388
|
if (!matrix) return void 0;
|
|
5746
|
-
if (role && matrix[role]) return matrix[role];
|
|
6389
|
+
if (role && matrix[role]) return { entry: matrix[role], source: "role", key: role };
|
|
5747
6390
|
const phase = phaseForRole(role);
|
|
5748
|
-
if (phase && matrix[phase]) return matrix[phase];
|
|
5749
|
-
if (matrix["*"]) return matrix["*"];
|
|
6391
|
+
if (phase && matrix[phase]) return { entry: matrix[phase], source: "phase", key: phase };
|
|
6392
|
+
if (matrix["*"]) return { entry: matrix["*"], source: "default", key: "*" };
|
|
5750
6393
|
return void 0;
|
|
5751
6394
|
}
|
|
6395
|
+
function resolveModelMatrix(matrix, role) {
|
|
6396
|
+
return resolveModelMatrixResolution(matrix, role)?.entry;
|
|
6397
|
+
}
|
|
6398
|
+
function resolveModelTargetFromEntry(config, entry) {
|
|
6399
|
+
if (!entry) return void 0;
|
|
6400
|
+
if (entry.model) {
|
|
6401
|
+
return {
|
|
6402
|
+
provider: entry.provider,
|
|
6403
|
+
model: entry.model,
|
|
6404
|
+
modelRuntime: entry.modelRuntime,
|
|
6405
|
+
fallbackProfile: entry.fallbackProfile,
|
|
6406
|
+
fallbackModels: fallbackProfileChain(config, entry.fallbackProfile)
|
|
6407
|
+
};
|
|
6408
|
+
}
|
|
6409
|
+
const chain = fallbackProfileChain(config, entry.fallbackProfile);
|
|
6410
|
+
const first = chain[0];
|
|
6411
|
+
if (!first) {
|
|
6412
|
+
return entry.modelRuntime ? { modelRuntime: entry.modelRuntime } : void 0;
|
|
6413
|
+
}
|
|
6414
|
+
const parsed = parseModelRef(first);
|
|
6415
|
+
return {
|
|
6416
|
+
provider: parsed.provider,
|
|
6417
|
+
model: parsed.model,
|
|
6418
|
+
modelRuntime: entry.modelRuntime,
|
|
6419
|
+
fallbackProfile: entry.fallbackProfile,
|
|
6420
|
+
fallbackModels: chain.slice(1)
|
|
6421
|
+
};
|
|
6422
|
+
}
|
|
6423
|
+
function roleNeedsIndependentReviewModel(role) {
|
|
6424
|
+
if (!role) return false;
|
|
6425
|
+
return role === "reviewer" || phaseForRole(role) === "review";
|
|
6426
|
+
}
|
|
6427
|
+
function resolveSubagentModelTarget(config, role, opts = {}) {
|
|
6428
|
+
const resolution = resolveModelMatrixResolution(config.modelMatrix, role);
|
|
6429
|
+
const matrixTarget = resolveModelTargetFromEntry(config, resolution?.entry);
|
|
6430
|
+
const implementationTarget = opts.implementationTarget ?? resolveImplementationModelTarget(config);
|
|
6431
|
+
if (!roleNeedsIndependentReviewModel(role)) {
|
|
6432
|
+
if (!matrixTarget) return void 0;
|
|
6433
|
+
return {
|
|
6434
|
+
...matrixTarget,
|
|
6435
|
+
source: "matrix",
|
|
6436
|
+
matrixSource: resolution?.source
|
|
6437
|
+
};
|
|
6438
|
+
}
|
|
6439
|
+
const matrixRef = materializeTarget(config, matrixTarget);
|
|
6440
|
+
if (resolution?.source === "role" || resolution?.source === "phase") {
|
|
6441
|
+
return matrixTarget ? { ...matrixTarget, source: "matrix", matrixSource: resolution.source } : void 0;
|
|
6442
|
+
}
|
|
6443
|
+
if (matrixRef && !sameModelReference(matrixRef, implementationTarget)) {
|
|
6444
|
+
return {
|
|
6445
|
+
...matrixTarget ?? {},
|
|
6446
|
+
source: "matrix",
|
|
6447
|
+
matrixSource: resolution?.source
|
|
6448
|
+
};
|
|
6449
|
+
}
|
|
6450
|
+
const diverse = chooseDiverseModelTarget(config, implementationTarget);
|
|
6451
|
+
if (diverse) {
|
|
6452
|
+
return {
|
|
6453
|
+
provider: diverse.provider,
|
|
6454
|
+
model: diverse.model,
|
|
6455
|
+
modelRuntime: matrixTarget?.modelRuntime,
|
|
6456
|
+
fallbackModels: matrixTarget?.fallbackModels,
|
|
6457
|
+
fallbackProfile: matrixTarget?.fallbackProfile,
|
|
6458
|
+
source: "diversity",
|
|
6459
|
+
matrixSource: resolution?.source,
|
|
6460
|
+
diversified: true
|
|
6461
|
+
};
|
|
6462
|
+
}
|
|
6463
|
+
if (!matrixTarget) return void 0;
|
|
6464
|
+
return {
|
|
6465
|
+
...matrixTarget,
|
|
6466
|
+
source: "matrix",
|
|
6467
|
+
matrixSource: resolution?.source
|
|
6468
|
+
};
|
|
6469
|
+
}
|
|
6470
|
+
function resolveImplementationModelTarget(config) {
|
|
6471
|
+
const target = resolveModelTargetFromEntry(
|
|
6472
|
+
config,
|
|
6473
|
+
resolveModelMatrix(config.modelMatrix, "executor")
|
|
6474
|
+
);
|
|
6475
|
+
return materializeTarget(config, target) ?? {
|
|
6476
|
+
provider: config.provider,
|
|
6477
|
+
model: config.model
|
|
6478
|
+
};
|
|
6479
|
+
}
|
|
6480
|
+
function sameModelReference(a, b) {
|
|
6481
|
+
if (!a?.model || !b?.model) return false;
|
|
6482
|
+
const providerA = a.provider ?? "";
|
|
6483
|
+
const providerB = b.provider ?? "";
|
|
6484
|
+
return providerA === providerB && a.model === b.model;
|
|
6485
|
+
}
|
|
6486
|
+
function materializeTarget(config, target) {
|
|
6487
|
+
if (!target?.model) return void 0;
|
|
6488
|
+
return {
|
|
6489
|
+
provider: target.provider ?? config.provider,
|
|
6490
|
+
model: target.model
|
|
6491
|
+
};
|
|
6492
|
+
}
|
|
6493
|
+
function chooseDiverseModelTarget(config, avoid) {
|
|
6494
|
+
const candidates = collectConfiguredModelTargets(config).filter(
|
|
6495
|
+
(candidate) => !sameModelReference(candidate, avoid)
|
|
6496
|
+
);
|
|
6497
|
+
candidates.sort((a, b) => modelDiversityScore(b, avoid) - modelDiversityScore(a, avoid));
|
|
6498
|
+
return candidates[0];
|
|
6499
|
+
}
|
|
6500
|
+
function collectConfiguredModelTargets(config) {
|
|
6501
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6502
|
+
const out = [];
|
|
6503
|
+
const add = (provider, model) => {
|
|
6504
|
+
if (!provider || !model) return;
|
|
6505
|
+
const key = `${provider}\0${model}`;
|
|
6506
|
+
if (seen.has(key)) return;
|
|
6507
|
+
seen.add(key);
|
|
6508
|
+
out.push({ provider, model });
|
|
6509
|
+
};
|
|
6510
|
+
add(config.provider, config.model);
|
|
6511
|
+
for (const [providerId, provider] of Object.entries(config.providers ?? {})) {
|
|
6512
|
+
if (!isProviderAvailable(providerId, provider, config.provider)) continue;
|
|
6513
|
+
for (const model of provider.models ?? []) add(providerId, model);
|
|
6514
|
+
for (const model of Object.keys(provider.customModels ?? {})) add(providerId, model);
|
|
6515
|
+
}
|
|
6516
|
+
for (const model of Object.keys(config.models ?? {})) add(config.provider, model);
|
|
6517
|
+
return out;
|
|
6518
|
+
}
|
|
6519
|
+
function isProviderAvailable(providerId, provider, leaderProvider) {
|
|
6520
|
+
if (providerId === leaderProvider) return true;
|
|
6521
|
+
if (typeof provider.apiKey === "string" && provider.apiKey.length > 0) return true;
|
|
6522
|
+
if (Array.isArray(provider.apiKeys) && provider.apiKeys.some((key) => key?.apiKey)) return true;
|
|
6523
|
+
if (typeof provider.baseUrl === "string" && provider.baseUrl.length > 0) return true;
|
|
6524
|
+
return false;
|
|
6525
|
+
}
|
|
6526
|
+
function modelDiversityScore(candidate, avoid) {
|
|
6527
|
+
let score = 0;
|
|
6528
|
+
if (candidate.provider !== avoid.provider) score += 100;
|
|
6529
|
+
if (candidate.model !== avoid.model) score += 20;
|
|
6530
|
+
if (/opus|gpt-5|o3|o4|gemini.*pro|deepseek-r1/i.test(candidate.model)) score += 10;
|
|
6531
|
+
if (/mini|haiku|flash/i.test(candidate.model)) score -= 5;
|
|
6532
|
+
return score;
|
|
6533
|
+
}
|
|
6534
|
+
function matrixKeyKind(key) {
|
|
6535
|
+
if (key === "*") return "default";
|
|
6536
|
+
if (key in AGENT_CATALOG) return "role";
|
|
6537
|
+
if (MATRIX_PHASE_KEYS.includes(key)) return "phase";
|
|
6538
|
+
return "unknown";
|
|
6539
|
+
}
|
|
6540
|
+
function isValidMatrixKey(key) {
|
|
6541
|
+
return matrixKeyKind(key) !== "unknown";
|
|
6542
|
+
}
|
|
5752
6543
|
|
|
5753
6544
|
// src/coordination/coordinator/error-classifier.ts
|
|
5754
6545
|
function classifySubagentError(err, hints = {}) {
|
|
@@ -6770,48 +7561,200 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
6770
7561
|
}
|
|
6771
7562
|
};
|
|
6772
7563
|
|
|
6773
|
-
// src/coordination/
|
|
6774
|
-
var
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
super(message
|
|
6781
|
-
this.name = "
|
|
6782
|
-
this.
|
|
6783
|
-
this.
|
|
6784
|
-
this.
|
|
7564
|
+
// src/coordination/worktree-task-runner.ts
|
|
7565
|
+
var WorktreeIntegrationError = class extends Error {
|
|
7566
|
+
taskId;
|
|
7567
|
+
subagentId;
|
|
7568
|
+
branch;
|
|
7569
|
+
conflictFiles;
|
|
7570
|
+
constructor(message, opts) {
|
|
7571
|
+
super(message);
|
|
7572
|
+
this.name = "WorktreeIntegrationError";
|
|
7573
|
+
this.taskId = opts.taskId;
|
|
7574
|
+
this.subagentId = opts.subagentId;
|
|
7575
|
+
this.branch = opts.branch;
|
|
7576
|
+
this.conflictFiles = opts.conflictFiles;
|
|
6785
7577
|
}
|
|
6786
7578
|
};
|
|
6787
|
-
var
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
7579
|
+
var MUTATING_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
7580
|
+
"write",
|
|
7581
|
+
"edit",
|
|
7582
|
+
"replace",
|
|
7583
|
+
"patch",
|
|
7584
|
+
"task",
|
|
7585
|
+
"plan",
|
|
7586
|
+
"design",
|
|
7587
|
+
"document",
|
|
7588
|
+
"scaffold",
|
|
7589
|
+
"bash",
|
|
7590
|
+
"exec",
|
|
7591
|
+
"lint",
|
|
7592
|
+
"format",
|
|
7593
|
+
"typecheck",
|
|
7594
|
+
"test",
|
|
7595
|
+
"install"
|
|
7596
|
+
]);
|
|
7597
|
+
var MUTATING_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
7598
|
+
ToolCapabilities.FS_WRITE,
|
|
7599
|
+
ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,
|
|
7600
|
+
ToolCapabilities.SHELL_ARBITRARY,
|
|
7601
|
+
ToolCapabilities.SHELL_RESTRICTED,
|
|
7602
|
+
ToolCapabilities.SHELL_EXEC,
|
|
7603
|
+
ToolCapabilities.PACKAGE_INSTALL
|
|
7604
|
+
]);
|
|
7605
|
+
function subagentNeedsWorktree(config) {
|
|
7606
|
+
if (config.provider === "acp") return false;
|
|
7607
|
+
if (config.tools?.some((tool) => MUTATING_TOOL_NAMES.has(tool))) return true;
|
|
7608
|
+
if (config.allowedCapabilities?.some((cap) => MUTATING_CAPABILITIES.has(cap))) return true;
|
|
7609
|
+
return !config.tools && !config.allowedCapabilities;
|
|
7610
|
+
}
|
|
7611
|
+
function resolveSubagentWorktreeDecision(config, policy) {
|
|
7612
|
+
if (policy?.enabled === false || policy?.mode === "off") return "off";
|
|
7613
|
+
if (config.worktree === false || config.worktree === "off") return "off";
|
|
7614
|
+
if (config.worktree === true || config.worktree === "required") return "required";
|
|
7615
|
+
const needsIsolation = subagentNeedsWorktree(config);
|
|
7616
|
+
if (!needsIsolation) return "off";
|
|
7617
|
+
return policy?.mode === "required" ? "required" : "optional";
|
|
7618
|
+
}
|
|
7619
|
+
function wrapSubagentRunnerWithWorktrees(opts) {
|
|
7620
|
+
return async (task, ctx) => {
|
|
7621
|
+
const decision = resolveSubagentWorktreeDecision(ctx.config, opts.policy);
|
|
7622
|
+
if (decision === "off") return opts.runner(task, ctx);
|
|
7623
|
+
if (!opts.worktrees) {
|
|
7624
|
+
if (decision === "required") {
|
|
7625
|
+
throw new WorktreeIntegrationError(
|
|
7626
|
+
"worktree isolation is required but no WorktreeManager is configured",
|
|
7627
|
+
{
|
|
7628
|
+
taskId: task.id,
|
|
7629
|
+
subagentId: ctx.subagentId
|
|
7630
|
+
}
|
|
7631
|
+
);
|
|
7632
|
+
}
|
|
7633
|
+
return opts.runner(task, ctx);
|
|
7634
|
+
}
|
|
7635
|
+
const handle = await opts.worktrees.allocate(task.id, {
|
|
7636
|
+
slugHint: worktreeSlugHint(task, ctx.config),
|
|
7637
|
+
ownerLabel: worktreeOwnerLabel(task, ctx.config)
|
|
7638
|
+
});
|
|
7639
|
+
if (handle.status !== "active") {
|
|
7640
|
+
emitUpdate(opts, task, ctx, handle, {
|
|
7641
|
+
status: "fallback",
|
|
7642
|
+
error: handle.lastError ?? "worktree allocation failed"
|
|
7643
|
+
});
|
|
7644
|
+
if (decision === "required") {
|
|
7645
|
+
throw new WorktreeIntegrationError(
|
|
7646
|
+
`worktree allocation failed: ${handle.lastError ?? "unknown error"}`,
|
|
7647
|
+
{
|
|
7648
|
+
taskId: task.id,
|
|
7649
|
+
subagentId: ctx.subagentId,
|
|
7650
|
+
branch: handle.branch
|
|
7651
|
+
}
|
|
7652
|
+
);
|
|
7653
|
+
}
|
|
7654
|
+
return opts.runner(task, ctx);
|
|
7655
|
+
}
|
|
7656
|
+
emitUpdate(opts, task, ctx, handle, { status: "allocated" });
|
|
7657
|
+
const isolatedConfig = { ...ctx.config, cwd: handle.dir };
|
|
7658
|
+
const isolatedCtx = { ...ctx, config: isolatedConfig };
|
|
7659
|
+
let outcome;
|
|
7660
|
+
try {
|
|
7661
|
+
outcome = await opts.runner(task, isolatedCtx);
|
|
7662
|
+
} catch (err) {
|
|
7663
|
+
await parkFailedWorktree(opts, task, ctx, handle, err);
|
|
7664
|
+
throw err;
|
|
7665
|
+
}
|
|
7666
|
+
await integrateSuccessfulWorktree(opts, task, ctx, isolatedConfig, handle);
|
|
7667
|
+
return outcome;
|
|
7668
|
+
};
|
|
7669
|
+
}
|
|
7670
|
+
async function integrateSuccessfulWorktree(opts, task, ctx, config, handle) {
|
|
7671
|
+
const committed = await opts.worktrees.commitAll(
|
|
7672
|
+
handle,
|
|
7673
|
+
`subagent(${config.role ?? config.name}): ${task.id}`
|
|
7674
|
+
);
|
|
7675
|
+
if (!committed.committed) {
|
|
7676
|
+
await opts.worktrees.release(handle, { keep: false });
|
|
7677
|
+
emitUpdate(opts, task, ctx, handle, { status: "released" });
|
|
7678
|
+
return;
|
|
6799
7679
|
}
|
|
6800
|
-
};
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
7680
|
+
emitUpdate(opts, task, ctx, handle, { status: "committed", commitSha: handle.sha });
|
|
7681
|
+
if (opts.policy?.autoMerge === false) {
|
|
7682
|
+
await opts.worktrees.release(handle, { keep: true });
|
|
7683
|
+
emitUpdate(opts, task, ctx, handle, { status: "kept", commitSha: handle.sha });
|
|
7684
|
+
return;
|
|
7685
|
+
}
|
|
7686
|
+
const merged = await opts.worktrees.merge(handle, {
|
|
7687
|
+
squash: true,
|
|
7688
|
+
message: `merge subagent ${ctx.subagentId} task ${task.id} (squash)`,
|
|
7689
|
+
...opts.conflictResolver ? {
|
|
7690
|
+
resolve: (info) => opts.conflictResolver({
|
|
7691
|
+
task,
|
|
7692
|
+
config,
|
|
7693
|
+
conflictFiles: info.conflictFiles,
|
|
7694
|
+
cwd: info.cwd
|
|
7695
|
+
})
|
|
7696
|
+
} : {}
|
|
7697
|
+
});
|
|
7698
|
+
if (!merged.ok) {
|
|
7699
|
+
await opts.worktrees.release(handle, { keep: true }).catch(() => void 0);
|
|
7700
|
+
const conflictFiles = merged.conflictFiles ?? [];
|
|
7701
|
+
emitUpdate(opts, task, ctx, handle, {
|
|
7702
|
+
status: merged.conflict ? "conflict" : "failed",
|
|
7703
|
+
commitSha: handle.sha,
|
|
7704
|
+
conflictFiles,
|
|
7705
|
+
error: merged.stderr || (merged.conflict ? "merge conflict" : "worktree merge failed")
|
|
7706
|
+
});
|
|
7707
|
+
throw new WorktreeIntegrationError(
|
|
7708
|
+
merged.conflict ? `worktree merge conflict${conflictFiles.length ? `: ${conflictFiles.join(", ")}` : ""}` : `worktree merge failed: ${merged.stderr ?? "unknown error"}`,
|
|
7709
|
+
{
|
|
7710
|
+
taskId: task.id,
|
|
7711
|
+
subagentId: ctx.subagentId,
|
|
7712
|
+
branch: handle.branch,
|
|
7713
|
+
conflictFiles
|
|
7714
|
+
}
|
|
6808
7715
|
);
|
|
6809
|
-
this.name = "FleetContextOverflowError";
|
|
6810
|
-
this.kind = "max_context_load";
|
|
6811
|
-
this.limit = limit;
|
|
6812
|
-
this.observed = observed;
|
|
6813
7716
|
}
|
|
6814
|
-
};
|
|
7717
|
+
await opts.worktrees.release(handle, { keep: false });
|
|
7718
|
+
emitUpdate(opts, task, ctx, handle, { status: "merged", commitSha: handle.sha });
|
|
7719
|
+
}
|
|
7720
|
+
async function parkFailedWorktree(opts, task, ctx, handle, err) {
|
|
7721
|
+
let committed = false;
|
|
7722
|
+
try {
|
|
7723
|
+
const res = await opts.worktrees.commitAll(
|
|
7724
|
+
handle,
|
|
7725
|
+
`subagent(${ctx.config.role ?? ctx.config.name}) failed: ${task.id}`
|
|
7726
|
+
);
|
|
7727
|
+
committed = res.committed;
|
|
7728
|
+
} catch {
|
|
7729
|
+
committed = false;
|
|
7730
|
+
}
|
|
7731
|
+
const keep = (opts.policy?.keepFailed ?? true) && committed;
|
|
7732
|
+
await opts.worktrees.release(handle, { keep }).catch(() => void 0);
|
|
7733
|
+
emitUpdate(opts, task, ctx, handle, {
|
|
7734
|
+
status: keep ? "kept" : "released",
|
|
7735
|
+
commitSha: handle.sha,
|
|
7736
|
+
error: toErrorMessage(err)
|
|
7737
|
+
});
|
|
7738
|
+
}
|
|
7739
|
+
function emitUpdate(opts, task, ctx, handle, patch) {
|
|
7740
|
+
opts.onUpdate?.({
|
|
7741
|
+
taskId: task.id,
|
|
7742
|
+
subagentId: ctx.subagentId,
|
|
7743
|
+
handleId: handle.id,
|
|
7744
|
+
dir: handle.dir,
|
|
7745
|
+
branch: handle.branch,
|
|
7746
|
+
baseBranch: handle.baseBranch,
|
|
7747
|
+
...patch
|
|
7748
|
+
});
|
|
7749
|
+
}
|
|
7750
|
+
function worktreeSlugHint(task, config) {
|
|
7751
|
+
return `${config.role ?? config.name ?? "subagent"}-${task.id}`;
|
|
7752
|
+
}
|
|
7753
|
+
function worktreeOwnerLabel(task, config) {
|
|
7754
|
+
const who = config.name || config.role || "Subagent";
|
|
7755
|
+
const brief = task.description.trim().replace(/\s+/g, " ").slice(0, 80);
|
|
7756
|
+
return brief ? `${who}: ${brief}` : who;
|
|
7757
|
+
}
|
|
6815
7758
|
|
|
6816
7759
|
// src/coordination/director.ts
|
|
6817
7760
|
var Director = class _Director {
|
|
@@ -6943,6 +7886,8 @@ var Director = class _Director {
|
|
|
6943
7886
|
/** Resolves task descriptions back from `assign()` so completion events
|
|
6944
7887
|
* can also carry a human-readable title. */
|
|
6945
7888
|
taskDescriptions = /* @__PURE__ */ new Map();
|
|
7889
|
+
/** Latest worktree state per task id (allocated/committed/merged/conflict/etc.). */
|
|
7890
|
+
taskWorktrees = /* @__PURE__ */ new Map();
|
|
6946
7891
|
/** Snapshot of which subagent owns each task — drives state-checkpoint
|
|
6947
7892
|
* status updates without re-walking the manifest. */
|
|
6948
7893
|
taskOwners = /* @__PURE__ */ new Map();
|
|
@@ -7056,9 +8001,16 @@ var Director = class _Director {
|
|
|
7056
8001
|
(id) => this.subagentMeta.get(id)
|
|
7057
8002
|
);
|
|
7058
8003
|
}
|
|
8004
|
+
const runner = opts.runner && (opts.worktrees || opts.worktreePolicy) ? wrapSubagentRunnerWithWorktrees({
|
|
8005
|
+
runner: opts.runner,
|
|
8006
|
+
worktrees: opts.worktrees,
|
|
8007
|
+
policy: opts.worktreePolicy,
|
|
8008
|
+
conflictResolver: opts.worktreeConflictResolver,
|
|
8009
|
+
onUpdate: (update) => this.recordWorktreeTaskUpdate(update)
|
|
8010
|
+
}) : opts.runner;
|
|
7059
8011
|
this.coordinator = new DefaultMultiAgentCoordinator(
|
|
7060
8012
|
{ ...opts.config, coordinatorId: this.id },
|
|
7061
|
-
{ runner
|
|
8013
|
+
{ runner, sessionId: () => this.currentSessionId() }
|
|
7062
8014
|
);
|
|
7063
8015
|
this.coordinator.setFleetBus(this.fleet);
|
|
7064
8016
|
this.fleetManager?.setCoordinator(this.coordinator);
|
|
@@ -7428,6 +8380,17 @@ var Director = class _Director {
|
|
|
7428
8380
|
clearTimeout(this.manifestTimer);
|
|
7429
8381
|
this.manifestTimer = null;
|
|
7430
8382
|
}
|
|
8383
|
+
recordWorktreeTaskUpdate(update) {
|
|
8384
|
+
this.taskWorktrees.set(update.taskId, update);
|
|
8385
|
+
const owner = this.taskOwners.get(update.taskId) ?? update.subagentId;
|
|
8386
|
+
const entry = this.manifestEntries.get(owner);
|
|
8387
|
+
if (entry) {
|
|
8388
|
+
entry.worktrees = { ...entry.worktrees ?? {}, [update.taskId]: update };
|
|
8389
|
+
}
|
|
8390
|
+
this.stateCheckpoint?.recordTaskWorktree(update.taskId, update);
|
|
8391
|
+
this.fleetManager?.recordTaskWorktree(update);
|
|
8392
|
+
if (!this.fleetManager) this.scheduleManifest();
|
|
8393
|
+
}
|
|
7431
8394
|
/**
|
|
7432
8395
|
* Spawn a subagent. Identical to the coordinator's `spawn()` but
|
|
7433
8396
|
* captures provider/model metadata for the usage aggregator and
|
|
@@ -7449,7 +8412,8 @@ var Director = class _Director {
|
|
|
7449
8412
|
const config = { ...callerConfig };
|
|
7450
8413
|
if (!config.model && this.modelMatrix) {
|
|
7451
8414
|
const matrix = typeof this.modelMatrix === "function" ? this.modelMatrix() : this.modelMatrix;
|
|
7452
|
-
const
|
|
8415
|
+
const resolution = resolveModelMatrixResolution(matrix, config.role);
|
|
8416
|
+
const entry = resolution?.source === "default" && roleNeedsIndependentReviewModel(config.role) ? void 0 : resolution?.entry;
|
|
7453
8417
|
if (entry?.model) {
|
|
7454
8418
|
config.model = entry.model;
|
|
7455
8419
|
if (entry.provider) config.provider = entry.provider;
|
|
@@ -7669,13 +8633,15 @@ var Director = class _Director {
|
|
|
7669
8633
|
// success/failure state.
|
|
7670
8634
|
results: e.taskIds.map((tid) => {
|
|
7671
8635
|
const r = this.completed.get(tid);
|
|
8636
|
+
const worktree = e.worktrees?.[tid];
|
|
7672
8637
|
return r ? {
|
|
7673
8638
|
taskId: tid,
|
|
7674
8639
|
status: r.status,
|
|
7675
8640
|
iterations: r.iterations,
|
|
7676
8641
|
toolCalls: r.toolCalls,
|
|
7677
|
-
durationMs: r.durationMs
|
|
7678
|
-
|
|
8642
|
+
durationMs: r.durationMs,
|
|
8643
|
+
...worktree ? { worktree } : {}
|
|
8644
|
+
} : { taskId: tid, status: "pending", ...worktree ? { worktree } : {} };
|
|
7679
8645
|
})
|
|
7680
8646
|
})),
|
|
7681
8647
|
usage: this.usage.snapshot()
|
|
@@ -8114,6 +9080,7 @@ var Director = class _Director {
|
|
|
8114
9080
|
makeAskTool(this),
|
|
8115
9081
|
makeAskResultTool(this),
|
|
8116
9082
|
makeRollUpTool(this),
|
|
9083
|
+
makeQualityGateTool(this, effectiveRoster),
|
|
8117
9084
|
makeTerminateTool(this),
|
|
8118
9085
|
makeTerminateAllTool(this),
|
|
8119
9086
|
makeFleetTool(this),
|
|
@@ -10207,14 +11174,17 @@ var FleetManager = class {
|
|
|
10207
11174
|
model: config.model,
|
|
10208
11175
|
taskIds: []
|
|
10209
11176
|
});
|
|
10210
|
-
this.stateCheckpoint?.recordSpawn(
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
11177
|
+
this.stateCheckpoint?.recordSpawn(
|
|
11178
|
+
{
|
|
11179
|
+
id: subagentId,
|
|
11180
|
+
name: config.name,
|
|
11181
|
+
role: config.role,
|
|
11182
|
+
provider: config.provider,
|
|
11183
|
+
model: config.model,
|
|
11184
|
+
spawnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11185
|
+
},
|
|
11186
|
+
this.spawnCount
|
|
11187
|
+
);
|
|
10218
11188
|
void this.appendSessionEvent({
|
|
10219
11189
|
type: "agent_spawned",
|
|
10220
11190
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10242,7 +11212,8 @@ var FleetManager = class {
|
|
|
10242
11212
|
role: entry.role,
|
|
10243
11213
|
provider: entry.provider,
|
|
10244
11214
|
model: entry.model,
|
|
10245
|
-
taskIds: entry.taskIds
|
|
11215
|
+
taskIds: entry.taskIds,
|
|
11216
|
+
worktrees: entry.worktrees
|
|
10246
11217
|
})),
|
|
10247
11218
|
usage: this.usage.snapshot()
|
|
10248
11219
|
};
|
|
@@ -10258,6 +11229,14 @@ var FleetManager = class {
|
|
|
10258
11229
|
const entry = this.manifestEntries.get(subagentId);
|
|
10259
11230
|
if (entry) entry.taskIds.push(taskId);
|
|
10260
11231
|
}
|
|
11232
|
+
recordTaskWorktree(update) {
|
|
11233
|
+
const entry = this.manifestEntries.get(update.subagentId);
|
|
11234
|
+
if (entry) {
|
|
11235
|
+
entry.worktrees = { ...entry.worktrees ?? {}, [update.taskId]: update };
|
|
11236
|
+
}
|
|
11237
|
+
this.stateCheckpoint?.recordTaskWorktree(update.taskId, update);
|
|
11238
|
+
this.scheduleManifest();
|
|
11239
|
+
}
|
|
10261
11240
|
/**
|
|
10262
11241
|
* Debounced manifest write. Call after any state mutation
|
|
10263
11242
|
* (spawn, assign, complete) so a burst collapses into one write.
|
|
@@ -10269,10 +11248,7 @@ var FleetManager = class {
|
|
|
10269
11248
|
if (this.manifestDebounceMs === 0) {
|
|
10270
11249
|
void this.writeManifest().catch((err) => {
|
|
10271
11250
|
const detail = toErrorMessage(err);
|
|
10272
|
-
process.emitWarning(
|
|
10273
|
-
`FleetManager manifest write failed: ${detail}`,
|
|
10274
|
-
"FleetManagerWarning"
|
|
10275
|
-
);
|
|
11251
|
+
process.emitWarning(`FleetManager manifest write failed: ${detail}`, "FleetManagerWarning");
|
|
10276
11252
|
});
|
|
10277
11253
|
return;
|
|
10278
11254
|
}
|
|
@@ -10282,10 +11258,7 @@ var FleetManager = class {
|
|
|
10282
11258
|
this.manifestTimer = null;
|
|
10283
11259
|
void this.writeManifest().catch((err) => {
|
|
10284
11260
|
const detail = toErrorMessage(err);
|
|
10285
|
-
process.emitWarning(
|
|
10286
|
-
`FleetManager manifest write failed: ${detail}`,
|
|
10287
|
-
"FleetManagerWarning"
|
|
10288
|
-
);
|
|
11261
|
+
process.emitWarning(`FleetManager manifest write failed: ${detail}`, "FleetManagerWarning");
|
|
10289
11262
|
});
|
|
10290
11263
|
}, this.manifestDebounceMs);
|
|
10291
11264
|
}
|
|
@@ -10298,10 +11271,7 @@ var FleetManager = class {
|
|
|
10298
11271
|
this.clearManifestTimer();
|
|
10299
11272
|
await this.writeManifest().catch((err) => {
|
|
10300
11273
|
const detail = toErrorMessage(err);
|
|
10301
|
-
process.emitWarning(
|
|
10302
|
-
`FleetManager manifest write failed: ${detail}`,
|
|
10303
|
-
"FleetManagerWarning"
|
|
10304
|
-
);
|
|
11274
|
+
process.emitWarning(`FleetManager manifest write failed: ${detail}`, "FleetManagerWarning");
|
|
10305
11275
|
});
|
|
10306
11276
|
}
|
|
10307
11277
|
clearManifestTimer() {
|
|
@@ -11467,166 +12437,6 @@ function formatMessage(m, readerId) {
|
|
|
11467
12437
|
};
|
|
11468
12438
|
}
|
|
11469
12439
|
|
|
11470
|
-
// src/coordination/mail-tools.ts
|
|
11471
|
-
function makeResolver(opts) {
|
|
11472
|
-
return opts.resolveMailbox ?? ((ctx) => new GlobalMailbox(opts.projectDir ?? defaultResolveProjectDir(ctx), opts.events));
|
|
11473
|
-
}
|
|
11474
|
-
async function register(mb, ctx) {
|
|
11475
|
-
const identity = resolveMailboxIdentity(ctx);
|
|
11476
|
-
try {
|
|
11477
|
-
await mb.registerAgent({
|
|
11478
|
-
agentId: identity.callerId,
|
|
11479
|
-
sessionId: identity.sessionId,
|
|
11480
|
-
name: identity.name,
|
|
11481
|
-
role: identity.role,
|
|
11482
|
-
pid: process.pid,
|
|
11483
|
-
source: ctx.meta["source"] ?? "cli"
|
|
11484
|
-
});
|
|
11485
|
-
await mb.heartbeat({ agentId: identity.callerId });
|
|
11486
|
-
} catch {
|
|
11487
|
-
}
|
|
11488
|
-
return identity;
|
|
11489
|
-
}
|
|
11490
|
-
function makeMailSendTool(opts = {}) {
|
|
11491
|
-
const resolveMailbox = makeResolver(opts);
|
|
11492
|
-
return {
|
|
11493
|
-
name: "mail_send",
|
|
11494
|
-
description: 'Send a mail to other agents working on this project (other terminals, TUIs, WebUIs). Use it to hand off work, ask questions, announce what you just did, or request a review (type="review" \u2014 passive ask, no immediate reply required). to="*" broadcasts to everyone; to="leader" reaches every leader process; an exact id like "leader@a1b2c3d4" reaches one agent. Recipients see your mail automatically before their next step. Pick the type that matches the intent: note (default), ask (blocking question), assign (task), steer (mid-task direction), result (completion notice), review (passive ask), btw/status/broadcast/control (informational).',
|
|
11495
|
-
usageHint: 'mail_send to="<id>" type="review" body="please skim <file>"',
|
|
11496
|
-
category: "Coordination",
|
|
11497
|
-
permission: "auto",
|
|
11498
|
-
mutating: true,
|
|
11499
|
-
capabilities: [ToolCapabilities.COORDINATION_MAIL],
|
|
11500
|
-
inputSchema: {
|
|
11501
|
-
type: "object",
|
|
11502
|
-
properties: {
|
|
11503
|
-
to: {
|
|
11504
|
-
type: "string",
|
|
11505
|
-
description: 'Recipient: exact agent id ("leader@a1b2c3d4"), base alias ("leader"), or "*" / "all" for everyone.'
|
|
11506
|
-
},
|
|
11507
|
-
subject: { type: "string", description: "Short subject line." },
|
|
11508
|
-
body: { type: "string", description: "The message." },
|
|
11509
|
-
type: {
|
|
11510
|
-
type: "string",
|
|
11511
|
-
enum: ["note", "ask", "assign", "steer", "btw", "broadcast", "status", "result", "review"],
|
|
11512
|
-
description: 'Message intent. Default: "broadcast" when to="*", otherwise "note". Actionable types: ask (blocking question), assign (task), result (completion notice), review (passive ask \u2014 code/doc/PR review, no immediate reply required). Behavioral: steer (mid-task direction change), btw (low-priority aside). Informational: note/status/broadcast/control.'
|
|
11513
|
-
},
|
|
11514
|
-
priority: { type: "string", enum: ["low", "normal", "high"] },
|
|
11515
|
-
replyTo: { type: "string", description: "Message id this replies to." }
|
|
11516
|
-
},
|
|
11517
|
-
required: ["to", "subject", "body"]
|
|
11518
|
-
},
|
|
11519
|
-
async execute(input, ctx) {
|
|
11520
|
-
const i = input ?? {};
|
|
11521
|
-
const rawTo = i.to;
|
|
11522
|
-
const subject = i.subject;
|
|
11523
|
-
const body = i.body;
|
|
11524
|
-
if (!rawTo || !subject || body === void 0 || body === null) {
|
|
11525
|
-
return { ok: false, error: '"to", "subject" and "body" are required.' };
|
|
11526
|
-
}
|
|
11527
|
-
const to = normalizeRecipient(rawTo);
|
|
11528
|
-
const mb = resolveMailbox(ctx);
|
|
11529
|
-
const identity = await register(mb, ctx);
|
|
11530
|
-
const type = i.type ?? (to === "*" ? "broadcast" : "note");
|
|
11531
|
-
const msg = await mb.send({
|
|
11532
|
-
from: identity.callerId,
|
|
11533
|
-
to,
|
|
11534
|
-
type,
|
|
11535
|
-
subject,
|
|
11536
|
-
body,
|
|
11537
|
-
priority: i.priority ?? "normal",
|
|
11538
|
-
replyTo: i.replyTo
|
|
11539
|
-
});
|
|
11540
|
-
return {
|
|
11541
|
-
ok: true,
|
|
11542
|
-
messageId: msg.id,
|
|
11543
|
-
from: identity.callerId,
|
|
11544
|
-
to: msg.to,
|
|
11545
|
-
summary: `Mail sent to ${msg.to === "*" ? "all agents" : msg.to} as ${identity.callerId}.`
|
|
11546
|
-
};
|
|
11547
|
-
}
|
|
11548
|
-
};
|
|
11549
|
-
}
|
|
11550
|
-
function makeMailInboxTool(opts = {}) {
|
|
11551
|
-
const resolveMailbox = makeResolver(opts);
|
|
11552
|
-
return {
|
|
11553
|
-
name: "mail_inbox",
|
|
11554
|
-
description: 'Read your unread mail from other agents on this project and mark it read. Covers mail addressed to you directly, to your base name (e.g. "leader"), and broadcasts ("*"). Urgent steer/btw mail is already injected automatically \u2014 use this to catch up on notes, questions, handoffs, results, and review requests (type="review" \u2014 passive asks where no reply is required). Best called after a long stretch of tool work. Set completed=true to finish every returned message in the same call.',
|
|
11555
|
-
usageHint: 'mail_inbox (optionally: limit=10, markRead=false to peek, completed=true outcome="handled")',
|
|
11556
|
-
category: "Coordination",
|
|
11557
|
-
permission: "auto",
|
|
11558
|
-
mutating: true,
|
|
11559
|
-
capabilities: [ToolCapabilities.COORDINATION_MAIL],
|
|
11560
|
-
inputSchema: {
|
|
11561
|
-
type: "object",
|
|
11562
|
-
properties: {
|
|
11563
|
-
limit: { type: "number", description: "Max messages to return (default 20)." },
|
|
11564
|
-
markRead: {
|
|
11565
|
-
type: "boolean",
|
|
11566
|
-
description: "Add a read receipt for each returned message (default true)."
|
|
11567
|
-
},
|
|
11568
|
-
completed: {
|
|
11569
|
-
type: "boolean",
|
|
11570
|
-
description: "Also mark each returned message completed (default false)."
|
|
11571
|
-
},
|
|
11572
|
-
outcome: {
|
|
11573
|
-
type: "string",
|
|
11574
|
-
description: "Completion outcome to store when completed=true."
|
|
11575
|
-
}
|
|
11576
|
-
}
|
|
11577
|
-
},
|
|
11578
|
-
async execute(input, ctx) {
|
|
11579
|
-
const i = input ?? {};
|
|
11580
|
-
const limit = i.limit ?? 20;
|
|
11581
|
-
const markRead = i.markRead ?? true;
|
|
11582
|
-
const completed = i.completed ?? false;
|
|
11583
|
-
const outcome = i.outcome;
|
|
11584
|
-
const mb = resolveMailbox(ctx);
|
|
11585
|
-
const identity = await register(mb, ctx);
|
|
11586
|
-
const targets = [identity.callerId];
|
|
11587
|
-
if (identity.baseId !== identity.callerId) targets.push(identity.baseId);
|
|
11588
|
-
const batches = await Promise.all(
|
|
11589
|
-
targets.map(
|
|
11590
|
-
(to) => mb.query({ to, unreadBy: identity.callerId, limit }).catch(() => [])
|
|
11591
|
-
)
|
|
11592
|
-
);
|
|
11593
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11594
|
-
const messages = batches.flat().filter((m) => {
|
|
11595
|
-
if (seen.has(m.id) || m.from === identity.callerId) return false;
|
|
11596
|
-
seen.add(m.id);
|
|
11597
|
-
return true;
|
|
11598
|
-
}).slice(0, limit);
|
|
11599
|
-
if (markRead || completed) {
|
|
11600
|
-
await mb.ackMany({
|
|
11601
|
-
acks: messages.map((m) => ({
|
|
11602
|
-
messageId: m.id,
|
|
11603
|
-
readerId: identity.callerId,
|
|
11604
|
-
read: markRead,
|
|
11605
|
-
completed,
|
|
11606
|
-
outcome: completed ? outcome : void 0
|
|
11607
|
-
}))
|
|
11608
|
-
}).catch(() => null);
|
|
11609
|
-
}
|
|
11610
|
-
return {
|
|
11611
|
-
ok: true,
|
|
11612
|
-
you: identity.callerId,
|
|
11613
|
-
count: messages.length,
|
|
11614
|
-
messages: messages.map((m) => ({
|
|
11615
|
-
id: m.id,
|
|
11616
|
-
from: m.from,
|
|
11617
|
-
to: m.to,
|
|
11618
|
-
type: m.type,
|
|
11619
|
-
subject: m.subject,
|
|
11620
|
-
body: m.body.length > 2e3 ? `${m.body.slice(0, 2e3)}\u2026 [truncated]` : m.body,
|
|
11621
|
-
timestamp: m.timestamp,
|
|
11622
|
-
replyTo: m.replyTo
|
|
11623
|
-
})),
|
|
11624
|
-
summary: messages.length === 0 ? "Inbox empty." : `${messages.length} unread message(s)${markRead ? " (marked read)" : ""}${completed ? " (completed)" : ""}. Reply with mail_send using the sender id.`
|
|
11625
|
-
};
|
|
11626
|
-
}
|
|
11627
|
-
};
|
|
11628
|
-
}
|
|
11629
|
-
|
|
11630
12440
|
// src/coordination/fleet-status-tool.ts
|
|
11631
12441
|
var TASK_SNIPPET_CHARS = 120;
|
|
11632
12442
|
function snippet(s) {
|
|
@@ -12271,6 +13081,166 @@ Idle workers: ${idleWorkerIds.join(", ")}`,
|
|
|
12271
13081
|
}
|
|
12272
13082
|
}
|
|
12273
13083
|
};
|
|
13084
|
+
|
|
13085
|
+
// src/coordination/mail-tools.ts
|
|
13086
|
+
function makeResolver(opts) {
|
|
13087
|
+
return opts.resolveMailbox ?? ((ctx) => new GlobalMailbox(opts.projectDir ?? defaultResolveProjectDir(ctx), opts.events));
|
|
13088
|
+
}
|
|
13089
|
+
async function register(mb, ctx) {
|
|
13090
|
+
const identity = resolveMailboxIdentity(ctx);
|
|
13091
|
+
try {
|
|
13092
|
+
await mb.registerAgent({
|
|
13093
|
+
agentId: identity.callerId,
|
|
13094
|
+
sessionId: identity.sessionId,
|
|
13095
|
+
name: identity.name,
|
|
13096
|
+
role: identity.role,
|
|
13097
|
+
pid: process.pid,
|
|
13098
|
+
source: ctx.meta["source"] ?? "cli"
|
|
13099
|
+
});
|
|
13100
|
+
await mb.heartbeat({ agentId: identity.callerId });
|
|
13101
|
+
} catch {
|
|
13102
|
+
}
|
|
13103
|
+
return identity;
|
|
13104
|
+
}
|
|
13105
|
+
function makeMailSendTool(opts = {}) {
|
|
13106
|
+
const resolveMailbox = makeResolver(opts);
|
|
13107
|
+
return {
|
|
13108
|
+
name: "mail_send",
|
|
13109
|
+
description: 'Send a mail to other agents working on this project (other terminals, TUIs, WebUIs). Use it to hand off work, ask questions, announce what you just did, or request a review (type="review" \u2014 passive ask, no immediate reply required). to="*" broadcasts to everyone; to="leader" reaches every leader process; an exact id like "leader@a1b2c3d4" reaches one agent. Recipients see your mail automatically before their next step. Pick the type that matches the intent: note (default), ask (blocking question), assign (task), steer (mid-task direction), result (completion notice), review (passive ask), btw/status/broadcast/control (informational).',
|
|
13110
|
+
usageHint: 'mail_send to="<id>" type="review" body="please skim <file>"',
|
|
13111
|
+
category: "Coordination",
|
|
13112
|
+
permission: "auto",
|
|
13113
|
+
mutating: true,
|
|
13114
|
+
capabilities: [ToolCapabilities.COORDINATION_MAIL],
|
|
13115
|
+
inputSchema: {
|
|
13116
|
+
type: "object",
|
|
13117
|
+
properties: {
|
|
13118
|
+
to: {
|
|
13119
|
+
type: "string",
|
|
13120
|
+
description: 'Recipient: exact agent id ("leader@a1b2c3d4"), base alias ("leader"), or "*" / "all" for everyone.'
|
|
13121
|
+
},
|
|
13122
|
+
subject: { type: "string", description: "Short subject line." },
|
|
13123
|
+
body: { type: "string", description: "The message." },
|
|
13124
|
+
type: {
|
|
13125
|
+
type: "string",
|
|
13126
|
+
enum: ["note", "ask", "assign", "steer", "btw", "broadcast", "status", "result", "review"],
|
|
13127
|
+
description: 'Message intent. Default: "broadcast" when to="*", otherwise "note". Actionable types: ask (blocking question), assign (task), result (completion notice), review (passive ask \u2014 code/doc/PR review, no immediate reply required). Behavioral: steer (mid-task direction change), btw (low-priority aside). Informational: note/status/broadcast/control.'
|
|
13128
|
+
},
|
|
13129
|
+
priority: { type: "string", enum: ["low", "normal", "high"] },
|
|
13130
|
+
replyTo: { type: "string", description: "Message id this replies to." }
|
|
13131
|
+
},
|
|
13132
|
+
required: ["to", "subject", "body"]
|
|
13133
|
+
},
|
|
13134
|
+
async execute(input, ctx) {
|
|
13135
|
+
const i = input ?? {};
|
|
13136
|
+
const rawTo = i.to;
|
|
13137
|
+
const subject = i.subject;
|
|
13138
|
+
const body = i.body;
|
|
13139
|
+
if (!rawTo || !subject || body === void 0 || body === null) {
|
|
13140
|
+
return { ok: false, error: '"to", "subject" and "body" are required.' };
|
|
13141
|
+
}
|
|
13142
|
+
const to = normalizeRecipient(rawTo);
|
|
13143
|
+
const mb = resolveMailbox(ctx);
|
|
13144
|
+
const identity = await register(mb, ctx);
|
|
13145
|
+
const type = i.type ?? (to === "*" ? "broadcast" : "note");
|
|
13146
|
+
const msg = await mb.send({
|
|
13147
|
+
from: identity.callerId,
|
|
13148
|
+
to,
|
|
13149
|
+
type,
|
|
13150
|
+
subject,
|
|
13151
|
+
body,
|
|
13152
|
+
priority: i.priority ?? "normal",
|
|
13153
|
+
replyTo: i.replyTo
|
|
13154
|
+
});
|
|
13155
|
+
return {
|
|
13156
|
+
ok: true,
|
|
13157
|
+
messageId: msg.id,
|
|
13158
|
+
from: identity.callerId,
|
|
13159
|
+
to: msg.to,
|
|
13160
|
+
summary: `Mail sent to ${msg.to === "*" ? "all agents" : msg.to} as ${identity.callerId}.`
|
|
13161
|
+
};
|
|
13162
|
+
}
|
|
13163
|
+
};
|
|
13164
|
+
}
|
|
13165
|
+
function makeMailInboxTool(opts = {}) {
|
|
13166
|
+
const resolveMailbox = makeResolver(opts);
|
|
13167
|
+
return {
|
|
13168
|
+
name: "mail_inbox",
|
|
13169
|
+
description: 'Read your unread mail from other agents on this project and mark it read. Covers mail addressed to you directly, to your base name (e.g. "leader"), and broadcasts ("*"). Urgent steer/btw mail is already injected automatically \u2014 use this to catch up on notes, questions, handoffs, results, and review requests (type="review" \u2014 passive asks where no reply is required). Best called after a long stretch of tool work. Set completed=true to finish every returned message in the same call.',
|
|
13170
|
+
usageHint: 'mail_inbox (optionally: limit=10, markRead=false to peek, completed=true outcome="handled")',
|
|
13171
|
+
category: "Coordination",
|
|
13172
|
+
permission: "auto",
|
|
13173
|
+
mutating: true,
|
|
13174
|
+
capabilities: [ToolCapabilities.COORDINATION_MAIL],
|
|
13175
|
+
inputSchema: {
|
|
13176
|
+
type: "object",
|
|
13177
|
+
properties: {
|
|
13178
|
+
limit: { type: "number", description: "Max messages to return (default 20)." },
|
|
13179
|
+
markRead: {
|
|
13180
|
+
type: "boolean",
|
|
13181
|
+
description: "Add a read receipt for each returned message (default true)."
|
|
13182
|
+
},
|
|
13183
|
+
completed: {
|
|
13184
|
+
type: "boolean",
|
|
13185
|
+
description: "Also mark each returned message completed (default false)."
|
|
13186
|
+
},
|
|
13187
|
+
outcome: {
|
|
13188
|
+
type: "string",
|
|
13189
|
+
description: "Completion outcome to store when completed=true."
|
|
13190
|
+
}
|
|
13191
|
+
}
|
|
13192
|
+
},
|
|
13193
|
+
async execute(input, ctx) {
|
|
13194
|
+
const i = input ?? {};
|
|
13195
|
+
const limit = i.limit ?? 20;
|
|
13196
|
+
const markRead = i.markRead ?? true;
|
|
13197
|
+
const completed = i.completed ?? false;
|
|
13198
|
+
const outcome = i.outcome;
|
|
13199
|
+
const mb = resolveMailbox(ctx);
|
|
13200
|
+
const identity = await register(mb, ctx);
|
|
13201
|
+
const targets = [identity.callerId];
|
|
13202
|
+
if (identity.baseId !== identity.callerId) targets.push(identity.baseId);
|
|
13203
|
+
const batches = await Promise.all(
|
|
13204
|
+
targets.map(
|
|
13205
|
+
(to) => mb.query({ to, unreadBy: identity.callerId, limit }).catch(() => [])
|
|
13206
|
+
)
|
|
13207
|
+
);
|
|
13208
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13209
|
+
const messages = batches.flat().filter((m) => {
|
|
13210
|
+
if (seen.has(m.id) || m.from === identity.callerId) return false;
|
|
13211
|
+
seen.add(m.id);
|
|
13212
|
+
return true;
|
|
13213
|
+
}).slice(0, limit);
|
|
13214
|
+
if (markRead || completed) {
|
|
13215
|
+
await mb.ackMany({
|
|
13216
|
+
acks: messages.map((m) => ({
|
|
13217
|
+
messageId: m.id,
|
|
13218
|
+
readerId: identity.callerId,
|
|
13219
|
+
read: markRead,
|
|
13220
|
+
completed,
|
|
13221
|
+
outcome: completed ? outcome : void 0
|
|
13222
|
+
}))
|
|
13223
|
+
}).catch(() => null);
|
|
13224
|
+
}
|
|
13225
|
+
return {
|
|
13226
|
+
ok: true,
|
|
13227
|
+
you: identity.callerId,
|
|
13228
|
+
count: messages.length,
|
|
13229
|
+
messages: messages.map((m) => ({
|
|
13230
|
+
id: m.id,
|
|
13231
|
+
from: m.from,
|
|
13232
|
+
to: m.to,
|
|
13233
|
+
type: m.type,
|
|
13234
|
+
subject: m.subject,
|
|
13235
|
+
body: m.body.length > 2e3 ? `${m.body.slice(0, 2e3)}\u2026 [truncated]` : m.body,
|
|
13236
|
+
timestamp: m.timestamp,
|
|
13237
|
+
replyTo: m.replyTo
|
|
13238
|
+
})),
|
|
13239
|
+
summary: messages.length === 0 ? "Inbox empty." : `${messages.length} unread message(s)${markRead ? " (marked read)" : ""}${completed ? " (completed)" : ""}. Reply with mail_send using the sender id.`
|
|
13240
|
+
};
|
|
13241
|
+
}
|
|
13242
|
+
};
|
|
13243
|
+
}
|
|
12274
13244
|
var MAILBOX_FILE2 = "_mailbox.jsonl";
|
|
12275
13245
|
var LINE_SEPARATOR2 = "\n";
|
|
12276
13246
|
var MESSAGE_CACHE_MAX_ENTRIES2 = 1e4;
|
|
@@ -16272,6 +17242,6 @@ ${input.detail}`
|
|
|
16272
17242
|
}
|
|
16273
17243
|
};
|
|
16274
17244
|
|
|
16275
|
-
export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AdaptiveConcurrencyController, AgentMonitorService, AutonomousBrain, AutonomousCoordinator, BUG_HUNTER_AGENT, BUILD_AGENTS, BrainDecisionQueue, BrainMonitor, BudgetExceededError, BudgetThresholdSignal, ChangeManager, CollabSession, ConsensusProtocol, DECISION_TIMEOUT_MS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_QUALITY_CHECKS, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultBrainArbiter, DefaultMailbox, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetSupervisor, FleetUsageAggregator, GlobalMailbox, HEAVY_BUDGET, HumanEscalatingBrainArbiter, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, KnowledgeGraph, LIGHT_BUDGET, LargeAnswerStore, MAILBOX_BRIDGE_LOCK_FILENAME, MAILBOX_BRIDGE_TOKEN_FILENAME, MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD, MAILBOX_HEALTH_DEFAULT_FROM, MAILBOX_HEALTH_DEFAULT_INTERVAL_MS, MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS, MEDIUM_BUDGET, META_AGENTS, MailboxHealthWatchdog, NULL_FLEET_BUS, ObservableBrainArbiter, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, TIMEOUT_PREEMPT_FRACTION, TaskAuctioneer, TaskDAG, VERIFY_AGENTS, acquireOrJoin, actionToAckInput, applyRosterBudget, attachAutoExtend, attachDepWatcherBridge, buildDownAlert, buildRecoveryAlert, composeDirectorPrompt, composeSubagentPrompt, createAgentMonitorService, createDelegateTool, createMailboxHooks, createMessage, detectEcosystem, dispatchAgent, finalize, formatHumanPrompt, getAgentDefinition, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, mailboxSessionTag, makeAgentSubagentRunner, makeAskResultTool, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetTool as makeFleetHealthTool, makeFleetTool as makeFleetSessionTool, makeFleetStatusTool, makeFleetTool, makeFleetTool as makeFleetUsageTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeRollUpTool, makeSpawnTool, makeTerminateAllTool, makeTerminateTool, makeWorkCompleteTool, normalizeRecipient, readLiveLock, recordPackageAction, release, resolveMailboxIdentity, resolveProjectDir, rosterSummaryFromConfigs, scoreAgents, startPackageOutdatedWatcher, updatePackageOutdatedStatus, validateWatchdogOptions, withDisabledToolFiltering };
|
|
17245
|
+
export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AdaptiveConcurrencyController, AgentMonitorService, AutonomousBrain, AutonomousCoordinator, BUG_HUNTER_AGENT, BUILD_AGENTS, BrainDecisionQueue, BrainMonitor, BudgetExceededError, BudgetThresholdSignal, ChangeManager, CollabSession, ConsensusProtocol, DECISION_TIMEOUT_MS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_QUALITY_CHECKS, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DEPENDENCY_FILE_PATTERNS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultBrainArbiter, DefaultMailbox, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetSupervisor, FleetUsageAggregator, GlobalMailbox, HEAVY_BUDGET, HumanEscalatingBrainArbiter, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, KnowledgeGraph, LIGHT_BUDGET, LargeAnswerStore, MAILBOX_BRIDGE_LOCK_FILENAME, MAILBOX_BRIDGE_TOKEN_FILENAME, MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD, MAILBOX_HEALTH_DEFAULT_FROM, MAILBOX_HEALTH_DEFAULT_INTERVAL_MS, MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS, MATRIX_PHASE_KEYS, MEDIUM_BUDGET, META_AGENTS, MailboxHealthWatchdog, NULL_FLEET_BUS, ObservableBrainArbiter, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, TIMEOUT_PREEMPT_FRACTION, TaskAuctioneer, TaskDAG, VERIFY_AGENTS, WorktreeIntegrationError, acquireOrJoin, actionToAckInput, applyRosterBudget, attachAutoExtend, attachDepWatcherBridge, buildDownAlert, buildRecoveryAlert, composeDirectorPrompt, composeSubagentPrompt, createAgentMonitorService, createDelegateTool, createMailboxHooks, createMessage, detectEcosystem, dispatchAgent, finalize, formatHumanPrompt, getAgentDefinition, getFullPackageLog, getManifestPackages, getPackageAuthor, getPackagesByAgent, isValidMatrixKey, mailboxSessionTag, makeAgentSubagentRunner, makeAskResultTool, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetTool as makeFleetHealthTool, makeFleetTool as makeFleetSessionTool, makeFleetStatusTool, makeFleetTool, makeFleetTool as makeFleetUsageTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeQualityGateTool, makeRollUpTool, makeSpawnTool, makeTerminateAllTool, makeTerminateTool, makeWorkCompleteTool, matrixKeyKind, normalizeRecipient, phaseForRole, readLiveLock, recordPackageAction, release, resolveImplementationModelTarget, resolveMailboxIdentity, resolveModelMatrix, resolveModelMatrixResolution, resolveModelTargetFromEntry, resolveProjectDir, resolveSubagentModelTarget, resolveSubagentWorktreeDecision, roleNeedsIndependentReviewModel, rosterSummaryFromConfigs, sameModelReference, scoreAgents, startPackageOutdatedWatcher, subagentNeedsWorktree, updatePackageOutdatedStatus, validateWatchdogOptions, withDisabledToolFiltering, wrapSubagentRunnerWithWorktrees };
|
|
16276
17246
|
//# sourceMappingURL=index.js.map
|
|
16277
17247
|
//# sourceMappingURL=index.js.map
|