Commit Graph
4233 Commits
Author SHA1 Message Date
can1357andCan Bölük b191e6c5ff fix(coding-agent): reject task-N ID confusion, error on partial todo apply
- todo-write.md adds an explicit note that tasks are referenced by
  verbatim content text; the tool never emits task-N IDs.
- resolveTaskOrError rejects ^task-\d+$ inputs with a clarifying error.
- execute sets isError:true when any op failed.
- appendItems short-circuits on the first "already exists" error so the
  call no longer applies the prefix of a doomed batch.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük fcd38b7143 fix(coding-agent): require symbol, distinguish timeout, coalesce lsp edits
Three independent lsp fixes that share the action dispatcher and import
graph in lsp/index.ts:

- symbol-required: project-aware references/rename/definition now reject
  an omitted symbol with a structured error pointing at symbol=<name>
  (and symbol#N for repeats). resolveSymbolColumn used to fall back to
  the first non-whitespace column and the server happily answered for
  whatever identifier sat there. findSymbolMatchIndexes also enforces
  word boundaries for bare identifiers.

- timeout-distinguish: the outer catch around dispatched LSP actions
  rethrew new ToolAbortError() for both an internal timeoutSignal abort
  and a caller signal abort, so callers got an opaque "Operation
  aborted". Timeouts now map to a ToolError that names the action and
  the elapsed budget; caller cancels stay ToolAbortError.

- edit-coalesce: rename and rename_file collected edits from every
  project-aware server and applied them sequentially, but each server
  computed positions against pre-edit text. Once server A wrote, server
  B's edits had stale offsets and produced malformed imports. Merge
  per-uri edits across servers, sort by descending position, and throw
  on overlap so the model retries instead of silently corrupting.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük b3b75ff1d5 fix(coding-agent): advance web_search chain on codex image placeholder
When the Codex backend returned the literal "(see attached image)" as
the answer for a text query and streamedAnswer was empty, the wrapper
accepted the placeholder as the response and the chain never advanced.
Throw SearchProviderError so the next provider is tried.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük ef505142bf fix(coding-agent): fall back to inline worker when tab worker startup errors
Worker emits BuildMessage errors via the async error event, after the
surrounding try/catch in spawnTabWorker has already resolved, so the
documented spawnInlineWorker fallback was unreachable for the very case
it was added to cover. initializeTabWorker now terminates the broken
worker and retries once via spawnInlineWorker, with the original error
attached as cause if the inline fallback also fails.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük 93e74819cb fix(coding-agent): raise browser tool timeout cap from 30s to 300s
clampTimeout silently floored the caller-supplied timeout to 30s, so a
requested 120s for a slow waitForResponse came back as a 30s failure
indistinguishable from the default. Raise the cap and document the new
max in the schema field description.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük d700004489 fix(coding-agent): default browser waitUntil to "load"
networkidle2 requires <=2 in-flight requests for 500ms which never
resolves on dev servers (HMR, websockets, telemetry beacons), so
browser.open and tab.goto timed out before user code ran. "load" matches
Puppeteer's documented default and works on real-world pages.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük 6d1ade1200 fix(coding-agent): only claim Applied patches: yes when something applied
Both empty-patch and whitespace-only-patch branches in the isolated-task
merge unconditionally appended "Applied patches: yes". The marker now
fires only when the combined patch is non-empty AND applyText succeeded.
No-op merges report "No changes to apply.". The renderer marker matcher
accepts the new string.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük be5451d5c3 fix(coding-agent): surface real jobId in background task announcement
The "Started N background task jobs" announcement listed the per-task
label (e.g. 7-MyScout) without the underlying jobId, but JobTool.execute
looks up by jobId. Append (job: ${jobId}) to each task entry and accept
the task label as a fallback alias in JobTool.execute.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük 0ed6edb8e2 fix(coding-agent): hide spawn-disabled agents from the task <agents> list
renderDescription filtered the listing only by disabledAgents. When a
subagent had parentSpawns empty the model still saw the full menu, tried
to spawn oracle, and got "Cannot spawn 'oracle'. Allowed: none". The
listing now intersects with the allowed-spawn set.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük 094273df5d fix(coding-agent): verify write actually mutated the file on disk
executePatchSingle returned success based on the writethrough callback
resolving, but the LSP-backed writethrough could resolve to an in-memory
editor buffer while disk stayed unchanged. Capture pre-write mtime+size,
re-stat post-write, and throw a ToolError when nothing changed.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük e0b3b086ff fix(coding-agent): tighten hashline recovery to refuse fuzzy 3-way merge
Diff.applyPatch with fuzzFactor:3 absorbed orphan duplicate closers from
elsewhere in the file, editing the wrong site. Recovery now requires the
cached snapshot to hash-match the model-supplied anchors AND applies
with fuzzFactor:0; otherwise the original mismatch is rethrown so the
caller re-reads.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük 5eabbe616f fix(coding-agent): stop seeding line hash with index for blank lines
computeLineHash mixed in the line index for blank and punctuation-only
lines so any line shift invalidated anchors whose content was unchanged.
Two adjacent blank lines now collide on the same hash by design; the
range and op disambiguate by line number.
2026-05-19 19:24:16 +09:00
can1357andCan Bölük a1fe78e092 fix(coding-agent): correct grep regex doc, hard-error on mis-shaped paths
- search.md no longer claims "full regex syntax". Engine is rust-regex
  (RE2) so lookaround and backreferences are unsupported; the doc now
  says so and points at the post-filter alternative.
- search.ts rejects array entries containing a top-level comma with an
  actionable ToolError, instead of silently demoting to a footer note
  and returning zero matches.
- Add a paths-as-array example to search.md.
2026-05-19 19:24:16 +09:00
can1357 9456e4fe2c fix(coding-agent): coalesce user timeout with JS worker startup window
READY_TIMEOUT_MS was a hard 5s ceiling, ignoring the per-cell timeout the
caller supplied. Cold Bun starts on slow machines routinely exceed 5s
and the worker init failed before user code ran. The window now takes
the larger of the default and the caller timeout.
2026-05-19 19:16:08 +09:00
can1357 7aef1f1cd5 fix(coding-agent): rewrite trailing return statement into final expression
A top-level `return value;` in a JS eval cell was previously swallowed:
returnFinalExpression only handled ExpressionStatement, so ReturnStatement
flipped the IIFE wrapper which discarded the value. Rewrite the trailing
return into __omp_set_final_expr__((expr)) so the existing
final-expression channel surfaces the value just like a trailing
expression.
2026-05-19 19:16:08 +09:00
can1357 9a335ece68 fix(coding-agent): timeout knob, partial matches on timeout, gitignore toggle
- Expose optional timeoutMs (clamped 0.5..60s) and pipe through to the
  native walker. Default stays at 5s.
- On timeout, drain accumulated matches and return them with
  truncated:true plus a notice line instead of throwing.
- Add gitignore boolean to the schema so callers can opt out of the
  default exclude when looking for .env/.jsonl/build artifacts.
- Reject comma-in-paths array entries with an actionable ToolError.
- Update find.md with the knobs and the array-shape example.
2026-05-19 19:15:58 +09:00
can1357 1da881b8e2 fix(coding-agent): spawn resolved pip binary in installPythonPackage
ResolveBinary picked pip3 when only pip3 exists, but the spawn passed the
bare string "pip" which throws on macOS hosts without a pip alias. Use
the resolved path and wrap the helper in try/catch so a missing or
broken installer never escapes as an uncaught throw breaking URL reads.
2026-05-19 19:15:54 +09:00
can1357 f48af07d3a fix(coding-agent): honor caller-supplied read selector limit
The ignoreResultLimits flag now gates only the byte-budget tail-truncate,
never the explicit line window. Reads of internal URLs (skill, local,
memory) with a line range previously returned the tail of the file
instead of the requested window for files larger than the byte budget.
2026-05-19 19:15:49 +09:00
Can BölükandGitHub 75f36351f6 Merge branch 'main' into farm/83f7f427/debug-dap-launch-failures-can-crash-omp- 2026-05-19 18:26:56 +09:00
Can BölükandGitHub b1231f3d37 Merge branch 'main' into farm/c8d0293b/edit-tool-seems-to-prepend-a-space-on-ea 2026-05-19 18:20:33 +09:00
Can Bölük 899983859e Merge remote-tracking branch 'origin/main' 2026-05-19 18:18:34 +09:00
can1357 94803877bd fix(coding-agent): fixed Anthropic fast-mode detection and scoped fast-mode icon
- Expanded `isAnthropicFastModeUnsupportedError` to treat 429 `rate_limit_error` responses mentioning fast mode as unsupported alongside 400 `invalid_request_error` speed-rejection cases.
- Added tests for unsupported-fast-mode detection covering 400, 429, and unrelated error payloads.
- Added `AgentSession.isFastModeActive()` with provider-scoped resolution and switched status-line rendering to use it for the fast-mode icon.
2026-05-19 18:18:26 +09:00
Can BölükandGitHub d80b9ca084 Merge branch 'main' into fix/acp-bash-permission-shape 2026-05-19 18:13:40 +09:00
Can BölükandGitHub ab78f43333 Merge branch 'main' into feat/anthropic-fast-mode 2026-05-19 18:07:56 +09:00
can1357 7e93d9b79c feat(ai,coding-agent): add scoped service tiers (claude-only, openai-only)
Two new `ServiceTier` values let users target priority/fast mode at one
provider family without paying premium costs on the other when switching
models mid-session:

- `"openai-only"` → resolves to `"priority"` on `openai` and
  `openai-codex`; `undefined` everywhere else.
- `"claude-only"` → resolves to `"priority"` on direct `anthropic`;
  `undefined` on Bedrock/Vertex Claude and elsewhere.

Implementation centers on a new `resolveServiceTier(serviceTier, provider)`
helper exported from `@oh-my-pi/pi-ai`. The three OpenAI providers and the
Anthropic provider all route through it, replacing the previous
`shouldSendServiceTier` type-guard pattern (which couldn't survive scoped
values — the input variable's literal type stops matching the wire type
once scopes are introduced). `shouldSendServiceTier` is kept as a plain
boolean for external callers but no longer narrows the input.

`getPriorityPremiumRequests` is reworked: it now counts Anthropic +
`"priority"` (fast mode) as one premium request — the original PR
introduced the realization but didn't update billing — and continues to
ignore providers that silently drop the field on the wire.

User-facing:
- `serviceTier` setting enum gains `"openai-only"` and `"claude-only"`
  with clear UI descriptions.
- `/fast on` still sets the unscoped `"priority"`, but `/fast status`
  and `isFastModeEnabled()` now report `on` for any priority-granting
  tier (including scoped values). `/fast off` clears to `undefined`
  regardless of scope.
- The Anthropic auto-fallback listener and re-arm clearing both cover
  `"priority"` and `"claude-only"` (the two values that grant priority
  on Anthropic). `"openai-only"` doesn't trigger the anthropic
  fallback even if the user is on an Anthropic model — by design.

Tests cover all four resolver branches (unscoped passthrough, openai-only
match/miss, claude-only match/miss), Anthropic provider's wire `speed`
field under each scope, and updated premium accounting.
2026-05-19 18:06:00 +09:00
can1357 250e55283e refactor(ai,coding-agent): unify fast mode under serviceTier
Replaces the parallel `speed` knob with the existing `serviceTier`
concept. The anthropic-messages provider now realizes
`serviceTier: "priority"` by setting `speed: "fast"` on the wire and
appending the `fast-mode-2026-02-01` beta header; other providers
continue to pass `service_tier` through natively or ignore it.

User-facing impact:
- `/fast` no longer dispatches on model.api. It just toggles
  `serviceTier: "priority"`. Anthropic-specific translation lives
  entirely in the provider.
- Anthropic auto-fallback marker is now the generic `"priority"`
  identifier in `AssistantMessage.disabledFeatures` instead of
  `"anthropic.fast_mode"`.
- New `clearAnthropicFastModeFallback(providerSessionState)` export is
  invoked from `AgentSession.setServiceTier` when transitioning into
  `"priority"`, so re-running `/fast on` after the provider
  auto-disabled fast mode actually re-arms the next request instead of
  silently no-oping.

Provider-side cleanups:
- Tightened cast site (`ParamsWithSpeed` alias) for the typed
  `speed: "fast"` injection.
- Widened the rejection matcher (`\bspeed\b` + `not support`) so
  phrasing drift ("is not supported" vs "does not support", quoted vs
  backticked) doesn't break the fallback.

Dropped from the PR:
- `Agent.speed` / `AgentOptions.speed` / `SimpleStreamOptions.speed`
  fields.
- `SpeedChangeEntry` and `appendSpeedChange` from the session entry
  schema; service-tier change entries already cover this.
- `AgentSession.setSpeed` / `.speed` and the previousSpeed
  capture/restore in `switchSession` — collapsed back into
  `setServiceTier` + previousServiceTier, which now covers the rollback
  too.
2026-05-19 17:55:44 +09:00
jiwangyihao 0820982b6a fix(acp): include execute metadata in bash permissions 2026-05-19 16:41:05 +08:00
roboomp 580389a13a style: bun run fix 2026-05-19 07:18:54 +00:00
roboomp cb34503ba5 fix(debug): preserved dap launch failures
- Preserved launch and attach request failures when configurationDone also fails.
- Handled initial stop-outcome watcher rejections for failed launch and attach attempts.
- Rejected directory-valued debug launch programs before adapter selection and documented the debugpy launch shape.

Fixes #1187
2026-05-19 07:18:33 +00:00
can1357 60e2befb35 chore: bump version to 15.1.6 2026-05-19 07:17:26 +02:00
can1357 2e40fb250b fix(coding-agent/tools): fixed internal URL selector splitting in read path resolution
- Added splitInternalUrlSel to iteratively peel internal-URL selector chunks while preserving unsupported schemes like mcp://.
- Updated ReadTool to use the internal splitter before routing so selector parsing is handled via parseSel.
- Added unit tests covering malformed selectors, namespaced skill hosts, and unchanged behavior for non-URLs or unsupported schemes.
2026-05-19 07:12:56 +02:00
Can BölükandGitHub 6f8c70db2f Merge branch 'main' into farm/07737278/qwen3-6-35b-a3b-mtp-still-not-able-to-en 2026-05-19 06:59:33 +02:00
roboomp bcf05e3ea6 revert(plan-mode): restore original prompt wording for resolve/extra.title
The schema-level fix (normalizing {} to true in open schema positions)
makes the prompts correct-by-construction: models that follow the schema
grammar now emit string values for extra.title without needing softer
prompt language. Revert the SHOULD/optional hedging to the original MUST
wording per maintainer review.

Fixes #1179
2026-05-19 04:42:16 +00:00
Can BölükandGitHub e54767b57d Merge pull request #1151 from can1357/farm/26a1d36a/omp-stats-crashes-modulenotfound-resolvi
fix(release): list worker --compile entrypoints in CI release script
2026-05-19 06:38:31 +02:00
Can BölükandGitHub aa2980c69c Merge pull request #1091 from can1357/farm/a0b5d6b7/edit-tool-hashline-mode-produces-line-du
fix(coding-agent): drop hashline anchor echo inserts
2026-05-19 06:37:01 +02:00
roboomp 14198e2ed3 fix(plan): derive plan title when resolve.extra.title is not a string
Grammar-constrained models (e.g. Qwen3.6-35B-MTP via llama.cpp) emit
`extra: { title: {} }` instead of `extra: { title: "<string>" }` because
the resolve schema declares `extra` as Record<string, unknown> with an
open value schema, leaving the model free to drop in an empty object.
The apply guard then threw 'Plan approval requires extra: { title: ... }'
on every retry, looping the model indefinitely (issue #1179).

Plan approval now uses a layered title resolution:
  1. `extra.title` if it is a non-empty string (and sanitizes to non-empty)
  2. First `# Heading` in the plan content
  3. Filename stem of `planFilePath` (`'/data/workspaces/can1357__oh-my-pi__1179/.omp-session/2026-05-19T03-59-21-254Z_019e3e63-62a6-7000-be63-371f2cd6d67d/local/PLAN.md'` → `PLAN`)
  4. Literal `plan` as a final safety net
Each candidate is run through `normalizePlanTitle`; rejected ones fall
through. Extracted as `resolvePlanTitle` in plan-mode/approved-plan.ts
so it's unit-testable.

Prompt language relaxed from MUST to SHOULD for `extra.title` in
plan-mode-active.md and plan-mode-tool-decision-reminder.md, noting the
fallback so models don't waste turns on a now-optional field.

Fixes #1179
2026-05-19 04:06:04 +00:00
can1357 7a63c5a621 chore: bump version to 15.1.5 2026-05-19 05:34:02 +02:00
can1357 c39295eaac feat(coding-agent/prompts): added oracle advisory agent prompt and embedded registration
- Added a new `oracle.md` prompt defining a read-only diagnostic, architecture, and debugging advisor.
- Imported `oracle.md` into the agent prompt loader in `packages/coding-agent/src/task/agents.ts`.
- Included `oracle.md` in `EMBEDDED_AGENT_DEFS` so the new agent is available at runtime.
2026-05-19 05:33:43 +02:00
can1357 aa8fa00c4e fix(coding-agent/tools): capped AST parse errors and preserved total counts
- Added capParseErrors in shared render utilities and updated ast_grep and ast_edit to return capped parseErrors plus parseErrorsTotal.
- Threaded the preserved totals into parse-error formatting and renderer output so labels and overflow counts report the full number of issues.
- Added an ast_grep test asserting parse errors are capped at PARSE_ERRORS_LIMIT while parseErrorsTotal retains the original count.
2026-05-19 05:30:59 +02:00
can1357 3976e31ffd chore: bump version to 15.1.4 2026-05-19 04:48:55 +02:00
can1357 226fe87345 fix(coding-agent/eval): hardened image display value coercion to strict base64
- Implemented strict base64 validation and normalization for image `displayValue` payloads in the JS runtime, supporting strict strings, `Uint8Array`, `Buffer`, `ArrayBuffer`, typed-array views, and JSON `Buffer` objects.
- Dropped unrecognized image payloads while emitting a warning and fallback text instead of forwarding malformed data.
- Added tests covering successful coercions and invalid image data rejection paths.
2026-05-19 04:36:30 +02:00
Can BölükandGitHub 072914981a Merge pull request #1169 from can1357/farm/c975bb5a/move-does-not-change-working-directory
fix(agent): update tool cwd after /move
2026-05-19 04:29:43 +02:00
roboomp ee442cedea fix(ask,plan): fix renderer crash and plan-mode exit loop for Qwen3 and similar models
- Guard renderInlineMarkdown against non-string input: partial JSON during
  streaming can leave option label fields as undefined, causing marked.lexer
  to throw 'undefined is not an object (evaluating e.replace)'. The ask tool
  renderer now silently falls back to an empty string or baseColor output.

- Sanitize normalizePlanTitle instead of hard-rejecting: models that produce
  natural-language plan titles like 'My Improvement Plan' were getting a
  ToolError on every resolve call, causing an infinite retry loop. Spaces are
  now converted to hyphens, remaining invalid chars are dropped, and only
  truly unresolvable titles (empty after sanitization, path separators) throw.

- Fix ask.md prompt example: the example showed the legacy single-question
  format (question/options/recommended at the top level) while the schema
  requires questions: [{id, question, options}]. Models that follow examples
  closely (Qwen3) generated calls that always failed schema validation.

Fixes #1176
2026-05-19 02:09:47 +00:00
Can Bölük 4024fbe7e2 fix(ai): decontaminate leaked Zod schema instances to valid JSON Schema
Rewrites JSON-roundtripped Zod 4 schema objects that leak Zod internals as
JSON Schema keywords (e.g., `type:"enum"`, `enum:{...}`) into valid
JSON Schema 2020-12. This prevents validation failures when such schemas
are used as tool input schemas (e.g., from MCP servers).

Updates `isZodSchema` to reject deserialized Zod impostors that retain
`_zod` but lose their prototype.

Wires `toJSON` methods onto TypeBox shim schemas to ensure `JSON.stringify`
produces clean JSON Schema, preventing future leaks.

Fixes #1101
2026-05-19 10:16:40 +09:00
roboomp 48253d36ef fix(edit): warned on hashline separator padding
Tightened the hashline prompt to forbid readability spaces after the payload separator.

Preserved parsed payload text verbatim and surfaced a warning when a payload block looks like separator padding was added across every line.

Fixes #1166
2026-05-18 21:42:35 +00:00
Lucas Szwarcberg d0efcea5ad feat(ai,coding-agent): added Anthropic fast mode with auto-fallback
Wires `speed: "fast"` and the `fast-mode-2026-02-01` beta into the
Anthropic provider, plumbs a matching `speed` option through
`SimpleStreamOptions` and the Agent, and teaches `/fast` to dispatch
on the active model's API (Anthropic -> speed=fast, OpenAI -> existing
serviceTier=priority path). Server is the authority on which models
support fast mode.

When the server rejects an unsupported model, the provider mirrors the
strict-tools fallback: drops the field, retries the same turn
transparently, persists the disable via `providerSessionState`, and
surfaces the action through the new `AssistantMessage.disabledFeatures`
marker so the session can sync the toggle off and warn the user.
2026-05-18 11:48:40 -07:00
roboomp 0c010cb0f3 fix(agent): updated tool cwd after move
Use the live session manager cwd for tool sessions so /move updates existing tools without recreating the agent session.

Fixes #1168
2026-05-18 13:33:25 +00:00
roboomp 9d0826266c fix(release): listed worker --compile entrypoints in CI release script
- Added stats sync, browser tab, and JS eval workers as explicit --compile
  entrypoints in scripts/ci-release-build-binaries.ts so Bun emits them
  into bunfs in published binaries, matching the dev build script and the
  AGENTS.md worker spawn contract.
- Switched the release-binary smoke step in .github/workflows/ci.yml to
  invoke --smoke-test (in addition to --version) so this regression
  cannot ship again.
- Added packages/coding-agent/test/issue-1150-repro.test.ts pinning the
  symmetric contract: both build scripts must list every worker entry.

Fixes #1150
2026-05-17 11:52:01 +00:00
Vilmos Nebehajandcan1357 98405e16de fix(utils): ignore unsafe dotenv entries 2026-05-17 13:43:00 +02:00
can1357 a2e276cc43 test(coding-agent): set GIT_CONFIG_* and GIT_TERMINAL_PROMPT
- Set GIT_CONFIG_* and GIT_TERMINAL_PROMPT environment variables to prevent test interference from user gitconfig, LFS filters, signing, and credential helpers.
- Enhanced git error messages to include stdout when stderr is empty, providing better diagnostics for test failures.
- Replaced symlink-resolving pathIsWithin with lexical path containment check to prevent test isolation bypass via symlinked extensions.
2026-05-17 13:36:12 +02:00