Commit Graph
558 Commits
Author SHA1 Message Date
can1357 e7558e37e7 fix(coding-agent): corrected tool resolution and conditional auto-qa session config
- Replaced getTool with getExecutableTool in CursorExecBridgeOptions to prioritize mounted-device permission wrappers over canonical tools.
- Updated createAgentSession to check isAutoQaEnabled against restricted tool filtering when configuring system prompts.
- Added test coverage verifying execution overrides preserve approval gates and restricted sessions omit auto-qa guidance.
2026-07-28 03:41:04 +02:00
can1357 21b3764b08 refactor(coding-agent): replaced xdevregistry with state interface and helpers
- Replaced the `XdevRegistry` class with the `XdevState` interface and pure helper functions across core and session tools.
- Updated session configurations, tool execution, and renderers to utilize canonical tool map initialization and sharing.
- Adapted unit tests and mocks to use `XdevState` and associated helper functions for permission and dispatch verification.
2026-07-28 03:34:36 +02:00
can1357 392aac4e49 fix(coding-agent): resolved third review pass on inspect_image vision mode
- read now treats an xd://-mounted inspect_image as available (top-level
  predicate OR mounted device gated by the effective mode), so default
  xdev sessions with a text-only model keep metadata-guidance reads
  instead of inlining images the provider boundary would scrub
- advisor tool session stops inheriting the primary's isToolActive and
  xdevRegistry: advisors cannot execute xd:// devices, so their reads
  inline images again
- setModelWithProviderSessionReset is now async and awaited at every
  callsite, so retry-fallback model switches cannot race the
  inspect_image tool-slate reconcile
- regression tests for both xd:// availability directions
2026-07-27 23:07:26 +02:00
alexis@epsilver.xyz c33b98e260 feat(coding-agent): capability-aware inspect_image with tri-state mode and /vision toggle
Replace the inspect_image.enabled boolean with inspect_image.mode
(auto|on|off, default auto). In auto the tool is registered only when
the active model lacks native image input, so vision-capable models
(e.g. kimi-code/k3) read images inline with their own capabilities
instead of delegating to a separate vision model. on/off force
registration regardless of model capability.

- New utils/inspect-image-mode.ts resolves the effective state from the
  /vision session override, the persisted setting, and model capability
- read tool re-evaluates the effective state per image read and
  re-renders its description, so it returns decoded image blocks again
  whenever inspect_image is hidden
- /vision [on|off|auto|status] slash command (modeled on /computer)
  overrides the mode for the current session only
- Tool set is reconciled on model switch with a status notice when
  inspect_image appears/disappears
- Legacy inspect_image.enabled true/false migrates to mode on/off
2026-07-27 16:24:02 -04:00
can1357 8c5dc16344 fix(task): enforced per-spawn effort ceiling across retry fallbacks
- task.maxEffort only clamped the initial thinking level; a retry
  fallback candidate could clamp back up to its model floor and run a
  low-capped spawn at high.
- The ceiling now rides the session as thinkingLevelCeiling: clamped in
  ModelControls (constructor, setThinkingLevel, auto classifier,
  restore) and in applyRetryFallbackCandidate; fallback candidates whose
  floor exceeds the ceiling are skipped.
- Effort value import moved to @oh-my-pi/pi-catalog/effort; changelog
  attribution added.
- Review follow-up for PR #6794.
2026-07-27 16:09:28 +02:00
can1357 e4e8f8a40a Merge PR #6785: fix(coding-agent): preserve extension providers for plan subagents (@roboomp) 2026-07-27 15:57:45 +02:00
can1357 b0063dd180 Merge PR #6787: fix(mcp): deduplicate aliased server connections (@roboomp) 2026-07-27 15:57:44 +02:00
can1357 6bbfc1110a Merge PR #6543: feat(agent): add a pre-model-call gate that can stop the turn (@paralin) 2026-07-27 14:01:11 +02:00
roboomp da11d906ff fix(mcp): unified tool collision handling
Moved first-wins MCP tool-name deduplication and origin-aware warnings into one shared helper used by startup extension registration, SDK custom-tool assembly, and deferred refreshes.

Added an SDK startup regression proving colliding MCP proxy tools keep the first origin instead of silently overwriting it.

