Extensions calling ctx.ui.addAutocompleteProvider (e.g. @ff-labs/pi-fff)
crashed at load with 'TypeError: ... is not a function' because omp's
ExtensionAPI.ui omitted pi's autocomplete-provider API; the throw also
aborted the rest of a try/catch-guarded session_start init.
ExtensionUIContext now declares addAutocompleteProvider(factory).
Interactive mode stacks each factory on the built-in editor provider in
registration order, re-applies the stack on every slash-command refresh,
and skips throwing/malformed factories; RPC, ACP, and headless contexts
accept the factory as a no-op, matching upstream pi's RPC behavior.
Fixes#4919
Extension sendUserMessage() without deliverAs fell through to prompt(),
which throws AgentBusyError during an active stream; the message was
dropped and surfaced as 'Extension sendUserMessage failed'. Route the
omitted-deliverAs path through prompt() with streamingBehavior 'steer'
so streaming queues a steer with normal prompt-flow side effects
(keyword notices, advisor auto-resume reset) and idle still starts a
turn.
ACP skill-command prompts now pass streamingBehavior 'steer'; the RPC
skill fast-path honors the prompt command's streamingBehavior field
(default steer) like the plain-prompt path already did. Documented the
extension-facing delivery semantics.
Synthesized from PR #4942 (prompt-flow steer routing, docs, tests) and
PR #4922 (RPC streamingBehavior threading, steer regression test);
dropped PR #4942's unrelated workflow-notice.md ellipsis churn.
Fixes#4923
Co-authored-by: roboomp <omp@can.ac>
Co-authored-by: metaphorics <metaphorics@users.noreply.github.com>
- Added `onTurnError` hook to `AdvisorRuntime` to handle failed turns before retries.
- Integrated credential blocking in `AgentSession` to prevent retrying usage-limited accounts when advisor turns fail.
- Included account key in `codex-auto-reset` debug logs to improve skip reason visibility.
Drained pending IRC asides before parking irc wait so replies that arrive between wait calls are returned instead of being treated only as queued interrupts.
Added regression coverage for the already-aborted queued-IRC signal path and documented the fix in the coding-agent changelog.
Fixes#4657
Reset per-turn maintenance counters before IRC wake prompts so yielded subagents do not carry stale yield termination into later wake turns.
Add regression coverage for empty-stop retry after an IRC wake following a yielded run.
Fixes#4658
- Allowed implicit default fallback resolution when other role fallback chains are configured.
- Covered the mixed-role first-run fallback case.
Fixes#4533
Rebuilt active advisor runtimes when modelRoles.advisor changes so live sessions stop using stale advisor models.
Added regression coverage for advisor role updates reaching the live advisor without a manual /advisor restart.
Fixes#4612
`#resolveAdvisorRuntimeDescriptors` hardcoded `ThinkingLevel.Medium` when
no thinking suffix was configured. For reasoning models with no
controllable effort surface (`devin-agent`: `reasoning: true`,
`thinking: undefined` — Cascade selects effort by routing to sibling
model ids, not a wire param), that default tripped
`requireSupportedEffort` on the first advisor prompt with an empty
`Supported efforts:` list, disabling the advisor session-wide.
Route the default through `resolveThinkingLevelForModel(model, level)`
which preserves explicit `off`, clamps a concrete effort into the
model's supported range, and returns `undefined` for reasoning models
without controllable efforts — falling back to `Inherit` so no effort is
sent while reasoning stays enabled. Matches the `auto`-path fix
(`clampAutoThinkingEffort`) and the Autonomous Memory clamp
(`clampThinkingLevelForModel`).
Fixes#4579
`plan.defaultOnStartup` records a `mode_change` before the composer restores its draft; without this the draft-cleanup arm check treats the file as durable and the metadata-only JSONL leak reappears for default-plan sessions.
Added a regression case that drives a model_change + mode_change + draft-clear cycle and asserts the session file is dropped on close().
Fixes#4571
Limit empty-session close cleanup to files whose draft sidecar lifecycle
materialized an otherwise startup-metadata-only session. Direct
ensureOnDisk() callers now remain discoverable even when they have no
user/assistant messages yet, and handoff custom_message entries survive
close before the next user turn.
Added regression coverage for resumed draft cleanup, ACP-style explicit
ensureOnDisk() records, and handoff custom messages.
Fixes#4571
`SessionManager.saveDraft(text)` calls `ensureOnDisk()` so the draft
sidecar has a parent JSONL. A follow-up `saveDraft("")` only unlinks
the sidecar — the session file was left behind, and `#shouldHaveSessionFile()`
could not prune it once the load path latched `#fileIsCurrent` and
`#forceFileCreation` to true. Each draft-then-clear-then-exit cycle
leaked a ~500–750 B zombie into `~/.omp/agent/sessions/<cwd>/`
containing only the title slot, session header, and a handful of
`model_change`/`mode_change`/`thinking_level_change` entries.
`close()` now calls `#dropIfEmptyAndNoDraft()` after draining the
writer: when the file exists, holds no user/assistant messages, and
no draft sidecar is present, it removes the session file and its
artifacts directory via `deleteSessionWithArtifacts`. Real conversations,
sessions with a saved draft still on disk (needed for `--resume`), and
never-materialized sessions are untouched.
Fixes#4571
TTSR stream-interrupt aborts now carry a per-tool reason so the placeholder
loop labels only the tool call whose stream matched the rule with the rule
name and gives sibling committed tool calls a neutral "TTSR interrupt on
another tool call" reason. Previously the single `message.errorMessage`
was stamped onto every retained tool-call block, so unrelated read/edit
calls read as violating a rule they never matched and misled the model's
own reasoning about which call fired.
Threads the matched `toolcall:<id>` extracted from the TTSR match context
through `agent.abort(...)` as a `ToolScopedAbortReason` object; the agent
loop unwraps it in `emitAbortedAssistantMessage` into a
`toolCallAbortMessages` map on the aborted `AssistantMessage`, and the
`stopReason === "aborted"` fanout in `runAgentLoop` prefers the per-tool
message when one exists.
Fixes#2783
- Treated the active model as the default retry primary when only retry.fallbackChains.default is configured.
- Covered the first-run case where modelRoles.default is unset but a default fallback chain exists.
Fixes#4533