@oh-my-pi/pi-coding-agent 13.18.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 +316 -1
- package/package.json +86 -24
- 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 +116 -30
- 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 +123 -178
- 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 -8
- package/src/commit/agentic/index.ts +22 -26
- package/src/commit/agentic/tools/analyze-file.ts +3 -3
- package/src/commit/agentic/tools/git-file-diff.ts +3 -6
- package/src/commit/agentic/tools/git-hunk.ts +3 -3
- package/src/commit/agentic/tools/git-overview.ts +6 -9
- package/src/commit/agentic/tools/index.ts +6 -8
- package/src/commit/agentic/tools/propose-commit.ts +4 -7
- package/src/commit/agentic/tools/recent-commits.ts +3 -3
- package/src/commit/agentic/tools/split-commit.ts +4 -4
- 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/changelog/index.ts +5 -9
- 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 +13 -16
- package/src/config/keybindings.ts +7 -6
- package/src/config/prompt-templates.ts +44 -226
- package/src/config/resolve-config-value.ts +4 -2
- package/src/config/settings-schema.ts +98 -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 +6 -18
- package/src/extensibility/custom-commands/bundled/review/index.ts +45 -43
- package/src/extensibility/custom-commands/loader.ts +1 -2
- package/src/extensibility/custom-tools/loader.ts +34 -11
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/loader.ts +9 -4
- package/src/extensibility/extensions/runner.ts +24 -1
- package/src/extensibility/extensions/types.ts +4 -2
- package/src/extensibility/hooks/loader.ts +5 -6
- package/src/extensibility/hooks/types.ts +2 -2
- package/src/extensibility/plugins/doctor.ts +2 -1
- package/src/extensibility/plugins/marketplace/fetcher.ts +2 -57
- package/src/extensibility/plugins/marketplace/source-resolver.ts +4 -4
- package/src/extensibility/slash-commands.ts +3 -7
- package/src/index.ts +3 -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 +125 -47
- 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/footer.ts +9 -29
- package/src/modes/components/hook-editor.ts +3 -3
- package/src/modes/components/hook-selector.ts +6 -1
- package/src/modes/components/read-tool-group.ts +6 -12
- package/src/modes/components/session-observer-overlay.ts +472 -0
- package/src/modes/components/settings-defs.ts +24 -0
- package/src/modes/components/status-line.ts +15 -61
- 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 +4 -2
- package/src/modes/controllers/event-controller.ts +59 -2
- package/src/modes/controllers/extension-ui-controller.ts +1 -0
- package/src/modes/controllers/input-controller.ts +15 -8
- package/src/modes/controllers/selector-controller.ts +26 -0
- package/src/modes/index.ts +20 -2
- package/src/modes/interactive-mode.ts +278 -69
- 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/session-observer-registry.ts +146 -0
- package/src/modes/shared.ts +0 -42
- package/src/modes/theme/theme.ts +80 -8
- package/src/modes/types.ts +4 -2
- package/src/modes/utils/keybinding-matchers.ts +9 -0
- package/src/prompts/system/custom-system-prompt.md +5 -0
- package/src/prompts/system/system-prompt.md +8 -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 +216 -165
- package/src/secrets/index.ts +1 -1
- package/src/secrets/obfuscator.ts +25 -17
- package/src/session/agent-session.ts +381 -286
- 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-manager.ts +15 -5
- 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 +25 -13
- package/src/task/agents.ts +5 -6
- package/src/task/commands.ts +2 -5
- package/src/task/executor.ts +32 -4
- package/src/task/index.ts +91 -82
- package/src/task/template.ts +2 -2
- package/src/task/types.ts +25 -0
- package/src/task/worktree.ts +131 -149
- 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 +3 -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 +130 -308
- 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 +211 -146
- 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/external-editor.ts +11 -5
- package/src/utils/file-display-mode.ts +6 -5
- package/src/utils/file-mentions.ts +8 -7
- package/src/utils/git.ts +1400 -0
- 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/web/search/render.ts +6 -4
- package/src/autoresearch/command-initialize.md +0 -34
- package/src/commit/git/errors.ts +0 -9
- package/src/commit/git/index.ts +0 -210
- package/src/commit/git/operations.ts +0 -54
- 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/gh-cli.ts +0 -125
- 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
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",
|
package/src/tools/output-meta.ts
CHANGED
|
@@ -337,7 +337,7 @@ export function formatTruncationMetaNotice(truncation: TruncationMeta): string {
|
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
if (truncation.nextOffset != null) {
|
|
340
|
-
notice += `. Use
|
|
340
|
+
notice += `. Use sel=L${truncation.nextOffset} to continue`;
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
if (truncation.artifactId != null) {
|
package/src/tools/python.ts
CHANGED
|
@@ -4,11 +4,10 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
4
4
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
5
5
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
6
6
|
import { Markdown, Text } from "@oh-my-pi/pi-tui";
|
|
7
|
-
import { getProjectDir } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import { getProjectDir, prompt } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import { type Static, Type } from "@sinclair/typebox";
|
|
9
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
10
9
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
|
-
import { executePython, getPreludeDocs, type PythonExecutorOptions } from "../ipy/executor";
|
|
10
|
+
import { executePython, getPreludeDocs, type PythonExecutorOptions, warmPythonEnvironment } from "../ipy/executor";
|
|
12
11
|
import type { PreludeHelper, PythonStatusEvent } from "../ipy/kernel";
|
|
13
12
|
import { truncateToVisualLines } from "../modes/components/visual-truncate";
|
|
14
13
|
import { getMarkdownTheme, type Theme } from "../modes/theme/theme";
|
|
@@ -136,7 +135,7 @@ function renderJsonTree(value: unknown, theme: Theme, expanded: boolean, maxDept
|
|
|
136
135
|
export function getPythonToolDescription(): string {
|
|
137
136
|
const helpers = getPreludeDocs();
|
|
138
137
|
const categories = groupPreludeHelpers(helpers);
|
|
139
|
-
return
|
|
138
|
+
return prompt.render(pythonDescription, { categories });
|
|
140
139
|
}
|
|
141
140
|
|
|
142
141
|
export interface PythonToolOptions {
|
|
@@ -146,7 +145,9 @@ export interface PythonToolOptions {
|
|
|
146
145
|
export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
147
146
|
readonly name = "python";
|
|
148
147
|
readonly label = "Python";
|
|
149
|
-
|
|
148
|
+
get description(): string {
|
|
149
|
+
return getPythonToolDescription();
|
|
150
|
+
}
|
|
150
151
|
readonly parameters = pythonSchema;
|
|
151
152
|
readonly concurrency = "exclusive";
|
|
152
153
|
readonly strict = true;
|
|
@@ -158,7 +159,6 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
158
159
|
options?: PythonToolOptions,
|
|
159
160
|
) {
|
|
160
161
|
this.#proxyExecutor = options?.proxyExecutor;
|
|
161
|
-
this.description = getPythonToolDescription();
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
async execute(
|
|
@@ -266,6 +266,19 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
266
266
|
},
|
|
267
267
|
});
|
|
268
268
|
const sessionId = sessionFile ? `session:${sessionFile}:cwd:${commandCwd}` : `cwd:${commandCwd}`;
|
|
269
|
+
|
|
270
|
+
if (getPreludeDocs().length === 0) {
|
|
271
|
+
const warmup = await warmPythonEnvironment(
|
|
272
|
+
commandCwd,
|
|
273
|
+
sessionId,
|
|
274
|
+
this.session.settings.get("python.sharedGateway"),
|
|
275
|
+
sessionFile ?? undefined,
|
|
276
|
+
);
|
|
277
|
+
if (!warmup.ok) {
|
|
278
|
+
throw new ToolError(warmup.reason ?? "Python prelude helpers unavailable");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
269
282
|
const baseExecutorOptions: Omit<PythonExecutorOptions, "reset"> = {
|
|
270
283
|
cwd: commandCwd,
|
|
271
284
|
deadlineMs,
|