@voybio/ace-swarm 0.2.3 → 0.2.5

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.
@@ -28,24 +28,8 @@ function extractStatusField(statusRaw, label) {
28
28
  const match = statusRaw.match(pattern);
29
29
  return match?.[1] ? clip(oneLine(match[1])) : undefined;
30
30
  }
31
- function determineRole(task, preferredRole) {
32
- const lowered = task.toLowerCase();
33
- if (preferredRole && preferredRole !== "orchestrator") {
34
- return preferredRole;
35
- }
36
- if (/\b(doc|docs|readme|changelog|guide)\b/.test(lowered))
37
- return "docs";
38
- if (/\b(test|qa|verify|regression|assert|review)\b/.test(lowered))
39
- return "qa";
40
- if (/\b(ui|design|layout|ux|css|frontend)\b/.test(lowered))
41
- return "ui";
42
- if (/\b(research|investigate|compare|audit|analyze|analysis)\b/.test(lowered))
43
- return "research";
44
- if (/\b(spec|schema|contract|interface)\b/.test(lowered))
45
- return "spec";
46
- if (/\b(build|implement|fix|patch|code|refactor|wire|edit)\b/.test(lowered))
47
- return "coders";
48
- return "orchestrator";
31
+ function determineRole(preferredRole) {
32
+ return preferredRole?.trim() || "orchestrator";
49
33
  }
50
34
  export function shouldSynthesizeShortPlan(task) {
51
35
  const lowered = task.toLowerCase();
@@ -103,17 +87,15 @@ export function buildAcePreflightPacket(input) {
103
87
  ? "thin"
104
88
  : "healthy";
105
89
  const preflightState = blockers.length > 0 ? "blocked" : warnings.length > 0 || blockedByStatus ? "attention_required" : "ready";
106
- const recommendedRole = determineRole(input.task, input.preferredRole);
90
+ const recommendedRole = determineRole(input.preferredRole);
107
91
  const synthesize = shouldSynthesizeShortPlan(input.task);
108
92
  const recommendedNextAction = preflightState === "blocked"
109
93
  ? "validate_framework"
110
94
  : synthesize
111
95
  ? "run_orchestrator"
112
- : quartetHealth !== "healthy"
113
- ? "recall_context"
114
- : recommendedRole === "orchestrator"
115
- ? "route_task"
116
- : "recall_context";
96
+ : recommendedRole === "orchestrator"
97
+ ? "run_orchestrator"
98
+ : "recall_context";
117
99
  return {
118
100
  session_id: input.sessionId,
119
101
  workspace_root: input.workspaceRoot,
@@ -154,7 +136,7 @@ export function buildStartupNudge(preflight, ledger) {
154
136
  const text = action === "validate_framework"
155
137
  ? "ACE state is incomplete. Run validate_framework before free-form execution."
156
138
  : action === "run_orchestrator"
157
- ? "This looks multi-step. Prefer run_orchestrator over a single free-form reply."
139
+ ? "Start with run_orchestrator so ACE-Orchestrator can route the work."
158
140
  : action === "route_task"
159
141
  ? "Role selection is still ambiguous. Route the task before deeper work."
160
142
  : "Load ACE context first with recall_context before deeper work.";
@@ -14,6 +14,8 @@
14
14
  */
15
15
  export declare const DEFAULT_OLLAMA_MODEL = "llama3.1:8b";
16
16
  export declare const DEFAULT_LLAMA_CPP_MODEL = "local-model";
17
+ export declare const LOCAL_LLM_PROVIDERS: readonly ["ollama", "llama.cpp"];
18
+ export type LocalLlmProvider = (typeof LOCAL_LLM_PROVIDERS)[number];
17
19
  export interface ProviderDiscoveryOptions {
18
20
  workspaceRoot: string;
19
21
  cliProvider?: string;
@@ -53,6 +55,10 @@ export declare function normalizeProvider(input: string | undefined): string | u
53
55
  export declare function normalizeLocalBaseUrl(url: string | undefined): string | undefined;
54
56
  export declare function buildOpenAiCompatibleBaseUrl(baseUrl: string): string;
55
57
  export declare function inferProviderFromModel(model: string | undefined): string | undefined;
58
+ export declare function isLocalLlmProvider(providerInput: string | undefined): providerInput is LocalLlmProvider;
59
+ export declare function defaultModelForProvider(providerInput: string | undefined): string;
60
+ export declare function providerEnvPrefix(providerInput: string | undefined): string;
61
+ export declare function buildProviderDoctorCommands(providerInput: string | undefined, modelInput: string | undefined, baseUrlInput?: string): string[];
56
62
  export declare function parseJsoncLoose(raw: string): unknown;
57
63
  export declare function discoverProviderContext(options: ProviderDiscoveryOptions): ProviderDiscoveryResult;
58
64
  export declare function scanLocalModelRuntimes(options?: LocalRuntimeScanOptions): Promise<LocalRuntimeScanResult>;
@@ -18,7 +18,14 @@ import { join, resolve } from "node:path";
18
18
  import { readStoreJsonSync } from "../store/store-snapshot.js";
19
19
  export const DEFAULT_OLLAMA_MODEL = "llama3.1:8b";
20
20
  export const DEFAULT_LLAMA_CPP_MODEL = "local-model";
21
- const LOCAL_RUNTIME_PROVIDER_PREFERENCE = ["ollama", "llama.cpp"];
21
+ const DEFAULT_HOSTED_MODELS = {
22
+ codex: "gpt-5",
23
+ claude: "claude-3-7-sonnet",
24
+ gemini: "gemini-2.5-pro",
25
+ copilot: "copilot/gpt-5-mini",
26
+ };
27
+ export const LOCAL_LLM_PROVIDERS = ["ollama", "llama.cpp"];
28
+ const LOCAL_RUNTIME_PROVIDER_PREFERENCE = LOCAL_LLM_PROVIDERS;
22
29
  const PROVIDER_PREFERENCE = [
23
30
  ...LOCAL_RUNTIME_PROVIDER_PREFERENCE,
24
31
  "codex",
@@ -95,12 +102,69 @@ export function inferProviderFromModel(model) {
95
102
  }
96
103
  return undefined;
97
104
  }
98
- function defaultModelForProvider(provider) {
99
- if (provider === "ollama")
105
+ export function isLocalLlmProvider(providerInput) {
106
+ const provider = normalizeProvider(providerInput);
107
+ return provider === "ollama" || provider === "llama.cpp";
108
+ }
109
+ export function defaultModelForProvider(providerInput) {
110
+ const provider = normalizeProvider(providerInput);
111
+ if (provider === "ollama" || !provider)
100
112
  return DEFAULT_OLLAMA_MODEL;
101
113
  if (provider === "llama.cpp")
102
114
  return DEFAULT_LLAMA_CPP_MODEL;
103
- return `${provider}/default`;
115
+ return DEFAULT_HOSTED_MODELS[provider] ?? DEFAULT_HOSTED_MODELS.codex;
116
+ }
117
+ export function providerEnvPrefix(providerInput) {
118
+ const provider = normalizeProvider(providerInput);
119
+ if (!provider)
120
+ return "LLM";
121
+ if (provider === "llama.cpp")
122
+ return "LLAMA_CPP";
123
+ return provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
124
+ }
125
+ export function buildProviderDoctorCommands(providerInput, modelInput, baseUrlInput) {
126
+ const provider = normalizeProvider(providerInput) ?? "ollama";
127
+ const model = modelInput?.trim() || defaultModelForProvider(provider);
128
+ const baseUrl = normalizeLocalBaseUrl(baseUrlInput);
129
+ if (provider === "ollama") {
130
+ return [
131
+ "ollama serve",
132
+ `ollama pull ${model}`,
133
+ ...(baseUrl ? [`curl -s ${baseUrl}/api/tags`] : []),
134
+ baseUrl
135
+ ? `ace doctor --llm ${provider} --model ${model} --base-url ${baseUrl}`
136
+ : `ace doctor --llm ${provider} --model ${model} --scan`,
137
+ ];
138
+ }
139
+ if (provider === "llama.cpp") {
140
+ return [
141
+ "# Start llama-server separately, for example:",
142
+ "# llama-server -m /path/to/model.gguf --port 8080",
143
+ ...(baseUrl ? [`curl -s ${buildOpenAiCompatibleBaseUrl(baseUrl)}/models`] : []),
144
+ baseUrl
145
+ ? `ace doctor --llm ${provider} --model ${model} --base-url ${baseUrl}`
146
+ : `ace doctor --llm ${provider} --model ${model} --scan`,
147
+ ];
148
+ }
149
+ if (provider === "codex") {
150
+ return [
151
+ "export OPENAI_API_KEY=<token>",
152
+ ...(baseUrl ? [`export OPENAI_BASE_URL=${baseUrl}`] : []),
153
+ `ace doctor --llm ${provider} --model ${model}${baseUrl ? ` --base-url ${baseUrl}` : ""}`,
154
+ ];
155
+ }
156
+ if (provider === "copilot") {
157
+ return [
158
+ "gh auth login # or export GITHUB_TOKEN=<token>",
159
+ `ace doctor --llm ${provider} --model ${model}`,
160
+ ];
161
+ }
162
+ const prefix = providerEnvPrefix(provider);
163
+ return [
164
+ `export ${prefix}_BASE_URL=${baseUrl ?? "<openai-compatible-base-url>"}`,
165
+ `export ${prefix}_API_KEY=<token>`,
166
+ `ace doctor --llm ${provider} --model ${model}${baseUrl ? ` --base-url ${baseUrl}` : ""}`,
167
+ ];
104
168
  }
105
169
  function looksLikeModel(value) {
106
170
  const v = value.trim().toLowerCase();
@@ -326,6 +390,8 @@ export function discoverProviderContext(options) {
326
390
  process.env.LLM_MODEL?.trim() ||
327
391
  undefined;
328
392
  const envGenericBaseUrl = normalizeLocalBaseUrl(process.env.ACE_TUI_BASE_URL ?? process.env.ACE_LLM_BASE_URL ?? process.env.LLM_BASE_URL);
393
+ const openAiBaseUrl = normalizeLocalBaseUrl(process.env.OPENAI_BASE_URL);
394
+ const genericBaseUrl = envGenericBaseUrl ?? openAiBaseUrl;
329
395
  const cliProvider = normalizeProvider(options.cliProvider);
330
396
  const cliModel = options.cliModel?.trim() || undefined;
331
397
  const cliBaseUrl = normalizeLocalBaseUrl(options.cliBaseUrl ?? options.cliOllamaUrl);
@@ -355,9 +421,18 @@ export function discoverProviderContext(options) {
355
421
  inferProviderFromModel(profileModel);
356
422
  }
357
423
  if (!provider) {
358
- provider = "ollama";
359
- if (settingHints.length > 0) {
360
- notes.push("runtime_default=ollama (VS Code model hints are discovery-only)");
424
+ const genericOpenAiSignals = Boolean(genericBaseUrl) ||
425
+ Boolean(process.env.OPENAI_API_KEY?.trim()) ||
426
+ Boolean(process.env.CODEX_API_KEY?.trim());
427
+ if (genericOpenAiSignals) {
428
+ provider = "codex";
429
+ notes.push("runtime_default=codex (generic OpenAI-compatible env detected)");
430
+ }
431
+ else {
432
+ provider = "ollama";
433
+ if (settingHints.length > 0) {
434
+ notes.push("runtime_default=ollama (VS Code model hints are discovery-only)");
435
+ }
361
436
  }
362
437
  }
363
438
  setProviderBaseUrl(providerBaseUrls, profileProvider, profileBaseUrl);
@@ -366,8 +441,8 @@ export function discoverProviderContext(options) {
366
441
  if (!providerBaseUrls.has(provider) && cliBaseUrl) {
367
442
  providerBaseUrls.set(provider, cliBaseUrl);
368
443
  }
369
- if (!providerBaseUrls.has(provider) && envGenericBaseUrl) {
370
- providerBaseUrls.set(provider, envGenericBaseUrl);
444
+ if (!providerBaseUrls.has(provider) && genericBaseUrl) {
445
+ providerBaseUrls.set(provider, genericBaseUrl);
371
446
  }
372
447
  if (!providerBaseUrls.has(provider) && profileBaseUrl && profileProvider === provider) {
373
448
  providerBaseUrls.set(provider, profileBaseUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voybio/ace-swarm",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "ACE Framework MCP server and CLI — single-file ACEPACK state, local-model serving, agent orchestration, and host compliance enforcement.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",