@voybio/ace-swarm 0.2.4 → 2.4.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/CHANGELOG.md +11 -1
- package/README.md +20 -13
- package/assets/.agents/skills/eval-harness/SKILL.md +14 -0
- package/assets/.agents/skills/handoff-lint/SKILL.md +14 -0
- package/assets/.agents/skills/incident-commander/SKILL.md +14 -0
- package/assets/.agents/skills/memory-curator/SKILL.md +14 -0
- package/assets/.agents/skills/release-sentry/SKILL.md +14 -0
- package/assets/.agents/skills/risk-quant/SKILL.md +14 -0
- package/assets/.agents/skills/schema-forge/SKILL.md +14 -0
- package/assets/.agents/skills/state-auditor/SKILL.md +14 -0
- package/assets/agent-state/EVIDENCE_LOG.md +1 -1
- package/assets/agent-state/MODULES/gates/gate-correctness.json +1 -1
- package/assets/agent-state/MODULES/roles/capability-framework.json +41 -0
- package/assets/agent-state/MODULES/roles/capability-git.json +33 -0
- package/assets/agent-state/MODULES/roles/capability-safety.json +37 -0
- package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +21 -0
- package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +43 -0
- package/assets/agent-state/MODULES/schemas/WORKSPACE_SESSION_REGISTRY.schema.json +11 -0
- package/assets/agent-state/STATUS.md +2 -2
- package/assets/scripts/ace-hook-dispatch.mjs +70 -6
- package/assets/scripts/render-mcp-configs.sh +19 -5
- package/dist/ace-context.js +22 -1
- package/dist/ace-server-instructions.js +3 -3
- package/dist/ace-state-resolver.js +5 -3
- package/dist/astgrep-index.d.ts +9 -1
- package/dist/astgrep-index.js +14 -3
- package/dist/cli.js +52 -20
- package/dist/handoff-registry.js +5 -5
- package/dist/helpers/artifacts.d.ts +19 -0
- package/dist/helpers/artifacts.js +152 -0
- package/dist/helpers/bootstrap.d.ts +24 -0
- package/dist/helpers/bootstrap.js +894 -0
- package/dist/helpers/constants.d.ts +53 -0
- package/dist/helpers/constants.js +288 -0
- package/dist/helpers/drift.d.ts +13 -0
- package/dist/helpers/drift.js +45 -0
- package/dist/helpers/path-utils.d.ts +17 -0
- package/dist/helpers/path-utils.js +104 -0
- package/dist/helpers/store-resolution.d.ts +19 -0
- package/dist/helpers/store-resolution.js +301 -0
- package/dist/helpers/workspace-root.d.ts +3 -0
- package/dist/helpers/workspace-root.js +80 -0
- package/dist/helpers.d.ts +8 -123
- package/dist/helpers.js +8 -1747
- package/dist/job-scheduler.js +3 -3
- package/dist/local-model-runtime.js +12 -1
- package/dist/model-bridge.d.ts +7 -0
- package/dist/model-bridge.js +75 -5
- package/dist/orchestrator-supervisor.d.ts +14 -0
- package/dist/orchestrator-supervisor.js +72 -1
- package/dist/run-ledger.js +3 -3
- package/dist/runtime-command.d.ts +8 -0
- package/dist/runtime-command.js +38 -6
- package/dist/runtime-executor.d.ts +14 -0
- package/dist/runtime-executor.js +669 -171
- package/dist/runtime-profile.d.ts +32 -0
- package/dist/runtime-profile.js +89 -13
- package/dist/runtime-tool-specs.d.ts +21 -0
- package/dist/runtime-tool-specs.js +78 -3
- package/dist/safe-edit.d.ts +7 -0
- package/dist/safe-edit.js +163 -37
- package/dist/schemas.js +19 -0
- package/dist/shared.d.ts +2 -2
- package/dist/status-events.js +9 -6
- package/dist/store/ace-packed-store.d.ts +3 -2
- package/dist/store/ace-packed-store.js +188 -110
- package/dist/store/bootstrap-store.d.ts +1 -1
- package/dist/store/bootstrap-store.js +94 -81
- package/dist/store/cache-workspace.d.ts +22 -0
- package/dist/store/cache-workspace.js +149 -0
- package/dist/store/materializers/context-snapshot-materializer.js +6 -7
- package/dist/store/materializers/hook-context-materializer.d.ts +6 -9
- package/dist/store/materializers/hook-context-materializer.js +11 -21
- package/dist/store/materializers/host-file-materializer.js +6 -0
- package/dist/store/materializers/projection-manager.d.ts +0 -1
- package/dist/store/materializers/projection-manager.js +5 -13
- package/dist/store/materializers/scheduler-projection-materializer.js +1 -1
- package/dist/store/materializers/vericify-projector.d.ts +7 -7
- package/dist/store/materializers/vericify-projector.js +11 -11
- package/dist/store/repositories/local-model-runtime-repository.d.ts +120 -3
- package/dist/store/repositories/local-model-runtime-repository.js +242 -6
- package/dist/store/skills-install.d.ts +4 -0
- package/dist/store/skills-install.js +21 -12
- package/dist/store/state-reader.d.ts +2 -0
- package/dist/store/state-reader.js +20 -0
- package/dist/store/store-artifacts.d.ts +7 -0
- package/dist/store/store-artifacts.js +27 -1
- package/dist/store/store-authority-audit.d.ts +18 -1
- package/dist/store/store-authority-audit.js +115 -5
- package/dist/store/store-snapshot.d.ts +3 -0
- package/dist/store/store-snapshot.js +22 -2
- package/dist/store/workspace-store-paths.d.ts +39 -0
- package/dist/store/workspace-store-paths.js +94 -0
- package/dist/store/write-coordinator.d.ts +65 -0
- package/dist/store/write-coordinator.js +386 -0
- package/dist/todo-state.js +5 -5
- package/dist/tools-agent.js +319 -34
- package/dist/tools-discovery.js +1 -1
- package/dist/tools-files.d.ts +7 -0
- package/dist/tools-files.js +299 -10
- package/dist/tools-framework.js +107 -27
- package/dist/tools-handoff.js +2 -2
- package/dist/tools-lifecycle.js +4 -4
- package/dist/tools-memory.js +6 -6
- package/dist/tools-todo.js +2 -2
- package/dist/tracker-adapters.d.ts +1 -1
- package/dist/tracker-adapters.js +13 -18
- package/dist/tracker-sync.js +5 -3
- package/dist/tui/agent-runner.js +3 -1
- package/dist/tui/chat.js +103 -7
- package/dist/tui/dashboard.d.ts +1 -0
- package/dist/tui/dashboard.js +43 -0
- package/dist/tui/layout.d.ts +20 -0
- package/dist/tui/layout.js +31 -1
- package/dist/tui/local-model-contract.d.ts +6 -2
- package/dist/tui/local-model-contract.js +16 -3
- package/dist/vericify-bridge.d.ts +5 -0
- package/dist/vericify-bridge.js +27 -3
- package/dist/workspace-manager.d.ts +30 -3
- package/dist/workspace-manager.js +257 -27
- package/package.json +1 -2
- package/dist/internal-tool-runtime.d.ts +0 -21
- package/dist/internal-tool-runtime.js +0 -136
- package/dist/store/workspace-snapshot.d.ts +0 -26
- package/dist/store/workspace-snapshot.js +0 -107
package/dist/tools-agent.js
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
* Agent, skill, kernel, and task-pack tool registrations.
|
|
3
3
|
*/
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { ALL_AGENTS, COMPOSABLE_AGENTS, SWARM_AGENTS, SWARM_SUBAGENT_MAP, classifyPathSource, getAgentInstructionPath, getAgentManifestPath, getKernelArtifactPath, isSwarmRole, listAvailableSkills, readAgentInstructions, readAgentManifest, readKernelArtifact, readSkillInstructions, readTaskArtifact, resolveWritableTaskPath,
|
|
5
|
+
import { ALL_AGENTS, COMPOSABLE_AGENTS, SWARM_AGENTS, SWARM_SUBAGENT_MAP, classifyPathSource, getAgentInstructionPath, getAgentManifestPath, getKernelArtifactPath, isSwarmRole, listAvailableSkills, readAgentInstructions, readAgentManifest, readKernelArtifact, readSkillInstructions, readTaskArtifact, resolveWorkspaceRoot, resolveWritableTaskPath, safeWriteAsync, } from "./helpers.js";
|
|
6
6
|
import { loadRuntimeProfile, readRuntimePromptTemplate, readRuntimeProfileState, validateRuntimeProfileContent, } from "./runtime-profile.js";
|
|
7
7
|
import { getUnattendedSession, listUnattendedSessions, startUnattendedSession, stopUnattendedSession, validateRuntimeExecutorSessionRegistryContent, waitForUnattendedSession, } from "./runtime-executor.js";
|
|
8
8
|
import { executeRuntimeTool, listRuntimeToolSpecs, loadRuntimeToolRegistry, validateRuntimeToolRegistryContent, } from "./runtime-tool-specs.js";
|
|
9
|
-
import {
|
|
9
|
+
import { createWorkspaceSessionAsync, listWorkspaceSessions, removeWorkspaceSession, resolveRuntimeWorkspaceRoot, validateManagedWorkspacePath, } from "./workspace-manager.js";
|
|
10
10
|
import { getTrackerAdapter, listTrackerAdapterKinds, loadTrackerSnapshot, validateTrackerSnapshotContent, } from "./tracker-adapters.js";
|
|
11
11
|
import { refreshTrackerSnapshot } from "./tracker-sync.js";
|
|
12
12
|
import { appendVericifyProcessPost, loadVericifyBridgeSnapshot, loadVericifyProcessPostLog, refreshVericifyBridgeSnapshot, validateVericifyBridgeSnapshotContent, validateVericifyProcessPostLogContent, } from "./vericify-bridge.js";
|
|
13
13
|
import { getRoleTitle, ROLE_ENUM, KERNEL_KEY_ENUM, ROLE_TITLES } from "./shared.js";
|
|
14
14
|
import { createDefaultModelBridgeClients, resolveLocalModelRuntime, runLocalModelTask, } from "./local-model-runtime.js";
|
|
15
|
+
import { withLocalModelRuntimeRepository } from "./store/repositories/local-model-runtime-repository.js";
|
|
15
16
|
import { executeAceInternalTool } from "./ace-internal-tools.js";
|
|
16
17
|
import { ModelBridge } from "./model-bridge.js";
|
|
17
18
|
import { getVericifyContextPacket, getVericifyDelta } from "./vericify-context.js";
|
|
@@ -52,6 +53,11 @@ function extractToolTextContent(result) {
|
|
|
52
53
|
.filter(Boolean)
|
|
53
54
|
.join("\n");
|
|
54
55
|
}
|
|
56
|
+
function didExecuteGatesPass(result) {
|
|
57
|
+
if (Boolean(result?.isError))
|
|
58
|
+
return false;
|
|
59
|
+
return !extractToolTextContent(result).trimStart().startsWith("❌");
|
|
60
|
+
}
|
|
55
61
|
function mapRoleToTaskType(role) {
|
|
56
62
|
switch (role) {
|
|
57
63
|
case "vos":
|
|
@@ -71,15 +77,180 @@ function extractHandoffId(text) {
|
|
|
71
77
|
const lineMatch = text.match(/handoff_id:\s*([A-Z0-9-]+)/i);
|
|
72
78
|
return lineMatch?.[1];
|
|
73
79
|
}
|
|
80
|
+
function stepLabel(index) {
|
|
81
|
+
return `step-${index + 1}`;
|
|
82
|
+
}
|
|
83
|
+
function isShipBoundaryTask(task) {
|
|
84
|
+
return /\b(ship|release|promot(?:e|ion)|land|merge)\b/i.test(task);
|
|
85
|
+
}
|
|
86
|
+
function isImplementationRole(role) {
|
|
87
|
+
return role === "coders" || role === "builder";
|
|
88
|
+
}
|
|
74
89
|
async function buildOrchestratorSteps(task, sessionId) {
|
|
75
90
|
void sessionId;
|
|
76
91
|
return [{ role: "orchestrator", task }];
|
|
77
92
|
}
|
|
93
|
+
function normalizeExplicitPlanSteps(steps, task) {
|
|
94
|
+
const originalIdByLabel = new Map();
|
|
95
|
+
const normalized = steps.map((step, index) => {
|
|
96
|
+
const id = `explicit-${index + 1}`;
|
|
97
|
+
originalIdByLabel.set(stepLabel(index), id);
|
|
98
|
+
return {
|
|
99
|
+
...step,
|
|
100
|
+
id,
|
|
101
|
+
depends_on_ids: [...(step.depends_on ?? [])],
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
for (const step of normalized) {
|
|
105
|
+
step.depends_on_ids = step.depends_on_ids.map((dependency) => originalIdByLabel.get(dependency) ?? dependency);
|
|
106
|
+
}
|
|
107
|
+
let insertedResearch = false;
|
|
108
|
+
for (let index = 0; index < normalized.length; index += 1) {
|
|
109
|
+
const step = normalized[index];
|
|
110
|
+
if (step.role !== "spec")
|
|
111
|
+
continue;
|
|
112
|
+
const hasResearchBefore = normalized.slice(0, index).some((candidate) => candidate.role === "research");
|
|
113
|
+
if (hasResearchBefore)
|
|
114
|
+
continue;
|
|
115
|
+
const researchId = `auto-research-${index + 1}`;
|
|
116
|
+
normalized.splice(index, 0, {
|
|
117
|
+
id: researchId,
|
|
118
|
+
role: "research",
|
|
119
|
+
task: `Validate source-backed claims and gather evidence before spec work: ${step.task}`,
|
|
120
|
+
tool_scope: ["recall_context", "read_workspace_file", "build_continuity_packet"],
|
|
121
|
+
depends_on_ids: [],
|
|
122
|
+
});
|
|
123
|
+
step.depends_on_ids = Array.from(new Set([researchId, ...step.depends_on_ids]));
|
|
124
|
+
insertedResearch = true;
|
|
125
|
+
index += 1;
|
|
126
|
+
}
|
|
127
|
+
const shipFanoutEnabled = isShipBoundaryTask(task) || normalized.some((step) => isShipBoundaryTask(step.task));
|
|
128
|
+
if (shipFanoutEnabled) {
|
|
129
|
+
const hasReviewRole = normalized.some((step) => step.role === "skeptic");
|
|
130
|
+
const hasSecurityRole = normalized.some((step) => step.role === "security");
|
|
131
|
+
const hasQaRole = normalized.some((step) => step.role === "qa");
|
|
132
|
+
const hasReleaseRole = normalized.some((step) => step.role === "release");
|
|
133
|
+
const lastImplementation = [...normalized].reverse().find((step) => isImplementationRole(step.role)) ?? normalized.at(-1);
|
|
134
|
+
const implementationDependency = lastImplementation ? [lastImplementation.id] : [];
|
|
135
|
+
const fanoutStepIds = [];
|
|
136
|
+
if (!hasReviewRole) {
|
|
137
|
+
const reviewId = `auto-review-${normalized.length + 1}`;
|
|
138
|
+
normalized.push({
|
|
139
|
+
id: reviewId,
|
|
140
|
+
role: "skeptic",
|
|
141
|
+
task: `Review ship readiness for: ${task}`,
|
|
142
|
+
tool_scope: ["execute_gates", "validate_framework"],
|
|
143
|
+
depends_on_ids: implementationDependency,
|
|
144
|
+
});
|
|
145
|
+
fanoutStepIds.push(reviewId);
|
|
146
|
+
}
|
|
147
|
+
if (!hasSecurityRole) {
|
|
148
|
+
const securityId = `auto-security-${normalized.length + 1}`;
|
|
149
|
+
normalized.push({
|
|
150
|
+
id: securityId,
|
|
151
|
+
role: "security",
|
|
152
|
+
task: `Assess security readiness for: ${task}`,
|
|
153
|
+
tool_scope: ["execute_gates", "validate_framework"],
|
|
154
|
+
depends_on_ids: implementationDependency,
|
|
155
|
+
});
|
|
156
|
+
fanoutStepIds.push(securityId);
|
|
157
|
+
}
|
|
158
|
+
if (!hasQaRole) {
|
|
159
|
+
const qaId = `auto-qa-${normalized.length + 1}`;
|
|
160
|
+
normalized.push({
|
|
161
|
+
id: qaId,
|
|
162
|
+
role: "qa",
|
|
163
|
+
task: `Validate ship readiness for: ${task}`,
|
|
164
|
+
tool_scope: ["run_tests", "execute_gates", "git_diff"],
|
|
165
|
+
depends_on_ids: implementationDependency,
|
|
166
|
+
});
|
|
167
|
+
fanoutStepIds.push(qaId);
|
|
168
|
+
}
|
|
169
|
+
if (!hasReleaseRole && fanoutStepIds.length > 0) {
|
|
170
|
+
normalized.push({
|
|
171
|
+
id: `auto-release-${normalized.length + 1}`,
|
|
172
|
+
role: "release",
|
|
173
|
+
task: `Finalize ship decision for: ${task}`,
|
|
174
|
+
tool_scope: ["git_status", "execute_gates", "validate_framework"],
|
|
175
|
+
depends_on_ids: fanoutStepIds,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const finalIdByInternal = new Map();
|
|
180
|
+
normalized.forEach((step, index) => {
|
|
181
|
+
finalIdByInternal.set(step.id, stepLabel(index));
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
steps: normalized.map((step) => ({
|
|
185
|
+
role: step.role,
|
|
186
|
+
task: step.task,
|
|
187
|
+
depends_on: step.depends_on_ids.length > 0
|
|
188
|
+
? step.depends_on_ids.map((dependency) => finalIdByInternal.get(dependency) ?? dependency)
|
|
189
|
+
: undefined,
|
|
190
|
+
parallel_group: step.parallel_group,
|
|
191
|
+
tool_scope: step.tool_scope,
|
|
192
|
+
})),
|
|
193
|
+
insertedResearch,
|
|
194
|
+
shipFanoutEnabled,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async function normalizeOrchestratorPlanSteps(task, steps, sessionId) {
|
|
198
|
+
if (!Array.isArray(steps) || steps.length === 0) {
|
|
199
|
+
return {
|
|
200
|
+
planSource: "orchestrator_default_step",
|
|
201
|
+
normalization: {
|
|
202
|
+
steps: await buildOrchestratorSteps(task, sessionId),
|
|
203
|
+
insertedResearch: false,
|
|
204
|
+
shipFanoutEnabled: false,
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
planSource: "explicit_steps",
|
|
210
|
+
normalization: normalizeExplicitPlanSteps(steps, task),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async function persistAcceptanceTraceMap(input) {
|
|
214
|
+
return safeWriteAsync("agent-state/ACCEPTANCE_TRACE_MAP.json", JSON.stringify({
|
|
215
|
+
version: 1,
|
|
216
|
+
generated_at: new Date().toISOString(),
|
|
217
|
+
plan_id: input.plan.plan_id,
|
|
218
|
+
task: input.task,
|
|
219
|
+
plan_source: input.planSource,
|
|
220
|
+
policies: {
|
|
221
|
+
inserted_research_before_spec: input.insertedResearch,
|
|
222
|
+
ship_fanout_enabled: input.shipFanoutEnabled,
|
|
223
|
+
},
|
|
224
|
+
steps: input.plan.steps.map((step) => ({
|
|
225
|
+
step_id: step.step_id,
|
|
226
|
+
role: step.role,
|
|
227
|
+
task: step.task,
|
|
228
|
+
depends_on: step.depends_on ?? [],
|
|
229
|
+
tool_scope: step.tool_scope ?? [],
|
|
230
|
+
verification_role: step.role === "coders" || step.role === "builder"
|
|
231
|
+
? "qa"
|
|
232
|
+
: step.role === "spec"
|
|
233
|
+
? "research"
|
|
234
|
+
: null,
|
|
235
|
+
})),
|
|
236
|
+
}, null, 2));
|
|
237
|
+
}
|
|
78
238
|
function appendUniqueNote(target, note) {
|
|
79
239
|
if (!target.includes(note)) {
|
|
80
240
|
target.push(note);
|
|
81
241
|
}
|
|
82
242
|
}
|
|
243
|
+
function createToolOnlyBridgeResult(step, reason) {
|
|
244
|
+
return {
|
|
245
|
+
bridge_id: `tool-only-${step.step_id}-${Date.now()}`,
|
|
246
|
+
role: step.role,
|
|
247
|
+
status: "completed",
|
|
248
|
+
summary: `Tool-only orchestrator completion for ${step.step_id} (${step.role}): ${step.task}. ${reason}`,
|
|
249
|
+
turns: 0,
|
|
250
|
+
tool_calls: [],
|
|
251
|
+
child_results: [],
|
|
252
|
+
};
|
|
253
|
+
}
|
|
83
254
|
function buildDefaultOrchestratorAmendment(input) {
|
|
84
255
|
if (input.result.status !== "completed" || input.step.role !== "coders") {
|
|
85
256
|
return undefined;
|
|
@@ -271,6 +442,45 @@ export function registerAgentTools(server) {
|
|
|
271
442
|
],
|
|
272
443
|
};
|
|
273
444
|
});
|
|
445
|
+
server.tool("get_transition_log", "Read the transition log for a session. Answers 'why stopped?', 'what changed?', and 'what evidence caused it?' from the ACE transition record store.", {
|
|
446
|
+
session_id: z.string().describe("Session ID to read transitions for"),
|
|
447
|
+
limit: z.number().int().positive().optional().default(20).describe("Max transitions to return (default: 20)"),
|
|
448
|
+
}, async ({ session_id, limit }) => {
|
|
449
|
+
try {
|
|
450
|
+
const transitions = await withLocalModelRuntimeRepository(resolveWorkspaceRoot(), (repo) => repo.getTransitionLog(session_id, limit ?? 20));
|
|
451
|
+
return {
|
|
452
|
+
content: [{ type: "text", text: JSON.stringify(transitions, null, 2) }],
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
return {
|
|
457
|
+
content: [{ type: "text", text: `Error reading transition log: ${error instanceof Error ? error.message : String(error)}` }],
|
|
458
|
+
isError: true,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
server.tool("get_capability_snapshot", "Read the capability snapshot for a specific turn. Shows which tools were available, their cost class, and any unavailable tools with reasons.", {
|
|
463
|
+
session_id: z.string().describe("Session ID"),
|
|
464
|
+
turn_number: z.number().int().positive().describe("Turn number"),
|
|
465
|
+
}, async ({ session_id, turn_number }) => {
|
|
466
|
+
try {
|
|
467
|
+
const snapshot = await withLocalModelRuntimeRepository(resolveWorkspaceRoot(), (repo) => repo.getCapabilitySnapshot(session_id, turn_number));
|
|
468
|
+
if (!snapshot) {
|
|
469
|
+
return {
|
|
470
|
+
content: [{ type: "text", text: `No capability snapshot found for session ${session_id} turn ${turn_number}` }],
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
content: [{ type: "text", text: JSON.stringify(snapshot, null, 2) }],
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
catch (error) {
|
|
478
|
+
return {
|
|
479
|
+
content: [{ type: "text", text: `Error reading capability snapshot: ${error instanceof Error ? error.message : String(error)}` }],
|
|
480
|
+
isError: true,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
});
|
|
274
484
|
server.tool("validate_runtime_profile", "Validate ACE runtime profile markdown content or the current ACE_WORKFLOW.md file", {
|
|
275
485
|
content: z
|
|
276
486
|
.string()
|
|
@@ -482,7 +692,19 @@ export function registerAgentTools(server) {
|
|
|
482
692
|
.boolean()
|
|
483
693
|
.optional()
|
|
484
694
|
.describe("If false, keep the managed workspace session after completion"),
|
|
485
|
-
|
|
695
|
+
emit_to: z
|
|
696
|
+
.array(z.enum(["tui", "tracker", "handoff", "vericify"]))
|
|
697
|
+
.optional()
|
|
698
|
+
.describe("Output emission targets for this session. Defaults to ['tui', 'vericify']."),
|
|
699
|
+
silent_unless_blocked: z
|
|
700
|
+
.boolean()
|
|
701
|
+
.optional()
|
|
702
|
+
.describe("If true, turns that produce no tool calls are classified as no_op_success and do not emit."),
|
|
703
|
+
require_approval_before_emit: z
|
|
704
|
+
.boolean()
|
|
705
|
+
.optional()
|
|
706
|
+
.describe("If true, require operator approval before emitting meaningful_completion output."),
|
|
707
|
+
}, async ({ task, context_json, workspace_name, workspace_path, objective_id, tracker_item_id, max_turns, turn_timeout_ms, auto_cleanup, emit_to, silent_unless_blocked, require_approval_before_emit, }) => {
|
|
486
708
|
const result = await startUnattendedSession({
|
|
487
709
|
task,
|
|
488
710
|
context: parseOptionalJsonObject(context_json),
|
|
@@ -493,6 +715,9 @@ export function registerAgentTools(server) {
|
|
|
493
715
|
max_turns,
|
|
494
716
|
turn_timeout_ms,
|
|
495
717
|
auto_cleanup,
|
|
718
|
+
emit_to,
|
|
719
|
+
silent_unless_blocked,
|
|
720
|
+
require_approval_before_emit,
|
|
496
721
|
});
|
|
497
722
|
return {
|
|
498
723
|
content: [
|
|
@@ -687,37 +912,77 @@ export function registerAgentTools(server) {
|
|
|
687
912
|
.optional()
|
|
688
913
|
.describe("Optional workspace root override; defaults to the active workspace"),
|
|
689
914
|
}, async ({ task, steps, execution_mode, max_turns_per_step, provider, model, base_url, ollama_url, workspace_root }, extra) => {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
915
|
+
let runtime;
|
|
916
|
+
const runtimeWarnings = [];
|
|
917
|
+
try {
|
|
918
|
+
runtime = resolveLocalModelRuntime({
|
|
919
|
+
workspaceRoot: workspace_root,
|
|
920
|
+
provider,
|
|
921
|
+
model,
|
|
922
|
+
baseUrl: base_url,
|
|
923
|
+
ollamaUrl: ollama_url,
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
catch (error) {
|
|
927
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
928
|
+
appendUniqueNote(runtimeWarnings, `Model bridge runtime unavailable; continuing in tool-only mode. ${message}`);
|
|
929
|
+
}
|
|
930
|
+
const effectiveWorkspaceRoot = runtime?.workspaceRoot ??
|
|
931
|
+
(workspace_root ? resolveRuntimeWorkspaceRoot(workspace_root) : resolveWorkspaceRoot());
|
|
697
932
|
const sessionId = typeof extra?.sessionId === "string" ? extra.sessionId : undefined;
|
|
698
|
-
const planSource =
|
|
699
|
-
const planSteps = Array.isArray(steps) && steps.length > 0
|
|
700
|
-
? steps
|
|
701
|
-
: await buildOrchestratorSteps(task, sessionId);
|
|
933
|
+
const { planSource, normalization } = await normalizeOrchestratorPlanSteps(task, steps, sessionId);
|
|
702
934
|
const plan = createTaskPlan({
|
|
703
935
|
task,
|
|
704
|
-
steps:
|
|
936
|
+
steps: normalization.steps,
|
|
705
937
|
execution_mode: execution_mode ?? "sequential",
|
|
706
938
|
});
|
|
707
|
-
const
|
|
939
|
+
const traceArtifactPath = await persistAcceptanceTraceMap({
|
|
940
|
+
plan,
|
|
941
|
+
task,
|
|
942
|
+
planSource,
|
|
943
|
+
insertedResearch: normalization.insertedResearch,
|
|
944
|
+
shipFanoutEnabled: normalization.shipFanoutEnabled,
|
|
945
|
+
});
|
|
946
|
+
const bridge = runtime
|
|
947
|
+
? new ModelBridge(createDefaultModelBridgeClients(runtime))
|
|
948
|
+
: undefined;
|
|
708
949
|
const fallbackHandoffPrefix = `LOCAL-${plan.plan_id}-`;
|
|
709
950
|
const vericifyWarnings = [];
|
|
951
|
+
const appendSessionPlanTransition = async (stepId, from, to, reason, reasonCode) => {
|
|
952
|
+
if (!sessionId)
|
|
953
|
+
return;
|
|
954
|
+
await withLocalModelRuntimeRepository(effectiveWorkspaceRoot, async (repo) => {
|
|
955
|
+
const step = plan.steps.find((candidate) => candidate.step_id === stepId);
|
|
956
|
+
if (!step)
|
|
957
|
+
return;
|
|
958
|
+
await repo.appendTransitionRecord({
|
|
959
|
+
session_id: sessionId,
|
|
960
|
+
subject_kind: "plan_step",
|
|
961
|
+
subject_id: `${plan.plan_id}/${step.step_id}`,
|
|
962
|
+
from,
|
|
963
|
+
to,
|
|
964
|
+
reason,
|
|
965
|
+
reason_code: reasonCode,
|
|
966
|
+
evidence_refs: step.tool_scope ?? [],
|
|
967
|
+
});
|
|
968
|
+
}).catch(() => undefined);
|
|
969
|
+
};
|
|
710
970
|
const supervised = await superviseTaskPlan(plan, {
|
|
711
971
|
async spawnStep(step) {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
972
|
+
if (bridge && runtime) {
|
|
973
|
+
return bridge.spawn({
|
|
974
|
+
task: step.task,
|
|
975
|
+
role: step.role,
|
|
976
|
+
workspace: runtime.workspaceRoot,
|
|
977
|
+
maxTurns: max_turns_per_step ?? 6,
|
|
978
|
+
provider: runtime.provider,
|
|
979
|
+
model: runtime.model,
|
|
980
|
+
toolScope: step.tool_scope,
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
const reason = runtimeWarnings[0] ??
|
|
984
|
+
"No local model provider/runtime was resolved for model bridge execution.";
|
|
985
|
+
return createToolOnlyBridgeResult(step, reason);
|
|
721
986
|
},
|
|
722
987
|
async createHandoff({ step, plan: activePlan }) {
|
|
723
988
|
const created = await executeAceInternalTool("create_handoff", {
|
|
@@ -747,7 +1012,12 @@ export function registerAgentTools(server) {
|
|
|
747
1012
|
note,
|
|
748
1013
|
}, sessionId);
|
|
749
1014
|
},
|
|
750
|
-
amendPlan({ plan: activePlan, step, result }) {
|
|
1015
|
+
async amendPlan({ plan: activePlan, step, result }) {
|
|
1016
|
+
await appendSessionPlanTransition(step.step_id, "running", step.status, `Plan step ${step.step_id} ${step.status}: ${result.summary}`, step.status === "done"
|
|
1017
|
+
? "step_completed"
|
|
1018
|
+
: step.status === "blocked"
|
|
1019
|
+
? "step_blocked"
|
|
1020
|
+
: "step_failed");
|
|
751
1021
|
return buildDefaultOrchestratorAmendment({
|
|
752
1022
|
plan: activePlan,
|
|
753
1023
|
step,
|
|
@@ -756,13 +1026,13 @@ export function registerAgentTools(server) {
|
|
|
756
1026
|
},
|
|
757
1027
|
async getVericifyContext() {
|
|
758
1028
|
return tryVericifyPacket(() => getVericifyContextPacket({
|
|
759
|
-
workspaceRoot:
|
|
1029
|
+
workspaceRoot: effectiveWorkspaceRoot,
|
|
760
1030
|
}), (message) => appendUniqueNote(vericifyWarnings, `Vericify context unavailable for ${plan.plan_id}: ${message}`));
|
|
761
1031
|
},
|
|
762
1032
|
async getVericifyDelta(since) {
|
|
763
1033
|
return tryVericifyPacket(() => getVericifyDelta({
|
|
764
1034
|
since,
|
|
765
|
-
workspaceRoot:
|
|
1035
|
+
workspaceRoot: effectiveWorkspaceRoot,
|
|
766
1036
|
}), (message) => appendUniqueNote(vericifyWarnings, `Vericify delta unavailable for ${plan.plan_id}: ${message}`));
|
|
767
1037
|
},
|
|
768
1038
|
async openCircuitBreaker(reason) {
|
|
@@ -779,7 +1049,7 @@ export function registerAgentTools(server) {
|
|
|
779
1049
|
async executeGates() {
|
|
780
1050
|
const result = await executeAceInternalTool("execute_gates", {}, sessionId);
|
|
781
1051
|
return {
|
|
782
|
-
ok:
|
|
1052
|
+
ok: didExecuteGatesPass(result),
|
|
783
1053
|
summary: extractToolTextContent(result),
|
|
784
1054
|
};
|
|
785
1055
|
},
|
|
@@ -794,6 +1064,9 @@ export function registerAgentTools(server) {
|
|
|
794
1064
|
}, sessionId);
|
|
795
1065
|
},
|
|
796
1066
|
async emitStatusEvent(event) {
|
|
1067
|
+
if (event.step_id) {
|
|
1068
|
+
await appendSessionPlanTransition(event.step_id, "planned", "running", `Plan step ${event.step_id} started: ${event.summary}`, "step_started");
|
|
1069
|
+
}
|
|
797
1070
|
await executeAceInternalTool("emit_status_event", {
|
|
798
1071
|
source_module: "capability-ops",
|
|
799
1072
|
event_type: "ORCHESTRATOR_STEP",
|
|
@@ -818,11 +1091,23 @@ export function registerAgentTools(server) {
|
|
|
818
1091
|
{
|
|
819
1092
|
type: "text",
|
|
820
1093
|
text: JSON.stringify({
|
|
821
|
-
runtime,
|
|
1094
|
+
runtime: runtime ?? null,
|
|
1095
|
+
execution_backend: runtime ? "model_bridge" : "tool_only",
|
|
1096
|
+
runtime_warnings: runtimeWarnings,
|
|
1097
|
+
workspace_root: effectiveWorkspaceRoot,
|
|
822
1098
|
plan_source: planSource,
|
|
823
1099
|
planning_note: planSource === "orchestrator_default_step"
|
|
824
1100
|
? "Auto-planning currently starts with ACE-Orchestrator. Pass explicit steps for multi-step orchestration."
|
|
825
|
-
:
|
|
1101
|
+
: normalization.insertedResearch
|
|
1102
|
+
? "Research was inserted ahead of spec work to require source-backed evidence before specification."
|
|
1103
|
+
: normalization.shipFanoutEnabled
|
|
1104
|
+
? "Ship fan-out enforcement added review, security, QA, and release coordination steps."
|
|
1105
|
+
: null,
|
|
1106
|
+
trace_artifact_path: traceArtifactPath,
|
|
1107
|
+
engskills_imports: {
|
|
1108
|
+
inserted_research_before_spec: normalization.insertedResearch,
|
|
1109
|
+
ship_fanout_enabled: normalization.shipFanoutEnabled,
|
|
1110
|
+
},
|
|
826
1111
|
plan: supervised.plan,
|
|
827
1112
|
step_summaries,
|
|
828
1113
|
handoff_ids: supervised.handoff_ids,
|
|
@@ -1122,7 +1407,7 @@ export function registerAgentTools(server) {
|
|
|
1122
1407
|
.optional()
|
|
1123
1408
|
.describe("Optional hook timeout override in milliseconds"),
|
|
1124
1409
|
}, async ({ workspace_name, workspace_path, source, objective_id, tracker_item_id, root, hooks_timeout_ms, }) => {
|
|
1125
|
-
const result =
|
|
1410
|
+
const result = await createWorkspaceSessionAsync({
|
|
1126
1411
|
workspace_name,
|
|
1127
1412
|
workspace_path,
|
|
1128
1413
|
source,
|
|
@@ -1173,7 +1458,7 @@ export function registerAgentTools(server) {
|
|
|
1173
1458
|
.optional()
|
|
1174
1459
|
.describe("Optional hook timeout override in milliseconds"),
|
|
1175
1460
|
}, async ({ session_id, workspace_path, root, hooks_timeout_ms }) => {
|
|
1176
|
-
const result = removeWorkspaceSession({
|
|
1461
|
+
const result = await removeWorkspaceSession({
|
|
1177
1462
|
session_id,
|
|
1178
1463
|
workspace_path,
|
|
1179
1464
|
root,
|
|
@@ -1509,7 +1794,7 @@ export function registerAgentTools(server) {
|
|
|
1509
1794
|
"",
|
|
1510
1795
|
].join("\n");
|
|
1511
1796
|
const existing = readTaskArtifact("lessons");
|
|
1512
|
-
const path =
|
|
1797
|
+
const path = await safeWriteAsync(resolveWritableTaskPath("lessons"), `${existing}${entry}`);
|
|
1513
1798
|
return {
|
|
1514
1799
|
content: [{ type: "text", text: `✅ Lesson recorded in ${path}` }],
|
|
1515
1800
|
};
|
package/dist/tools-discovery.js
CHANGED
|
@@ -25,7 +25,7 @@ export function registerDiscoveryTools(server) {
|
|
|
25
25
|
.optional()
|
|
26
26
|
.describe("Include rep_astgrep.cxml corpus mining when available (default: true)"),
|
|
27
27
|
}, async ({ scope, append_evidence, emit_event, include_rep_corpus }) => {
|
|
28
|
-
const result = refreshAstgrepIndex({
|
|
28
|
+
const result = await refreshAstgrepIndex({
|
|
29
29
|
scope,
|
|
30
30
|
append_evidence,
|
|
31
31
|
emit_event,
|
package/dist/tools-files.d.ts
CHANGED
|
@@ -2,5 +2,12 @@
|
|
|
2
2
|
* File operation tool registrations + new safe-edit and diff tools.
|
|
3
3
|
*/
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
export interface AstgrepRewriteTargetPlan {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
affected_files: string[];
|
|
8
|
+
target_file?: string;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function planAstgrepRewriteTargets(files: string[]): AstgrepRewriteTargetPlan;
|
|
5
12
|
export declare function registerFileTools(server: McpServer): void;
|
|
6
13
|
//# sourceMappingURL=tools-files.d.ts.map
|