Fixes #6786
2026-07-27 10:49:59 +00:00
roboomp 879707bd32 fix(coding-agent): preserved plan subagent providers
- Skipped extension-source reconciliation when restricted sessions intentionally load no extensions.
- Added a shared-registry regression covering the provider model, credential, and custom API.

Fixes #6783
2026-07-27 10:01:42 +00:00
can1357 1dbf51bf25 Merge PR #6743: perf(coding-agent): avoid unused compact tool metadata (@usr-bin-roygbiv) 2026-07-27 04:58:27 +02:00
can1357 e07db86f2d Merge PR #6670: fix(mcp): map mounted tools to xd routes (@jeffscottward) 2026-07-27 04:58:27 +02:00
usr-bin-roygbiv 4dfc428043 style(coding-agent): sort metadata imports 2026-07-27 01:21:09 +00:00
usr-bin-roygbiv 3c5c2514be fix(coding-agent): preserve tool metadata builder API 2026-07-27 01:05:33 +00:00
usr-bin-roygbiv 7cbc5a57d3 perf(coding-agent): avoid unused compact tool metadata 2026-07-27 00:40:28 +00:00
roboomp d61a19695c fix(coding-agent): preferred auth in deferred resolution
Deferred role candidate selection now resolves against authenticated models before falling back to the full catalog, matching eager CLI resolution.

Fixes #6727
2026-07-26 19:10:38 +00:00
Christian Stewart e79eabc3b6 feat(agent): add a pre-model-call gate that can stop the turn
The agent loop had no place to refuse a provider request. A host that needs to
act on the assembled context before it is billed, checking that the prompt still
fits the window, that a budget boundary has not been crossed, or that the
session should hand off instead of spending, could only observe the request
after the fact, when the tokens were already committed.

Add `AgentLoopConfig.beforeModelCall`, asked once per turn beside the deadline
check and before `turn_start` is emitted. A `stop` result ends the stream with
no turn open, so nothing has to synthesise a cancellation event and no consumer
is left holding a half-open turn. Placing it there also keeps `turn_end`'s
contract intact: that event carries the assistant message for a completed turn,
and a gated stop has no assistant message to report.

`syncContextBeforeModelCall` keeps its existing void contract and its job of
refreshing prompt and tool state, so implementations typed as returning void are
unaffected.

`Agent.setBeforeModelCall` installs the host's callback, and `addBeforeModelCall`
registers an additional callback without displacing the host's, returning a
disposer so an extension can attach and detach independently. A supplied
`reason` is logged where the loop stops.

Signed-off-by: Christian Stewart <christian@aperture.us>
2026-07-26 12:02:18 -07:00
Diogo Soares Rodrigues 7214951ead fix(cursor): sync native todo list from server-resolved tool calls
Cursor resolves its native `update_todos`/`read_todos` tools server-side,
so the todo list never followed the model's intent locally.

Two defects, both silent:

- `agent.v1.ToolCall` is a protobuf oneof. A decoded message exposes the
  selected variant as `tool: { case, value }` and has no flattened
  `updateTodosToolCall` property, so the bridge recognized no native todo
  call at all on the wire path.
- The synthesized `todo` block was emitted as locally runnable carrying a
  `{todos}` payload the local tool's schema rejects, turning every update
  into a validation error and driving a spurious continuation turn.

Todo calls are now read through the oneof, both native blocks are stamped
resolved, and local state is mirrored only from the server's confirmed
success snapshot. Partial `read_todos` responses -- narrowed by
`status_filter`/`id_filter`, or short of the server's own `total_count` --
are subsets, not the list, and are refused rather than deleting the tasks
they omit. `TODO_STATUS_CANCELLED` maps to `abandoned` instead of
reverting the task to `pending`.

The exec bridge mirrors each snapshot into session state, refreshes the
interactive panel via a synthetic `tool_execution_end`, and persists to
the session branch so the list survives reloads, rewinds, compaction, and
session switches. Existing phase grouping is preserved.

