@oh-my-pi/pi-coding-agent 15.0.2 → 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.
Files changed (138) hide show
  1. package/CHANGELOG.md +56 -1
  2. package/examples/custom-tools/README.md +11 -7
  3. package/examples/custom-tools/hello/index.ts +2 -2
  4. package/examples/extensions/README.md +19 -8
  5. package/examples/extensions/api-demo.ts +15 -19
  6. package/examples/extensions/hello.ts +5 -6
  7. package/examples/extensions/plan-mode.ts +1 -1
  8. package/examples/extensions/reload-runtime.ts +4 -3
  9. package/examples/extensions/with-deps/index.ts +4 -3
  10. package/examples/sdk/06-extensions.ts +4 -2
  11. package/package.json +7 -17
  12. package/src/autoresearch/tools/init-experiment.ts +38 -41
  13. package/src/autoresearch/tools/log-experiment.ts +32 -41
  14. package/src/autoresearch/tools/run-experiment.ts +3 -3
  15. package/src/autoresearch/tools/update-notes.ts +11 -11
  16. package/src/commit/agentic/tools/analyze-file.ts +4 -4
  17. package/src/commit/agentic/tools/git-file-diff.ts +4 -4
  18. package/src/commit/agentic/tools/git-hunk.ts +5 -5
  19. package/src/commit/agentic/tools/git-overview.ts +4 -4
  20. package/src/commit/agentic/tools/propose-changelog.ts +13 -13
  21. package/src/commit/agentic/tools/propose-commit.ts +6 -6
  22. package/src/commit/agentic/tools/recent-commits.ts +3 -3
  23. package/src/commit/agentic/tools/schemas.ts +28 -28
  24. package/src/commit/agentic/tools/split-commit.ts +22 -21
  25. package/src/commit/analysis/summary.ts +4 -4
  26. package/src/commit/changelog/generate.ts +7 -11
  27. package/src/commit/shared-llm.ts +22 -34
  28. package/src/config/config-file.ts +35 -13
  29. package/src/config/model-registry.ts +9 -190
  30. package/src/config/models-config-schema.ts +166 -0
  31. package/src/config/settings-schema.ts +18 -0
  32. package/src/edit/index.ts +2 -2
  33. package/src/edit/modes/apply-patch.ts +7 -6
  34. package/src/edit/modes/patch.ts +18 -25
  35. package/src/edit/modes/replace.ts +18 -20
  36. package/src/eval/js/shared/rewrite-imports.ts +131 -10
  37. package/src/eval/py/executor.ts +233 -623
  38. package/src/eval/py/kernel.ts +27 -2
  39. package/src/exa/factory.ts +5 -4
  40. package/src/exa/mcp-client.ts +1 -1
  41. package/src/exa/researcher.ts +9 -20
  42. package/src/exa/search.ts +26 -52
  43. package/src/exa/types.ts +1 -1
  44. package/src/exa/websets.ts +54 -53
  45. package/src/exec/bash-executor.ts +2 -1
  46. package/src/extensibility/custom-commands/loader.ts +5 -3
  47. package/src/extensibility/custom-commands/types.ts +4 -2
  48. package/src/extensibility/custom-tools/loader.ts +5 -3
  49. package/src/extensibility/custom-tools/types.ts +7 -6
  50. package/src/extensibility/custom-tools/wrapper.ts +1 -1
  51. package/src/extensibility/extensions/loader.ts +7 -3
  52. package/src/extensibility/extensions/types.ts +9 -5
  53. package/src/extensibility/extensions/wrapper.ts +1 -2
  54. package/src/extensibility/hooks/loader.ts +3 -1
  55. package/src/extensibility/hooks/tool-wrapper.ts +1 -1
  56. package/src/extensibility/hooks/types.ts +4 -2
  57. package/src/extensibility/plugins/legacy-pi-compat.ts +30 -0
  58. package/src/extensibility/shared-events.ts +1 -1
  59. package/src/extensibility/typebox.ts +391 -0
  60. package/src/goals/tools/goal-tool.ts +6 -12
  61. package/src/hashline/types.ts +4 -4
  62. package/src/hindsight/state.ts +2 -2
  63. package/src/index.ts +0 -2
  64. package/src/internal-urls/docs-index.generated.ts +7 -7
  65. package/src/lsp/types.ts +30 -38
  66. package/src/mcp/manager.ts +1 -1
  67. package/src/mcp/tool-bridge.ts +1 -1
  68. package/src/modes/components/session-observer-overlay.ts +12 -1
  69. package/src/modes/components/status-line/segments.ts +2 -1
  70. package/src/modes/controllers/command-controller.ts +27 -2
  71. package/src/modes/controllers/event-controller.ts +3 -4
  72. package/src/modes/interactive-mode.ts +1 -1
  73. package/src/modes/rpc/host-tools.ts +1 -1
  74. package/src/modes/rpc/rpc-client.ts +1 -1
  75. package/src/modes/rpc/rpc-types.ts +1 -1
  76. package/src/modes/theme/theme.ts +111 -117
  77. package/src/modes/types.ts +1 -1
  78. package/src/modes/utils/context-usage.ts +2 -2
  79. package/src/sdk.ts +31 -8
  80. package/src/session/agent-session.ts +74 -104
  81. package/src/session/messages.ts +16 -51
  82. package/src/session/session-manager.ts +22 -2
  83. package/src/session/streaming-output.ts +16 -6
  84. package/src/task/executor.ts +208 -86
  85. package/src/task/index.ts +15 -11
  86. package/src/task/render.ts +32 -5
  87. package/src/task/types.ts +54 -39
  88. package/src/tools/ask.ts +12 -12
  89. package/src/tools/ast-edit.ts +11 -15
  90. package/src/tools/ast-grep.ts +9 -10
  91. package/src/tools/bash.ts +9 -23
  92. package/src/tools/browser.ts +39 -53
  93. package/src/tools/calculator.ts +12 -11
  94. package/src/tools/checkpoint.ts +7 -7
  95. package/src/tools/debug.ts +40 -43
  96. package/src/tools/eval.ts +6 -8
  97. package/src/tools/find.ts +10 -13
  98. package/src/tools/gh.ts +71 -128
  99. package/src/tools/hindsight-recall.ts +4 -6
  100. package/src/tools/hindsight-reflect.ts +5 -5
  101. package/src/tools/hindsight-retain.ts +15 -17
  102. package/src/tools/image-gen.ts +31 -81
  103. package/src/tools/index.ts +4 -1
  104. package/src/tools/inspect-image.ts +8 -9
  105. package/src/tools/irc.ts +15 -27
  106. package/src/tools/job.ts +14 -21
  107. package/src/tools/read.ts +7 -8
  108. package/src/tools/recipe/index.ts +7 -9
  109. package/src/tools/render-mermaid.ts +12 -12
  110. package/src/tools/report-tool-issue.ts +4 -4
  111. package/src/tools/resolve.ts +11 -11
  112. package/src/tools/review.ts +14 -26
  113. package/src/tools/search-tool-bm25.ts +7 -9
  114. package/src/tools/search.ts +19 -22
  115. package/src/tools/ssh.ts +7 -7
  116. package/src/tools/todo-write.ts +26 -34
  117. package/src/tools/vim.ts +10 -26
  118. package/src/tools/write.ts +5 -5
  119. package/src/tools/yield.ts +100 -54
  120. package/src/web/search/index.ts +9 -24
  121. package/src/prompts/compaction/branch-summary-context.md +0 -5
  122. package/src/prompts/compaction/branch-summary-preamble.md +0 -2
  123. package/src/prompts/compaction/branch-summary.md +0 -30
  124. package/src/prompts/compaction/compaction-short-summary.md +0 -9
  125. package/src/prompts/compaction/compaction-summary-context.md +0 -5
  126. package/src/prompts/compaction/compaction-summary.md +0 -38
  127. package/src/prompts/compaction/compaction-turn-prefix.md +0 -17
  128. package/src/prompts/compaction/compaction-update-summary.md +0 -45
  129. package/src/prompts/system/auto-handoff-threshold-focus.md +0 -1
  130. package/src/prompts/system/file-operations.md +0 -10
  131. package/src/prompts/system/handoff-document.md +0 -49
  132. package/src/prompts/system/summarization-system.md +0 -3
  133. package/src/session/compaction/branch-summarization.ts +0 -324
  134. package/src/session/compaction/compaction.ts +0 -1420
  135. package/src/session/compaction/errors.ts +0 -31
  136. package/src/session/compaction/index.ts +0 -8
  137. package/src/session/compaction/pruning.ts +0 -91
  138. package/src/session/compaction/utils.ts +0 -184
package/src/tools/eval.ts CHANGED
@@ -3,7 +3,7 @@ import type { ImageContent } from "@oh-my-pi/pi-ai";
3
3
  import type { Component } from "@oh-my-pi/pi-tui";
4
4
  import { Markdown, Text } from "@oh-my-pi/pi-tui";
5
5
  import { prompt } from "@oh-my-pi/pi-utils";
6
- import { type Static, Type } from "@sinclair/typebox";
6
+ import * as z from "zod/v4";
7
7
  import { jsBackend, parseEvalInput, pythonBackend, sniffEvalLanguage } from "../eval";
8
8
  import type { ExecutorBackend } from "../eval/backend";
9
9
  import evalGrammar from "../eval/eval.lark" with { type: "text" };
@@ -29,12 +29,10 @@ import { clampTimeout } from "./tool-timeouts";
29
29
 
30
30
  export const EVAL_DEFAULT_PREVIEW_LINES = 10;
31
31
 
32
- export const evalSchema = Type.Object({
33
- input: Type.String({
34
- description: 'eval input as a sequence of `*** Cell <lang>:"title"` cell headers followed by code',
35
- }),
32
+ export const evalSchema = z.object({
33
+ input: z.string().describe('eval input as a sequence of `*** Cell <lang>:"title"` cell headers followed by code'),
36
34
  });
37
- export type EvalToolParams = Static<typeof evalSchema>;
35
+ export type EvalToolParams = z.infer<typeof evalSchema>;
38
36
 
39
37
  export type EvalToolResult = {
40
38
  content: Array<{ type: "text"; text: string }>;
@@ -228,7 +226,7 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
228
226
  readonly parameters = evalSchema;
229
227
  readonly concurrency = "exclusive";
230
228
  readonly strict = true;
231
- readonly intent = (args: Partial<Static<typeof evalSchema>>): string | undefined => {
229
+ readonly intent = (args: Partial<z.infer<typeof evalSchema>>): string | undefined => {
232
230
  const input = args.input;
233
231
  if (input) {
234
232
  try {
@@ -254,7 +252,7 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
254
252
 
255
253
  async execute(
256
254
  _toolCallId: string,
257
- params: Static<typeof evalSchema>,
255
+ params: z.infer<typeof evalSchema>,
258
256
  signal?: AbortSignal,
259
257
  onUpdate?: AgentToolUpdateCallback,
260
258
  _ctx?: AgentToolContext,
package/src/tools/find.ts CHANGED
@@ -5,8 +5,7 @@ import * as natives from "@oh-my-pi/pi-natives";
5
5
  import type { Component } from "@oh-my-pi/pi-tui";
6
6
  import { Text } from "@oh-my-pi/pi-tui";
7
7
  import { isEnoent, prompt, untilAborted } from "@oh-my-pi/pi-utils";
8
- import type { Static } from "@sinclair/typebox";
9
- import { Type } from "@sinclair/typebox";
8
+ import * as z from "zod/v4";
10
9
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
11
10
  import { InternalUrlRouter } from "../internal-urls";
12
11
  import type { Theme } from "../modes/theme/theme";
@@ -35,17 +34,15 @@ import {
35
34
  import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
36
35
  import { toolResult } from "./tool-result";
37
36
 
38
- const findSchema = Type.Object({
39
- paths: Type.Array(Type.String({ description: "glob including search path" }), {
40
- minItems: 1,
41
- description: "globs including search paths",
42
- examples: [["src/**/*.ts"], ["lib/*.json"], ["apps/", "packages/"], ["*.ts"]],
43
- }),
44
- hidden: Type.Optional(Type.Boolean({ description: "include hidden files", default: true })),
45
- limit: Type.Optional(Type.Number({ description: "max results", default: 1000 })),
46
- });
37
+ const findSchema = z
38
+ .object({
39
+ paths: z.array(z.string().describe("glob including search path")).min(1).describe("globs including search paths"),
40
+ hidden: z.boolean().default(true).describe("include hidden files").optional(),
41
+ limit: z.number().default(1000).describe("max results").optional(),
42
+ })
43
+ .strict();
47
44
 
48
- export type FindToolInput = Static<typeof findSchema>;
45
+ export type FindToolInput = z.infer<typeof findSchema>;
49
46
 
50
47
  const DEFAULT_LIMIT = 1000;
51
48
  const GLOB_TIMEOUT_MS = 5000;
@@ -107,7 +104,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
107
104
 
108
105
  async execute(
109
106
  _toolCallId: string,
110
- params: Static<typeof findSchema>,
107
+ params: z.infer<typeof findSchema>,
111
108
  signal?: AbortSignal,
112
109
  onUpdate?: AgentToolUpdateCallback<FindToolDetails>,
113
110
  _context?: AgentToolContext,
package/src/tools/gh.ts CHANGED
@@ -3,9 +3,9 @@ import * as os from "node:os";
3
3
  import * as path from "node:path";
4
4
  import { scheduler } from "node:timers/promises";
5
5
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
6
- import { StringEnum } from "@oh-my-pi/pi-ai";
6
+
7
7
  import { getWorktreesDir, isEnoent, prompt, untilAborted } from "@oh-my-pi/pi-utils";
8
- import { type Static, Type } from "@sinclair/typebox";
8
+ import * as z from "zod/v4";
9
9
  import type { Settings } from "../config/settings";
10
10
  import githubDescription from "../prompts/tools/github.md" with { type: "text" };
11
11
  import * as git from "../utils/git";
@@ -197,135 +197,78 @@ const RUN_SUCCESS_CONCLUSIONS = new Set(["success", "neutral", "skipped"]);
197
197
  const RUN_FAILURE_CONCLUSIONS = new Set(["failure", "timed_out", "cancelled", "action_required", "startup_failure"]);
198
198
  const JOB_FAILURE_CONCLUSIONS = new Set(["failure", "timed_out", "cancelled", "action_required"]);
199
199
 
200
- const githubSchema = Type.Object({
201
- op: StringEnum(
202
- [
203
- "repo_view",
204
- "pr_create",
205
- "pr_checkout",
206
- "pr_push",
207
- "search_issues",
208
- "search_prs",
209
- "search_code",
210
- "search_commits",
211
- "search_repos",
212
- "run_watch",
213
- ],
214
- { description: "github operation" },
215
- ),
216
- repo: Type.Optional(
217
- Type.String({
218
- description: "owner/repo (any op)",
219
- examples: ["facebook/react"],
220
- }),
221
- ),
222
- branch: Type.Optional(
223
- Type.String({
224
- description: "branch (repo_view, pr_push local branch, run_watch)",
225
- examples: ["main", "develop"],
226
- }),
227
- ),
228
- pr: Type.Optional(
229
- Type.Union(
230
- [
231
- Type.String({ examples: ["123", "feature-branch"] }),
232
- Type.Array(Type.String(), {
233
- examples: [["123", "456"]],
234
- }),
235
- ],
236
- {
237
- description:
238
- "pr number, url, or branch (pr_checkout); pass an array to batch-process multiple pull requests in one call",
239
- },
240
- ),
241
- ),
242
- force: Type.Optional(Type.Boolean({ description: "reset existing local branch (pr_checkout)" })),
243
- forceWithLease: Type.Optional(Type.Boolean({ description: "force-with-lease push (pr_push)" })),
244
- title: Type.Optional(
245
- Type.String({
246
- description: "PR title (pr_create)",
247
- examples: ["Fix login bug"],
248
- }),
249
- ),
250
- body: Type.Optional(
251
- Type.String({
252
- description: "PR body markdown (pr_create); mutually exclusive with fill",
253
- }),
254
- ),
255
- base: Type.Optional(
256
- Type.String({
257
- description: "PR base branch (pr_create); defaults to repo default branch",
258
- examples: ["main"],
259
- }),
260
- ),
261
- head: Type.Optional(
262
- Type.String({
263
- description: "PR head branch (pr_create); defaults to current branch",
264
- examples: ["feature/foo"],
265
- }),
266
- ),
267
- draft: Type.Optional(Type.Boolean({ description: "open PR as draft (pr_create)" })),
268
- fill: Type.Optional(
269
- Type.Boolean({
270
- description: "auto-fill PR title/body from commits (pr_create); mutually exclusive with title/body",
271
- }),
272
- ),
273
- reviewer: Type.Optional(
274
- Type.Array(Type.String(), {
275
- description: "reviewers to request (pr_create); accepts users or org/team",
276
- examples: [["octocat", "myorg/team"]],
277
- }),
278
- ),
279
- assignee: Type.Optional(
280
- Type.Array(Type.String(), {
281
- description: "assignees (pr_create); use @me for the authenticated user",
282
- examples: [["@me"]],
283
- }),
284
- ),
285
- label: Type.Optional(
286
- Type.Array(Type.String(), {
287
- description: "labels to apply (pr_create)",
288
- examples: [["bug", "enhancement"]],
289
- }),
290
- ),
291
- query: Type.Optional(
292
- Type.String({
293
- description: "search query (search_issues, search_prs, search_code, search_commits, search_repos)",
294
- examples: ["is:open label:bug"],
295
- }),
296
- ),
297
- since: Type.Optional(
298
- Type.String({
299
- description:
200
+ const githubSchema = z
201
+ .object({
202
+ op: z
203
+ .enum([
204
+ "repo_view",
205
+ "pr_create",
206
+ "pr_checkout",
207
+ "pr_push",
208
+ "search_issues",
209
+ "search_prs",
210
+ "search_code",
211
+ "search_commits",
212
+ "search_repos",
213
+ "run_watch",
214
+ ] as const)
215
+ .describe("github operation"),
216
+ repo: z.string().describe("owner/repo (any op)").optional(),
217
+ branch: z.string().describe("branch (repo_view, pr_push local branch, run_watch)").optional(),
218
+ pr: z
219
+ .union([z.string(), z.array(z.string())])
220
+ .describe(
221
+ "pr number, url, or branch (pr_checkout); pass an array to batch-process multiple pull requests in one call",
222
+ )
223
+ .optional(),
224
+ force: z.boolean().describe("reset existing local branch (pr_checkout)").optional(),
225
+ forceWithLease: z.boolean().describe("force-with-lease push (pr_push)").optional(),
226
+ title: z.string().describe("PR title (pr_create)").optional(),
227
+ body: z.string().describe("PR body markdown (pr_create); mutually exclusive with fill").optional(),
228
+ base: z.string().describe("PR base branch (pr_create); defaults to repo default branch").optional(),
229
+ head: z.string().describe("PR head branch (pr_create); defaults to current branch").optional(),
230
+ draft: z.boolean().describe("open PR as draft (pr_create)").optional(),
231
+ fill: z
232
+ .boolean()
233
+ .describe("auto-fill PR title/body from commits (pr_create); mutually exclusive with title/body")
234
+ .optional(),
235
+ reviewer: z.array(z.string()).describe("reviewers to request (pr_create); accepts users or org/team").optional(),
236
+ assignee: z.array(z.string()).describe("assignees (pr_create); use @me for the authenticated user").optional(),
237
+ label: z.array(z.string()).describe("labels to apply (pr_create)").optional(),
238
+ query: z
239
+ .string()
240
+ .describe("search query (search_issues, search_prs, search_code, search_commits, search_repos)")
241
+ .optional(),
242
+ since: z
243
+ .string()
244
+ .describe(
300
245
  "lower-bound date for search_issues/search_prs/search_commits/search_repos. Accepts a relative duration (`<n><unit>` with unit `m`/`h`/`d`/`w`/`mo`/`y`, e.g. `3d`, `12h`, `2w`) or an ISO date (`YYYY-MM-DD`) / datetime. Translated to a `created:>=…` (or `committer-date:`/`pushed:`) qualifier; not supported by search_code.",
301
- examples: ["3d", "2w", "2026-05-01"],
302
- }),
303
- ),
304
- until: Type.Optional(
305
- Type.String({
306
- description:
246
+ )
247
+ .optional(),
248
+ until: z
249
+ .string()
250
+ .describe(
307
251
  "upper-bound date in the same format as `since`. With both, builds a `field:since..until` range qualifier.",
308
- examples: ["1d", "2026-05-09"],
309
- }),
310
- ),
311
- dateField: Type.Optional(
312
- StringEnum(["created", "updated"], {
313
- description:
252
+ )
253
+ .optional(),
254
+ dateField: z
255
+ .enum(["created", "updated"] as const)
256
+ .describe(
314
257
  "date field used by `since`/`until`. issues/prs: `created` (default) or `updated`. repos: `created` (default) or `updated` (mapped to GitHub's `pushed:`). commits: ignored — always uses `committer-date`.",
315
- default: "created",
316
- }),
317
- ),
318
- limit: Type.Optional(
319
- Type.Number({
320
- description: "max results (search_issues, search_prs, search_code, search_commits, search_repos)",
321
- default: 10,
322
- }),
323
- ),
324
- run: Type.Optional(Type.String({ description: "actions run id or url (run_watch)", examples: ["123456"] })),
325
- tail: Type.Optional(Type.Number({ description: "log lines per failed job (run_watch)", default: 15 })),
326
- });
327
-
328
- type GithubInput = Static<typeof githubSchema>;
258
+ )
259
+ .default("created")
260
+ .optional(),
261
+ limit: z
262
+ .number()
263
+ .default(10)
264
+ .describe("max results (search_issues, search_prs, search_code, search_commits, search_repos)")
265
+ .optional(),
266
+ run: z.string().describe("actions run id or url (run_watch)").optional(),
267
+ tail: z.number().default(15).describe("log lines per failed job (run_watch)").optional(),
268
+ })
269
+ .strict();
270
+
271
+ type GithubInput = z.infer<typeof githubSchema>;
329
272
 
330
273
  export interface GhToolDetails {
331
274
  meta?: OutputMeta;
@@ -1,17 +1,15 @@
1
1
  import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
2
2
  import { logger, untilAborted } from "@oh-my-pi/pi-utils";
3
- import { type Static, Type } from "@sinclair/typebox";
3
+ import * as z from "zod/v4";
4
4
  import { formatCurrentTime, formatMemories } from "../hindsight/content";
5
5
  import recallDescription from "../prompts/tools/recall.md" with { type: "text" };
6
6
  import type { ToolSession } from ".";
7
7
 
8
- const hindsightRecallSchema = Type.Object({
9
- query: Type.String({
10
- description: "Natural language search query. Be specific about what you need to know.",
11
- }),
8
+ const hindsightRecallSchema = z.object({
9
+ query: z.string().describe("Natural language search query. Be specific about what you need to know."),
12
10
  });
13
11
 
14
- export type HindsightRecallParams = Static<typeof hindsightRecallSchema>;
12
+ export type HindsightRecallParams = z.infer<typeof hindsightRecallSchema>;
15
13
 
16
14
  export class HindsightRecallTool implements AgentTool<typeof hindsightRecallSchema> {
17
15
  readonly name = "recall";
@@ -1,16 +1,16 @@
1
1
  import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
2
2
  import { logger, untilAborted } from "@oh-my-pi/pi-utils";
3
- import { type Static, Type } from "@sinclair/typebox";
3
+ import * as z from "zod/v4";
4
4
  import { ensureBankMission } from "../hindsight/bank";
5
5
  import reflectDescription from "../prompts/tools/reflect.md" with { type: "text" };
6
6
  import type { ToolSession } from ".";
7
7
 
8
- const hindsightReflectSchema = Type.Object({
9
- query: Type.String({ description: "The question to answer using long-term memory." }),
10
- context: Type.Optional(Type.String({ description: "Optional additional context to guide the reflection." })),
8
+ const hindsightReflectSchema = z.object({
9
+ query: z.string().describe("The question to answer using long-term memory."),
10
+ context: z.string().describe("Optional additional context to guide the reflection.").optional(),
11
11
  });
12
12
 
13
- export type HindsightReflectParams = Static<typeof hindsightReflectSchema>;
13
+ export type HindsightReflectParams = z.infer<typeof hindsightReflectSchema>;
14
14
 
15
15
  export class HindsightReflectTool implements AgentTool<typeof hindsightReflectSchema> {
16
16
  readonly name = "reflect";
@@ -1,27 +1,25 @@
1
1
  import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
2
- import { type Static, Type } from "@sinclair/typebox";
2
+ import * as z from "zod/v4";
3
3
  import retainDescription from "../prompts/tools/retain.md" with { type: "text" };
4
4
  import type { ToolSession } from ".";
5
5
 
6
- const hindsightRetainSchema = Type.Object({
7
- items: Type.Array(
8
- Type.Object({
9
- content: Type.String({
10
- description: "The information to remember. Be specific and self-contained — include who, what, when, why.",
6
+ const hindsightRetainSchema = z.object({
7
+ items: z
8
+ .array(
9
+ z.object({
10
+ content: z
11
+ .string()
12
+ .describe("The information to remember. Be specific and self-contained — include who, what, when, why."),
13
+ context: z.string().describe("Optional context describing where this information came from.").optional(),
11
14
  }),
12
- context: Type.Optional(
13
- Type.String({ description: "Optional context describing where this information came from." }),
14
- ),
15
- }),
16
- {
17
- minItems: 1,
18
- description:
19
- "One or more memories to retain. Batch related facts in a single call rather than calling retain repeatedly — they are deduplicated and consolidated together.",
20
- },
21
- ),
15
+ )
16
+ .min(1)
17
+ .describe(
18
+ "One or more memories to retain. Batch related facts in a single call rather than calling retain repeatedly — they are deduplicated and consolidated together.",
19
+ ),
22
20
  });
23
21
 
24
- export type HindsightRetainParams = Static<typeof hindsightRetainSchema>;
22
+ export type HindsightRetainParams = z.infer<typeof hindsightRetainSchema>;
25
23
  export class HindsightRetainTool implements AgentTool<typeof hindsightRetainSchema> {
26
24
  readonly name = "retain";
27
25
  readonly label = "Retain";
@@ -1,6 +1,6 @@
1
1
  import * as os from "node:os";
2
2
  import * as path from "node:path";
3
- import { getAntigravityUserAgent, getEnvApiKey, type Model, StringEnum } from "@oh-my-pi/pi-ai";
3
+ import { getAntigravityUserAgent, getEnvApiKey, type Model } from "@oh-my-pi/pi-ai";
4
4
  import {
5
5
  CODEX_BASE_URL,
6
6
  getCodexAccountId,
@@ -18,7 +18,7 @@ import {
18
18
  Snowflake,
19
19
  untilAborted,
20
20
  } from "@oh-my-pi/pi-utils";
21
- import { type Static, Type } from "@sinclair/typebox";
21
+ import * as z from "zod/v4";
22
22
  import packageJson from "../../package.json" with { type: "json" };
23
23
  import { isAuthenticated, type ModelRegistry } from "../config/model-registry";
24
24
  import type { CustomTool } from "../extensibility/custom-tools/types";
@@ -46,87 +46,37 @@ interface ImageApiKey {
46
46
  model?: Model;
47
47
  }
48
48
 
49
- const responseModalitySchema = StringEnum(["IMAGE", "TEXT"]);
50
- const aspectRatioSchema = StringEnum(["1:1", "3:4", "4:3", "9:16", "16:9"], {
51
- description: "aspect ratio",
52
- examples: ["1:1", "3:4", "16:9"],
53
- });
54
- const imageSizeSchema = StringEnum(["1024x1024", "1536x1024", "1024x1536"], {
55
- description: "image size",
56
- examples: ["1024x1024", "1536x1024"],
57
- });
58
-
59
- const inputImageSchema = Type.Object(
60
- {
61
- path: Type.Optional(Type.String({ description: "input image path" })),
62
- data: Type.Optional(Type.String({ description: "base64 image data" })),
63
- mime_type: Type.Optional(Type.String({ description: "mime type" })),
64
- },
65
- { additionalProperties: false },
66
- );
67
-
68
- const baseImageSchema = Type.Object(
69
- {
70
- subject: Type.String({
71
- description: "main subject",
72
- examples: ["a stoic robot barista", "a weathered lighthouse"],
73
- }),
74
- action: Type.Optional(
75
- Type.String({
76
- description: "what subject is doing",
77
- examples: ["pouring latte art", "standing against waves"],
78
- }),
79
- ),
80
- scene: Type.Optional(
81
- Type.String({
82
- description: "location or environment",
83
- examples: ["futuristic café on mars", "thunderstorm at dusk"],
84
- }),
85
- ),
86
- composition: Type.Optional(
87
- Type.String({
88
- description: "camera angle and framing",
89
- examples: ["low-angle close-up", "wide establishing shot"],
90
- }),
91
- ),
92
- lighting: Type.Optional(
93
- Type.String({
94
- description: "lighting setup",
95
- examples: ["warm rim lighting", "golden hour backlight"],
96
- }),
97
- ),
98
- style: Type.Optional(
99
- Type.String({
100
- description: "artistic style",
101
- examples: ["film noir", "studio ghibli watercolor", "photorealistic"],
102
- }),
103
- ),
104
- text: Type.Optional(
105
- Type.String({
106
- description: "text to render",
107
- examples: ["headline 'urban explorer' top center"],
108
- }),
109
- ),
110
- changes: Type.Optional(
111
- Type.Array(Type.String(), {
112
- description: "edits to make",
113
- examples: [["change tie to green", "remove car"]],
114
- }),
115
- ),
116
- aspect_ratio: Type.Optional(aspectRatioSchema),
117
- image_size: Type.Optional(imageSizeSchema),
118
- input: Type.Optional(
119
- Type.Array(inputImageSchema, {
120
- description: "input images",
121
- }),
122
- ),
123
- },
124
- { additionalProperties: false },
125
- );
49
+ const responseModalitySchema = z.enum(["IMAGE", "TEXT"] as const);
50
+ const aspectRatioSchema = z.enum(["1:1", "3:4", "4:3", "9:16", "16:9"] as const).describe("aspect ratio");
51
+ const imageSizeSchema = z.enum(["1024x1024", "1536x1024", "1024x1536"] as const).describe("image size");
52
+
53
+ const inputImageSchema = z
54
+ .object({
55
+ path: z.string().describe("input image path").optional(),
56
+ data: z.string().describe("base64 image data").optional(),
57
+ mime_type: z.string().describe("mime type").optional(),
58
+ })
59
+ .strict();
60
+
61
+ const baseImageSchema = z
62
+ .object({
63
+ subject: z.string().describe("main subject"),
64
+ action: z.string().describe("what subject is doing").optional(),
65
+ scene: z.string().describe("location or environment").optional(),
66
+ composition: z.string().describe("camera angle and framing").optional(),
67
+ lighting: z.string().describe("lighting setup").optional(),
68
+ style: z.string().describe("artistic style").optional(),
69
+ text: z.string().describe("text to render").optional(),
70
+ changes: z.array(z.string()).describe("edits to make").optional(),
71
+ aspect_ratio: aspectRatioSchema.optional(),
72
+ image_size: imageSizeSchema.optional(),
73
+ input: z.array(inputImageSchema).describe("input images").optional(),
74
+ })
75
+ .strict();
126
76
 
127
77
  export const imageGenSchema = baseImageSchema;
128
- export type ImageGenParams = Static<typeof imageGenSchema>;
129
- export type GeminiResponseModality = Static<typeof responseModalitySchema>;
78
+ export type ImageGenParams = z.infer<typeof imageGenSchema>;
79
+ export type GeminiResponseModality = z.infer<typeof responseModalitySchema>;
130
80
 
131
81
  /**
132
82
  * Assembles a structured prompt from the provided parameters.
@@ -1,4 +1,4 @@
1
- import type { AgentTool } from "@oh-my-pi/pi-agent-core";
1
+ import type { AgentTelemetryConfig, AgentTool } from "@oh-my-pi/pi-agent-core";
2
2
  import type { ToolChoice } from "@oh-my-pi/pi-ai";
3
3
  import { $env, $flag, logger } from "@oh-my-pi/pi-utils";
4
4
  import type { PromptTemplate } from "../config/prompt-templates";
@@ -250,6 +250,9 @@ export interface ToolSession {
250
250
 
251
251
  /** Queue a hidden message to be injected at the next agent turn. */
252
252
  queueDeferredMessage?(message: CustomMessage): void;
253
+ /** Get the active OpenTelemetry config so subagent dispatch can forward
254
+ * the parent's tracer/hooks with the subagent's own identity stamped. */
255
+ getTelemetry?: () => AgentTelemetryConfig | undefined;
253
256
  }
254
257
 
255
258
  export type ToolFactory = (session: ToolSession) => Tool | null | Promise<Tool | null>;
@@ -1,7 +1,7 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
2
  import { type Api, completeSimple, type Model } from "@oh-my-pi/pi-ai";
3
3
  import { prompt } from "@oh-my-pi/pi-utils";
4
- import { type Static, Type } from "@sinclair/typebox";
4
+ import * as z from "zod/v4";
5
5
  import { extractTextContent } from "../commit/utils";
6
6
  import { expandRoleAlias, resolveModelFromString } from "../config/model-resolver";
7
7
  import inspectImageDescription from "../prompts/tools/inspect-image.md" with { type: "text" };
@@ -15,15 +15,14 @@ import {
15
15
  import type { ToolSession } from "./index";
16
16
  import { ToolError } from "./tool-errors";
17
17
 
18
- const inspectImageSchema = Type.Object(
19
- {
20
- path: Type.String({ description: "image path", examples: ["image.png"] }),
21
- question: Type.String({ description: "question about image", examples: ["What is in this image?"] }),
22
- },
23
- { additionalProperties: false },
24
- );
18
+ const inspectImageSchema = z
19
+ .object({
20
+ path: z.string().describe("image path"),
21
+ question: z.string().describe("question about image"),
22
+ })
23
+ .strict();
25
24
 
26
- export type InspectImageParams = Static<typeof inspectImageSchema>;
25
+ export type InspectImageParams = z.infer<typeof inspectImageSchema>;
27
26
 
28
27
  export interface InspectImageToolDetails {
29
28
  model: string;
package/src/tools/irc.ts CHANGED
@@ -20,39 +20,27 @@
20
20
 
21
21
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
22
22
  import { prompt } from "@oh-my-pi/pi-utils";
23
- import { type Static, Type } from "@sinclair/typebox";
23
+ import * as z from "zod/v4";
24
24
  import ircDescription from "../prompts/tools/irc.md" with { type: "text" };
25
25
  import type { AgentRef, AgentRegistry } from "../registry/agent-registry";
26
26
  import type { ToolSession } from ".";
27
27
 
28
- const ircSchema = Type.Object({
29
- op: Type.Union(
30
- [
31
- Type.Literal("send", { description: "Send a message to one peer or to all peers" }),
32
- Type.Literal("list", { description: "List currently visible peers" }),
33
- ],
34
- { description: "IRC operation" },
35
- ),
36
- to: Type.Optional(
37
- Type.String({
38
- description: 'Recipient agent id (e.g. "0-Main", "0-AuthLoader") or "all" to broadcast',
39
- examples: ["0-Main", "all"],
40
- }),
41
- ),
42
- message: Type.Optional(
43
- Type.String({
44
- description: "Message body to deliver",
45
- examples: ["Should we use JWT or session cookies?"],
46
- }),
47
- ),
48
- awaitReply: Type.Optional(
49
- Type.Boolean({
50
- description: "Wait for the recipient's prose reply (default: true for DM, false for broadcast)",
51
- }),
52
- ),
28
+ const ircSchema = z.object({
29
+ op: z
30
+ .union([
31
+ z.literal("send").describe("Send a message to one peer or to all peers"),
32
+ z.literal("list").describe("List currently visible peers"),
33
+ ])
34
+ .describe("IRC operation"),
35
+ to: z.string().optional().describe('Recipient agent id (e.g. "0-Main", "0-AuthLoader") or "all" to broadcast'),
36
+ message: z.string().optional().describe("Message body to deliver"),
37
+ awaitReply: z
38
+ .boolean()
39
+ .optional()
40
+ .describe("Wait for the recipient's prose reply (default: true for DM, false for broadcast)"),
53
41
  });
54
42
 
55
- type IrcParams = Static<typeof ircSchema>;
43
+ type IrcParams = z.infer<typeof ircSchema>;
56
44
 
57
45
  interface IrcReply {
58
46
  from: string;