Skip to content

feat(queen): endpoint pools and a worker ceiling of 1024, onto the branch production builds - #485

Merged
gHashTag merged 4 commits into
fix/queen-worker-provider-and-prompt-sizefrom
ship/pools-and-ceiling
Sep 17, 2026
Merged

gHashTag merged 4 commits into
fix/queen-worker-provider-and-prompt-sizefrom
ship/pools-and-ceiling

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Railway's trios-agent-server deploys from fix/queen-worker-provider-and-prompt-size (confirmed against the Railway API: repoTriggers.branch, root trios/agent-server). #484 and the ceiling commit landed on feat/queen-supervisor, which production does not build. This carries the same four commits here so the change reaches the running container.

Cherry-picked, unmodified:

Verified on this branch

  • bun test tests/api/queen-dispatch.test.ts: 82 pass, 0 fail.
  • The two Swift copies of QueenDelegation.swift are byte-identical.
  • grep "parsed, 16" over the three policy sources returns nothing.
  • The compiled policy answers: unset -> 4, 64 -> 64, 5000 -> 1024, unparseable -> 4. The default did not move.

Pre-existing on this branch, not introduced here

bun run typecheck reports two errors in queen-tick.ts (2197, 2202). They are present on 0e37000d8 before any of these commits; this branch is behind the mainline where that was fixed.

Not done here

TRIOS_QUEEN_MAX_WORKERS is not changed. 1024 is a bound against a typo; the working value is chosen by measurement.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

🤖 Generated with Claude Code

dmitrii-f-t27 and others added 4 commits September 17, 2026 18:07
…URL was the whole pool

Measured on 2026-09-17 in production: ten working Z.ai keys carried sixteen
bees while three working NVIDIA keys sat unused beside them. A key handed to a
bee is only as good as the URL the bee sends it to, and the deployment has
exactly one: TRIOS_QUEEN_WORKER_BASE_URL, one model, every generic key sent
there. Putting an NVIDIA key into TRIOS_QUEEN_WORKER_API_KEY_n would not widen
the swarm, it would hand a bee a 401 that arrives blamed on the work.

So there are now numbered endpoint pools. The FIRST pool is the variables that
already exist, unchanged in name and meaning. Further pools start at 2:

  TRIOS_QUEEN_WORKER_POOL_<n>_BASE_URL   the endpoint (required)
  TRIOS_QUEEN_WORKER_POOL_<n>_MODEL      the model that endpoint serves (required)
  TRIOS_QUEEN_WORKER_POOL_<n>_PROVIDER   openai-compatible (default) or zai
  TRIOS_QUEEN_WORKER_POOL_<n>_CONTEXT    that model's context window
  TRIOS_QUEEN_WORKER_POOL_<n>_API_KEY, _API_KEY_2 ... _API_KEY_16

What travels to /chat - provider, base URL, model, context window - comes from
the same pool as the key. One allocator runs over the concatenated list, so a
wave of bees takes one credential of every pool before any key carries a second
lane: the rule availableKeyIndex already applied inside one pool.

queen_dispatch.key_index is one integer, read back every tick to learn which
credentials are busy. First-pool keys keep the index they have always had, so
rows in flight across the deploy still mean the same key. A key of pool n is
(n - 1) * POOL_KEY_STRIDE + position (pool 2 starts at 1000). The pool NUMBER
is used rather than its rank among today's valid pools, so disconnecting pool 2
does not rename every busy key of pool 3.

Deliberately not changed:
- A single endpoint takes the old code path byte for byte; every existing test
  passes untouched (66 before, 78 after).
