Skip to content

feat: /model autocomplete from a configurable :models list, plus /effort - #1

Merged
HelgeSverre merged 3 commits into
mainfrom
claude/model-autocomplete-config-rzyoz0
Jul 12, 2026
Merged

HelgeSverre merged 3 commits into
mainfrom
claude/model-autocomplete-config-rzyoz0

Conversation

@HelgeSverre

@HelgeSverre HelgeSverre commented Jul 11, 2026 •

Copy link
Copy Markdown
Member

/model argument autocomplete

The slash palette now completes /model's argument: once the input reads /model <partial>, it fuzzy-filters a picker list shown as Provider: Model Name — e.g. Anthropic: Claude Opus 4.6 claude-opus-4-6. Tab inserts the selected id, Enter runs it, and any id typed by hand still works, so the list never gates model choice. The active model is marked ●, and providers whose API-key env var is unset are annotated · no key. /model with no argument prints the same list.

The list is config data in init.sema under a new :models key, hot-reloaded like everything else:

:models
(list
  (provider "Anthropic"
    (list (model "claude-opus-4-6"  "Claude Opus 4.6")
          (model "claude-sonnet-5"  "Claude Sonnet 5")
          (model "claude-haiku-4-5" "Claude Haiku 4.5")))
  (provider "OpenAI"
    (list (model "gpt-5.6-sol"   "GPT-5.6 Sol")
          (model "gpt-5.6-terra" "GPT-5.6 Terra")
          (model "gpt-5.6-luna"  "GPT-5.6 Luna")
          (model "gpt-5.5"       "GPT-5.5"))))

All default ids are verified against the providers' published model lists (the GPT-5.6 family ids come from OpenAI's July 2026 release; the bare gpt-5.6 alias routes to Sol, so the explicit -sol/-terra/-luna ids are used).

The mechanism is generic: register-completions! attaches a completion source to any command. Sources receive the live state map and may mark an entry :active. The palette's Enter/Tab logic lives in pure palette-choice / palette-completion functions, covered headlessly by tests.

/effort

Sema's agent/run accepts a portable :reasoning-effort option (none/minimal/low/medium/high/xhigh) that maps to each provider's native control and no-ops on models without reasoning support.

  • /effort <level> sets it for the session (with palette autocomplete, active level marked); /effort default resets; bare /effort shows the current level.
  • (model id label {:effort "high"}) sets a per-model default. Precedence: /effort override → model default → config :effort → provider default.
  • The TUI header shows effort <level> when a non-default level is active.

Sessions

  • save-session! persists the session's effective effort alongside its model.
  • Restoring a session — via the ⌃R modal or the new /resume <id> (which autocompletes from the saved-session list) — now brings back the model and effort it ran with and rebuilds the agent on them. Previously a resumed session silently continued on the current model.
  • /config completes its edit argument.

Shadowing fix

coder.sema's top-level provider/model locals are renamed (llm-provider/cli-model) — in Sema's single namespace they would have clobbered the new config constructors, breaking init.sema on the first hot-reload. Same trap the file already documents for agent.

Notes for review

  • Tests cover the constructors, model-entries/model-effort, config defaults, palette argument mode, the pure Enter/Tab selection logic, active-value marking, session effort round-trip, and the model/effort precedence helpers — but the suite was not executed (the sandbox couldn't install the sema interpreter). Please run jake coder.test before merging.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U4ocGFxVK7FsgQaEhFmJCC

claude added 2 commits July 11, 2026 13:06
The slash palette now completes /model's argument: once the input reads
"/model <partial>", it fuzzy-filters a picker list shown as
"Provider: Model Name" (Tab inserts the selected id, Enter runs it; any
id typed by hand still works, so the list never gates model choice).

The list lives in init.sema as (provider … (model id label) …) groups
under a new :models key, hot-reloaded like everything else. Defaults:
Anthropic (Opus 4.6, Sonnet 5, Haiku 4.5) and OpenAI (GPT-5.6
Sol/Terra/Luna, GPT-5.5). /model with no argument now prints the list.

Mechanism is generic: register-completions! attaches a completion source
to any command; the palette grows an argument mode on top of the existing
command mode. coder.sema's top-level `provider`/`model` locals are
renamed — they would shadow the new constructors on config hot-reload
(the same single-namespace trap already documented for `agent`).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U4ocGFxVK7FsgQaEhFmJCC
Sema's agent/run accepts a portable :reasoning-effort option (none,
minimal, low, medium, high, xhigh) that maps to each provider's native
control and no-ops on models without reasoning support — so a single
session-level setting is safe for every model, no per-model gating.

