- Carried startup-selected fallback role and primary selector into AgentSession.
- Continued remaining role fallback entries after the startup fallback fails.
- Added regression coverage for chained startup failover.
Fixes#6283
Versioned request-header restoration metadata inside v10 cache rows so only markers written by the old id-only matcher can bypass an unrestorable marker through requestModelId. Current aliases whose live headers differ from their static base remain unresolved and are refetched or dropped.
Added catalog and startup-registry regressions for custom-header aliases while preserving legacy Copilot -1m cache recovery.
Fixes#6284
Copilot -1m long-context variants are synthesized with transport
headers and a requestModelId to a bundled base. The v10 cache omits
headers; the writer only matched a same-id static entry, so these
variants were flagged unrestorable and dropped on the next offline
read, vanishing from the picker with a "Could not restore model"
warning. The startup registry loader dropped them the same way.
Restore/match headers through requestModelId in the cache writer, the
model-manager restore path, and the coding-agent startup loader, and
bypass a stale unrestorable marker written by the old id-only writer.
Fixes#6284
- Carried configured role identity through deferred CLI model resolution.
- Consulted ordered authenticated role fallbacks after unavailable primaries.
- Added startup regression coverage for missing primary and fallback entries.
Fixes#6283
resolveCodexDiscoveryAccounts now returns null when any stored Codex OAuth
account fails to resolve (e.g. a transient refresh failure), and the manager's
resolveAccounts callback propagates null to skip discovery. Previously a failed
account was silently dropped before unionCodexModels saw it, so the remaining
accounts were unioned and cached as the authoritative catalog, hiding the
failed account's models for the cache TTL. Aborting keeps the previous/bundled
catalog.
Add a ModelRegistry regression test with one refreshable and one failing Codex
account asserting discovery makes no /models call and bundled models survive.
Fixes#6265
Keep the bearer resolved by the discovery preflight when it is not among the
stored OAuth account resolutions. This preserves Codex discovery for env,
runtime/config override, and stored non-OAuth credential sources while still
unioning all configured OAuth account catalogs.
Add a ModelRegistry regression test that drives runtime-key discovery and
asserts the resolved bearer reaches the Codex models endpoint.
Fixes#6265
Codex catalog discovery resolved a single access token, mapped it to one
chatgpt-account-id, and made one authoritative fetchCodexModels call whose
result pruned bundled entries. With multiple ChatGPT/Codex OAuth accounts,
the visible catalog depended on whichever account the discovery preflight
selected, hiding models available only through a sibling account.
openaiCodexModelManagerOptions now takes a resolveAccounts callback, fetches
each configured account's /models catalog independently, and unions them by
id before the authoritative merge. Bundled models are retained when every
account fetch fails. The runtime wiring resolves every stored openai-codex
OAuth account via AuthStorage.getOAuthAccesses.
Fixes#6265
switchSession (/resume, RPC reload) updates the manager's roots from
the target header but never rebuilt the base system prompt. The next
turn would see the previous session's stale <workspace-roots> block
until an unrelated prompt rebuild happened.
Co-authored-by: oh-my-pi <https://omp.sh>
- main.ts:buildSessionOptions now merges --add-dir with settings
before passing to options.additionalDirectories
- sdk.ts: when options.additionalDirectories is explicitly provided,
uses it as-is (no settings re-merge); falls back to settings only
when not provided
- This prevents removed roots from being re-seeded in subagent sessions
Co-authored-by: oh-my-pi <https://omp.sh>
Setting options.additionalDirectories to undefined wasn't enough:
createAgentSession also merges settings.get('workspace.additionalDirectories').
Now createSubagentSettings gets an override to clear the setting
when worktree is set, ensuring isolated runs can't edit outside the
worktree.
Co-authored-by: oh-my-pi <https://omp.sh>
Isolated tasks clone only cwd into the worktree. Forwarding the
parent's additional directories would let the subagent edit absolute
paths under the original extra roots, bypassing isolation. Now
additionalDirectories is undefined when worktree is set.
Co-authored-by: oh-my-pi <https://omp.sh>
Subagents (task tool) now inherit the parent session's
additionalDirectories via ToolSession → ExecutorOptions →
CreateAgentSessionOptions, so delegated agents see the same
<workspace-roots> block and can read/grep/glob added roots.
Co-authored-by: oh-my-pi <https://omp.sh>
Relative paths in workspace.additionalDirectories settings (e.g.
'../shared') were stored raw in the new-session header instead of
being expanded to absolute. Now all new-session roots go through the
same normalizer used at startup.
Co-authored-by: oh-my-pi <https://omp.sh>
- Add additionalDirectories to NewSessionOptions
- #resetToNewSession now seeds #additionalDirectories from options,
so all new-session transitions (handoff, branch, /new) get the roots
- AgentSession.newSession passes settings dirs via options instead of
calling setAdditionalDirectories after the fact
Co-authored-by: oh-my-pi <https://omp.sh>
- createBranchedSession (/branch, /btw) now copies additionalDirectories
to the new header so branches preserve multi-root state
- forkFrom filters source additionalDirectories against the target cwd
so the new cwd is never also listed as an additional root
Co-authored-by: oh-my-pi <https://omp.sh>
Fixes a crash: createAgentSession passes workspaceTreePromise (a
Promise) as providedWorkspaceTree. The merge path accessed
primary.agentsMdFiles without awaiting, rejecting the system-prompt
prep and falling back to an empty tree.
Co-authored-by: oh-my-pi <https://omp.sh>
- Filter #additionalDirectories when moveTo changes cwd so the new cwd
is never also listed as an additional root (session-manager.ts)
- Build workspace tree for each additional root to discover nested
AGENTS.md files under added roots, merging agentsMdFiles into the
primary set (system-prompt.ts)
Co-authored-by: oh-my-pi <https://omp.sh>
When --add-dir is provided, settings.get('workspace.additionalDirectories')
was skipped entirely. Now both sources are merged so configured default
roots apply to every session even when CLI adds a one-off root.
Co-authored-by: oh-my-pi <https://omp.sh>
- Call refreshBaseSystemPrompt() after newSession so the
<workspace-roots> block reflects the new session's directory set,
not the previous session's stale roots (agent-session.ts)
- Replace inline require('node:os') with top-level import * as os
in test file, following repo convention
Co-authored-by: oh-my-pi <https://omp.sh>
Serialize queued global saves and remove opportunistically persisted roles from the pending set after a successful write when their value has not changed again. This prevents a redundant follow-up save from replaying stale local values over newer external edits.
Expanded the locked-save regression to externally change the same role after the first write and verify flush leaves that newer disk value intact.
restoreState() now syncs #additionalDirectories from the captured
snapshot header, so a failed switchSession (e.g. from a session_switch
hook or model-restore error) doesn't leave the original session with
the target's workspace roots.
Co-authored-by: oh-my-pi <https://omp.sh>
Snapshot model roles when each save starts and merge any newer pending values before replacing the in-memory global settings. This keeps a second model switch intact while an earlier locked save is in flight.
Added a deterministic regression test that blocks the first file-lock operation, changes another role, and verifies both memory and disk.
- Always augment context files with additional root context, even when
createAgentSession passes preloaded contextFiles (system-prompt.ts)
- Merge configured dirs with existing restored roots on resume instead
of replacing them (sdk.ts)
- Copy additionalDirectories from source header in forkFrom so forks
preserve the multi-root set (session-manager.ts)
- Add test for forkFrom preserving additionalDirectories
Co-authored-by: oh-my-pi <https://omp.sh>
Global setModelRole marked the whole modelRoles path modified and
saveNow overwrote the freshly re-read disk record with the stale
in-memory map, clobbering concurrent/external per-role edits despite
the re-read intended to preserve them. Track modified global roles
individually and merge only those into the re-read file, mirroring the
project save path.
Fixes#6260
When additional workspace directories have their own AGENTS.md/rules,
the agent now discovers and injects those context files alongside the
primary cwd's context. This prevents the agent from editing under a
root without seeing the rules that apply there.
Co-authored-by: oh-my-pi <https://omp.sh>
- Seed workspace.additionalDirectories settings on initial launch session,
not just /new (sdk.ts)
- Always call setAdditionalDirectories on /new, even with empty list, to
clear stale roots from the previous session (agent-session.ts)
- Make setAdditionalDirectories async and trigger atomic rewrite when a
session file already exists, so --continue --add-dir persists (session-manager.ts)
- Route addWorkspaceDirectory/removeWorkspaceDirectory through
normalizeWorkspaceDirectory for consistent ~ expansion (session-manager.ts)
- Drop dead exports: workspaceRootForPath (no production callers),
getWorkspace (no production callers), and unused SessionWorkspace type
import from session-manager.ts (session-workspace.ts, session-manager.ts)
- Remove unnecessary as SettingPath / as string[] casts (agent-session.ts)
- Update tests: add ~ expansion coverage, root-clearing on /new,
persistence on resumed sessions, fix header line parsing
Co-authored-by: oh-my-pi <https://omp.sh>
A session now carries an ordered list of workspace directories beyond cwd,
managed live from the terminal. New /add-dir, /remove-dir, and /dirs slash
commands let you add and remove folders mid-session; the repeatable --add-dir
CLI flag seeds them at launch, and the workspace.additionalDirectories
setting persists defaults per project. Additional roots are persisted in the
session header, survive reopen/fork/move, and are surfaced to the agent in the
system prompt so it knows they exist and can read/grep/glob them by absolute
path. Design aligns with the endorsed community implementation on
feature/session-workspace.
Co-authored-by: oh-my-pi <https://omp.sh>
A non-retriable provider error on the continuation turn after a failed
tool result ended the run, but #persistSessionMessageIfMissing dropped
the empty error turn as reload poison, so the session JSONL stopped at
the last tool result and the provider errorMessage was lost with no
durable record of why the run stopped. When retry, model fallback, and
compaction all decline the turn, the non-retry terminal error tail now
persists it via the same helper the retry-lifecycle dead-ends use; the
empty turn stays off the wire on reload via the transform-messages
empty-assistant filter, matching the existing retry-exhaustion path.
Fixes#6249
Used the shared JSON Schema validator for Type.Unsafe so direct safeParse calls and composed shim schemas reject invalid values while preserving valid input identity.
Added direct and composed runtime regression assertions.
MCP-backed tools never declared an explicit strict value, so OpenAI-family
serializers (post-#4336/#4340) had no false to preserve and models over-filled
mutually exclusive optional fields. Task/subagent proxies also rebuilt a raw
tools/call instead of executing through the source MCPTool, bypassing intent
stripping, placeholder pruning, local-URL resolution, reconnect, abort, and
result metadata; strict servers rejected proxied calls with
unrecognized_keys ["i"].
- MCPTool/DeferredMCPTool now declare `readonly strict = false as const`.
- createMCPProxyTools delegates to the current source tool, re-resolved by raw
MCP server/tool metadata so reconnect replacements are honored, and keeps the
Task 60s timeout by combining its abort signal with the caller's.
- Regression coverage: strict flags, proxy parity for i/placeholder shaping,
declared-i passthrough, and reconnect re-resolution.
Fixes#6208
Preserved raw JSON Schema documents while keeping the shim validator identity-based, allowing provider wire conversion and runtime argument validation to consume MCP input schemas.
Added direct shim and remapped-extension regression coverage.
Fixes#6221
- Exempted the handler-less conflict:// scheme from the URI-like guard so parseConflictUri still splices registered blocks.
- Extended the near-miss regression to assert conflict://1 reaches the resolver.
Fixes#6123
The fullscreen Plan Review overlay stayed mounted, focused, and fully
interactive after a choice was picked. showPlanReview's finish() resolves
the choice promise but deliberately defers the hide until #approvePlan
(guarded for #5688/#5319/#5689), so during slow async approval work — e.g.
context compaction — arrow keys still moved the cursor and repeat
Enter/Esc were silently swallowed by the settle guard, with the
fullscreen buffer masking all progress underneath. Users on Ghostty and
macOS Terminal read this as "/plan is frozen".
The overlay now flips to a committed state the moment a choice fires:
handleInput is a no-op, and the render shows a "<choice> — submitting…"
indicator plus an "applying your selection" footer. The deferred-hide
timing is untouched, so the existing stale-buffer and focus guards stay
intact.
Fixes#5926
The read-only git helpers spawned `git` directly and only inspected the
result exit code. When git is absent from PATH, Bun's spawn throws ENOENT
(uv_spawn 'git') at launch, which escaped as an unhandled rejection and
crashed the process (e.g. Windows without git, relying on WSL git).
Translate a missing-binary launch failure into a non-zero GitCommandResult
in the async git() wrapper and into a null degrade in the sync reftable ref
readers, matching the existing non-zero-exit handling. Mutating/checked
commands keep surfacing the clean "git is not installed." error.
Fixes#6169
The agent_end handler only recorded stopReason/provider/model at debug and dropped errorMessage/errorStatus/errorId, so a session dying repeatedly on provider stream failures left no actionable trace in the main log. Extract logProviderTurnError and emit one warn-level entry carrying provider, model, errorMessage, errorStatus, and errorId when a turn ends in stopReason:error.
Fixes#6177
Bundled the release history as a fallback when package assets cannot be resolved, while preserving external package-directory overrides.
Added regression coverage for the compiled-binary fallback.
Fixes#6172
On a cache-cold interactive launch, a modelRoles.default pointing at a
models.yml discovery provider (openai-models-list) was silently replaced
by an unrelated authenticated provider's default. createAgentSession
resolves the default role before background discovery populates the
catalog, so the configured provider had no models yet and the fallback
fell through to pickDefaultAvailableModel.
Await one cache-aware discovery pass and re-resolve the configured
default whenever it is still unresolved (not only when nothing resolved
at all) before accepting a bundled-provider fallback.
Fixes#6162
Made startup resolution rank configured providers before catalog-only matches while preserving explicit provider pins and catalog fallback behavior.
Added regression coverage for shared bare model IDs across authenticated and unauthenticated providers.
Fixes#6150
- Seeded dirty-baseline blobs into the parent object database before reconstructing filtered agent commits.
- Used three-way synthetic-tree application for committed and trailing task state while preserving parent WIP.
- Added a focused merge regression covering unrelated edits in the same tracked file.
Fixes#6135
Short-circuited session_stop emission when an abort or disposal is already in progress, avoiding extension work whose result cannot be used.
Added deterministic coverage for an abort racing the final settle pass.
Fixes#6134
The single 30s hang-guard from #4290 (sized for metadata fetches per #4229)
wrapped every Hindsight op including reflect, an agentic retrieve+synthesize
call whose healthy latency routinely exceeds 30s, so ordinary successful
reflects were aborted client-side.
- Give HindsightApi per-op deadlines with sensible defaults (reflect 120s,
retain 60s, recall/request 30s) plus a HindsightTimeouts option bag.
- Report the effective seconds in the timeout error instead of a hard-coded
"after 30s".
- Add hindsight.requestTimeoutMs / reflectTimeoutMs / recallTimeoutMs /
retainTimeoutMs settings and matching HINDSIGHT_*_TIMEOUT_MS env vars.
- Preserve caller-abort merging via withTimeoutSignal.
Fixes#6125
- Blocked malformed and unregistered URI-like paths before filesystem resolution.
- Suggested canonical xd:// spelling while preserving explicitly escaped local paths.
- Added regression coverage for xdt://, xd:/, and xd/ near misses.
Fixes#6123
- Dismissed the fullscreen plan review and settled its pending choice when a turn-ending provider error is pinned.
- Added regression coverage for restored editor focus and visible error presentation.
Fixes#6086
Removed display-only home shortening from the provider-facing project prompt and covered home-relative project paths with a regression test.
Fixes#6100