@oh-my-pi/pi-coding-agent 15.0.1 → 15.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -1
- package/examples/custom-tools/README.md +11 -7
- package/examples/custom-tools/hello/index.ts +2 -2
- package/examples/extensions/README.md +19 -8
- package/examples/extensions/api-demo.ts +15 -19
- package/examples/extensions/hello.ts +5 -6
- package/examples/extensions/plan-mode.ts +1 -1
- package/examples/extensions/reload-runtime.ts +4 -3
- package/examples/extensions/with-deps/index.ts +4 -3
- package/examples/sdk/06-extensions.ts +4 -2
- package/package.json +8 -18
- package/src/autoresearch/tools/init-experiment.ts +38 -41
- package/src/autoresearch/tools/log-experiment.ts +32 -41
- package/src/autoresearch/tools/run-experiment.ts +3 -3
- package/src/autoresearch/tools/update-notes.ts +11 -11
- package/src/commands/commit.ts +10 -0
- package/src/commit/agentic/tools/analyze-file.ts +4 -4
- package/src/commit/agentic/tools/git-file-diff.ts +4 -4
- package/src/commit/agentic/tools/git-hunk.ts +5 -5
- package/src/commit/agentic/tools/git-overview.ts +4 -4
- package/src/commit/agentic/tools/propose-changelog.ts +13 -13
- package/src/commit/agentic/tools/propose-commit.ts +6 -6
- package/src/commit/agentic/tools/recent-commits.ts +3 -3
- package/src/commit/agentic/tools/schemas.ts +28 -28
- package/src/commit/agentic/tools/split-commit.ts +22 -21
- package/src/commit/analysis/summary.ts +4 -4
- package/src/commit/changelog/generate.ts +7 -11
- package/src/commit/shared-llm.ts +22 -34
- package/src/config/config-file.ts +35 -13
- package/src/config/model-registry.ts +40 -191
- package/src/config/models-config-schema.ts +166 -0
- package/src/config/settings-schema.ts +29 -0
- package/src/discovery/claude-plugins.ts +19 -7
- package/src/edit/index.ts +2 -2
- package/src/edit/modes/apply-patch.ts +7 -6
- package/src/edit/modes/patch.ts +18 -25
- package/src/edit/modes/replace.ts +18 -20
- package/src/eval/js/shared/rewrite-imports.ts +131 -10
- package/src/eval/py/executor.ts +233 -623
- package/src/eval/py/kernel.ts +27 -2
- package/src/eval/py/runner.py +42 -11
- package/src/eval/py/runtime.ts +1 -0
- package/src/exa/factory.ts +5 -4
- package/src/exa/mcp-client.ts +1 -1
- package/src/exa/researcher.ts +9 -20
- package/src/exa/search.ts +26 -52
- package/src/exa/types.ts +1 -1
- package/src/exa/websets.ts +54 -53
- package/src/exec/bash-executor.ts +2 -1
- package/src/extensibility/custom-commands/loader.ts +5 -3
- package/src/extensibility/custom-commands/types.ts +4 -2
- package/src/extensibility/custom-tools/loader.ts +5 -3
- package/src/extensibility/custom-tools/types.ts +7 -6
- package/src/extensibility/custom-tools/wrapper.ts +1 -1
- package/src/extensibility/extensions/get-commands-handler.ts +77 -0
- package/src/extensibility/extensions/loader.ts +7 -3
- package/src/extensibility/extensions/types.ts +9 -5
- package/src/extensibility/extensions/wrapper.ts +1 -2
- package/src/extensibility/hooks/loader.ts +3 -1
- package/src/extensibility/hooks/tool-wrapper.ts +1 -1
- package/src/extensibility/hooks/types.ts +4 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +78 -31
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/typebox.ts +391 -0
- package/src/goals/tools/goal-tool.ts +6 -12
- package/src/hashline/input.ts +2 -1
- package/src/hashline/parser.ts +27 -3
- package/src/hashline/types.ts +4 -4
- package/src/hindsight/state.ts +2 -2
- package/src/index.ts +0 -2
- package/src/internal-urls/docs-index.generated.ts +15 -15
- package/src/internal-urls/router.ts +8 -0
- package/src/internal-urls/types.ts +21 -0
- package/src/lsp/config.ts +15 -6
- package/src/lsp/defaults.json +6 -2
- package/src/lsp/types.ts +30 -38
- package/src/mcp/manager.ts +1 -1
- package/src/mcp/tool-bridge.ts +1 -1
- package/src/modes/acp/acp-agent.ts +248 -50
- package/src/modes/components/session-observer-overlay.ts +12 -1
- package/src/modes/components/status-line/segments.ts +39 -4
- package/src/modes/controllers/command-controller.ts +27 -2
- package/src/modes/controllers/event-controller.ts +3 -4
- package/src/modes/controllers/extension-ui-controller.ts +3 -2
- package/src/modes/interactive-mode.ts +1 -1
- package/src/modes/rpc/host-tools.ts +1 -1
- package/src/modes/rpc/host-uris.ts +235 -0
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-mode.ts +27 -1
- package/src/modes/rpc/rpc-types.ts +58 -1
- package/src/modes/runtime-init.ts +2 -1
- package/src/modes/theme/defaults/dark-poimandres.json +1 -0
- package/src/modes/theme/defaults/light-poimandres.json +1 -0
- package/src/modes/theme/theme.ts +117 -117
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/context-usage.ts +2 -2
- package/src/prompts/tools/github.md +4 -4
- package/src/prompts/tools/hashline.md +22 -26
- package/src/prompts/tools/read.md +55 -37
- package/src/sdk.ts +31 -8
- package/src/session/agent-session.ts +74 -104
- package/src/session/messages.ts +16 -51
- package/src/session/session-manager.ts +22 -2
- package/src/session/streaming-output.ts +16 -6
- package/src/task/discovery.ts +5 -2
- package/src/task/executor.ts +210 -87
- package/src/task/index.ts +15 -11
- package/src/task/render.ts +32 -5
- package/src/task/types.ts +54 -39
- package/src/tools/ask.ts +12 -12
- package/src/tools/ast-edit.ts +11 -15
- package/src/tools/ast-grep.ts +9 -10
- package/src/tools/bash-command-fixup.ts +47 -0
- package/src/tools/bash.ts +48 -38
- package/src/tools/browser/render.ts +2 -2
- package/src/tools/browser.ts +39 -53
- package/src/tools/calculator.ts +12 -11
- package/src/tools/checkpoint.ts +7 -7
- package/src/tools/debug.ts +40 -43
- package/src/tools/eval.ts +16 -10
- package/src/tools/find.ts +10 -13
- package/src/tools/gh.ts +108 -132
- package/src/tools/hindsight-recall.ts +4 -6
- package/src/tools/hindsight-reflect.ts +5 -5
- package/src/tools/hindsight-retain.ts +15 -17
- package/src/tools/image-gen.ts +31 -81
- package/src/tools/index.ts +4 -1
- package/src/tools/inspect-image.ts +8 -9
- package/src/tools/irc.ts +15 -27
- package/src/tools/job.ts +30 -28
- package/src/tools/output-meta.ts +26 -0
- package/src/tools/read.ts +39 -12
- package/src/tools/recipe/index.ts +7 -9
- package/src/tools/render-mermaid.ts +12 -12
- package/src/tools/report-tool-issue.ts +4 -4
- package/src/tools/resolve.ts +11 -11
- package/src/tools/review.ts +14 -26
- package/src/tools/search-tool-bm25.ts +7 -9
- package/src/tools/search.ts +19 -22
- package/src/tools/ssh.ts +10 -9
- package/src/tools/todo-write.ts +26 -34
- package/src/tools/vim.ts +10 -26
- package/src/tools/write.ts +25 -5
- package/src/tools/yield.ts +100 -54
- package/src/web/search/index.ts +9 -24
- package/src/web/search/providers/anthropic.ts +5 -0
- package/src/web/search/providers/exa.ts +3 -0
- package/src/web/search/providers/gemini.ts +5 -0
- package/src/web/search/providers/jina.ts +5 -2
- package/src/web/search/providers/zai.ts +5 -2
- package/src/prompts/compaction/branch-summary-context.md +0 -5
- package/src/prompts/compaction/branch-summary-preamble.md +0 -2
- package/src/prompts/compaction/branch-summary.md +0 -30
- package/src/prompts/compaction/compaction-short-summary.md +0 -9
- package/src/prompts/compaction/compaction-summary-context.md +0 -5
- package/src/prompts/compaction/compaction-summary.md +0 -38
- package/src/prompts/compaction/compaction-turn-prefix.md +0 -17
- package/src/prompts/compaction/compaction-update-summary.md +0 -45
- package/src/prompts/system/auto-handoff-threshold-focus.md +0 -1
- package/src/prompts/system/file-operations.md +0 -10
- package/src/prompts/system/handoff-document.md +0 -49
- package/src/prompts/system/summarization-system.md +0 -3
- package/src/session/compaction/branch-summarization.ts +0 -324
- package/src/session/compaction/compaction.ts +0 -1420
- package/src/session/compaction/errors.ts +0 -31
- package/src/session/compaction/index.ts +0 -8
- package/src/session/compaction/pruning.ts +0 -91
- package/src/session/compaction/utils.ts +0 -184
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,98 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.1.0] - 2026-05-15
|
|
6
|
+
### Breaking Changes
|
|
7
|
+
|
|
8
|
+
- Changed the extension and hook runtime API by moving schema typing from direct TypeBox imports to `TSchema` from `@oh-my-pi/pi-ai`, requiring callers who use TypeScript imports of `Type` to migrate via provided injected modules
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added a cancellable handoff progress indicator in `/handoff` that displays while handoff generation runs and can be aborted with `Esc`
|
|
13
|
+
- Added `apiKey` as a supported provider override field in model config, allowing API-key-only overrides to provide fallback credentials for built-in models
|
|
14
|
+
- Added `supportsMultipleSystemMessages`, `allowsSyntheticReasoningContentForToolCalls`, `disableReasoningOnToolChoice`, and `levels` model-thinking compatibility fields to model configuration schemas
|
|
15
|
+
- Added `zod` to the Extension, Custom Tool, Hook, and Custom Command APIs as `pi.zod` so extension and plugin authors can define tool schemas with Zod without separate imports
|
|
16
|
+
- Added `pi.zod` as a canonical schema API for examples and extension plugins while keeping `typebox` available as legacy compatibility
|
|
17
|
+
- Added a `telemetry` option to `createAgentSession` for passing OpenTelemetry configuration through to the underlying Agent
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Changed handoff generation to run as a one-shot handoff request and switch to the new session only after it completes, avoiding an extra assistant handoff turn in chat history
|
|
22
|
+
- Changed `pi.typebox.Type.Composite` to merge all object schemas in the provided list, enabling more than two object inputs
|
|
23
|
+
- Changed `pi.typebox.Type.Record` to validate record keys against the provided key schema instead of forcing string keys
|
|
24
|
+
- Changed `pi.typebox.Type.Array` with `uniqueItems: true` to reject duplicate items while preserving the constraint in wire schemas
|
|
25
|
+
- Changed `pi.typebox.Type.Object` with `additionalProperties: false` to reject unknown properties during parsing
|
|
26
|
+
- Changed `pi.typebox.Type.Enum` in the compatibility shim to preserve numeric TypeScript enum values
|
|
27
|
+
- Changed tool parameter schemas across the agent to use the shared Pi schema pipeline (`TSchema` plus Zod/JSON Schema validation) instead of direct AJV/TypeBox compilation for stricter schema validation compatibility
|
|
28
|
+
- Changed GitHub tool input schema shape to expose operation fields in a flat schema form without legacy `run_watch`-style nesting
|
|
29
|
+
- Changed Python session pooling to remove the previous 4-session retention cap and 5-minute idle-session eviction, so kernels now stay alive for a session until explicitly disposed via `disposeKernelSessionsByOwner` or `disposeAllKernelSessions`
|
|
30
|
+
- Changed kernel cleanup behavior to avoid automatic eviction by idle timeout and capacity pressure, so additional Python sessions are not queued behind retained-session shutdown retries
|
|
31
|
+
- Replaced the bundled `@sinclair/typebox` runtime dependency with an in-repo Zod-backed shim exposed through `pi.typebox.Type.*`. Common builders (`Object`, `String`, `Number`, `Integer`, `Boolean`, `Array`, `Tuple`, `Union`, `Intersect`, `Literal`, `Enum`, `Optional`, `Nullable`, `Record`, `Partial`, `Required`, `Pick`, `Omit`, `Composite`, …) keep their existing call signatures but now return Zod schemas that flow through the same validation/wire pipeline as `pi.zod`. Bare `@sinclair/typebox` imports inside extensions are transparently remapped to the same shim by the runtime plugin shim, so plugins that authored against `import { Type } from "@sinclair/typebox"` keep working unchanged. Plugins that relied on TypeBox-only submodule APIs (`@sinclair/typebox/compiler`, `@sinclair/typebox/value`, `TypeRegistry`, the `Symbol(TypeBox.Kind)` marker) must vendor `@sinclair/typebox` in their own package — only the root import is remapped.
|
|
32
|
+
|
|
33
|
+
### Deprecated
|
|
34
|
+
|
|
35
|
+
- Deprecated direct TypeBox-only examples for plugin schemas by updating example documentation to prefer `pi.zod`
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Fixed auto-triggered handoff flow to perform only a single handoff-generation model call instead of an extra prompt cycle
|
|
40
|
+
- Fixed handoff cancellation behavior so a pre-cancelled signal returns `Handoff cancelled` without starting generation and aborting handoff now propagates through the handoff request signal
|
|
41
|
+
- Fixed `create_conventional_analysis` parsing to ignore harmless extra fields and still parse the required conventional fields
|
|
42
|
+
- Fixed BashTool async request validation flow so async execution remains disabled and returns the explicit `Async bash execution is disabled` error
|
|
43
|
+
- Fixed `task.simple` invalid `schema` and `context` argument handling to still reject unsupported fields after tool-argument validation
|
|
44
|
+
- Fixed subagent execution hangs by enforcing `task.maxRuntimeMs` as a wall-clock limit even when inference streaming stalls, so stuck subagents now abort and report runtime-limit exceeded
|
|
45
|
+
- Fixed tool schema compatibility validation by routing TypeBox schemas through shared conversion and Zod-based validation to avoid strict-schema provider mismatches
|
|
46
|
+
- Fixed Python execution cancellation and timeouts by escalating to kernel shutdown if `SIGINT` did not terminate a running cell within 2 seconds, preventing indefinite hangs in queued or stuck sessions
|
|
47
|
+
- Fixed cleanup blocking during long-running executions by forcing a kernel shutdown path when interrupt-based cancellation is ignored
|
|
48
|
+
- Fixed bash output emitting a spurious `[… 0 lines elided (NB) …]` marker (and reordering the artifact link before the command output) when the shell minimizer rewrote a small command's output. After `OutputSink.replace()` swapped the minimized text into the buffer, the subsequent `sink.push("[raw output: artifact://N]\n")` chunk was funneled back into the (now empty) head-retention window while the pre-replace `#totalBytes` still tracked the original raw stream — so `dump()` composed `<head=artifact-link> + <middle-elision marker against stale totals> + <tail=minimized text>` instead of `<minimized text> + <artifact link>`. `replace()` now realigns `#totalBytes`/`#totalLines`/`#sawData`/`#truncated` to the authoritative buffer and disables head retention for the lifetime of the sink, so further pushes append to the tail buffer in order. The bash executor also drops the leading `\n` on the artifact-link push when the minimized text already ends with one so the separator stays single-newline.
|
|
49
|
+
- Fixed legacy plugin extensions failing to load on Windows when they import a bare-specifier dependency from their own `node_modules` (e.g. `import YAML from "yaml"` in `supipowers`). The legacy-pi mirror resolved the dependency to its absolute path and then ran the path through `isUrlLikeSpecifier`, whose `^[A-Za-z][A-Za-z\d+.-]*:` regex matched the Windows drive letter (`C:`) and short-circuited the `pathToFileURL` conversion. The raw path was emitted into the mirrored TS source as `import x from "C:\\Users\\...\\dep\\dist\\index.js"`, where `\n`, `\U`, `\y` and other backslash sequences were eaten by the TS string-literal parser, producing nonsense package specifiers like `C:Usersjames.ompagentextensionssupipowers\node_modulesyamldistindex.js` that Bun's resolver rejected with `Cannot find package …`. `isUrlLikeSpecifier` now rejects `^[A-Za-z]:[\\/]` first, so Windows absolute paths flow through `pathToFileURL` like every other absolute path and reach the mirror as proper `file:///C:/...` URLs.
|
|
50
|
+
- Fixed Python session queued executions silently resurrecting kernels after `disposeAllKernelSessions` or `disposeKernelSessionsByOwner` removed the session: queued work now checks the session is still registered before replacing or executing on a kernel and rejects with cancellation otherwise
|
|
51
|
+
- Fixed Python session disposal treating an unconfirmed `PythonKernel.shutdown()` result as success: sessions whose kernel shutdown returns `{ confirmed: false }` (or rejects) are now retained in the registry and a `warn` is logged so a later dispose can retry instead of orphaning the subprocess
|
|
52
|
+
- Fixed `task.maxRuntimeMs` losing wall-clock aborts that fired during pre-prompt session setup by re-checking the abort signal immediately before issuing the model prompt, so a stalled subagent now exits with the runtime-limit reason instead of hanging through setup races
|
|
53
|
+
- Fixed late `yield` events landing after a wall-clock timeout from flipping a timed-out subagent to a successful exit, so the reported `aborted` flag and exit code now always reflect the runtime-limit breach while yield payloads remain in `extractedToolData`
|
|
54
|
+
- Fixed async-task progress consumer to copy `contextTokens` and `contextWindow` from the completed `SingleResult` onto `AgentProgress`, so UI gauges keep showing per-turn context after a backgrounded task finishes
|
|
55
|
+
- Fixed the status-line `path` segment ignoring `stripWorkPrefix: false` when selecting the folder icon for scratch directories. The icon selection now respects the same gate as the scratch path stripping, so disabling `stripWorkPrefix` keeps the regular `folder` icon even when the project directory is inside a scratch root.
|
|
56
|
+
- Fixed `YieldTool` constructor to fall back to the loose record schema when the session `outputSchema` contains unresolved `$ref` strings (e.g. external or cyclic references that survive dereferencing), instead of installing a validator that would reject every payload with an unresolved-reference error
|
|
57
|
+
- Fixed `pi.typebox.Type.String` dropping `minLength`/`maxLength`/`pattern` constraints when a `format` (e.g. `email`, `url`, `uuid`) was also supplied; length and pattern checks are now applied to the format-specific schema instead of being gated on an `instanceof z.ZodString` check that never matched the format subclasses.
|
|
58
|
+
- Fixed `pi.typebox.Type.Object` stripping unknown properties when constructed without explicit `additionalProperties`. TypeBox preserves extras by default, so the shim now installs `.loose()` for the omitted/`true` cases while keeping `.strict()` for `additionalProperties: false` and `.catchall(schema)` for a schema value.
|
|
59
|
+
|
|
60
|
+
## [15.0.2] - 2026-05-15
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- Added the `set_host_uri_schemes` RPC command so hosts can register and replace writable/read-only internal URI schemes with scheme metadata (`writable`, `immutable`) at runtime
|
|
65
|
+
- Enabled the `write` tool to dispatch `write(url, content)` to registered internal URL handlers, allowing edits to non-filesystem resources via host-managed URI schemes
|
|
66
|
+
- Added host-owned internal URI read/write over RPC, including abort support, so URI operations are resolved by the host transport for `read` and `write` requests
|
|
67
|
+
- Added handling of host URI request results in RPC mode so host services can stream completion frames for internal URI operations
|
|
68
|
+
- Added scratch-directory awareness to the status-line `path` segment. When the project directory is inside an OS-level scratch root (the platform `os.tmpdir()`, `/tmp` and `/var/tmp` plus their macOS `/private/...` aliases, `~/tmp`, or — on Windows — `%TEMP%` / `%TMP%` / `%SystemRoot%\Temp`), the segment now (1) renders the new `icon.scratchFolder` symbol instead of `icon.folder`, and (2) strips the scratch root from the displayed path so only the trailing folder (and any subpath beneath it) is shown — mirroring how `/work` and `~/Projects` are already abbreviated. Both behaviors honor the existing `stripWorkPrefix` option. Icon defaults: 🗑 (emoji), `` (nf-fa-trash) for Nerd Font, `[T]` for ASCII, `◌` in the poimandres themes; themes can override `icon.scratchFolder` independently of `icon.folder`.
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- Changed the `github` tool's search ops (`search_issues`, `search_prs`, `search_code`, `search_commits`) to default the `repo` scope to the current checkout's `owner/repo` when `repo` is omitted. The auto-scope is skipped when the query already carries an explicit `repo:`/`org:`/`user:`/`owner:` qualifier or when `gh repo view` cannot resolve a github remote (in which case the search proceeds across all of GitHub as before). `search_repos` is unchanged — repository-scoping there must live in the query.
|
|
73
|
+
|
|
74
|
+
- Changed bash command preprocessing to strip trailing `| head` and `| tail` pipelines (including `|&`) from each top-level segment in command chains separated by `;`, `&&`, `||`, or `&`
|
|
75
|
+
- Changed bash fixup notices to state that stderr is already merged into stdout and to reflect that fixes were applied for multiple stripped segments when several transforms fire
|
|
76
|
+
- Changed shell-minimizer per-line truncation marker from a bare `…` to `…[+N]`, where `N` is the count of dropped Unicode scalars. The bracketed tally disambiguates minimizer-driven cuts from genuine `…` characters in the source (paths, JSON, stack traces, etc.) and gives the agent an exact count so it can decide whether the missing tail is recoverable inline or warrants reading the `[raw output: artifact://<id>]` footer the bash wrapper already emits when the minimizer rewrites output. Affects pipeline Stage 5 (`truncate_lines_at` in `defs/*.toml`) and the internal callers in `filters/git.rs`, `filters/listing.rs`, and `filters/lint.rs`. ([#1046](https://github.com/can1357/oh-my-pi/issues/1046))
|
|
77
|
+
- Changed bash command preprocessing to use the real `brush-parser` AST via `pi-natives` `applyBashFixups` instead of a hand-rolled top-level mask scanner. The previous regex/character-walking implementation reimplemented quote/heredoc/`$(...)` tracking with conservative bail-outs (notably refusing to fixup commands containing here-strings); the AST-driven version inherits the full shell parser, so semantics-preserving rewrites like stripping `| head -5` off `cat <<<'content' | head -5` now succeed instead of being skipped. No public API change — `applyBashFixups(command)` returns the same `{ command, stripped }` shape.
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- Fixed bash command fixups to remove a redundant standalone trailing `2>&1` redirect when no other pipe or redirection remains
|
|
82
|
+
- Fixed command-fixup notices to list all stripped segments instead of reporting only one
|
|
83
|
+
- Fixed summarized `read` output stalling agents on elided regions by appending an explicit footer like `[NN lines across MM elided regions; read <path>:raw or a line range like <path>:1-9999 for verbatim content]`. The footer fires whenever the structural summarizer elided at least one span, so the model gets a concrete recovery selector instead of having to guess from a bare `...` / `{ .. }` marker. Surfaces `elidedLines` on `ReadToolDetails.summary` alongside the existing `elidedSpans`. ([#1046](https://github.com/can1357/oh-my-pi/issues/1046))
|
|
84
|
+
- Updated the `read` tool prompt to describe the new elision footer and instruct the model to follow `:raw` (or an explicit line range) when the elided body is actually needed, rather than guessing.
|
|
85
|
+
- Fixed plugin extensions failing to load when their `peerDependencies` reference internal `pi-*` packages under any scope other than `@mariozechner` (e.g. `Cannot find module '@earendil-works/pi-tui'` from `@juicesharp/rpiv-ask-user-question`, or `Cannot find module '@oh-my-pi/pi-utils'` from `@oh-my-pi/swarm-extension`). The legacy-pi specifier shim now treats `@mariozechner`, `@earendil-works`, **and** the canonical `@oh-my-pi` itself as aliases for the same set of bundled in-process packages (`pi-agent-core`, `pi-ai`, `pi-coding-agent`, `pi-natives`, `pi-tui`, `pi-utils`), and additionally rewrites the upstream-only `pi-ai/oauth` subpath onto our `pi-ai/utils/oauth` layout. Restored the `Key` runtime helper export on `@oh-my-pi/pi-tui` to match upstream — plugins using `Key.enter` / `Key.ctrl("c")` (e.g. `@plannotator/pi-extension`, `@juicesharp/rpiv-ask-user-question`) no longer fail with `Export named 'Key' not found`. End-to-end verified against `@juicesharp/rpiv-ask-user-question`, `@oh-my-pi/swarm-extension`, and `@plannotator/pi-extension` — each now loads cleanly with all of its tools/commands/handlers registered. Plugins importing any of those scopes are remapped to the omp binary's own copy at load time, so peer deps are no longer dragged in from npm and there is exactly one module instance per package regardless of which scope name the plugin's manifest happened to declare.
|
|
86
|
+
- Fixed `omp commit` hanging after a successful commit instead of returning to the shell. The command now mirrors the `runPrintMode` exit pattern and calls `postmortem.quit(0)` once the pipeline resolves so lingering HTTP/2 keep-alive sockets, the Settings autosave timer, and other AgentSession background handles don't keep the event loop pinned. ([#1041](https://github.com/can1357/oh-my-pi/issues/1041))
|
|
87
|
+
- Fixed hashline payload parsing to silently treat truly-blank lines as empty `~`-prefixed payload lines when more payload follows in the same run. The previous behavior broke at the blank ("payload line has no preceding +, <, or = operation.") even though the intent is obvious — the only ambiguity is between in-payload blanks and end-of-section blanks, and a one-line lookahead resolves it: blanks that precede a non-payload op still end the run cleanly as section separators. Recovers the common case of forgetting the leading separator on a blank inserted line without changing how trailing blanks between ops behave.
|
|
88
|
+
- Rewrote the hashline edit prompt examples to use an ASCII-only `TITLE = "Mr"` → `"Mrs"` / `"Dr"` motif instead of the previous `" • "` and `"·"` separators. Some agents had been copying the middle-dot literal characters into real edits as if they were format scaffolding (e.g. emitting payload lines like `~ ·`), since the demo inserts were near-twins of the existing string. The new example keeps every original op shape (single-line replace, multiline replace, insert AFTER/BEFORE, append, delete, blank, plus both anti-patterns) but uses content that is obviously domain-specific and clearly distinct from any payload separator. Pure prompt change; no parser, schema, or runtime behavior is affected.
|
|
89
|
+
- Fixed startup fallback-chain validation to recognize cached runtime-discovered standard provider models, including Ollama Cloud models listed by `--list-models`, so `retry.fallbackChains` no longer warns that valid `ollama-cloud/<model>` selectors are unknown. ([#1052](https://github.com/can1357/oh-my-pi/issues/1052))
|
|
90
|
+
- Fixed `discoverAgents()` ignoring `disabledProviders` for the `claude-plugins` provider. Plugin roots from `~/.claude/plugins/` were scanned unconditionally, so agents from Claude Code marketplace plugins continued to appear in `/agents` and the Agent Control Center even when `disabledProviders: [claude-plugins]` was set. The discovery path now checks `isProviderEnabled("claude-plugins")` before calling `listClaudePluginRoots()`, matching how every other capability respects the disabled-providers set. ([#1075](https://github.com/can1357/oh-my-pi/issues/1075))
|
|
91
|
+
|
|
92
|
+
### Fixed
|
|
93
|
+
|
|
94
|
+
- Fixed `$env:VAR` PowerShell variables being mangled on Windows when commands invoked PowerShell as a subprocess (e.g. `powershell -Command "Write-Host $env:SystemRoot"`). Brush-core applied POSIX parameter expansion to `$env` before spawning the child, leaving a dangling `:NAME`. The fix lives in `pi-shell` at env-var application time: every brush session now defines `env=$env` as an internal shell variable so `$env:NAME` expands to the literal `$env:NAME` token that PowerShell expects. The fallback is not exported, only influences brush's own expansion, and is shadowed by any user assignment to `env` (e.g. `env=prod; echo "$env:8080"` still prints `prod:8080`), so the POSIX bash contract is preserved. ([#1079](https://github.com/can1357/oh-my-pi/issues/1079))
|
|
95
|
+
|
|
96
|
+
|
|
5
97
|
## [15.0.1] - 2026-05-14
|
|
6
98
|
### Breaking Changes
|
|
7
99
|
|
|
@@ -15,6 +107,7 @@
|
|
|
15
107
|
- Added per-line column cap shared across streaming tool outputs (`bash`, `ssh`, `python`, `js eval`) and the `read` tool. Lines wider than `tools.outputMaxColumns` bytes (default **768**) are ellipsis-truncated at write time and remaining bytes up to the next `\n` are dropped — bounded memory even on multi-MB single-line outputs (e.g. `cat /dev/urandom`). The cap lives on `OutputSink` as the new `maxColumns` option, persists state across chunk boundaries so split-mid-line writes still respect the budget, and exposes `columnDroppedBytes` / `columnTruncatedLines` on `OutputSummary`. Middle-elision byte math subtracts column drops so the "elided from middle" count stays honest. `read` reuses the same setting but trims its already-collected lines via `truncateLine`. Skipped when the read selector is `:raw`. The artifact file (`artifact://<id>`) keeps the full uncapped stream. Set `tools.outputMaxColumns = 0` to disable.
|
|
16
108
|
- Added Bun HTTP/2 fetch opt-in. Dev scripts (`bun run dev`, `bun run stats`) now pass `bun --experimental-http2-fetch` so every `fetch()` advertises `h2` in the TLS ALPN list and falls back to HTTP/1.1 when the server doesn't select it. Multiplexing collapses parallel requests to the same origin onto one TLS connection. For the installed `omp` binary, export `BUN_FEATURE_FLAG_EXPERIMENTAL_HTTP2_CLIENT=1` in your shell to enable the same behavior (the flag has to be set before Bun starts; `process.env` from inside JS is too late). Requires Bun **1.3.14**.
|
|
17
109
|
- Added per-subagent cost display (`$X.XX` in the task progress tree and the session-observer stats line). Cost is accumulated incrementally from `message_end` events and shown only when non-zero, using the `statusLineCost` theme color. Providers that do not report per-turn cost data (e.g. subscription/OAuth usage) continue to show nothing.
|
|
110
|
+
- Added ACP elicitation bridge so skills/extensions calling `select`, `confirm`, or `input` on the extension UI context now produce real `unstable_createElicitation` form requests to the ACP client (rather than always resolving to `undefined` / `false`). The `acpExtensionUiContext` constant is promoted to `createAcpExtensionUiContext(connection, getSessionId, clientCapabilities)` — invoked once per session inside `#configureExtensions`, with `getSessionId: () => string` so the live `record.session.sessionId` is read on every elicitation (the underlying id mutates when an extension command calls `ctx.newSession` / `ctx.switchSession`). Each method maps to a single-property `value` schema: `select` → `{type: "string", enum}`, `confirm` → `{type: "boolean"}` (joined `title` + `message` when the trimmed message is non-empty; otherwise just `title`), `input` → `{type: "string", description: placeholder?}` (ACP has no `placeholder` field on `StringPropertySchema`; empty / whitespace-only placeholders are treated as absent). `accept` responses narrow the returned `ElicitationContentValue` back to the method's declared type with a runtime `typeof` guard; `decline` / `cancel` / transport failures fall back to the prior stub return values. `dialogOptions.signal` is honored: an already-aborted signal short-circuits before any SDK round-trip, and an abort mid-flight races against the elicitation so the caller's promise resolves to the stub fallback (the ACP request itself keeps running on the client side — the SDK exposes no form-mode cancel surface; `unstable_completeElicitation` is URL-mode only — matching the in-flight pattern used by `requestRpcEditor`). `dialogOptions.timeout` is honored on parity with `RpcExtensionUIContext`: when the timer fires before the client responds, `onTimeout` is invoked and the caller resolves to the stub fallback. A throwing `onTimeout` is caught and logged (`logger.warn`) so the elicitation promise still settles. Late SDK rejections that arrive after abort/timeout are dropped silently to keep operator logs clean; transport failures still emit `logger.warn` with `{ sessionId, method, error }`. Calls are skipped when the client did not advertise `clientCapabilities.elicitation.form` during `initialize`, so non-elicitation clients are unaffected. `createAcpExtensionUiContext` is exported for tests.
|
|
18
111
|
|
|
19
112
|
### Changed
|
|
20
113
|
|
|
@@ -56,7 +149,7 @@
|
|
|
56
149
|
- Added `pr://<N>/diff`, `pr://<N>/diff/<i>`, and `pr://<N>/diff/all` internal-URL shapes covering changed-file listings, per-file slices, and the full unified diff. They share one `pr-diff` SQLite cache row with the same TTL knobs as `pr://<N>` views (`github.cache.softTtlSec` / `github.cache.hardTtlSec` / `github.cache.enabled`). Single PR views now advertise the diff entry point via a `Diff: pr://<owner>/<repo>/<N>/diff` note. Cache schema bumped to `user_version = 3`; older rows are dropped on first open to add credential-scoped keys and relax the `kind` CHECK constraint.
|
|
57
150
|
- Added `issue://` / `pr://` internal-URL schemes that share a SQLite-backed cache with the rest of the `github` tool. Single-item reads (`issue://<N>`, `issue://<owner>/<repo>/<N>`) return rendered markdown and within `github.cache.softTtlSec` (default 5 minutes) skip the `gh` round-trip entirely; within `github.cache.hardTtlSec` (default 7 days) the cached row is returned and a background refresh is scheduled. Root and repo-scoped reads (`issue://`, `pr://owner/repo`) issue a live `gh issue list` / `gh pr list` for browsing, supporting `?state=open|closed|all` for issues, `?state=open|closed|merged|all` for PRs, and `?limit=`, `?author=`, `?label=` query params. Rendered output lands in `~/.omp/cache/github-cache.db` (override via `OMP_GITHUB_CACHE_DB`); disable the cache entirely with `github.cache.enabled = false`. Cwd→default-repo lookups (`gh repo view`) are memoized per-process.
|
|
58
151
|
- Added new `Approve and compact context` choice to the ExitPlanMode approval selector. Sits between `Approve and execute` (purge session) and `Approve and keep context` (full transcript) — runs `/compact` on the plan-mode transcript with a planning-specific summarization hint, then dispatches the plan-approved execution turn so it lands on a fresh cache anchor with the summarized rationale carried over. Cancelling the compaction (Esc or any other abort source) defers the execution dispatch and surfaces a warning so the operator can resubmit manually; non-abort failures proceed best-effort.
|
|
59
|
-
- Added `CompactionCancelledError` typed sentinel and `CompactionOutcome` (`"ok" | "cancelled" | "failed"`) return type to `@oh-my-pi/pi-
|
|
152
|
+
- Added `CompactionCancelledError` typed sentinel and `CompactionOutcome` (`"ok" | "cancelled" | "failed"`) return type to `@oh-my-pi/pi-agent-core/compaction`. `CommandController.executeCompaction` and `handleCompactCommand` now return the outcome instead of `void` so callers can discriminate user-driven aborts from generic failures without inspecting error messages.
|
|
60
153
|
- Added a `credential_disabled` extension event so extensions can subscribe via `pi.on("credential_disabled", handler)` and react when `AuthStorage` automatically soft-disables a credential (e.g. OAuth `invalid_grant`). Replaces the current `agent_end` errorMessage regex pattern downstream extensions have to match against. Handler payload is `{ type, provider, disabledCause }`. `createAgentSession()` subscribes the per-session extension runner to the shared `AuthStorage` via `authStorage.onCredentialDisabled(...)` at the very top of session creation — before any startup model probes run — so events fire on every disable regardless of whether the embedder also has a constructor `onCredentialDisabled` handler attached. The SDK forwards through `ExtensionRunner.emitCredentialDisabled(event)`, which buffers events until `runner.initialize(...)` runs in the mode controller and then flushes them through `emit()` so extension handlers see populated UI/runtime context (rather than the constructor's no-op default with `hasUI=false`, an unset model, and no-op runtime actions). On `session.dispose()` the subscription is unsubscribed; the embedder's constructor-attached listener keeps firing through its own permanent subscription. The outer `createAgentSession()` catch also releases the subscription if startup throws before the dispose-wrap is wired, so repeated retries don't accumulate dead listeners.
|
|
61
154
|
- Added `omp acp` subcommand for launching as an ACP (Agent Client Protocol) server over stdio
|
|
62
155
|
- Added explicit `type` discriminators to ACP `initialize` auth methods, including a `terminal` setup method gated on `clientCapabilities.auth.terminal`
|
|
@@ -47,7 +47,6 @@ See [docs/custom-tools.md](../../docs/custom-tools.md) for full documentation.
|
|
|
47
47
|
**Factory pattern:**
|
|
48
48
|
|
|
49
49
|
```typescript
|
|
50
|
-
import { Type } from "@sinclair/typebox";
|
|
51
50
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
52
51
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
53
52
|
import type { CustomToolFactory } from "@oh-my-pi/pi-coding-agent";
|
|
@@ -56,7 +55,7 @@ const factory: CustomToolFactory = (pi) => ({
|
|
|
56
55
|
name: "my_tool",
|
|
57
56
|
label: "My Tool",
|
|
58
57
|
description: "Tool description for LLM",
|
|
59
|
-
parameters:
|
|
58
|
+
parameters: pi.zod.object({
|
|
60
59
|
action: StringEnum(["list", "add"] as const),
|
|
61
60
|
}),
|
|
62
61
|
|
|
@@ -78,6 +77,8 @@ const factory: CustomToolFactory = (pi) => ({
|
|
|
78
77
|
export default factory;
|
|
79
78
|
```
|
|
80
79
|
|
|
80
|
+
**Legacy:** `parameters: pi.typebox.Type.Object({ ... })` still works; the injected `typebox` is a small Zod-backed shim, and schemas flow through the same Zod pipeline as `pi.zod` schemas.
|
|
81
|
+
|
|
81
82
|
**Custom rendering:**
|
|
82
83
|
|
|
83
84
|
```typescript
|
|
@@ -96,14 +97,17 @@ renderResult(result, { expanded, isPartial }, theme) {
|
|
|
96
97
|
},
|
|
97
98
|
```
|
|
98
99
|
|
|
99
|
-
**Use StringEnum for string
|
|
100
|
+
**Use `StringEnum` for discriminated string tool args** (required for Google API compatibility):
|
|
100
101
|
|
|
101
102
|
```typescript
|
|
102
103
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
const { z } = pi.zod;
|
|
106
|
+
|
|
107
|
+
// Good — Google-safe enum wiring
|
|
108
|
+
parameters: z.object({
|
|
109
|
+
action: StringEnum(["list", "add"] as const),
|
|
110
|
+
});
|
|
106
111
|
|
|
107
|
-
//
|
|
108
|
-
action: Type.Union([Type.Literal("list"), Type.Literal("add")]);
|
|
112
|
+
// Avoid raw union-of-literals patterns that don't degrade well for strict JSON Schema providers
|
|
109
113
|
```
|
|
@@ -4,8 +4,8 @@ const factory: CustomToolFactory = pi => ({
|
|
|
4
4
|
name: "hello",
|
|
5
5
|
label: "Hello",
|
|
6
6
|
description: "A simple greeting tool",
|
|
7
|
-
parameters: pi.
|
|
8
|
-
name: pi.
|
|
7
|
+
parameters: pi.zod.object({
|
|
8
|
+
name: pi.zod.string().describe("Name to greet"),
|
|
9
9
|
}),
|
|
10
10
|
|
|
11
11
|
async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
|
|
@@ -71,9 +71,10 @@ See [docs/extensions.md](../../docs/extensions.md) for full documentation.
|
|
|
71
71
|
|
|
72
72
|
```typescript
|
|
73
73
|
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
74
|
-
import { Type } from "@sinclair/typebox";
|
|
75
74
|
|
|
76
75
|
export default function (pi: ExtensionAPI) {
|
|
76
|
+
const z = pi.zod;
|
|
77
|
+
|
|
77
78
|
// Subscribe to lifecycle events
|
|
78
79
|
pi.on("tool_call", async (event, ctx) => {
|
|
79
80
|
if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
|
|
@@ -87,8 +88,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
87
88
|
name: "greet",
|
|
88
89
|
label: "Greeting",
|
|
89
90
|
description: "Generate a greeting",
|
|
90
|
-
parameters:
|
|
91
|
-
name:
|
|
91
|
+
parameters: z.object({
|
|
92
|
+
name: z.string().describe("Name to greet"),
|
|
92
93
|
}),
|
|
93
94
|
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
94
95
|
return {
|
|
@@ -108,18 +109,28 @@ export default function (pi: ExtensionAPI) {
|
|
|
108
109
|
}
|
|
109
110
|
```
|
|
110
111
|
|
|
112
|
+
**Legacy TypeBox-style schemas** (`pi.typebox`) remain available for older extensions and are backed by a tiny Zod-shim — prefer `pi.zod` directly for new code.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const { Type } = pi.typebox;
|
|
116
|
+
parameters: Type.Object({ name: Type.String() });
|
|
117
|
+
```
|
|
118
|
+
|
|
111
119
|
## Key Patterns
|
|
112
120
|
|
|
113
|
-
**Use StringEnum for string
|
|
121
|
+
**Use `StringEnum` for discriminated string tool args** (required for Google API compatibility):
|
|
114
122
|
|
|
115
123
|
```typescript
|
|
116
124
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
const { z } = pi.zod;
|
|
127
|
+
|
|
128
|
+
// Good — Google-safe enum wiring
|
|
129
|
+
parameters: z.object({
|
|
130
|
+
action: StringEnum(["list", "add"] as const),
|
|
131
|
+
});
|
|
120
132
|
|
|
121
|
-
//
|
|
122
|
-
action: Type.Union([Type.Literal("list"), Type.Literal("add")]);
|
|
133
|
+
// Avoid raw union-of-literals patterns that don't degrade well for strict JSON Schema providers
|
|
123
134
|
```
|
|
124
135
|
|
|
125
136
|
**State persistence via details:**
|
|
@@ -1,39 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* API Demo Extension
|
|
3
3
|
*
|
|
4
|
-
* Demonstrates using ExtensionAPI's logger,
|
|
4
|
+
* Demonstrates using ExtensionAPI's logger, injected `pi.zod`, and pi module access.
|
|
5
5
|
* These features are now exposed directly on the ExtensionAPI, matching
|
|
6
6
|
* the CustomToolAPI interface.
|
|
7
7
|
*/
|
|
8
8
|
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
9
9
|
|
|
10
10
|
export default function (pi: ExtensionAPI) {
|
|
11
|
-
|
|
12
|
-
const { Type } = pi.typebox;
|
|
11
|
+
const { z } = pi.zod;
|
|
13
12
|
|
|
14
|
-
//
|
|
15
|
-
pi.logger.debug("API demo extension loaded");
|
|
16
|
-
|
|
17
|
-
// 3. Register a tool that uses all three API features
|
|
18
|
-
// Import StringEnum from typebox helpers
|
|
13
|
+
// Access shared schema helpers from package exports (e.g. StringEnum for Google-safe enums)
|
|
19
14
|
const { StringEnum } = pi.pi;
|
|
20
15
|
|
|
16
|
+
// Access the logger for debugging
|
|
17
|
+
pi.logger.debug("API demo extension loaded");
|
|
18
|
+
|
|
21
19
|
pi.registerTool({
|
|
22
20
|
name: "api_demo",
|
|
23
21
|
label: "API Demo",
|
|
24
|
-
description: "Demonstrates ExtensionAPI capabilities: logger,
|
|
25
|
-
parameters:
|
|
26
|
-
message:
|
|
27
|
-
logLevel:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}),
|
|
32
|
-
),
|
|
22
|
+
description: "Demonstrates ExtensionAPI capabilities: logger, zod, and pi module access",
|
|
23
|
+
parameters: z.object({
|
|
24
|
+
message: z.string().describe("Test message"),
|
|
25
|
+
logLevel: StringEnum(["error", "warn", "debug"], {
|
|
26
|
+
description: "Log level to use",
|
|
27
|
+
default: "debug",
|
|
28
|
+
}),
|
|
33
29
|
}),
|
|
34
30
|
|
|
35
31
|
async execute(_toolCallId, params, _onUpdate, ctx, _signal) {
|
|
36
|
-
const { message, logLevel
|
|
32
|
+
const { message, logLevel } = params;
|
|
37
33
|
|
|
38
34
|
// Use logger at specified level
|
|
39
35
|
pi.logger[logLevel]("API demo tool executed", { message, logLevel });
|
|
@@ -58,7 +54,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
58
54
|
``,
|
|
59
55
|
`Features demonstrated:`,
|
|
60
56
|
`1. ✓ Logger access via pi.logger`,
|
|
61
|
-
`2. ✓
|
|
57
|
+
`2. ✓ Zod access via pi.zod`,
|
|
62
58
|
`3. ✓ Pi module access via pi.pi`,
|
|
63
59
|
``,
|
|
64
60
|
`Context:`,
|
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hello Tool - Minimal custom tool example
|
|
3
3
|
*
|
|
4
|
-
* Demonstrates using ExtensionAPI's logger,
|
|
4
|
+
* Demonstrates using ExtensionAPI's logger, injected `pi.zod`, and pi module access.
|
|
5
5
|
*/
|
|
6
6
|
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
7
7
|
|
|
8
8
|
export default function (pi: ExtensionAPI) {
|
|
9
|
-
|
|
10
|
-
const { Type } = pi.typebox;
|
|
9
|
+
const { z } = pi.zod;
|
|
11
10
|
|
|
12
11
|
pi.registerTool({
|
|
13
12
|
name: "hello",
|
|
14
13
|
label: "Hello",
|
|
15
14
|
description: "A simple greeting tool",
|
|
16
|
-
parameters:
|
|
17
|
-
name:
|
|
15
|
+
parameters: z.object({
|
|
16
|
+
name: z.string().describe("Name to greet"),
|
|
18
17
|
}),
|
|
19
18
|
|
|
20
19
|
async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
|
|
21
|
-
const { name } = params
|
|
20
|
+
const { name } = params;
|
|
22
21
|
|
|
23
22
|
// Use logger for debugging
|
|
24
23
|
pi.logger.debug("Hello tool executed", { name });
|
|
@@ -426,7 +426,7 @@ Execute each step in order.`,
|
|
|
426
426
|
|
|
427
427
|
// Extract todos from last message
|
|
428
428
|
const messages = event.messages;
|
|
429
|
-
const lastAssistant =
|
|
429
|
+
const lastAssistant = messages.findLast(m => m.role === "assistant");
|
|
430
430
|
if (lastAssistant && Array.isArray(lastAssistant.content)) {
|
|
431
431
|
const textContent = lastAssistant.content
|
|
432
432
|
.filter(
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
* tool that queues a follow-up command to trigger reload.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { ExtensionAPI } from "@
|
|
9
|
-
import { Type } from "@sinclair/typebox";
|
|
8
|
+
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
10
9
|
|
|
11
10
|
export default function (pi: ExtensionAPI) {
|
|
11
|
+
const { z } = pi.zod;
|
|
12
|
+
|
|
12
13
|
// Command entrypoint for reload.
|
|
13
14
|
// Treat reload as terminal for this handler.
|
|
14
15
|
pi.registerCommand("reload-runtime", {
|
|
@@ -25,7 +26,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
25
26
|
name: "reload_runtime",
|
|
26
27
|
label: "Reload Runtime",
|
|
27
28
|
description: "Reload extensions, skills, prompts, and themes",
|
|
28
|
-
parameters:
|
|
29
|
+
parameters: z.object({}),
|
|
29
30
|
async execute() {
|
|
30
31
|
pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" });
|
|
31
32
|
return {
|
|
@@ -5,17 +5,18 @@
|
|
|
5
5
|
* Requires: npm install in this directory
|
|
6
6
|
*/
|
|
7
7
|
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
8
|
-
import { Type } from "@sinclair/typebox";
|
|
9
8
|
import ms from "ms";
|
|
10
9
|
|
|
11
10
|
export default function (pi: ExtensionAPI) {
|
|
11
|
+
const { z } = pi.zod;
|
|
12
|
+
|
|
12
13
|
// Register a tool that uses ms
|
|
13
14
|
pi.registerTool({
|
|
14
15
|
name: "parse_duration",
|
|
15
16
|
label: "Parse Duration",
|
|
16
17
|
description: "Parse a human-readable duration string (e.g., '2 days', '1h', '5m') to milliseconds",
|
|
17
|
-
parameters:
|
|
18
|
-
duration:
|
|
18
|
+
parameters: z.object({
|
|
19
|
+
duration: z.string().describe("Duration string like '2 days', '1h', '5m'"),
|
|
19
20
|
}),
|
|
20
21
|
execute: async (_toolCallId, params) => {
|
|
21
22
|
const result = ms(params.duration as ms.StringValue);
|
|
@@ -41,6 +41,8 @@ console.log();
|
|
|
41
41
|
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
42
42
|
|
|
43
43
|
export default function (pi: ExtensionAPI) {
|
|
44
|
+
const { z } = pi.zod;
|
|
45
|
+
|
|
44
46
|
pi.on("agent_start", async () => {
|
|
45
47
|
console.log("[Extension] Agent starting");
|
|
46
48
|
});
|
|
@@ -60,8 +62,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
60
62
|
name: "my_tool",
|
|
61
63
|
label: "My Tool",
|
|
62
64
|
description: "Does something useful",
|
|
63
|
-
parameters:
|
|
64
|
-
input:
|
|
65
|
+
parameters: z.object({
|
|
66
|
+
input: z.string(),
|
|
65
67
|
}),
|
|
66
68
|
execute: async (_toolCallId, params, _onUpdate, _ctx, _signal) => ({
|
|
67
69
|
content: [{ type: "text", text: \`Processed: \${params.input}\` }],
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "15.0
|
|
4
|
+
"version": "15.1.0",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
|
-
"homepage": "https://
|
|
6
|
+
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
8
8
|
"contributors": [
|
|
9
9
|
"Mario Zechner"
|
|
@@ -47,17 +47,15 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
48
48
|
"@babel/parser": "^7.29.3",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/omp-stats": "15.0
|
|
51
|
-
"@oh-my-pi/pi-agent-core": "15.0
|
|
52
|
-
"@oh-my-pi/pi-ai": "15.0
|
|
53
|
-
"@oh-my-pi/pi-natives": "15.0
|
|
54
|
-
"@oh-my-pi/pi-tui": "15.0
|
|
55
|
-
"@oh-my-pi/pi-utils": "15.0
|
|
50
|
+
"@oh-my-pi/omp-stats": "15.1.0",
|
|
51
|
+
"@oh-my-pi/pi-agent-core": "15.1.0",
|
|
52
|
+
"@oh-my-pi/pi-ai": "15.1.0",
|
|
53
|
+
"@oh-my-pi/pi-natives": "15.1.0",
|
|
54
|
+
"@oh-my-pi/pi-tui": "15.1.0",
|
|
55
|
+
"@oh-my-pi/pi-utils": "15.1.0",
|
|
56
56
|
"@puppeteer/browsers": "^2.13.0",
|
|
57
|
-
"@sinclair/typebox": "^0.34.49",
|
|
58
57
|
"@types/turndown": "5.0.6",
|
|
59
58
|
"@xterm/headless": "^6.0.0",
|
|
60
|
-
"ajv": "^8.20.0",
|
|
61
59
|
"chalk": "^5.6.2",
|
|
62
60
|
"diff": "^9.0.0",
|
|
63
61
|
"fflate": "0.8.2",
|
|
@@ -473,14 +471,6 @@
|
|
|
473
471
|
"types": "./src/session/*.ts",
|
|
474
472
|
"import": "./src/session/*.ts"
|
|
475
473
|
},
|
|
476
|
-
"./session/compaction": {
|
|
477
|
-
"types": "./src/session/compaction/index.ts",
|
|
478
|
-
"import": "./src/session/compaction/index.ts"
|
|
479
|
-
},
|
|
480
|
-
"./session/compaction/*": {
|
|
481
|
-
"types": "./src/session/compaction/*.ts",
|
|
482
|
-
"import": "./src/session/compaction/*.ts"
|
|
483
|
-
},
|
|
484
474
|
"./slash-commands/*": {
|
|
485
475
|
"types": "./src/slash-commands/*.ts",
|
|
486
476
|
"import": "./src/slash-commands/*.ts"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
4
|
-
import
|
|
4
|
+
import * as z from "zod/v4";
|
|
5
5
|
import type { ToolDefinition } from "../../extensibility/extensions";
|
|
6
6
|
import type { Theme } from "../../modes/theme/theme";
|
|
7
7
|
import { replaceTabs, truncateToWidth } from "../../tools/render-utils";
|
|
@@ -16,46 +16,43 @@ export const HARNESS_FILENAME = "autoresearch.sh";
|
|
|
16
16
|
export const DEFAULT_HARNESS_COMMAND = `bash ${HARNESS_FILENAME}`;
|
|
17
17
|
const HARNESS_COMMIT_TITLE = "autoresearch: harness setup";
|
|
18
18
|
|
|
19
|
-
const initExperimentSchema =
|
|
20
|
-
name:
|
|
21
|
-
goal:
|
|
22
|
-
primary_metric:
|
|
23
|
-
|
|
19
|
+
const initExperimentSchema = z.object({
|
|
20
|
+
name: z.string().describe("Human-readable experiment name."),
|
|
21
|
+
goal: z.string().describe("Free-form description of what this session optimizes.").optional(),
|
|
22
|
+
primary_metric: z
|
|
23
|
+
.string()
|
|
24
|
+
.describe(
|
|
24
25
|
"Primary metric name shown in the dashboard. Match the `METRIC <name>=<value>` lines printed by the benchmark.",
|
|
25
|
-
|
|
26
|
-
metric_unit:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
),
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
description:
|
|
56
|
-
"When true, bump to a new segment even when an active session exists. New baselines and best-metric reset.",
|
|
57
|
-
}),
|
|
58
|
-
),
|
|
26
|
+
),
|
|
27
|
+
metric_unit: z.string().describe("Unit for the primary metric (e.g. ms, µs, mb). Empty when unitless.").optional(),
|
|
28
|
+
direction: z
|
|
29
|
+
.enum(["lower", "higher"] as const)
|
|
30
|
+
.describe("Whether lower or higher values are better. Defaults to lower.")
|
|
31
|
+
.optional(),
|
|
32
|
+
secondary_metrics: z
|
|
33
|
+
.array(z.string())
|
|
34
|
+
.describe("Names of secondary metrics tracked alongside the primary metric.")
|
|
35
|
+
.optional(),
|
|
36
|
+
scope_paths: z
|
|
37
|
+
.array(z.string())
|
|
38
|
+
.describe(
|
|
39
|
+
"Files or directories the agent expects to modify. Used post-hoc to flag scope deviations on log_experiment; never used to block edits.",
|
|
40
|
+
)
|
|
41
|
+
.optional(),
|
|
42
|
+
off_limits: z
|
|
43
|
+
.array(z.string())
|
|
44
|
+
.describe(
|
|
45
|
+
"Paths the agent SHOULD NOT modify. Used post-hoc to flag scope deviations on log_experiment; never used to block edits.",
|
|
46
|
+
)
|
|
47
|
+
.optional(),
|
|
48
|
+
constraints: z.array(z.string()).describe("Free-form constraints (e.g. 'no api break').").optional(),
|
|
49
|
+
max_iterations: z.number().describe("Soft cap on iterations per segment. Optional.").optional(),
|
|
50
|
+
new_segment: z
|
|
51
|
+
.boolean()
|
|
52
|
+
.describe(
|
|
53
|
+
"When true, bump to a new segment even when an active session exists. New baselines and best-metric reset.",
|
|
54
|
+
)
|
|
55
|
+
.optional(),
|
|
59
56
|
});
|
|
60
57
|
|
|
61
58
|
interface InitExperimentDetails {
|