Commit Graph
798 Commits
Author SHA1 Message Date
can1357 1b458f2e61 fix(coding-agent): preserved teardown exit reasons during session disposal
- Thread the postmortem reason through the session teardown pipeline to the session dispose process.
- Prevent generic "dispose" logs from overwriting real triggers like SIGTERM, SIGHUP, or uncaught exceptions.
- Ensure the first teardown trigger's reason is preserved when concurrent disposal calls occur.
- Add comprehensive test coverage verifying signal-specific reason mapping inside exit diagnostics.
- Fix a minor unhandled-exception test utility expectation in input controller tests.
2026-07-02 01:51:10 +02:00
can1357 73ef29bd00 fix(session): corrected branch traversal order breaking ctrl+p cycling
- Removed a duplicated branch.reverse() left by the PR #3862 merge in
  SessionEntryIndex.pathTo(), which returned branches leaf-to-root and made
  getLastModelChangeRole() read the oldest model change instead of the
  newest — pinning the ctrl+p cycle to one slot and breaking session model
  restore.
- Hardened getRoleModelCycle() to trust the recorded role only while its
  resolved model still equals the active model, falling back to matching by
  model after switches through alt+m, /model, or retry fallback.
- Added mutation-verified regression tests for branch ordering and the
  stale-role fallback.
2026-07-01 23:48:26 +02:00
can1357 1bf06d9cec Merge PR #3640 (selective): advisor inherits main agent promptCacheKey (@roboomp)
Ports only the advisor cache-key fix (advisorPromptCacheKey = agent.promptCacheKey ?? advisorSessionId) + its provider-options parity regression. tan/shared sessions read the parent provider cache shard byte-for-byte. Excludes the unrelated CI-isolation test commit e3160a09c. Fixes #3639.
2026-07-01 22:34:13 +02:00
can1357 2e53c40c9e Merge PR #3412 (selective): clamp compaction reserve budget for small windows (@wolfiesch)
Cherry-pick of the reserve-budget clamp only (resolveBudgetReserveTokens + no-op compaction guard): applies compaction.ts + agent-session.ts + compaction/shake/progress-guard tests. Excludes unrelated Julia prelude timeout and ai/test churn from the PR head.
2026-07-01 22:29:53 +02:00
can1357 a5a7b5b77c fix(coding-agent): limit mnemopi shutdown timeout to interactive exit 2026-07-01 22:22:09 +02:00
roboompandcan1357 efaad3ffb5 fix(coding-agent): bounded mnemopi consolidate-on-dispose so /quit returns within ~2 s
/quit and /exit hung for many seconds because AgentSession.dispose()
awaited MnemopiSessionState.dispose() unconditionally, and that path
runs consolidate() (state.ts:421) which fires a fresh LLM fact
extraction for the just-retained transcript and then awaits
flushExtractions() per owned bank. One LLM round-trip per shutdown,
no upper bound, no visible status.

- Add a timeoutMs option to MnemopiSessionState.dispose. When the cap
  fires the in-flight consolidate is detached to the background and the
  SQLite handles close once it settles, so writes never race a closed
  handle.
- AgentSession.dispose passes SHUTDOWN_CONSOLIDATE_BUDGET_MS = 1_500 on
  the user-visible shutdown path. Per-turn maybeRetainOnAgentEnd has
  already retained earlier turns, so the worst case is losing episodic
  promotion for the last few turns. State-replacement disposes
  (mnemopiBackend.start) stay unbounded.
- InteractiveMode.shutdown surfaces a 'Closing session…' status before
  dispose runs so the brief pause is explained rather than mysterious.

Two regression tests in memory-tools.test.ts cover (1) dispose returns
within the budget when flushExtractions stalls and the deferred close
still runs once consolidate settles, and (2) unbounded dispose still
runs the full #2320 consolidate-then-close pipeline.

Fixes #3641
2026-07-01 22:18:44 +02:00
can1357 9403df1abd fix(session): avoid empty exit-marker sessions 2026-07-01 21:55:01 +02:00
can1357 b8ae1e21b1 Merge PR #2607: fix(session): detected pending tool calls without toolUse (@roboomp)
# Conflicts:
#	packages/coding-agent/src/session/agent-session.ts
2026-07-01 21:55:01 +02:00
can1357 569b83d5a6 Merge PR #4166: fix(agent): preserve approved plan path (@roboomp) 2026-07-01 21:53:19 +02:00
can1357 021d4fc1e3 Merge PR #4161: fix(agent): interrupt waits for IRC delivery (@roboomp) 2026-07-01 21:53:19 +02:00
can1357 debe71ae0e Merge PR #4129: fix(coding-agent): preserved explicit :auto suffix in modelRoles (@roboomp) 2026-07-01 21:53:17 +02:00
can1357 1479b689d8 Merge PR #4121: fix(coding-agent): route SIGTERM/SIGHUP/uncaughtException through session teardown (@roboomp) 2026-07-01 21:53:16 +02:00
can1357 9ae2b48b10 Merge PR #4077: fix(agent): add retry path diagnostics (@roboomp) 2026-07-01 21:53:14 +02:00
can1357 826517dc69 Merge PR #3969: fix: preserve bash cwd without hidden pwd probe (@jeffscottward) 2026-07-01 21:50:54 +02:00
can1357 b3b4a762ac Merge PR #3736: fix(coding-agent): replan title refresh honors TITLE_SYSTEM.md override (@roboomp) 2026-07-01 21:42:25 +02:00
can1357 97b72df087 fix(coding-agent): reset mid-run todo counter after stop reminder 2026-07-01 21:42:24 +02:00
can1357 2d734f65c4 Merge PR #3652: fix(coding-agent): nudge todo reconciliation mid-run instead of only at stop (@roboomp) 2026-07-01 21:42:23 +02:00
roboomp 6cd93546cb fix(agent): preserved approved plan path
Approved plan execution now requires reading the durable local plan file instead of embedding the plan body in synthetic execution prompts. This keeps execution recoverable when Headroom-compressed inline content expires.

Fixes #4164
2026-07-01 17:19:20 +00:00
roboomp f8241aee9d refactor(irc): moved parent IRC steer text into a prompt file 2026-07-01 17:08:49 +00:00
roboomp 619bfda3eb fix(agent): interrupted irc waits
Fixes #4160
2026-07-01 16:56:08 +00:00
roboomp 9f3e648e5a fix(coding-agent): gated :auto suffix behind allowAutoAlias
Follow-up on the review: the widened parseThinkingSuffix recognized :auto unconditionally, so parseModelString and extractExplicitThinkingSelector would silently strip a literal provider/model:auto id before the isLiteralModelId guard the :max path already uses.

- Add allowAutoAlias option and require callers to opt in, mirroring allowMaxAlias.

- MAX_THINKING_SUFFIX_OPTIONS enables both aliases; parseModelPatternWithContext still tries exact match first, so a real :auto id wins there too.

- sdk.ts (session restore x2), agent-session.ts (retry fallback selector, context-promotion/compaction targets), and model-registry.ts (normalizeSuppressedSelector) now pass allowAutoAlias: true alongside allowMaxAlias.

- Regressions: literal example/runtime:auto wins over the sentinel in parseModelPattern, parseModelString (with and without isLiteralModelId), resolveModelFromString, and extractExplicitThinkingSelector; auto is still extracted when the id isn't literal.
2026-07-01 08:30:58 +00:00
roboomp a4ae4c130c fix(coding-agent): preserved explicit :auto suffix in modelRoles
The model selector's persistence path dropped the `:auto` selector when parsing role values, producing a warning ('Invalid thinking level "auto"') and rendering the badge as `inherit` instead of `auto`. Reload of the default role also lost the auto state whenever the role value carried an explicit `:auto` suffix instead of relying on `defaultThinkingLevel`.

Widen the resolver chain (`parseThinkingSuffix`, `splitThinkingSuffix`, `parseModelString`, `parseModelPattern*`, `ResolvedModelRoleValue`, `ResolvedRoleModel`, `ResolveCliModelResult`) to carry the `AUTO_THINKING` sentinel end to end, and coerce it back to `undefined` at concrete-only boundaries (glob scope patterns, retry fallback, advisor, commit pipeline, guided-goal, bench).

Regression tests cover:

- `resolveModelRoleValue("provider/model:auto")` returns explicit auto without a warning.

- `ModelSelector` renders `DEFAULT (auto)` and `SMOL (auto)` when the role value has `:auto`.

- `cycleRoleModels` activates auto thinking on entering a `:auto` role.

- Startup resume activates auto thinking when `modelRoles.default` carries `:auto`.