- The closed breakdown (browseros-ai#1308) stays three integers. Lanes per credential stay
  one number for the deployment, which keeps it an exact statement:
  credentials x lanes, bounded by the policy ceiling. No pool name, URL or
  variable name enters it.
- An explicit endpoint stays authoritative, including its refusal: a valid
  second pool does not take over from a first pool with no key.
- A local Ollama stays one measured inference slot and reads no pools.
- The model is required per pool and never inherited: the first pool's model
  name sent to another provider is a 404.
- One secret named by two pools is one credential (browseros-ai#1293).

A pool someone began to configure and dispatch ignored reads as configured in a
variable editor and supplies nothing. endpointPoolProblems() names the missing
variable (names only, never a value), and the "every key is busy" refusal
carries it, because that is the moment an operator asks why the swarm is
narrower than the variables suggest.

The dispatch detail printed `key ${keyIndex + 1}`; with a durable index of 1002
that would read "key 1003/3". It now prints the pool and the position in it.

Applies cleanly to fix/queen-worker-provider-and-prompt-size (the branch
production deploys from) as well as to feat/queen-supervisor.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…here a loop ended

keysFor() read the unsuffixed variable and then _2 ... _16. Sixteen was never a
measurement: it is where the loop happened to stop, and it equals the policy
ceiling on bees only by coincidence. They are different quantities. The ceiling
bounds how many bees RUN. The key list bounds how many credentials the rotation
may SPREAD them over - and a free key refuses its third concurrent request in
under half a second (1302), so a swarm at the ceiling wants more keys than
bees, not the same number.

A TRIOS_QUEEN_WORKER_API_KEY_17 was therefore read by nothing and reported by
nothing: it looks configured in a variable editor and supplies nothing, the
zero-length-key trap one step to the right.

The suffix now runs to MAX_KEYS_PER_POOL = 1000, for every pool and for the
legacy provider variables alike (they share keysFor). Widening the list does
not widen the swarm: queenWorkerLimit() still answers at most 16, and a test
pins seventeen credentials to a capacity of sixteen.

POOL_KEY_STRIDE moves from 1000 to 10000 with it. The durable index of pool n
starts at (n - 1) * stride, so a pool that could hold `stride` keys would have
its last key collide with the next pool's first. Nothing has been written with
the old stride - it exists only in this pull request - and a test now holds
MAX_KEYS_PER_POOL below POOL_KEY_STRIDE so the two cannot drift.

Dispatch tests: 81 pass (78 before this commit). Typecheck clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…g of 1024

MAX_KEYS_PER_POOL becomes 1024. With one lane per credential a swarm of N bees
needs N keys, so a key bound under the worker bound is a second, hidden ceiling
that reports nothing when it is hit. The operator is asking for the policy
ceiling to be raised to 1024; a round thousand would have been that hidden
ceiling the day it was. The worker ceiling itself is NOT changed here - it is a
policy with a Swift mirror, and raising it is a separate, deliberate decision.

Dispatch tests: 81 pass. Typecheck clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s deployment

The policy clamped TRIOS_QUEEN_MAX_WORKERS to 16 in three places. Sixteen was
not a measurement of this deployment: it is where the number happened to be
written when the swarm had one endpoint. Once a deployment could connect a
second provider's endpoint and its keys, that clamp sat BELOW the credentials
already paid for - and a clamp says nothing when it clamps, so the capacity a
swarm did not get was reported by no line anywhere.

The bound moves to 1024, which is a guard against a typo rather than a working
value. What a deployment runs is decided by connected credentials times lanes
per credential, and by the number the operator sets. "Review cost is linear in
running workers" is still true and is exactly why that number is chosen by
measurement - raised in steps until container memory, worktree disk, the
remaining GitHub API quota or the review backlog is the thing that binds. That
is a reason for the value in the environment, not for a constant in code.

The three copies move together in this one commit, because the failure this
number already had was drift: the TypeScript side was raised alone once and the
swarm reported `capacity: 12` while every tick refused at "limit 4".

The default is untouched. Unset, unreadable or below one still means four.
Verified against the compiled policy rather than the source: unset -> 4,
64 -> 64, 5000 -> 1024, unparseable -> 4; and on the dispatch side seventeen
credentials under a ceiling of 64 now answer 17 instead of 16.

- rings/SR-00/QueenDelegation.swift
- agent-server/queen-core/Sources/QueenPolicy/QueenDelegation.swift (byte-identical)
- agent-server/apps/server/src/api/services/queen-dispatch.ts

queen-core-sync reports QueenDelegation.swift in sync, queen-core compiles,
ring00_parity is green (it pins the default of 4, which did not move), and
queen-dispatch.test.ts is 82 pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gHashTag
gHashTag merged commit d513a72 into fix/queen-worker-provider-and-prompt-size Sep 17, 2026
17 of 20 checks passed
@github-actions

Copy link
Copy Markdown

❌ Tests failed — 7/2144 failed

Suite Passed Failed Skipped
✅ agent 87/87 0 0
✅ build 9/9 0 0
✅ cdp-protocol 5/5 0 0
✅ eval 93/93 0 0
✅ server-agent 272/272 0 0
❌ server-api 992/1030 4 34
✅ server-browser 6/6 0 0
✅ server-integration 10/11 0 1
✅ server-lib 273/273 0 0
✅ server-pglive 3/3 0 0
✅ server-root 68/68 0 0
✅ server-skills 31/31 0 0
❌ server-tools 239/242 3 0
✅ shared 14/14 0 0
Failed tests
  • server-api — witnessVerdicts, the measurement as verdict lines > emits three met lines for a clean file
  • server-api — witnessVerdicts, the measurement as verdict lines > holds a new file that fails typecheck as a regression
  • server-api — route-guard audit over src/api/server.ts > sees the full route table
  • server-api — route-guard audit over src/api/server.ts > splits the nineteen /queen mounts into 7 public-read, 7 wrapper-guarded and 5 allowlisted shells
  • server-tools — navigation tools > new_hidden_page opens a hidden tab
  • server-tools — navigation tools > show_page restores a hidden page to visible
  • server-tools — window tools > create_hidden_window creates and closes a hidden window

View workflow run

@github-actions
github-actions Bot deleted the ship/pools-and-ceiling branch September 20, 2026 04:22
@gHashTag
gHashTag restored the ship/pools-and-ceiling branch September 28, 2026 12:25
@gHashTag
gHashTag deleted the ship/pools-and-ceiling branch October 8, 2026 18:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants