@oh-my-pi/pi-coding-agent 15.13.1 → 15.13.2

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 (71) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/cli.js +957 -214
  3. package/dist/types/config/model-registry.d.ts +1 -0
  4. package/dist/types/config/models-config-schema.d.ts +3 -0
  5. package/dist/types/config/models-config.d.ts +3 -0
  6. package/dist/types/config/settings-schema.d.ts +66 -0
  7. package/dist/types/edit/hashline/block-resolver.d.ts +1 -1
  8. package/dist/types/edit/index.d.ts +2 -0
  9. package/dist/types/modes/components/welcome.d.ts +1 -0
  10. package/dist/types/modes/controllers/input-controller.d.ts +4 -4
  11. package/dist/types/modes/rpc/rpc-types.d.ts +2 -1
  12. package/dist/types/sdk.d.ts +3 -0
  13. package/dist/types/session/session-dump-format.d.ts +2 -1
  14. package/dist/types/system-prompt.d.ts +11 -0
  15. package/dist/types/tools/ask.d.ts +2 -0
  16. package/dist/types/tools/ast-edit.d.ts +2 -0
  17. package/dist/types/tools/ast-grep.d.ts +2 -0
  18. package/dist/types/tools/browser.d.ts +2 -0
  19. package/dist/types/tools/debug.d.ts +2 -0
  20. package/dist/types/tools/eval.d.ts +2 -0
  21. package/dist/types/tools/find.d.ts +2 -0
  22. package/dist/types/tools/inspect-image.d.ts +2 -1
  23. package/dist/types/tools/irc.d.ts +2 -0
  24. package/dist/types/tools/ssh.d.ts +2 -0
  25. package/dist/types/tools/todo.d.ts +2 -0
  26. package/dist/types/tui/tree-list.d.ts +1 -0
  27. package/package.json +12 -12
  28. package/src/config/model-registry.ts +10 -0
  29. package/src/config/models-config-schema.ts +2 -0
  30. package/src/config/models-config.ts +1 -0
  31. package/src/config/settings-schema.ts +53 -0
  32. package/src/edit/hashline/block-resolver.ts +1 -1
  33. package/src/edit/hashline/execute.ts +1 -6
  34. package/src/edit/index.ts +48 -0
  35. package/src/eval/__tests__/js-context-manager.test.ts +41 -1
  36. package/src/eval/js/context-manager.ts +92 -26
  37. package/src/eval/js/worker-core.ts +1 -1
  38. package/src/internal-urls/docs-index.generated.ts +9 -2
  39. package/src/modes/components/welcome.ts +14 -4
  40. package/src/modes/controllers/input-controller.ts +21 -38
  41. package/src/modes/rpc/rpc-mode.ts +1 -0
  42. package/src/modes/rpc/rpc-types.ts +2 -2
  43. package/src/prompts/system/system-prompt.md +17 -21
  44. package/src/prompts/tools/ask.md +0 -8
  45. package/src/prompts/tools/ast-edit.md +0 -15
  46. package/src/prompts/tools/ast-grep.md +0 -13
  47. package/src/prompts/tools/browser.md +0 -21
  48. package/src/prompts/tools/debug.md +0 -13
  49. package/src/prompts/tools/eval.md +0 -9
  50. package/src/prompts/tools/find.md +0 -13
  51. package/src/prompts/tools/inspect-image.md +0 -9
  52. package/src/prompts/tools/irc.md +0 -15
  53. package/src/prompts/tools/patch.md +0 -13
  54. package/src/prompts/tools/ssh.md +0 -9
  55. package/src/prompts/tools/todo.md +1 -19
  56. package/src/sdk.ts +19 -0
  57. package/src/session/agent-session.ts +125 -19
  58. package/src/session/session-dump-format.ts +10 -31
  59. package/src/system-prompt.ts +31 -0
  60. package/src/tools/ask.ts +41 -0
  61. package/src/tools/ast-edit.ts +46 -0
  62. package/src/tools/ast-grep.ts +24 -0
  63. package/src/tools/browser.ts +52 -0
  64. package/src/tools/debug.ts +17 -0
  65. package/src/tools/eval.ts +20 -1
  66. package/src/tools/find.ts +24 -0
  67. package/src/tools/inspect-image.ts +27 -1
  68. package/src/tools/irc.ts +41 -0
  69. package/src/tools/ssh.ts +16 -0
  70. package/src/tools/todo.ts +82 -3
  71. package/src/tui/tree-list.ts +68 -19
