@voybio/ace-swarm 2.4.0 → 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.
Files changed (80) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +502 -56
  3. package/assets/.agents/ACE/agent-qa/instructions.md +11 -0
  4. package/assets/agent-state/MODULES/schemas/RUNTIME_TOOL_SPEC_REGISTRY.schema.json +43 -0
  5. package/assets/agent-state/runtime-tool-specs.json +70 -2
  6. package/assets/instructions/ACE_Coder.instructions.md +13 -0
  7. package/assets/instructions/ACE_UI.instructions.md +11 -0
  8. package/dist/ace-context.js +70 -11
  9. package/dist/ace-internal-tools.d.ts +3 -1
  10. package/dist/ace-internal-tools.js +10 -2
  11. package/dist/agent-runtime/role-adapters.d.ts +18 -1
  12. package/dist/agent-runtime/role-adapters.js +49 -5
  13. package/dist/astgrep-index.d.ts +48 -0
  14. package/dist/astgrep-index.js +126 -1
  15. package/dist/cli.js +487 -17
  16. package/dist/discovery-runtime-wrappers.d.ts +108 -0
  17. package/dist/discovery-runtime-wrappers.js +615 -0
  18. package/dist/helpers/bootstrap.js +1 -1
  19. package/dist/helpers/constants.d.ts +4 -2
  20. package/dist/helpers/constants.js +8 -0
  21. package/dist/helpers/path-utils.d.ts +8 -1
  22. package/dist/helpers/path-utils.js +27 -8
  23. package/dist/helpers/store-resolution.js +7 -3
  24. package/dist/hermes/bridge-protocol.d.ts +41 -0
  25. package/dist/hermes/bridge-protocol.js +70 -0
  26. package/dist/hermes/launch-profile.d.ts +19 -0
  27. package/dist/hermes/launch-profile.js +81 -0
  28. package/dist/hermes/session-manager.d.ts +42 -0
  29. package/dist/hermes/session-manager.js +187 -0
  30. package/dist/job-scheduler.js +30 -4
  31. package/dist/json-sanitizer.d.ts +16 -0
  32. package/dist/json-sanitizer.js +26 -0
  33. package/dist/local-model-policy.d.ts +27 -0
  34. package/dist/local-model-policy.js +84 -0
  35. package/dist/local-model-runtime.d.ts +17 -0
  36. package/dist/local-model-runtime.js +77 -20
  37. package/dist/model-bridge.d.ts +6 -1
  38. package/dist/model-bridge.js +338 -21
  39. package/dist/orchestrator-supervisor.d.ts +42 -0
  40. package/dist/orchestrator-supervisor.js +110 -3
  41. package/dist/plan-proposal.d.ts +115 -0
  42. package/dist/plan-proposal.js +1073 -0
  43. package/dist/runtime-executor.d.ts +6 -1
  44. package/dist/runtime-executor.js +72 -5
  45. package/dist/runtime-tool-specs.d.ts +19 -1
  46. package/dist/runtime-tool-specs.js +67 -26
  47. package/dist/schemas.js +30 -1
  48. package/dist/server.d.ts +3 -0
  49. package/dist/server.js +73 -4
  50. package/dist/shared.d.ts +1 -0
  51. package/dist/shared.js +2 -0
  52. package/dist/store/bootstrap-store.d.ts +1 -0
  53. package/dist/store/bootstrap-store.js +8 -2
  54. package/dist/store/materializers/vericify-projector.js +3 -0
  55. package/dist/store/repositories/local-model-runtime-repository.d.ts +13 -1
  56. package/dist/store/repositories/local-model-runtime-repository.js +4 -1
  57. package/dist/store/repositories/vericify-repository.d.ts +1 -1
  58. package/dist/tools-agent.d.ts +20 -0
  59. package/dist/tools-agent.js +544 -29
  60. package/dist/tools-discovery.js +135 -0
  61. package/dist/tools-files.js +768 -66
  62. package/dist/tools-framework.js +80 -61
  63. package/dist/tools.d.ts +4 -1
  64. package/dist/tools.js +35 -13
  65. package/dist/tui/chat.d.ts +8 -0
  66. package/dist/tui/chat.js +74 -0
  67. package/dist/tui/index.d.ts +7 -0
  68. package/dist/tui/index.js +45 -2
  69. package/dist/tui/layout.d.ts +1 -0
  70. package/dist/tui/layout.js +4 -1
  71. package/dist/tui/ollama.d.ts +8 -1
  72. package/dist/tui/ollama.js +53 -12
  73. package/dist/tui/openai-compatible.d.ts +13 -0
  74. package/dist/tui/openai-compatible.js +305 -5
  75. package/dist/tui/provider-discovery.d.ts +1 -0
  76. package/dist/tui/provider-discovery.js +50 -24
  77. package/dist/vericify-bridge.d.ts +4 -1
  78. package/dist/vericify-bridge.js +3 -0
  79. package/package.json +2 -1
  80. package/scripts/hermes_bridge_worker.py +136 -0
