@oh-my-pi/pi-coding-agent 3.20.1 → 3.24.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 (123) hide show
  1. package/CHANGELOG.md +107 -8
  2. package/docs/custom-tools.md +3 -3
  3. package/docs/extensions.md +226 -220
  4. package/docs/hooks.md +2 -2
  5. package/docs/sdk.md +50 -53
  6. package/examples/custom-tools/README.md +2 -17
  7. package/examples/extensions/README.md +76 -74
  8. package/examples/extensions/todo.ts +2 -5
  9. package/examples/hooks/custom-compaction.ts +2 -4
  10. package/examples/hooks/handoff.ts +1 -1
  11. package/examples/hooks/qna.ts +1 -1
  12. package/examples/sdk/02-custom-model.ts +1 -1
  13. package/examples/sdk/README.md +7 -11
  14. package/package.json +6 -6
  15. package/src/cli/args.ts +9 -6
  16. package/src/cli/file-processor.ts +1 -1
  17. package/src/cli/list-models.ts +1 -1
  18. package/src/core/agent-session.ts +16 -5
  19. package/src/core/auth-storage.ts +1 -1
  20. package/src/core/compaction/branch-summarization.ts +2 -2
  21. package/src/core/compaction/compaction.ts +2 -2
  22. package/src/core/compaction/utils.ts +1 -1
  23. package/src/core/custom-tools/types.ts +1 -1
  24. package/src/core/custom-tools/wrapper.ts +0 -1
  25. package/src/core/extensions/index.ts +1 -6
  26. package/src/core/extensions/runner.ts +1 -1
  27. package/src/core/extensions/types.ts +1 -1
  28. package/src/core/extensions/wrapper.ts +1 -8
  29. package/src/core/file-mentions.ts +5 -8
  30. package/src/core/hooks/runner.ts +2 -2
  31. package/src/core/hooks/types.ts +1 -1
  32. package/src/core/messages.ts +1 -1
  33. package/src/core/model-registry.ts +1 -1
  34. package/src/core/model-resolver.ts +1 -1
  35. package/src/core/sdk.ts +64 -105
  36. package/src/core/session-manager.ts +18 -22
  37. package/src/core/settings-manager.ts +66 -1
  38. package/src/core/slash-commands.ts +12 -5
  39. package/src/core/system-prompt.ts +49 -36
  40. package/src/core/title-generator.ts +2 -2
  41. package/src/core/tools/ask.ts +98 -4
  42. package/src/core/tools/bash-interceptor.ts +11 -4
  43. package/src/core/tools/bash.ts +121 -5
  44. package/src/core/tools/context.ts +7 -0
  45. package/src/core/tools/edit-diff.ts +73 -24
  46. package/src/core/tools/edit.ts +221 -34
  47. package/src/core/tools/exa/render.ts +4 -16
  48. package/src/core/tools/find.ts +149 -5
  49. package/src/core/tools/gemini-image.ts +279 -56
  50. package/src/core/tools/git.ts +17 -3
  51. package/src/core/tools/grep.ts +185 -5
  52. package/src/core/tools/index.test.ts +180 -0
  53. package/src/core/tools/index.ts +96 -242
  54. package/src/core/tools/ls.ts +133 -5
  55. package/src/core/tools/lsp/index.ts +32 -29
  56. package/src/core/tools/lsp/render.ts +21 -22
  57. package/src/core/tools/notebook.ts +112 -4
  58. package/src/core/tools/output.ts +175 -15
  59. package/src/core/tools/read.ts +127 -25
  60. package/src/core/tools/render-utils.ts +241 -0
  61. package/src/core/tools/renderers.ts +40 -828
  62. package/src/core/tools/review.ts +26 -25
  63. package/src/core/tools/rulebook.ts +11 -3
  64. package/src/core/tools/task/agents.ts +28 -7
  65. package/src/core/tools/task/discovery.ts +0 -6
  66. package/src/core/tools/task/executor.ts +264 -254
  67. package/src/core/tools/task/index.ts +48 -208
  68. package/src/core/tools/task/render.ts +26 -11
  69. package/src/core/tools/task/types.ts +7 -12
  70. package/src/core/tools/task/worker-protocol.ts +17 -0
  71. package/src/core/tools/task/worker.ts +238 -0
  72. package/src/core/tools/truncate.ts +27 -1
  73. package/src/core/tools/web-fetch.ts +25 -49
  74. package/src/core/tools/web-search/index.ts +132 -46
  75. package/src/core/tools/web-search/providers/anthropic.ts +7 -2
  76. package/src/core/tools/web-search/providers/exa.ts +2 -1
  77. package/src/core/tools/web-search/providers/perplexity.ts +6 -1
  78. package/src/core/tools/web-search/render.ts +6 -4
  79. package/src/core/tools/web-search/types.ts +13 -0
  80. package/src/core/tools/write.ts +96 -14
  81. package/src/core/voice.ts +1 -1
  82. package/src/discovery/helpers.test.ts +1 -1
  83. package/src/index.ts +5 -16
  84. package/src/main.ts +5 -5
  85. package/src/modes/interactive/components/assistant-message.ts +1 -1
  86. package/src/modes/interactive/components/custom-message.ts +1 -1
  87. package/src/modes/interactive/components/extensions/inspector-panel.ts +25 -22
  88. package/src/modes/interactive/components/extensions/state-manager.ts +12 -0
  89. package/src/modes/interactive/components/footer.ts +1 -1
  90. package/src/modes/interactive/components/hook-message.ts +1 -1
  91. package/src/modes/interactive/components/model-selector.ts +1 -1
  92. package/src/modes/interactive/components/oauth-selector.ts +1 -1
  93. package/src/modes/interactive/components/settings-defs.ts +49 -0
  94. package/src/modes/interactive/components/status-line.ts +1 -1
  95. package/src/modes/interactive/components/tool-execution.ts +93 -538
  96. package/src/modes/interactive/interactive-mode.ts +19 -7
  97. package/src/modes/interactive/theme/theme.ts +4 -4
  98. package/src/modes/print-mode.ts +1 -1
  99. package/src/modes/rpc/rpc-client.ts +1 -1
  100. package/src/modes/rpc/rpc-types.ts +1 -1
  101. package/src/prompts/system-prompt.md +4 -0
  102. package/src/prompts/task.md +0 -7
  103. package/src/prompts/tools/gemini-image.md +5 -1
  104. package/src/prompts/tools/output.md +6 -2
  105. package/src/prompts/tools/task.md +68 -0
  106. package/src/prompts/tools/web-fetch.md +1 -0
  107. package/src/prompts/tools/web-search.md +2 -0
  108. package/src/utils/image-convert.ts +8 -2
  109. package/src/utils/image-magick.ts +247 -0
  110. package/src/utils/image-resize.ts +53 -13
  111. package/examples/custom-tools/question/index.ts +0 -84
  112. package/examples/custom-tools/subagent/README.md +0 -172
  113. package/examples/custom-tools/subagent/agents/planner.md +0 -37
  114. package/examples/custom-tools/subagent/agents/scout.md +0 -50
  115. package/examples/custom-tools/subagent/agents/worker.md +0 -24
  116. package/examples/custom-tools/subagent/agents.ts +0 -156
  117. package/examples/custom-tools/subagent/commands/implement-and-review.md +0 -10
  118. package/examples/custom-tools/subagent/commands/implement.md +0 -10
  119. package/examples/custom-tools/subagent/commands/scout-and-plan.md +0 -9
  120. package/examples/custom-tools/subagent/index.ts +0 -1002
  121. package/examples/sdk/05-tools.ts +0 -94
  122. package/examples/sdk/12-full-control.ts +0 -95
  123. package/src/prompts/browser.md +0 -71
