@desplega.ai/agent-swarm 1.76.3 → 1.77.1
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/openapi.json +1 -1
- package/package.json +1 -1
- package/src/cli.tsx +3 -24
- package/src/commands/credential-wait.ts +31 -6
- package/src/commands/runner.ts +1069 -1067
- package/src/tests/tool-call-progress.test.ts +44 -0
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Swarm API",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.77.0",
|
|
6
6
|
"description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
package/package.json
CHANGED
package/src/cli.tsx
CHANGED
|
@@ -34,7 +34,6 @@ interface ParsedArgs {
|
|
|
34
34
|
systemPrompt: string;
|
|
35
35
|
systemPromptFile: string;
|
|
36
36
|
additionalArgs: string[];
|
|
37
|
-
aiLoop: boolean;
|
|
38
37
|
preset: string;
|
|
39
38
|
open: boolean;
|
|
40
39
|
showHelp: boolean;
|
|
@@ -54,7 +53,6 @@ function parseArgs(args: string[]): ParsedArgs {
|
|
|
54
53
|
let systemPrompt = "";
|
|
55
54
|
let systemPromptFile = "";
|
|
56
55
|
let additionalArgs: string[] = [];
|
|
57
|
-
let aiLoop = false;
|
|
58
56
|
let preset = "";
|
|
59
57
|
let open = false;
|
|
60
58
|
let showHelp = false;
|
|
@@ -92,8 +90,6 @@ function parseArgs(args: string[]): ParsedArgs {
|
|
|
92
90
|
} else if (arg === "--system-prompt-file") {
|
|
93
91
|
systemPromptFile = mainArgs[i + 1] || systemPromptFile;
|
|
94
92
|
i++;
|
|
95
|
-
} else if (arg === "--ai-loop") {
|
|
96
|
-
aiLoop = true;
|
|
97
93
|
} else if (arg === "--preset") {
|
|
98
94
|
preset = mainArgs[i + 1] || preset;
|
|
99
95
|
i++;
|
|
@@ -122,7 +118,6 @@ function parseArgs(args: string[]): ParsedArgs {
|
|
|
122
118
|
systemPrompt,
|
|
123
119
|
systemPromptFile,
|
|
124
120
|
additionalArgs,
|
|
125
|
-
aiLoop,
|
|
126
121
|
preset,
|
|
127
122
|
open,
|
|
128
123
|
showHelp,
|
|
@@ -207,7 +202,6 @@ const COMMAND_HELP: Record<
|
|
|
207
202
|
" --yolo Continue on errors instead of stopping",
|
|
208
203
|
" --system-prompt <text> Custom system prompt (appended to Claude)",
|
|
209
204
|
" --system-prompt-file <path> Read system prompt from file",
|
|
210
|
-
" --ai-loop Use AI-based polling (legacy mode)",
|
|
211
205
|
" -- <args...> Additional arguments to pass to Claude CLI",
|
|
212
206
|
" -h, --help Show this help",
|
|
213
207
|
].join("\n"),
|
|
@@ -226,7 +220,6 @@ const COMMAND_HELP: Record<
|
|
|
226
220
|
" --yolo Continue on errors instead of stopping",
|
|
227
221
|
" --system-prompt <text> Custom system prompt",
|
|
228
222
|
" --system-prompt-file <path> Read system prompt from file",
|
|
229
|
-
" --ai-loop Use AI-based polling (legacy mode)",
|
|
230
223
|
" -- <args...> Additional arguments to pass to Claude CLI",
|
|
231
224
|
" -h, --help Show this help",
|
|
232
225
|
].join("\n"),
|
|
@@ -406,7 +399,6 @@ interface RunnerProps {
|
|
|
406
399
|
systemPrompt: string;
|
|
407
400
|
systemPromptFile: string;
|
|
408
401
|
additionalArgs: string[];
|
|
409
|
-
aiLoop: boolean;
|
|
410
402
|
}
|
|
411
403
|
|
|
412
404
|
function WorkerRunner({
|
|
@@ -415,7 +407,6 @@ function WorkerRunner({
|
|
|
415
407
|
systemPrompt,
|
|
416
408
|
systemPromptFile,
|
|
417
409
|
additionalArgs,
|
|
418
|
-
aiLoop,
|
|
419
410
|
}: RunnerProps) {
|
|
420
411
|
const { exit } = useApp();
|
|
421
412
|
|
|
@@ -427,25 +418,17 @@ function WorkerRunner({
|
|
|
427
418
|
systemPromptFile: systemPromptFile || undefined,
|
|
428
419
|
additionalArgs,
|
|
429
420
|
logsDir: "./logs",
|
|
430
|
-
aiLoop,
|
|
431
421
|
}).catch((err) => {
|
|
432
422
|
console.error("[error] Worker encountered an error:", err);
|
|
433
423
|
exit(err);
|
|
434
424
|
});
|
|
435
425
|
// Note: runWorker runs indefinitely, so we don't call exit() on success
|
|
436
|
-
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs,
|
|
426
|
+
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs, exit]);
|
|
437
427
|
|
|
438
428
|
return null;
|
|
439
429
|
}
|
|
440
430
|
|
|
441
|
-
function LeadRunner({
|
|
442
|
-
prompt,
|
|
443
|
-
yolo,
|
|
444
|
-
systemPrompt,
|
|
445
|
-
systemPromptFile,
|
|
446
|
-
additionalArgs,
|
|
447
|
-
aiLoop,
|
|
448
|
-
}: RunnerProps) {
|
|
431
|
+
function LeadRunner({ prompt, yolo, systemPrompt, systemPromptFile, additionalArgs }: RunnerProps) {
|
|
449
432
|
const { exit } = useApp();
|
|
450
433
|
|
|
451
434
|
useEffect(() => {
|
|
@@ -456,13 +439,12 @@ function LeadRunner({
|
|
|
456
439
|
systemPromptFile: systemPromptFile || undefined,
|
|
457
440
|
additionalArgs,
|
|
458
441
|
logsDir: "./logs",
|
|
459
|
-
aiLoop,
|
|
460
442
|
}).catch((err) => {
|
|
461
443
|
console.error("[error] Lead encountered an error:", err);
|
|
462
444
|
exit(err);
|
|
463
445
|
});
|
|
464
446
|
// Note: runLead runs indefinitely, so we don't call exit() on success
|
|
465
|
-
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs,
|
|
447
|
+
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs, exit]);
|
|
466
448
|
|
|
467
449
|
return null;
|
|
468
450
|
}
|
|
@@ -495,7 +477,6 @@ function App({ args }: { args: ParsedArgs }) {
|
|
|
495
477
|
systemPrompt,
|
|
496
478
|
systemPromptFile,
|
|
497
479
|
additionalArgs,
|
|
498
|
-
aiLoop,
|
|
499
480
|
preset,
|
|
500
481
|
} = args;
|
|
501
482
|
|
|
@@ -516,7 +497,6 @@ function App({ args }: { args: ParsedArgs }) {
|
|
|
516
497
|
systemPrompt={systemPrompt}
|
|
517
498
|
systemPromptFile={systemPromptFile}
|
|
518
499
|
additionalArgs={additionalArgs}
|
|
519
|
-
aiLoop={aiLoop}
|
|
520
500
|
/>
|
|
521
501
|
);
|
|
522
502
|
case "lead":
|
|
@@ -527,7 +507,6 @@ function App({ args }: { args: ParsedArgs }) {
|
|
|
527
507
|
systemPrompt={systemPrompt}
|
|
528
508
|
systemPromptFile={systemPromptFile}
|
|
529
509
|
additionalArgs={additionalArgs}
|
|
530
|
-
aiLoop={aiLoop}
|
|
531
510
|
/>
|
|
532
511
|
);
|
|
533
512
|
// version, help, docs handled before render()
|
|
@@ -46,8 +46,17 @@ export class BootMaxWaitExceededError extends Error {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export interface AwaitCredentialsOptions {
|
|
49
|
-
/**
|
|
49
|
+
/** Initial harness provider name — picks the predicate to run. */
|
|
50
50
|
provider: string;
|
|
51
|
+
/**
|
|
52
|
+
* Optional getter that re-reads the harness provider on each tick. Lets the
|
|
53
|
+
* caller swap the harness mid-wait when an operator flips `HARNESS_PROVIDER`
|
|
54
|
+
* in `swarm_config` to escape a missing-credentials wedge. When unset, the
|
|
55
|
+
* static `provider` is used for the whole wait. The caller is responsible
|
|
56
|
+
* for any side effects of the swap (adapter, prompt rebuild, etc.) inside
|
|
57
|
+
* `refreshEnv` or out-of-band.
|
|
58
|
+
*/
|
|
59
|
+
getProvider?: () => string;
|
|
51
60
|
/** Pull latest swarm_config values into env. Resolves to the merged env. */
|
|
52
61
|
refreshEnv: () => Promise<Record<string, string | undefined>>;
|
|
53
62
|
/** Callback invoked on every tick — Phase 3 wires this to the status-report API. */
|
|
@@ -118,10 +127,17 @@ export async function awaitCredentials(opts: AwaitCredentialsOptions): Promise<C
|
|
|
118
127
|
const initialEnv = opts.initialEnv ?? process.env;
|
|
119
128
|
const backoff = resolveBackoff(opts.backoff, initialEnv);
|
|
120
129
|
|
|
130
|
+
// Re-read on every iteration so an operator flipping HARNESS_PROVIDER in
|
|
131
|
+
// swarm_config during the wait actually flips the predicate.
|
|
132
|
+
const readProvider = () => opts.getProvider?.() ?? opts.provider;
|
|
133
|
+
|
|
121
134
|
// Fast path: already satisfied at boot.
|
|
122
|
-
let
|
|
135
|
+
let currentProvider = readProvider();
|
|
136
|
+
let status = checkProviderCredentials(currentProvider, initialEnv, opts.credCheckOptions);
|
|
123
137
|
if (status.ready) {
|
|
124
|
-
log(
|
|
138
|
+
log(
|
|
139
|
+
`[boot] credentials ready (provider=${currentProvider}, satisfiedBy=${status.satisfiedBy})`,
|
|
140
|
+
);
|
|
125
141
|
return status;
|
|
126
142
|
}
|
|
127
143
|
|
|
@@ -143,7 +159,7 @@ export async function awaitCredentials(opts: AwaitCredentialsOptions): Promise<C
|
|
|
143
159
|
|
|
144
160
|
log(
|
|
145
161
|
`[boot] waiting for ${status.missing.join(", ") || "credentials"} ` +
|
|
146
|
-
`(attempt ${attempt}, retry in ${delayMs}ms)${status.hint ? ` — ${status.hint}` : ""}`,
|
|
162
|
+
`(attempt ${attempt}, retry in ${delayMs}ms, provider=${currentProvider})${status.hint ? ` — ${status.hint}` : ""}`,
|
|
147
163
|
);
|
|
148
164
|
|
|
149
165
|
await sleep(delayMs);
|
|
@@ -158,7 +174,16 @@ export async function awaitCredentials(opts: AwaitCredentialsOptions): Promise<C
|
|
|
158
174
|
log(`[boot] env refresh failed (non-fatal): ${err}`);
|
|
159
175
|
}
|
|
160
176
|
|
|
161
|
-
|
|
177
|
+
// Re-read provider in case the operator flipped HARNESS_PROVIDER during
|
|
178
|
+
// the wait. The caller is expected to have already swapped adapter/prompt
|
|
179
|
+
// (typically inside `refreshEnv`); we just pivot the predicate here.
|
|
180
|
+
const nextProvider = readProvider();
|
|
181
|
+
if (nextProvider !== currentProvider) {
|
|
182
|
+
log(`[boot] provider changed mid-wait: ${currentProvider} → ${nextProvider}`);
|
|
183
|
+
currentProvider = nextProvider;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
status = checkProviderCredentials(currentProvider, process.env, opts.credCheckOptions);
|
|
162
187
|
|
|
163
188
|
if (!status.ready) {
|
|
164
189
|
// Exponential backoff with cap.
|
|
@@ -174,7 +199,7 @@ export async function awaitCredentials(opts: AwaitCredentialsOptions): Promise<C
|
|
|
174
199
|
}
|
|
175
200
|
|
|
176
201
|
log(
|
|
177
|
-
`[boot] credentials ready (provider=${
|
|
202
|
+
`[boot] credentials ready (provider=${currentProvider}, satisfiedBy=${status.satisfiedBy}, attempts=${attempt})`,
|
|
178
203
|
);
|
|
179
204
|
// Final tick so callers can clear the waiting state.
|
|
180
205
|
try {
|