/effort <level> sets it for the session (autocompleting via the same
palette argument mode as /model), /effort default resets, and a bare
/effort shows the current level. A new :effort config key supplies the
hot-reloadable default, the TUI header shows a non-default level, and
run-turn/run-turn-streaming thread it into agent/run's opts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U4ocGFxVK7FsgQaEhFmJCC
@HelgeSverre HelgeSverre changed the title feat: /model argument autocomplete from a configurable :models list feat: /model autocomplete from a configurable :models list, plus /effort Jul 11, 2026
…er-model effort

Five follow-ups on the /model + /effort work:

- /resume (modal or the new /resume <id> form, which autocompletes from
  the saved-session list) now restores the model and effort the session
  ran with and rebuilds the agent on them; save-session! persists effort
  alongside model. Fixes resumed sessions silently continuing on the
  current model.
- Completion sources now receive the live state map instead of just the
  config, so the picker can mark the value currently in effect (● on the
  active model / effort level) and annotate providers whose API key env
  var is unset (· no key). /model with no argument shows the same marks.
- (model id label {:effort "high"}) sets a per-model default effort;
  precedence is /effort override → model default → config :effort →
  provider default (pick-effort, with choose-model factored out of
  create-agent for the model side).
- /config completes its edit argument.
- The palette's Enter/Tab logic is extracted into pure palette-choice /
  palette-completion functions, now covered headlessly in palette_test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U4ocGFxVK7FsgQaEhFmJCC
@HelgeSverre
HelgeSverre merged commit 1c43dc3 into main Jul 12, 2026
1 check failed
@HelgeSverre
HelgeSverre deleted the claude/model-autocomplete-config-rzyoz0 branch July 13, 2026 10:36
HelgeSverre added a commit that referenced this pull request Jul 13, 2026
Correctness / crashes (#f treated as truthy by when-let/if-let on current sema):
- overlay: resume-sel-session / mcp-sel-server return nil, not #f, so the
  restore/connect when-let guards skip on an empty modal instead of calling
  (:id #f) / (:name #f) and crashing the TUI (#1, #4).
- commands: editor-command returns nil so open-config! can't run a shell
  command literally named "#f" when $VISUAL/$EDITOR are unset (#12).

Data loss:
- tui: gate the ⌃O/⌃R overlay opens on *busy* — a mid-turn restore raced the
  finishing turn, which then overwrote *messages* and persisted onto the wrong
  session file (#2).
- tui: /clear (messages → '()) now starts a fresh session id via apply-tui-state!
  so the next turn doesn't overwrite the cleared conversation's file (#6).
- session: save-session! writes a temp file then renames over the target, so a
  crash mid-write can't truncate the only copy (#14).

Config reload:
- commands: /reload keeps the running config on a broken init.sema (like the
  file-watch path) instead of reconciling to defaults, which wiped the user's
  live commands/keybindings/servers over a typo (#3).
- tui/commands: re-run mcp-autostart! on hot-reload and /reload so newly-declared
  :autostart servers actually connect (#8).

Output caps / render:
- tools: read-file and grep apply a character cap (not just a line cap), so a
  few very long lines can't flood context / OOM (#5, #13).
- tui: re-clamp the frame after overlay-center so an overlay taller than the
  terminal can't write past the bottom and desync the diff renderer (#7).

Tests (new audit_regressions_test.sema + additions):
- resume/mcp selection nil-safety, /clear session rotation, provider-key-missing?
  on an unknown provider (#11), truncate-chars (#10), :raw whitespace
  preservation (#15), and reconcile preserving a live MCP connection (#9).
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.

2 participants