@@ -19,13 +19,6 @@ const PRIORITY_LABELS: Record<number, string> = {
19
19
  3: "P3",
20
20
  };
21
21
 
22
- const _PRIORITY_DESCRIPTIONS: Record<number, string> = {
23
- 0: "Drop everything to fix. Blocking release, operations, or major usage.",
24
- 1: "Urgent. Should be addressed in the next cycle.",
25
- 2: "Normal. To be fixed eventually.",
26
- 3: "Low. Nice to have.",
27
- };
28
-
29
22
  // report_finding schema
30
23
  const ReportFindingParams = Type.Object({
31
24
  title: Type.String({
@@ -62,8 +55,6 @@ export const reportFindingTool: AgentTool<typeof ReportFindingParams, ReportFind
62
55
  label: "Report Finding",
63
56
  description: "Report a code review finding. Use this for each issue found. Call submit_review when done.",
64
57
  parameters: ReportFindingParams,
65
- hidden: true,
66
-
67
58
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
68
59
  const { title, body, priority, confidence, file_path, line_start, line_end } = params;
69
60
  const location = `${file_path}:${line_start}${line_end !== line_start ? `-${line_end}` : ""}`;
@@ -72,7 +63,9 @@ export const reportFindingTool: AgentTool<typeof ReportFindingParams, ReportFind
72
63
  content: [
73
64
  {
74
65
  type: "text",
75
- text: `Finding recorded: ${PRIORITY_LABELS[priority]} ${title}\nLocation: ${location}\nConfidence: ${(confidence * 100).toFixed(0)}%`,
66
+ text: `Finding recorded: ${PRIORITY_LABELS[priority]} ${title}\nLocation: ${location}\nConfidence: ${(
67
+ confidence * 100
68
+ ).toFixed(0)}%`,
76
69
  },
77
70
  ],
78
71
  details: { title, body, priority, confidence, file_path, line_start, line_end },
@@ -84,7 +77,10 @@ export const reportFindingTool: AgentTool<typeof ReportFindingParams, ReportFind
84
77
  const color = args.priority === 0 ? "error" : args.priority === 1 ? "warning" : "muted";
85
78
  const titleText = String(args.title).replace(/^\[P\d\]\s*/, "");
86
79
  return new Text(
87
- `${theme.fg("toolTitle", theme.bold("report_finding "))}${theme.fg(color, `[${priority}]`)} ${theme.fg("dim", titleText)}`,
80
+ `${theme.fg("toolTitle", theme.bold("report_finding "))}${theme.fg(color, `[${priority}]`)} ${theme.fg(
81
+ "dim",
82
+ titleText,
83
+ )}`,
88
84
  0,
89
85
  0,
90
86
  );
@@ -99,7 +95,9 @@ export const reportFindingTool: AgentTool<typeof ReportFindingParams, ReportFind
99
95
 
100
96
  const priority = PRIORITY_LABELS[details.priority] ?? "P?";
101
97
  const color = details.priority === 0 ? "error" : details.priority === 1 ? "warning" : "muted";
102
- const location = `${details.file_path}:${details.line_start}${details.line_end !== details.line_start ? `-${details.line_end}` : ""}`;
98
+ const location = `${details.file_path}:${details.line_start}${
99
+ details.line_end !== details.line_start ? `-${details.line_end}` : ""
100
+ }`;
103
101
 
104
102
  return new Text(
105
103
  `${theme.fg("success", theme.status.success)} ${theme.fg(color, `[${priority}]`)} ${theme.fg("dim", location)}`,
@@ -135,13 +133,16 @@ export const submitReviewTool: AgentTool<typeof SubmitReviewParams, SubmitReview
135
133
  label: "Submit Review",
136
134
  description: "Submit the final review verdict. Call this after all findings have been reported.",
137
135
  parameters: SubmitReviewParams,
138
- hidden: true,
139
136
 
140
137
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
141
138
  const { overall_correctness, explanation, confidence } = params;
142
139
 
143
140
  let summary = `## Review Summary\n\n`;
144
- summary += `**Verdict:** ${overall_correctness === "correct" ? `${theme.status.success} Patch is correct` : `${theme.status.error} Patch is incorrect`}\n`;
141
+ summary += `**Verdict:** ${
142
+ overall_correctness === "correct"
143
+ ? `${theme.status.success} Patch is correct`
144
+ : `${theme.status.error} Patch is incorrect`
145
+ }\n`;
145
146
  summary += `**Confidence:** ${(confidence * 100).toFixed(0)}%\n\n`;
146
147
  summary += explanation;
147
148
 
@@ -155,7 +156,10 @@ export const submitReviewTool: AgentTool<typeof SubmitReviewParams, SubmitReview
155
156
  const verdict = args.overall_correctness === "correct" ? "correct" : "incorrect";
156
157
  const color = args.overall_correctness === "correct" ? "success" : "error";
157
158
  return new Text(
158
- `${theme.fg("toolTitle", theme.bold("submit_review "))}${theme.fg(color, verdict)} ${theme.fg("dim", `(${((args.confidence as number) * 100).toFixed(0)}%)`)}`,
159
+ `${theme.fg("toolTitle", theme.bold("submit_review "))}${theme.fg(color, verdict)} ${theme.fg(
160
+ "dim",
161
+ `(${((args.confidence as number) * 100).toFixed(0)}%)`,
162
+ )}`,
159
163
  0,
160
164
  0,
161
165
  );
@@ -174,7 +178,10 @@ export const submitReviewTool: AgentTool<typeof SubmitReviewParams, SubmitReview
174
178
 
175
179
  container.addChild(
176
180
  new Text(
177
- `${theme.fg(verdictColor, verdictIcon)} Patch is ${theme.fg(verdictColor, details.overall_correctness)} ${theme.fg("dim", `(${(details.confidence * 100).toFixed(0)}% confidence)`)}`,
181
+ `${theme.fg(verdictColor, verdictIcon)} Patch is ${theme.fg(
182
+ verdictColor,
183
+ details.overall_correctness,
184
+ )} ${theme.fg("dim", `(${(details.confidence * 100).toFixed(0)}% confidence)`)}`,
178
185
  0,
179
186
  0,
180
187
  ),
@@ -189,14 +196,6 @@ export const submitReviewTool: AgentTool<typeof SubmitReviewParams, SubmitReview
189
196
  },
190
197
  };
191
198
 
192
- export function createReportFindingTool(): AgentTool<typeof ReportFindingParams, ReportFindingDetails, Theme> {
193
- return reportFindingTool;
194
- }
195
-
196
- export function createSubmitReviewTool(): AgentTool<typeof SubmitReviewParams, SubmitReviewDetails, Theme> {
197
- return submitReviewTool;
198
- }
199
-
200
199
  // Re-export types for external use
201
200
  export type { ReportFindingDetails, SubmitReviewDetails };
202
201
 
@@ -264,7 +263,9 @@ subprocessToolRegistry.register<SubmitReviewDetails>("submit_review", {
264
263
  const verdictColor = data.overall_correctness === "correct" ? "success" : "error";
265
264
  const verdictIcon = data.overall_correctness === "correct" ? theme.status.success : theme.status.error;
266
265
  return new Text(
267
- `${theme.fg(verdictColor, verdictIcon)} Review: ${theme.fg(verdictColor, data.overall_correctness)} (${(data.confidence * 100).toFixed(0)}%)`,
266
+ `${theme.fg(verdictColor, verdictIcon)} Review: ${theme.fg(verdictColor, data.overall_correctness)} (${(
267
+ data.confidence * 100
268
+ ).toFixed(0)}%)`,
268
269
  0,
269
270
  0,
270
271
  );
@@ -9,6 +9,7 @@
9
9
  import type { AgentTool } from "@oh-my-pi/pi-agent-core";
10
10
  import { Type } from "@sinclair/typebox";
11
11
  import type { Rule } from "../../capability/rule";
12
+ import type { ToolSession } from "./index";
12
13
 
13
14
  export interface RulebookToolDetails {
14
15
  type: "rulebook";
@@ -23,9 +24,14 @@ const rulebookSchema = Type.Object({
23
24
 
24
25
  /**
25
26
  * Create a rulebook tool with access to discovered rules.
26
- * @param rules - Array of discovered rules (non-TTSR rules with descriptions)
27
+ * Returns null if no rules available.
27
28
  */
28
- export function createRulebookTool(rules: Rule[]): AgentTool<typeof rulebookSchema> {
29
+ export function createRulebookTool(session: ToolSession): AgentTool<typeof rulebookSchema> | null {
30
+ const rules = session.rulebookRules;
31
+ if (!rules || rules.length === 0) {
32
+ return null;
33
+ }
34
+
29
35
  // Build lookup map for O(1) access
30
36
  const ruleMap = new Map<string, Rule>();
31
37
  for (const rule of rules) {
@@ -37,7 +43,9 @@ export function createRulebookTool(rules: Rule[]): AgentTool<typeof rulebookSche
37
43
  return {
38
44
  name: "rulebook",
39
45
  label: "Rulebook",
40
- description: `Fetch the full content of a project rule by name. Use this when a rule listed in <available_rules> is relevant to your current task. Available: ${ruleNames.join(", ") || "(none)"}`,
46
+ description: `Fetch the full content of a project rule by name. Use this when a rule listed in <available_rules> is relevant to your current task. Available: ${
47
+ ruleNames.join(", ") || "(none)"
48
+ }`,
41
49
  parameters: rulebookSchema,
42
50
  execute: async (_toolCallId: string, { name }: { name: string }) => {
43
51
  const rule = ruleMap.get(name);
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  // Embed agent markdown files at build time
8
- import browserMd from "../../../prompts/browser.md" with { type: "text" };
9
8
  import exploreMd from "../../../prompts/explore.md" with { type: "text" };
10
9
  import planMd from "../../../prompts/plan.md" with { type: "text" };
11
10
  import reviewerMd from "../../../prompts/reviewer.md" with { type: "text" };
@@ -13,11 +12,37 @@ import taskMd from "../../../prompts/task.md" with { type: "text" };
13
12
  import type { AgentDefinition, AgentSource } from "./types";
14
13
 
15
14
  const EMBEDDED_AGENTS: { name: string; content: string }[] = [
16
- { name: "browser.md", content: browserMd },
17
15
  { name: "explore.md", content: exploreMd },
18
16
  { name: "plan.md", content: planMd },
19
17
  { name: "reviewer.md", content: reviewerMd },
20
- { name: "task.md", content: taskMd },
18
+ {
19
+ name: "task.md",
20
+ content: `---
21
+ name: task
22
+ description: General-purpose subagent with full capabilities for delegated multi-step tasks
23
+ spawns: explore
24
+ model: default
25
+ ---
26
+ ${taskMd}`,
27
+ },
28
+ {
29
+ name: "quick_task.md",
30
+ content: `---
31
+ name: quick_task
32
+ description: Quick task for fast execution
33
+ model: pi/smol
34
+ ---
35
+ ${taskMd}`,
36
+ },
37
+ {
38
+ name: "deep_task.md",
39
+ content: `---
40
+ name: deep_task
41
+ description: Deep task for comprehensive reasoning
42
+ model: pi/slow
43
+ ---
44
+ ${taskMd}`,
45
+ },
21
46
  ];
22
47
 
23
48
  /**
@@ -88,16 +113,12 @@ function parseAgent(fileName: string, content: string, source: AgentSource): Age
88
113
  spawns = "*";
89
114
  }
90
115
 
91
- const recursive =
92
- frontmatter.recursive === undefined ? false : frontmatter.recursive === "true" || frontmatter.recursive === "1";
93
-
94
116
  return {
95
117
  name: frontmatter.name,
96
118
  description: frontmatter.description,
97
119
  tools: tools && tools.length > 0 ? tools : undefined,
98
120
  spawns,
99
121
  model: frontmatter.model,
100
- recursive,
101
122
  systemPrompt: body,
102
123
  source,
103
124
  filePath: `embedded:${fileName}`,
@@ -126,18 +126,12 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentDefinition[]
126
126
  spawns = "*";
127
127
  }
128
128
 
129
- const recursive =
130
- frontmatter.recursive === undefined
131
- ? undefined
132
- : frontmatter.recursive === "true" || frontmatter.recursive === "1";
133
-
134
129
  agents.push({
135
130
  name: frontmatter.name,
136
131
  description: frontmatter.description,
137
132
  tools: tools && tools.length > 0 ? tools : undefined,
138
133
  spawns,
139
134
  model: frontmatter.model,
140
- recursive,
141
135
  systemPrompt: body,
142
136
  source,
143
137
  filePath,