@voybio/ace-swarm 2.4.1 → 2.4.2
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 +8 -0
- package/README.md +501 -56
- package/dist/cli.js +282 -2
- package/dist/helpers/constants.d.ts +2 -0
- package/dist/helpers/constants.js +1 -0
- package/dist/hermes/bridge-protocol.d.ts +41 -0
- package/dist/hermes/bridge-protocol.js +70 -0
- package/dist/hermes/launch-profile.d.ts +19 -0
- package/dist/hermes/launch-profile.js +81 -0
- package/dist/hermes/session-manager.d.ts +42 -0
- package/dist/hermes/session-manager.js +187 -0
- package/dist/local-model-runtime.d.ts +11 -0
- package/dist/local-model-runtime.js +58 -2
- package/dist/schemas.js +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +22 -4
- package/dist/store/materializers/vericify-projector.js +3 -0
- package/dist/store/repositories/local-model-runtime-repository.d.ts +12 -0
- package/dist/store/repositories/local-model-runtime-repository.js +3 -0
- package/dist/tools-agent.js +6 -1
- package/dist/tools.d.ts +4 -1
- package/dist/tools.js +35 -13
- package/dist/tui/chat.d.ts +8 -0
- package/dist/tui/chat.js +74 -0
- package/dist/tui/index.d.ts +7 -0
- package/dist/tui/index.js +35 -1
- package/dist/tui/layout.d.ts +1 -0
- package/dist/tui/layout.js +4 -1
- package/dist/tui/provider-discovery.js +15 -13
- package/dist/vericify-bridge.d.ts +3 -0
- package/dist/vericify-bridge.js +3 -0
- package/package.json +2 -1
- package/scripts/hermes_bridge_worker.py +136 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { HERMES_BRIDGE_PROTOCOL_VERSION, HermesBridgeFrameDecoder, } from "./bridge-protocol.js";
|
|
8
|
+
import { resolveHermesLaunchProfile, } from "./launch-profile.js";
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
const DIST_ROOT = resolve(__dirname, "..");
|
|
12
|
+
const PACKAGE_ROOT = resolve(DIST_ROOT, "..");
|
|
13
|
+
const MIN_HERMES_LOCAL_CONTEXT_LENGTH = 65536;
|
|
14
|
+
function summarizeToolResult(value) {
|
|
15
|
+
if (typeof value === "string")
|
|
16
|
+
return value.slice(0, 500);
|
|
17
|
+
try {
|
|
18
|
+
return JSON.stringify(value).slice(0, 500);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return String(value).slice(0, 500);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function eventText(event) {
|
|
25
|
+
const value = event.text ?? event.message;
|
|
26
|
+
return typeof value === "string" ? value : "";
|
|
27
|
+
}
|
|
28
|
+
function hermesBaseUrl(provider, baseUrl) {
|
|
29
|
+
const normalized = String(baseUrl ?? "").replace(/\/+$/, "");
|
|
30
|
+
if (provider === "ollama" && normalized && !normalized.endsWith("/v1")) {
|
|
31
|
+
return `${normalized}/v1`;
|
|
32
|
+
}
|
|
33
|
+
return normalized;
|
|
34
|
+
}
|
|
35
|
+
export class HermesSubprocessExecutor {
|
|
36
|
+
options;
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.options = options;
|
|
39
|
+
}
|
|
40
|
+
async runTurn(options) {
|
|
41
|
+
const sessionId = `hermes-${randomUUID()}`;
|
|
42
|
+
const shadowId = `shadow-${randomUUID()}`;
|
|
43
|
+
const hermesHome = mkdtempSync(resolve(tmpdir(), "ace-hermes-home-"));
|
|
44
|
+
mkdirSync(hermesHome, { recursive: true });
|
|
45
|
+
const toolScope = options.toolScope ?? [];
|
|
46
|
+
const cliPath = resolve(DIST_ROOT, "cli.js");
|
|
47
|
+
const baseUrl = hermesBaseUrl(options.runtime.provider, options.runtime.baseUrl ?? options.runtime.ollamaUrl);
|
|
48
|
+
writeFileSync(resolve(hermesHome, "config.yaml"), [
|
|
49
|
+
"model:",
|
|
50
|
+
` default: ${JSON.stringify(options.runtime.model)}`,
|
|
51
|
+
" provider: custom",
|
|
52
|
+
` base_url: ${JSON.stringify(baseUrl)}`,
|
|
53
|
+
" api_key: no-key-required",
|
|
54
|
+
` context_length: ${MIN_HERMES_LOCAL_CONTEXT_LENGTH}`,
|
|
55
|
+
"",
|
|
56
|
+
"auxiliary:",
|
|
57
|
+
" compression:",
|
|
58
|
+
` model: ${JSON.stringify(options.runtime.model)}`,
|
|
59
|
+
" provider: custom",
|
|
60
|
+
` base_url: ${JSON.stringify(baseUrl)}`,
|
|
61
|
+
" api_key: no-key-required",
|
|
62
|
+
` context_length: ${MIN_HERMES_LOCAL_CONTEXT_LENGTH}`,
|
|
63
|
+
"",
|
|
64
|
+
"mcp_servers:",
|
|
65
|
+
" ace_shadow:",
|
|
66
|
+
` command: ${JSON.stringify(process.execPath)}`,
|
|
67
|
+
" args:",
|
|
68
|
+
` - ${JSON.stringify(cliPath)}`,
|
|
69
|
+
" - mcp-shadow",
|
|
70
|
+
` - ${JSON.stringify("--tools")}`,
|
|
71
|
+
` - ${JSON.stringify(toolScope.join(","))}`,
|
|
72
|
+
" timeout: 30",
|
|
73
|
+
"",
|
|
74
|
+
].join("\n"), "utf-8");
|
|
75
|
+
const launchProfile = this.options.launchProfile ??
|
|
76
|
+
resolveHermesLaunchProfile({
|
|
77
|
+
workspaceRoot: options.runtime.workspaceRoot,
|
|
78
|
+
cliHermesRoot: this.options.hermesRoot,
|
|
79
|
+
cliHermesPython: this.options.pythonCommand,
|
|
80
|
+
});
|
|
81
|
+
const workerPath = this.options.workerPath ?? launchProfile.worker_path;
|
|
82
|
+
const hermesRoot = this.options.hermesRoot ?? launchProfile.hermes_root;
|
|
83
|
+
const command = this.options.command ?? launchProfile.command;
|
|
84
|
+
const [bin, ...args] = command;
|
|
85
|
+
if (!bin) {
|
|
86
|
+
throw new Error("Hermes launch command must contain at least one executable argument.");
|
|
87
|
+
}
|
|
88
|
+
const child = spawn(bin, [...args, workerPath], {
|
|
89
|
+
cwd: PACKAGE_ROOT,
|
|
90
|
+
env: {
|
|
91
|
+
...process.env,
|
|
92
|
+
HERMES_HOME: hermesHome,
|
|
93
|
+
ACE_WORKSPACE_ROOT: options.runtime.workspaceRoot,
|
|
94
|
+
},
|
|
95
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
96
|
+
});
|
|
97
|
+
const decoder = new HermesBridgeFrameDecoder();
|
|
98
|
+
const events = [];
|
|
99
|
+
const malformed = [];
|
|
100
|
+
const stderr = [];
|
|
101
|
+
let finalText = "";
|
|
102
|
+
let turns = 0;
|
|
103
|
+
let sawError = "";
|
|
104
|
+
child.stdout.on("data", (chunk) => {
|
|
105
|
+
for (const frame of decoder.push(chunk)) {
|
|
106
|
+
if (frame.ok) {
|
|
107
|
+
events.push(frame.event);
|
|
108
|
+
if (frame.event.type === "final") {
|
|
109
|
+
finalText = eventText(frame.event);
|
|
110
|
+
const rawTurns = frame.event.turns;
|
|
111
|
+
turns = typeof rawTurns === "number" ? rawTurns : turns;
|
|
112
|
+
}
|
|
113
|
+
if (frame.event.type === "error") {
|
|
114
|
+
sawError = eventText(frame.event) || "Hermes bridge error";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
malformed.push(frame.reason);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
child.stderr.on("data", (chunk) => {
|
|
123
|
+
stderr.push(chunk.toString("utf8"));
|
|
124
|
+
});
|
|
125
|
+
const request = {
|
|
126
|
+
session_id: sessionId,
|
|
127
|
+
turn_id: randomUUID(),
|
|
128
|
+
hermes_root: hermesRoot ?? "",
|
|
129
|
+
task: options.task,
|
|
130
|
+
role: options.role,
|
|
131
|
+
provider: options.runtime.provider,
|
|
132
|
+
model: options.runtime.model,
|
|
133
|
+
base_url: options.runtime.baseUrl ?? options.runtime.ollamaUrl,
|
|
134
|
+
max_turns: options.maxTurns,
|
|
135
|
+
system_prompt: "You are running inside ACE Hermes-local mode. Use only the imported ACE MCP toolset for tool calls. Do not use plain text as executable authority.",
|
|
136
|
+
};
|
|
137
|
+
child.stdin.end(`${JSON.stringify(request)}\n`);
|
|
138
|
+
const exitCode = await new Promise((resolvePromise, reject) => {
|
|
139
|
+
child.on("error", reject);
|
|
140
|
+
child.on("close", resolvePromise);
|
|
141
|
+
});
|
|
142
|
+
for (const frame of decoder.push(new Uint8Array(), true)) {
|
|
143
|
+
if (frame.ok)
|
|
144
|
+
events.push(frame.event);
|
|
145
|
+
else
|
|
146
|
+
malformed.push(frame.reason);
|
|
147
|
+
}
|
|
148
|
+
if (!this.options.keepTemp) {
|
|
149
|
+
rmSync(hermesHome, { recursive: true, force: true });
|
|
150
|
+
}
|
|
151
|
+
const toolCalls = events
|
|
152
|
+
.filter((event) => event.type === "tool_complete")
|
|
153
|
+
.map((event) => ({
|
|
154
|
+
tool: String(event.tool ?? "unknown"),
|
|
155
|
+
ok: !event.is_error,
|
|
156
|
+
summary: summarizeToolResult(event.result ?? eventText(event)),
|
|
157
|
+
isError: Boolean(event.is_error),
|
|
158
|
+
}));
|
|
159
|
+
const status = sawError || malformed.length > 0 || exitCode !== 0 ? "failed" : "completed";
|
|
160
|
+
const summary = status === "failed"
|
|
161
|
+
? sawError ||
|
|
162
|
+
`Hermes bridge failed${malformed.length ? `; malformed_frames=${malformed.join(",")}` : ""}${stderr.length ? `; stderr=${stderr.join("").slice(0, 500)}` : ""}`
|
|
163
|
+
: finalText || "Hermes-local turn completed.";
|
|
164
|
+
return {
|
|
165
|
+
result: {
|
|
166
|
+
bridge_id: sessionId,
|
|
167
|
+
role: options.role,
|
|
168
|
+
status,
|
|
169
|
+
summary,
|
|
170
|
+
turns,
|
|
171
|
+
tool_calls: toolCalls,
|
|
172
|
+
child_results: [],
|
|
173
|
+
evidence_refs: toolCalls.map((tool) => `tool:${tool.tool}`),
|
|
174
|
+
},
|
|
175
|
+
metadata: {
|
|
176
|
+
bridge_protocol_version: HERMES_BRIDGE_PROTOCOL_VERSION,
|
|
177
|
+
hermes_session_id: sessionId,
|
|
178
|
+
shadow_mcp_session_id: shadowId,
|
|
179
|
+
execution_engine: "hermes_local",
|
|
180
|
+
provider: options.runtime.provider,
|
|
181
|
+
model: options.runtime.model,
|
|
182
|
+
events,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=session-manager.js.map
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { type ExecutionEngine } from "./helpers/constants.js";
|
|
1
2
|
import { type BridgeResult, type ModelBridgeClients } from "./model-bridge.js";
|
|
2
3
|
import type { AceContextTier } from "./ace-context.js";
|
|
3
4
|
import { type LocalModelExecutionPolicy } from "./local-model-policy.js";
|
|
4
5
|
import type { RuntimeModelClass } from "./runtime-profile.js";
|
|
6
|
+
import { type HermesLocalExecutor, type HermesLocalTurnResult } from "./hermes/session-manager.js";
|
|
7
|
+
import { type HermesLaunchProfile } from "./hermes/launch-profile.js";
|
|
5
8
|
export interface LocalModelRuntimeConfig {
|
|
6
9
|
workspaceRoot: string;
|
|
10
|
+
executionEngine: ExecutionEngine;
|
|
7
11
|
provider: string;
|
|
8
12
|
model: string;
|
|
9
13
|
baseUrl?: string;
|
|
@@ -16,6 +20,7 @@ export interface RunLocalModelTaskOptions {
|
|
|
16
20
|
role?: string;
|
|
17
21
|
workspaceRoot?: string;
|
|
18
22
|
provider?: string;
|
|
23
|
+
engine?: string;
|
|
19
24
|
model?: string;
|
|
20
25
|
baseUrl?: string;
|
|
21
26
|
ollamaUrl?: string;
|
|
@@ -24,6 +29,8 @@ export interface RunLocalModelTaskOptions {
|
|
|
24
29
|
modelClass?: RuntimeModelClass;
|
|
25
30
|
toolScope?: string[];
|
|
26
31
|
clients?: ModelBridgeClients;
|
|
32
|
+
hermesExecutor?: HermesLocalExecutor;
|
|
33
|
+
hermesLaunchProfile?: HermesLaunchProfile;
|
|
27
34
|
}
|
|
28
35
|
export interface RunLocalModelTaskResult {
|
|
29
36
|
runtime: LocalModelRuntimeConfig;
|
|
@@ -31,15 +38,19 @@ export interface RunLocalModelTaskResult {
|
|
|
31
38
|
routingSummary?: string;
|
|
32
39
|
policy: LocalModelExecutionPolicy;
|
|
33
40
|
result: BridgeResult;
|
|
41
|
+
hermes?: HermesLocalTurnResult["metadata"];
|
|
34
42
|
}
|
|
43
|
+
export declare function parseExecutionEngine(input?: string): ExecutionEngine | undefined;
|
|
35
44
|
export declare function resolveTier(requested: RunLocalModelTaskOptions["tier"], provider: string, model: string, role: string): AceContextTier;
|
|
36
45
|
export declare function createDefaultModelBridgeClients(runtime: Pick<LocalModelRuntimeConfig, "providerBaseUrls">): ModelBridgeClients;
|
|
37
46
|
export declare function resolveLocalModelRuntime(input: {
|
|
38
47
|
workspaceRoot?: string;
|
|
39
48
|
provider?: string;
|
|
49
|
+
engine?: string;
|
|
40
50
|
model?: string;
|
|
41
51
|
baseUrl?: string;
|
|
42
52
|
ollamaUrl?: string;
|
|
53
|
+
hermesReady?: boolean;
|
|
43
54
|
}): LocalModelRuntimeConfig;
|
|
44
55
|
export declare function runLocalModelTask(options: RunLocalModelTaskOptions): Promise<RunLocalModelTaskResult>;
|
|
45
56
|
export { resolveLocalModelExecutionPolicy, resolveLocalModelClass } from "./local-model-policy.js";
|
|
@@ -1,12 +1,36 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { ROLE_ENUM } from "./shared.js";
|
|
3
3
|
import { resolveWorkspaceRoot } from "./helpers.js";
|
|
4
|
+
import { ALL_EXECUTION_ENGINES } from "./helpers/constants.js";
|
|
4
5
|
import { executeAceInternalTool } from "./ace-internal-tools.js";
|
|
5
6
|
import { ModelBridge } from "./model-bridge.js";
|
|
6
7
|
import { OllamaClient } from "./tui/ollama.js";
|
|
7
8
|
import { OpenAICompatibleClient, diagnoseChatRuntimeConfig, } from "./tui/openai-compatible.js";
|
|
8
9
|
import { discoverProviderContext } from "./tui/provider-discovery.js";
|
|
9
10
|
import { defaultToolScopeForPolicy, defaultTurnsForPolicy, resolveLocalModelExecutionPolicy, } from "./local-model-policy.js";
|
|
11
|
+
import { HermesSubprocessExecutor, } from "./hermes/session-manager.js";
|
|
12
|
+
import { resolveHermesLaunchProfile, } from "./hermes/launch-profile.js";
|
|
13
|
+
export function parseExecutionEngine(input) {
|
|
14
|
+
if (!input)
|
|
15
|
+
return undefined;
|
|
16
|
+
const normalized = input.trim().toLowerCase().replace(/-/g, "_");
|
|
17
|
+
return ALL_EXECUTION_ENGINES.includes(normalized)
|
|
18
|
+
? normalized
|
|
19
|
+
: undefined;
|
|
20
|
+
}
|
|
21
|
+
function isLocalProvider(provider) {
|
|
22
|
+
return provider === "ollama" || provider === "llama.cpp";
|
|
23
|
+
}
|
|
24
|
+
function resolveExecutionEngine(input) {
|
|
25
|
+
const parsed = parseExecutionEngine(input.requested);
|
|
26
|
+
if (parsed) {
|
|
27
|
+
if (parsed === "hermes_local" && !isLocalProvider(input.provider)) {
|
|
28
|
+
throw new Error("engine=hermes_local is only valid for local providers.");
|
|
29
|
+
}
|
|
30
|
+
return parsed;
|
|
31
|
+
}
|
|
32
|
+
return isLocalProvider(input.provider) && input.hermesReady ? "hermes_local" : "direct";
|
|
33
|
+
}
|
|
10
34
|
function extractTextContent(result) {
|
|
11
35
|
if (!result || typeof result !== "object")
|
|
12
36
|
return "";
|
|
@@ -80,6 +104,11 @@ export function resolveLocalModelRuntime(input) {
|
|
|
80
104
|
cliBaseUrl: input.baseUrl,
|
|
81
105
|
cliOllamaUrl: input.ollamaUrl,
|
|
82
106
|
});
|
|
107
|
+
const executionEngine = resolveExecutionEngine({
|
|
108
|
+
requested: input.engine,
|
|
109
|
+
provider: discovered.provider,
|
|
110
|
+
hermesReady: input.hermesReady,
|
|
111
|
+
});
|
|
83
112
|
if (discovered.provider === "ollama" && !discovered.ollamaUrl) {
|
|
84
113
|
throw new Error("Ollama base URL is not configured. Provide `--base-url`/`ollama_url`, set OLLAMA_HOST, or run `ace doctor --llm ollama --scan`.");
|
|
85
114
|
}
|
|
@@ -93,6 +122,7 @@ export function resolveLocalModelRuntime(input) {
|
|
|
93
122
|
}
|
|
94
123
|
return {
|
|
95
124
|
workspaceRoot,
|
|
125
|
+
executionEngine,
|
|
96
126
|
provider: discovered.provider,
|
|
97
127
|
model: discovered.model,
|
|
98
128
|
baseUrl: discovered.baseUrl,
|
|
@@ -105,6 +135,7 @@ export async function runLocalModelTask(options) {
|
|
|
105
135
|
const runtime = resolveLocalModelRuntime({
|
|
106
136
|
workspaceRoot: options.workspaceRoot,
|
|
107
137
|
provider: options.provider,
|
|
138
|
+
engine: options.engine,
|
|
108
139
|
model: options.model,
|
|
109
140
|
baseUrl: options.baseUrl,
|
|
110
141
|
ollamaUrl: options.ollamaUrl,
|
|
@@ -119,15 +150,40 @@ export async function runLocalModelTask(options) {
|
|
|
119
150
|
requested_tier: options.tier,
|
|
120
151
|
requested_model_class: options.modelClass,
|
|
121
152
|
});
|
|
153
|
+
const maxTurns = options.maxTurns ?? defaultTurnsForPolicy(role, policy);
|
|
154
|
+
const toolScope = options.toolScope ?? defaultToolScopeForPolicy(role, policy);
|
|
155
|
+
if (runtime.executionEngine === "hermes_local") {
|
|
156
|
+
const launchProfile = options.hermesLaunchProfile ?? resolveHermesLaunchProfile({ workspaceRoot: runtime.workspaceRoot });
|
|
157
|
+
const hermesExecutor = options.hermesExecutor ??
|
|
158
|
+
new HermesSubprocessExecutor({
|
|
159
|
+
launchProfile,
|
|
160
|
+
});
|
|
161
|
+
const hermes = await hermesExecutor.runTurn({
|
|
162
|
+
task: options.task,
|
|
163
|
+
role,
|
|
164
|
+
runtime,
|
|
165
|
+
policy,
|
|
166
|
+
toolScope,
|
|
167
|
+
maxTurns,
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
runtime,
|
|
171
|
+
role,
|
|
172
|
+
routingSummary,
|
|
173
|
+
policy,
|
|
174
|
+
result: hermes.result,
|
|
175
|
+
hermes: hermes.metadata,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
122
178
|
const result = await bridge.run({
|
|
123
179
|
task: options.task,
|
|
124
180
|
role,
|
|
125
181
|
workspace: runtime.workspaceRoot,
|
|
126
182
|
tier: policy.tier,
|
|
127
|
-
maxTurns
|
|
183
|
+
maxTurns,
|
|
128
184
|
provider: runtime.provider,
|
|
129
185
|
model: runtime.model,
|
|
130
|
-
toolScope
|
|
186
|
+
toolScope,
|
|
131
187
|
});
|
|
132
188
|
return {
|
|
133
189
|
runtime,
|
package/dist/schemas.js
CHANGED
|
@@ -436,6 +436,7 @@ const vericifyProcessPostSchema = z
|
|
|
436
436
|
agent_id: NON_EMPTY,
|
|
437
437
|
kind: z.enum(["intent", "progress", "blocker", "handoff_note", "stale_ack", "completion", "plan_proposal", "plan_quality_assessment"]),
|
|
438
438
|
summary: NON_EMPTY,
|
|
439
|
+
blocker_category: z.string().optional(),
|
|
439
440
|
tool_refs: z.array(z.string()),
|
|
440
441
|
evidence_refs: z.array(z.string()),
|
|
441
442
|
checkpoint_ref: z.string().optional(),
|
package/dist/server.d.ts
CHANGED
|
@@ -4,7 +4,10 @@ export declare const ACE_MCP_SERVER_VERSION = "0.2.1";
|
|
|
4
4
|
export interface CreateAceServerOptions {
|
|
5
5
|
toolGovernance?: boolean;
|
|
6
6
|
instructions?: string;
|
|
7
|
+
toolAllowlist?: readonly string[];
|
|
8
|
+
mode?: "public" | "hermes_shadow";
|
|
7
9
|
}
|
|
8
10
|
export declare function createAceServer(options?: CreateAceServerOptions): McpServer;
|
|
9
11
|
export declare function startStdioServer(logStartup?: boolean): Promise<void>;
|
|
12
|
+
export declare function startHermesShadowStdioServer(toolAllowlist: readonly string[], logStartup?: boolean): Promise<void>;
|
|
10
13
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.js
CHANGED
|
@@ -12,20 +12,26 @@ import { registerTools } from "./tools.js";
|
|
|
12
12
|
import { backfillHandoffsIntoScheduler } from "./tools-handoff.js";
|
|
13
13
|
export const ACE_MCP_SERVER_NAME = "ace-swarm";
|
|
14
14
|
export const ACE_MCP_SERVER_VERSION = "0.2.1";
|
|
15
|
+
const HERMES_SHADOW_INSTRUCTIONS = "ACE filtered shadow MCP tool transport for Hermes-local execution. Only tools allowed by the active ACE capability snapshot are registered; public ACE prompts and resources are not exposed.";
|
|
15
16
|
export function createAceServer(options = {}) {
|
|
16
17
|
const workspaceRoot = resolveWorkspaceRoot();
|
|
17
18
|
const server = new McpServer({
|
|
18
19
|
name: ACE_MCP_SERVER_NAME,
|
|
19
20
|
version: ACE_MCP_SERVER_VERSION,
|
|
20
21
|
}, {
|
|
21
|
-
instructions: options.instructions ??
|
|
22
|
+
instructions: options.instructions ??
|
|
23
|
+
(options.mode === "hermes_shadow"
|
|
24
|
+
? HERMES_SHADOW_INSTRUCTIONS
|
|
25
|
+
: buildServerInstructions(workspaceRoot)),
|
|
22
26
|
});
|
|
23
27
|
if (options.toolGovernance !== false) {
|
|
24
28
|
installAceToolGovernance(server, workspaceRoot);
|
|
25
29
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
if (options.mode !== "hermes_shadow") {
|
|
31
|
+
registerResources(server);
|
|
32
|
+
registerPrompts(server);
|
|
33
|
+
}
|
|
34
|
+
registerTools(server, { toolAllowlist: options.toolAllowlist });
|
|
29
35
|
return server;
|
|
30
36
|
}
|
|
31
37
|
function appendEmergencyMcpStatusEvent(workspaceRoot, message) {
|
|
@@ -94,4 +100,16 @@ export async function startStdioServer(logStartup = true) {
|
|
|
94
100
|
console.error(`ACE MCP Server (${ACE_MCP_SERVER_NAME}) running on stdio`);
|
|
95
101
|
}
|
|
96
102
|
}
|
|
103
|
+
export async function startHermesShadowStdioServer(toolAllowlist, logStartup = false) {
|
|
104
|
+
const server = createAceServer({
|
|
105
|
+
mode: "hermes_shadow",
|
|
106
|
+
toolAllowlist,
|
|
107
|
+
instructions: HERMES_SHADOW_INSTRUCTIONS,
|
|
108
|
+
});
|
|
109
|
+
const transport = new StdioServerTransport();
|
|
110
|
+
await server.connect(transport);
|
|
111
|
+
if (logStartup) {
|
|
112
|
+
console.error(`ACE Hermes shadow MCP Server (${ACE_MCP_SERVER_NAME}) running on stdio with ${toolAllowlist.length} tools`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
97
115
|
//# sourceMappingURL=server.js.map
|
|
@@ -160,6 +160,9 @@ export class VericifyProjector {
|
|
|
160
160
|
timestamp: new Date(post.ts).toISOString(),
|
|
161
161
|
branch_id: typeof post.metadata?.branch_id === "string" ? post.metadata.branch_id : undefined,
|
|
162
162
|
lane_id: typeof post.metadata?.lane_id === "string" ? post.metadata.lane_id : undefined,
|
|
163
|
+
blocker_category: typeof post.metadata?.blocker_category === "string"
|
|
164
|
+
? post.metadata.blocker_category
|
|
165
|
+
: undefined,
|
|
163
166
|
checkpoint_ref: typeof post.metadata?.checkpoint_ref === "string"
|
|
164
167
|
? post.metadata.checkpoint_ref
|
|
165
168
|
: undefined,
|
|
@@ -27,6 +27,12 @@ export interface AceSessionContinuityRecord {
|
|
|
27
27
|
recent_decisions: string[];
|
|
28
28
|
recommended_next_action?: string;
|
|
29
29
|
evidence_refs: string[];
|
|
30
|
+
execution_engine?: "direct" | "hermes_local";
|
|
31
|
+
underlying_provider?: string;
|
|
32
|
+
underlying_model?: string;
|
|
33
|
+
hermes_bridge_protocol_version?: string;
|
|
34
|
+
hermes_session_id?: string;
|
|
35
|
+
shadow_mcp_session_id?: string;
|
|
30
36
|
last_transition_id?: string;
|
|
31
37
|
}
|
|
32
38
|
export interface AceRuntimeStatusPacket {
|
|
@@ -56,6 +62,12 @@ export interface AceRuntimeStatusPacket {
|
|
|
56
62
|
tokens_in?: number;
|
|
57
63
|
tokens_out?: number;
|
|
58
64
|
updated_at: number;
|
|
65
|
+
execution_engine?: "direct" | "hermes_local";
|
|
66
|
+
underlying_provider?: string;
|
|
67
|
+
underlying_model?: string;
|
|
68
|
+
hermes_bridge_protocol_version?: string;
|
|
69
|
+
hermes_session_id?: string;
|
|
70
|
+
shadow_mcp_session_id?: string;
|
|
59
71
|
surface_kind?: "tui_interactive" | "unattended_runtime" | "scheduled_job" | "bridge_resumed" | "supervised_step";
|
|
60
72
|
model_class?: "frontier" | "mid" | "small_local";
|
|
61
73
|
waiting_on?: string;
|
|
@@ -196,6 +196,9 @@ export class LocalModelRuntimeRepository {
|
|
|
196
196
|
session_id: record.session_id,
|
|
197
197
|
bridge_status: record.bridge_status,
|
|
198
198
|
preflight_state: record.preflight_state,
|
|
199
|
+
execution_engine: record.execution_engine,
|
|
200
|
+
underlying_provider: record.underlying_provider,
|
|
201
|
+
underlying_model: record.underlying_model,
|
|
199
202
|
});
|
|
200
203
|
await this.addToIndex(STATUS_INDEX_KEY, record.session_id);
|
|
201
204
|
return record;
|
package/dist/tools-agent.js
CHANGED
|
@@ -1806,6 +1806,10 @@ export function registerAgentTools(server) {
|
|
|
1806
1806
|
.enum(["intent", "progress", "blocker", "handoff_note", "stale_ack", "completion"])
|
|
1807
1807
|
.describe("Structured process post kind"),
|
|
1808
1808
|
summary: z.string().describe("Short operator-facing summary"),
|
|
1809
|
+
blocker_category: z
|
|
1810
|
+
.string()
|
|
1811
|
+
.optional()
|
|
1812
|
+
.describe("Optional blocker category for blocker posts"),
|
|
1809
1813
|
tool_refs: z
|
|
1810
1814
|
.array(z.string())
|
|
1811
1815
|
.optional()
|
|
@@ -1815,7 +1819,7 @@ export function registerAgentTools(server) {
|
|
|
1815
1819
|
.optional()
|
|
1816
1820
|
.describe("Optional evidence references attached to the process post"),
|
|
1817
1821
|
checkpoint_ref: z.string().optional().describe("Optional checkpoint id"),
|
|
1818
|
-
}, async ({ run_id, branch_id, lane_id, agent_id, kind, summary, tool_refs, evidence_refs, checkpoint_ref }) => {
|
|
1822
|
+
}, async ({ run_id, branch_id, lane_id, agent_id, kind, summary, blocker_category, tool_refs, evidence_refs, checkpoint_ref, }) => {
|
|
1819
1823
|
const result = await appendVericifyProcessPost({
|
|
1820
1824
|
run_id,
|
|
1821
1825
|
branch_id,
|
|
@@ -1823,6 +1827,7 @@ export function registerAgentTools(server) {
|
|
|
1823
1827
|
agent_id,
|
|
1824
1828
|
kind,
|
|
1825
1829
|
summary,
|
|
1830
|
+
blocker_category,
|
|
1826
1831
|
tool_refs,
|
|
1827
1832
|
evidence_refs,
|
|
1828
1833
|
checkpoint_ref,
|
package/dist/tools.d.ts
CHANGED
|
@@ -5,5 +5,8 @@
|
|
|
5
5
|
* This keeps the registration entry-point small and each domain testable.
|
|
6
6
|
*/
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
-
export
|
|
8
|
+
export interface RegisterToolsOptions {
|
|
9
|
+
toolAllowlist?: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function registerTools(server: McpServer, options?: RegisterToolsOptions): void;
|
|
9
12
|
//# sourceMappingURL=tools.d.ts.map
|
package/dist/tools.js
CHANGED
|
@@ -16,18 +16,40 @@ import { registerMemoryTools } from "./tools-memory.js";
|
|
|
16
16
|
import { registerDriftTools } from "./tools-drift.js";
|
|
17
17
|
import { registerSchedulerTools } from "./tools-scheduler.js";
|
|
18
18
|
import { registerSkillTools } from "./tools-skills.js";
|
|
19
|
-
|
|
20
|
-
registerAgentTools
|
|
21
|
-
registerHandoffTools
|
|
22
|
-
registerTodoTools
|
|
23
|
-
registerDiscoveryTools
|
|
24
|
-
registerLifecycleTools
|
|
25
|
-
registerFileTools
|
|
26
|
-
registerFrameworkTools
|
|
27
|
-
registerGitTools
|
|
28
|
-
registerMemoryTools
|
|
29
|
-
registerDriftTools
|
|
30
|
-
registerSchedulerTools
|
|
31
|
-
registerSkillTools
|
|
19
|
+
const TOOL_REGISTRARS = [
|
|
20
|
+
registerAgentTools,
|
|
21
|
+
registerHandoffTools,
|
|
22
|
+
registerTodoTools,
|
|
23
|
+
registerDiscoveryTools,
|
|
24
|
+
registerLifecycleTools,
|
|
25
|
+
registerFileTools,
|
|
26
|
+
registerFrameworkTools,
|
|
27
|
+
registerGitTools,
|
|
28
|
+
registerMemoryTools,
|
|
29
|
+
registerDriftTools,
|
|
30
|
+
registerSchedulerTools,
|
|
31
|
+
registerSkillTools,
|
|
32
|
+
];
|
|
33
|
+
function createAllowlistedServer(server, allowed) {
|
|
34
|
+
return new Proxy(server, {
|
|
35
|
+
get(target, property, receiver) {
|
|
36
|
+
if (property !== "tool")
|
|
37
|
+
return Reflect.get(target, property, receiver);
|
|
38
|
+
const registerTool = Reflect.get(target, property, receiver);
|
|
39
|
+
return (name, ...args) => {
|
|
40
|
+
if (!allowed.has(name))
|
|
41
|
+
return undefined;
|
|
42
|
+
return Reflect.apply(registerTool, target, [name, ...args]);
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function registerTools(server, options = {}) {
|
|
48
|
+
const target = options.toolAllowlist === undefined
|
|
49
|
+
? server
|
|
50
|
+
: createAllowlistedServer(server, new Set(options.toolAllowlist));
|
|
51
|
+
for (const register of TOOL_REGISTRARS) {
|
|
52
|
+
register(target);
|
|
53
|
+
}
|
|
32
54
|
}
|
|
33
55
|
//# sourceMappingURL=tools.js.map
|
package/dist/tui/chat.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ import type { ChatMessage } from "./layout.js";
|
|
|
12
12
|
import { ModelBridge } from "../model-bridge.js";
|
|
13
13
|
import type { AceContextTier } from "../ace-context.js";
|
|
14
14
|
import { type AceRuntimeStatusPacket } from "../store/repositories/local-model-runtime-repository.js";
|
|
15
|
+
import type { HermesLocalExecutor } from "../hermes/session-manager.js";
|
|
16
|
+
import type { HermesLaunchProfile } from "../hermes/launch-profile.js";
|
|
15
17
|
export interface ChatSessionOptions {
|
|
16
18
|
provider: string;
|
|
17
19
|
model: string;
|
|
@@ -25,7 +27,10 @@ export interface ChatSessionOptions {
|
|
|
25
27
|
aceRole?: string;
|
|
26
28
|
aceTier?: AceContextTier;
|
|
27
29
|
maxTurns?: number;
|
|
30
|
+
engine?: string;
|
|
28
31
|
bridge?: Pick<ModelBridge, "run" | "interrupt">;
|
|
32
|
+
hermesExecutor?: HermesLocalExecutor;
|
|
33
|
+
hermesLaunchProfile?: HermesLaunchProfile;
|
|
29
34
|
}
|
|
30
35
|
export interface ChatSessionClients {
|
|
31
36
|
ollama: Pick<OllamaClient, "chat" | "abort">;
|
|
@@ -51,7 +56,10 @@ export declare class ChatSession extends EventEmitter {
|
|
|
51
56
|
private aceRole;
|
|
52
57
|
private aceTier?;
|
|
53
58
|
private maxTurns;
|
|
59
|
+
private executionEngine;
|
|
54
60
|
private aceBridge;
|
|
61
|
+
private hermesExecutor?;
|
|
62
|
+
private hermesLaunchProfile?;
|
|
55
63
|
private activeAceBridge;
|
|
56
64
|
private providerBaseUrls;
|
|
57
65
|
private sessionId;
|