Threshold-driven auto-compaction with strategy=shake auto-continued even when
the shake reclaimed nothing material, and the next agent turn re-triggered the
same shake (which had nothing new to drop on a second pass), spinning forever.
After shake completes, recompute the post-shake context estimate; when it
still exceeds the auto-compact threshold (or shake reclaimed nothing on overflow
recovery), emit a one-shot fallback warning and hand off to the summarization
driven context-full path so progress actually resumes. Idle is exempt — its
60s+ timer self-throttles and cannot dead-loop on its own.
Fixes#2119
Skill prompt custom messages now scan user-authored skill args for magic keywords and turn budgets, matching normal prompt steering behavior without scanning skill body text.
Added a regression test for workflowz and hard turn-budget args on skill prompts.
Fixes#2128
- Introduced filterInitialToolsForDiscoveryAll() to centralize tool filtering when discovery mode is "all", replacing inline logic in createAgentSession.
- Added forceActive parameter to ensure tools required by forced tool_choice features (e.g., eager todo) remain active in the request, preventing provider 400 errors.
- Updated eager todo enforcement to check active tool set instead of registry, ensuring it respects tool discovery hiding.
- Derived device_id from both install id and account UUID via v2 hash domain.
- Fell back to v1 install-only hash when no account UUID is present.
- Threaded account UUID through Anthropic metadata user_id resolution.
- Normalized image-content preprocessing in agent sessions now returns early when `content` is missing or not a string/array, avoiding invalid normalization paths.
- Updated agent-loop tests to verify partial tool calls are dropped when an assistant aborts before `toolcall_end`, with run completion reported via an assistant `stopReason` of `aborted`.
- Adjusted Anthropic alignment expectations to reflect a single trailing cache-control breakpoint on the final system block.
- Added astCondition to rule frontmatter parsing and rule metadata, with AST-grep normalization.
- Updated TTSR bucketing so astCondition-only rules are treated as interruptible matches.
- Added ts-redundant-clear-guard as a built-in JS/TS tool rule for guarded clear* calls.
- Added AST snapshot matching in agent sessions with per-stream cache throttling and cleanup.
- Removed `maxToolCallsPerTurn` from `AgentOptions`, `AgentLoopConfig`, and config serialization.
- Removed stream-loop cap enforcement, including the `toolcall_end` abort path and capped assistant messages.
- Removed Anthropic Opus 4.8 batch-cap resolver and agent-session sync logic from coding-agent.
- Updated tests and changelogs to align with uncapped tool-call behavior and dropped cap-specific cases.
- Introduced `AsideMessage` as a message-or-thunk union so aside providers can defer injection decisions.
- Updated agent loop handling to resolve aside thunks at injection time and skip entries that returned `null`, then switched the session yield queue to `drainLazy` for deferred message building.
- Added tests validating lazy aside evaluation and staleness-aware dropping when everything becomes stale after dequeueing.
- Added a new aside-message source on `Agent` and exposed it in `AgentLoopConfig` as `getAsideMessages`.
- Updated the agent loop to poll aside messages after tool batches and before yielding, merging them with follow-up messages before continuing.
- Changed coding-agent session and yield queue handling to pull queued background messages via `drainMessages` at step boundaries instead of streaming-only injection.
- Added first-party-first provider priority defaults for model ranking.
- Consolidated model resolution to use getModelMatchPreferences from session settings.
- Prioritized providerPriorityRank ahead of usage rank when picking preferred models.
- Added second-pass fallback to default-model or API-key-valid matching order.
- Updated task call and result rendering to process shared context with the Markdown renderer, so context sections are now displayed with proper Markdown formatting.
- Stopped shimmer animation on pending bash/eval/task blocks once async state is `running`, preventing the committed frame from freezing a transient dark border segment.
- Adjusted rule path display to fall back to a root-relative path when cwd-relative resolution is unavailable.
- Updated InputController streaming submit handling to interrupt and resume when queued steering exists, refreshing the pending-message UI and render.
- Added AgentSession.interruptAndFlushQueuedMessages to abort active work and continue processing queued messages immediately.
- Added tests for queued steering interruption in both agent-session concurrency and input-controller keybinding flows.
- Passed a formatted TTSR match message into the agent abort call when streaming is interrupted by TTSR rules.
- Added a `#formatTtsrAbortReason` helper to include matched rule names in the abort reason.
- Added a concurrent-session test confirming aborted tool results mention the matched TTSR rule instead of `Request was aborted`.
- Added `/tan` slash command registration and interactive handling.
- Added TanCommandController validation and async task scheduling for `/tan` dispatch.
- Added session cloning that suppresses breadcrumbs, copies artifacts, and handles abort cleanup.
- Added `promptCacheKey` support in Agent and inherited `providerPromptCacheKey` in session creation.
- Added optional `reason` parameters to `Agent.abort` and `AgentSession.abort` APIs.
- Passed abort reasons through interrupt flows into underlying agent cancellation.
- Replaced hard-coded abort text with `resolveAbortLabel` for streaming and replayed messages.
- Fell back to generic `Request was aborted` text when no abort reason was provided.
- Added `AgentSession.freshSession()` to rotate provider-facing IDs and prune provider stream state.
- Added `/fresh` command handling in the builtin registry and mode command flow.
- Kept persisted session metadata intact during `/fresh` and cleared transient IDs on session switches.
- Invalidated `appendOnlyContext` and provider caches when refreshing provider state.
- Lazy-loaded OTEL SDK, HTML export, TTSR, and autoresearch modules.
- Made resolveMemoryBackend async to import backends on demand.
- Replaced backend resolution with direct settings reads for rekey checks.
- Made "auto" the default, hiding MCP tools past 40-tool threshold.
- Centralized discovery mode resolution in shared mode helper.
- Activated search tool in createAgentSession once full registry exists.
When Anthropic Claude returns stopReason: "toolUse" but the assistant
message contains no actual toolCall, the session would append a spurious
toolResult entry. This creates tool_result blocks without matching
tool_use blocks — structurally invalid for Anthropic's API validator.
The symptom is overloaded_error on every subsequent request (in: 0 out: 0),
even though servers aren't overloaded. Other providers handle the same
corrupted history more leniently, making the problem appear Anthropic-specific.
The #isEmptyAssistantStop guard now checks for stopReason === "toolUse"
with no text and no toolCall. When the retry cap is hit, tool-use orphans
are still removed from active context (unlike regular empty stops) because
they corrupt message history. A regression test covers both the retry and
cap scenarios.
For affected sessions: run /compact to drop the corrupted history tail.
Fixes review feedback from chatgpt-codex-connector.
Add retry.modelFallback so users can keep automatic retry enabled while preventing retry recovery from switching through configured fallback model chains.
The default remains enabled, preserving existing fallback behavior. When disabled, retry still honors retry-after delays and retry limits while staying on the primary model.
Op: correct
Restores: spec:retry can stay enabled without automatic model switching
AgentSession now stores the same scoped AsyncJobManager reference that tools receive: owning top-level sessions use their constructed manager, subagents inherit the parent's manager, and secondary in-process top-level sessions get no manager when a singleton is already live.
getAsyncJobSnapshot and ACP delivery drains now use that scoped manager instead of AsyncJobManager.instance(), so secondary sessions cannot report or drain the primary session's background jobs. The regression test covers a secondary session created while the primary has a Main-owned running job.
Any in-process secondary createAgentSession() (e.g. the Agent Control Center's create flow in agent-dashboard.ts) was constructing its own AsyncJobManager, overwriting the process-global singleton, and then clearing it on its own dispose. The primary session still held its #ownedAsyncJobManager reference, but AsyncJobManager.instance() was undefined for the rest of the process — the task async path hard-failed with "Async execution is enabled but no async job manager is available" and only a full restart cleared it.
- sdk.ts: skip constructing/installing a second AsyncJobManager when a singleton is already live, so secondary top-level sessions share the owning session's manager instead of clobbering it.\n- agent-session.ts: scope #cancelOwnAsyncJobs so a secondary session inheriting the singleton with the default MAIN_AGENT_ID can no longer cancel the primary session's running bash/task jobs at dispose time. Subagents still reach the inherited singleton via their unique agent ids; the owning session still cancels its own jobs through #ownedAsyncJobManager.
Fixes#1923
- Stopped leaking absolute home directory to the model in ttsr-interrupt and ttsr-tool-reminder blocks.
- Rendered rule paths as cwd-relative in-project, `~`-relative under home, else raw.
Mid-session edits to hindsight.bankId / bankIdPrefix / scoping kept the
active HindsightSessionState pinned to the bank selected at session
start, so retain/recall/reflect calls landed in the stale bank. Settings
hooks now fire onHindsightScopeChanged; the backend rebuilds the
primary state against the recomputed scope, disposing the previous one
after flushing its queue so queued tool-initiated retains still land in
the bank they were enqueued for.
Also:
- Renamed ensureBankMission to ensureBankExists. The old version
skipped creation entirely when bankMission was blank, so the first
mental-model POST (auto-seed) could land against a never-PUT bank.
Bank creation is now idempotent and unconditional, and runs before
mental-model bootstrap.
- Fixed AgentSession.dispose to flush the retain queue BEFORE clearing
the session state pointer. Reversed, HindsightRetainQueue.#doFlush's
identity guard would see the cleared pointer and drop the spliced
batch with a 'session vanished' warning.
- Snapshotted hindsightScopeCallbacks before iterating because each
rebuild subscribes a fresh callback inside the same fire; iterating
the live Set would spin.
Fixes#1902
- Marked steering user messages and wrapped them pre-LLM so the model sees a `` envelope.
- Kept transcripts and persisted history with the user's original raw text.
- Restored `AssistantMessageComponent` stable-prefix completion API.
- Registered and triggered a session-switch reconciler during init and after switch.
- Rebuilt resume flow to restore plan/goal mode state and clear stale mode flags.
- Marked fallback and context-promotion model switches ephemeral and skipped them on restore.
- Added regression tests for temporary model ordering, fallback precedence, and mode cleanup.
Centralized append-only context auto-mode resolution so SDK sessions, interactive sessions, and the status display use the same provider checks. Auto mode now enables for Xiaomi/SGLang hosts and explicit stored-request compat signals while preserving DeepSeek behavior.
Added focused regression coverage for Xiaomi Token Plan SGLang HiCache endpoints and explicit on/off behavior.
Fixes#1851
- Renamed `TodoWriteTool` to `TodoTool` and its source/prompt files.
- Updated tool registration, schema, renderers, and gating to `todo`.
- Adjusted cursor provider native tool names and tests to match.
- Renamed strike-animation constants and `todo-error-reminder` type.
- Added shared `getReadToolPath` API to extract paired read `path` values for protection matchers.
- Added `createPlanReadMatcher` and session wiring so compaction prune/shake keeps active plan reads intact.
- Updated `todo-write` instructions to initialize every user-supplied plan item as an individual task.
- Added compaction tests validating plan reads are protected from prune and shake while regular reads are still removable.
- Added optional `AgentTool.matcherDigest(args)` hook so tools can expose plain source text instead of wire-encoded arguments to TTSR rule matchers.
- Implemented `matcherDigest` on edit (all modes: hashline, patch, apply_patch, replace) and write tools, stripping patch prefixes and JSON escaping.
- Added `TtsrManager.checkSnapshot()` to replace the scoped buffer with a tool digest rather than appending raw deltas.
- Fixed TTSR conditions never matching streamed edit/write calls whose wire format obscured real content.
- Added `parseClaudeRateLimitHeaders` to extract 5h/7d utilization from `anthropic-ratelimit-unified-*` response headers.
- Added `AuthStorage.ingestUsageHeaders` to warm the per-credential usage cache from headers, throttled to 60s per key.
- Merges header-derived limits onto the last full usage report, preserving per-tier data not present in headers.
- Wires ingestion into `AgentSession` on each Anthropic response to reduce direct OAuth `/usage` probes.
- Derived Anthropic and session metadata `device_id` from `getInstallId()` deterministically.
- Added CLAUDE bootstrap identity lookup and merged fallback into token exchange/refresh.
- Recovered `accountId` and `email` during token exchange/refresh when token payloads lacked them.
- Enforced bootstrap failures for non-OK responses and invalid JSON payloads.
Try the last active role model first, then the saved default model when the role model cannot be restored during session switching or startup resume.\n\nFixes #1649