Regression tests drive the bridge with wire-encoded protobuf, which is
the only shape production ever sees; all six fail without this change.
2026-07-26 09:29:13 -03:00
Jeff Scott Ward fcdd33d2fe fix(mcp): map mounted tools to xd routes 2026-07-26 01:02:11 -04:00
can1357 c780662881 feat(agent): added resolveFallbackTool option for routing unadvertised tool calls
- Add `resolveFallbackTool` callback to `AgentOptions` and `AgentLoopConfig` that resolves tool calls not found in the advertised set.
- Use the callback as a third lookup step after `name` and `customWireName` match, enabling side transports like `xd://` device mounts.
- Add test coverage verifying the fallback resolves known devices and preserves "not found" errors for unknown names.
- Wire the coding agent's device registry as `resolveFallbackTool` in both `createAgentSession` and `streamAgentSession` paths.
2026-07-24 12:18:17 +02:00
can1357andusr-bin-roygbiv 681d7daf65 feat(computer): unified native addon, /computer toggle, function tool
- Replaced the separate GUI-linked pi_natives.desktop.linux-x64 addon with
  a pure-Rust X11 backend (x11rb RustConnection capture via RandR/GetImage,
  XTest input with keysym mapping) compiled into the core addon on every
  published target; Linux arm64 and musl are now supported and headless
  hosts load the addon unaffected.
- Removed the native-desktop-linux cargo feature, desktop_unsupported.rs,
  lazy desktop loader, second napi build, desktop packaging/CI steps, GUI
  build dependencies, and the now-unreferenced vendored libspa crate;
  reverted setup-system-deps to main.
- Preserved the desktop input hardening semantics on the unified backend:
  XTest layouts reject negative origins and coordinates beyond 0..=32767,
  batch coordinates stay bound to the frame last returned to JS with
  intermediate screenshots deferred, coordinate input requires a
  previously returned frame, and failed chord releases still release
  every held key.
- Enforced a 60s worker-side execute deadline (DESKTOP_DEADLINE_EXCEEDED):
  no input is emitted after expiry and wait-heavy batches are rejected
  upfront.
- Added int32 fail-closed validation for coordinates, drag points, and
  scroll deltas at the JS ingress and gateway schema.
- Exposed computer to models without native OpenAI computer-use support as
  a regular function tool with a typed GA action schema across OpenAI,
  Azure, and Codex Responses providers, including named forced choice.
- Added the /computer slash command (on/off/status/toggle) for
  session-only enablement via runtime tool registration in SessionTools.
- Updated docs, changelogs, and contract tests accordingly.
2026-07-24 01:40:05 +00:00
usr-bin-roygbiv b9504f65e7 feat: add native Codex computer use 2026-07-24 01:40:04 +00:00
can1357 366bd6203e Merge PR #6392: feat(coding-agent): add usage-aware model fallback (@eggpeat) 2026-07-24 02:25:35 +02:00
Brentandcan1357 6d4a345d69 fix(coding-agent): defer ACP reserve confirmation 2026-07-24 02:23:51 +02:00
Brentandcan1357 0bfb0bd1e3 feat(coding-agent): add usage-aware model fallback 2026-07-24 02:23:51 +02:00
Joe Shullandcan1357 f4641c165e feat: allowlist xdev prompt docs 2026-07-24 02:23:22 +02:00
Joe Shullandcan1357 f15191c37d feat: configure xdev prompt docs 2026-07-24 02:23:22 +02:00
roboomp 5a1f227a6b fix(memory): synchronized live backend lifecycle
- Serialized backend transitions across runtime state, tools, and prompts.
- Rehydrated Mnemopi listeners after clear and enqueue maintenance.
- Made memory.backend the sole post-migration local runtime gate.