@@ -0,0 +1,26 @@
1
+ export function sanitizeJsonLikeText(raw) {
2
+ const hadBom = raw.startsWith("\uFEFF");
3
+ let removed = 0;
4
+ const text = raw
5
+ .replace(/^\uFEFF/, "")
6
+ .replace(/\r\n?/g, "\n")
7
+ .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, () => {
8
+ removed += 1;
9
+ return "";
10
+ });
11
+ return { text, removed_control_bytes: removed, had_bom: hadBom };
12
+ }
13
+ export function parseJsonLikeText(raw) {
14
+ const sanitized = sanitizeJsonLikeText(raw);
15
+ try {
16
+ return { ok: true, value: JSON.parse(sanitized.text), sanitized };
17
+ }
18
+ catch (error) {
19
+ return {
20
+ ok: false,
21
+ error: error instanceof Error ? error.message : String(error),
22
+ sanitized,
23
+ };
24
+ }
25
+ }
26
+ //# sourceMappingURL=json-sanitizer.js.map
@@ -0,0 +1,27 @@
1
+ import type { AceContextTier } from "./ace-context.js";
2
+ import { type RuntimeModelClass } from "./runtime-profile.js";
3
+ export interface LocalModelPolicyInput {
4
+ provider: string;
5
+ model: string;
6
+ role: string;
7
+ task?: string;
8
+ requested_tier?: "auto" | AceContextTier;
9
+ requested_model_class?: RuntimeModelClass;
10
+ }
11
+ export interface LocalModelExecutionPolicy {
12
+ model_class: RuntimeModelClass;
13
+ tier: AceContextTier;
14
+ mutation_lane: "structural_edit" | "raw_write_allowed";
15
+ structural_tools_required: boolean;
16
+ read_file_lines_max_lines: number | null;
17
+ }
18
+ export declare function resolveLocalModelClass(input: {
19
+ provider: string;
20
+ model: string;
21
+ requested_model_class?: RuntimeModelClass;
22
+ }): RuntimeModelClass;
23
+ export declare function tierForModelClass(role: string, modelClass: RuntimeModelClass, requestedTier?: "auto" | AceContextTier): AceContextTier;
24
+ export declare function defaultTurnsForPolicy(role: string, policy: LocalModelExecutionPolicy): number;
25
+ export declare function defaultToolScopeForPolicy(role: string, policy: LocalModelExecutionPolicy): string[] | undefined;
26
+ export declare function resolveLocalModelExecutionPolicy(input: LocalModelPolicyInput): LocalModelExecutionPolicy;
27
+ //# sourceMappingURL=local-model-policy.d.ts.map
@@ -0,0 +1,84 @@
1
+ import { DEFAULT_SURGICAL_READ_BUDGETS, } from "./runtime-profile.js";
2
+ const FRONTIER_MODEL_PATTERN = /\b(70b|72b|90b|405b|claude|gpt-|codex|gemini|o[1345])\b/i;
3
+ const SMALL_LOCAL_MODEL_PATTERN = /\b(1\.5b|2b|3b|4b|5b|6b|7b|8b|mini|small|phi|tiny|qwen2\.5-coder|llama-3\.2-3b)\b/i;
4
+ const LOCAL_PROVIDER_PATTERN = /\b(ollama|llama\.cpp|llamacpp|openai-compatible|local)\b/i;
5
+ const HOSTED_PROVIDER_PATTERN = /\b(codex|claude|gemini|copilot)\b/i;
6
+ function normalize(value) {
7
+ return (value ?? "").trim().toLowerCase();
8
+ }
9
+ function isMutationTask(task, role) {
10
+ if (role === "coders" || role === "builder")
11
+ return true;
12
+ return /\b(write|create|mutate|edit|patch|modify|persist|save|generate|implement)\b/i.test(task ?? "");
13
+ }
14
+ export function resolveLocalModelClass(input) {
15
+ if (input.requested_model_class)
16
+ return input.requested_model_class;
17
+ const provider = normalize(input.provider);
18
+ const model = normalize(input.model);
19
+ const joined = `${provider} ${model}`;
20
+ if (FRONTIER_MODEL_PATTERN.test(joined) || HOSTED_PROVIDER_PATTERN.test(provider) || provider === "openai") {
21
+ return "frontier";
22
+ }
23
+ if (SMALL_LOCAL_MODEL_PATTERN.test(model)) {
24
+ return "small_local";
25
+ }
26
+ if (LOCAL_PROVIDER_PATTERN.test(provider)) {
27
+ return "mid";
28
+ }
29
+ return "mid";
30
+ }
31
+ export function tierForModelClass(role, modelClass, requestedTier) {
32
+ if (requestedTier && requestedTier !== "auto")
33
+ return requestedTier;
34
+ if (role === "orchestrator")
35
+ return "compressed";
36
+ if (modelClass === "frontier")
37
+ return "full";
38
+ if (modelClass === "small_local")
39
+ return "brief";
40
+ return "compressed";
41
+ }
42
+ export function defaultTurnsForPolicy(role, policy) {
43
+ if (role === "orchestrator")
44
+ return 6;
45
+ return policy.model_class === "small_local" ? 4 : 4;
46
+ }
47
+ export function defaultToolScopeForPolicy(role, policy) {
48
+ if (!policy.structural_tools_required || !(role === "coders" || role === "builder")) {
49
+ return undefined;
50
+ }
51
+ return [
52
+ "outline_file",
53
+ "astgrep_query",
54
+ "astgrep_locate",
55
+ "read_file_lines",
56
+ "compile_structural_edit",
57
+ "preview_structural_edit",
58
+ "astgrep_rewrite",
59
+ "safe_edit_file",
60
+ "write_workspace_file",
61
+ "run_tests",
62
+ "git_diff",
63
+ "git_status",
64
+ "execute_gates",
65
+ ];
66
+ }
67
+ export function resolveLocalModelExecutionPolicy(input) {
68
+ const role = normalize(input.role);
69
+ const modelClass = resolveLocalModelClass({
70
+ provider: input.provider,
71
+ model: input.model,
72
+ requested_model_class: input.requested_model_class,
73
+ });
74
+ const mutationIntent = isMutationTask(input.task, role);
75
+ const structuralToolsRequired = modelClass === "small_local" && mutationIntent;
76
+ return {
77
+ model_class: modelClass,
78
+ tier: tierForModelClass(role, modelClass, input.requested_tier),
79
+ mutation_lane: structuralToolsRequired ? "structural_edit" : "raw_write_allowed",
80
+ structural_tools_required: structuralToolsRequired,
81
+ read_file_lines_max_lines: DEFAULT_SURGICAL_READ_BUDGETS[modelClass],
82
+ };
83
+ }
84
+ //# sourceMappingURL=local-model-policy.js.map
@@ -1,7 +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";
4
+ import { type LocalModelExecutionPolicy } from "./local-model-policy.js";
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";
3
8
  export interface LocalModelRuntimeConfig {
4
9
  workspaceRoot: string;
10
+ executionEngine: ExecutionEngine;
5
11
  provider: string;
6
12
  model: string;
7
13
  baseUrl?: string;
@@ -14,27 +20,38 @@ export interface RunLocalModelTaskOptions {
14
20
  role?: string;
15
21
  workspaceRoot?: string;
16
22
  provider?: string;
23
+ engine?: string;
17
24
  model?: string;
18
25
  baseUrl?: string;
19
26
  ollamaUrl?: string;
20
27
  maxTurns?: number;
21
28
  tier?: AceContextTier | "auto";
29
+ modelClass?: RuntimeModelClass;
22
30
  toolScope?: string[];
23
31
  clients?: ModelBridgeClients;
32
+ hermesExecutor?: HermesLocalExecutor;
33
+ hermesLaunchProfile?: HermesLaunchProfile;
24
34
  }
25
35
  export interface RunLocalModelTaskResult {
26
36
  runtime: LocalModelRuntimeConfig;
27
37
  role: string;
28
38
  routingSummary?: string;
39
+ policy: LocalModelExecutionPolicy;
29
40
  result: BridgeResult;
41
+ hermes?: HermesLocalTurnResult["metadata"];
30
42
  }
43
+ export declare function parseExecutionEngine(input?: string): ExecutionEngine | undefined;
44
+ export declare function resolveTier(requested: RunLocalModelTaskOptions["tier"], provider: string, model: string, role: string): AceContextTier;
31
45
  export declare function createDefaultModelBridgeClients(runtime: Pick<LocalModelRuntimeConfig, "providerBaseUrls">): ModelBridgeClients;
32
46
  export declare function resolveLocalModelRuntime(input: {
33
47
  workspaceRoot?: string;
34
48
  provider?: string;
49
+ engine?: string;
35
50
  model?: string;
36
51
  baseUrl?: string;
37
52
  ollamaUrl?: string;
53
+ hermesReady?: boolean;
38
54
  }): LocalModelRuntimeConfig;
39
55
  export declare function runLocalModelTask(options: RunLocalModelTaskOptions): Promise<RunLocalModelTaskResult>;
56
+ export { resolveLocalModelExecutionPolicy, resolveLocalModelClass } from "./local-model-policy.js";
40
57
  //# sourceMappingURL=local-model-runtime.d.ts.map
@@ -1,11 +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";
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
+ }
9
34
  function extractTextContent(result) {
10
35
  if (!result || typeof result !== "object")
11
36
  return "";
@@ -50,22 +75,13 @@ async function resolveRole(task, sessionId, requestedRole) {
50
75
  routingSummary,
51
76
  };
52
77
  }
