@oh-my-pi/pi-coding-agent 13.19.0 → 14.0.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.
- package/CHANGELOG.md +266 -1
- package/package.json +86 -20
- package/scripts/format-prompts.ts +2 -2
- package/src/autoresearch/apply-contract-to-state.ts +24 -0
- package/src/autoresearch/contract.ts +0 -44
- package/src/autoresearch/dashboard.ts +1 -2
- package/src/autoresearch/git.ts +91 -0
- package/src/autoresearch/helpers.ts +49 -0
- package/src/autoresearch/index.ts +28 -187
- package/src/autoresearch/prompt.md +26 -9
- package/src/autoresearch/state.ts +0 -6
- package/src/autoresearch/tools/init-experiment.ts +202 -117
- package/src/autoresearch/tools/log-experiment.ts +83 -125
- package/src/autoresearch/tools/run-experiment.ts +48 -10
- package/src/autoresearch/types.ts +2 -2
- package/src/capability/index.ts +4 -2
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/grep-cli.ts +8 -8
- package/src/cli/grievances-cli.ts +78 -0
- package/src/cli/read-cli.ts +67 -0
- package/src/cli/setup-cli.ts +4 -4
- package/src/cli/update-cli.ts +3 -3
- package/src/cli.ts +2 -0
- package/src/commands/grep.ts +6 -1
- package/src/commands/grievances.ts +20 -0
- package/src/commands/read.ts +33 -0
- package/src/commit/agentic/agent.ts +5 -5
- package/src/commit/agentic/index.ts +3 -4
- package/src/commit/agentic/tools/analyze-file.ts +3 -3
- package/src/commit/agentic/validation.ts +1 -1
- package/src/commit/analysis/conventional.ts +4 -4
- package/src/commit/analysis/summary.ts +3 -3
- package/src/commit/changelog/generate.ts +4 -4
- package/src/commit/map-reduce/map-phase.ts +4 -4
- package/src/commit/map-reduce/reduce-phase.ts +4 -4
- package/src/commit/pipeline.ts +3 -4
- package/src/config/prompt-templates.ts +44 -226
- package/src/config/resolve-config-value.ts +4 -2
- package/src/config/settings-schema.ts +54 -2
- package/src/config/settings.ts +25 -26
- package/src/dap/client.ts +674 -0
- package/src/dap/config.ts +150 -0
- package/src/dap/defaults.json +211 -0
- package/src/dap/index.ts +4 -0
- package/src/dap/session.ts +1255 -0
- package/src/dap/types.ts +600 -0
- package/src/debug/log-viewer.ts +3 -2
- package/src/discovery/builtin.ts +1 -2
- package/src/discovery/codex.ts +2 -2
- package/src/discovery/github.ts +2 -1
- package/src/discovery/helpers.ts +2 -2
- package/src/discovery/opencode.ts +2 -2
- package/src/edit/diff.ts +818 -0
- package/src/edit/index.ts +309 -0
- package/src/edit/line-hash.ts +67 -0
- package/src/edit/modes/chunk.ts +454 -0
- package/src/{patch → edit/modes}/hashline.ts +741 -361
- package/src/{patch/applicator.ts → edit/modes/patch.ts} +420 -117
- package/src/{patch/fuzzy.ts → edit/modes/replace.ts} +519 -197
- package/src/{patch → edit}/normalize.ts +97 -76
- package/src/{patch/shared.ts → edit/renderer.ts} +181 -108
- package/src/exec/bash-executor.ts +4 -2
- package/src/exec/idle-timeout-watchdog.ts +126 -0
- package/src/exec/non-interactive-env.ts +5 -0
- package/src/extensibility/custom-commands/bundled/ci-green/index.ts +2 -2
- package/src/extensibility/custom-commands/bundled/review/index.ts +2 -2
- package/src/extensibility/custom-commands/loader.ts +1 -2
- package/src/extensibility/custom-tools/loader.ts +34 -11
- package/src/extensibility/extensions/loader.ts +9 -4
- package/src/extensibility/extensions/runner.ts +24 -1
- package/src/extensibility/extensions/types.ts +1 -1
- package/src/extensibility/hooks/loader.ts +5 -6
- package/src/extensibility/hooks/types.ts +1 -1
- package/src/extensibility/plugins/doctor.ts +2 -1
- package/src/extensibility/slash-commands.ts +3 -7
- package/src/index.ts +2 -1
- package/src/internal-urls/docs-index.generated.ts +11 -11
- package/src/ipy/executor.ts +58 -17
- package/src/ipy/gateway-coordinator.ts +6 -4
- package/src/ipy/kernel.ts +45 -22
- package/src/ipy/runtime.ts +2 -2
- package/src/lsp/client.ts +7 -4
- package/src/lsp/clients/lsp-linter-client.ts +4 -4
- package/src/lsp/config.ts +2 -2
- package/src/lsp/defaults.json +688 -154
- package/src/lsp/index.ts +234 -45
- package/src/lsp/lspmux.ts +2 -2
- package/src/lsp/startup-events.ts +13 -0
- package/src/lsp/types.ts +12 -1
- package/src/lsp/utils.ts +8 -1
- package/src/main.ts +102 -46
- package/src/memories/index.ts +4 -5
- package/src/modes/acp/acp-agent.ts +563 -163
- package/src/modes/acp/acp-event-mapper.ts +9 -1
- package/src/modes/acp/acp-mode.ts +4 -2
- package/src/modes/components/agent-dashboard.ts +3 -4
- package/src/modes/components/diff.ts +6 -7
- package/src/modes/components/read-tool-group.ts +6 -12
- package/src/modes/components/settings-defs.ts +5 -0
- package/src/modes/components/tool-execution.ts +1 -1
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/controllers/btw-controller.ts +2 -2
- package/src/modes/controllers/command-controller.ts +3 -2
- package/src/modes/controllers/input-controller.ts +12 -8
- package/src/modes/index.ts +20 -2
- package/src/modes/interactive-mode.ts +94 -37
- package/src/modes/rpc/host-tools.ts +186 -0
- package/src/modes/rpc/rpc-client.ts +178 -13
- package/src/modes/rpc/rpc-mode.ts +73 -3
- package/src/modes/rpc/rpc-types.ts +53 -1
- package/src/modes/theme/theme.ts +80 -8
- package/src/modes/types.ts +2 -2
- package/src/prompts/system/system-prompt.md +2 -1
- package/src/prompts/tools/chunk-edit.md +219 -0
- package/src/prompts/tools/debug.md +43 -0
- package/src/prompts/tools/grep.md +3 -0
- package/src/prompts/tools/lsp.md +5 -5
- package/src/prompts/tools/read-chunk.md +17 -0
- package/src/prompts/tools/read.md +19 -5
- package/src/sdk.ts +190 -154
- package/src/secrets/obfuscator.ts +1 -1
- package/src/session/agent-session.ts +306 -256
- package/src/session/agent-storage.ts +12 -12
- package/src/session/compaction/branch-summarization.ts +3 -3
- package/src/session/compaction/compaction.ts +5 -6
- package/src/session/compaction/utils.ts +3 -3
- package/src/session/history-storage.ts +62 -19
- package/src/session/messages.ts +3 -3
- package/src/session/session-dump-format.ts +203 -0
- package/src/session/session-storage.ts +4 -2
- package/src/session/streaming-output.ts +1 -1
- package/src/session/tool-choice-queue.ts +213 -0
- package/src/slash-commands/builtin-registry.ts +56 -8
- package/src/ssh/connection-manager.ts +2 -2
- package/src/ssh/sshfs-mount.ts +5 -5
- package/src/stt/downloader.ts +4 -4
- package/src/stt/recorder.ts +4 -4
- package/src/stt/transcriber.ts +2 -2
- package/src/system-prompt.ts +21 -13
- package/src/task/agents.ts +5 -6
- package/src/task/commands.ts +2 -5
- package/src/task/executor.ts +4 -4
- package/src/task/index.ts +3 -4
- package/src/task/template.ts +2 -2
- package/src/task/worktree.ts +4 -4
- package/src/tools/ask.ts +2 -3
- package/src/tools/ast-edit.ts +7 -7
- package/src/tools/ast-grep.ts +7 -7
- package/src/tools/auto-generated-guard.ts +36 -41
- package/src/tools/await-tool.ts +2 -2
- package/src/tools/bash.ts +5 -23
- package/src/tools/browser.ts +4 -5
- package/src/tools/calculator.ts +2 -3
- package/src/tools/cancel-job.ts +2 -2
- package/src/tools/checkpoint.ts +3 -3
- package/src/tools/debug.ts +1007 -0
- package/src/tools/exit-plan-mode.ts +2 -3
- package/src/tools/fetch.ts +67 -3
- package/src/tools/find.ts +4 -5
- package/src/tools/fs-cache-invalidation.ts +5 -0
- package/src/tools/gemini-image.ts +13 -5
- package/src/tools/gh.ts +10 -11
- package/src/tools/grep.ts +57 -9
- package/src/tools/index.ts +44 -22
- package/src/tools/inspect-image.ts +4 -4
- package/src/tools/output-meta.ts +1 -1
- package/src/tools/python.ts +19 -6
- package/src/tools/read.ts +198 -67
- package/src/tools/render-mermaid.ts +2 -3
- package/src/tools/render-utils.ts +20 -6
- package/src/tools/renderers.ts +3 -1
- package/src/tools/report-tool-issue.ts +80 -0
- package/src/tools/resolve.ts +70 -39
- package/src/tools/search-tool-bm25.ts +2 -2
- package/src/tools/ssh.ts +2 -2
- package/src/tools/todo-write.ts +2 -2
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/write.ts +5 -6
- package/src/tui/tree-list.ts +3 -1
- package/src/utils/clipboard.ts +80 -0
- package/src/utils/commit-message-generator.ts +2 -3
- package/src/utils/edit-mode.ts +49 -0
- package/src/utils/file-display-mode.ts +6 -5
- package/src/utils/file-mentions.ts +8 -7
- package/src/utils/git.ts +4 -4
- package/src/utils/image-loading.ts +98 -0
- package/src/utils/title-generator.ts +2 -3
- package/src/utils/tools-manager.ts +6 -6
- package/src/web/scrapers/choosealicense.ts +1 -1
- package/src/web/search/index.ts +3 -3
- package/src/autoresearch/command-initialize.md +0 -34
- package/src/patch/diff.ts +0 -433
- package/src/patch/index.ts +0 -888
- package/src/patch/parser.ts +0 -532
- package/src/patch/types.ts +0 -292
- package/src/prompts/agents/oracle.md +0 -77
- package/src/tools/pending-action.ts +0 -49
- package/src/utils/child-process.ts +0 -88
- package/src/utils/frontmatter.ts +0 -117
- package/src/utils/image-input.ts +0 -274
- package/src/utils/mime.ts +0 -53
- package/src/utils/prompt-format.ts +0 -170
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
3
|
-
import { isEnoent } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import { isEnoent, prompt } from "@oh-my-pi/pi-utils";
|
|
4
4
|
import { type Static, Type } from "@sinclair/typebox";
|
|
5
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
6
5
|
import exitPlanModeDescription from "../prompts/tools/exit-plan-mode.md" with { type: "text" };
|
|
7
6
|
import type { ToolSession } from ".";
|
|
8
7
|
import { resolvePlanPath } from "./plan-mode-guard";
|
|
@@ -49,7 +48,7 @@ export class ExitPlanModeTool implements AgentTool<typeof exitPlanModeSchema, Ex
|
|
|
49
48
|
readonly concurrency = "exclusive";
|
|
50
49
|
|
|
51
50
|
constructor(private readonly session: ToolSession) {
|
|
52
|
-
this.description =
|
|
51
|
+
this.description = prompt.render(exitPlanModeDescription);
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
async execute(
|
package/src/tools/fetch.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
|
4
4
|
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
|
5
5
|
import { htmlToMarkdown } from "@oh-my-pi/pi-natives";
|
|
6
6
|
import { type Component, Text } from "@oh-my-pi/pi-tui";
|
|
7
|
-
import { ptree, truncate } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import { $which, ptree, truncate } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import { parseHTML } from "linkedom";
|
|
9
9
|
import type { Settings } from "../config/settings";
|
|
10
10
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
@@ -23,7 +23,7 @@ import { convertWithMarkit, fetchBinary } from "../web/scrapers/utils";
|
|
|
23
23
|
import { applyListLimit } from "./list-limit";
|
|
24
24
|
import { formatStyledArtifactReference, type OutputMeta } from "./output-meta";
|
|
25
25
|
import { formatExpandHint, getDomain } from "./render-utils";
|
|
26
|
-
import { ToolAbortError } from "./tool-errors";
|
|
26
|
+
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
27
27
|
import { toolResult } from "./tool-result";
|
|
28
28
|
import { clampTimeout } from "./tool-timeouts";
|
|
29
29
|
|
|
@@ -94,7 +94,7 @@ const MAX_INLINE_IMAGE_OUTPUT_BYTES = 0.75 * 1024 * 1024;
|
|
|
94
94
|
* Check if a command exists (cross-platform)
|
|
95
95
|
*/
|
|
96
96
|
function hasCommand(cmd: string): boolean {
|
|
97
|
-
return Boolean(
|
|
97
|
+
return Boolean($which(cmd));
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
@@ -137,6 +137,70 @@ export function isReadableUrlPath(value: string): boolean {
|
|
|
137
137
|
return /^https?:\/\//i.test(value) || /^www\./i.test(value);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
const URL_LINE_RANGE_RE = /^L(\d+)(?:-L?(\d+))?$/i;
|
|
141
|
+
|
|
142
|
+
export interface ParsedReadUrlTarget {
|
|
143
|
+
path: string;
|
|
144
|
+
raw: boolean;
|
|
145
|
+
offset?: number;
|
|
146
|
+
limit?: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function parseReadUrlTarget(readPath: string, sel?: string): ParsedReadUrlTarget | null {
|
|
150
|
+
const embedded = sel ? undefined : tryExtractEmbeddedUrlSelector(readPath);
|
|
151
|
+
const urlPath = embedded?.path ?? readPath;
|
|
152
|
+
if (!isReadableUrlPath(urlPath)) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const selector = sel ?? embedded?.sel;
|
|
157
|
+
const raw = selector === "raw";
|
|
158
|
+
const lineMatch = selector ? URL_LINE_RANGE_RE.exec(selector) : null;
|
|
159
|
+
if (lineMatch) {
|
|
160
|
+
const startLine = Number.parseInt(lineMatch[1]!, 10);
|
|
161
|
+
if (startLine < 1) {
|
|
162
|
+
throw new ToolError("L0 is invalid; lines are 1-indexed. Use sel=L1.");
|
|
163
|
+
}
|
|
164
|
+
const endLine = lineMatch[2] ? Number.parseInt(lineMatch[2], 10) : undefined;
|
|
165
|
+
if (endLine !== undefined && endLine < startLine) {
|
|
166
|
+
throw new ToolError(`Invalid range L${startLine}-L${endLine}: end must be >= start.`);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
path: urlPath,
|
|
170
|
+
raw: false,
|
|
171
|
+
offset: startLine,
|
|
172
|
+
limit: endLine !== undefined ? endLine - startLine + 1 : undefined,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { path: urlPath, raw };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function tryExtractEmbeddedUrlSelector(readPath: string): { path: string; sel?: string } | null {
|
|
180
|
+
const lastColonIndex = readPath.lastIndexOf(":");
|
|
181
|
+
if (lastColonIndex <= 0) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const candidateSelector = readPath.slice(lastColonIndex + 1);
|
|
186
|
+
const isEmbeddedSelector = candidateSelector === "raw" || URL_LINE_RANGE_RE.test(candidateSelector);
|
|
187
|
+
if (!isEmbeddedSelector) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const basePath = readPath.slice(0, lastColonIndex);
|
|
192
|
+
if (!isReadableUrlPath(basePath)) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
new URL(basePath.startsWith("http://") || basePath.startsWith("https://") ? basePath : `https://${basePath}`);
|
|
198
|
+
return { path: basePath, sel: candidateSelector };
|
|
199
|
+
} catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
140
204
|
/**
|
|
141
205
|
* Normalize MIME type (lowercase, strip charset/params)
|
|
142
206
|
*/
|
package/src/tools/find.ts
CHANGED
|
@@ -4,10 +4,9 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
4
4
|
import { FileType, type GlobMatch, glob } 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
|
-
import { isEnoent, untilAborted } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import { isEnoent, prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import type { Static } from "@sinclair/typebox";
|
|
9
9
|
import { Type } from "@sinclair/typebox";
|
|
10
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
11
10
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
11
|
import type { Theme } from "../modes/theme/theme";
|
|
13
12
|
import findDescription from "../prompts/tools/find.md" with { type: "text" };
|
|
@@ -86,7 +85,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
86
85
|
options?: FindToolOptions,
|
|
87
86
|
) {
|
|
88
87
|
this.#customOps = options?.operations;
|
|
89
|
-
this.description =
|
|
88
|
+
this.description = prompt.render(findDescription);
|
|
90
89
|
}
|
|
91
90
|
|
|
92
91
|
async execute(
|
|
@@ -234,8 +233,8 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
234
233
|
});
|
|
235
234
|
};
|
|
236
235
|
const onMatch = onUpdate
|
|
237
|
-
? (match: GlobMatch | null) => {
|
|
238
|
-
if (signal?.aborted || !match) return;
|
|
236
|
+
? (err: Error | null, match: GlobMatch | null) => {
|
|
237
|
+
if (err || signal?.aborted || !match) return;
|
|
239
238
|
let relativePath = match.path;
|
|
240
239
|
if (!relativePath) return;
|
|
241
240
|
if (match.fileType === FileType.Dir && !relativePath.endsWith("/")) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { invalidateFsScanCache } from "@oh-my-pi/pi-natives";
|
|
2
|
+
import { invalidateChunkCache } from "../edit/modes/chunk";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Invalidate shared filesystem scan caches after a content write/update.
|
|
5
6
|
*/
|
|
6
7
|
export function invalidateFsScanAfterWrite(path: string): void {
|
|
7
8
|
invalidateFsScanCache(path);
|
|
9
|
+
invalidateChunkCache(path);
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -12,6 +14,7 @@ export function invalidateFsScanAfterWrite(path: string): void {
|
|
|
12
14
|
*/
|
|
13
15
|
export function invalidateFsScanAfterDelete(path: string): void {
|
|
14
16
|
invalidateFsScanCache(path);
|
|
17
|
+
invalidateChunkCache(path);
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
/**
|
|
@@ -22,7 +25,9 @@ export function invalidateFsScanAfterDelete(path: string): void {
|
|
|
22
25
|
*/
|
|
23
26
|
export function invalidateFsScanAfterRename(oldPath: string, newPath: string): void {
|
|
24
27
|
invalidateFsScanCache(oldPath);
|
|
28
|
+
invalidateChunkCache(oldPath);
|
|
25
29
|
if (newPath !== oldPath) {
|
|
26
30
|
invalidateFsScanCache(newPath);
|
|
31
|
+
invalidateChunkCache(newPath);
|
|
27
32
|
}
|
|
28
33
|
}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import * as os from "node:os";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { getAntigravityHeaders, getEnvApiKey, StringEnum } from "@oh-my-pi/pi-ai";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
$env,
|
|
6
|
+
isEnoent,
|
|
7
|
+
parseImageMetadata,
|
|
8
|
+
prompt,
|
|
9
|
+
ptree,
|
|
10
|
+
readSseJson,
|
|
11
|
+
Snowflake,
|
|
12
|
+
untilAborted,
|
|
13
|
+
} from "@oh-my-pi/pi-utils";
|
|
5
14
|
import { type Static, Type } from "@sinclair/typebox";
|
|
6
15
|
import type { ModelRegistry } from "../config/model-registry";
|
|
7
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
8
16
|
import type { CustomTool } from "../extensibility/custom-tools/types";
|
|
9
17
|
import geminiImageDescription from "../prompts/tools/gemini-image.md" with { type: "text" };
|
|
10
|
-
import { detectSupportedImageMimeTypeFromFile } from "../utils/mime";
|
|
11
18
|
import { resolveReadPath } from "./path-utils";
|
|
12
19
|
|
|
13
20
|
const DEFAULT_MODEL = "gemini-3-pro-image-preview";
|
|
@@ -417,7 +424,8 @@ async function loadImageFromPath(imagePath: string, cwd: string): Promise<Inline
|
|
|
417
424
|
throw new Error(`Image file too large: ${imagePath}`);
|
|
418
425
|
}
|
|
419
426
|
|
|
420
|
-
const
|
|
427
|
+
const metadata = parseImageMetadata(buffer);
|
|
428
|
+
const mimeType = metadata?.mimeType;
|
|
421
429
|
if (!mimeType) {
|
|
422
430
|
throw new Error(`Unsupported image type: ${imagePath}`);
|
|
423
431
|
}
|
|
@@ -599,7 +607,7 @@ async function parseAntigravitySseForImage(response: Response, signal?: AbortSig
|
|
|
599
607
|
export const geminiImageTool: CustomTool<typeof geminiImageSchema, GeminiImageToolDetails> = {
|
|
600
608
|
name: "generate_image",
|
|
601
609
|
label: "GenerateImage",
|
|
602
|
-
description:
|
|
610
|
+
description: prompt.render(geminiImageDescription),
|
|
603
611
|
parameters: geminiImageSchema,
|
|
604
612
|
async execute(_toolCallId, params, _onUpdate, ctx, signal) {
|
|
605
613
|
return untilAborted(signal, async () => {
|
package/src/tools/gh.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
4
|
-
import { abortableSleep, isEnoent, untilAborted } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { abortableSleep, isEnoent, prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import { type Static, Type } from "@sinclair/typebox";
|
|
6
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
7
6
|
import ghIssueViewDescription from "../prompts/tools/gh-issue-view.md" with { type: "text" };
|
|
8
7
|
import ghPrCheckoutDescription from "../prompts/tools/gh-pr-checkout.md" with { type: "text" };
|
|
9
8
|
import ghPrDiffDescription from "../prompts/tools/gh-pr-diff.md" with { type: "text" };
|
|
@@ -1902,7 +1901,7 @@ function buildTextResult(
|
|
|
1902
1901
|
export class GhRepoViewTool implements AgentTool<typeof ghRepoViewSchema, GhToolDetails> {
|
|
1903
1902
|
readonly name = "gh_repo_view";
|
|
1904
1903
|
readonly label = "GitHub Repo";
|
|
1905
|
-
readonly description =
|
|
1904
|
+
readonly description = prompt.render(ghRepoViewDescription);
|
|
1906
1905
|
readonly parameters = ghRepoViewSchema;
|
|
1907
1906
|
readonly strict = true;
|
|
1908
1907
|
|
|
@@ -1943,7 +1942,7 @@ export class GhRepoViewTool implements AgentTool<typeof ghRepoViewSchema, GhTool
|
|
|
1943
1942
|
export class GhIssueViewTool implements AgentTool<typeof ghIssueViewSchema, GhToolDetails> {
|
|
1944
1943
|
readonly name = "gh_issue_view";
|
|
1945
1944
|
readonly label = "GitHub Issue";
|
|
1946
|
-
readonly description =
|
|
1945
|
+
readonly description = prompt.render(ghIssueViewDescription);
|
|
1947
1946
|
readonly parameters = ghIssueViewSchema;
|
|
1948
1947
|
readonly strict = true;
|
|
1949
1948
|
|
|
@@ -1980,7 +1979,7 @@ export class GhIssueViewTool implements AgentTool<typeof ghIssueViewSchema, GhTo
|
|
|
1980
1979
|
export class GhPrViewTool implements AgentTool<typeof ghPrViewSchema, GhToolDetails> {
|
|
1981
1980
|
readonly name = "gh_pr_view";
|
|
1982
1981
|
readonly label = "GitHub PR";
|
|
1983
|
-
readonly description =
|
|
1982
|
+
readonly description = prompt.render(ghPrViewDescription);
|
|
1984
1983
|
readonly parameters = ghPrViewSchema;
|
|
1985
1984
|
readonly strict = true;
|
|
1986
1985
|
|
|
@@ -2024,7 +2023,7 @@ export class GhPrViewTool implements AgentTool<typeof ghPrViewSchema, GhToolDeta
|
|
|
2024
2023
|
export class GhPrDiffTool implements AgentTool<typeof ghPrDiffSchema, GhToolDetails> {
|
|
2025
2024
|
readonly name = "gh_pr_diff";
|
|
2026
2025
|
readonly label = "GitHub PR Diff";
|
|
2027
|
-
readonly description =
|
|
2026
|
+
readonly description = prompt.render(ghPrDiffDescription);
|
|
2028
2027
|
readonly parameters = ghPrDiffSchema;
|
|
2029
2028
|
readonly strict = true;
|
|
2030
2029
|
|
|
@@ -2073,7 +2072,7 @@ export class GhPrDiffTool implements AgentTool<typeof ghPrDiffSchema, GhToolDeta
|
|
|
2073
2072
|
export class GhPrCheckoutTool implements AgentTool<typeof ghPrCheckoutSchema, GhToolDetails> {
|
|
2074
2073
|
readonly name = "gh_pr_checkout";
|
|
2075
2074
|
readonly label = "GitHub PR Checkout";
|
|
2076
|
-
readonly description =
|
|
2075
|
+
readonly description = prompt.render(ghPrCheckoutDescription);
|
|
2077
2076
|
readonly parameters = ghPrCheckoutSchema;
|
|
2078
2077
|
readonly strict = true;
|
|
2079
2078
|
|
|
@@ -2204,7 +2203,7 @@ export class GhPrCheckoutTool implements AgentTool<typeof ghPrCheckoutSchema, Gh
|
|
|
2204
2203
|
export class GhPrPushTool implements AgentTool<typeof ghPrPushSchema, GhToolDetails> {
|
|
2205
2204
|
readonly name = "gh_pr_push";
|
|
2206
2205
|
readonly label = "GitHub PR Push";
|
|
2207
|
-
readonly description =
|
|
2206
|
+
readonly description = prompt.render(ghPrPushDescription);
|
|
2208
2207
|
readonly parameters = ghPrPushSchema;
|
|
2209
2208
|
readonly strict = true;
|
|
2210
2209
|
|
|
@@ -2265,7 +2264,7 @@ export class GhPrPushTool implements AgentTool<typeof ghPrPushSchema, GhToolDeta
|
|
|
2265
2264
|
export class GhSearchIssuesTool implements AgentTool<typeof ghSearchIssuesSchema, GhToolDetails> {
|
|
2266
2265
|
readonly name = "gh_search_issues";
|
|
2267
2266
|
readonly label = "GitHub Issue Search";
|
|
2268
|
-
readonly description =
|
|
2267
|
+
readonly description = prompt.render(ghSearchIssuesDescription);
|
|
2269
2268
|
readonly parameters = ghSearchIssuesSchema;
|
|
2270
2269
|
readonly strict = true;
|
|
2271
2270
|
|
|
@@ -2300,7 +2299,7 @@ export class GhSearchIssuesTool implements AgentTool<typeof ghSearchIssuesSchema
|
|
|
2300
2299
|
export class GhSearchPrsTool implements AgentTool<typeof ghSearchPrsSchema, GhToolDetails> {
|
|
2301
2300
|
readonly name = "gh_search_prs";
|
|
2302
2301
|
readonly label = "GitHub PR Search";
|
|
2303
|
-
readonly description =
|
|
2302
|
+
readonly description = prompt.render(ghSearchPrsDescription);
|
|
2304
2303
|
readonly parameters = ghSearchPrsSchema;
|
|
2305
2304
|
readonly strict = true;
|
|
2306
2305
|
|
|
@@ -2335,7 +2334,7 @@ export class GhSearchPrsTool implements AgentTool<typeof ghSearchPrsSchema, GhTo
|
|
|
2335
2334
|
export class GhRunWatchTool implements AgentTool<typeof ghRunWatchSchema, GhToolDetails> {
|
|
2336
2335
|
readonly name = "gh_run_watch";
|
|
2337
2336
|
readonly label = "GitHub Run Watch";
|
|
2338
|
-
readonly description =
|
|
2337
|
+
readonly description = prompt.render(ghRunWatchDescription);
|
|
2339
2338
|
readonly parameters = ghRunWatchSchema;
|
|
2340
2339
|
readonly strict = true;
|
|
2341
2340
|
|
package/src/tools/grep.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
|
|
4
|
-
import { type GrepMatch, type GrepResult, grep } from "@oh-my-pi/pi-natives";
|
|
4
|
+
import { type GrepMatch, GrepOutputMode, type GrepResult, grep } 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
|
-
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import { type Static, Type } from "@sinclair/typebox";
|
|
9
|
-
import {
|
|
9
|
+
import { computeLineHash } from "../edit/line-hash";
|
|
10
|
+
import { formatChunkedGrepLine } from "../edit/modes/chunk";
|
|
10
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
|
-
import type
|
|
12
|
-
import { computeLineHash } from "../patch/hashline";
|
|
12
|
+
import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
|
|
13
13
|
import grepDescription from "../prompts/tools/grep.md" with { type: "text" };
|
|
14
14
|
import { DEFAULT_MAX_COLUMN, type TruncationResult, truncateHead } from "../session/streaming-output";
|
|
15
15
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
16
|
+
import { resolveEditMode } from "../utils/edit-mode";
|
|
16
17
|
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
17
18
|
import type { ToolSession } from ".";
|
|
18
19
|
import { formatFullOutputReference, type OutputMeta } from "./output-meta";
|
|
@@ -72,9 +73,10 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
72
73
|
|
|
73
74
|
constructor(private readonly session: ToolSession) {
|
|
74
75
|
const displayMode = resolveFileDisplayMode(session);
|
|
75
|
-
this.description =
|
|
76
|
+
this.description = prompt.render(grepDescription, {
|
|
76
77
|
IS_HASHLINE_MODE: displayMode.hashLines,
|
|
77
78
|
IS_LINE_NUMBER_MODE: !displayMode.hashLines && displayMode.lineNumbers,
|
|
79
|
+
IS_CHUNK_MODE: displayMode.chunked,
|
|
78
80
|
});
|
|
79
81
|
}
|
|
80
82
|
|
|
@@ -89,6 +91,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
89
91
|
|
|
90
92
|
return untilAborted(signal, async () => {
|
|
91
93
|
const normalizedPattern = pattern.trim();
|
|
94
|
+
const chunkMode = resolveEditMode(this.session) === "chunk";
|
|
92
95
|
if (!normalizedPattern) {
|
|
93
96
|
throw new ToolError("Pattern must not be empty");
|
|
94
97
|
}
|
|
@@ -162,7 +165,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
162
165
|
throw new ToolError(`Path not found: ${scopePath}`);
|
|
163
166
|
}
|
|
164
167
|
|
|
165
|
-
const effectiveOutputMode =
|
|
168
|
+
const effectiveOutputMode = GrepOutputMode.Content;
|
|
166
169
|
const effectiveLimit = normalizedLimit ?? DEFAULT_MATCH_LIMIT;
|
|
167
170
|
const internalLimit = Math.min(effectiveLimit * 5, 2000);
|
|
168
171
|
|
|
@@ -270,6 +273,50 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
270
273
|
}
|
|
271
274
|
matchesByFile.get(relativePath)!.push(match);
|
|
272
275
|
}
|
|
276
|
+
if (chunkMode) {
|
|
277
|
+
const annotatedLines = await Promise.all(
|
|
278
|
+
selectedMatches.map(match => {
|
|
279
|
+
const relativePath = match.path.startsWith("/") ? match.path.slice(1) : match.path;
|
|
280
|
+
const absoluteFilePath = isDirectory ? path.join(searchPath, relativePath) : searchPath;
|
|
281
|
+
const displayPath = formatPath(match.path);
|
|
282
|
+
fileMatchCounts.set(displayPath, (fileMatchCounts.get(displayPath) ?? 0) + 1);
|
|
283
|
+
return formatChunkedGrepLine({
|
|
284
|
+
filePath: absoluteFilePath,
|
|
285
|
+
lineNumber: match.lineNumber,
|
|
286
|
+
line: match.line,
|
|
287
|
+
cwd: this.session.cwd,
|
|
288
|
+
language: getLanguageFromPath(absoluteFilePath),
|
|
289
|
+
});
|
|
290
|
+
}),
|
|
291
|
+
);
|
|
292
|
+
const rawOutput = annotatedLines.join("\n");
|
|
293
|
+
const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
294
|
+
const truncated = Boolean(matchLimitReached || result.limitReached || truncation.truncated);
|
|
295
|
+
const details: GrepToolDetails = {
|
|
296
|
+
scopePath,
|
|
297
|
+
matchCount: selectedMatches.length,
|
|
298
|
+
fileCount: fileList.length,
|
|
299
|
+
files: fileList,
|
|
300
|
+
fileMatches: fileList.map(path => ({
|
|
301
|
+
path,
|
|
302
|
+
count: fileMatchCounts.get(path) ?? 0,
|
|
303
|
+
})),
|
|
304
|
+
truncated,
|
|
305
|
+
matchLimitReached: matchLimitReached ? effectiveLimit : undefined,
|
|
306
|
+
resultLimitReached: result.limitReached ? internalLimit : undefined,
|
|
307
|
+
};
|
|
308
|
+
if (truncation.truncated) details.truncation = truncation;
|
|
309
|
+
const resultBuilder = toolResult(details)
|
|
310
|
+
.text(truncation.content)
|
|
311
|
+
.limits({
|
|
312
|
+
matchLimit: matchLimitReached ? effectiveLimit : undefined,
|
|
313
|
+
resultLimit: result.limitReached ? internalLimit : undefined,
|
|
314
|
+
});
|
|
315
|
+
if (truncation.truncated) {
|
|
316
|
+
resultBuilder.truncation(truncation, { direction: "head" });
|
|
317
|
+
}
|
|
318
|
+
return resultBuilder.done();
|
|
319
|
+
}
|
|
273
320
|
const renderMatchesForFile = (relativePath: string) => {
|
|
274
321
|
const fileMatches = matchesByFile.get(relativePath) ?? [];
|
|
275
322
|
for (const match of fileMatches) {
|
|
@@ -286,12 +333,13 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
286
333
|
}
|
|
287
334
|
const lineWidth = Math.max(...lineNumbers.map(value => value.toString().length));
|
|
288
335
|
const formatLine = (lineNumber: number, line: string, isMatch: boolean): string => {
|
|
336
|
+
const separator = isMatch ? ":" : "-";
|
|
289
337
|
if (useHashLines) {
|
|
290
338
|
const ref = `${lineNumber}#${computeLineHash(lineNumber, line)}`;
|
|
291
|
-
return
|
|
339
|
+
return `${ref}${separator}${line}`;
|
|
292
340
|
}
|
|
293
341
|
const padded = lineNumber.toString().padStart(lineWidth, " ");
|
|
294
|
-
return
|
|
342
|
+
return `${padded}${separator}${line}`;
|
|
295
343
|
};
|
|
296
344
|
if (match.contextBefore) {
|
|
297
345
|
for (const ctx of match.contextBefore) {
|
package/src/tools/index.ts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { ToolChoice } from "@oh-my-pi/pi-ai";
|
|
2
3
|
import type { SearchDb } from "@oh-my-pi/pi-natives";
|
|
3
4
|
import { $env, logger } from "@oh-my-pi/pi-utils";
|
|
4
5
|
import type { AsyncJobManager } from "../async";
|
|
5
6
|
import type { PromptTemplate } from "../config/prompt-templates";
|
|
6
7
|
import type { Settings } from "../config/settings";
|
|
8
|
+
import { EditTool } from "../edit";
|
|
7
9
|
import type { Skill } from "../extensibility/skills";
|
|
8
10
|
import type { InternalUrlRouter } from "../internal-urls";
|
|
9
11
|
import { getPreludeDocs, warmPythonEnvironment } from "../ipy/executor";
|
|
10
12
|
import { checkPythonKernelAvailability } from "../ipy/kernel";
|
|
11
13
|
import { LspTool } from "../lsp";
|
|
12
14
|
import type { DiscoverableMCPSearchIndex, DiscoverableMCPTool } from "../mcp/discoverable-tool-metadata";
|
|
13
|
-
import { EditTool } from "../patch";
|
|
14
15
|
import type { PlanModeState } from "../plan-mode/state";
|
|
16
|
+
import type { CustomMessage } from "../session/messages";
|
|
17
|
+
import type { ToolChoiceQueue } from "../session/tool-choice-queue";
|
|
15
18
|
import { TaskTool } from "../task";
|
|
16
19
|
import type { AgentOutputManager } from "../task/output-manager";
|
|
17
20
|
import type { EventBus } from "../utils/event-bus";
|
|
@@ -22,9 +25,11 @@ import { AstGrepTool } from "./ast-grep";
|
|
|
22
25
|
import { AwaitTool } from "./await-tool";
|
|
23
26
|
import { BashTool } from "./bash";
|
|
24
27
|
import { BrowserTool } from "./browser";
|
|
28
|
+
|
|
25
29
|
import { CalculatorTool } from "./calculator";
|
|
26
30
|
import { CancelJobTool } from "./cancel-job";
|
|
27
31
|
import { type CheckpointState, CheckpointTool, RewindTool } from "./checkpoint";
|
|
32
|
+
import { DebugTool } from "./debug";
|
|
28
33
|
import { ExitPlanModeTool } from "./exit-plan-mode";
|
|
29
34
|
import { FindTool } from "./find";
|
|
30
35
|
import {
|
|
@@ -45,6 +50,7 @@ import { wrapToolWithMetaNotice } from "./output-meta";
|
|
|
45
50
|
import { PythonTool } from "./python";
|
|
46
51
|
import { ReadTool } from "./read";
|
|
47
52
|
import { RenderMermaidTool } from "./render-mermaid";
|
|
53
|
+
import { createReportToolIssueTool, isAutoQaEnabled } from "./report-tool-issue";
|
|
48
54
|
import { ResolveTool } from "./resolve";
|
|
49
55
|
import { reportFindingTool } from "./review";
|
|
50
56
|
import { SearchToolBm25Tool } from "./search-tool-bm25";
|
|
@@ -55,10 +61,10 @@ import { WriteTool } from "./write";
|
|
|
55
61
|
|
|
56
62
|
// Exa MCP tools (22 tools)
|
|
57
63
|
|
|
64
|
+
export * from "../edit";
|
|
58
65
|
export * from "../exa";
|
|
59
66
|
export type * from "../exa/types";
|
|
60
67
|
export * from "../lsp";
|
|
61
|
-
export * from "../patch";
|
|
62
68
|
export * from "../session/streaming-output";
|
|
63
69
|
export * from "../task";
|
|
64
70
|
export * from "../web/search";
|
|
@@ -71,6 +77,7 @@ export * from "./browser";
|
|
|
71
77
|
export * from "./calculator";
|
|
72
78
|
export * from "./cancel-job";
|
|
73
79
|
export * from "./checkpoint";
|
|
80
|
+
export * from "./debug";
|
|
74
81
|
export * from "./exit-plan-mode";
|
|
75
82
|
export * from "./find";
|
|
76
83
|
export * from "./gemini-image";
|
|
@@ -78,10 +85,10 @@ export * from "./gh";
|
|
|
78
85
|
export * from "./grep";
|
|
79
86
|
export * from "./inspect-image";
|
|
80
87
|
export * from "./notebook";
|
|
81
|
-
export * from "./pending-action";
|
|
82
88
|
export * from "./python";
|
|
83
89
|
export * from "./read";
|
|
84
90
|
export * from "./render-mermaid";
|
|
91
|
+
export * from "./report-tool-issue";
|
|
85
92
|
export * from "./resolve";
|
|
86
93
|
export * from "./review";
|
|
87
94
|
export * from "./search-tool-bm25";
|
|
@@ -175,12 +182,21 @@ export interface ToolSession {
|
|
|
175
182
|
getSelectedMCPToolNames?: () => string[];
|
|
176
183
|
/** Merge MCP tool selections into the active session tool set. */
|
|
177
184
|
activateDiscoveredMCPTools?: (toolNames: string[]) => Promise<string[]>;
|
|
178
|
-
/**
|
|
179
|
-
|
|
185
|
+
/** The tool-choice queue used to force forthcoming tool invocations and carry invocation handlers. */
|
|
186
|
+
getToolChoiceQueue?(): ToolChoiceQueue;
|
|
187
|
+
/** Build a model-provider-specific ToolChoice that targets the named tool, or undefined if unsupported. */
|
|
188
|
+
buildToolChoice?(toolName: string): ToolChoice | undefined;
|
|
189
|
+
/** Steer a hidden custom message into the conversation (e.g. a preview reminder). */
|
|
190
|
+
steer?(message: { customType: string; content: string; details?: unknown }): void;
|
|
191
|
+
/** Peek the currently in-flight tool-choice queue directive's invocation handler. Used by the `resolve` tool to dispatch to the pending action. */
|
|
192
|
+
peekQueueInvoker?(): ((input: unknown) => Promise<unknown> | unknown) | undefined;
|
|
180
193
|
/** Get active checkpoint state if any. */
|
|
181
194
|
getCheckpointState?: () => CheckpointState | undefined;
|
|
182
195
|
/** Set or clear active checkpoint state. */
|
|
183
196
|
setCheckpointState?: (state: CheckpointState | null) => void;
|
|
197
|
+
|
|
198
|
+
/** Queue a hidden message to be injected at the next agent turn. */
|
|
199
|
+
queueDeferredMessage?(message: CustomMessage): void;
|
|
184
200
|
}
|
|
185
201
|
|
|
186
202
|
type ToolFactory = (session: ToolSession) => Tool | null | Promise<Tool | null>;
|
|
@@ -191,6 +207,7 @@ export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
|
|
|
191
207
|
render_mermaid: s => new RenderMermaidTool(s),
|
|
192
208
|
ask: AskTool.createIf,
|
|
193
209
|
bash: s => new BashTool(s),
|
|
210
|
+
debug: DebugTool.createIf,
|
|
194
211
|
python: s => new PythonTool(s),
|
|
195
212
|
calc: s => new CalculatorTool(s),
|
|
196
213
|
ssh: loadSshTool,
|
|
@@ -225,6 +242,7 @@ export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
|
|
|
225
242
|
export const HIDDEN_TOOLS: Record<string, ToolFactory> = {
|
|
226
243
|
submit_result: s => new SubmitResultTool(s),
|
|
227
244
|
report_finding: () => reportFindingTool,
|
|
245
|
+
report_tool_issue: s => createReportToolIssueTool(s),
|
|
228
246
|
exit_plan_mode: s => new ExitPlanModeTool(s),
|
|
229
247
|
resolve: s => new ResolveTool(s),
|
|
230
248
|
};
|
|
@@ -282,11 +300,7 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
282
300
|
const isTestEnv = Bun.env.BUN_ENV === "test" || Bun.env.NODE_ENV === "test";
|
|
283
301
|
const skipPythonWarm = isTestEnv || $env.PI_PYTHON_SKIP_CHECK === "1";
|
|
284
302
|
if (shouldCheckPython) {
|
|
285
|
-
const availability = await logger.
|
|
286
|
-
"createTools:pythonCheck",
|
|
287
|
-
checkPythonKernelAvailability,
|
|
288
|
-
session.cwd,
|
|
289
|
-
);
|
|
303
|
+
const availability = await logger.time("createTools:pythonCheck", checkPythonKernelAvailability, session.cwd);
|
|
290
304
|
pythonAvailable = availability.ok;
|
|
291
305
|
if (!availability.ok) {
|
|
292
306
|
logger.warn("Python kernel unavailable, falling back to bash", {
|
|
@@ -296,12 +310,13 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
296
310
|
const sessionFile = session.getSessionFile?.() ?? undefined;
|
|
297
311
|
const warmSessionId = sessionFile ? `session:${sessionFile}:cwd:${session.cwd}` : `cwd:${session.cwd}`;
|
|
298
312
|
try {
|
|
299
|
-
await logger.
|
|
313
|
+
await logger.time(
|
|
300
314
|
"createTools:warmPython",
|
|
301
315
|
warmPythonEnvironment,
|
|
302
316
|
session.cwd,
|
|
303
317
|
warmSessionId,
|
|
304
318
|
session.settings.get("python.sharedGateway"),
|
|
319
|
+
sessionFile,
|
|
305
320
|
);
|
|
306
321
|
} catch (err) {
|
|
307
322
|
logger.warn("Failed to warm Python environment", {
|
|
@@ -343,9 +358,10 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
343
358
|
}
|
|
344
359
|
const allTools: Record<string, ToolFactory> = { ...BUILTIN_TOOLS, ...HIDDEN_TOOLS };
|
|
345
360
|
const isToolAllowed = (name: string) => {
|
|
346
|
-
if (name === "lsp") return enableLsp;
|
|
361
|
+
if (name === "lsp") return enableLsp && session.settings.get("lsp.enabled");
|
|
347
362
|
if (name === "bash") return allowBash;
|
|
348
363
|
if (name === "python") return allowPython;
|
|
364
|
+
if (name === "debug") return session.settings.get("debug.enabled");
|
|
349
365
|
if (name === "todo_write") return !includeSubmitResult && session.settings.get("todo.enabled");
|
|
350
366
|
if (name === "find") return session.settings.get("find.enabled");
|
|
351
367
|
if (name === "grep") return session.settings.get("grep.enabled");
|
|
@@ -357,7 +373,6 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
357
373
|
if (name === "inspect_image") return session.settings.get("inspect_image.enabled");
|
|
358
374
|
if (name === "web_search") return session.settings.get("web_search.enabled");
|
|
359
375
|
if (name === "search_tool_bm25") return session.settings.get("mcp.discoveryMode");
|
|
360
|
-
if (name === "lsp") return session.settings.get("lsp.enabled");
|
|
361
376
|
if (name === "calc") return session.settings.get("calc.enabled");
|
|
362
377
|
if (name === "browser") return session.settings.get("browser.enabled");
|
|
363
378
|
if (name === "checkpoint" || name === "rewind") return session.settings.get("checkpoint.enabled");
|
|
@@ -384,21 +399,28 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
384
399
|
|
|
385
400
|
const baseResults = await Promise.all(
|
|
386
401
|
baseEntries.map(async ([name, factory]) => {
|
|
387
|
-
const tool = await logger.
|
|
402
|
+
const tool = await logger.time(`createTools:${name}`, factory, session);
|
|
388
403
|
return tool ? wrapToolWithMetaNotice(tool) : null;
|
|
389
404
|
}),
|
|
390
405
|
);
|
|
391
406
|
const tools = baseResults.filter((r): r is Tool => r !== null);
|
|
392
407
|
const hasDeferrableTools = tools.some(tool => tool.deferrable === true);
|
|
393
|
-
if (!
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
408
|
+
if (hasDeferrableTools && !tools.some(tool => tool.name === "resolve")) {
|
|
409
|
+
const resolveTool = await logger.time("createTools:resolve", HIDDEN_TOOLS.resolve, session);
|
|
410
|
+
if (resolveTool) {
|
|
411
|
+
tools.push(wrapToolWithMetaNotice(resolveTool));
|
|
412
|
+
}
|
|
398
413
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
414
|
+
|
|
415
|
+
// Auto-inject report_tool_issue when autoqa is enabled (env or setting).
|
|
416
|
+
// Injected unconditionally into every agent, regardless of requested tool list.
|
|
417
|
+
const autoQA = isAutoQaEnabled(session.settings);
|
|
418
|
+
if (autoQA && !tools.some(t => t.name === "report_tool_issue")) {
|
|
419
|
+
const qaTool = await HIDDEN_TOOLS.report_tool_issue(session);
|
|
420
|
+
if (qaTool) {
|
|
421
|
+
tools.push(wrapToolWithMetaNotice(qaTool));
|
|
422
|
+
}
|
|
402
423
|
}
|
|
424
|
+
|
|
403
425
|
return tools;
|
|
404
426
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import { type Api, type AssistantMessage, completeSimple, type Model } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import { prompt } from "@oh-my-pi/pi-utils";
|
|
3
4
|
import { type Static, Type } from "@sinclair/typebox";
|
|
4
5
|
import { expandRoleAlias, resolveModelFromString } from "../config/model-resolver";
|
|
5
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
6
6
|
import inspectImageDescription from "../prompts/tools/inspect-image.md" with { type: "text" };
|
|
7
7
|
import inspectImageSystemPromptTemplate from "../prompts/tools/inspect-image-system.md" with { type: "text" };
|
|
8
8
|
import {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
type LoadedImageInput,
|
|
11
11
|
loadImageInput,
|
|
12
12
|
MAX_IMAGE_INPUT_BYTES,
|
|
13
|
-
} from "../utils/image-
|
|
13
|
+
} from "../utils/image-loading";
|
|
14
14
|
import type { ToolSession } from "./index";
|
|
15
15
|
import { ToolError } from "./tool-errors";
|
|
16
16
|
|
|
@@ -49,7 +49,7 @@ export class InspectImageTool implements AgentTool<typeof inspectImageSchema, In
|
|
|
49
49
|
private readonly session: ToolSession,
|
|
50
50
|
private readonly completeImageRequest: typeof completeSimple = completeSimple,
|
|
51
51
|
) {
|
|
52
|
-
this.description =
|
|
52
|
+
this.description = prompt.render(inspectImageDescription);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
async execute(
|
|
@@ -127,7 +127,7 @@ export class InspectImageTool implements AgentTool<typeof inspectImageSchema, In
|
|
|
127
127
|
const response = await this.completeImageRequest(
|
|
128
128
|
model,
|
|
129
129
|
{
|
|
130
|
-
systemPrompt:
|
|
130
|
+
systemPrompt: prompt.render(inspectImageSystemPromptTemplate),
|
|
131
131
|
messages: [
|
|
132
132
|
{
|
|
133
133
|
role: "user",
|