Skip to content

A web run runs on the model it was started with (#1697) - #1714

Merged
suleimansh merged 1 commit into
mainfrom
1697-web-run-model
Aug 26, 2026
Merged

A web run runs on the model it was started with (#1697)#1714
suleimansh merged 1 commit into
mainfrom
1697-web-run-model

Conversation

@suleimansh

Copy link
Copy Markdown
Contributor

Fixes #1697 (option 1).

What

A run started with a model choice (--model, the launcher's model, Settings) that lands on the web path now runs on that model. The choice travels the whole way — /_web-start → the start-queue → /_bridge/start → the Driver's tf-drive — and content.js picks it in claude.ai's model menu before sending, reporting what it clicked the way the repo and branch chips do. A menu that does not offer the model, or a page with no picker, fails the creation naming it, so the run stops with that note instead of running on the page's default.

Before this, cloud.ts posted {repo, branch, prompt} although agent.ts already handed it model; the dashboard then showed the chosen model on a web run that claude.ai was running on its own default.

How

  • driver/cloud.ts: the request body carries model from the start options when set; the "asked the browser extension…" notice names it.
  • dashboard/web-start-endpoints.ts: model, when present, must be a string (400 otherwise).
  • dashboard/bridge-starts.ts: model stored trimmed on the request; blank is none; over 100 characters is refused (MAX_START_MODEL).
  • dashboard/server.ts + bridge-endpoints.ts: /_bridge/start hands the extension the model.
  • background.js: the claimed request's model rides the tf-drive start.
  • content.js createSession: after the branch chip is verified and before anything is filled — the model trigger (button[aria-haspopup="menu"] reading a model name, beside the effort button; not a combobox, so the chips' order is untouched) is read; if it does not read the model, its menu ([role="menuitemradio"] entries, label read without the hidden shortcut digit and check glyph) is opened and the entry clicked — exact label first, else the first entry carrying the model's word (opus → "Opus 5", the newest), the "More models" submenu searched when the menu offers nothing — and the trigger is read again. Notes: model already Opus 5 / model: clicked "Sonnet 5" via menu / model: the menu offered no "gpt-9" (6 entries: …) / no model picker on the page — not sending. No model in the request → the picker is never touched. probeNewSession reports the picker's text.
  • Options page: a lastCycle line — background.SPEC.md said the outcome is kept so the options page can state it; the page never read it. Rendered on open and re-rendered from chrome.storage.onChanged, so "reloading the extension: content.js changed on disk" is visible there.

Selectors from one live look at claude.ai/code on 2026-08-26: trigger button[aria-haspopup="menu"] "Opus 5"; menu div[role="menu"] of div[role="menuitemradio"][aria-checked] with the label in the first span, a kbd shortcut in an aria-hidden span, and a check glyph on the current one; More models is a menuitem[aria-haspopup="menu"] that opens a submenu (Opus 4.8 / 4.7 / 4.6, Sonnet 4.6) on click; a plain .click() on an entry picks it, the trigger text becomes the label, and the pick survives a page load.

Tests

  • cloud.test.ts: the model rides the POST body; absent when unset.
  • web-start-endpoints.test.ts: string travels to the queue; non-string is 400.
  • bridge-starts.test.ts: trimmed, blank dropped, cap refused.
  • bridge-endpoints.test.ts: /_bridge/start carries it.
  • server.test.ts: end to end through a dashboard with the bridge on — run posts model, the extension's claim reads it (this one covers the server.ts wiring; broken on purpose, it fails).
  • check.mjs: five new cases — picked, already reads it (picker not opened), found behind "More models", not offered (nothing sent, note names the model and the entries), no picker (nothing sent) — plus the no-model case asserting the picker is never opened. Each broken on purpose once: removing the entry click, the model-word filter on the trigger, or the read-back fails exactly the cases guarding it.

Specs

content.SPEC.md, background.SPEC.md, options.SPEC.md, the extension's SPEC.md, driver/cloud.SPEC.md, dashboard/web-start-endpoints.SPEC.md, dashboard/bridge-starts.SPEC.md, dashboard/bridge-endpoints.SPEC.md, and FEATURES-SPEC.md (the model on web runs; the options page's last-cycle line).

Not done here: option 2's "don't offer a model pick for a web run" — moot once the pick is honoured.

🤖 automated · Fable 5, effort high

@suleimansh

Copy link
Copy Markdown
Contributor Author

Dogfood on the live dashboard (daemon rebuilt from this branch, pid 53455; extension self-reloaded onto this branch's files), prefs temporarily target=web, model=sonnet — the page's remembered model was Opus 5, so the pick had to happen:

  • Run 2026-08-26T09-39-23-076Z on gemstack. The run's notice: "asked the browser extension to create the cloud session on framework/the-framework at cloud-1-ca581338 on sonnet (request c52eeac6-…)".
  • The extension's report on the request (GET /_web-start/c52eeac6-…): state: created, session_01TeJWj29xRD5K12PTbfs6nn, note "repo already the-framework; branch: clicked "cloud-1-ca581338" via combobox; model: clicked "Sonnet 5" via menu; sent via button".
  • https://claude.ai/code/session_01TeJWj29xRD5K12PTbfs6nn: the composer's model trigger reads Sonnet 5, and the session's own reply is "Running as claude-sonnet-5 (both configured/session model and last served model). No files changed, no PR opened."
  • A probe request with model queued through /_web-start and claimed by hand on /_bridge/start came back with "model":"sonnet" (claimed and reported failed by me at once, never driven).
  • The fold-in: the options page shows "Last cycle at 12:38:14 PM: read 1 of 1 (0 awaiting, 1 unread, 0 missing), visited 0, typed 0" — the first time that record has been visible anywhere.

One earlier attempt (run …T05-24-26-123Z, session_01H66fhqqJwvNdwo9hAUYWmB) ran on Opus 5 with no model note: I had switched the checkout back to main after building, and the extension — which loads its files from the checkout — self-reloaded onto main's old files while the daemon kept the new dist. Nothing wrong in the change; a dogfood-procedure trap, now in my notes.

Prefs and the page's remembered model are restored (target=local, model=opus; Opus 5).

🤖 automated · Fable 5, effort high

@suleimansh

Copy link
Copy Markdown
Contributor Author

The red build check here is not this change: bridge-store.test.ts's list-status test asks waiting() with the wall clock against a status stamped 2026-08-25T18:00Z, and the twelve-hour session window ran out at 06:00 UTC today — it fails on main too (reproduced locally). Fixed in #1715; this branch goes green once that lands and this is rebased on it.

🤖 automated · Fable 5, effort high

The model choice reached the cloud driver — agent.ts hands `model` to every driver's start —
and stopped there: cloud.ts asked the daemon for a session with repo, branch and prompt only,
so the session ran on whatever claude.ai defaults to while the dashboard showed the chosen
model. The choice now travels /_web-start → start-queue → /_bridge/start → tf-drive, and
content.js picks it in claude.ai's model menu before sending, reporting what it clicked like
the repo and branch chips do. A menu that does not offer the model, or a page with no picker,
fails the creation naming it, so the run stops with that note rather than running on the
default. No model in the request leaves the picker untouched.

Selectors from one live look on 2026-08-26: the trigger is a menu button reading the model,
the menu radio items whose label sits beside a hidden shortcut digit and check glyph, and
"More models" a submenu of older versions that opens on click; a plain click picks an entry
and the pick survives a page load.

Also: the options page shows the worker's last cycle — background.SPEC.md said the outcome is
kept so the options page can state it, and the page never read it — live, so a reload the
worker did because its files changed on disk is visible there.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@suleimansh
suleimansh merged commit c3861d8 into main Aug 26, 2026
2 checks passed
@suleimansh
suleimansh deleted the 1697-web-run-model branch August 26, 2026 10:03
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.

A model choice is silently dropped on web runs

1 participant