Uh oh!
There was an error while loading. Please reload this page.
🤖 feat: route skills to model classes (Settings-managed large/medium/small) - #3849
🤖 feat: route skills to model classes (Settings-managed large/medium/small)#3849asm wants to merge 18 commits into
Conversation
To use Codex here, create a Codex account and connect to github. |
asm
commented
Aug 14, 2026
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:60f19ad5e5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review All three findings addressed in b1b0bf8:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:b1b0bf8591
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Round-2 finding addressed in 6c4903d: routed sends now compact within |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:6c4903deb0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Both round-3 findings addressed in 297b210:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:297b210330
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Round-4 finding addressed in 50b68ee: added |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:50b68ee8fc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review All three round-5 findings addressed in 6452b8a:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:6452b8a491
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Both round-6 findings addressed in 47afc04:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:47afc04612
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Round-7 findings in 44facc0:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:44facc03ea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review All three round-8 findings addressed in 79fb8e0:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:79fb8e040b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Round-9 finding addressed in 6284377: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:62843778d0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Both round-10 findings addressed, and the branch is rebased onto latest main (the #3844 conflict in agentSession.ts resolved by adopting the new gateway-preserving
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:3d6ffbd18d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Round-11 finding addressed: the compact-and-retry metadata rebuild now carries |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:f9eb115404
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Round-12 finding addressed: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:2ecc3f4b18
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review All three round-13 findings addressed:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:642c4389c4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Both round-14 findings addressed:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:d35a3c78fd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
asm
commented
Aug 14, 2026
@codex review Round-15 finding addressed: |
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…), compose one-shots with skill invocations Skills bound to a model class (frontmatter metadata model-class, or the skillModelClasses config table) stream on the class's model for that send only. Classes are edited in Settings -> Models -> Model Classes; broken bindings fail the send with actionable errors; /model+thinking one-shots compose with skill invocations and bypass class routing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Send path: - Resolve the skill model-class override before the pricing gate, PDF preflight, and history mutations so a broken binding can no longer charge gates against the wrong model or persist side effects before erroring. - Route compaction follow-ups with the pre-routing options so a routed skill send that triggers auto-compaction resumes on the original model/thinking, and only compact routed sends at >=100% usage. - Add a dedicated skipSkillModelRouting wire flag instead of overloading skipAiSettingsPersistence; one-shot model overrides set it explicitly and compaction retries re-derive it from the original message text. - One-shot composed sends now carry the full command prefix in muxMetadata so transcript badges render the model prefix. Binding semantics: - Frontmatter bindings to an unconfigured class are inert (portable skills can ship model-class metadata without breaking sends); a dangling skillModelClasses table entry still errors loudly since the table is the user's explicit routing intent. Blank table entries are treated as unbound. Settings/editor: - Store model-class maps verbatim instead of sanitizing away entries this build cannot parse, so edits from an older/newer build no longer destroy unknown classes. - Gate class edits and the unroutable-model warning on config/routing load completion to avoid clobbering state during the initial fetch. - Carry thinking suffixes across model swaps only when the new model's policy supports them; show raw invalid values in a tooltip. - Share provider/gateway servability predicates between the editor warning and the send-time gate so the two can't drift. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rides through retry Codex review round 1: - Numeric one-shot thinking is model-relative, but the frontend resolves it against the workspace model before routing is known. Pass the raw index (oneShotThinkingIndex) and re-resolve it against the routed class model in AgentSession, so "/+0 /skill" means the routed model's lowest level rather than the workspace model's. - Compact-and-retry rebuilds now carry the one-shot's thinking (named resolved as-is, numeric resolved against the explicit model or kept as a raw index for routed re-resolution) and skipAiSettingsPersistence, and prepareCompactionMessage stops letting ambient stored options clobber carried one-shot fields — without the persistence flag the re-dispatch would also have persisted the one-shot model as the new workspace default. - Preserve skipSkillModelRouting and oneShotThinkingIndex in pickPreservedSendOptions so backend-built compaction follow-ups keep one-shot semantics too. - Stamp the routed model into the persisted user-message metadata (requestedModel) so the pending-turn label and history consumers attribute routed sends to the model that actually streams. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex review round 2: the >=100% band left no room for the new message, attachments, or skill snapshot (recorded usage excludes the pending turn), so a near-limit history could overrun the routed model at request startup instead of compacting. Routed sends now compact within ROUTED_SEND_COMPACTION_HEADROOM_PERCENT of the routed window — still far above the workspace threshold, so a cheap skill invocation still cannot force an unrequested compaction of a fitting history. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…odel that fits Codex review round 3: - Mid-stream usage updates during a routed turn applied the workspace threshold+buffer against the (smaller) routed window, immediately forcing the exact surprise compaction the pre-send band declined. checkMidStream now takes a force-threshold override and routed turns pass the routed-send headroom policy. - When a class routes UP to a larger-window model, repeated routed turns can outgrow the user's model; summarizing on it would just context-error again. On-send and mid-stream compaction now run on whichever of the user/routed model has the larger usable window (normally still the user's model). The deferred follow-up keeps pre-routing options and re-routes at dispatch either way. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex review round 4: OpenAI's isConfigured can mean Codex-OAuth-only credentials, which serve only the OAuth-allowed model set — the class preflight would pass for an OAuth-ineligible model (e.g. gpt-5.5-pro) and the direct route would win over a later gateway, only for the factory to fail with api_key_not_found. canDirectOpenAIServeModel mirrors the factory's credential selection (OAuth-required models need stored tokens even with an API key; OAuth-only configs serve only the allowed set) and the shared servability predicate consults it, so the editor warning and send-time error stay aligned with what a send would really do. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d model
Codex review round 5:
- ProviderModelFactory.resolveModelRoute now passes the canonical model
into isProviderAvailableForRouting: a Codex-OAuth-only OpenAI
credential no longer wins the direct route for a model outside the
OAuth-allowed set (which createModel would reject with
api_key_not_found) — a usable gateway later in routePriority wins
instead, matching the shared canDirectOpenAIServeModel predicate.
Also realigned that predicate with the factory's actual fallback: an
API key attempts any model (OAuth-preferred models fall back to the
key), while tokens-only serves only the allowed set.
- ChatInput's client-side PDF preflight judged the workspace model,
rejecting routable skill sends before the IPC call ever reached the
backend's routed-model gate; it now defers to that authoritative
check when a routable skill invocation is present.
- sendMessage now returns SendMessageAccepted { routedModel } through
AgentSession → WorkspaceService → router → wire schema, and ChatInput
attributes successful-send telemetry to the routed model (queued
sends report none and fall back to the requested model).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>… for class rows Codex review round 6: - React Compiler conventions ban useCallback for identity stabilization: the subscription's fetch now lives inside the effect (its natural scope) and the write-failure revert reaches it through a ref, so no manual memoization and no exhaustive-deps suppressions. - ModelsConfiguredPhone pins a Pixel phone matrix variant (mirrored with globals.viewport) so CI snapshots the Model Classes rows at the narrow width their wrapping layout exists for; verified live at 375px (label/select wrap, inline no-route warning, no overflow). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…in telemetry Codex review round 7: - Class edits persisted AFTER the UI published them: a quick /skill invocation would route on the backend's old map while the editor claimed the new one. useModelClasses now serializes writes and publishes state on the write's ack; rapid edits build on the newest pending intent and failures still revert to backend truth. - The accepted-send payload gains routedThinkingLevel (class thinking suffix or re-resolved numeric one-shot) and ChatInput attributes message_sent telemetry to it, so small:"haiku+0" invocations stop reporting the workspace's ambient thinking level. - Queued sends still attribute to the requested model: routing resolves only at dispatch, and correct queued attribution needs backend-side event capture (frontend-only provenance in the payload) — descoped as a follow-up; the persisted requestedModel stamp already attributes the durable record correctly at dispatch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…king Codex review round 8: - Routable skill sends skip the browser PDF preflight (round 5), so a queued send whose PDF the routed model rejects died on a bare Err in the queue drain — composer already cleared, text and attachment gone. Both PDF rejection branches now persist + surface the error through preserveRejectedManualSend, like the pricing and routing gates. - routedThinkingLevel reported the pre-policy value while the stream clamps against per-model minimum floors; the floor resolution + clamping now live in one shared method used by both the stream build and the accepted-send payload. - messageSent's thinking fallback reads the send's actual options (composed one-shot thinking included) rather than the ambient workspace setting. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex review round 9: routedThinkingLevel was populated only when
routing replaced the thinking, so a named one-shot riding through
("/+off /skill") onto a floor-clamped model reported nothing while the
stream ran at the clamped level. The payload now reports whatever
optionsForStream carries — class suffix, re-resolved numeric index, or
a named/ambient level — clamped by the shared per-model floor
enforcement.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Codex review round 10: - Same-session stream retries (retryActiveStream → resumeStream, and the post-compaction context-exceeded retry) restarted the stream without the routed turn's compaction context, reverting mid-stream checks to the workspace threshold against the routed window and summarization to the smaller model. The auto-retry resume state now carries compactionBaseOptions, resumeStream threads it through, and the post-compaction retry reads it from the captured stream context. - The compact-retry one-shot reparse guard anchored at column zero while parseCommand trims leading whitespace; " /haiku+0 /done" lost its override. The guard now trims before checking. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex review round 11: the follow-up metadata rebuild passed rawCommand
but dropped commandPrefix, so a recovered composed invocation
("/haiku+0 /done") lost its command badge — UserMessageContent keys its
highlighting on that value.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Codex review round 12: a custom openai-compatible provider defined under the "openai" id is direct-only and authenticates against its own endpoint (key optional), but canDirectOpenAIServeModel applied built-in OpenAI credential rules and reported every class model on it unavailable — rejecting class-bound skills while ordinary sends worked. The predicate now recognizes the custom-provider shape and defers to the ordinary isConfigured gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… compaction context Codex review round 13: - Rejected EDITS no longer append the edited text as a new tail turn: the class-routing and PDF gates skip preserveRejectedManualSend when editMessageId is set — preservation exists for dequeued sends whose composer already cleared, and the browser restores the edit draft on failure. - Editor rows disable while their write is in flight (per-class pending counts from useModelClasses): with state publishing on the write's ack, a rapid model→thinking edit would otherwise compose the second value from the still-old rendered model and overwrite the first. - The persisted retrySendOptions embed a durable one-level compactionBaseOptions pick for routed turns, and startup recovery feeds it back into the resume state — the routed compaction policy (90% force bar, larger-window compaction base) now survives a relaunch. Rows written by older versions lack the field and fall back to today's behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…he pricing gate Codex review round 14: - deriveStartupAutoRetryRequest never copied the persisted retrySendOptions.compactionBaseOptions into the retry request, so the round-13 restore always read undefined and a relaunched routed turn still reverted to the workspace compaction policy. The builder now restores the field. - The budgeted-goal pricing gate gets the same editMessageId guard as the class-routing and PDF gates: a rejected EDIT (reachable here via routed skill edits judging the class model) returns bare instead of appending the edited text as a new tail turn. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rkspaces Codex review round 15: child task workspaces prefer creation-time agent settings for startup retry, which would resume a class-routed turn on the workspace model while restoring a routed compaction policy — mismatched in both directions. Retry rows marked with routed compaction context now use the persisted model/thinking (the class values the turn actually streamed with); the child's agent identity precedence is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Main now exports this helper with its own one-argument test suite; the routing ctx parameter defaults to a null providers/model context, which degrades to the designed fallback (numeric one-shot thinking rides along as an index for the backend to resolve against the streaming model). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Skills can now be routed to user-defined model size classes so mechanical skills (wrap-up chores, formatting passes, routine repo tasks) don't consume frontier-model tokens. Classes map a name to a
model[+thinking]value (one-shot syntax) and are edited in Settings → Models → Model Classes; skills bind to a class via the spec-standard frontmattermetadata: model-class: smallor a localskillModelClassesconfig table. The class model applies to that invocation only — the workspace model is untouched. One-shot overrides also compose with skill invocations now (/haiku+0 /deep-review), and an explicit one-shot always beats class routing.Background
Models churn constantly, so per-skill bindings shouldn't name concrete models — they name a class (
large/medium/small), and only the class map names models. Updating one class re-routes every bound skill.model) and extends it to compose with skill slash invocations.ai.modelparsed but not consulted); this PR takes the same position for skills — a declared model preference should be honored — while keeping it strictly opt-in.metadatamap, which other harnesses ignore. Frontmatter bindings to a class the user never defined are deliberately inert, so skills shippingmetadata: model-classcan never break users who haven't opted in. The config table exists for routing skills the user doesn't own — and because the table is the user's own explicit intent, a dangling table entry (naming a class that was deleted) fails loudly instead of silently unrouting.Implementation
modelClassesandskillModelClassesrecords (schema, load normalization,saveConfigwhitelist,config.updateModelClassesroute). Maps are stored verbatim — entries this build can't parse are preserved, not dropped, so edits from an older/newer build never destroy classes they don't understand. Validity is judged lazily at send time by the resolver.src/common/utils/ai/skillModelClasses.ts): binding resolution as a discriminated union (unbound/unknown-class/invalid-value/resolved), plusisModelServableWithProvidersConfig(modelAvailability.ts) wrapping the routing layer'sisModelAvailablewith the same exported provider/gateway predicatesuseRoutingconsumes — so a model reachable only via a configured gateway (e.g. OpenRouter) correctly counts as available, route-priority membership is honored, and the editor warning cannot drift from the send-time gate.AgentSession.sendMessage): the override is resolved before the pricing gate, PDF-support preflight, and any history mutation, so those gates evaluate the model that will actually stream and a broken binding errors before persisting side effects. Routing is gated by a dedicatedskipSkillModelRoutingsend option (set by explicit one-shot composition and compaction retries) rather than overloadingskipAiSettingsPersistence. Bound-but-broken mappings (dangling table entry, invalid value, no configured route for the model) fail the send with an actionable error naming the fix and the one-shot bypass; unbound skills take a null fast-path and infrastructure failures (unreadable skill/config, providers state unavailable) fail open.ROUTED_SEND_COMPACTION_HEADROOM_PERCENT(10 points) of the routed model's window — headroom for the pending turn, while still far above the workspace threshold so a small-context class model can't trigger surprise compaction of a history the workspace model handles fine.large/medium/small— a shared vocabulary keeps skill frontmatter portable across machines), model + thinking selects per class, custom hand-edited classes preserved on save and listed read-only (unparseable raw values shown in a tooltip), and an inline "no configured route can serve this model" warning using the same predicate as the send-time check. Edits are disabled until config and routing state finish loading, so an early click can't clobber persisted classes; thinking suffixes carry across model swaps only when the target model's policy supports them.parseCommandWithSkillInvocationcomposes a leading one-shot with a skill invocation by re-runningparseCommandon the one-shot's message — registered commands and nested one-shots stay out of skill resolution, mirroring direct-invocation semantics exactly. Composed sends record the full command prefix (model /skill) in message metadata so transcript badges render what was actually typed. Numeric one-shot thinking is model-relative, so a thinking-only composed send (/+0 /skill) also passes the raw index (oneShotThinkingIndex) for the backend to re-resolve against the routed model's ladder —+0means the class model's lowest level, not the workspace model's. Compact-and-retry rebuilds re-derive the one-shot's model and thinking from the original text (withskipAiSettingsPersistence, so a re-dispatch never persists one-shot values as new workspace defaults), andprepareCompactionMessagekeeps carried one-shot fields from being clobbered by ambient stored options.requestedModel), so the pending-turn label and history consumers see the model that actually streams.Review-round hardening
Sixteen Codex review rounds tightened the edges (all threads resolved):
skipAiSettingsPersistence), and process relaunch (durablecompactionBaseOptionsinretrySendOptions, honored even in child task workspaces).ProviderModelFactory.resolveModelRouteboth apply model-aware OpenAI credential rules (Codex-OAuth-only serves the OAuth set; API keys attempt anything; custom openai-compatible providers shadowing theopenaiid are exempt).routedModel+ post-floorroutedThinkingLevel; persisted metadata re-stampsrequestedModel. Queued-send event attribution is documented as a follow-up (needs backend-side event capture).Validation
saveConfigwhitelist (including preservation of unknown classes), end-to-end AgentSession routing and error paths via the session harness (gate ordering,skipSkillModelRoutingexemption, thinking-only bindings, compaction follow-up model), composition parser cases, and editor UI behavior (clear preserves custom classes; load gating; warning states).bun test srcfailure set is identical tomain's on the same machine (pre-existing env-sensitive tests only).ModelsSectionstories now seed classes, including one pointing at an unconfigured provider to exercise the warning; row layout wraps at mobile widths) and in a packaged build used for daily work.Risks
The sensitive area is the insertion in
AgentSession.sendMessage. Scope is tightly bounded: only sends carryingagent-skillmetadata withoutskipSkillModelRoutingare considered, and workspaces with nomodelClasses/table binding hit an early return before any skill read — no behavior change for anyone who hasn't opted in. Compaction interplay (threshold on the routed model, compaction request and mid-stream forced compaction on the user's model, follow-up resume options) is covered by tests. One known asymmetry, documented at the helper: the shared servability predicate mirrors the routing layer's gateway/priority gates but not per-request policy checks, so an editor warning can under-report in exotic policy setups — the send-time error remains authoritative.🤖 Generated with Claude Code