Fixes #5638
2026-07-23 19:52:09 +00:00
can1357 5b3275c7ae feat(coding-agent): introduced ordered provider priority lists for search and images
- Replaced single-provider preferences with ordered priority lists for web search and image generation.
- Added a `MultiSelectSubmenu` component supporting toggle and reordering interactions in settings.
- Implemented migration logic to convert legacy single-provider preferences into ordered priority lists.
- Updated setup wizard scenes, image generation fallback logic, and search provider chains to use priority lists.
2026-07-23 20:44:50 +02:00
can1357 878b8fd556 Merge PR #6029: feat(omp): configure web search provider order (@riverpilot)
# Conflicts:
#	packages/coding-agent/src/modes/controllers/selector-controller.ts
2026-07-23 20:18:08 +02:00
can1357 5d66eb7f2a Merge PR #5464: fix(coding-agent): persist vibe sessions across restarts (@roboomp) 2026-07-23 18:06:11 +02:00
can1357 c0c1622012 Merge PR #4636: feat(secrets): add friendly names to secret placeholders (@Mathews-Tom)
# Conflicts:
#	packages/ai/test/pi-native-client.test.ts
#	packages/coding-agent/src/advisor/runtime.ts
#	packages/coding-agent/src/prompts/tools/eval.md
2026-07-23 17:56:24 +02:00
can1357 c522eceff2 Merge PR #6119: feat: lift subagent async/auto-background limits via owner-routed delivery and quiescence (@korri123)
# Conflicts:
#	packages/coding-agent/src/task/executor.ts
2026-07-23 17:52:52 +02:00
can1357 26726fdcb9 Merge PR #6255: add dynamic multi-root workspace context (@maatheusgois-dd) 2026-07-23 17:30:33 +02:00
can1357 0f54c0df70 fix(tools): autoqa consent handling from default off to opt-in 2026-07-23 13:24:45 +02:00
can1357 bf15acb25d fix(coding-agent): hub cancel reaches the registration behind a settled job row
A budget-aborted keep-alive subagent's job row (job id == agent id) settles
failed and is retained ~5 min; executeCancel short-circuited to
already_completed for that window, leaving the zombie registration
unkillable exactly when the user wants it dead. Fall through to
cancelAgentRegistration for settled rows; keep already_completed when no
lingering registration exists.

Also stop wiring AgentLifecycleManager.global() onto SDK sessions created
with a caller-supplied agentRegistry: the global lifecycle releases through
AgentRegistry.global(), so it would report a cancel while releasing an
unrelated global ref. Without a lifecycle, cancel falls back to
dispose + unregister on the session's own registry.

Addresses both Codex P2 review findings on #6319.
2026-07-23 11:37:13 +02:00
can1357 9756fea7af Merge PR #6319: fix(coding-agent): let hub cancel kill a jobless agent registration (@roboomp) 2026-07-23 11:37:13 +02:00
can1357 370045b310 fix(sdk): always await in-flight runtime discovery in deferred --model retry
The getDiscoverableProviders() guard skipped awaiting runtimeDiscoveryPromise
when no config-discovery providers exist, so a cold deferred selector backed
only by runtime model managers (extension fetchDynamicModels) with implicit
local discovery disabled still resolved against the offline cache. Awaiting
unconditionally is free when no runtime managers are registered
(refreshRuntimeProviders early-returns); the full refresh fallback stays
gated on discoverable providers.
2026-07-23 11:37:11 +02:00
ReqX 838e37417f fix(rpc): await background model discovery in get_available_models, set_model, and deferred --model resolution
Three read paths raced background model discovery on cold start:

1. `get_available_models` RPC (rpc-mode.ts) read the registry
   synchronously and returned a partial catalog containing only
   statically-bundled models.
2. `set_model` RPC (rpc-mode.ts) read the registry synchronously and
   rejected discovery-backed selectors with "Model not found".
3. `--model <provider>/<pattern>` CLI flag deferred retry (sdk.ts:2078)
   resolved synchronously after extension registration, before
   discovery-backed providers had populated `#models`.

Paths 1 and 2 are fixed by exposing the existing in-flight background
refresh promise (`#backgroundRefresh`, already tracked and cleared by
`refreshInBackground`) via a new public
`ModelRegistry.awaitBackgroundRefresh()` method, and awaiting it at each
RPC read site. No-op when no refresh is in flight (warm sessions
unaffected).

