- Parsed OpenRouter reasoning effort ladders and defaults during discovery.
- Preserved explicit thinking metadata from models.yml patches.
- Regenerated the catalog and covered both regression paths.
Fixes#7307
- Prevent xdev state allocation and tool mounting in sessions lacking a write tool.
- Expose discoverable tools top-level instead of auto-granting write transports.
- Change the default MCP JSON-RPC request ID format from snowflake strings to sequential integers.
- Update server configuration schema, connection equivalence checks, and tests to reflect the new integer default.
The option only exists in OMP's own config format, so the OMP-owned discovery
providers are the only ones that parse it. Say so in the schema description, the
MCPServerConfigBase doc, and the changelog, and name the config paths where
setting it actually takes effect, so nobody expects a server imported from
another tool's config to honor it.
Apple's `xcrun mcpbridge` decodes JSON-RPC `id` as an integer only. OMP
mints collision-resistant snowflake strings, so the bridge logs
`mcpbridge.DecodeError Code=1`, never replies, and every request hangs
until it times out (#7053). JSON-RPC 2.0 permits String and Number ids
equally, so both shapes are legal and the string default stays.
Add `requestIdFormat: "string" | "number"` to the shared server config
and honor it in all three transports through one allocator. The string
default is unchanged, so this is inert unless a server opts in.
Verified against Xcode 26.3's bridge: with `"number"`, `initialize`
succeeds and `tools/list` returns all 21 tools; with the default, the
same request times out.
- Replaced the reactive weekly-only auto-redeem predicate with a pool-wide
planner: an expiry-salvage sweep piggybacks on the 5-minute usage
heartbeat and spends any account's reset that would otherwise expire
within codexResets.salvageHorizonHours, and the blocked-turn path scans
all stored accounts with eligibility built from the exact exhausted
5h/weekly windows (openai/codex#28525), unblocking at the latest reset
among them.
- Made the live 429's parsed unblock timestamp authoritative for the
active account (pre-block snapshots survive cache invalidation via
in-flight adoption and last-good fallback), synthesizing the candidate
when no usable report exists, and overlaying live credit counts from
the dedicated credits route since a stale /wham/usage zero is never
corrected upstream.
- Treated nothing_to_reset, credit_list_failed, and thrown consumes as
non-terminal: the episode key is released and deferred 30 minutes
instead of burying a banked credit; redeemResetCredit now spends the
soonest-expiring credit.
- Added planner unit fixtures plus integration regressions driving the
real triggers end to end, with an injectable per-session coordinator
seam and a sweep settlement handle.
macOS Terminal.app consumes Option for character composition, so Alt+Up
never reaches the app and the dequeue is unreachable there. Bind Shift+Up
alongside it -- Shift is not intercepted, and the key was unbound in the
input path.
The three overlay handlers that already use shift+up for fast scroll
(scroll-view, model-hub, log-viewer) match keys directly rather than
through the manager, so they never see this binding.
Both default tables move together: the registry in config/keybindings.ts
and DEFAULT_ACTION_KEYS in custom-editor.ts, which silently shadows the
registry when they disagree.
- Add the `app.live.toggle` keybinding defaulted to `Ctrl+L` to start or stop live voice mode.
- Remap the default display-reset action (`app.display.reset`) from `Ctrl+L` to `Alt+L`.
- Update the live visualizer to listen for stop keys so the toggle chord terminates active sessions.
Ollama's online-if-uncached path keyed every endpoint under the same
provider namespace. Changing OLLAMA_BASE_URL or OLLAMA_HOST therefore
reused fresh models routed to the previous endpoint until cache expiry.
Centralize an endpoint-normalized Ollama cache namespace and apply it to
both configured coding-agent discovery and the catalog model manager.
Add coverage proving a default refresh discovers the new endpoint even
while the previous endpoint has a fresh row.
Fixes#7087
llama.cpp and Ollama model discovery probed /models and /props with a
250ms timeout tuned for a loopback server. That cap also applied to a
host reached over the network, so a remote or LAN LLAMA_CPP_BASE_URL
(or OLLAMA_BASE_URL/OLLAMA_HOST) with normal round-trip latency timed
out, discovery returned no models, and the picker fell back to stale
127.0.0.1:8080 entries.
Select the probe timeout by host: strictly-loopback base URLs keep the
fast fail so a busy or foreign service on the default port never stalls
startup; every non-loopback host gets a generous discovery budget.
Fixes#7087
The soft request budget resolved to `SOFT_REQUEST_BUDGET[agent.name] ??
configured`, so the bundled entries for scout and sonic replaced the
configured value outright. Lowering `task.softRequestBudget` to tighten
the guard therefore did nothing for exactly the two agents that spawn
most often: a scout kept its 100-request budget no matter how small the
user set the knob. Only 0 (disable) and raising the value for
non-bundled agents had any effect.
Treat both numbers as upper bounds and take the smaller one. The bundled
entries stay ceilings, so a runaway scout is still stopped at 100 by
default and existing behavior is unchanged for anyone who has not
lowered the setting; a configured 0 still disables the guard entirely.
Resolution moves into `resolveSoftRequestBudget`, which also normalizes
negative and fractional inputs, so the rule is testable without standing
up a subprocess run.
This composes with `task.maxEffort` on a separate axis: effort caps how
hard each request thinks, this caps how many requests a run may spend.
(cherry picked from commit f0db29f8f725f11390b64ca9342300c482ff5c5d)
The previous commits patched each rebuild path individually to avoid feeding a
modifyModels hook its own output. That left the invariant implicit and the
provider-scoped path applying only a subset of hooks, which is wrong for a hook
that inspects or suppresses another provider's models.
Keep #unprojectedModels as the canonical pre-projection catalog and derive
#models from it at every mutation point, so projections are always a pure
function of the unprojected base:
- #composeUnprojectedStaticModels builds the catalog; #composeStaticModels
projects it. A scoped lookup with modifiers registered composes and projects
the whole catalog before narrowing, matching getAll() followed by a filter.
Providers without modifiers keep the cheap filtered path.
- Discovery completion, registerProvider, and runtime transport overrides
update the unprojected snapshot and reproject, instead of mutating an
already-projected array.
- Runtime metadata patches apply to the unprojected model, then reproject, so
a later registration cannot discard them.
- Provider lookup snapshots are invalidated wherever the projection changes.
Hooks no longer take a providerFilter: a modifier is a whole-catalog transform
and every rebuild now runs the full ordered set exactly once.
(cherry picked from commit e5d2e9eac7c371cc196e9b362f77d3a5d7bdf507)
registerProvider composed nextModels from the already-projected #models,
stripping only the incoming provider, then reran every stored modifier over
it. Loaders drain registrations one at a time, so the previously registered
provider's projection was fed back into its own hook — an append-style hook
compounded on each subsequent registration.
Apply only the incoming provider's hook. Every other provider's projection is
already present exactly once, and full rebuilds still go through
#composeStaticModels.
(cherry picked from commit b16db642b08cc223b062c0c556f00d46fda2520a)
Review follow-up on two defects in the original change:
- The throwing-hook fallback wrote to #lastDiscoveryWarnings, which is only
ever read to dedup a logger.warn inside #warnProviderDiscoveryFailure. No
log line was emitted, so a broken extension degraded invisibly, and the
shared key could mask a later discovery failure for the same provider. Log
via logger.warn with its own dedup map.
- #refreshRuntimeDiscoveries starts from the already-projected #models, and
the overlay merge only replaces matching provider+id pairs, so a hook's
projection-only entries survived and were fed back into it. An append-style
hook duplicated its output on every refresh. Drop each modifier provider
before the merge so it re-seeds from the unprojected overlays.
(cherry picked from commit b6f841e080d4882a08b8d713de009461b6acc6fe)
`registerProvider` applies `oauth.modifyModels` once and assigns the result
straight to `#models`, but only the pre-projection definitions are persisted
in `#runtimeModelOverlays`. Any subsequent static reload rebuilds `#models`
from those overlays and silently drops the projection.
The model selector reloads on every open (`refresh("offline")`), so an
extension provider that projects a credential-aware catalog shows its
correct models everywhere except the picker — the one place users look.
`refreshProvider()` and online discovery completion had the same hole.
Persist the hook per provider and re-apply it wherever `#models` is
recomposed, honouring the `providerFilter` used by scoped lookups. A hook
that throws now degrades to that provider's unprojected catalog instead of
failing the whole composition, so one broken extension cannot empty the
registry.
(cherry picked from commit 33b7c72f225b4253b68bb71ecb3a9186151b18b3)
Attaching to a long-running browser (a signed-in profile, an Electron app kept
open for a session) meant repeating app.cdp_url on every browser call, and any
call that omitted it silently launched a fresh headless Chromium instead.
browser.cdpUrl supplies that endpoint once. It is a default rather than an
override: app.cdp_url and app.path still win, and an unset or blank value leaves
cmux and headless resolution exactly as before.
- read now derives its image behavior from actual tool availability
(session.isToolActive) with the mode computation as fallback, so
restricted sessions whose explicit slate omits inspect_image (e.g.
subagents) never get metadata-only reads pointing at an absent tool
- reconcile passes the post-change availability into the read
description sync, keeping the advertised prompt correct across flips
in both directions and when tool construction fails
- flat quoted-dotted inspect_image.mode is normalized into the nested
target during migration instead of being silently dropped when a
legacy flat enabled key is present
- regression tests for all three: availability-driven read behavior,
flat+flat migration, description advertising
- Reconcile inspect_image centrally from setModelWithProviderSessionReset
so retry-fallback model changes (turn-recovery.ts) that bypass
syncAfterModelChange cannot leave a stale tool set
- Apply persisted inspect_image.mode changes immediately from the
settings selector via a new handleSettingChange branch
- Refresh the read tool's advertised description during reconciliation,
before applyActiveToolsByName rebuilds the prompt, instead of only
lazily on the next image read
- Fix the flat (quoted-dotted) enabled->mode migration to write the
nested target form the resolver actually reads
- Add committed regression tests: tri-state x capability matrix,
override precedence, and enabled->mode migration (nested, flat, and
explicit-mode-wins)
Replace the inspect_image.enabled boolean with inspect_image.mode
(auto|on|off, default auto). In auto the tool is registered only when
the active model lacks native image input, so vision-capable models
(e.g. kimi-code/k3) read images inline with their own capabilities
instead of delegating to a separate vision model. on/off force
registration regardless of model capability.
- New utils/inspect-image-mode.ts resolves the effective state from the
/vision session override, the persisted setting, and model capability
- read tool re-evaluates the effective state per image read and
re-renders its description, so it returns decoded image blocks again
whenever inspect_image is hidden
- /vision [on|off|auto|status] slash command (modeled on /computer)
overrides the mode for the current session only
- Tool set is reconciled on model switch with a status notice when
inspect_image appears/disappears
- Legacy inspect_image.enabled true/false migrates to mode on/off
- Keep terminal working titles static with a colon separator on Windows instead of scheduling animated spinner updates.
- Update terminal title builder and state machine to check the platform and bypass timer intervals on win32.
- Introduce task.enableEffort setting defaulting to false to hide per-spawn effort parameters.
- Conditionally include effort in single and batch task schemas and descriptions based on the new setting.