@@ -248,6 +248,7 @@ export interface ProviderConfigInput {
248
248
  reasoning: boolean;
249
249
  thinking?: ThinkingConfig;
250
250
  input: ("text" | "image")[];
251
+ supportsTools?: boolean;
251
252
  cost: {
252
253
  input: number;
253
254
  output: number;
@@ -215,6 +215,7 @@ export declare const ModelOverrideSchema: z.ZodObject<{
215
215
  image: "image";
216
216
  text: "text";
217
217
  }>>>;
218
+ supportsTools: z.ZodOptional<z.ZodBoolean>;
218
219
  cost: z.ZodOptional<z.ZodObject<{
219
220
  input: z.ZodOptional<z.ZodNumber>;
220
221
  output: z.ZodOptional<z.ZodNumber>;
@@ -633,6 +634,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
633
634
  image: "image";
634
635
  text: "text";
635
636
  }>>>;
637
+ supportsTools: z.ZodOptional<z.ZodBoolean>;
636
638
  cost: z.ZodOptional<z.ZodObject<{
637
639
  input: z.ZodNumber;
638
640
  output: z.ZodNumber;
@@ -862,6 +864,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
862
864
  image: "image";
863
865
  text: "text";
864
866
  }>>>;
867
+ supportsTools: z.ZodOptional<z.ZodBoolean>;
865
868
  cost: z.ZodOptional<z.ZodObject<{
866
869
  input: z.ZodOptional<z.ZodNumber>;
867
870
  output: z.ZodOptional<z.ZodNumber>;
@@ -9,6 +9,7 @@ export interface ProviderValidationModel {
9
9
  id: string;
10
10
  api?: Api;
11
11
  contextWindow?: number;
12
+ supportsTools?: boolean;
12
13
  maxTokens?: number;
13
14
  }
14
15
  export interface ProviderValidationConfig {
@@ -150,6 +151,7 @@ export declare const ModelsConfigFile: ConfigFile<{
150
151
  supportsDisplay?: boolean | undefined;
151
152
  } | undefined;
152
153
  input?: ("image" | "text")[] | undefined;
154
+ supportsTools?: boolean | undefined;
153
155
  cost?: {
154
156
  input: number;
155
157
  output: number;
@@ -274,6 +276,7 @@ export declare const ModelsConfigFile: ConfigFile<{
274
276
  supportsDisplay?: boolean | undefined;
275
277
  } | undefined;
276
278
  input?: ("image" | "text")[] | undefined;
279
+ supportsTools?: boolean | undefined;
277
280
  cost?: {
278
281
  input?: number | undefined;
279
282
  output?: number | undefined;
@@ -1841,6 +1841,62 @@ export declare const SETTINGS_SCHEMA: {
1841
1841
  readonly description: "Experimental: render large historical tool results as dense PNG image(s) instead of text (vision models only). Saves tokens on accumulated read/search output.";
1842
1842
  };
1843
1843
  };
1844
+ readonly "tools.format": {
1845
+ readonly type: "enum";
1846
+ readonly values: readonly ["auto", "native", "glm", "hermes", "kimi", "xml", "anthropic", "deepseek", "harmony", "pi", "qwen3"];
1847
+ readonly default: "auto";
1848
+ readonly ui: {
1849
+ readonly tab: "context";
1850
+ readonly group: "Experimental";
1851
+ readonly label: "Tool Call Format";
1852
+ readonly description: "Controls how tools are exposed to the model. Auto uses native tool calls unless the selected model is marked as not supporting tools, then falls back to GLM-style in-band tool calls. Native forces provider-native tools; the other values force the named in-band syntax. Applies on session start.";
1853
+ readonly options: readonly [{
1854
+ readonly value: "auto";
1855
+ readonly label: "Auto";
1856
+ readonly description: "Use native tool calls unless the model is known not to support them.";
1857
+ }, {
1858
+ readonly value: "native";
1859
+ readonly label: "Native";
1860
+ readonly description: "Use provider-native tool calls.";
1861
+ }, {
1862
+ readonly value: "glm";
1863
+ readonly label: "GLM";
1864
+ readonly description: "Use GLM-style in-band tool calls.";
1865
+ }, {
1866
+ readonly value: "hermes";
1867
+ readonly label: "Hermes";
1868
+ readonly description: "Use Hermes-style in-band tool calls.";
1869
+ }, {
1870
+ readonly value: "kimi";
1871
+ readonly label: "Kimi";
1872
+ readonly description: "Use Kimi-style in-band tool calls.";
1873
+ }, {
1874
+ readonly value: "xml";
1875
+ readonly label: "XML";
1876
+ readonly description: "Use generic XML in-band tool calls.";
1877
+ }, {
1878
+ readonly value: "anthropic";
1879
+ readonly label: "Anthropic";
1880
+ readonly description: "Use Anthropic-style in-band tool calls.";
1881
+ }, {
1882
+ readonly value: "deepseek";
1883
+ readonly label: "DeepSeek";
1884
+ readonly description: "Use DeepSeek-style in-band tool calls.";
1885
+ }, {
1886
+ readonly value: "harmony";
1887
+ readonly label: "Harmony";
1888
+ readonly description: "Use Harmony-style in-band tool calls.";
1889
+ }, {
1890
+ readonly value: "pi";
1891
+ readonly label: "Pi";
1892
+ readonly description: "Use Pi-style in-band tool calls.";
1893
+ }, {
1894
+ readonly value: "qwen3";
1895
+ readonly label: "Qwen3";
1896
+ readonly description: "Use Qwen3-style in-band tool calls.";
1897
+ }];
1898
+ };
1899
+ };
1844
1900
  readonly "snapcompact.shape": {
1845
1901
  readonly type: "enum";
1846
1902
  readonly values: readonly ["auto", ...("11on16-bw" | "5x8-bw" | "5x8-sent" | "6x12-dim" | "6x6u-bw" | "6x6u-sent" | "8on16-bw" | "8on22-bw" | "8x13-bw" | "8x8r-bw" | "8x8r-sent" | "8x8u-bw" | "8x8u-sent" | "doc-8on16-bw" | "doc-8on16-sent" | "doc-8on16-sent-dim")[]];
@@ -3315,6 +3371,16 @@ export declare const SETTINGS_SCHEMA: {
3315
3371
  readonly description: "Ask the agent to describe the intent of each tool call before executing it";
3316
3372
  };
3317
3373
  };
3374
+ readonly "tools.abortOnFabricatedResult": {
3375
+ readonly type: "boolean";
3376
+ readonly default: true;
3377
+ readonly ui: {
3378
+ readonly tab: "tools";
3379
+ readonly group: "Execution";
3380
+ readonly label: "Abort On Fabricated Tool Result";
3381
+ readonly description: "With in-band tool calls, stop the model immediately when it starts hallucinating a tool result mid-turn. Disable to let the model finish generating and discard the fabricated continuation instead.";
3382
+ };
3383
+ };
3318
3384
  readonly "tools.maxTimeout": {
3319
3385
  readonly type: "number";
3320
3386
  readonly default: 0;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tree-sitter-backed {@link BlockResolver} for the hashline `replace block N:`
2
+ * Tree-sitter-backed {@link BlockResolver} for the hashline block replace
3
3
  * operator. Bridges the pure hashline seam to the native `blockRangeAt`
4
4
  * primitive in `@oh-my-pi/pi-natives`, which infers the language from the file
5
5
  * path and returns the 1-indexed line span of the syntactic block beginning on
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import type { ToolSession } from "../tools";
3
4
  import { type EditMode } from "../utils/edit-mode";
4
5
  import { type HashlineParams, hashlineEditParamsSchema } from "./hashline";
@@ -34,6 +35,7 @@ export declare class EditTool implements AgentTool<TInput> {
34
35
  get mode(): EditMode;
35
36
  get description(): string;
36
37
  get parameters(): TInput;
38
+ get examples(): readonly ToolExample[] | undefined;
37
39
  /**
38
40
  * When in `apply_patch` mode, expose the Codex Lark grammar so providers
39
41
  * that support OpenAI-style custom tools can emit a grammar-constrained
@@ -30,6 +30,7 @@ export declare class WelcomeComponent implements Component {
30
30
  private recentSessions;
31
31
  private lspServers;
32
32
  constructor(version: string, modelName: string, providerName: string, recentSessions?: RecentSession[], lspServers?: LspServerInfo[]);
33
+ get tip(): string | undefined;
33
34
  invalidate(): void;
34
35
  /**
35
36
  * Play a one-shot intro that sweeps the gradient through every phase
@@ -35,10 +35,10 @@ export declare class InputController {
35
35
  */
36
36
  handleLargePaste(text: string, lineCount: number): boolean;
37
37
  /**
38
- * Present the large-paste menu and apply the chosen action: wrap in a code block or in XML tags
39
- * (both collapse to a `[Paste]` marker that expands on submit), or save the text to a file and
40
- * reference its path so the agent can `read` it on demand. Cancelling (Esc) falls back to the
41
- * default inline paste marker, so the pasted content is never lost.
38
+ * Present the large-paste menu and apply the chosen action: wrap in `<attachment>` tags (collapsed
39
+ * to a `[Paste]` marker that expands on submit), save the text to a file and reference its path so
40
+ * the agent can `read` it on demand, or paste inline. Cancelling (Esc) falls back to the default
41
+ * inline paste marker, so the pasted content is never lost.
42
42
  */
43
43
  presentLargePasteMenu(text: string, lineCount: number): Promise<void>;
44
44
  createAutocompleteProvider(commands: SlashCommand[], basePath: string): AutocompleteProvider;
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import type { AgentMessage, AgentToolResult, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
8
8
  import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
9
- import type { Effort, ImageContent, Model } from "@oh-my-pi/pi-ai";
9
+ import type { Effort, ImageContent, Model, ToolExample } from "@oh-my-pi/pi-ai";
10
10
  import type { BashResult } from "../../exec/bash-executor";
11
11
  import type { ContextUsage } from "../../extensibility/extensions/types";
12
12
  import type { AgentSessionEvent, SessionStats } from "../../session/agent-session";
@@ -186,6 +186,7 @@ export interface RpcSessionState {
186
186
  name: string;
187
187
  description: string;
188
188
  parameters: unknown;
189
+ examples?: readonly ToolExample[];
189
190
  }>;
190
191
  /** Current context window usage. Null tokens/percent when unknown (e.g. right after compaction). */
191
192
  contextUsage?: ContextUsage;
@@ -1,5 +1,6 @@
1
1
  import { type AgentTelemetryConfig, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import { type Model } from "@oh-my-pi/pi-ai";
3
+ import type { ToolCallSyntax } from "@oh-my-pi/pi-ai/grammar";
3
4
  import { type Rule } from "./capability/rule";
4
5
  import { ModelRegistry } from "./config/model-registry";
5
6
  import { type PromptTemplate } from "./config/prompt-templates";
@@ -183,6 +184,8 @@ export interface CreateAgentSessionResult {
183
184
  /** Shared event bus for tool/extension communication */
184
185
  eventBus: EventBus;
185
186
  }
187
+ export type ToolCallFormat = "auto" | "native" | ToolCallSyntax;
188
+ export declare function resolveToolCallSyntax(format: ToolCallFormat, model: Pick<Model, "supportsTools"> | undefined): ToolCallSyntax | undefined;
186
189
  export type { PromptTemplate } from "./config/prompt-templates";
187
190
  export { Settings, type SkillsSettings } from "./config/settings";
188
191
  export type { CustomCommand, CustomCommandFactory } from "./extensibility/custom-commands/types";
@@ -2,12 +2,13 @@
2
2
  * Plain-text / markdown session formatting (same shape as /dump clipboard export).
3
3
  */
4
4
  import type { AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
5
- import type { Model } from "@oh-my-pi/pi-ai";
5
+ import type { Model, ToolExample } from "@oh-my-pi/pi-ai";
6
6
  /** Minimal tool shape for dump output (matches AgentTool fields used by formatSessionDumpText). */
7
7
  export interface SessionDumpToolInfo {
8
8
  name: string;
9
9
  description: string;
10
10
  parameters: unknown;
11
+ examples?: readonly ToolExample[];
11
12
  }
12
13
  export interface FormatSessionDumpTextOptions {
13
14
  messages: readonly AgentMessage[];
@@ -2,6 +2,7 @@
2
2
  * System prompt construction and project context loading
3
3
  */
4
4
  import type { AgentTool } from "@oh-my-pi/pi-agent-core";
5
+ import type { ToolExample, TSchema } from "@oh-my-pi/pi-ai";
5
6
  import type { Personality, SkillsSettings } from "./config/settings";
6
7
  import { type Skill } from "./extensibility/skills";
7
8
  import { type WorkspaceTree } from "./workspace-tree";
@@ -38,6 +39,10 @@ export interface SystemPromptToolMetadata {
38
39
  description: string;
39
40
  /** Tool name the model sees on the provider wire. Defaults to the internal tool name. */
40
41
  wireName?: string;
42
+ /** Tool parameters schema (Zod or JSON Schema), fed to the verbose inventory renderer. */
43
+ parameters?: TSchema;
44
+ /** Illustrative examples rendered into the verbose inventory. */
45
+ examples?: readonly ToolExample[];
41
46
  }
42
47
  export declare function buildSystemPromptToolMetadata(tools: Map<string, AgentTool>, overrides?: Partial<Record<string, Partial<SystemPromptToolMetadata>>>): Map<string, SystemPromptToolMetadata>;
43
48
  export interface BuildSystemPromptOptions {
@@ -51,6 +56,12 @@ export interface BuildSystemPromptOptions {
51
56
  appendSystemPrompt?: string;
52
57
  /** Repeat full tool descriptions in system prompt. Default: false */
53
58
  repeatToolDescriptions?: boolean;
59
+ /**
60
+ * Whether provider-native tool calling is active (no owned/in-band syntax).
61
+ * When true and `repeatToolDescriptions` is false, the inventory renders as a
62
+ * compact tool-name list; otherwise it renders full `# Tool:` sections. Default: true
63
+ */
64
+ nativeTools?: boolean;
54
65
  /** Skills settings for discovery. */
55
66
  skillsSettings?: SkillsSettings;
56
67
  /** Working directory. Default: getProjectDir() */
@@ -15,6 +15,7 @@
15
15
  * - Questions may time out and auto-select the recommended option (configurable, disabled in plan mode)
16
16
  */
17
17
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
18
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
18
19
  import { type Component } from "@oh-my-pi/pi-tui";
19
20
  import { z } from "zod/v4";
20
21
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
@@ -83,6 +84,7 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
83
84
  }, z.core.$strip>>;
84
85
  }, z.core.$strip>;
85
86
  readonly strict = true;
87
+ readonly examples: readonly ToolExample<z.input<typeof askSchema>>[];
86
88
  readonly concurrency = "exclusive";
87
89
  readonly loadMode = "discoverable";
88
90
  constructor(session: ToolSession);
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import type { Component } from "@oh-my-pi/pi-tui";
3
4
  import { z } from "zod/v4";
4
5
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
@@ -54,6 +55,7 @@ export declare class AstEditTool implements AgentTool<typeof astEditSchema, AstE
54
55
  paths: z.ZodArray<z.ZodString>;
55
56
  }, z.core.$strip>;
56
57
  readonly strict = true;
58
+ readonly examples: readonly ToolExample<z.input<typeof astEditSchema>>[];
57
59
  readonly deferrable = true;
58
60
  readonly loadMode = "discoverable";
59
61
  constructor(session: ToolSession);
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import type { Component } from "@oh-my-pi/pi-tui";
3
4
  import { z } from "zod/v4";
4
5
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
@@ -48,6 +49,7 @@ export declare class AstGrepTool implements AgentTool<typeof astGrepSchema, AstG
48
49
  skip: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
49
50
  }, z.core.$strip>;
50
51
  readonly strict = true;
52
+ readonly examples: readonly ToolExample<z.input<typeof astGrepSchema>>[];
51
53
  readonly loadMode = "discoverable";
52
54
  constructor(session: ToolSession);
53
55
  execute(_toolCallId: string, params: z.infer<typeof astGrepSchema>, signal?: AbortSignal, _onUpdate?: AgentToolUpdateCallback<AstGrepToolDetails>, _context?: AgentToolContext): Promise<AgentToolResult<AstGrepToolDetails>>;
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import { z } from "zod/v4";
3
4
  import type { ToolSession } from "../sdk";
4
5
  import { type BrowserKindTag } from "./browser/registry";
@@ -110,6 +111,7 @@ export declare class BrowserTool implements AgentTool<typeof browserSchema, Brow
110
111
  kill: z.ZodOptional<z.ZodBoolean>;
111
112
  }, z.core.$strip>;
112
113
  readonly strict = true;
114
+ readonly examples: readonly ToolExample<z.input<typeof browserSchema>>[];
113
115
  constructor(session: ToolSession);
114
116
  get description(): string;
115
117
  /** Restart browser to apply mode changes (e.g. headless toggle). Drops only headless browsers. */
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback, RenderResultOptions, ToolApprovalDecision } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import { type Component } from "@oh-my-pi/pi-tui";
3
4
  import { z } from "zod/v4";
4
5
  import { type DapBreakpointRecord, type DapContinueOutcome, type DapDataBreakpointInfoResponse, type DapDataBreakpointRecord, type DapDisassembledInstruction, type DapEvaluateResponse, type DapFunctionBreakpointRecord, type DapInstructionBreakpointRecord, type DapModule, type DapScope, type DapSessionSummary, type DapSource, type DapStackFrame, type DapThread, type DapVariable } from "../dap";
@@ -208,6 +209,7 @@ export declare class DebugTool implements AgentTool<typeof debugSchema, DebugToo
208
209
  timeout: z.ZodOptional<z.ZodNumber>;
209
210
  }, z.core.$strip>;
210
211
  readonly strict = true;
212
+ readonly examples: readonly ToolExample<z.input<typeof debugSchema>>[];
211
213
  readonly concurrency = "exclusive";
212
214
  readonly loadMode = "discoverable";
213
215
  constructor(session: ToolSession);
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import { z } from "zod/v4";
3
4
  import type { EvalToolDetails } from "../eval/types";
4
5
  import type { ToolSession } from ".";
@@ -65,6 +66,7 @@ export declare class EvalTool implements AgentTool<typeof evalSchema> {
65
66
  readonly loadMode = "discoverable";
66
67
  readonly label = "Eval";
67
68
  get description(): string;
69
+ readonly examples: readonly ToolExample<z.input<typeof evalSchema>>[];
68
70
  readonly parameters: z.ZodObject<{
69
71
  cells: z.ZodArray<z.ZodObject<{
70
72
  language: z.ZodEnum<{
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import type { Component } from "@oh-my-pi/pi-tui";
3
4
  import { z } from "zod/v4";
4
5
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
@@ -72,6 +73,7 @@ export declare class FindTool implements AgentTool<typeof findSchema, FindToolDe
72
73
  limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
73
74
  timeout: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
74
75
  }, z.core.$strict>;
76
+ readonly examples: readonly ToolExample<z.input<typeof findSchema>>[];
75
77
  readonly strict = true;
76
78
  constructor(session: ToolSession, options?: FindToolOptions);
77
79
  execute(_toolCallId: string, params: z.infer<typeof findSchema>, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<FindToolDetails>, _context?: AgentToolContext): Promise<AgentToolResult<FindToolDetails>>;
@@ -1,5 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
- import { completeSimple } from "@oh-my-pi/pi-ai";
2
+ import { completeSimple, type ToolExample } from "@oh-my-pi/pi-ai";
3
3
  import { z } from "zod/v4";
4
4
  import type { ToolSession } from "./index";
5
5
  declare const inspectImageSchema: z.ZodObject<{
@@ -26,6 +26,7 @@ export declare class InspectImageTool implements AgentTool<typeof inspectImageSc
26
26
  question: z.ZodString;
27
27
  }, z.core.$strict>;
28
28
  readonly strict = false;
29
+ readonly examples: readonly ToolExample<z.input<typeof inspectImageSchema>>[];
29
30
  constructor(session: ToolSession, completeImageRequest?: typeof completeSimple);
30
31
  execute(_toolCallId: string, params: InspectImageParams, signal?: AbortSignal, _onUpdate?: AgentToolUpdateCallback<InspectImageToolDetails>, _context?: AgentToolContext): Promise<AgentToolResult<InspectImageToolDetails>>;
31
32
  }
@@ -9,6 +9,7 @@
9
9
  * drains pending messages; `list` shows every addressable peer.
10
10
  */
11
11
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
12
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
12
13
  import { type Component } from "@oh-my-pi/pi-tui";
13
14
  import { z } from "zod/v4";
14
15
  import type { Settings } from "../config/settings";
@@ -83,6 +84,7 @@ export declare class IrcTool implements AgentTool<typeof ircSchema, IrcDetails>
83
84
  peek: z.ZodOptional<z.ZodBoolean>;
84
85
  }, z.core.$strip>;
85
86
  readonly strict = true;
87
+ readonly examples: readonly ToolExample<z.input<typeof ircSchema>>[];
86
88
  readonly loadMode = "discoverable";
87
89
  constructor(session: ToolSession);
88
90
  static createIf(session: ToolSession): IrcTool | null;
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import type { Component } from "@oh-my-pi/pi-tui";
3
4
  import { z } from "zod/v4";
4
5
  import type { SSHHost } from "../capability/ssh";
@@ -36,6 +37,7 @@ export declare class SshTool implements AgentTool<typeof sshSchema, SSHToolDetai
36
37
  }, z.core.$strip>;
37
38
  readonly concurrency = "exclusive";
38
39
  readonly strict = true;
40
+ readonly examples: readonly ToolExample<z.input<typeof sshSchema>>[];
39
41
  constructor(session: ToolSession, hostNames: string[], hostsByName: Map<string, SSHHost>, description: string);
40
42
  execute(_toolCallId: string, { host, command, cwd, timeout: rawTimeout }: SshToolParams, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<SSHToolDetails>, _ctx?: AgentToolContext): Promise<AgentToolResult<SSHToolDetails>>;
41
43
  }
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
+ import type { ToolExample } from "@oh-my-pi/pi-ai";
2
3
  import type { Component } from "@oh-my-pi/pi-tui";
3
4
  import { z } from "zod/v4";
4
5
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
@@ -117,6 +118,7 @@ export declare class TodoTool implements AgentTool<typeof todoSchema, TodoToolDe
117
118
  }, z.core.$strip>;
118
119
  readonly concurrency = "exclusive";
119
120
  readonly strict = true;
121
+ readonly examples: readonly ToolExample<z.input<typeof todoSchema>>[];
120
122
  readonly loadMode = "discoverable";
121
123
  constructor(session: ToolSession);
122
124
  execute(_toolCallId: string, params: TodoParams, _signal?: AbortSignal, _onUpdate?: AgentToolUpdateCallback<TodoToolDetails>, _context?: AgentToolContext): Promise<AgentToolResult<TodoToolDetails>>;
@@ -12,6 +12,7 @@ export interface TreeListOptions<T> {
12
12
  */
13
13
  maxCollapsedLines?: number;
14
14
  itemType?: string;
15
+ truncateFrom?: "start" | "end";
15
16
  /** Called once per item with `isLast: false` during budget calculation;
16
17
  * line count MUST NOT vary based on `isLast`. */
17
18
  renderItem: (item: T, context: TreeContext) => string | string[];
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.13.1",
4
+ "version": "15.13.2",
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,17 @@
47
47
  "@agentclientprotocol/sdk": "0.25.0",
48
48
  "@babel/parser": "^7.29.7",
49
49
  "@mozilla/readability": "^0.6.0",
50
- "@oh-my-pi/hashline": "15.13.1",
51
- "@oh-my-pi/omp-stats": "15.13.1",
52
- "@oh-my-pi/pi-agent-core": "15.13.1",
53
- "@oh-my-pi/pi-ai": "15.13.1",
54
- "@oh-my-pi/pi-catalog": "15.13.1",
55
- "@oh-my-pi/pi-mnemopi": "15.13.1",
56
- "@oh-my-pi/pi-natives": "15.13.1",
57
- "@oh-my-pi/pi-tui": "15.13.1",
58
- "@oh-my-pi/pi-utils": "15.13.1",
59
- "@oh-my-pi/pi-wire": "15.13.1",
60
- "@oh-my-pi/snapcompact": "15.13.1",
50
+ "@oh-my-pi/hashline": "15.13.2",
51
+ "@oh-my-pi/omp-stats": "15.13.2",
52
+ "@oh-my-pi/pi-agent-core": "15.13.2",
53
+ "@oh-my-pi/pi-ai": "15.13.2",
54
+ "@oh-my-pi/pi-catalog": "15.13.2",
55
+ "@oh-my-pi/pi-mnemopi": "15.13.2",
56
+ "@oh-my-pi/pi-natives": "15.13.2",
57
+ "@oh-my-pi/pi-tui": "15.13.2",
58
+ "@oh-my-pi/pi-utils": "15.13.2",
59
+ "@oh-my-pi/pi-wire": "15.13.2",
60
+ "@oh-my-pi/snapcompact": "15.13.2",
61
61
  "@opentelemetry/api": "^1.9.1",
62
62
  "@opentelemetry/context-async-hooks": "^2.7.1",
63
63
  "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
@@ -130,11 +130,13 @@ export function mergeDiscoveredModel<TApi extends Api>(
130
130
  providerOverride?: Pick<ProviderOverride, "baseUrl" | "headers" | "transport">,
131
131
  ): Model<TApi> {
132
132
  if (existing) {
133
+ const supportsTools = model.supportsTools ?? existing.supportsTools;
133
134
  return buildModel({
134
135
  ...model,
135
136
  baseUrl: providerOverride?.baseUrl ?? model.baseUrl ?? existing.baseUrl,
136
137
  headers: existing.headers ? { ...existing.headers, ...model.headers } : model.headers,
137
138
  transport: providerOverride?.transport ?? existing.transport ?? model.transport,
139
+ ...(supportsTools !== undefined ? { supportsTools } : {}),
138
140
  compat: model.compatConfig,
139
141
  } as ModelSpec<TApi>);
140
142
  }
@@ -370,6 +372,7 @@ interface ModelPatch {
370
372
  reasoning?: boolean;
371
373
  thinking?: ThinkingConfig;
372
374
  input?: ("text" | "image")[];
375
+ supportsTools?: boolean;
373
376
  cost?: Partial<Model<Api>["cost"]>;
374
377
  contextWindow?: number;
375
378
  maxTokens?: number;
@@ -395,6 +398,7 @@ function applyModelPatch(base: Model<Api>, patch: ModelPatch, transport: ModelTr
395
398
  if (patch.reasoning !== undefined) result.reasoning = patch.reasoning;
396
399
  if (patch.thinking !== undefined) result.thinking = patch.thinking;
397
400
  if (patch.input !== undefined) result.input = patch.input;
401
+ if (patch.supportsTools !== undefined) result.supportsTools = patch.supportsTools;
398
402
  if (patch.contextWindow !== undefined) result.contextWindow = patch.contextWindow;
399
403
  if (patch.maxTokens !== undefined) result.maxTokens = patch.maxTokens;
400
404
  if (patch.omitMaxOutputTokens !== undefined) result.omitMaxOutputTokens = patch.omitMaxOutputTokens;
@@ -506,6 +510,7 @@ function buildCustomModelOverlay(
506
510
  reasoning: modelDef.reasoning,
507
511
  thinking: modelDef.thinking,
508
512
  input: modelDef.input,
513
+ supportsTools: modelDef.supportsTools,
509
514
  cost: modelDef.cost,
510
515
  contextWindow: modelDef.contextWindow,
511
516
  maxTokens: modelDef.maxTokens,
@@ -535,6 +540,7 @@ function finalizeCustomModel(model: CustomModelOverlay, options: CustomModelBuil
535
540
  reference?.cost ??
536
541
  (options.useDefaults ? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } : undefined);
537
542
  const input = resolvedModel.input ?? reference?.input ?? (options.useDefaults ? ["text"] : undefined);
543
+ const supportsTools = resolvedModel.supportsTools ?? reference?.supportsTools;
538
544
  return buildModel({
539
545
  id: resolvedModel.id,
540
546
  name: resolvedModel.name ?? (options.useDefaults ? resolvedModel.id : undefined),
@@ -544,6 +550,7 @@ function finalizeCustomModel(model: CustomModelOverlay, options: CustomModelBuil
544
550
  reasoning: resolvedModel.reasoning ?? reference?.reasoning ?? (options.useDefaults ? false : undefined),
545
551
  thinking: resolvedModel.thinking ?? reference?.thinking,
546
552
  input: input as ("text" | "image")[],
553
+ ...(supportsTools !== undefined ? { supportsTools } : {}),
547
554
  cost,
548
555
  contextWindow: resolvedModel.contextWindow ?? reference?.contextWindow ?? (options.useDefaults ? 128000 : null),
549
556
  maxTokens: resolvedModel.maxTokens ?? reference?.maxTokens ?? (options.useDefaults ? 16384 : null),
@@ -878,10 +885,12 @@ export class ModelRegistry {
878
885
  #mergeResolvedModels(baseModels: Model<Api>[], replacementModels: Model<Api>[]): Model<Api>[] {
879
886
  return mergeByModelKey(baseModels, replacementModels, (existing, replacementModel) => {
880
887
  if (!existing) return replacementModel;
888
+ const supportsTools = replacementModel.supportsTools ?? existing.supportsTools;
881
889
  return {
882
890
  ...replacementModel,
883
891
  contextWindow: replacementModel.contextWindow ?? existing.contextWindow,
884
892
  maxTokens: replacementModel.maxTokens ?? existing.maxTokens,
893
+ ...(supportsTools !== undefined ? { supportsTools } : {}),
885
894
  };
886
895
  });
887
896
  }
@@ -2205,6 +2214,7 @@ export interface ProviderConfigInput {
2205
2214
  reasoning: boolean;
2206
2215
  thinking?: ThinkingConfig;
2207
2216
  input: ("text" | "image")[];
2217
+ supportsTools?: boolean;
2208
2218
  cost: { input: number; output: number; cacheRead: number; cacheWrite: number };
2209
2219
  contextWindow: number;
2210
2220
  maxTokens: number;
@@ -133,6 +133,7 @@ const ModelDefinitionSchema = z.object({
133
133
  reasoning: z.boolean().optional(),
134
134
  thinking: ModelThinkingSchema.optional(),
135
135
  input: z.array(z.enum(["text", "image"])).optional(),
136
+ supportsTools: z.boolean().optional(),
136
137
  cost: z
137
138
  .object({
138
139
  input: z.number(),
@@ -155,6 +156,7 @@ export const ModelOverrideSchema = z.object({
155
156
  reasoning: z.boolean().optional(),
156
157
  thinking: ModelThinkingSchema.optional(),
157
158
  input: z.array(z.enum(["text", "image"])).optional(),
159
+ supportsTools: z.boolean().optional(),
158
160
  cost: z
159
161
  .object({
160
162
  input: z.number().optional(),
@@ -17,6 +17,7 @@ export interface ProviderValidationModel {
17
17
  id: string;
18
18
  api?: Api;
19
19
  contextWindow?: number;
20
+ supportsTools?: boolean;
20
21
  maxTokens?: number;
21
22
  }
22
23