- Added support for `viewport.scale` and `open` `dialogs` options when launching/reusing browser tabs.
- Applied configurable dialog auto-handling policies to acquired tabs and cleaned up handlers when tabs are disposed.
- Added new tab APIs (`evaluate`, `scrollIntoView`, `select`, `uploadFile`, `waitForUrl`, `waitForResponse`) and updated browser tool docs.
- Updated the browser tab drag API to accept `DragTarget` values as selectors or `{ x, y }` points.
- Adjusted drag execution to resolve selector targets to element centers, validate point inputs, and dispose temporary handles.
- Changed waitFor to return the resolved `ElementHandle` and updated docs for handle-based chaining.
- Added `browserToolRenderer` to display `run` tool calls as JavaScript code cells with status and output previews.
- Rendered `browser` `open`/`close` actions as compact status lines with optional output text.
- Hooked `browserToolRenderer` into `toolRenderers` so browser calls use the new renderer.
- Removed legacy actions and reworked tool schema to open/run/close with required open-before-run async-JS flow.
- Added named tab reuse with browser-kind checks and close options all/kill with ref-counted disposal.
- Implemented launch/CDP hardening by finding free ports, reusing live targets, waiting for readiness, and killing process trees.
- Added readable result extraction, selector and action visibility checks, and screenshot/observation support in run execution.
- Added `Process` class with pidfd (Linux), libproc (macOS), and handle (Windows) ownership for race-free signaling.
- Replaced `killTree`/`listDescendants` free functions with `Process.fromPid`, `fromPath`, `terminate`, and `waitForExit`.
- Added `TerminationTargets` for batching pgid+pid sets across pty and shell job teardown.
- Migrated `procmgr` and `ptree` to use the new native API, removing the `setNativeKillTree` injection pattern.
Exposes model.compat.disableStrictTools (already supported by the anthropic
transport since #826) via models.yml so users can configure it without code
changes.
Set disableStrictTools: true at the provider level to disable strict tool
schemas for third-party Anthropic-compatible endpoints (AWS Bedrock, Vertex
AI proxies, custom gateways) that reject the strict field.
- Add disableStrictTools to ProviderConfigSchema
- Merge { disableStrictTools: true } into provider compat override when set,
flowing through the existing compat pipeline to model.compat.disableStrictTools
- disableStrictTools alone is sufficient for an override-only provider entry
- Update docs/models.md with field reference, Bedrock example, and proxy note
- Add tests covering provider-level propagation, built-in override, and
overlay merge
- Added plan-mode path resolution that routed bare and cwd-relative PLAN.md targets to the canonical local plan artifact when plan mode was enabled.
- Preserved existing resolution for non-matching basenames and disabled-plan-mode sessions by returning the raw path unchanged.
- Expanded local plan-mode guard tests to cover redirects for PLAN.md and enforcement of non-plan and delete restrictions.
- Updated atom edit prompt guidance to remove obsolete small-drift hash-auto-rebase instructions.
- Removed `id` fields from todo models/fixtures and switched session clones to content-based task identity.
- Replaced `/todo_write` `replace` with `init`, updated setup schemas to `list`/`phase`, and append content-only items.
- Updated `/todo` command flows to match phases and tasks by names/content (exact/prefix/substr, case-insensitive), with no ID targeting.
- Updated rendering/output labels to `# Todos`, `formatPhaseDisplayName`, and Roman-numeral phase headings across todo views.
- Aligned prompts, changelog, and todo tests/fixtures with the new init and content-based todo-write contract.
- Added a lookahead helper to detect `\` continuation lines after blank lines during range replacements.
- Converted interior blank lines to explicit continuation-sentinel inserts when followed by a continuation, preserving open replacement state.
- Extended atom parser tests to cover implicit blank-`\` handling for range and single-anchor replacements, including trailing-blank termination.
- Integrated `isUnexpectedSocketCloseMessage` into transient error detection so Bun socket-closure failures are treated as retryable.
- Added a retry fallback test that simulates a Bun socket close error and verifies the request is retried successfully with matching retry start/end events and recovered output.
- Updated adjacent-duplicate auto-fix logic to remove a line from each detected pair when bracket balance changed.
- Adjusted the validation to accept the corrected file only after all removals restore original bracket balance.
- Added a regression test for one edit creating duplicate block closers in two unrelated segments and asserting the auto-fix warning.
- Fixed bash interceptor to check both raw and cwd-normalized commands, catching commands hidden behind leading `cd ... &&` wrappers.
- Fixed LSP client shutdown to await graceful shutdown with a 5s timeout before killing the process, and parallelized `shutdownAll` via `Promise.allSettled`.
- Fixed concurrent bash command tracking by replacing a single abort controller with a Set, preventing premature cancellation of parallel commands.
- Removed `./hooks` and `./hooks/*` export entries from the coding-agent package exports map.
- Updated pinned Rust nightly toolchain from `nightly-2026-03-27` to `nightly-2026-04-29` in `rust-toolchain.toml` and CI workflow.
- Replaced custom already-published detection in `ci-release-publish.ts` with `bun publish --tolerate-republish` flag.
The helper guarded `model.api === "openai-completions"` and returned undefined
for openai-responses models. The discoverable-custom-compat test sets
`api: "openai-responses"` on a custom model with `compat.extraBody`, so the
post-refresh assertion saw `undefined` instead of the configured proxy hint.
The OpenAICompatSchema gates user-facing custom-model compat regardless of the
underlying api wire format, so reading the field as OpenAICompat for any api
matches what the registry actually stores.
Commit a190397d8 made `Model.compat` resolve to `OpenAICompat | AnthropicCompat`
under the default `TApi = any`. The widened union broke every site that treated
`compat` as openai-shaped: model-registry deep-merge, openai-completions resolved
compat, and ~20 test fixtures. This restores the assumption locally instead of
papering over it with casts.
- getBundledModel is now generic on TApi so test fixtures that spread it into
`Model<"openai-completions">` get the narrow compat back.
- mergeCompat is generic over TBase/TOverride; the schema-driven model-registry
override path keeps its OpenAICompat-shaped merge fields, anthropic overrides
pass through untouched.
- OpenAICompatSchema gains the openai-only fields it was missing
(requiresMistralToolIds, reasoningContentField, requiresReasoningContent*,
thinkingFormat, requiresThinkingAsText, disableReasoningOnForcedToolChoice).
- resolveOpenAICompat fills in disableReasoningOnForcedToolChoice so the
Required<OpenAICompat> shape stays satisfied.
- Anthropic tool-result block id assignment uses the proper unknown double-cast.
- isForcedToolChoice accepts unknown so it can read `params.tool_choice` whose
type comes from the OpenAI SDK ChatCompletionToolChoiceOption (now wider than
our local OpenAICompletionsToolChoice).
- Test fixtures and Required<OpenAICompat> literals updated for the field set.
Fixes CI red on main.
Mirror anthropic.ts:disableThinkingIfToolChoiceForced for backends that 400
on combined reasoning + forced tool_choice. Kimi explicitly rejects this
combination ('tool_choice specified is incompatible with thinking enabled')
on its native API, OpenCode-Go, OpenRouter, etc. Anthropic itself enforces
the same constraint, so Claude reached through OpenAI-compat proxies
(LiteLLM, Vertex chat-completions, OpenRouter) needs the same handling.
Adds disableReasoningOnForcedToolChoice compat flag, defaulted on for any
Kimi (moonshotai/kimi*, kimi-* ids) or Anthropic (provider/baseUrl/claude*
ids) model. When tool_choice resolves to anything that forces a tool call
(required, named function), reasoning_effort and the OpenRouter-shaped
nested reasoning object are dropped for that turn. The forced tool_choice
itself stays so the agent still gets the tool call.
Replaces the previous (incorrect) approach of unconditionally dropping
tool_choice for kimi reasoning models, which broke explicit tool routing.
Fixes#827
Standalone Bun binaries on WSL (and any host where the user moves the
binary away from the build-host's checkout) failed to load
pi_natives.<platform>-<arch>*.node. The loader's isCompiledBinary
detection relied on two signals that are both false in shipped binaries:
process.env.PI_COMPILED (bun --define PI_COMPILED=true substitutes the
bare identifier, not property accesses on process.env) and
__filename.includes("$bunfs") (Bun retains the build-host absolute path
in __filename for required CJS modules — only import.meta.url is
rewritten). Detection therefore returned false, embedded-addon
extraction was skipped, and the only candidates probed were the
build-host nativeDir and execDir.
Make embedded-addon presence the authoritative compiled-mode signal
(it is null in the post-build --reset stub, populated when embed:native
ran for the standalone build), eagerly require the manifest, and
extract candidate-path computation into a pure helper covered by a
host-platform-agnostic unit test. Also fix the build-time --define so
process.env.PI_COMPILED is genuinely set at runtime as a defensive
fallback.
Fixes#823
flushCompactionQueue() fires session.prompt(text) on the first non-slash
queued message. If the session is still streaming when compaction-end
lands (race between isStreaming flipping false and the event arriving),
prompt() throws AgentBusyError, restoreQueue() dumps the message back
into compactionQueuedMessages, and it stalls there: nothing drains that
array except the next compaction-end. The user sees the steer preview
but cannot deliver the message (Alt+Up consults session.clearQueue, not
compactionQueuedMessages).
Pass streamingBehavior derived from the queued message's mode so
prompt() routes into the steer/follow-up queue when busy and runs as a
fresh prompt when idle.
Fixes#825
buildSessionContext walked the entry path and unconditionally overwrote
models.default from every assistant message's reported model. Temporary
fallbacks (retry fallback, context promotion) and codex-side model
downgrades both produce assistant messages tagged with a different model
id, which clobbered the user's explicit /model pick on resume and made
the session silently revert to the older model.
Treat assistant-message inference as a legacy fallback that only fills
in models.default when no explicit `model_change` with role="default"
has been seen on the path.
Fixes#849
Phase1 caught every per-claim failure, recorded the reason in
jobs.last_error, and surfaced only an aggregate failed count via the
phase1 completion debug line. Users hitting setup-time failures (e.g.
WSL2 stale rollout paths producing ENOENT before any LLM call) had no
diagnostic. Emit logger.error per failed claim with threadId,
rolloutPath, and reason so the actual error is visible in omp.log.
Fixes#846
Add optional defaultLevel to ThinkingConfig schema/type so models.yml can
declare a preferred starting thinking level per model. On model switch
the agent session adopts model.thinking.defaultLevel when present (with
explicit caller-supplied level still winning); otherwise current behavior
is preserved. SDK initial selection prefers the model's defaultLevel
before falling back to the global defaultThinkingLevel setting.
Fixes#775
When entering plan mode while the session is streaming, #applyPlanModeModel
defers the switch into #pendingModelSwitch and snapshots the previous model.
On exit, the snapshot was restored but the deferred switch was left queued,
so the next agent_end flush landed the session on the plan-role model after
the user had already left plan mode.
Drop the pending switch in #exitPlanMode when its target matches the
plan-role resolution; leave any other queued switch alone.
Fixes#816
Claude marketplace plugins (e.g. context7@claude-plugins-official) ship
.mcp.json with the server map at the top level rather than under the
mcpServers key. The loader only accepted the nested shape, so install
appeared to succeed but no MCP tools were registered. Detect both shapes
and validate that each entry declares command (stdio) or url (HTTP/SSE)
before registering.
Fixes#851
The autoContinue post-compaction prompt echoed the summary's '## Next
Steps' heading, but that section is generated only from the compacted
tail; the kept ~20k recent tokens are not fed to the summarizer. When
the user pivoted within the kept window, 'Continue if you have next
steps.' anchored the model on the now-outdated plan instead of the
latest intent.
Move the prompt to prompts/system/auto-continue.md (per AGENTS.md
no-inline-prompts rule) and rewrite it to direct the model to re-read
the kept recent messages and follow the user's most recent request,
explicitly allowing it to stop when nothing remains.
Fixes#840
isPathInDirectory only normalized strings via path.resolve, so on Windows
when Bun is installed via Scoop (~/.bun is a junction to scoop\persist\
Oven-sh.Bun\.bun) the omp path from $which and the bunBinDir from
'bun pm bin -g' compared as different directories, causing 'omp update'
to take the binary-swap path instead of 'bun install -g' and fail with
EPERM unlinking omp.exe.bak (Bun has the running exe open). Layer
fs.realpathSync.native on top of the existing lexical guard, resolving
the file's parent dir so non-existent target paths still fall through.
Fixes#845
- Added a shared session path resolver that maps local:// URLs through local-protocol options, skips other internal schemes, and returns an absolute filesystem path for real files.
- Updated streaming-edit pre-cache and post-edit cache invalidation to use the shared resolver, preventing internal-scheme assertions while keeping filesystem-based flow for local plan files.
- Extended streaming-edit tests to confirm local:// plan edits complete without panicking and that auto-generated checks receive resolved absolute paths.
- Added support for batch PR operations by accepting `pr` as string or array and dropping `worktree` input.
- Updated `pr_view` and `pr_diff` to normalize PR IDs, process multiple PRs in parallel, and emit combined summaries.
- Refactored checkout into `checkoutPullRequest`, added repo-locking, fixed worktree paths, and summary metadata outputs.
- Updated `remote.add` handling with URL-aware idempotency and per-repo queueing for serialized git mutations.
- Added temp-home test scaffolding and expanded tests for batched PR flows and remote add conflict/no-op cases.
The task description prompt was compressed in c6cab807d — the explicit 'Current input mode' and 'Every assignment must stand on its own.' phrasings are gone. Replace those literal-string assertions with checks against the rendered mode-dependent content that actually differentiates the modes ('context` or `assignment`' for schema-free, 'each `assignment`' for independent). Mode-driven schema differences remain covered by the surrounding parameter-bullet assertions.
- Removed example and verbose description metadata from many debug tool schema properties while preserving field types and names.
- Simplified Enum declarations for `action` and `access_type` by using direct enum lists.
- Normalized several numeric and string field definitions in the schema without changing parameter names.
- Added a PROMPT_TASK_LIMIT constant set to 20 in the recipe runner model.
- Updated buildPromptModel to include only the first 20 tasks from each runner when generating prompt tasks.
- Added an optional hiddenTaskCount field to PromptRunnerModel to represent truncated tasks.
- Added a `/context` slash command flow from registry to interactive-mode command dispatch.
- Added `handleContextCommand()` to the mode context interface and command-controller wiring.
- Added context usage breakdown utilities, cell allocation, and 20x10 usage rendering for token categories.
- Reworked compaction token estimation to use tokenizer counts, role aggregation, image token estimates, and fallback handling.
- Exported `resolveThresholdTokens()` as a public compaction helper.
- Allowed bare `LidA..LidB` to recover a missing-range-delete typo and accepted `|` as a legacy range replacement separator while validating ranges and replacement text.
- Enabled indented hashline statements to parse as replacement edits and added a preflight pass that validates all atom sections before any file write occurs.
- Updated hash-mismatch messaging, prompt wording, and tests to reflect hash-only rebase candidates and the new range/section behaviors.
- Updated the Atom grammar to parse replacement blocks via a set block rule that no longer targets range replacements only.
- Extended continuation preprocessing to allow backslash lines after single-line replace operations (including legacy `@` and `|` forms) while preserving the active-replacement check.
- Added tests and prompt documentation for single-line continuation cases and for rejection of backslash-like text outside an active replacement.
- Added `with_text` to keep minimized output byte counters consistent when replacing output text.
- Wrapped successful pipeline and overlay minimizer results with a post-step that emits `OK\n` when the transform empties output on success.
- Added tests to confirm successful empty-output minimization becomes `OK\n` and failures keep empty output.
- Added atom edit support for Lid ranges, before-anchor inserts, and no-op Lid=TEXT success handling.
- Expanded hashline recovery to scan shifted hashes, match unique alternates, and emit ±5 anchor-shift hints.
- Added edit failure categorization with per-category counts, percentages, and detailed report lines.
- Added regression coverage for shifted-hash recovery, range continuation, cursor shorthand, and split-file atom ops.
- Resolved recipe operations now return a command plus optional working directory, and the shell tool path forwards both values when executing.
- Updated the package runner to assign task-local `cwd` entries for workspace scripts instead of embedding workspace command prefixes.
- Adjusted renderer wiring and tests to use the new `cwdFromOp` helper and assert task object shapes with preserved `cwd` values.