- Added a streaming parser path for apply_patch envelopes that tolerates incomplete patch bodies.
- Updated apply patch preview expansion to return best-effort hunks when the renderer is in partial mode.
- Added a renderer test confirming streaming apply_patch input shows file paths without end-marker parse errors.
- Added built-in model entries for gpt-5.5 and gpt-image-2, including updated context windows, token limits, and pricing.
- Updated generated-model policy application to set or clear applyPatchToolType based on inferred GPT-5 freeform rules.
- Changed Spark edit-mode resolution to return apply_patch by default, honoring explicit replace and strict-mode overrides.
- Added tests for GPT-5 freeform policy inference and Spark edit-mode default, variant, and strict-mode behavior.
Slots a new "apply_patch" variant alongside the existing edit modes
(replace, patch, hashline, chunk, vim). The mode accepts a single input
string containing a Codex *** Begin Patch / *** End Patch envelope,
parses it with a new lenient parser (heredoc-tolerant), and fans each
file-op out to the existing executePatchSingle so LSP writethrough,
plan-mode guards, fs-cache invalidation and diagnostics are shared
with the patch mode.
Exposes both tool shapes from the spec: the JSON function-tool variant
(§1.2, {input: string}) and the OpenAI custom-tool / Lark-grammar
"freeform" variant (§1.1, raw patch string). The edit tool advertises
a Lark grammar via customFormat and a wire name via customWireName;
openai-responses emits it as a grammar-constrained custom tool when a
model opts in with applyPatchToolType: "freeform" in models.json.
custom_tool_call / custom_tool_call_output are plumbed end-to-end
through the shared responses code (emission, streaming, history
replay), and the agent-loop dispatcher matches tool calls by either
name or customWireName so returned calls route correctly.
Also threads preview/diff rendering for apply_patch through the TUI
(tool-execution + edit renderer) so streaming patches show per-file
diffs like the other edit modes.
Default edit mode is unchanged (hashline); opt in via edit.mode or
PI_EDIT_VARIANT=apply_patch.
Review-pass findings:
1. python.md (P3) — "Put workflow explanations in assistant message or
cell title" lost its **MUST** weight during compression. Agents were
observed embedding explanations as in-cell comments, polluting the
kernel and wasting tokens. Restored as "You **MUST** put workflow
explanations in the assistant message or cell title — never inside
cell code."
2. ast-grep.md + ast-edit.md (P3) — The variadic-capture warning that
$$$NAME (three dollars) is correct and $$NAME (two dollars) is
invalid was dropped during compression. LLMs trained on shell/regex
conventions where $$ is common are prone to this mistake; ast-grep
emits a generic parse error rather than a "bad metavariable"
diagnostic, so the negative example has direct reproduction value.
Added "Use $$$NAME, **NOT** $$NAME" to both files.
All 6/6 template tests pass; bun check clean.
Further compresses packages/coding-agent/src/prompts/system/system-prompt.md
from 21,530 B to 16,545 B (−23% on top of the prior compression;
−9,060 B / ~−2,265 tok per turn vs origin/main) while restoring
RFC 2119 weight on every inviolable rule and reorganizing the
pre-yield discipline.
system-prompt.md
RFC 2119 keyword restoration
All rules under `# Contract`, Procedure §§2/6, and the tail `<critical>`
block use `**MUST**` / `**MUST NOT**` keywords that the file's preamble
pins to RFC 2119. The previous draft had downgraded 29 of these to
`Do **NOT**`, which reads as below-MUST-NOT against the same preamble.
Restored sites:
- `# Contract` — all 7 inviolable bullets
- `<critical>` tail block — all 4 safety rules
- `## 6. Verification` — mock ban and no-proof yield rule
- Procedure §2 — "search for existing examples" rule regains the
PROHIBITED parallel-convention clause it lost
- `<dir-context>` — AGENTS.md read requirement regains MUST
Structural dedup
- `<source-of-truth>` and `<instruction-priority>` were two priority
lists with overlapping scope. Merged into a single
`<instruction-priority>` covering all 5 conflict-resolution levels.
- `<self-check>` and `<scope-check>` were two pre-yield checklists;
`## 6. Verification` also had a third numbered "Before yielding,
verify..." list with overlapping checks. Collapsed all three into
one `<pre-yield-check>` section (incl. "output format matches the
ask" from the old verification list). `## 6. Verification` now
focuses on verification discipline (test rigor, mocks, run-scope).
Signal restoration
Added four anchors to `<design-checklist>` that were dropped from the
earlier `<code-integrity>` block and had no home in the new structure:
- Adversarial-caller / tired-maintainer self-questioning
- Cost-of-easy-path framing
- Inhabit-the-call-site self-review
- Persistence on hard problems (do not punt half-solved work)
Handlebars fix
The `### Tool priority` header was emitted unconditionally but its
body was wrapped in `{{#ifAny python|bash}}`, producing a bare heading
with no content when neither tool was available. Header now sits
inside the conditional.
SECTION_SEPARATOR helper relocation
The `SECTION_SEPARATOR` Handlebars helper is a generic section-header
formatter that was registered in coding-agent's
`config/prompt-templates.ts`. This coupled every template consumer to
a side-effect import of that module; a prior fix added
`import "./config/prompt-templates"` to `system-prompt.ts` so the
`/system-prompt` sub-path export would register the helper, but
sibling consumers (`task/executor.ts`, `task/template.ts`) worked only
by accident because the parent agent happened to load
`system-prompt.ts` first.
- Moved `sectionSeparator` function and helper registration to
`packages/utils/src/prompt.ts` next to the other generic helpers
(`xml`, `codeblock`, `ifAny`, `includes`, `not`, `jsonStringify`).
- `packages/coding-agent/src/config/prompt-templates.ts` now
re-exports `sectionSeparator` from `@oh-my-pi/pi-utils/prompt` for
the test that imports it via the coding-agent path.
- Removed the side-effect import from
`packages/coding-agent/src/system-prompt.ts`.
Template typo fix
Also fixes a latent `SECTION_SEPERATOR` spelling (→ `SECTION_SEPARATOR`)
in the two subagent templates (`subagent-system-prompt.md`,
`subagent-user-prompt.md`). Before the move the typo was masked
because every call site and the helper shared the wrong spelling.
Post-move, the helper is canonical `SECTION_SEPARATOR` in pi-utils
and all templates match.
Verification
- `bun check` clean (TS + Rust, all 9 packages)
- `bun test packages/coding-agent/test/system-prompt-templates.test.ts`
6/6 pass (was 4/6 failing pre-existing before the infrastructure fix)
- `bun test packages/coding-agent/test/tools/task-template.test.ts`
4/4 pass (exercises the `sectionSeparator` re-export)
- `bun run format-prompts` clean
When a user models.yml declares a provider with auth: none (e.g. from
an older version), getApiKey() returns the literal 'N/A' without ever
consulting authStorage — even when valid OAuth credentials exist from
a successful /login.
Check authStorage.hasAuth() before returning kNoAuth. If real
credentials are present, fall through to the normal auth flow.
Fixes#749
Compiled Bun binaries unconditionally load bunfig.toml and .env from
the current working directory at runtime, before any application code
runs. Since omp is a coding agent that runs from arbitrary project
directories, it picks up foreign project configs -- most critically
preload directives that cause immediate crashes, but also a potential
security issue since preloads execute arbitrary code.
Add --no-compile-autoload-bunfig and --no-compile-autoload-dotenv to
the bun build --compile invocations (available since Bun v1.3.3).
Note: source installs via 'bun install -g' are still affected because
'bun run' has no equivalent flag. That remains an open issue.
- Standardized missing-file read errors and now return `File not found: <path>` for absent edit targets.
- Centralized AI provider, usage, and OAuth helpers into shared modules to remove duplicated logic.
- Migrated OAuth/API-key login flows to shared factory helpers and removed inline prompt/token-exchange code.
- Reused shared tools and formatter utilities for discovery, stream tails, LSP batching, and source formatting.
- Consolidated repeated test helpers and fixtures into shared modules, replacing inline helper duplicates.
- Updated path resolution to derive a file path from the first edit entry via filePathFromEditEntry when top-level fields are absent.
- Updated single-file result rendering to fall back to first-edit entry values for op and rename metadata before detail-level metadata.
- Added a new read.toolResultPreview boolean setting defaulting to false to control inline read result rendering.
- Updated read tool group rendering to show inline previews only when enabled and to hide duplicate summary rows for previewed entries.
- Passed the setting through event and UI helper constructors and added tests for default-off behavior and the duplicate-preview summary case.
The previous check only validated 'local:' prefix, which caused
'local:PLAN.md' to incorrectly resolve to 'LAN.md' (the colon was
interpreted as a Windows drive letter).
Now requires 'local:/' or 'local://' prefix to ensure proper URI parsing.
- Refactor path normalization to combine expandPath and normalizeLocalScheme
- Add validation in utils.ts to reject local:// paths as filesystem paths
- Fix bash-skill-urls regex to handle hyphen-prefixed local:/ patterns
- Add tests for hyphen-prefixed and @local: patterns
- Add negative lookbehind to regex in bash-skill-urls to prevent matching local:/
inside paths like /repo/local:/PLAN.md
- Normalize local scheme before expanding paths in path-utils
- Add test cases for both changes
Expands the regex pattern to match local:/ (single-slash) URLs in addition to local:// (triple-slash), preventing potential Linux path leaks.
- Add regex patterns for single-quoted, double-quoted, and unquoted local:/ URLs
- Add test coverage for all three quote styles
Extract duplicate normalizeLocalScheme regex pattern into a shared function in path-utils.ts. Updated interactive-mode.ts, approved-plan.ts, agent-session.ts, bash-skill-urls.ts, and plan-mode-guard.ts to use the shared utility. Also fixed error message formatting (removed extra backslashes).
On Linux, Node's path.normalize() collapses the double slash in
local://PLAN.md to local:/PLAN.md, creating a directory called local:
in the project root instead of routing through the local:// protocol handler.
Defense-in-depth fixes across 5 layers:
1. resolveToCwd() now throws if a path starts with any internal URL
scheme prefix (local:, agent:, skill:, etc.), preventing all 59
call sites from treating URIs as relative filesystem paths.
2. resolvePlanPath() now matches on local: prefix (not just local://)
and normalizes local:/ to local:// before resolution, catching
all slash variants.
3. Bash URL expansion regex and early-exit checks now also match
local:/ (single slash), and normalize before resolution.
4. Edit preview/diff functions now gracefully skip internal URL paths
instead of crashing via the resolveToCwd guard.
5. All startsWith('local://') checks updated to startsWith('local:')
with normalization in agent-session, interactive-mode, and
approved-plan modules.
Also adds local: to .gitignore to prevent accidental commits of the
leaked directory.
Removed unconditional topic:news coupling in buildRequestBody that scoped
Tavily index to news publications whenever recency was set. Technical queries
with --recency now search the general index filtered by time only.
Tightened SearchParams.recency contract in base.ts: providers MUST interpret
recency as a pure time filter and MUST NOT change topic scope as a side effect.
Previously ReadToolGroupComponent completely ignored the expanded
state and discarded result content, making read tool output invisible
in the TUI (only showed a one-line path summary with no file content).
Changes:
- Store expanded state in #expanded field (was discarded with _ prefix)
- Store result content text in ReadEntry.contentText (was thrown away)
- Show a small code preview (3 lines) by default in collapsed mode
- Show full file content when expanded via Ctrl+O
- Uses renderCodeCell with PREVIEW_LIMITS.OUTPUT_COLLAPSED for
consistent truncation with "... N more lines (Ctrl+O for more)" hint
This brings read tool output in line with bash and grep tools which
already show previews when collapsed.
When persist writes race with test-level tempDir cleanup (e.g. in agent-session-auto-compaction-queue.test.ts), fs.rename can fail with ENOENT during the atomic swap inside #writeEntriesAtomically. The error is already routed through #persistChain so #persistError surfaces it to future persist calls, but the awaited rejection returned by #queuePersistTask was bubbling out of the fire-and-forget callers (#rewriteFile path and the incremental writer path) and Bun's test runner reported it as an 'Unhandled error between tests' even though the test itself passed. Attach a silent .catch on both void paths so the rejection is considered handled at the callsite while the persistChain retains the error state.
Three fixes to make CI green after the opus 4.7 and auto-bump landed:
1. github-copilot model mapper: prefer capabilities.limits.max_prompt_tokens
over the root-level context_length field (which mirrors max_context_window_tokens, i.e.
total window). Copilot's real /models response returns both for the gpt-5.x family, and
context_length inflates contextWindow with the output budget. Also restore the bundled
Copilot limits (claude-opus-4.6, gpt-5.2, gpt-5.4, gpt-5.4-mini, grok-code-fast-1) to
the values the fixed mapper produces so tests that depend on truthful offline fallbacks
pass. Update the two Copilot discovery tests whose payloads conflated context_length
with prompt capacity.
2. coding-agent task schema: make the per-task assignment description context-mode-aware.
The previous description unconditionally told agents that 'shared background belongs
in context', which is wrong for independent mode where shared context is disabled.
3. coding-agent model-registry test: update the anthropic-latest canonical collapse case
to claude-opus-4-7 since opus 4.7 is now the newest official opus in models.json.
- Updated todo start handling to set the requested task to in_progress while demoting all other in_progress tasks to pending.
- Added task note rendering in summary output by prefixing each note line with "Note:".
- Set GIT_OPTIONAL_LOCKS to 0 in git execution options and added tests for out-of-order start jumps and note summaries.