Skip to content

Swarm: second provider family (Gemini) behind the same CLI - #15

Merged
Joe975 merged 3 commits into
mainfrom
claude/gemini-api-outsourcing-1tqdnm
Aug 15, 2026
Merged

Swarm: second provider family (Gemini) behind the same CLI#15
Joe975 merged 3 commits into
mainfrom
claude/gemini-api-outsourcing-1tqdnm

Conversation

@Joe975

@Joe975 Joe975 commented Aug 15, 2026

Copy link
Copy Markdown
Owner

The swarm tool talked only to the OpenAI Responses API. A Gemini key is now
available, and the reason to wire it in is not redundancy or price — the two
floor tiers are within 25% of each other — it is that docs/CYCLE.md step 4
wants skeptic re-implementations written by a different implementation, and
a different model family is the strongest version of that available cheaply.

scripts/swarm.py grows a Provider layer: each class translates the same four
job knobs (model, prompt, effort, token cap) into one API's dialect and reads
back text, normalized {input,output}_tokens usage, and a reason-string when
the response came back short. Nothing outside the layer knows which API is in
use; a third provider is a class plus a PROVIDERS row.

Provider is inferred from the model name (gemini-/gemma- -> gemini, else
openai, so an OpenAI-compatible proxy's model name keeps working); --provider
overrides. --effort maps straight onto Gemini's thinkingLevel under the same
four names, so no translation table can drift.

Two Gemini specifics that would silently corrupt records if missed, both
pinned by tests: thought-summary parts are dropped from the response text, and
thinking tokens are billed at the output rate so they are folded into the
output bucket rather than dropped from the cost estimate. Truncation
(finishReason MAX_TOKENS) fails the job exactly as OpenAI's incomplete does

  • a truncated draft is worse than a retry. 503 "high demand" is routine on the
    Gemini side and is absorbed by the existing retry ladder.

Verified live end to end: plan -> run -> resume (skips paid work) -> status,
with the provider recorded in each job's meta. 230 tests pass.

docs/SWARM.md gains the provider table and the rule that follows from it: the
family that drafted a claim stays off that claim's verification, and a record
leaning on both must say which did what.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01FPhAGm1qhBoCYYiMFAjziD

claude added 3 commits August 15, 2026 14:56
The swarm tool talked only to the OpenAI Responses API. A Gemini key is now
available, and the reason to wire it in is not redundancy or price — the two
floor tiers are within 25% of each other — it is that docs/CYCLE.md step 4
wants skeptic re-implementations written by a *different* implementation, and
a different model family is the strongest version of that available cheaply.

scripts/swarm.py grows a Provider layer: each class translates the same four
job knobs (model, prompt, effort, token cap) into one API's dialect and reads
back text, normalized {input,output}_tokens usage, and a reason-string when
the response came back short. Nothing outside the layer knows which API is in
use; a third provider is a class plus a PROVIDERS row.

Provider is inferred from the model name (gemini-*/gemma-* -> gemini, else
openai, so an OpenAI-compatible proxy's model name keeps working); --provider
overrides. --effort maps straight onto Gemini's thinkingLevel under the same
four names, so no translation table can drift.

Two Gemini specifics that would silently corrupt records if missed, both
pinned by tests: thought-summary parts are dropped from the response text, and
thinking tokens are billed at the output rate so they are folded into the
output bucket rather than dropped from the cost estimate. Truncation
(finishReason MAX_TOKENS) fails the job exactly as OpenAI's `incomplete` does
- a truncated draft is worse than a retry. 503 "high demand" is routine on the
Gemini side and is absorbed by the existing retry ladder.

Verified live end to end: plan -> run -> resume (skips paid work) -> status,
with the provider recorded in each job's meta. 230 tests pass.

docs/SWARM.md gains the provider table and the rule that follows from it: the
family that drafted a claim stays off that claim's verification, and a record
leaning on both must say which did what.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FPhAGm1qhBoCYYiMFAjziD
Three defects the first cross-family sweep exposed, all of which fail quietly
in the direction that matters most -- a verification pass that looks done but
is not what it claims.

DEFAULT_GEMINI_MODEL was dead code. `--provider gemini` with no `--model` fell
through to the OpenAI default, so a sweep launched as a cross-family skeptic
pass silently ran on the same family it was meant to be independent of, and the
only trace was one line of stdout. resolve_target() now derives (provider,
model) from whichever of the two the caller actually gave, and the test pins
the gemini-with-no-model case specifically.

The backoff ladder ignored Google's retry hint. OpenAI throttles via a
`Retry-After` header; Google sends nothing in the headers and puts the wait in
a google.rpc.RetryInfo in the error body. A free-tier key's quota window is 30s
-- longer than the whole 2/4/8/16 ladder -- so every throttled job burned all
five attempts and died. retry_hint_seconds() reads both channels, rounds
fractional delays up, and is capped at 60s: a job stuck behind a multi-minute
quota should fail and be resumed, not hold a worker slot.

The Gemini default is now gemini-3.7-flash, the current Flash release
(2026-08-13). It is the tier tuned for coding and multi-step agent work, which
is what a skeptic re-implementation brief actually asks for, and $0.75/$3.75 is
introductory pricing through 2026-12-31 -- docs/SWARM.md notes the date it
doubles. gemini-3.1-flash-lite stays documented as the floor tier for breadth
work returning prose rather than programs.

docs/SWARM.md also records the free-tier symptom explicitly, because the fix is
enabling billing rather than adding retries, and the 429 body says so in a
place that is easy to miss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FPhAGm1qhBoCYYiMFAjziD
001's one nonstandard lead asked for dominator trees, minimum cuts and
treewidth on the truncated Collatz digraph G_B for B = 2^12..2^24, with the
falsifiable dichotomy "interface bounded vs growing". It resolves degenerately,
and the reason is one paragraph rather than one cycle of computation: the
Collatz map is a function, so G_B has out-degree one everywhere, so it is a
forest plus the 1->4->2->1 triangle. Every invariant the lead proposed is fixed
before any arithmetic is consulted.

- Dominator tree IS the orbit tree: idom(v) = T(v), zero mismatches to B = 2^18
  under a real Cooper-Harvey-Kennedy computation rather than by assertion.
- Treewidth is exactly 2 for every B, so "track growth in B" has nothing to
  track, and the flow-cutter tooling never needs building.
- Minimum cut has the closed form |S_k| = (2^{k-1} - (-1)^{k-1})/3 = J_{k-1},
  ~ 2^k/6, decided by the single inequality 3r+1 > 2^{k+1} -- magnitude, no
  dynamics -- with B dropping out of the cut entirely.

Keeping the arithmetic labels, as 001 instructed, shows nothing: the cut is an
interval of odd integers, so it is uniform mod 3 by construction (233,017 each
at k = 22).

Verified three independent ways past the census itself: unit-capacity Dinic
max-flow on the explicit graph (k <= 12), and three gemini-3.7-flash workers
given only the definitions under three different stances (k <= 14, unanimous).
This is the first use of the cross-family skeptic rule -- the census was
written by the session model, so its verification went to the other family --
and it paid: one worker returned a cleaner proof than the census was built on,
showing crossing candidates above 2^k have in-degree zero outright. That
argument is adopted in the record. The escape fraction quoted as a by-product
was separately re-derived by unmemoized brute force.

The novelty pre-step (001 gap 2) is discharged: no dominator/treewidth Collatz
work found, but the inverted-graph-is-a-tree fact is classical, which explains
the empty literature better than novelty does. Literature remains [T]-grade --
web search, no PDFs -- and the record says so.

The collapse argument generalizes to any iterated map, so it prices the whole
graph-decomposition family, not just this lead; recorded as the mechanism tag
functional-graph-invariants and as a dead-end entry. One live lead survives:
the escape fraction #{n <= 2^k : orbit > 2^{k+1}}/2^k is non-monotone -- 0.609
at k = 12, 0.379 at k = 13, then flat near 0.404 through k = 22 -- and is
unexplained.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FPhAGm1qhBoCYYiMFAjziD
@Joe975
Joe975 merged commit 0bb4aff into main Aug 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants