@oh-my-pi/pi-coding-agent 15.0.2 → 15.1.1
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 +56 -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 +7 -17
- 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/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 +9 -190
- package/src/config/models-config-schema.ts +166 -0
- package/src/config/settings-schema.ts +18 -0
- 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/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/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 +30 -0
- 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/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 +7 -7
- 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/components/session-observer-overlay.ts +12 -1
- package/src/modes/components/status-line/segments.ts +2 -1
- package/src/modes/controllers/command-controller.ts +27 -2
- package/src/modes/controllers/event-controller.ts +3 -4
- package/src/modes/interactive-mode.ts +1 -1
- package/src/modes/rpc/host-tools.ts +1 -1
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/modes/theme/theme.ts +111 -117
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/context-usage.ts +2 -2
- 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/executor.ts +208 -86
- 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.ts +9 -23
- 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 +6 -8
- package/src/tools/find.ts +10 -13
- package/src/tools/gh.ts +71 -128
- 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 +32 -82
- 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 +14 -21
- package/src/tools/read.ts +7 -8
- 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 +7 -7
- package/src/tools/todo-write.ts +26 -34
- package/src/tools/vim.ts +10 -26
- package/src/tools/write.ts +5 -5
- package/src/tools/yield.ts +100 -54
- package/src/web/search/index.ts +9 -24
- 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,61 @@
|
|
|
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
|
+
|
|
5
60
|
## [15.0.2] - 2026-05-15
|
|
6
61
|
|
|
7
62
|
### Added
|
|
@@ -94,7 +149,7 @@
|
|
|
94
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.
|
|
95
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.
|
|
96
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.
|
|
97
|
-
- 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.
|
|
98
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.
|
|
99
154
|
- Added `omp acp` subcommand for launching as an ACP (Agent Client Protocol) server over stdio
|
|
100
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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.1.1",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -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.
|
|
51
|
-
"@oh-my-pi/pi-agent-core": "15.
|
|
52
|
-
"@oh-my-pi/pi-ai": "15.
|
|
53
|
-
"@oh-my-pi/pi-natives": "15.
|
|
54
|
-
"@oh-my-pi/pi-tui": "15.
|
|
55
|
-
"@oh-my-pi/pi-utils": "15.
|
|
50
|
+
"@oh-my-pi/omp-stats": "15.1.1",
|
|
51
|
+
"@oh-my-pi/pi-agent-core": "15.1.1",
|
|
52
|
+
"@oh-my-pi/pi-ai": "15.1.1",
|
|
53
|
+
"@oh-my-pi/pi-natives": "15.1.1",
|
|
54
|
+
"@oh-my-pi/pi-tui": "15.1.1",
|
|
55
|
+
"@oh-my-pi/pi-utils": "15.1.1",
|
|
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 {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
5
|
-
import
|
|
5
|
+
import * as z from "zod/v4";
|
|
6
6
|
import type { ToolDefinition } from "../../extensibility/extensions";
|
|
7
7
|
import type { Theme } from "../../modes/theme/theme";
|
|
8
8
|
import { replaceTabs, truncateToWidth } from "../../tools/render-utils";
|
|
@@ -36,46 +36,37 @@ import type {
|
|
|
36
36
|
|
|
37
37
|
const EXPERIMENT_TOOL_NAMES = ["init_experiment", "run_experiment", "log_experiment", "update_notes"];
|
|
38
38
|
|
|
39
|
-
const logExperimentSchema =
|
|
40
|
-
metric:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
status:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
}),
|
|
67
|
-
),
|
|
68
|
-
flag_runs: Type.Optional(
|
|
69
|
-
Type.Array(
|
|
70
|
-
Type.Object({
|
|
71
|
-
run_id: Type.Number({ description: "Run id (#) of a previously logged run to flag as suspect." }),
|
|
72
|
-
reason: Type.String({
|
|
73
|
-
description: "Why this earlier run is suspect (e.g. reward-hacked, broken metric).",
|
|
74
|
-
}),
|
|
39
|
+
const logExperimentSchema = z.object({
|
|
40
|
+
metric: z
|
|
41
|
+
.number()
|
|
42
|
+
.describe("Primary metric value for this run. May differ from the parsed value; deviation is recorded."),
|
|
43
|
+
status: z.enum(["keep", "discard", "crash", "checks_failed"] as const).describe("Outcome for this run."),
|
|
44
|
+
description: z.string().describe("Short description of the experiment."),
|
|
45
|
+
metrics: z.record(z.string(), z.number()).describe("Secondary metrics for this run.").optional(),
|
|
46
|
+
asi: z
|
|
47
|
+
.object({})
|
|
48
|
+
.passthrough()
|
|
49
|
+
.describe("Free-form structured metadata captured for this run (hypothesis, learnings, etc.).")
|
|
50
|
+
.optional(),
|
|
51
|
+
commit: z
|
|
52
|
+
.string()
|
|
53
|
+
.describe("Override the commit hash recorded for this run. Defaults to the current HEAD.")
|
|
54
|
+
.optional(),
|
|
55
|
+
justification: z
|
|
56
|
+
.string()
|
|
57
|
+
.describe(
|
|
58
|
+
"Required when the run modifies paths outside scope or inside off-limits and you still want it kept. Free-form explanation.",
|
|
59
|
+
)
|
|
60
|
+
.optional(),
|
|
61
|
+
flag_runs: z
|
|
62
|
+
.array(
|
|
63
|
+
z.object({
|
|
64
|
+
run_id: z.number().describe("Run id (#) of a previously logged run to flag as suspect."),
|
|
65
|
+
reason: z.string().describe("Why this earlier run is suspect (e.g. reward-hacked, broken metric)."),
|
|
75
66
|
}),
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
|
|
67
|
+
)
|
|
68
|
+
.describe("Mark earlier runs as flagged. Flagged runs are excluded from baseline and best-metric math.")
|
|
69
|
+
.optional(),
|
|
79
70
|
});
|
|
80
71
|
|
|
81
72
|
export function createLogExperimentTool(
|
|
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
5
5
|
import { formatBytes } from "@oh-my-pi/pi-utils";
|
|
6
|
-
import
|
|
6
|
+
import * as z from "zod/v4";
|
|
7
7
|
import type { ToolDefinition } from "../../extensibility/extensions";
|
|
8
8
|
import type { Theme } from "../../modes/theme/theme";
|
|
9
9
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateTail } from "../../session/streaming-output";
|
|
@@ -26,8 +26,8 @@ import { openAutoresearchStorageIfExists } from "../storage";
|
|
|
26
26
|
import type { AutoresearchToolFactoryOptions, RunDetails, RunExperimentProgressDetails } from "../types";
|
|
27
27
|
import { DEFAULT_HARNESS_COMMAND } from "./init-experiment";
|
|
28
28
|
|
|
29
|
-
const runExperimentSchema =
|
|
30
|
-
timeout_seconds:
|
|
29
|
+
const runExperimentSchema = z.object({
|
|
30
|
+
timeout_seconds: z.number().describe("Timeout in seconds. Defaults to 600.").optional(),
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
interface ProcessExecutionResult {
|