Path 3 mirrors the cold-cache race fix already applied to the
default-role fallback on this branch (issues #6114, #6162, sdk.ts:2343):
when a deferred pattern is unresolved and any discoverable provider is
registered, run a cache-aware `refresh("online-if-uncached")` pass
before the retry. Reuses the existing discovery machinery rather than
introducing a new ordering dependency.

The `omp models` CLI never had this bug because it awaits
`modelRegistry.refresh()` directly before listing.

Behavioral characteristics:
- **Warm-session fast path preserved**: when no refresh is in flight
  (`#backgroundRefresh === undefined`), `await undefined` resolves in a
  microtask. No regression for sessions that don't need discovery or
  have already settled.
- **Failure isolation preserved**: `refreshInBackground()` already
  swallows discovery errors via `.catch(...)`, so `awaitBackgroundRefresh()`
  resolves even when discovery fails — callers then read whatever models
  made it into `#models` (built-in + cached). No new failure modes.
- **Scoped**: doesn't change `refreshInBackground()` semantics. Adds a
  new read-only awaiter with minimal API surface. Reuses the
  well-established `refresh("online-if-uncached")` pattern for the
  deferred retry path.

Reproduction (get_available_models RPC, with any discovery-backed
provider configured in `~/.omp/agent/models.yaml`):

  cd ~
  {
    sleep 1
    printf '%s\n' '{"id":"m1","type":"get_available_models"}'
    sleep 5
  } | timeout 15 omp --mode rpc-ui --approval-mode yolo 2>/dev/null \
    | grep '"id":"m1"' | jq '.data.models | {count: length, providers: ([.[].provider]|unique)}'

Before: discovery-backed provider absent from the response on cold start.
After:  discovery-backed provider present.

Reproduction (--model CLI flag, same config):

  omp --mode rpc-ui --model <discovery-provider>/<model-id> --approval-mode yolo

Before: exits 1 with "Model \"<discovery-provider>/<model-id>\" not found".
After:  starts rpc-ui session with the requested model selected.
2026-07-23 08:46:31 +00:00
roboomp f56ad1ae06 fix(coding-agent): let hub cancel kill a jobless agent registration
A keep-alive subagent force-stopped for exceeding its soft request budget
is kept resumable (status idle, adopted by AgentLifecycleManager) so its
context can be salvaged, but its async job row settles and is reaped after
~5 min. After that, hub cancel <id> only reported "Background job not
found" because executeCancel consulted AsyncJobManager alone, leaving the
registration unkillable short of a broker restart.

hub cancel now falls through to the agent registration when no live job
matches: for a sub the caller spawned, it aborts any in-flight turn,
disposes the session, and releases it from the lifecycle. Cross-agent
kills stay impossible and Main/advisor refs are never targeted.

Fixes #6315
2026-07-22 19:45:45 +00:00
can1357 9995325ad5 fix(sdk): carry strict through the custom-tool definition bridge
customToolToDefinition rebuilt ToolDefinition without strict, so the
Task proxies' (and startup MCP tools') explicit strict:false was dropped
before RegisteredToolAdapter and the OpenAI-family serializers saw it.
Declare strict on ToolDefinition, copy it in the bridge, and cover the
proxy -> definition -> registered adapter path in the parity test.
2026-07-22 21:13:21 +02:00
can1357 ccbe190d64 fix(sdk): inherit role thinking level on startup retry fallback
A retry-chain entry without its own :level suffix now inherits the
unavailable primary's configured thinking level, matching runtime
fallback-chain semantics. Regression test asserts a level that differs
from the fallback model's default.
2026-07-22 21:13:13 +02:00
can1357 a929cde5e2 Merge PR #6285: fix(sdk): resolve missing role fallback chains (@roboomp) 2026-07-22 21:13:13 +02:00
roboomp b257a6dcbf fix(session): preserved startup fallback ownership
- 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
2026-07-22 11:11:30 +00:00
roboomp 093f7c2660 fix(sdk): resolved missing role fallback chains
- 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
2026-07-22 10:52:57 +00:00
maatheusgois-ddandoh-my-pi <https://omp.sh> 00fd98729a Make parent live root list authoritative for subagents, CLI merge stays in buildSessionOptions
- 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>
2026-07-22 03:01:10 -03:00
maatheusgois-ddandoh-my-pi <https://omp.sh> ffe50650e1 Propagate workspace roots into subagent sessions
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>
2026-07-22 02:36:38 -03:00
maatheusgois-ddandoh-my-pi <https://omp.sh> 25761276bb Merge CLI --add-dir roots with settings roots instead of skipping settings
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>
2026-07-22 01:38:27 -03:00
maatheusgois-ddandoh-my-pi <https://omp.sh> ab0c25e058 Fix 2nd-round AI review: context files for all roots, merge on resume, fork copies roots
- 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>
2026-07-22 01:14:13 -03:00
maatheusgois-ddandoh-my-pi <https://omp.sh> 48381f0e98 Fix AI review findings: settings on initial launch, /new root leak, persisted roots on resume, consistent ~ normalization, dead exports
- 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>
2026-07-22 00:58:02 -03:00