Fixes #4128
2026-07-01 08:18:42 +00:00
roboomp 73a12c7ea2 fix(coding-agent): routed SIGTERM/SIGHUP/uncaughtException through session teardown
The postmortem SIGTERM/SIGHUP/uncaughtException handlers only ran the registered
cleanup callback list before process.exit, and the only session-related callback
was session-manager-flush. So a real kernel signal (terminal close, process
manager killing omp, IDE stop) skipped saveDraft, session.dispose (session_shutdown
emit, owned async job disposal, kernel disposal, MCP disconnect, browser tab
release), and violated the SessionShutdownEvent docstring contract that promises
delivery on SIGINT/SIGTERM. The LSP client also owned its own SIGINT/SIGTERM
handlers that called shutdownAll then process.exit(0), which could race postmortem's
async runCleanup and short-circuit the session teardown.

- Extracted a promise-memoized createSessionTeardown helper (modes/session-teardown.ts)
  that snapshots the editor draft, persists it via sessionManager.saveDraft, then
  invokes session.dispose. A saveDraft failure is logged but never aborts disposal.
- Memoized AgentSession.dispose so the keypress path and the signal path share one
  settled promise and cannot double-emit session_shutdown or double-drain the owned
  AsyncJobManager.
- Registered the teardown on postmortem as "session-teardown" in InteractiveMode.init,
  replacing the narrower session-manager-flush callback. InteractiveMode.shutdown
  now delegates the draft+dispose steps to the same helper.
- Replaced the LSP client's SIGINT/SIGTERM handlers with a "lsp-shutdown" postmortem
  callback so LSP cleanup runs alongside every other session teardown instead of
  racing them via process.exit(0). beforeExit is unchanged.
- Added session-teardown.test.ts covering: draft-then-dispose ordering, disposal
  after saveDraft rejects, empty-string clears stale sidecar, promise memoization
  under concurrent invocation, and snapshot-at-first-call semantics.

Fixes #4080
2026-07-01 07:19:30 +00:00
roboomp 9009d5b8f7 fix(agent): added retry path diagnostics
Logged assistant-tail removal outcomes and scheduled continuation state for transient retry failures.

Fixes #4070
2026-07-01 06:55:03 +00:00
Jeff Scott Ward 3da25618ea fix: preserve bash cwd without pwd probe 2026-06-30 23:51:28 -04:00
can1357 ef7636805b feat(coding-agent): removed canonical model variant selection and tracking
- Removed the canonical model variant indexing, selection, and tracking logic from the model registry and resolver.
- Eliminated the `canonical` sub-command, tab view, search tokens, and equivalence configuration structures from the CLI and model selector components.
- Refined model identification, lookup, and provider fallback resolution to bind exclusively to standard, raw model IDs.
- Relocated the equivalence utility script within the catalog package to support script-only policy generation.
2026-07-01 05:22:42 +02:00
can1357 8e8c3e92ce Merge remote-tracking branch 'origin/farm/e0aafd27/cross-turn-tool-call-loop-guard' 2026-07-01 05:08:41 +02:00
roboomp cf52840c18 fix(agent): detected repeated tool-call turns
Added a cross-turn tool-call loop guard that hashes canonical tool names and arguments, ignores intent metadata, and injects a hidden redirect when identical calls reach the configured threshold.

Fixes #3971
2026-07-01 02:47:08 +00:00
roboomp dff941d5fe fix(coding-agent): preserved bash status while syncing cwd
Propagated the native shell working directory in ShellRunResult so AgentSession can refresh cwd without running a hidden pwd command in the persistent shell.

Added regression coverage for cd plus a failing command followed by echo $?, proving cwd sync no longer overwrites the user's last shell status.

Fixes #3958
2026-07-01 02:27:05 +00:00
roboomp 19b85bca70 fix(browser): reap Chromium/Puppeteer on aborted open and session dispose
Two termination boundaries in the browser tool leaked browser-owned OS resources into the long-lived coding-agent process.

1. Aborted 'open' published an orphan. #open wrapped acquisition in untilAborted, which rejects its outer wrapper on abort but lets the inner launch resolve in the background; acquireBrowser then unconditionally stored the resolved handle in the module-global browsers map. releaseAllTabs walks tabs, not browsers, so the refCount:0 handle stayed alive to process exit.

2. Session dispose had no browser teardown. Browser/tab state lives in module-global maps, and AgentSession.dispose() had no hook to walk them, so headless/spawned Chromium the session opened survived it.

acquireBrowser now short-circuits before launch on a pre-aborted signal and disposes the handle when the launch completes after abort. TabSession records the creating session's id (opts.ownerSessionId, threaded through BrowserTool.#open), preserved across reuse so a subagent re-driving an existing tab does not yank teardown responsibility. AgentSession.dispose() invokes releaseTabsForOwner bounded by withTimeout(3s), mirroring the async-job/MCP disposal pattern.

