Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ pnpm demo
# Open http://127.0.0.1:4173 (or pnpm exec next dev --webpack --hostname 127.0.0.1 --port 4187 for a different port)
```

The root page compares parallel Codex CLI runs with full versus Jev-selected synthetic MCP tools. Choose one of four example cards, inspect its task, then explicitly run the comparison. Details open over the results in modal drawers. Save a personal TypeSafe key under **API key**; **Usage** tracks reported Jev usage. The host records proposed patches without applying them.
The root page compares parallel Codex CLI runs with full versus Jev-selected synthetic MCP tools. Choose one of four example cards, inspect its task, then explicitly run the comparison. Details open over the results in modal drawers. Save a personal TypeSafe key under **Settings → Jev API key**; **Usage** tracks reported Jev usage. The host records proposed patches without applying them.

Completed and interrupted comparisons are saved in this browser, up to 30 runs within 2 MB. **History** reopens evidence and compares input tokens or duration for matching tasks and harness setups, including Jev overhead. Unknown measurements remain unknown; a run is not a benchmark. The old `/arena` URL redirects to `/`; the Routing room and Example lab pages have been removed. See [the demo guide and browser verification](docs/routing-demo.md).

Expand Down
14 changes: 14 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -472,3 +472,17 @@ body:has(dialog[open]) { overflow: hidden; }
.detail-dialog .arena-answer { max-width: none; }
@media (hover: hover) { .detail-trigger:hover { color: var(--pink); } }
@media (max-width: 600px) { .detail-dialog-heading { padding: 18px; gap: 12px; } .detail-dialog-heading h2 { font-size: 20px; } .detail-dialog-body { padding: 20px 18px; } .run-inspector > .detail-trigger { padding: 18px; } .arena-method > .detail-trigger { min-height: 40px; } .lane-activity > .detail-trigger { padding-bottom: 6px; } .detail-dialog .inspector-tabs { display: grid; grid-template-columns: 1fr 1fr; } }

/* Settings keeps the manual key source explicit without revealing a credential. */
.settings-dialog { width: min(560px, 100%); }
.settings-dialog h3 { font-size: 18px; margin: 0 0 10px; }
.key-override-dot { display: inline-block; width: 6px; height: 6px; margin-left: 8px; border-radius: 50%; background: var(--pink); vertical-align: middle; }
.key-source-card { margin: 24px 0; padding: 18px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel); }
.key-source-card > span { display: block; font-size: 11px; color: var(--muted); }
.key-source-card strong { display: block; margin-top: 8px; font-size: 16px; font-weight: 500; }
.key-source-card.has-override strong { color: var(--pink); }
.key-source-card p { color: var(--muted); font-size: 13px; line-height: 1.8; margin: 10px 0 0; }
.settings-dialog .dialog-actions { flex-wrap: wrap; margin-top: 20px; gap: 10px; }
.key-message { font-size: 13px; line-height: 1.8; color: var(--muted); }
.key-error { color: var(--pink); }
.key-message:empty { display: none; }
33 changes: 25 additions & 8 deletions components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,43 @@
"use client";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import { readApiKey, saveApiKey } from "../examples/routing/api-key";
import { KEY_STORAGE, readApiKey, saveApiKey } from "../examples/routing/api-key";
import { clearUsage, getUsage, summarizeUsage, type UsageEntry } from "../examples/routing/usage";
export function Header() {
const keyDialog = useRef<HTMLDialogElement>(null), usageDialog = useRef<HTMLDialogElement>(null);
const [saved, setSaved] = useState(false), [draft, setDraft] = useState(""), [error, setError] = useState("");
const [saved, setSaved] = useState(false), [draft, setDraft] = useState(""), [error, setError] = useState(""), [notice, setNotice] = useState("");
const [entries, setEntries] = useState<UsageEntry[]>([]);
const total = summarizeUsage(entries);
useEffect(() => {
const syncKey = () => setSaved(Boolean(readApiKey()));
const syncUsage = () => setEntries([...getUsage()]);
const syncStoredKey = (event: StorageEvent) => { if (event.key === KEY_STORAGE || event.key === null) { syncKey(); setDraft(""); setError(""); setNotice(""); } };
syncKey(); syncUsage();
window.addEventListener("storage", syncKey); window.addEventListener("jev-key-change", syncKey); window.addEventListener("jev-usage-change", syncUsage);
return () => { window.removeEventListener("storage", syncKey); window.removeEventListener("jev-key-change", syncKey); window.removeEventListener("jev-usage-change", syncUsage); };
window.addEventListener("storage", syncStoredKey); window.addEventListener("jev-key-change", syncKey); window.addEventListener("jev-usage-change", syncUsage);
return () => { window.removeEventListener("storage", syncStoredKey); window.removeEventListener("jev-key-change", syncKey); window.removeEventListener("jev-usage-change", syncUsage); };
}, []);
function save(value: string) {
try { saveApiKey(value); setDraft(""); setError(""); setSaved(Boolean(value.trim())); window.dispatchEvent(new Event("jev-key-change")); return true; }
catch { setError("Could not save. Check the key format and browser storage permissions."); return false; }
try { saveApiKey(value); setDraft(""); setError(""); setSaved(Boolean(value.trim())); setNotice(value.trim() ? "Manual override saved. Your next comparison will use this key." : "Manual override removed. Your next comparison will use the server default if configured."); window.dispatchEvent(new Event("jev-key-change")); return true; }
catch { setNotice(""); setError("Could not update the override. Check the key format and browser storage permissions."); return false; }
}
return <><header className="masthead"><div className="header-bar"><Link className="wordmark" href="/" aria-label="Jev Harness agent arena">jev<span> / agent arena</span></Link><div className="header-actions"><button className="quiet" id="usage-open" onClick={() => usageDialog.current?.showModal()}>Usage{total.requests ? ` · ${total.requests}` : ""}</button><button className="quiet" id="key-settings" onClick={() => keyDialog.current?.showModal()}>API key{saved ? " · saved" : ""}</button></div></div></header>
<dialog ref={keyDialog} id="key-dialog" aria-labelledby="key-title" onClose={() => { setDraft(""); setError(""); }}><div className="dialog-heading"><h2 id="key-title">Your TypeSafe API key</h2><button className="quiet" aria-label="Close API key settings" onClick={() => keyDialog.current?.close()}>Close</button></div><p className="hint">{saved ? "A personal key is saved for this origin. It overrides the host's default." : "No personal key saved. Live requests use the host's default if configured."}</p><form onSubmit={event => { event.preventDefault(); if (draft.trim() && save(draft)) keyDialog.current?.close(); }}><label htmlFor="api-key">API key</label><input id="api-key" type="password" value={draft} onChange={event => setDraft(event.target.value)} autoComplete="off" autoCapitalize="none" spellCheck={false} maxLength={1024} required placeholder="Paste your TypeSafe API key" /><p className="hint">Saved unencrypted in this browser until removed. Masked on screen; sent only with live requests through this local host. The saved value is never displayed.</p><p role="alert" className="hint">{error}</p><div className="dialog-actions"><button className="primary" type="submit">Save key</button><button className="quiet" type="button" disabled={!saved} onClick={() => save("")}>Remove key</button></div></form></dialog>
return <><header className="masthead"><div className="header-bar"><Link className="wordmark" href="/" aria-label="Jev Harness agent arena">jev<span> / agent arena</span></Link><div className="header-actions"><button className="quiet" id="usage-open" onClick={() => usageDialog.current?.showModal()}>Usage{total.requests ? ` · ${total.requests}` : ""}</button><button className="quiet" id="key-settings" aria-haspopup="dialog" aria-controls="key-dialog" aria-label={saved ? "Settings, manual key override active" : "Settings"} onClick={() => keyDialog.current?.showModal()}>Settings{saved && <span className="key-override-dot" aria-hidden="true" />}</button></div></div></header>
<dialog ref={keyDialog} id="key-dialog" className="detail-dialog settings-dialog" aria-labelledby="key-title" onClose={() => { setDraft(""); setError(""); setNotice(""); }}>
<div className="detail-dialog-heading"><div><p className="eyebrow">Agent arena</p><h2 id="key-title">Settings</h2></div><button className="quiet" aria-label="Close settings" onClick={() => keyDialog.current?.close()} autoFocus>Close <span aria-hidden="true">×</span></button></div>
<div className="detail-dialog-body">
<section aria-labelledby="key-section-title">
<h3 id="key-section-title">Jev API key</h3>
<p className="hint">Set a manual TypeSafe API key override for comparisons in this browser.</p>
<div className={`key-source-card ${saved ? "has-override" : ""}`}><span>Active key source</span><strong>{saved ? "Manual override" : "Server default"}</strong><p>{saved ? "Your saved key takes priority over the server key. Replace it below or remove the override to return to the default." : "Uses the server key when configured. Save your own key below to override it."}</p></div>
<form onSubmit={event => { event.preventDefault(); if (draft.trim()) save(draft); }}>
<label htmlFor="api-key">{saved ? "Replacement API key" : "Override API key"}</label>
<input id="api-key" type="password" value={draft} onChange={event => setDraft(event.target.value)} aria-describedby="key-storage-note" autoComplete="off" autoCapitalize="none" spellCheck={false} maxLength={1024} required placeholder="Paste your TypeSafe API key" />
<p id="key-storage-note" className="hint">Stored unencrypted on this device for this origin. The saved key is never shown again or included in results. Only explicit live requests use it.</p>
<div className="dialog-actions"><button className="primary" type="submit" disabled={!draft.trim()}>{saved ? "Replace override" : "Save override"}</button><button className="quiet" type="button" disabled={!saved} onClick={() => save("")}>Remove override</button></div>
<p role="alert" className="key-message key-error">{error}</p><p role="status" className="key-message">{notice}</p>
</form>
</section>
</div>
</dialog>
<dialog ref={usageDialog} id="usage-dialog" aria-labelledby="usage-title"><div className="dialog-heading"><h2 id="usage-title">Usage &amp; budget</h2><button className="quiet" aria-label="Close usage dashboard" onClick={() => usageDialog.current?.close()}>Close</button></div><p className="hint">This tab's latest 200 live Jev requests · survives refresh. Account-wide quotas and balances are unavailable.</p><div className="usage-totals"><div><span>Requests</span><strong id="usage-requests">{total.requests}</strong></div><div><span>Reported input</span><strong id="usage-input">{total.input.toLocaleString()}</strong></div><div><span>Reported output</span><strong id="usage-output">{total.output.toLocaleString()}</strong></div></div><p id="usage-unknown" className="hint">{total.unknown ? `${total.unknown} requests have incomplete usage. Totals include reported tokens only.` : total.requests ? "All listed requests have reported token usage." : "Run a comparison to see Jev usage. Agent CLI usage is shown in each result."}</p><div className="usage-price"><span>Reported-input price estimate</span><strong>${(total.input * 42 / 1_000_000_000).toFixed(8)}</strong><p className="hint">At <a href="https://typesafe.ai/" target="_blank" rel="noopener noreferrer">$42 per billion input tokens</a> (checked Sep 22, 2026). Excludes output, unknown usage and account-specific pricing. Not an invoice.</p></div><details><summary>Request history</summary><div className="table-scroll"><table><caption>Provider-reported tokens. Missing usage stays unknown.</caption><thead><tr>{["Time", "Status", "Input", "Output", "Duration"].map(label => <th scope="col" key={label}>{label}</th>)}</tr></thead><tbody>{entries.map((entry, index) => <tr key={index}><td>{new Date(entry.at).toLocaleTimeString()}</td><td>{entry.status} · {entry.keySource} key</td><td>{entry.input ?? "Unknown"}</td><td>{entry.output ?? "Unknown"}</td><td>{entry.latencyMs === null ? "Unknown" : `${(entry.latencyMs / 1000).toFixed(2)} s`}</td></tr>)}</tbody></table></div></details><details><summary>Request limits</summary><p className="hint">Local host: 30 starts/minute, 2 concurrent across keys and tabs. Local safeguards, not account quotas. Billing (402) and rate-limit (429) failures remain visible. No automatic retries.</p></details><button id="usage-clear" className="quiet" onClick={clearUsage}>Clear local usage history</button></dialog>
</>;
}
2 changes: 1 addition & 1 deletion docs/routing-demo.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Primary details open in a modal drawer over the content: **How the comparison wo

## Key and usage controls

**API key** follows the playground's personal-override convention: masked input, save/replace/remove, origin-local `typesafe-api-key-override` storage. The saved value is never filled back into the input. Storage is unencrypted and accessible to same-origin scripts; origins include ports. A personal key overrides the host's server-only `TYPESAFE_API_KEY`. Server keys never reach the browser.
**Settings → Jev API key** exposes the manual override and current key source. Saving activates it immediately; replacing updates it, and **Remove override** restores the server default for the next comparison. It follows the playground's personal-override convention: masked input, save/replace/remove, origin-local `typesafe-api-key-override` storage. The saved value is never filled back into the input. Storage is unencrypted and accessible to same-origin scripts; origins include ports. A personal key overrides the host's server-only `TYPESAFE_API_KEY`. Server keys never reach the browser.

**Usage** opens reported input/output totals, a price estimate and request history for this tab's latest 200 live Jev requests. Session storage preserves scalar telemetry across refresh, without prompts or keys. **Clear local usage history** removes only that telemetry. Missing usage on failed/cancelled calls is not free; partial totals are labeled. Personal and host-key calls are identified separately. CLI usage is shown per arena lane, not mixed into the Jev totals.

Expand Down
97 changes: 97 additions & 0 deletions docs/verification/arena-key-settings-2026-09-22.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"date": "2026-09-22",
"scope": "Settings manual Jev API key override",
"baseCommit": "bc2434ae1e336b47a744604ab3b0cebcaac9b088",
"checks": {
"typecheck": "passed",
"offlineTests": {
"passed": 84,
"failed": 0
},
"productionBuild": "passed in isolated copy",
"secretScan": "passed",
"diffWhitespace": "passed",
"hostCredentialPrecedence": "Server default, personal override, replacement and return to default tested with an injected fake provider"
},
"browser": {
"settings": {
"checks": [
"manual override is discoverable under Settings",
"settings identifies the default key source",
"empty drafts cannot replace an existing key",
"manual entry is masked",
"saving clearly activates the manual override",
"saving clears the draft and makes no provider request",
"settings drawer fits 320px",
"settings drawer fits 390px",
"settings drawer fits 768px",
"settings drawer fits 1440px",
"Escape returns focus to Settings",
"the comparison sends the manual override header",
"replacement persists across refresh without revealing its value",
"the next request uses the replacement key",
"removing the override restores the default source",
"default mode omits the override header",
"closing settings discards an unsaved draft",
"storage failure does not claim an override was activated",
"a key change in another tab updates Settings and invalidates stale results",
"cross-tab key changes clear stale drafts and save confirmations",
"cross-tab removal clears the active override indicator"
],
"count": 21,
"providerCalls": 0,
"liveCliCalls": 0,
"humanAccessibilityAcceptance": "not performed"
},
"arenaControls": {
"checks": [
"four examples expose their intent before selection",
"keyboard selection updates the task preview",
"selecting examples never starts a request",
"details open with focus inside the overlay at 1440px",
"opening details preserves the underlying layout at 1440px",
"drawer fits and locks background scrolling at 1440px",
"background controls are inert while details are open at 1440px",
"Escape closes details and restores focus at 1440px",
"details open with focus inside the overlay at 390px",
"opening details preserves the underlying layout at 390px",
"drawer fits and locks background scrolling at 390px",
"background controls are inert while details are open at 390px",
"Escape closes details and restores focus at 390px",
"details open with focus inside the overlay at 320px",
"opening details preserves the underlying layout at 320px",
"drawer fits and locks background scrolling at 320px",
"background controls are inert while details are open at 320px",
"Escape closes details and restores focus at 320px",
"clicking the backdrop closes the drawer",
"saved credentials are never redisplayed after reload",
"personal credentials travel only in the request header",
"run snapshots exclude credentials",
"storage failure is visible and preserves the current results",
"quota failure preserves the previous cache",
"failed unsaved runs retain an explicit in-memory result",
"unsaved early failures can download their original status and timestamps",
"usage dashboard records reported Jev usage independently",
"clearing usage preserves saved comparisons",
"clearing comparisons preserves the API key",
"removing a saved API key clears the browser override"
],
"count": 30,
"providerCalls": 0,
"liveCliCalls": 0,
"humanAccessibilityAcceptance": "not performed"
}
},
"visualInspection": {
"sizes": [
390,
1440
],
"surface": "Settings drawer with manual override active",
"result": "reviewed screenshots"
},
"limitations": [
"No live credential validation or provider calls.",
"Human keyboard-only and VoiceOver acceptance not performed."
]
}
Loading
Loading