Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion trios/agent-server/apps/server/src/api/routes/queen-lease.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,20 @@
* transport they have. One lease, one name, two kinds of client.
*/

import { createHash, timingSafeEqual } from 'node:crypto'
import { Hono } from 'hono'
import type { Pool } from 'pg'
import { createQueenPool } from '../../lib/db/queen-pool'
import { leased, vault, zaiLeaseCall } from '../services/queen-free-lane'
import * as KV from '../services/queen-key-vault-card.gen'
import {
acquireQueenLease,
queenLeaseDatabaseUrl,
queenLeaseStatus,
releaseQueenLease,
} from '../services/queen-lease'
import { runQueenTickOnce } from '../services/queen-tick'
import { zaiLeaseLanes } from '../services/queen-reviewer'
import { runningKeys, runQueenTickOnce } from '../services/queen-tick'

const LEASE_NAME = 'queen-tick'

Expand Down Expand Up @@ -174,3 +178,38 @@ export function createQueenLeaseRoute() {
})
)
}

/** What a lease forwards of the caller's request: never its token. */
const ZAI_HEADERS = {
'content-type': 'application/json',
'anthropic-version': '2023-06-01',
}
/** The Mac reviewer's z.ai calls, made here so no key leaves the Queen. */
export function createQueenZaiLeaseRoute() {
return new Hono().all('/*', async (c) => {
const token = process.env.TRIOS_QUEEN_REVIEW_LEASE_TOKEN ?? ''
const sha = (s: string) => createHash('sha256').update(s).digest()
if (token.length < 32) return c.json({ error: 'lease_off' }, 503)
const given = sha(c.req.header('authorization') ?? '')
if (!timingSafeEqual(given, sha(`Bearer ${token}`)))
return c.json({ error: 'forbidden' }, 403)
const url = queenLeaseDatabaseUrl()
const taken = url ? await runningKeys(poolForTick(url)) : []
const lanes = zaiLeaseLanes(taken, leased)
const total = zaiLeaseLanes([], leased).length + leased.size
const n = leased.size
const ask = [KV.LEASE_REVIEW, KV.SRC_STORE, n, lanes.length, total, n, 1]
const answer = vault('lease_answer', ...ask)
const path = c.req.url.replace(/^.*?\/zai-lease/, '')
const body = c.req.method === 'GET' ? undefined : await c.req.arrayBuffer()
const init = { method: c.req.method, headers: ZAI_HEADERS, body }
const res =
answer === KV.LA_GRANT && (await zaiLeaseCall(lanes, path, init))
if (res) return res
const refused = answer === KV.LA_REFUSE
const wait = vault('retry_after_seconds', refused ? answer : KV.LA_WAIT)
c.header('retry-after', String(wait))
const error = { type: 'rate_limit_error', message: 'no z.ai lane free' }
return c.json({ type: 'error', error }, refused ? 403 : 429)
})
}
7 changes: 6 additions & 1 deletion trios/agent-server/apps/server/src/api/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ import {
createQueenKanbanRoute,
createQueenPublicBoardRoute,
} from './routes/queen-kanban'
import { createQueenLeaseRoute } from './routes/queen-lease'
import {
createQueenLeaseRoute,
createQueenZaiLeaseRoute,
} from './routes/queen-lease'
import { createQueenNeedsYouRoute } from './routes/queen-needs-you'
import { createQueenPublicActivityRoute } from './routes/queen-public-activity'
import { createQueenPublicActorsRoute } from './routes/queen-public-actors'
Expand Down Expand Up @@ -502,6 +505,8 @@ export async function createHttpServer(config: HttpServerConfig) {
.route('/queen/public-earnings', createQueenPublicEarningsRoute())
// Separate server-to-server capability; never a public-read or operator-token route.
.route('/queen/contributor-keys', createQueenContributorKeysRoute())
// The Mac reviewer's z.ai lease (specs/queen/key_vault.t27): its own token.
.route('/queen/zai-lease', createQueenZaiLeaseRoute())
// The vault (gHashTag/trios#1759): every request is Ed25519-signed and
// judged by specs/vault/policy.t27 request_code; no browser Origin, so no
// trusted-origin guard. 503 for everything unless TRIOS_VAULT=on.
Expand Down
40 changes: 40 additions & 0 deletions trios/agent-server/apps/server/src/api/services/queen-free-lane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

import type { Pool } from 'pg'
import type { AppLlm } from './queen-app'
import { loadCardWasm } from './queen-card-wasm'
import { reviewLaneCandidates, type WorkerProvider } from './queen-dispatch'
import * as KV from './queen-key-vault-card.gen'
import {
chooseReviewerLane,
defaultReviewerLlm,
Expand Down Expand Up @@ -72,3 +74,41 @@ export function freeLaneLlm(
return { ok: false, error: last, transient: true }
}
}

/** Lease decisions are key_vault.t27's; `leased` is the z.ai keys out now. */
export const vault = (fn: string, ...args: number[]) =>
loadCardWasm('queen/key_vault.wasm').call(fn, ...args)
export const leased = new Map<string, symbol>()

/** One leased request: a lane makes it, a refused lane hands it on. */
export async function zaiLeaseCall(
lanes: WorkerProvider[],
path: string,
init: RequestInit & { headers: Record<string, string> },
) {
let last: Response | null = null
for (const [i, lane] of lanes.slice(0, KV.LEASE_TRIES).entries()) {
const key = reviewerLaneKey(lane)
const id = Symbol()
const free = () => leased.get(key) === id && leased.delete(key)
leased.set(key, id)
setTimeout(free, KV.LEASE_SECONDS * 1000)
const res = await fetch(`https://api.z.ai/api/anthropic${path}`, {
...init,
headers: { ...init.headers, authorization: `Bearer ${lane.apiKey}` },
signal: AbortSignal.timeout(KV.LEASE_SECONDS * 1000),
}).catch(() => null)
const headers = { 'content-type': res?.headers.get('content-type') ?? '' }
if (res?.ok && res.body) {
const done = new TransformStream({ flush: () => void free() })
return new Response(res.body.pipeThrough(done), { headers })
}
free()
const text = (await res?.text().catch(() => '')) ?? ''
const code = Number(/"code"\s*:\s*"?(\d+)/.exec(text)?.[1] ?? 0)
last = res && new Response(text, { status: res.status, headers })
if (vault('lease_step', res?.status ?? 0, code, i + 1) === KV.LS_ANSWER)
break
}
return last
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Generated by `t27c gen-ts` from key_vault.t27. Do not edit.
//
// Every name, value and type here comes from that spec. Change the spec and
// regenerate; an edit made here is lost the next time anyone builds.

export const SRC_STORE = 0 satisfies number;
export const SRC_PRIVATE = 1 satisfies number;
// t27c gen-ts: fn may_serve was not emitted -- this backend lowers declarations, not bodies.
export const START_LEASE = 0 satisfies number;
export const START_OWN_KEYS = 1 satisfies number;
export const START_REFUSE = 2 satisfies number;
// t27c gen-ts: fn consumer_start was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn start_warns was not emitted -- this backend lowers declarations, not bodies.
export const LEASE_REVIEW = 0 satisfies number;
export const LEASE_WORKER = 1 satisfies number;
export const REVIEW_FLOOR_LANES = 2 satisfies number;
export const REVIEW_HOLDERS = 3 satisfies number;
// t27c gen-ts: fn lanes_of was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn review_share was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn worker_share was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn holder_cap was not emitted -- this backend lowers declarations, not bodies.
export const LA_GRANT = 0 satisfies number;
export const LA_WAIT = 1 satisfies number;
export const LA_REFUSE = 2 satisfies number;
// t27c gen-ts: fn lease_answer was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn retry_after_seconds was not emitted -- this backend lowers declarations, not bodies.
export const LEASE_SECONDS = 600 satisfies number;
export const LEASE_TRIES = 3 satisfies number;
export const LS_ANSWER = 0 satisfies number;
export const LS_NEXT_LANE = 1 satisfies number;
// t27c gen-ts: fn lease_step was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a InvariantBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a InvariantBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a InvariantBlock was not emitted -- it is checked by the compiler, not by the artifact.
export const COOL_BASE_SECONDS = 15 satisfies number;
export const KE_AUTH = 3 satisfies number;
export const KE_OK = 0 satisfies number;
export const KE_QUOTA = 2 satisfies number;
export const KE_REQUEST = 4 satisfies number;
export const KE_TRANSIENT = 1 satisfies number;
export const ZAI_OVERLOAD = 1305 satisfies number;
export const ZAI_RATE_LIMIT = 1302 satisfies number;
// t27c gen-ts: fn error_kind was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn is_quota_code was not emitted -- this backend lowers declarations, not bodies.
export const U32_MAX = 4294967295 satisfies number;
export const ZAI_REQUESTS_PER_KEY = 2 satisfies number;

// Declaration order, which the spec's own laws depend on.
export const __STRUCT_ORDER__ = [] as const;
export const __DECL_ORDER__ = ["SRC_STORE", "SRC_PRIVATE", "START_LEASE", "START_OWN_KEYS", "START_REFUSE", "LEASE_REVIEW", "LEASE_WORKER", "REVIEW_FLOOR_LANES", "REVIEW_HOLDERS", "LA_GRANT", "LA_WAIT", "LA_REFUSE", "LEASE_SECONDS", "LEASE_TRIES", "LS_ANSWER", "LS_NEXT_LANE", "COOL_BASE_SECONDS", "KE_AUTH", "KE_OK", "KE_QUOTA", "KE_REQUEST", "KE_TRANSIENT", "ZAI_OVERLOAD", "ZAI_RATE_LIMIT", "U32_MAX", "ZAI_REQUESTS_PER_KEY"] as const;

// What this spec holds and this backend did not print. Empty is the whole
// story most of the time; an entry here is a promise the artifact does not
// keep, and reading it is how a tool tells a partial module from a complete
// one without parsing comments.
//
// A LIST, not a map keyed by name. `specs/numeric/formats.t27` declares four
// separate consts called `result`, one per test block, and under an object
// literal three of the four omissions vanished into the fourth -- a record of
// what went missing that itself went missing. A spec is free to reuse a
// name; this file is not free to lose the second one.
export const __NOT_EMITTED__ = Object.freeze([] as const);
10 changes: 10 additions & 0 deletions trios/agent-server/apps/server/src/api/services/queen-reviewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,16 @@ export function reviewerLaneBackedOff(
return true
}

/** z.ai review lanes no bee, backoff or lease holds (key_vault.t27). */
export const zaiLeaseLanes = (taken: number[], busy: Map<string, symbol>) =>
reviewLaneCandidates(taken).filter(
(lane) =>
!!lane.apiKey &&
!!lane.baseUrl?.includes('api.z.ai') &&
!reviewerLaneBackedOff(lane) &&
!busy.has(reviewerLaneKey(lane)),
)

/** For suites: every lane is trusted again. */
export function forgetReviewerLaneFailures(): void {
failedLanes.clear()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ const report = auditServer(source, DEFAULT_ALLOWLIST)
// RE-MEASURED 2026-10-11, queen merged into vault-mvp (trios#1759): both
// joined, so the list is fourteen, recomputed with --no-allowlist on the
// merged server.ts.
// RE-MEASURED 2026-10-19: /queen/zai-lease joined (key_vault.t27), so fifteen.
// The Mac reviewer calls it with no Origin; its guard is its own lease token.
const EXPECTED_UNGUARDED_WITHOUT_ALLOWLIST = [
'/api/inngest',
'/hosting',
Expand All @@ -71,6 +73,7 @@ const EXPECTED_UNGUARDED_WITHOUT_ALLOWLIST = [
'/queen/roadmap',
'/queen/runner',
'/queen/tree',
'/queen/zai-lease',
'/vault',
]

Expand Down Expand Up @@ -199,7 +202,9 @@ describe('route-guard audit over src/api/server.ts', () => {
// tools/route-guard-audit.mjs, not copied. 66: /vault, /hosting and
// /queen/public-net-credits together; 18 prefix guards, 20 guarded
// sub-apps, 18 public-read.
expect(report.totalMounts).toBe(66)
// RE-MEASURED 2026-10-19, the key vault lease (key_vault.t27): 66 became 67
// with /queen/zai-lease, allowlisted with its own-token reason.
expect(report.totalMounts).toBe(67)
expect(report.prefixGuardCount).toBe(18)
expect(report.guardedSubAppCount).toBe(20)
expect(report.publicReadCount).toBe(18)
Expand All @@ -212,7 +217,7 @@ describe('route-guard audit over src/api/server.ts', () => {
expect(report.entriesMissingReason).toEqual([])
})

it('reports exactly the fourteen reasoned exceptions when the allowlist is dropped', () => {
it('reports exactly the fifteen reasoned exceptions when the allowlist is dropped', () => {
// The classifier reports mounts in file order; the assertion is on the
// exact set, so both sides are sorted before comparing.
expect([...unguardedMounts(source, [])].sort()).toEqual(
Expand Down Expand Up @@ -289,7 +294,9 @@ describe('route-guard audit over src/api/server.ts', () => {
// RE-MEASURED 2026-10-10, queen merged in: still forty, recomputed.
// RE-MEASURED 2026-10-10, the network job: forty became forty-one. The
// eighteenth public-read is /queen/public-net-credits.
expect(queenMounts.length).toBe(41)
// RE-MEASURED 2026-10-19: forty-one became forty-two. The eleventh
// allowlisted mount is /queen/zai-lease, behind its own lease token.
expect(queenMounts.length).toBe(42)

const counts: Record<string, number> = {
'public-read': 0,
Expand All @@ -306,7 +313,7 @@ describe('route-guard audit over src/api/server.ts', () => {
'public-read': 18,
'prefix-guard': 0,
wrapper: 13,
unguarded: 10,
unguarded: 11,
})

// Every unguarded /queen mount must be one of the allowlisted shells.
Expand Down
4 changes: 4 additions & 0 deletions trios/agent-server/specs/PIN
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,7 @@ claim: queen/claim.wasm sha256 08fc2b32d46742638c00d20fe1e64dd81289080dcfc8fa662
review_first card: gHashTag/t27 specs/queen/review_first.t27 (t27#10555, PR t27#10562), byte-identical; review_first.wasm = t27c gen-c + zig 0.16.0 cc --target=wasm32-wasi -Oz -DNDEBUG -mexec-model=reactor, exports every fn of the card: kind_of,in_review_queue,backlog_open,admission,admits,round_refused (reproducible: two builds, one hash); constants: t27c gen-ts > apps/server/src/api/services/queen-review-first-card.gen.ts
review_first: queen/review_first.t27 sha256 c0ec4028feccb9740ddd434f8a1ee8f4fce9b7a4ce2dd1664de504a0b5d06e88
review_first: queen/review_first.wasm sha256 6c9fbeca0bc9dc98122ee4dcc8cdf1ad0c37c659625422828281309875555f2f
key_vault card: gHashTag/t27 specs/queen/key_vault.t27 (t27#10564, PR t27#10567 head ae8bcbe6f, blob 341c272cb4b76382eecfe81ae901bf750458bba1), byte-identical; it imports error_kind and its codes from queen/key_failover.t27 (blob 3ce96bef2b149e03cfd5879491e448b8c8c5a9a8, vendored byte-identical, the same file trios#2045 vendors) and ZAI_REQUESTS_PER_KEY from queen/reviewer_sizing.t27 (already vendored), so gen-c compiles them in; key_vault.wasm = t27c 0.5.2 gen-c + zig 0.16.0 cc --target=wasm32-wasi -Oz -DNDEBUG -mexec-model=reactor, exports may_serve,consumer_start,start_warns,lanes_of,review_share,worker_share,holder_cap,lease_answer,retry_after_seconds,lease_step,error_kind (reproducible: two builds, one hash, 797 bytes); constants: t27c gen-ts > apps/server/src/api/services/queen-key-vault-card.gen.ts (sha256 666f3ae917f810d6be10cf1d8bec0e140a277f330201276f37d1cef290c3d341)
key_vault: queen/key_vault.t27 sha256 caa5c0913648ec6eb545c0544fe0d51e383c42f5b4617ae25db6f542f2fa4097
key_vault: queen/key_failover.t27 sha256 822367357fc6b487c1c7fb7ac8369165e6a7e6636fd9b0dcafec29e9a6274301
key_vault: queen/key_vault.wasm sha256 8eb18f8eb0d6ff7866c51b8771aeff69dae25db71254b557401332154e7bf20f
Loading
Loading