swarm-code 0.1.8 → 0.1.10
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.
|
@@ -244,6 +244,7 @@ function cmdHelp() {
|
|
|
244
244
|
out.write(` ${cyan("/dag")} ${dim("Show thread DAG with status indicators")}\n`);
|
|
245
245
|
out.write(` ${cyan("/budget")} ${dim("Show budget state")}\n`);
|
|
246
246
|
out.write(` ${cyan("/status")} ${dim("Overall session status")}\n`);
|
|
247
|
+
out.write(` ${cyan("/configure")} ${dim("(/c)")} ${dim("Change agent, model, or backend")}\n`);
|
|
247
248
|
out.write(` ${cyan("/help")} ${dim("Show this help")}\n`);
|
|
248
249
|
out.write(` ${cyan("/quit")} ${dim("(/exit)")} ${dim("Cleanup and exit")}\n`);
|
|
249
250
|
out.write("\n");
|
|
@@ -536,6 +537,120 @@ function cmdStatus(threadManager, sessionStartTime, taskCount) {
|
|
|
536
537
|
}
|
|
537
538
|
out.write("\n");
|
|
538
539
|
}
|
|
540
|
+
// ── Configure command ───────────────────────────────────────────────────────
|
|
541
|
+
async function cmdConfigure(config, resolved, rl) {
|
|
542
|
+
const out = process.stderr;
|
|
543
|
+
const ask = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
544
|
+
out.write("\n");
|
|
545
|
+
out.write(` ${bold(cyan("Configuration"))}\n`);
|
|
546
|
+
out.write(` ${dim(symbols.horizontal.repeat(40))}\n\n`);
|
|
547
|
+
out.write(` ${dim("Current settings:")}\n`);
|
|
548
|
+
out.write(` ${cyan("1")} Agent ${bold(config.default_agent)}\n`);
|
|
549
|
+
out.write(` ${cyan("2")} Model ${bold(config.default_model)}\n`);
|
|
550
|
+
out.write(` ${cyan("3")} Max threads ${bold(String(config.max_threads))}\n`);
|
|
551
|
+
out.write(` ${cyan("4")} Auto routing ${bold(config.auto_model_selection ? "on" : "off")}\n`);
|
|
552
|
+
out.write(` ${cyan("5")} Session budget ${bold(`$${config.max_session_budget_usd.toFixed(2)}`)}\n`);
|
|
553
|
+
out.write(` ${cyan("6")} Thread budget ${bold(`$${config.max_thread_budget_usd.toFixed(2)}`)}\n`);
|
|
554
|
+
out.write(` ${cyan("7")} Compression ${bold(config.compression_strategy)}\n`);
|
|
555
|
+
out.write("\n");
|
|
556
|
+
const choice = await ask(` ${coral(symbols.arrow)} Setting to change [1-7, or enter to cancel]: `);
|
|
557
|
+
if (!choice) {
|
|
558
|
+
out.write(` ${dim("No changes made.")}\n\n`);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
switch (choice) {
|
|
562
|
+
case "1": {
|
|
563
|
+
const agents = (await import("./agents/provider.js")).listAgents();
|
|
564
|
+
out.write(`\n ${dim("Available agents:")} ${agents.join(", ")}\n`);
|
|
565
|
+
const val = await ask(` ${coral(symbols.arrow)} New agent [${config.default_agent}]: `);
|
|
566
|
+
if (val && agents.includes(val)) {
|
|
567
|
+
config.default_agent = val;
|
|
568
|
+
logSuccess(`Agent set to ${bold(val)}`);
|
|
569
|
+
}
|
|
570
|
+
else if (val) {
|
|
571
|
+
logWarn(`Unknown agent "${val}"`);
|
|
572
|
+
}
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
case "2": {
|
|
576
|
+
out.write(`\n ${dim("Enter model ID (e.g. ollama/deepseek-coder-v2, anthropic/claude-sonnet-4-6, openrouter/auto)")}\n`);
|
|
577
|
+
const val = await ask(` ${coral(symbols.arrow)} New model [${config.default_model}]: `);
|
|
578
|
+
if (val) {
|
|
579
|
+
const lookupId = val.startsWith("ollama/") || val.startsWith("openrouter/")
|
|
580
|
+
? val
|
|
581
|
+
: val.replace(/^(anthropic|openai|google)\//, "");
|
|
582
|
+
const newResolved = resolveModel(lookupId, logWarn);
|
|
583
|
+
if (newResolved) {
|
|
584
|
+
config.default_model = val;
|
|
585
|
+
resolved.model = newResolved.model;
|
|
586
|
+
resolved.provider = newResolved.provider;
|
|
587
|
+
logSuccess(`Model set to ${bold(val)}`);
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
logWarn(`Could not resolve model "${val}"`);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
break;
|
|
594
|
+
}
|
|
595
|
+
case "3": {
|
|
596
|
+
const val = await ask(` ${coral(symbols.arrow)} Max concurrent threads [${config.max_threads}]: `);
|
|
597
|
+
const n = parseInt(val, 10);
|
|
598
|
+
if (n >= 1 && n <= 20) {
|
|
599
|
+
config.max_threads = n;
|
|
600
|
+
logSuccess(`Max threads set to ${bold(String(n))}`);
|
|
601
|
+
}
|
|
602
|
+
else if (val) {
|
|
603
|
+
logWarn("Must be between 1 and 20");
|
|
604
|
+
}
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
case "4": {
|
|
608
|
+
config.auto_model_selection = !config.auto_model_selection;
|
|
609
|
+
logSuccess(`Auto routing ${bold(config.auto_model_selection ? "enabled" : "disabled")}`);
|
|
610
|
+
break;
|
|
611
|
+
}
|
|
612
|
+
case "5": {
|
|
613
|
+
const val = await ask(` ${coral(symbols.arrow)} Session budget USD [${config.max_session_budget_usd}]: `);
|
|
614
|
+
const n = parseFloat(val);
|
|
615
|
+
if (Number.isFinite(n) && n > 0) {
|
|
616
|
+
config.max_session_budget_usd = n;
|
|
617
|
+
logSuccess(`Session budget set to ${bold(`$${n.toFixed(2)}`)}`);
|
|
618
|
+
}
|
|
619
|
+
else if (val) {
|
|
620
|
+
logWarn("Must be a positive number");
|
|
621
|
+
}
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
case "6": {
|
|
625
|
+
const val = await ask(` ${coral(symbols.arrow)} Per-thread budget USD [${config.max_thread_budget_usd}]: `);
|
|
626
|
+
const n = parseFloat(val);
|
|
627
|
+
if (Number.isFinite(n) && n > 0) {
|
|
628
|
+
config.max_thread_budget_usd = n;
|
|
629
|
+
logSuccess(`Thread budget set to ${bold(`$${n.toFixed(2)}`)}`);
|
|
630
|
+
}
|
|
631
|
+
else if (val) {
|
|
632
|
+
logWarn("Must be a positive number");
|
|
633
|
+
}
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
636
|
+
case "7": {
|
|
637
|
+
const strategies = ["structured", "llm-summary", "diff-only", "truncate"];
|
|
638
|
+
out.write(`\n ${dim("Options:")} ${strategies.join(", ")}\n`);
|
|
639
|
+
const val = await ask(` ${coral(symbols.arrow)} Compression [${config.compression_strategy}]: `);
|
|
640
|
+
if (val && strategies.includes(val)) {
|
|
641
|
+
config.compression_strategy = val;
|
|
642
|
+
logSuccess(`Compression set to ${bold(val)}`);
|
|
643
|
+
}
|
|
644
|
+
else if (val) {
|
|
645
|
+
logWarn(`Unknown strategy "${val}"`);
|
|
646
|
+
}
|
|
647
|
+
break;
|
|
648
|
+
}
|
|
649
|
+
default:
|
|
650
|
+
logWarn("Invalid option");
|
|
651
|
+
}
|
|
652
|
+
out.write("\n");
|
|
653
|
+
}
|
|
539
654
|
// ── Interactive banner ──────────────────────────────────────────────────────
|
|
540
655
|
function renderInteractiveBanner(config) {
|
|
541
656
|
const w = Math.max(Math.min(termWidth(), 60), 24);
|
|
@@ -932,6 +1047,11 @@ export async function runInteractiveSwarm(rawArgs) {
|
|
|
932
1047
|
case "/s":
|
|
933
1048
|
cmdStatus(threadManager, sessionStartTime, taskCount);
|
|
934
1049
|
break;
|
|
1050
|
+
case "/configure":
|
|
1051
|
+
case "/config":
|
|
1052
|
+
case "/c":
|
|
1053
|
+
await cmdConfigure(config, resolved, rl);
|
|
1054
|
+
break;
|
|
935
1055
|
case "/quit":
|
|
936
1056
|
case "/exit":
|
|
937
1057
|
case "/q":
|
|
@@ -21,14 +21,22 @@ const DEFAULT_MODELS = {
|
|
|
21
21
|
};
|
|
22
22
|
/**
|
|
23
23
|
* Create a synthetic pi-ai Model for Ollama (OpenAI-compatible API at localhost:11434).
|
|
24
|
+
*
|
|
25
|
+
* Uses provider "openai" so pi-ai's API key lookup resolves to OPENAI_API_KEY.
|
|
26
|
+
* We set a dummy OPENAI_API_KEY if none exists — Ollama ignores auth headers.
|
|
24
27
|
*/
|
|
25
28
|
function createOllamaModel(modelId) {
|
|
26
29
|
const shortId = modelId.replace("ollama/", "");
|
|
30
|
+
// pi-ai requires an API key for the "openai" provider. Ollama doesn't need one,
|
|
31
|
+
// but we must satisfy pi-ai's check. Set a dummy key if no real one exists.
|
|
32
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
33
|
+
process.env.OPENAI_API_KEY = "ollama-local";
|
|
34
|
+
}
|
|
27
35
|
return {
|
|
28
36
|
id: shortId,
|
|
29
37
|
name: shortId,
|
|
30
38
|
api: "openai-completions",
|
|
31
|
-
provider: "
|
|
39
|
+
provider: "openai",
|
|
32
40
|
baseUrl: "http://localhost:11434/v1",
|
|
33
41
|
reasoning: false,
|
|
34
42
|
input: ["text"],
|
package/package.json
CHANGED