oxedyne/daimond/dev/verify_slots.mjs
6.4 KiB, 1 run
created by r2519314175:681, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | // verify_slots.mjs — parallel workers each run on their OWN minted key. |
| 2 | // |
| 3 | // The overspend the multi-key work fixes is caused by parallel workers SHARING |
| 4 | // one spend-capped key: their concurrent requests race the host's stale cap |
| 5 | // check and overshoot it. The fix is a key per concurrent slot. This proves the |
| 6 | // CLIENT half end to end: a conductor that dispatches several workers makes the |
| 7 | // gateway mint a DISTINCT slot per worker, and each worker's real provider |
| 8 | // request carries its OWN slot key — never a shared one, never the chat's. |
| 9 | // |
| 10 | // The gateway is not run; its /api/inference-key is fetch-stubbed to hand back a key |
| 11 | // keyed to the slot in the request body, exactly as the real one now keys by slot. The |
| 12 | // provider endpoint is stubbed to record which bearer key each request used. Everything |
| 13 | // else is the real wasm, the real models.js and the real daimond.js Workers pool. Needs |
| 14 | // dev/serve.mjs (DAIMOND_PORT, default 8777) and dev/mockllm.mjs (DAIMOND_MOCK_PORT, |
| 15 | // default 9099). |
| 16 | import { open, signInAs, shot, MOCK } from './harness.mjs'; |
| 17 | |
| 18 | const CORS = { 'access-control-allow-origin': '*', 'access-control-allow-headers': '*' }; |
| 19 | const json = (body, status = 200) => ({ status, contentType: 'application/json', headers: CORS, body: JSON.stringify(body) }); |
| 20 | const OR_BASE = 'https://openrouter.ai/api/v1'; |
| 21 | const OR_URL = `${OR_BASE}/chat/completions`; |
| 22 | const FLOAT = 200; |
| 23 | const WORKER_SAYS = /You are a worker agent dispatched/; |
| 24 | // A key whose slot is legible in a haystack. |
| 25 | const keyForSlot = (slot) => `sk-or-v1-SLOT${slot}-zqxwmarker000000000000000000000000000000`; |
| 26 | const slotOf = (auth) => { const m = /SLOT(\d+)-/.exec(auth || ''); return m ? Number(m[1]) : null; }; |
| 27 | |
| 28 | const ok = [], bad = []; |
| 29 | const check = (name, pass, detail) => { |
| 30 | (pass ? ok : bad).push(name); |
| 31 | console.log((pass ? ' ok ' : ' FAIL ') + name + (detail ? ' — ' + detail : '')); |
| 32 | }; |
| 33 | |
| 34 | const gw = { bal: 2000, mintedSlots: [], providerCalls: [] }; |
| 35 | |
| 36 | async function stubGateway(page) { |
| 37 | await page.route('**/api/account', r => r.fulfill(json({ ok: true }))); |
| 38 | await page.route('**/api/auth/challenge', r => r.fulfill(json({ ok: true, challenge: 'chal-zqxw', challenge_id: 'cid-1' }))); |
| 39 | await page.route('**/api/auth/verify', r => r.fulfill(json({ ok: true }))); |
| 40 | await page.route('**/api/balance', r => r.fulfill(json({ ok: true, credits_minor: gw.bal, currency: 'usd', entries: [] }))); |
| 41 | |
| 42 | // The contract under test: the body names a slot, and the key handed back is |
| 43 | // that slot's own. The real gateway does exactly this. |
| 44 | await page.route('**/api/inference-key', r => { |
| 45 | let slot = 0; |
| 46 | try { slot = (JSON.parse(r.request().postData() || '{}').slot) | 0; } catch (e) { slot = 0; } |
| 47 | gw.mintedSlots.push(slot); |
| 48 | return r.fulfill(json({ |
| 49 | ok: true, key: keyForSlot(slot), url: OR_BASE, |
| 50 | limit_minor: Math.min(FLOAT, gw.bal), credits_minor: gw.bal, currency: 'usd', |
| 51 | })); |
| 52 | }); |
| 53 | |
| 54 | await page.route('https://openrouter.ai/api/v1/models', |
| 55 | r => r.fulfill(json({ data: [{ id: 'anthropic/claude-opus-4.5' }, { id: 'openai/gpt-5.2' }] }))); |
| 56 | |
| 57 | // The provider the browser talks to directly. Record the bearer key and |
| 58 | // whether the caller was a worker, then let the mock actually answer. |
| 59 | await page.route(OR_URL, async (r) => { |
| 60 | const auth = r.request().headers()['authorization'] || ''; |
| 61 | const sent = r.request().postData() || ''; |
| 62 | gw.providerCalls.push({ slot: slotOf(auth), worker: WORKER_SAYS.test(sent) }); |
| 63 | const res = await fetch(MOCK, { method: 'POST', headers: { 'content-type': 'application/json' }, body: sent }); |
| 64 | const body = await res.text(); |
| 65 | return r.fulfill({ status: res.status, headers: CORS, contentType: res.headers.get('content-type') || 'application/json', body }); |
| 66 | }); |
| 67 | } |
| 68 | |
| 69 | const s = await open({ name: 'slots', signIn: false, connect: false }); |
| 70 | const { page } = s; |
| 71 | await stubGateway(page); |
| 72 | await signInAs(s, 'slots'); |
| 73 | await page.waitForTimeout(2500); // unlock → bootstrap → mint slot 0 → list catalogue |
| 74 | |
| 75 | // Start new chats and Diamonds on credits, so the conductor and its workers all run |
| 76 | // on the minted key path (slot 0 for the chat/conductor, ≥1 for workers). |
| 77 | await page.evaluate(() => window.DaimondModels.setDefault('credits', 'anthropic/claude-opus-4.5')); |
| 78 | |
| 79 | check('unlock minted slot 0 (the chat/conductor key)', gw.mintedSlots.includes(0), 'slots ' + JSON.stringify(gw.mintedSlots)); |
| 80 | |
| 81 | // A Diamond, and a conductor turn that dispatches three workers at once. |
| 82 | await page.click('#new-diamond-btn'); |
| 83 | await page.waitForSelector('.dlg-input', { timeout: 8000 }); |
| 84 | await page.fill('.dlg-input', 'Audit'); |
| 85 | await page.click('.dlg-ok'); |
| 86 | await page.waitForSelector('#chat-input', { timeout: 10000 }); |
| 87 | await page.waitForTimeout(400); |
| 88 | const steer = '@tools spawn_agent {"name":"a","task":"inspect one"} ;; ' |
| 89 | + 'spawn_agent {"name":"b","task":"inspect two"} ;; ' |
| 90 | + 'spawn_agent {"name":"c","task":"inspect three"}'; |
| 91 | await page.fill('#chat-input', steer); |
| 92 | await page.click('#chat-send'); |
| 93 | |
| 94 | // Wait for all three workers to finish (Workers.active back to 0). |
| 95 | const until = async (fn, ms = 25000) => { |
| 96 | const t0 = Date.now(); |
| 97 | for (;;) { try { if (await page.evaluate(fn)) return true; } catch (e) {} if (Date.now() - t0 > ms) return false; await new Promise(r => setTimeout(r, 150)); } |
| 98 | }; |
| 99 | await until(() => gw.__done, 100).catch(() => {}); |
| 100 | await page.waitForTimeout(6000); // let the fan-out run against the mock |
| 101 | |
| 102 | // ── The assertions ──────────────────────────────────────────────── |
| 103 | const workerSlots = gw.mintedSlots.filter(x => x >= 1); |
| 104 | const uniqWorker = Array.from(new Set(workerSlots)); |
| 105 | check('three workers minted three distinct worker slots', |
| 106 | uniqWorker.length >= 3 && workerSlots.length === uniqWorker.length, |
| 107 | 'minted slots ' + JSON.stringify(gw.mintedSlots)); |
| 108 | check('no worker used slot 0 (the chat/conductor key)', |
| 109 | !gw.providerCalls.some(c => c.worker && c.slot === 0), |
| 110 | JSON.stringify(gw.providerCalls)); |
| 111 | |
| 112 | const workerCallSlots = gw.providerCalls.filter(c => c.worker).map(c => c.slot); |
| 113 | const uniqCallSlots = Array.from(new Set(workerCallSlots)); |
| 114 | check('each worker request carried its OWN distinct slot key', |
| 115 | workerCallSlots.length >= 3 && uniqCallSlots.length === workerCallSlots.length, |
| 116 | 'worker call slots ' + JSON.stringify(workerCallSlots)); |
| 117 | |
| 118 | await shot(s, 'slots'); |
| 119 | await s.close(); |
| 120 | console.log('\nminted slots: ' + JSON.stringify(gw.mintedSlots)); |
| 121 | console.log('provider calls: ' + JSON.stringify(gw.providerCalls)); |
| 122 | console.log(ok.length + ' ok, ' + bad.length + ' failed'); |
| 123 | process.exit(bad.length ? 1 : 0); |