53
- function resolveTier(requested, provider, model, role) {
54
- if (requested && requested !== "auto")
55
- return requested;
56
- const normalizedProvider = provider.trim().toLowerCase();
57
- const normalizedModel = model.trim().toLowerCase();
58
- if (role === "orchestrator")
59
- return "compressed";
60
- if (normalizedProvider !== "ollama")
61
- return "full";
62
- if (/(70b|72b|90b|405b|claude|gpt-|codex|gemini|o[1345])/.test(normalizedModel)) {
63
- return "full";
64
- }
65
- if (/(7b|8b|mini|small|phi|tiny)/.test(normalizedModel)) {
66
- return "brief";
67
- }
68
- return "compressed";
78
+ export function resolveTier(requested, provider, model, role) {
79
+ return resolveLocalModelExecutionPolicy({
80
+ provider,
81
+ model,
82
+ role,
83
+ requested_tier: requested,
84
+ }).tier;
69
85
  }
70
86
  export function createDefaultModelBridgeClients(runtime) {
71
87
  const providerConfigs = {};
@@ -88,6 +104,11 @@ export function resolveLocalModelRuntime(input) {
88
104
  cliBaseUrl: input.baseUrl,
89
105
  cliOllamaUrl: input.ollamaUrl,
90
106
  });
107
+ const executionEngine = resolveExecutionEngine({
108
+ requested: input.engine,
109
+ provider: discovered.provider,
110
+ hermesReady: input.hermesReady,
111
+ });
91
112
  if (discovered.provider === "ollama" && !discovered.ollamaUrl) {
92
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`.");
93
114
  }
@@ -101,6 +122,7 @@ export function resolveLocalModelRuntime(input) {
101
122
  }
102
123
  return {
103
124
  workspaceRoot,
125
+ executionEngine,
104
126
  provider: discovered.provider,
105
127
  model: discovered.model,
106
128
  baseUrl: discovered.baseUrl,
@@ -113,28 +135,63 @@ export async function runLocalModelTask(options) {
113
135
  const runtime = resolveLocalModelRuntime({
114
136
  workspaceRoot: options.workspaceRoot,
115
137
  provider: options.provider,
138
+ engine: options.engine,
116
139
  model: options.model,
117
140
  baseUrl: options.baseUrl,
118
141
  ollamaUrl: options.ollamaUrl,
119
142
  });
120
143
  const bridge = new ModelBridge(options.clients ?? createDefaultModelBridgeClients(runtime));
121
144
  const { role, routingSummary } = await resolveRole(options.task, undefined, options.role);
122
- const tier = resolveTier(options.tier, runtime.provider, runtime.model, role);
145
+ const policy = resolveLocalModelExecutionPolicy({
146
+ provider: runtime.provider,
147
+ model: runtime.model,
148
+ role,
149
+ task: options.task,
150
+ requested_tier: options.tier,
151
+ requested_model_class: options.modelClass,
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
+ }
123
178
  const result = await bridge.run({
124
179
  task: options.task,
125
180
  role,
126
181
  workspace: runtime.workspaceRoot,
127
- tier,
128
- maxTurns: options.maxTurns ?? (role === "orchestrator" ? 6 : 4),
182
+ tier: policy.tier,
183
+ maxTurns,
129
184
  provider: runtime.provider,
130
185
  model: runtime.model,
131
- toolScope: options.toolScope,
186
+ toolScope,
132
187
  });
133
188
  return {
134
189
  runtime,
135
190
  role,
136
191
  routingSummary,
192
+ policy,
137
193
  result,
138
194
  };
139
195
  }
196
+ export { resolveLocalModelExecutionPolicy, resolveLocalModelClass } from "./local-model-policy.js";
140
197
  //# sourceMappingURL=local-model-runtime.js.map
@@ -19,12 +19,13 @@ export interface BridgeProgressEvent {
19
19
  export interface BridgeResult {
20
20
  bridge_id: string;
21
21
  role: string;
22
- status: "completed" | "needs_input" | "failed" | "max_turns";
22
+ status: "completed" | "blocked" | "needs_input" | "failed" | "max_turns";
23
23
  summary: string;
24
24
  turns: number;
25
25
  tool_calls: BridgeToolResult[];
26
26
  child_results: BridgeResult[];
27
27
  evidence_refs?: string[];
28
+ reason_code?: string;
28
29
  }
29
30
  export interface ModelBridgeClients {
30
31
  ollama: Pick<OllamaClient, "chat" | "abort">;
@@ -40,6 +41,10 @@ export interface ModelBridgeRunOptions {
40
41
  provider: string;
41
42
  model: string;
42
43
  toolScope?: string[];
44
+ expectedArtifacts?: {
45
+ path: string;
46
+ required?: boolean;
47
+ }[];
43
48
  parentBridge?: string;
44
49
  onToolCall?: (tool: string, args: Record<string, unknown>) => void;
45
50
  onToolResult?: (tool: string, result: BridgeToolResult) => void;