bullswarm 0.25.2 → 0.25.4
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 +93 -0
- package/README.md +88 -12
- package/connectors/_schema.json +15 -0
- package/connectors/claude-code.json +13 -0
- package/connectors/codex.json +157 -14
- package/connectors/command-code.json +8 -0
- package/connectors/echo-worker.mjs +6 -0
- package/connectors/echo.json +1 -0
- package/connectors/grok.json +133 -14
- package/connectors/opencode2.json +2 -0
- package/package.json +1 -1
- package/skill/SKILL.md +19 -1
- package/skill/references/operations.md +52 -6
- package/src/cli.js +84 -7
- package/src/help.js +82 -16
- package/src/integrate.js +6 -2
- package/src/lib/config.js +38 -0
- package/src/lib/quota.js +380 -0
- package/src/lib/reasoning.js +190 -0
- package/src/lib/route.js +74 -12
- package/src/lib/state.js +12 -5
- package/src/lib/strategy.js +100 -0
- package/src/lib/watch.js +90 -10
- package/src/meters/framework.js +36 -6
- package/src/meters/registry.js +17 -2
- package/src/setup.js +70 -3
- package/src/strategy-cli.js +159 -12
- package/src/strategy-dashboard.js +4 -1
- package/src/workflow/action-validator.js +8 -1
- package/src/workflow/cli.js +50 -8
- package/src/workflow/dashboard.js +28 -9
- package/src/workflow/pool-refresh.js +73 -0
- package/src/workflow/runner.js +2 -0
- package/src/workflow/runs-cli.js +14 -0
- package/src/workflow/runtime.js +27 -3
- package/src/workflow/v2-dispatch.js +92 -8
- package/src/workflow/v2-outcome.js +16 -1
- package/src/workflow/v2-planner.js +19 -1
- package/src/workflow/v2-runtime.js +35 -5
- package/src/workflow/v2-state.js +5 -4
- package/src/workflow/watch-cli.js +87 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,98 @@
|
|
|
1
1
|
# bullswarm changelog
|
|
2
2
|
|
|
3
|
+
## 0.25.4 — reasoning levels
|
|
4
|
+
|
|
5
|
+
- A connector now declares how its own CLI expresses a thinking level, and
|
|
6
|
+
every dispatch resolves exactly one level per attempt. The block is
|
|
7
|
+
`reasoning: { flag | args, levels, defaults, skipModels? }` — `flag` for a
|
|
8
|
+
CLI that takes `--effort <level>`, `args` for one whose control is a config
|
|
9
|
+
override (`-c model_reasoning_effort={level}`). The packaged `claude-code`,
|
|
10
|
+
`codex`, `grok`, and `command-code` templates carry the block read from
|
|
11
|
+
their installed CLIs or an official source (Claude Code and Command Code from
|
|
12
|
+
`--help`, Codex from its config reference, Grok from the binary's own
|
|
13
|
+
validation message); Command Code's model-dependent set stays marked
|
|
14
|
+
UNVERIFIED rather than invented. One shared resolver applies the precedence
|
|
15
|
+
chain — the action's own `reasoning` field, the run-wide override, the
|
|
16
|
+
configured `strategy.reasoning` level for that pool and tier, the same for
|
|
17
|
+
the tier globally, then the connector's default for the effort tier — so
|
|
18
|
+
the first layer that sets a level wins, not the strongest. The level is
|
|
19
|
+
appended to the spawned command exactly as `--model` is appended today;
|
|
20
|
+
nothing is appended for a connector with no block, for the literal level
|
|
21
|
+
`default`, or for a model the connector marks under `skipModels`. A level
|
|
22
|
+
the connector does not accept is clamped to the nearest one it does, never
|
|
23
|
+
dropped and never invented. `{ requested, applied, source, clamped }` is
|
|
24
|
+
recorded on every attempt, in the decision log, in `bullswarm run --json`,
|
|
25
|
+
in the V2 result envelope, and in the new `bullswarm run --dry-run` command
|
|
26
|
+
preview — which builds its argv through the same builder that spawns, so
|
|
27
|
+
preview and dispatch cannot drift.
|
|
28
|
+
|
|
29
|
+
- `bullswarm setup` asks one reasoning level per effort tier (suggesting
|
|
30
|
+
high=xhigh, medium=high, low=medium, with `default` always offered to leave
|
|
31
|
+
a worker CLI's own setting untouched) and stores the answers under
|
|
32
|
+
`state.strategy.reasoning`. Agents configure the same thing without a
|
|
33
|
+
terminal: `bullswarm strategy set-reasoning --tier <high|medium|low> --level
|
|
34
|
+
<low|medium|high|xhigh|max|default> [--pool <name>] --yes`, `bullswarm
|
|
35
|
+
strategy reset-reasoning [--tier ..] [--pool ..] --yes`, and a `reasoning`
|
|
36
|
+
section in `strategy configure --file <json> --yes` whose invalidity rejects
|
|
37
|
+
the whole document. `bullswarm strategy inventory --json` reports the
|
|
38
|
+
configured levels and, through the resolver dispatch itself uses, the
|
|
39
|
+
effective level and its source for every pool and tier. Installed home
|
|
40
|
+
connectors receive the packaged `reasoning` block additively on upgrade, and
|
|
41
|
+
a block the user has customized is never overwritten.
|
|
42
|
+
|
|
43
|
+
- A V2 program action accepts an optional `reasoning` field
|
|
44
|
+
(`low|medium|high|xhigh|max|default`) that the calling agent or the
|
|
45
|
+
Workflow Planner can set and that outranks every configured level for that
|
|
46
|
+
one action; `workflow plan contract` documents the field and echoes the
|
|
47
|
+
run-wide levels a launch would apply. `workflow goal` takes
|
|
48
|
+
`--worker-reasoning <level>` for every non-planner dispatch and
|
|
49
|
+
`--planner-reasoning <level>` for a dispatched Workflow Planner, and
|
|
50
|
+
`bullswarm run` takes `--reasoning <level>`; a level off the scale is a
|
|
51
|
+
usage error that launches nothing. The applied level appears next to the
|
|
52
|
+
model in `workflow runs show` (text and `--json`), `workflow runs result
|
|
53
|
+
--json`, the TUI attempt rows and agent pane, so a run that thought more
|
|
54
|
+
cheaply than asked is visible rather than inferred.
|
|
55
|
+
|
|
56
|
+
## 0.25.3 — usage-limit recovery and headroom-aware routing
|
|
57
|
+
|
|
58
|
+
- A provider that reports a usage limit is now its own mechanical failure kind,
|
|
59
|
+
`quota` — never `process`, `semantic`, or `auth`. The attempt is killed at
|
|
60
|
+
once instead of waiting out a CLI that printed its limit and then hung, and
|
|
61
|
+
the pool is quarantined until the reset the message named, falling back to
|
|
62
|
+
that pool's cached 5-hour `resets_at` and then to 30 minutes rather than the
|
|
63
|
+
flat 10. The quarantine record carries `kind: 'quota'` and excludes the pool
|
|
64
|
+
from every later dispatch, in that run and in others, until it expires; the
|
|
65
|
+
action moves to another pool with quota and is never retried on the one that
|
|
66
|
+
hit the limit. `bullswarm run`, the V1 runtime, and V2 dispatch all apply the
|
|
67
|
+
same deadline. Detection is shape-gated: an agent report that discusses usage
|
|
68
|
+
limits, or tool output quoting them, is not a limit, and phrases that other
|
|
69
|
+
services also emit (`rate limited`, `too many requests`, `quota exceeded`)
|
|
70
|
+
count only as a bare notice, never as narration about someone else's quota
|
|
71
|
+
("rate limited by the GitHub API, retrying"). Connectors declare their
|
|
72
|
+
own phrases under `quotaSignatures`; installed connectors receive new ones on
|
|
73
|
+
upgrade.
|
|
74
|
+
|
|
75
|
+
- Routing avoids pools that are close to their 5-hour limit. A pool at or above
|
|
76
|
+
`FIVE_HOUR_NEAR_LIMIT_PCT` (75) is chosen only when no eligible pool below it
|
|
77
|
+
exists for the lane, ahead of pace, an approved assignment, and incumbency;
|
|
78
|
+
pools at or above 90 stay excluded outright, and a pool with no 5-hour
|
|
79
|
+
reading counts as having headroom. Routing reasons and candidate lists name
|
|
80
|
+
the utilization that decided the pick, and `bullswarm pools` shows it as
|
|
81
|
+
`5h=<n>%` with a `NEAR-5H-LIMIT` label. Meters and quarantines are re-read
|
|
82
|
+
from the meter cache and core state before every action dispatch and before
|
|
83
|
+
every retry inside one — forced live right after a usage limit — so a long
|
|
84
|
+
run no longer dispatches from the pool snapshot frozen at launch.
|
|
85
|
+
|
|
86
|
+
- `workflow watch` reports a usage-limit retry as a notable event in both
|
|
87
|
+
modes' vocabulary: `⚠ <action> usage limit on <pool> · paused until
|
|
88
|
+
<deadline> · retrying on another pool`, then `↺ <action> now on <pool> ·
|
|
89
|
+
<model>` once the retry lands. Both print without `--verbose`, wake `--next`,
|
|
90
|
+
and appear in `--jsonl` as `attempt.quota` and `attempt.moved`. The new
|
|
91
|
+
`--classic` flag forces the older heartbeat-based watcher (transition-on-change
|
|
92
|
+
snapshots plus a periodic heartbeat, 60 seconds unless `--heartbeat <seconds>`
|
|
93
|
+
is given) for a V2 run; it is a no-op for legacy runs and cannot combine with
|
|
94
|
+
`--next`.
|
|
95
|
+
|
|
3
96
|
## 0.25.2 — event-based watch
|
|
4
97
|
|
|
5
98
|
- `workflow watch <run> --next` is safe to relaunch after every wake-up: each
|
package/README.md
CHANGED
|
@@ -37,12 +37,17 @@ detaches safely.
|
|
|
37
37
|
passing verification.
|
|
38
38
|
2. **Pace by meter.** The scheduling resource is the subscription window:
|
|
39
39
|
elapsed% minus used%, most-behind pool wins. Pace may only promote a
|
|
40
|
-
*cheaper* pool. Lanes are work-nature, never hard-coded to pools.
|
|
40
|
+
*cheaper* pool. Lanes are work-nature, never hard-coded to pools. The
|
|
41
|
+
5-hour window never paces — it gates: a pool at or above 75% of it is
|
|
42
|
+
chosen only when no eligible pool below that line exists, and one at or
|
|
43
|
+
above 90% is not dispatched at all.
|
|
41
44
|
3. **Delegate output is evidence, never authority.** The Workflow Planner may
|
|
42
45
|
propose actions, but only the deterministic kernel validates the program,
|
|
43
46
|
accepts requirement-scoped evidence, and computes completion.
|
|
44
47
|
4. **Quarantine re-probes.** A benched pool must be able to return to service
|
|
45
|
-
automatically; a lane is never allowed to silently go down.
|
|
48
|
+
automatically; a lane is never allowed to silently go down. A pool benched
|
|
49
|
+
for a usage limit waits for the reset the provider named, not a flat
|
|
50
|
+
guess — and never longer.
|
|
46
51
|
|
|
47
52
|
## Install
|
|
48
53
|
|
|
@@ -94,7 +99,7 @@ bullswarm health # re-judge saved outputs; catch gate failures
|
|
|
94
99
|
| `delegate` | Explain and execute the smallest reliable shape: one content-verified agent, or the planning contract for an autonomous workflow you author (`--orchestrator` dispatches a planner agent instead). |
|
|
95
100
|
| `run` | route → dispatch → watch → verify → one JSON verdict |
|
|
96
101
|
| `health` | Re-judge saved outputs against their verdicts; surface verify-gate failures and quarantine clusters |
|
|
97
|
-
| `pools` | Show each pool's meter state, pace position, quarantine status |
|
|
102
|
+
| `pools` | Show each pool's meter state, pace position, 5-hour utilization (`5h=<n>%`, flagged `NEAR-5H-LIMIT` at or above 75%), quarantine status |
|
|
98
103
|
| `strategy` | Interactive provider/model control center with live high/medium/low route previews and an agent-facing JSON API |
|
|
99
104
|
| `doctor` | Machine-readable readiness report; self-heals on first call |
|
|
100
105
|
| `workflow` | Start an autonomous goal, or run / validate / draft / inspect explicit workflows and their live instances. |
|
|
@@ -144,6 +149,9 @@ bullswarm strategy set-model opencode2 kaihk/gpt-5.6-luna \
|
|
|
144
149
|
--tiers high,medium,low --yes
|
|
145
150
|
bullswarm strategy configure --file strategy.json --yes # atomic agent-authored policy
|
|
146
151
|
bullswarm strategy reset-tier low --yes # restore one tier to automatic
|
|
152
|
+
bullswarm strategy set-reasoning --tier high --level xhigh --yes
|
|
153
|
+
bullswarm strategy set-reasoning --tier high --level high --pool codex --yes
|
|
154
|
+
bullswarm strategy reset-reasoning --tier high --yes # back to connector defaults
|
|
147
155
|
bullswarm strategy refresh
|
|
148
156
|
bullswarm strategy show --json
|
|
149
157
|
bullswarm strategy apply --yes --refresh-hours 24
|
|
@@ -209,8 +217,15 @@ best eligible models on its configured interval. Disable it with
|
|
|
209
217
|
`strategy auto off --yes`. Discovery commands, model argument syntax, pricing,
|
|
210
218
|
and benchmark declarations remain connector-owned. Unknown license value,
|
|
211
219
|
prices, and benchmarks stay `null` rather than being guessed. An assignment is
|
|
212
|
-
only a preference: quarantine, exhaustion, burst gates,
|
|
213
|
-
still win.
|
|
220
|
+
only a preference: quarantine, exhaustion, burst gates, 5-hour headroom, and
|
|
221
|
+
capability checks still win. Routing prefers pools below
|
|
222
|
+
`FIVE_HOUR_NEAR_LIMIT_PCT` (75) of their 5-hour window over pools at or above
|
|
223
|
+
it, ahead of pace, an approved assignment, and incumbency; a near-limit pool is
|
|
224
|
+
still picked when it is the only eligible one, and a pool with no 5-hour
|
|
225
|
+
reading counts as having headroom. The routing reason and every candidate row
|
|
226
|
+
name the utilization that decided the pick, and meters and quarantines are
|
|
227
|
+
re-read before each dispatch — and again, live, right after a usage limit —
|
|
228
|
+
so a long run never routes off the snapshot it launched with.
|
|
214
229
|
|
|
215
230
|
Model exclusions are hard routing policy. An excluded model is removed from
|
|
216
231
|
recommendations and assignments, and Bullswarm pins a same-tier allowed model
|
|
@@ -290,6 +305,16 @@ adversarial acceptance judgment. Merely being an analysis/evidence action or
|
|
|
290
305
|
part of a difficult goal never promotes an action to high. The selected effort
|
|
291
306
|
then resolves through the High/Medium/Low routes configured by `bullswarm setup`.
|
|
292
307
|
|
|
308
|
+
Reasoning depth is a third, independent decision. An action may carry an
|
|
309
|
+
optional `reasoning` field — `low`, `medium`, `high`, `xhigh`, `max`, or
|
|
310
|
+
`default` — that sets how hard the picked model thinks on that one action and
|
|
311
|
+
outranks every configured level for it. `default` passes nothing and lets the
|
|
312
|
+
worker CLI's own setting decide. Omitting the field keeps the configured level.
|
|
313
|
+
It never changes the pool, model, or effort tier, so a `low`-effort mechanical
|
|
314
|
+
step can still be given `xhigh` thinking and a `high`-effort action can be told
|
|
315
|
+
to think cheaply. A connector that does not accept the requested level gets the
|
|
316
|
+
nearest level it supports.
|
|
317
|
+
|
|
293
318
|
The planner does not author phases or declare success/failure. The kernel
|
|
294
319
|
derives stable presentation stages for the TUI and computes the final V2
|
|
295
320
|
result. Saved V2 runs retain their original execution and workspace policy on
|
|
@@ -340,6 +365,30 @@ The worker lock covers scout, work actions, and evidence actions. A pool that ca
|
|
|
340
365
|
the requested model is ineligible rather than silently substituting another
|
|
341
366
|
model.
|
|
342
367
|
|
|
368
|
+
Reasoning depth can be pinned for a whole run the same way, without touching
|
|
369
|
+
global strategy:
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
bullswarm workflow goal "Implement and verify the change" --cwd . \
|
|
373
|
+
--program plan.json --worker-reasoning high --json
|
|
374
|
+
bullswarm run --lane build --reasoning xhigh --prompt '<task>' --json
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
`--worker-reasoning` covers scout, work actions, and evidence actions;
|
|
378
|
+
`--planner-reasoning` covers a dispatched Workflow Planner and applies only
|
|
379
|
+
with `--orchestrator`. Exactly one level is resolved per attempt, and the
|
|
380
|
+
first layer that sets one wins — not the strongest: the action's own
|
|
381
|
+
`reasoning` field, then the run-wide flag (`--worker-reasoning`,
|
|
382
|
+
`--planner-reasoning`, `bullswarm run --reasoning`), then the configured
|
|
383
|
+
`strategy.reasoning` level for that pool and tier, then the same for the tier
|
|
384
|
+
globally, then the connector's own default for the effort tier, and otherwise
|
|
385
|
+
nothing is appended. So an action asking for `low` beats a run-wide `max`.
|
|
386
|
+
`default` at any layer stops there and passes nothing, letting the worker
|
|
387
|
+
CLI's own setting decide; a connector with no `reasoning` block, or a model it
|
|
388
|
+
marks as skipped, never receives a flag. The applied level is recorded on
|
|
389
|
+
every attempt with the layer that set it and displayed next to the model, so a
|
|
390
|
+
run that thought more cheaply than requested is visible rather than inferred.
|
|
391
|
+
|
|
343
392
|
The `opencode2` connector itself does not require a KaiHK provider: its base
|
|
344
393
|
spawn command carries no hardcoded model, so a plain OpenCode installation
|
|
345
394
|
dispatches with OpenCode's own configured default. When
|
|
@@ -490,9 +539,18 @@ prints one attach line, then one line per notable event as it happens
|
|
|
490
539
|
planner turn, stall/recovery, cancellation, and the existing pause and
|
|
491
540
|
terminal `outcome:` / `next:` lines) and stays silent while work is merely
|
|
492
541
|
in progress. Agent starts, mechanical retries, and steering delivery print
|
|
493
|
-
only with `--verbose`.
|
|
494
|
-
|
|
495
|
-
|
|
542
|
+
only with `--verbose`. A usage-limit failure (`failureKind: 'quota'`) always
|
|
543
|
+
prints, verbose or not: `⚠ <actionId> usage limit on <pool> · paused until
|
|
544
|
+
<deadline> · retrying on another pool`, followed once the mechanical retry
|
|
545
|
+
lands on another pool by `↺ <actionId> now on <pool> · <model>`. The
|
|
546
|
+
periodic heartbeat is off unless you pass `--heartbeat <seconds>`;
|
|
547
|
+
`--stall-after <seconds>` (default 300) reports a running agent that has
|
|
548
|
+
gone silent. Pass `--classic` to force the older heartbeat-based watcher
|
|
549
|
+
instead (the transition-on-change snapshot stream plus a periodic
|
|
550
|
+
heartbeat, every 60 seconds unless `--heartbeat <seconds>` is given) —
|
|
551
|
+
legacy (non-V2) runs already behave this way and `--classic` is a no-op for
|
|
552
|
+
them; `--classic` cannot combine with `--next`, which exists only for event
|
|
553
|
+
mode. `--next` prints no attach line and
|
|
496
554
|
exits after the first notable event so a background terminal can wake the
|
|
497
555
|
caller; relaunch until the outcome line reports a pause or a terminal
|
|
498
556
|
status (exit 0 while the run continues or delivered, 1 when it ended
|
|
@@ -507,12 +565,14 @@ reported does not produce a duplicate stall line (its recovery still
|
|
|
507
565
|
prints). `--jsonl` emits one JSON object per notable event with a stable
|
|
508
566
|
`type` (`attach`, `action.finished`,
|
|
509
567
|
`evidence.recorded`, `stage.completed`, `planner.finished`, `agent.stalled`,
|
|
510
|
-
`agent.recovered`, `cancellation.requested`, `
|
|
568
|
+
`agent.recovered`, `cancellation.requested`, `attempt.quota`,
|
|
569
|
+
`attempt.moved`, `paused`, `finished`,
|
|
511
570
|
`interrupted`, and with `--verbose` `action.started`, `attempt.retrying`,
|
|
512
571
|
`steering.delivered`); in that mode the relaunch line is not printed and
|
|
513
572
|
every object instead carries the `sequence` it was emitted at, which is the
|
|
514
573
|
value to pass as `--after`. `--once` still prints one current snapshot. Legacy
|
|
515
|
-
(non-V2) runs keep the compact transition-plus-heartbeat stream unchanged
|
|
574
|
+
(non-V2) runs keep the compact transition-plus-heartbeat stream unchanged,
|
|
575
|
+
the same stream `--classic` opts a V2 run into.
|
|
516
576
|
|
|
517
577
|
```bash
|
|
518
578
|
bullswarm workflow watch <shortId>
|
|
@@ -523,6 +583,7 @@ bullswarm workflow watch <shortId> --jsonl # one JSON object per event
|
|
|
523
583
|
bullswarm workflow watch <shortId> --once # one current/terminal snapshot
|
|
524
584
|
bullswarm workflow watch <shortId> --verbose # started / retry / steering too
|
|
525
585
|
bullswarm workflow watch <shortId> --stall-after 120 --heartbeat 30
|
|
586
|
+
bullswarm workflow watch <shortId> --classic # older heartbeat-based watcher instead of event mode
|
|
526
587
|
```
|
|
527
588
|
|
|
528
589
|
`workflow tui` is the interactive, Claude-style `/workflows` view. For an
|
|
@@ -611,6 +672,20 @@ channel, so reading source text such as an auth-signature matcher cannot falsely
|
|
|
611
672
|
quarantine Grok or Command Code. Error-shaped semantic results and stderr
|
|
612
673
|
diagnostics still trigger the auth/quota guard.
|
|
613
674
|
|
|
675
|
+
A provider that reports a usage limit — `You've hit your session limit ·
|
|
676
|
+
resets 8:20pm (Asia/Hong_Kong)`, `usage_credits_required`, `rate limit
|
|
677
|
+
exceeded`, `quota exceeded` — is its own mechanical failure kind, `quota`,
|
|
678
|
+
never `process`, `semantic`, or `auth`. The attempt is killed immediately
|
|
679
|
+
even if the CLI would otherwise hang, and the pool is quarantined until the
|
|
680
|
+
reset time parsed from the message, falling back to that pool's cached 5-hour
|
|
681
|
+
`resets_at` and then to 30 minutes. The quarantine record carries
|
|
682
|
+
`kind: 'quota'` and excludes the pool from every later dispatch, in this run
|
|
683
|
+
and in others, until it expires; the action is immediately re-dispatched on
|
|
684
|
+
another pool with quota and never retried on the one that hit the limit. An
|
|
685
|
+
agent report that merely discusses usage limits, or tool output that quotes
|
|
686
|
+
them, is not a limit: detection is shape-gated to lines that look like a
|
|
687
|
+
provider notice.
|
|
688
|
+
|
|
614
689
|
After ten minutes without transport, parsed-event, or semantic-action evidence,
|
|
615
690
|
an active child is labeled `suspected_stalled`. This is an inspection signal,
|
|
616
691
|
not a death verdict and never an automatic kill: buffered CLIs can be silent
|
|
@@ -618,8 +693,9 @@ while working. Process exit, a fatal auth/quota signature, explicit operator
|
|
|
618
693
|
cancellation, or an opt-in timeout remain the terminal signals.
|
|
619
694
|
|
|
620
695
|
Each attempt records the phase/action, selected pool and model, effort tier,
|
|
621
|
-
|
|
622
|
-
artifact paths, outcome,
|
|
696
|
+
the applied reasoning level with the layer that set it, routing reason, all
|
|
697
|
+
eligible candidates with quota surplus, timestamps, artifact paths, outcome,
|
|
698
|
+
and reported-or-estimated token/cost/quota usage.
|
|
623
699
|
`workflow tui <id>` renders this breakdown for completed runs as well as live
|
|
624
700
|
ones; `workflow tui --json <id>` exposes the durable audit document.
|
|
625
701
|
When a provider event stream reports the actual model, Bullswarm records that
|
package/connectors/_schema.json
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
"$comment-cwd": "cwdMode documents how the CLI resolves its project: 'pwd' means the CLI resolves from $PWD so the watcher MUST set PWD and spawn inside --add-dir"
|
|
11
11
|
},
|
|
12
12
|
"authSignatures": ["strings in output that mean auth/throttle failure"],
|
|
13
|
+
"quotaSignatures": ["strings in output that mean this credential is out of quota RIGHT NOW (usage/rate limit hit)"],
|
|
14
|
+
"$comment-quotaSignatures": "Optional. Merged on top of DEFAULT_QUOTA_SIGNATURES (src/lib/quota.js), matched case-insensitively, and only honored when the matched line is quota-shaped (<=300 chars and the phrase starts in the first 40 chars or the line is error-shaped) so agent prose and tool output that merely discuss limits are never killed. A hit is classified as the mechanical failure kind `quota` (checked before authSignatures), kills the attempt, and quarantines the pool until the reset time parsed from the message, else the pool's cached five_hour.resets_at, else 30 minutes.",
|
|
13
15
|
"outputExtraction": {
|
|
14
16
|
"$comment": "how to get the real answer out of stdout+stderr+files",
|
|
15
17
|
"strategy": "stdout|stdout-tail|json-field|file|event-stream",
|
|
@@ -72,6 +74,19 @@
|
|
|
72
74
|
"free": false
|
|
73
75
|
}],
|
|
74
76
|
"modelSelection": {"flag": "--model", "mode": "replace-or-append"},
|
|
77
|
+
"reasoning": {
|
|
78
|
+
"$comment": "Optional. How THIS CLI expresses a thinking level. Omit the block entirely when the CLI has no such control: core then appends nothing and reports source 'unsupported'. Declare exactly one of flag/args.",
|
|
79
|
+
"flag": "--effort",
|
|
80
|
+
"args": ["-c", "model_reasoning_effort={level}"],
|
|
81
|
+
"$comment-form": "flag: appended as `<flag> <level>` with replace-or-append semantics, so a level already pinned in spawn.cmd is replaced rather than duplicated. args: appended verbatim with {level} substituted, for CLIs whose control is a config override rather than a flag.",
|
|
82
|
+
"levels": ["low", "medium", "high", "xhigh", "max"],
|
|
83
|
+
"$comment-levels": "the subset of the common scale (low, medium, high, xhigh, max — weakest to strongest, src/lib/reasoning.js) that this CLI accepts, weakest first. A requested level outside the subset is clamped to the strongest supported level not above it, or to the weakest supported level when the request is below all of them, and the clamp is recorded.",
|
|
84
|
+
"defaults": {"high": "xhigh", "medium": "high", "low": "medium"},
|
|
85
|
+
"$comment-defaults": "the level to use for each effort tier when nothing else asked. Last layer of the precedence chain: action override > run override > strategy per-pool > strategy per-tier > THESE > nothing appended. The literal 'default' at any layer means 'append nothing, let the CLI's own configuration decide'.",
|
|
86
|
+
"skipModels": ["^model-id-regex-that-rejects-the-flag"],
|
|
87
|
+
"$comment-skipModels": "Optional connector-owned regexes. A selected model matching one gets no level appended (source 'skipped-model'), for CLIs whose flag is only valid on some models."
|
|
88
|
+
},
|
|
89
|
+
"$comment-reasoning": "Optional prose companion. Say which command's output the block was read from, and mark anything the CLI does not actually print as UNVERIFIED — never invent an accepted value.",
|
|
75
90
|
"subscription": {"plan": null, "monthlyPriceUsd": null, "includedValueUsd": null, "quotaWindow": "weekly"},
|
|
76
91
|
"flags": {
|
|
77
92
|
"stealth": false,
|
|
@@ -23,6 +23,12 @@
|
|
|
23
23
|
"not logged in",
|
|
24
24
|
"please run /login"
|
|
25
25
|
],
|
|
26
|
+
"$comment-quotaSignatures": "usage-limit phrases: classified `quota`, quarantined until the reset the message names. DEFAULT_QUOTA_SIGNATURES (src/lib/quota.js) apply on top of these.",
|
|
27
|
+
"quotaSignatures": [
|
|
28
|
+
"hit your session limit",
|
|
29
|
+
"hit your limit",
|
|
30
|
+
"hit your usage limit"
|
|
31
|
+
],
|
|
26
32
|
"outputExtraction": {
|
|
27
33
|
"strategy": "event-stream"
|
|
28
34
|
},
|
|
@@ -54,6 +60,13 @@
|
|
|
54
60
|
"capabilities": ["strong-analysis", "code-reading", "file-editing", "workflow-planning"],
|
|
55
61
|
"knownModels": ["claude-fable-5", "claude-opus-5", "claude-sonnet-5", "claude-haiku-4-5"],
|
|
56
62
|
"modelSelection": { "flag": "--model", "mode": "replace-or-append" },
|
|
63
|
+
"$comment-reasoning": "verified from `claude --help` (Claude Code 2.1.263): `--effort <level> Effort level for the current session (low, medium, high, xhigh, max)`. skipModels: `--help` does not state per-model support, so Haiku is excluded conservatively — re-verify before removing the exclusion. With no `reasoning` override anywhere, workers inherit whatever effortLevel the home settings.json sets.",
|
|
64
|
+
"reasoning": {
|
|
65
|
+
"flag": "--effort",
|
|
66
|
+
"levels": ["low", "medium", "high", "xhigh", "max"],
|
|
67
|
+
"defaults": { "high": "xhigh", "medium": "high", "low": "medium" },
|
|
68
|
+
"skipModels": ["^claude-haiku-"]
|
|
69
|
+
},
|
|
57
70
|
"conversation": {
|
|
58
71
|
"newArgs": ["--session-id", "{sessionId}"],
|
|
59
72
|
"resumeArgs": ["--resume", "{sessionId}"]
|
package/connectors/codex.json
CHANGED
|
@@ -21,19 +21,71 @@
|
|
|
21
21
|
"unauthorized",
|
|
22
22
|
"invalid api key"
|
|
23
23
|
],
|
|
24
|
+
"$comment-quotaSignatures": "usage_credits_required is a spent window, not a broken credential: it classifies `quota` (checked before authSignatures) so the pool is quarantined until its reset instead of re-probed in 10 minutes.",
|
|
25
|
+
"quotaSignatures": [
|
|
26
|
+
"usage_credits_required",
|
|
27
|
+
"usage limit"
|
|
28
|
+
],
|
|
24
29
|
"outputExtraction": {
|
|
25
30
|
"strategy": "event-stream"
|
|
26
31
|
},
|
|
27
32
|
"eventStream": {
|
|
28
33
|
"format": "jsonl",
|
|
29
|
-
"args": [
|
|
34
|
+
"args": [
|
|
35
|
+
"--json"
|
|
36
|
+
],
|
|
30
37
|
"silenceThresholdSec": 600,
|
|
31
38
|
"rules": [
|
|
32
|
-
{
|
|
33
|
-
|
|
39
|
+
{
|
|
40
|
+
"rootMatch": {
|
|
41
|
+
"path": "type",
|
|
42
|
+
"equals": "item.started"
|
|
43
|
+
},
|
|
44
|
+
"idPaths": [
|
|
45
|
+
"item.id"
|
|
46
|
+
],
|
|
47
|
+
"kindPaths": [
|
|
48
|
+
"item.type"
|
|
49
|
+
],
|
|
50
|
+
"kindMap": {
|
|
51
|
+
"agent_message": "response"
|
|
52
|
+
},
|
|
53
|
+
"summaryPaths": [
|
|
54
|
+
"item.command",
|
|
55
|
+
"item.text"
|
|
56
|
+
],
|
|
57
|
+
"status": "running"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"rootMatch": {
|
|
61
|
+
"path": "type",
|
|
62
|
+
"equals": "item.completed"
|
|
63
|
+
},
|
|
64
|
+
"idPaths": [
|
|
65
|
+
"item.id"
|
|
66
|
+
],
|
|
67
|
+
"kindPaths": [
|
|
68
|
+
"item.type"
|
|
69
|
+
],
|
|
70
|
+
"kindMap": {
|
|
71
|
+
"agent_message": "response"
|
|
72
|
+
},
|
|
73
|
+
"summaryPaths": [
|
|
74
|
+
"item.command",
|
|
75
|
+
"item.text"
|
|
76
|
+
],
|
|
77
|
+
"status": "completed"
|
|
78
|
+
}
|
|
34
79
|
],
|
|
35
80
|
"output": [
|
|
36
|
-
{
|
|
81
|
+
{
|
|
82
|
+
"match": {
|
|
83
|
+
"path": "type",
|
|
84
|
+
"equals": "item.completed"
|
|
85
|
+
},
|
|
86
|
+
"path": "item.text",
|
|
87
|
+
"mode": "last"
|
|
88
|
+
}
|
|
37
89
|
]
|
|
38
90
|
},
|
|
39
91
|
"meter": {
|
|
@@ -46,18 +98,109 @@
|
|
|
46
98
|
"build",
|
|
47
99
|
"chore"
|
|
48
100
|
],
|
|
49
|
-
"capabilities": [
|
|
50
|
-
|
|
51
|
-
|
|
101
|
+
"capabilities": [
|
|
102
|
+
"strong-analysis",
|
|
103
|
+
"code-reading",
|
|
104
|
+
"file-editing",
|
|
105
|
+
"workflow-planning"
|
|
106
|
+
],
|
|
107
|
+
"knownModels": [
|
|
108
|
+
"gpt-5.6-sol",
|
|
109
|
+
"gpt-5.6-terra",
|
|
110
|
+
"gpt-5.6-luna",
|
|
111
|
+
"gpt-5.5",
|
|
112
|
+
"gpt-5.4",
|
|
113
|
+
"gpt-5.4-mini",
|
|
114
|
+
"gpt-5.3-codex"
|
|
115
|
+
],
|
|
116
|
+
"modelSelection": {
|
|
117
|
+
"flag": "--model",
|
|
118
|
+
"mode": "replace-or-append"
|
|
119
|
+
},
|
|
120
|
+
"$comment-reasoning": "Codex has no reasoning flag; the control is the config key `model_reasoning_effort`, overridden per invocation with the escape hatch verified from `codex exec --help` (codex-cli 0.153.4): `-c, --config <key=value> Override a configuration value that would otherwise be loaded from ~/.codex/config.toml`. Accepted values verified from the official Codex config reference (https://learn.chatgpt.com/docs/config-file/config-reference, read 2026-09-09): `minimal | low | medium | high | xhigh` — \"Adjust reasoning effort for supported models (Responses API only; xhigh is model-dependent)\". `minimal` sits below bullswarm's common scale, so a request below `low` clamps up to `low`. Tier defaults stay at high/medium/low because `xhigh` is model-dependent; an explicit `xhigh` request passes through. Without this block Codex workers think at whatever config.toml sets (this machine: low).",
|
|
121
|
+
"reasoning": {
|
|
122
|
+
"args": [
|
|
123
|
+
"-c",
|
|
124
|
+
"model_reasoning_effort={level}"
|
|
125
|
+
],
|
|
126
|
+
"levels": [
|
|
127
|
+
"low",
|
|
128
|
+
"medium",
|
|
129
|
+
"high",
|
|
130
|
+
"xhigh"
|
|
131
|
+
],
|
|
132
|
+
"defaults": {
|
|
133
|
+
"high": "high",
|
|
134
|
+
"medium": "medium",
|
|
135
|
+
"low": "low"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
52
138
|
"modelProfiles": [
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
139
|
+
{
|
|
140
|
+
"match": "^gpt-5\\.6-sol$",
|
|
141
|
+
"tier": "high",
|
|
142
|
+
"qualityRank": 6,
|
|
143
|
+
"pricing": {
|
|
144
|
+
"inputUsdPerMillion": 4,
|
|
145
|
+
"cacheReadUsdPerMillion": 0.4,
|
|
146
|
+
"outputUsdPerMillion": 20
|
|
147
|
+
},
|
|
148
|
+
"pricingSource": "https://help.openai.com/en/articles/20001415-chatgpt-rate-card-enterprise-token-based-pricing",
|
|
149
|
+
"pricingUpdatedAt": "2026-08-27"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"match": "^gpt-5\\.(5|4)$",
|
|
153
|
+
"tier": "high",
|
|
154
|
+
"qualityRank": 5
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"match": "^gpt-5\\.6-terra$",
|
|
158
|
+
"tier": "medium",
|
|
159
|
+
"qualityRank": 4,
|
|
160
|
+
"pricing": {
|
|
161
|
+
"inputUsdPerMillion": 2,
|
|
162
|
+
"cacheReadUsdPerMillion": 0.2,
|
|
163
|
+
"outputUsdPerMillion": 12
|
|
164
|
+
},
|
|
165
|
+
"pricingSource": "https://developers.openai.com/api/docs/models/gpt-5.6-terra",
|
|
166
|
+
"pricingUpdatedAt": "2026-08-27"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"match": "^gpt-5\\.3-codex$",
|
|
170
|
+
"tier": "medium",
|
|
171
|
+
"qualityRank": 4,
|
|
172
|
+
"pricing": {
|
|
173
|
+
"inputUsdPerMillion": 1.75,
|
|
174
|
+
"cacheReadUsdPerMillion": 0.175,
|
|
175
|
+
"outputUsdPerMillion": 14
|
|
176
|
+
},
|
|
177
|
+
"pricingSource": "https://help.openai.com/en/articles/20001415-chatgpt-rate-card-enterprise-token-based-pricing",
|
|
178
|
+
"pricingUpdatedAt": "2026-08-27"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"match": "^gpt-5\\.6-luna$",
|
|
182
|
+
"tier": "low",
|
|
183
|
+
"qualityRank": 3,
|
|
184
|
+
"pricing": {
|
|
185
|
+
"inputUsdPerMillion": 0.2,
|
|
186
|
+
"cacheReadUsdPerMillion": 0.02,
|
|
187
|
+
"outputUsdPerMillion": 1.2
|
|
188
|
+
},
|
|
189
|
+
"pricingSource": "https://developers.openai.com/api/docs/models",
|
|
190
|
+
"pricingUpdatedAt": "2026-08-27"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"match": "mini",
|
|
194
|
+
"tier": "low",
|
|
195
|
+
"qualityRank": 2
|
|
196
|
+
}
|
|
59
197
|
],
|
|
60
|
-
"subscription": {
|
|
198
|
+
"subscription": {
|
|
199
|
+
"plan": null,
|
|
200
|
+
"monthlyPriceUsd": null,
|
|
201
|
+
"includedValueUsd": null,
|
|
202
|
+
"quotaWindow": "weekly"
|
|
203
|
+
},
|
|
61
204
|
"flags": {
|
|
62
205
|
"stealth": false
|
|
63
206
|
},
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
"not authenticated",
|
|
22
22
|
"cmd login"
|
|
23
23
|
],
|
|
24
|
+
"$comment-quotaSignatures": "empty on purpose: no cmd-specific usage-limit wording has been observed yet; DEFAULT_QUOTA_SIGNATURES in src/lib/quota.js covers the generic provider phrasings.",
|
|
25
|
+
"quotaSignatures": [],
|
|
24
26
|
"outputExtraction": {
|
|
25
27
|
"strategy": "event-stream"
|
|
26
28
|
},
|
|
@@ -53,6 +55,12 @@
|
|
|
53
55
|
"capabilities": ["code-reading", "file-editing", "strong-analysis", "workflow-planning"],
|
|
54
56
|
"modelDiscovery": { "cmd": ["command-code", "--list-models"], "parse": "columns", "ignorePattern": "^(Available|Open Source$|Anthropic$|OpenAI$|Google$|Sakana$|Meta$|xAI$|Pass|cmd|Docs)", "timeoutMs": 20000, "maxModels": 150 },
|
|
55
57
|
"modelSelection": { "flag": "--model", "mode": "replace-or-append" },
|
|
58
|
+
"$comment-reasoning": "verified from `command-code --help` (1.44.0): `--effort <level> Set reasoning effort for the session (e.g. low, medium, high) — depends on the model`. UNVERIFIED: the CLI says \"e.g.\" and \"depends on the model\", so the accepted set is neither closed nor uniform across this pool's many providers; low/medium/high is declared conservatively and a stronger request clamps down to high.",
|
|
59
|
+
"reasoning": {
|
|
60
|
+
"flag": "--effort",
|
|
61
|
+
"levels": ["low", "medium", "high"],
|
|
62
|
+
"defaults": { "high": "high", "medium": "medium", "low": "low" }
|
|
63
|
+
},
|
|
56
64
|
"modelProfiles": [
|
|
57
65
|
{ "match": "^meta/muse-spark-1\\.3-contributor$", "tier": "high", "qualityRank": 5, "pricing": { "inputUsdPerMillion": 0.1, "cacheReadUsdPerMillion": 0.002, "outputUsdPerMillion": 0.2 }, "pricingSource": "https://commandcode.ai/docs/resources/pricing-limits", "pricingUpdatedAt": "2026-09-03" },
|
|
58
66
|
{ "match": "^meta/muse-spark-", "tier": "high", "qualityRank": 5, "pricing": { "inputUsdPerMillion": 1.25, "cacheReadUsdPerMillion": 0.15, "outputUsdPerMillion": 4.25 }, "pricingSource": "https://commandcode.ai/docs/resources/pricing-limits", "pricingUpdatedAt": "2026-09-03" },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// echo-worker.mjs — deterministic test delegate for bullswarm.
|
|
2
2
|
// Reads a task file; behavior is driven by directives in the task text.
|
|
3
3
|
// FAIL:auth -> prints an auth failure, exits 0 (the lying-exit trap)
|
|
4
|
+
// FAIL:quota -> prints a provider usage limit naming its reset, exits 0
|
|
4
5
|
// FAIL:exit -> prints a complete answer, exits 1 (exit-1-after-success)
|
|
5
6
|
// INTENT: -> prints only an announcement, exits 0
|
|
6
7
|
// otherwise -> echoes the task as a completed answer, exit 0
|
|
@@ -11,6 +12,11 @@ const task = readFileSync(process.argv[2], 'utf8');
|
|
|
11
12
|
const sleepMatch = task.match(/SLEEP_MS:(\d+)/);
|
|
12
13
|
if (sleepMatch) await new Promise((resolve) => setTimeout(resolve, Number(sleepMatch[1])));
|
|
13
14
|
|
|
15
|
+
if (task.includes('FAIL:quota')) {
|
|
16
|
+
// A usage limit is not a broken credential: it names when it resets.
|
|
17
|
+
console.log('Error: usage limit reached · resets in 45 minutes');
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
14
20
|
if (task.includes('FAIL:auth-hang')) {
|
|
15
21
|
console.log('Authentication failed: quota exhausted; waiting process should be terminated.');
|
|
16
22
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|