Regression tests exercise both boundaries via spied CmuxSocketClient (no real puppeteer/socket) and cover: pre-aborted open short-circuit, aborted-mid-launch cleanup, releaseTabsForOwner reaping only owned tabs, and reuse preserving original ownership.

Fixes #3963
2026-07-01 02:09:04 +00:00
roboomp 66a9667cc1 fix(coding-agent): synced bash cwd after cd
Updated interactive bash execution to query the persistent shell PWD after commands and move the session cwd when it changes, keeping the status line and session-scoped settings aligned with shell navigation.

Added regression coverage for syncing persistent shell directory changes back to the owning session.

Fixes #3958
2026-07-01 01:43:37 +00:00
can1357 3c012a6c54 Merge remote-tracking branch 'origin/farm/a3e74c54/preserve-auto-model-thinking' 2026-06-30 17:54:52 +02:00
can1357 3aa47d2ab9 fix(coding-agent): matched persisted messages by key identity during mid-run compaction
- Replaced the map-based persisted message index with a Set of key identities.
- Removed the message content equality check during branch verification to avoid false out-of-order skips when display-side content variants are present.
2026-06-30 17:44:09 +02:00
can1357 6b7d7e6e7e feat(coding-agent): injected loop-guard redirect notices during thinking loop retries
- Added a hidden system notice prompt to instruct the model to break repetitive behaviors when a thinking or response loop is detected.
- Injected the redirect notice into the retried turn's context when resetting the active context after a loop retry.
- Added unit tests to verify the custom redirect message is appended, configured as non-displaying, and visible in subsequent LLM contexts.
2026-06-30 16:36:49 +02:00
roboomp 51da3add83 fix(coding-agent): preserved auto thinking across plan approval
Captured the configured thinking selector when entering plan mode so approving a plan restores auto instead of the provisional concrete effort. Reloaded DEFAULT(auto) badges from defaultThinkingLevel and covered the plan-approval handoff plus /model display.

