- The model menu and the inline `/model <query>` suggestions match each query word against the full `provider/model` ID, so `anthropic opus` and `claude sonnet 4.5` find their models.
- Punctuation inside a query word is ignored, so `sonnet45` finds `claude-sonnet-4.5` and `z.ai glm` finds the `zai/glm-*` models.
- A query word also matches when its letters appear in order from the start of a word in the ID, so `cs45` finds `anthropic/claude-sonnet-4.5`.
- Results that contain the query as typed come first, then word matches, then fuzzy matches, each in catalog order, so queries that already worked keep the same top results.
The retry of an empty reply cut short by the provider's default used a
flat 32,768-token limit and kept it for every later step, even when the
catalog named a limit of its own. A known context window now bounds the
limit, as it bounds a full-window limit, and a catalog limit wins on
later steps.
ChatGPT's Codex endpoint chooses its own output limit, so a retry there
sent the same request again and said it was raising the limit. Providers
now say whether a request carries fx's limit, and the retry runs only
through one that does.
The model cache and command replay comments now describe the bounded
wait and the run id in each handle.
Main now pluralizes subagent counts in tool group summaries the same way
this branch pluralizes MCP calls, so the label keeps both: "subagents"
and "MCP calls".
Tests that read command replays matched the old handle, fx-command-replay-
and the hash, so they found none once each run's handle gained a run id.
They now accept the run id and take the blob's name from the hash after
it. D91 in the session manager's design record amends D44 with the new
handle shape.
A name the registry lacks but that has the mcp_ prefix now counts as an
MCP call, so the unsupported-tool test expects "1 command · 1 MCP call".
The ACP length test scripts the retry's reply and checks that the retry
carries a 32,768-token limit and never asks for a summary.
A command's full_output_handle named the blob that holds its output, so
two commands with identical output got the same handle, and a later
result looked like a replay of an earlier one.
The handle now starts with a random id for the run and still ends with
the blob's hash. Runs with the same output keep sharing one stored copy
under handles of their own, and existing handles still resolve.
When a request named no output limit and the provider's own default ran
out before any text or tool call, fx ended the turn with "Done." for an
empty reply.
fx now sends the request again once, with a limit of 32,768 tokens, and
says it is retrying. If that reply is also empty, or the request already
had the catalog's limit, the turn ends with "The reply ran out of output
tokens before any text." instead of "Done.".
When the model catalog failed to load, the retry a submitted prompt
starts ran behind the failed state, so the prompt's first request went
out without the model's limits. With no output limit, some providers
stop a reply at 4,096 tokens.
A request now waits up to two seconds for that retry, as it waits for a
first load. A retry that lands in time gives the request the catalog's
limits. A slower one leaves the request as it was before, so a retry
that hangs never holds a prompt for longer than that.
A tool the model loads with capability_search or mcp_select_tool stays
loaded only for that turn. When the model called it again in a later
turn, or after a resume, the terminal app and fx ask failed the call
with "Dynamic MCP tool not selected for this model step", and the model
had to load the tool again before it could use it.
ACP already loads such a call's current definition from the live
catalog and sends the call through normal validation and permission
review. The terminal app and fx ask now do the same. A name that no live
server has still fails without reaching any server.
A tool the registry does not hold was counted as a command, so a turn's
MCP calls showed up as "2 commands" in its tool group summary and as
commands started in the status line.
Every MCP tool name has the mcp_ prefix, so those calls now have their
own activity kind. The summary reads "1 MCP call" or "2 MCP calls", and
the status line counts MCP calls made.
While a sign-in waits, the server screen in /mcp now reads "Didn't open?
Open the sign-in page." with the label linking the whole address, as the
transcript does since the sign-in links change. A long address no longer
fills the panel. An address that can't be a link target, or a screen too
narrow for the label, still shows the whole address. The transcript and
the screen share the label from menu.sign_in_link_label.
- An MCP tool call over HTTP after the server dropped an idle connection now goes out on a new connection, instead of failing with "the server went away" on every call until fx restarts.
- Renewing an MCP login after the sign-in server dropped an idle connection now goes through, instead of failing with "the sign-in server didn't answer" until fx restarts.
- A connection the server closed cleanly while idle is replaced before the call is sent, so the call no longer fails once with "the tool may have run".
- Connections unused for more than a minute are replaced instead of reused, so a call after the network silently dropped one no longer waits out its timeout.
- A request whose send fails goes out once more on a new connection. A request that was fully sent is still never sent twice.
The repeated-login driver read the sign-in address the transcript printed.
The transcript now links it, so the driver records the shell's output and
reads each link's target instead.
A typed /mcp login and the Vercel sign-in picker printed the whole sign-in
address. Both now show a few underlined words whose OSC 8 link is the
address: "Open the sign-in page" for MCP and "Authorize with Vercel", the
way Codex and Grok already link theirs. Notices underline a link on every
row it wraps onto. An address that can't be a link target is still printed
so it can be copied.
- `/effort` opens a menu of the current model's reasoning effort levels with the one in use marked. ↑↓ moves, Enter applies the highlighted level, and Esc closes it.
- `/effort <level>` applies a level without the menu, and `/effort default` goes back to the model's default.
- Tab after `/effort` opens a level column under the prompt, as Tab after `/model` opens the model column. ↑↓ previews the level in the status line, typing filters the list, Tab fills in the highlighted level, and Enter applies it.
- A new level is saved like a level chosen in `/settings`, and fx prints `Reasoning effort set to <level> for <model>`.
- During a response, the line reads `Next turn will use reasoning effort <level> for <model>`. The running turn keeps its level.
- A model without levels, a level the model doesn't offer, or a malformed level prints a notice and leaves the effort unchanged. If the model list is still loading, the notice asks to try again.
- In a short terminal, the menu leaves the end of the conversation in view and scrolls.
- `/model` still asks for the effort after a model is chosen.
- `/help` lists `/effort` with the model commands.
The SignIn model and its driver still had every reload replace the host and
end the sign-in. A reload now keeps a sign-in when it leaves that server
alone and ends it when it removes or changes the server; the host swap
remains for reloads the loader can't apply in place. KeptSignInGoesOn checks
the first, with a planted bug for the old behavior.
- The model can ask up to 20 questions in one ask_user_question call, so a related set of questions opens as one prompt instead of several prompts of 4.
- The tool schema and description tell the model the new limit.
- A call with more than 20 questions is rejected with "provide 1 to 20 questions", and no prompt opens.
- Resumed sessions show every answer from a batch of up to 20 questions.
Running /permissions with no arguments printed the mode, configured
rules, session grants, and saved rules to the transcript. It now opens a
read-only panel in the footer, like /status, and prints nothing. Each
configured rule, session grant, and saved rule is a bullet, and saved
rules show the ID that /permissions revoke takes. The panel updates when
an approval adds a grant. Subcommands such as /permissions auto and
/permissions remember still confirm in the transcript.
The /status panel becomes a shared info panel that both commands use.
Tests that ran /permissions only to put text in the transcript now run
/allowlist.
wasm32 has no 64-bit atomics, so the SDK's WASM builds failed to compile
the catalog's generation counter. Bindings only compare it for equality,
so 32 bits is enough.
With FX_RECORD set, fx prints a recording notice under the banner, so a
12-row terminal has no room left for the banner above the panel. The
tests now check that the last row of the transcript stays in view.
An /mcp add, remove, approve, or reject used to build a new MCP host and
restart every server. The runtime now applies the change in place through
Engine.reload: servers with the same config keep their process, connection,
sign-in, and calls; removed or changed servers stop and their calls end;
a changed or re-added server starts once its own old process has exited.
The engine copies each server's environment and compares it by content, so
reading the same config again no longer looks like a change.
In a short terminal the panel could take every row but three and cover
the turn in progress. Closing it redrew the rows it had covered, which a
terminal could already have scrolled into history, so they showed twice.
Output written while the panel was open could lose them instead.
The panel now gets the rows an inline picker gets, which leave the end of
the transcript in view, and scrolls the rest with the arrow keys. The E2E
reader scrolls a panel that does not fit to read every line.
- /status opens a panel in the footer instead of writing a notice to the transcript. Esc or Enter closes it and leaves nothing behind.
- The panel's first line shows the open session's ID and whether it is saved yet, so it can be resumed with fx --resume <id>. A shell that can't save sessions shows none.
- The open panel updates when a running turn saves the session or finishes.
- When the panel doesn't fit, the arrow keys scroll it and the hint says so. Long values such as the workspace path wrap instead of being cut off.
- When profile settings can't be read, the panel shows a Settings line and leaves out auth, instead of printing an error with no status.
- A fork made before the first prompt now counts as saved: /status shows it as saved, and the exit line prints its resume command.
- When a stdio MCP server replies with more than 16 MiB, the model is told the reply was too large and fx restarted the server, instead of "the server went away".
- When an HTTP MCP server replies with more than 16 MiB, fx ends the call at once and tells the model the reply was too large, instead of "the server went away".
- fx no longer resumes an HTTP stream (2025 protocol) to fetch an oversized reply again. Before, it downloaded the same reply up to two more times.
- fx no longer requests an oversized tool list again from an HTTP server on the 2026 protocol.
- The debug trace logs each dropped reply with the server, transport, and reason.
- /mcp logout in a shell now also revokes the login another terminal saved after the shell started. Before, that login stayed valid at the server.
- After another terminal logs out of an MCP server, a shell that still holds the login revokes it the next time it would renew it, instead of renewing it and saving it back.