Fixes #3901
2026-06-30 14:28:07 +00:00
can1357 5b026d304f fix(coding-agent): recovered from auto-compaction dead-ends using shake elisions
- Added a last-resort recovery step to run `shake("elide")` on oversized message tails when auto-compaction cannot otherwise free enough context.
- Re-tests the context headroom and auto-continue predicates after a successful rescue before falling back to pausing maintenance.
- Updated the dead-end warning message to suggest running `/shake images` for irreducible, image-only tails.
2026-06-30 10:48:04 +02:00
can1357 fc24a70f5e Merge branch 'farm/ad81bc64/retry-anthropic-internal-server-error'
fix(compaction): cap snapcompact frame payloads (#3866)

Bound rebuilt snapcompact image payloads by a per-request base64 byte
budget so long sessions stop re-sending multi-megabyte standing image
archives on every provider request; auto-compaction falls back to
context-full summaries when snapcompact output is too large.

Resolved snapcompact.ts conflict against the main font-rendering refactor
by keeping both renderabilityProbeText and the frame-budget helpers.
Fixed historyBlocks to emit the omitted-frame notice before the kept
(newer) images, since the byte budget drops the oldest frames — keeping
reconstructed blocks oldest-to-newest (addresses Codex P2 review).

Fixes #3792
2026-06-30 09:59:03 +02:00
roboomp 156dfd8467 fix(compaction): capped unknown-window snapcompact frames
Apply the snapcompact frame byte-budget cap even when the active model has no known context window, avoiding 80-frame archives on custom vision models.
2026-06-30 05:43:17 +00:00
roboomp 88308f105f fix(compaction): capped snapcompact frame payloads
Bounded persisted snapcompact image archives by base64 byte size so large sessions stop re-sending multi-megabyte frame walls on every provider request.

Auto snapcompact now falls back to context-full summaries when rendered frame payloads exceed the byte budget, and legacy oversized archives omit over-budget frames during LLM context rebuilds.

Fixes #3792
2026-06-30 05:36:14 +00:00
can1357 d20e6c0829 feat: migrated service tier settings to a per-model-family architecture
- Migrated global service tier settings to a per-model-family architecture (OpenAI, Anthropic, Google).
- Implemented `ServiceTierByFamily` mapping to allow independent configuration and resolution per provider.
- Added automatic migration logic for legacy service tier and fast-mode application settings.
- Updated telemetry, session management, and task execution to support provider-specific tier resolution.
2026-06-30 04:14:48 +02:00
can1357 ea6d9f32c4 merge #3836: surface pending IRC asides in inbox without double-injecting 2026-06-30 03:01:01 +02:00
can1357 5f4af63e30 merge #3847: skip rebuilding previous session context on different-session switch 2026-06-30 03:01:01 +02:00
can1357 242705c06c feat: enabled dynamic font rendering with CJK and unicode support
- Added Silver.ttf TrueType font support to `pi-natives` with automated fallback logic for bitmap font rendering.
- Implemented wide code point detection and cell-width calculation to improve CJK character handling and layout.
- Introduced dynamic font-aware preflight probing via `resolveShapeForText` and `renderabilityProbeText` for better font selection.
- Enabled semantic emoji folding and improved text normalization to handle non-Latin characters and emoji filtering.
2026-06-30 02:49:31 +02:00
roboomp d8bf76dfd6 fix(coding-agent): skipped rebuilding previous session display context on different-session switch
AgentSession.switchSession() eagerly called buildDisplaySessionContext()
before setSessionFile, walking the previous session's branch and expanding
every compaction entry's snapcompact archive and openaiRemoteCompaction
replacementHistory into messages. For huge pre-fix sessions that materialized
GBs of data and OOMed in-TUI /resume even after the streaming loader fix.

The snapshot is only needed for same-session reloads, where
#didSessionMessagesChange compares the pre/post message arrays to detect
rollback edits. Different-session switches skip the call entirely; the
error-recovery path rebuilds the previous context on demand from the
restored state so MCP-selection restoration still has its inputs.

Added a regression test (test/agent-session-switch-prev-context.test.ts)
that spies on sessionManager.buildSessionContext across switchSession and
asserts the expected call count and target file per branch.

Fixes #3846
2026-06-30 00:34:02 +00:00
roboomp 66eba507f5 fix(irc): consumed peeked pending asides to avoid double inject
- Always remove surfaced irc:incoming records from the pending-aside queue; the inbox tool result already injects the body, so leaving them queued would auto-inject a duplicate at the next step.

- Updated the inbox tool to drain pending asides regardless of peek.

- Added a regression test asserting a peeked pending aside does not auto-inject.
2026-06-29 22:29:10 +00:00
roboomp 3104d232aa fix(irc): surfaced pending asides in inbox
- Drained running-session IRC asides through the inbox tool before the model step consumes them.

- Added a regression test for messages delivered while the recipient is already running.

Fixes #3834
2026-06-29 22:21:24 +00:00
can1357 312b71b0a5 feat(sdk): enabled websocket transport configuration for sdk and cli
- Added `preferWebsockets` option to `AgentSessionConfig` to expose transport preferences.
- Updated `AgentSession` to manage and forward websocket preferences to sub-sessions.
- Enabled websocket transport by default for benchmark CLI requests.
2026-06-29 08:05:02 +02:00
can1357 1cde03b6ce Merge remote-tracking branch 'origin/farm/e54ee037/provider-concurrency-semaphore-per-llm-turn' 2026-06-28 23:25:34 +02:00
roboomp 9599689af3 fix(compaction): routed summary oneshots through provider cap
Compaction issued summarization HTTP requests via the default
`completeSimple` transport, bypassing
`wrapStreamFnWithProviderConcurrency` which was only wired into
`Agent.streamFn` / `sideStreamFn`. With the per-LLM-turn bracket
introduced in this PR, multiple ollama-cloud subagents that auto- or
manually compact could issue uncapped summary requests in parallel
and exceed `providers.ollama-cloud.maxConcurrency` (chatgpt-codex
review on #3751).

Added an optional `completeImpl` transport override to
`SummaryOptions` and `GenerateBranchSummaryOptions` and threaded it
into every `instrumentedCompleteSimple` call in compaction +
branch-summarization. Wired `AgentSession.#compactWithFallbackModel`
and the `generateBranchSummary` caller to route through
`#sideStreamFn` — the same limiter-wrapped transport the handoff path
already uses.

Pinned with a coding-agent regression that drives `compact()` end to
end against the wrapped sideStreamFn at maxConcurrency=1 and asserts
peak in-flight stays at 1 across a concurrent unrelated side request.

Fixes #3749
2026-06-28 21:11:48 +00:00
roboomp edaaec398c fix(task): routed side requests through provider cap
Passed the provider-capped stream wrapper into AgentSession side-channel requests so /btw, /omfg, IRC auto-replies, and handoff generation share the same per-provider concurrency limit as normal turns.

Added focused coverage for runEphemeralTurn and handoff generation using the configured side stream function.
2026-06-28 20:57:13 +00:00