@oh-my-pi/pi-coding-agent 8.1.0 → 8.2.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.
- package/CHANGELOG.md +21 -1
- package/docs/session.md +111 -46
- package/examples/custom-tools/hello/index.ts +1 -1
- package/examples/custom-tools/todo/index.ts +3 -4
- package/examples/extensions/api-demo.ts +0 -1
- package/examples/extensions/chalk-logger.ts +2 -3
- package/examples/extensions/hello.ts +0 -1
- package/examples/extensions/pirate.ts +0 -1
- package/examples/extensions/plan-mode.ts +15 -16
- package/examples/extensions/todo.ts +3 -4
- package/examples/extensions/tools.ts +1 -2
- package/examples/extensions/with-deps/index.ts +0 -1
- package/examples/hooks/auto-commit-on-exit.ts +1 -2
- package/examples/hooks/confirm-destructive.ts +0 -1
- package/examples/hooks/custom-compaction.ts +1 -2
- package/examples/hooks/dirty-repo-guard.ts +0 -1
- package/examples/hooks/file-trigger.ts +3 -4
- package/examples/hooks/git-checkpoint.ts +0 -1
- package/examples/hooks/handoff.ts +3 -4
- package/examples/hooks/permission-gate.ts +1 -2
- package/examples/hooks/protected-paths.ts +1 -2
- package/examples/hooks/qna.ts +2 -3
- package/examples/hooks/snake.ts +4 -5
- package/examples/hooks/status-line.ts +0 -1
- package/examples/sdk/01-minimal.ts +2 -3
- package/examples/sdk/02-custom-model.ts +2 -3
- package/examples/sdk/03-custom-prompt.ts +3 -4
- package/examples/sdk/04-skills.ts +2 -3
- package/examples/sdk/06-extensions.ts +1 -2
- package/examples/sdk/06-hooks.ts +6 -7
- package/examples/sdk/07-context-files.ts +0 -1
- package/examples/sdk/08-prompt-templates.ts +0 -1
- package/examples/sdk/08-slash-commands.ts +0 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +0 -1
- package/examples/sdk/10-settings.ts +0 -1
- package/examples/sdk/11-sessions.ts +0 -1
- package/package.json +51 -23
- package/scripts/format-prompts.ts +0 -1
- package/src/capability/context-file.ts +2 -3
- package/src/capability/extension-module.ts +2 -3
- package/src/capability/extension.ts +2 -3
- package/src/capability/fs.ts +20 -21
- package/src/capability/hook.ts +2 -3
- package/src/capability/index.ts +15 -16
- package/src/capability/instruction.ts +2 -3
- package/src/capability/mcp.ts +2 -3
- package/src/capability/prompt.ts +2 -3
- package/src/capability/rule.ts +2 -3
- package/src/capability/settings.ts +1 -2
- package/src/capability/skill.ts +2 -3
- package/src/capability/slash-command.ts +2 -3
- package/src/capability/ssh.ts +2 -3
- package/src/capability/system-prompt.ts +2 -3
- package/src/capability/tool.ts +2 -3
- package/src/cli/args.ts +5 -6
- package/src/cli/config-cli.ts +6 -7
- package/src/cli/file-processor.ts +19 -17
- package/src/cli/jupyter-cli.ts +105 -0
- package/src/cli/list-models.ts +10 -11
- package/src/cli/plugin-cli.ts +20 -21
- package/src/cli/session-picker.ts +2 -3
- package/src/cli/setup-cli.ts +2 -3
- package/src/cli/stats-cli.ts +2 -3
- package/src/cli/update-cli.ts +25 -22
- package/src/commit/agentic/agent.ts +21 -23
- package/src/commit/agentic/fallback.ts +9 -9
- package/src/commit/agentic/index.ts +30 -38
- package/src/commit/agentic/state.ts +1 -6
- package/src/commit/agentic/tools/analyze-file.ts +15 -15
- package/src/commit/agentic/tools/git-file-diff.ts +3 -3
- package/src/commit/agentic/tools/git-hunk.ts +7 -7
- package/src/commit/agentic/tools/git-overview.ts +5 -5
- package/src/commit/agentic/tools/index.ts +14 -14
- package/src/commit/agentic/tools/propose-changelog.ts +6 -6
- package/src/commit/agentic/tools/propose-commit.ts +8 -8
- package/src/commit/agentic/tools/recent-commits.ts +2 -2
- package/src/commit/agentic/tools/split-commit.ts +19 -23
- package/src/commit/agentic/topo-sort.ts +1 -1
- package/src/commit/agentic/trivial.ts +3 -3
- package/src/commit/agentic/validation.ts +12 -12
- package/src/commit/analysis/conventional.ts +7 -11
- package/src/commit/analysis/index.ts +4 -4
- package/src/commit/analysis/scope.ts +4 -4
- package/src/commit/analysis/summary.ts +7 -9
- package/src/commit/analysis/validation.ts +1 -1
- package/src/commit/changelog/detect.ts +6 -6
- package/src/commit/changelog/generate.ts +7 -9
- package/src/commit/changelog/index.ts +13 -13
- package/src/commit/changelog/parse.ts +2 -2
- package/src/commit/cli.ts +1 -1
- package/src/commit/git/diff.ts +3 -3
- package/src/commit/git/index.ts +19 -24
- package/src/commit/index.ts +1 -1
- package/src/commit/map-reduce/index.ts +9 -9
- package/src/commit/map-reduce/map-phase.ts +19 -34
- package/src/commit/map-reduce/reduce-phase.ts +9 -11
- package/src/commit/message.ts +2 -2
- package/src/commit/model-selection.ts +3 -7
- package/src/commit/pipeline.ts +20 -22
- package/src/commit/utils/exclusions.ts +3 -3
- package/src/config/file-lock.ts +17 -7
- package/src/config/keybindings.ts +6 -8
- package/src/config/model-registry.ts +55 -37
- package/src/config/model-resolver.ts +18 -19
- package/src/config/prompt-templates.ts +11 -11
- package/src/config/settings-manager.ts +50 -34
- package/src/config.ts +60 -62
- package/src/cursor.ts +11 -9
- package/src/discovery/agents-md.ts +11 -12
- package/src/discovery/builtin.ts +68 -73
- package/src/discovery/claude.ts +41 -42
- package/src/discovery/cline.ts +11 -12
- package/src/discovery/codex.ts +52 -53
- package/src/discovery/cursor.ts +9 -10
- package/src/discovery/gemini.ts +17 -22
- package/src/discovery/github.ts +13 -14
- package/src/discovery/helpers.ts +35 -34
- package/src/discovery/index.ts +16 -18
- package/src/discovery/mcp-json.ts +8 -9
- package/src/discovery/ssh.ts +8 -9
- package/src/discovery/vscode.ts +4 -5
- package/src/discovery/windsurf.ts +6 -7
- package/src/exa/company.ts +1 -2
- package/src/exa/index.ts +2 -3
- package/src/exa/linkedin.ts +1 -2
- package/src/exa/mcp-client.ts +14 -16
- package/src/exa/render.ts +10 -11
- package/src/exa/researcher.ts +1 -2
- package/src/exa/search.ts +1 -2
- package/src/exa/types.ts +0 -1
- package/src/exa/websets.ts +1 -2
- package/src/exec/bash-executor.ts +3 -4
- package/src/exec/exec.ts +0 -1
- package/src/export/custom-share.ts +5 -6
- package/src/export/html/index.ts +24 -21
- package/src/export/ttsr.ts +2 -3
- package/src/extensibility/custom-commands/bundled/review/index.ts +7 -8
- package/src/extensibility/custom-commands/loader.ts +17 -14
- package/src/extensibility/custom-commands/types.ts +1 -2
- package/src/extensibility/custom-tools/loader.ts +10 -11
- package/src/extensibility/custom-tools/types.ts +6 -7
- package/src/extensibility/custom-tools/wrapper.ts +2 -3
- package/src/extensibility/extensions/loader.ts +75 -53
- package/src/extensibility/extensions/runner.ts +11 -12
- package/src/extensibility/extensions/types.ts +19 -26
- package/src/extensibility/extensions/wrapper.ts +3 -4
- package/src/extensibility/hooks/index.ts +1 -1
- package/src/extensibility/hooks/loader.ts +8 -9
- package/src/extensibility/hooks/runner.ts +7 -8
- package/src/extensibility/hooks/tool-wrapper.ts +0 -1
- package/src/extensibility/hooks/types.ts +10 -17
- package/src/extensibility/plugins/doctor.ts +3 -3
- package/src/extensibility/plugins/installer.ts +27 -27
- package/src/extensibility/plugins/loader.ts +59 -56
- package/src/extensibility/plugins/manager.ts +211 -171
- package/src/extensibility/plugins/parser.ts +1 -1
- package/src/extensibility/plugins/paths.ts +8 -8
- package/src/extensibility/skills.ts +63 -60
- package/src/extensibility/slash-commands.ts +10 -10
- package/src/index.ts +46 -46
- package/src/internal-urls/agent-protocol.ts +21 -11
- package/src/internal-urls/artifact-protocol.ts +17 -13
- package/src/internal-urls/router.ts +1 -2
- package/src/internal-urls/rule-protocol.ts +3 -4
- package/src/internal-urls/skill-protocol.ts +3 -4
- package/src/ipy/executor.ts +14 -10
- package/src/ipy/gateway-coordinator.ts +79 -90
- package/src/ipy/kernel.ts +32 -30
- package/src/ipy/modules.ts +13 -13
- package/src/lsp/client.ts +21 -10
- package/src/lsp/clients/biome-client.ts +1 -2
- package/src/lsp/clients/index.ts +3 -3
- package/src/lsp/clients/lsp-linter-client.ts +4 -5
- package/src/lsp/config.ts +15 -15
- package/src/lsp/edits.ts +4 -5
- package/src/lsp/index.ts +43 -44
- package/src/lsp/lspmux.ts +8 -8
- package/src/lsp/render.ts +10 -16
- package/src/lsp/utils.ts +3 -3
- package/src/main.ts +55 -34
- package/src/mcp/client.ts +2 -3
- package/src/mcp/config.ts +5 -6
- package/src/mcp/json-rpc.ts +0 -1
- package/src/mcp/loader.ts +3 -4
- package/src/mcp/manager.ts +17 -18
- package/src/mcp/tool-bridge.ts +4 -9
- package/src/mcp/tool-cache.ts +2 -3
- package/src/mcp/transports/http.ts +2 -4
- package/src/mcp/transports/stdio.ts +1 -2
- package/src/migrations.ts +60 -49
- package/src/modes/components/armin.ts +4 -5
- package/src/modes/components/assistant-message.ts +6 -6
- package/src/modes/components/bash-execution.ts +7 -8
- package/src/modes/components/bordered-loader.ts +3 -3
- package/src/modes/components/branch-summary-message.ts +3 -3
- package/src/modes/components/compaction-summary-message.ts +3 -3
- package/src/modes/components/countdown-timer.ts +0 -1
- package/src/modes/components/custom-message.ts +5 -5
- package/src/modes/components/diff.ts +1 -1
- package/src/modes/components/dynamic-border.ts +2 -2
- package/src/modes/components/extensions/extension-dashboard.ts +6 -7
- package/src/modes/components/extensions/extension-list.ts +2 -3
- package/src/modes/components/extensions/inspector-panel.ts +3 -4
- package/src/modes/components/extensions/state-manager.ts +25 -26
- package/src/modes/components/extensions/types.ts +1 -2
- package/src/modes/components/footer.ts +47 -43
- package/src/modes/components/history-search.ts +2 -2
- package/src/modes/components/hook-editor.ts +3 -4
- package/src/modes/components/hook-input.ts +2 -3
- package/src/modes/components/hook-message.ts +5 -5
- package/src/modes/components/hook-selector.ts +2 -3
- package/src/modes/components/keybinding-hints.ts +2 -3
- package/src/modes/components/login-dialog.ts +2 -2
- package/src/modes/components/model-selector.ts +12 -12
- package/src/modes/components/oauth-selector.ts +2 -2
- package/src/modes/components/plugin-settings.ts +20 -20
- package/src/modes/components/python-execution.ts +7 -8
- package/src/modes/components/queue-mode-selector.ts +3 -3
- package/src/modes/components/read-tool-group.ts +2 -2
- package/src/modes/components/session-selector.ts +4 -4
- package/src/modes/components/settings-defs.ts +77 -69
- package/src/modes/components/settings-selector.ts +16 -16
- package/src/modes/components/show-images-selector.ts +2 -2
- package/src/modes/components/status-line/segments.ts +4 -4
- package/src/modes/components/status-line/separators.ts +1 -1
- package/src/modes/components/status-line/types.ts +2 -2
- package/src/modes/components/status-line-segment-editor.ts +7 -8
- package/src/modes/components/status-line.ts +12 -12
- package/src/modes/components/theme-selector.ts +8 -7
- package/src/modes/components/thinking-selector.ts +4 -4
- package/src/modes/components/todo-display.ts +2 -2
- package/src/modes/components/todo-reminder.ts +4 -4
- package/src/modes/components/tool-execution.ts +11 -16
- package/src/modes/components/tree-selector.ts +11 -11
- package/src/modes/components/ttsr-notification.ts +5 -5
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +1 -1
- package/src/modes/components/visual-truncate.ts +0 -1
- package/src/modes/components/welcome.ts +4 -4
- package/src/modes/controllers/command-controller.ts +46 -47
- package/src/modes/controllers/event-controller.ts +16 -20
- package/src/modes/controllers/extension-ui-controller.ts +40 -46
- package/src/modes/controllers/input-controller.ts +17 -18
- package/src/modes/controllers/selector-controller.ts +103 -91
- package/src/modes/index.ts +3 -3
- package/src/modes/interactive-mode.ts +27 -29
- package/src/modes/print-mode.ts +12 -13
- package/src/modes/rpc/rpc-client.ts +7 -8
- package/src/modes/rpc/rpc-mode.ts +24 -25
- package/src/modes/rpc/rpc-types.ts +3 -4
- package/src/modes/theme/mermaid-cache.ts +2 -2
- package/src/modes/theme/theme.ts +128 -53
- package/src/modes/types.ts +10 -10
- package/src/modes/utils/ui-helpers.ts +17 -17
- package/src/patch/applicator.ts +18 -19
- package/src/patch/diff.ts +1 -2
- package/src/patch/fuzzy.ts +1 -2
- package/src/patch/index.ts +10 -11
- package/src/patch/normalize.ts +4 -4
- package/src/patch/normative.ts +1 -2
- package/src/patch/parser.ts +8 -9
- package/src/patch/shared.ts +12 -13
- package/src/sdk.ts +60 -63
- package/src/session/agent-session.ts +83 -84
- package/src/session/agent-storage.ts +11 -11
- package/src/session/artifacts.ts +8 -9
- package/src/session/auth-storage.ts +25 -29
- package/src/session/compaction/branch-summarization.ts +7 -10
- package/src/session/compaction/compaction.ts +8 -19
- package/src/session/compaction/utils.ts +6 -9
- package/src/session/history-storage.ts +10 -10
- package/src/session/messages.ts +4 -5
- package/src/session/session-manager.ts +76 -65
- package/src/session/session-storage.ts +57 -69
- package/src/session/storage-migration.ts +2 -3
- package/src/session/streaming-output.ts +2 -2
- package/src/ssh/connection-manager.ts +43 -50
- package/src/ssh/ssh-executor.ts +2 -2
- package/src/ssh/sshfs-mount.ts +11 -18
- package/src/system-prompt.ts +27 -34
- package/src/task/agents.ts +45 -30
- package/src/task/commands.ts +6 -7
- package/src/task/discovery.ts +39 -76
- package/src/task/executor.ts +14 -15
- package/src/task/index.ts +33 -36
- package/src/task/output-manager.ts +3 -4
- package/src/task/parallel.ts +0 -1
- package/src/task/render.ts +19 -20
- package/src/task/subprocess-tool-registry.ts +1 -2
- package/src/task/worker-protocol.ts +3 -3
- package/src/task/worker.ts +32 -38
- package/src/task/worktree.ts +19 -19
- package/src/tools/ask.ts +8 -9
- package/src/tools/bash-interceptor.ts +1 -5
- package/src/tools/bash.ts +19 -18
- package/src/tools/calculator.ts +12 -12
- package/src/tools/complete.ts +3 -4
- package/src/tools/context.ts +2 -2
- package/src/tools/fetch.ts +23 -26
- package/src/tools/find.ts +15 -16
- package/src/tools/gemini-image.ts +14 -14
- package/src/tools/grep.ts +27 -27
- package/src/tools/index.ts +78 -56
- package/src/tools/list-limit.ts +1 -1
- package/src/tools/ls.ts +7 -7
- package/src/tools/notebook.ts +5 -5
- package/src/tools/output-meta.ts +3 -4
- package/src/tools/output-utils.ts +1 -1
- package/src/tools/path-utils.ts +5 -5
- package/src/tools/python.ts +36 -37
- package/src/tools/read.ts +23 -23
- package/src/tools/render-utils.ts +8 -9
- package/src/tools/renderers.ts +6 -7
- package/src/tools/review.ts +8 -11
- package/src/tools/ssh.ts +31 -30
- package/src/tools/todo-write.ts +13 -13
- package/src/tools/tool-errors.ts +3 -3
- package/src/tools/tool-result.ts +3 -8
- package/src/tools/write.ts +11 -16
- package/src/tui/code-cell.ts +3 -9
- package/src/tui/file-list.ts +3 -4
- package/src/tui/output-block.ts +1 -2
- package/src/tui/status-line.ts +2 -3
- package/src/tui/tree-list.ts +2 -3
- package/src/tui/types.ts +1 -2
- package/src/tui/utils.ts +2 -3
- package/src/utils/changelog.ts +9 -10
- package/src/utils/clipboard.ts +11 -11
- package/src/utils/file-mentions.ts +4 -10
- package/src/utils/frontmatter.ts +6 -3
- package/src/utils/fuzzy.ts +2 -2
- package/src/utils/image-convert.ts +1 -1
- package/src/utils/image-resize.ts +1 -1
- package/src/utils/mime.ts +2 -2
- package/src/utils/shell-snapshot.ts +11 -13
- package/src/utils/shell.ts +4 -5
- package/src/utils/title-generator.ts +8 -9
- package/src/utils/tools-manager.ts +23 -23
- package/src/vendor/photon/index.js +1099 -1059
- package/src/vendor/photon/photon_rs_bg.wasm +0 -0
- package/src/web/scrapers/artifacthub.ts +1 -1
- package/src/web/scrapers/arxiv.ts +2 -2
- package/src/web/scrapers/bluesky.ts +2 -2
- package/src/web/scrapers/cheatsh.ts +1 -1
- package/src/web/scrapers/chocolatey.ts +2 -2
- package/src/web/scrapers/choosealicense.ts +5 -5
- package/src/web/scrapers/cisa-kev.ts +1 -1
- package/src/web/scrapers/crossref.ts +2 -2
- package/src/web/scrapers/devto.ts +3 -3
- package/src/web/scrapers/discogs.ts +3 -4
- package/src/web/scrapers/discourse.ts +1 -1
- package/src/web/scrapers/dockerhub.ts +1 -1
- package/src/web/scrapers/fdroid.ts +2 -2
- package/src/web/scrapers/firefox-addons.ts +3 -3
- package/src/web/scrapers/flathub.ts +1 -1
- package/src/web/scrapers/github.ts +3 -3
- package/src/web/scrapers/gitlab.ts +4 -4
- package/src/web/scrapers/hackernews.ts +2 -2
- package/src/web/scrapers/huggingface.ts +1 -1
- package/src/web/scrapers/iacr.ts +2 -2
- package/src/web/scrapers/index.ts +0 -1
- package/src/web/scrapers/jetbrains-marketplace.ts +1 -1
- package/src/web/scrapers/lemmy.ts +2 -2
- package/src/web/scrapers/maven.ts +2 -2
- package/src/web/scrapers/mdn.ts +2 -4
- package/src/web/scrapers/metacpan.ts +2 -2
- package/src/web/scrapers/musicbrainz.ts +1 -2
- package/src/web/scrapers/npm.ts +1 -1
- package/src/web/scrapers/nuget.ts +2 -2
- package/src/web/scrapers/nvd.ts +3 -3
- package/src/web/scrapers/ollama.ts +7 -9
- package/src/web/scrapers/opencorporates.ts +2 -2
- package/src/web/scrapers/openlibrary.ts +6 -6
- package/src/web/scrapers/orcid.ts +0 -1
- package/src/web/scrapers/osv.ts +2 -2
- package/src/web/scrapers/packagist.ts +1 -1
- package/src/web/scrapers/pubmed.ts +1 -2
- package/src/web/scrapers/rawg.ts +2 -2
- package/src/web/scrapers/readthedocs.ts +1 -2
- package/src/web/scrapers/repology.ts +2 -2
- package/src/web/scrapers/rfc.ts +1 -1
- package/src/web/scrapers/searchcode.ts +2 -2
- package/src/web/scrapers/semantic-scholar.ts +1 -1
- package/src/web/scrapers/snapcraft.ts +2 -2
- package/src/web/scrapers/sourcegraph.ts +1 -1
- package/src/web/scrapers/spdx.ts +3 -3
- package/src/web/scrapers/spotify.ts +0 -1
- package/src/web/scrapers/twitter.ts +1 -1
- package/src/web/scrapers/types.ts +1 -2
- package/src/web/scrapers/utils.ts +5 -5
- package/src/web/scrapers/wikidata.ts +3 -3
- package/src/web/scrapers/youtube.ts +9 -14
- package/src/web/search/auth.ts +4 -9
- package/src/web/search/index.ts +11 -21
- package/src/web/search/providers/anthropic.ts +3 -9
- package/src/web/search/providers/exa.ts +6 -10
- package/src/web/search/providers/perplexity.ts +5 -5
- package/src/web/search/render.ts +16 -18
- package/scripts/generate-wasm-b64.ts +0 -24
- package/src/commit/map-reduce/.map-phase.ts.kate-swp +0 -0
- package/src/task/.executor.ts.kate-swp +0 -0
- package/src/vendor/photon/photon_rs_bg.wasm.b64.js +0 -1
package/src/tools/fetch.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import
|
|
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 { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
|
|
5
|
-
import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
6
|
-
import { type Theme, theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
7
|
-
import fetchDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/fetch.md" with { type: "text" };
|
|
8
|
-
import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
|
|
9
|
-
import { ToolAbortError } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
|
10
|
-
import { renderOutputBlock, renderStatusLine } from "@oh-my-pi/pi-coding-agent/tui";
|
|
11
|
-
import { ensureTool } from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
|
|
12
|
-
import { specialHandlers } from "@oh-my-pi/pi-coding-agent/web/scrapers";
|
|
13
|
-
import type { RenderResult } from "@oh-my-pi/pi-coding-agent/web/scrapers/types";
|
|
14
|
-
import { finalizeOutput, loadPage, MAX_OUTPUT_CHARS } from "@oh-my-pi/pi-coding-agent/web/scrapers/types";
|
|
15
|
-
import { convertWithMarkitdown, fetchBinary } from "@oh-my-pi/pi-coding-agent/web/scrapers/utils";
|
|
16
4
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
17
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
18
6
|
import { ptree } from "@oh-my-pi/pi-utils";
|
|
19
7
|
import { type Static, Type } from "@sinclair/typebox";
|
|
20
8
|
import { nanoid } from "nanoid";
|
|
21
9
|
import { parse as parseHtml } from "node-html-parser";
|
|
10
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
11
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
|
+
import { type Theme, theme } from "../modes/theme/theme";
|
|
13
|
+
import fetchDescription from "../prompts/tools/fetch.md" with { type: "text" };
|
|
14
|
+
import { renderOutputBlock, renderStatusLine } from "../tui";
|
|
15
|
+
import { ensureTool } from "../utils/tools-manager";
|
|
16
|
+
import { specialHandlers } from "../web/scrapers";
|
|
17
|
+
import type { RenderResult } from "../web/scrapers/types";
|
|
18
|
+
import { finalizeOutput, loadPage, MAX_OUTPUT_CHARS } from "../web/scrapers/types";
|
|
19
|
+
import { convertWithMarkitdown, fetchBinary } from "../web/scrapers/utils";
|
|
22
20
|
import type { ToolSession } from ".";
|
|
23
21
|
import { applyListLimit } from "./list-limit";
|
|
22
|
+
import type { OutputMeta } from "./output-meta";
|
|
24
23
|
import { formatExpandHint } from "./render-utils";
|
|
24
|
+
import { ToolAbortError } from "./tool-errors";
|
|
25
25
|
import { toolResult } from "./tool-result";
|
|
26
26
|
|
|
27
27
|
// =============================================================================
|
|
@@ -450,7 +450,6 @@ async function renderHtmlToText(
|
|
|
450
450
|
timeout: number,
|
|
451
451
|
scratchDir: string,
|
|
452
452
|
): Promise<{ content: string; ok: boolean; method: string }> {
|
|
453
|
-
await mkdir(scratchDir, { recursive: true });
|
|
454
453
|
const tmpFile = path.join(scratchDir, `omp-${nanoid()}.html`);
|
|
455
454
|
|
|
456
455
|
try {
|
|
@@ -479,7 +478,7 @@ async function renderHtmlToText(
|
|
|
479
478
|
return { content: "", ok: false, method: "none" };
|
|
480
479
|
} finally {
|
|
481
480
|
try {
|
|
482
|
-
await rm(tmpFile, { force: true });
|
|
481
|
+
await fs.rm(tmpFile, { force: true });
|
|
483
482
|
} catch {}
|
|
484
483
|
}
|
|
485
484
|
}
|
|
@@ -498,13 +497,13 @@ function isLowQualityOutput(content: string): boolean {
|
|
|
498
497
|
"please enable javascript",
|
|
499
498
|
"browser not supported",
|
|
500
499
|
];
|
|
501
|
-
if (content.length < 1024 && jsGated.some(
|
|
500
|
+
if (content.length < 1024 && jsGated.some(t => lower.includes(t))) {
|
|
502
501
|
return true;
|
|
503
502
|
}
|
|
504
503
|
|
|
505
504
|
// Mostly navigation (high link/menu density)
|
|
506
|
-
const lines = content.split("\n").filter(
|
|
507
|
-
const shortLines = lines.filter(
|
|
505
|
+
const lines = content.split("\n").filter(l => l.trim());
|
|
506
|
+
const shortLines = lines.filter(l => l.trim().length < 40);
|
|
508
507
|
if (lines.length > 10 && shortLines.length / lines.length > 0.7) {
|
|
509
508
|
return true;
|
|
510
509
|
}
|
|
@@ -695,7 +694,7 @@ async function renderUrl(
|
|
|
695
694
|
if (isHtml && !raw) {
|
|
696
695
|
// 5A: Check for page-specific markdown alternate
|
|
697
696
|
const alternates = parseAlternateLinks(rawContent, finalUrl);
|
|
698
|
-
const markdownAlt = alternates.find(
|
|
697
|
+
const markdownAlt = alternates.find(alt => alt.endsWith(".md") || alt.includes("markdown"));
|
|
699
698
|
if (markdownAlt) {
|
|
700
699
|
const resolved = markdownAlt.startsWith("http") ? markdownAlt : new URL(markdownAlt, finalUrl).href;
|
|
701
700
|
const altResult = await loadPage(resolved, { timeout, signal });
|
|
@@ -767,7 +766,7 @@ async function renderUrl(
|
|
|
767
766
|
}
|
|
768
767
|
|
|
769
768
|
// 5E: Check for feed alternates
|
|
770
|
-
const feedAlternates = alternates.filter(
|
|
769
|
+
const feedAlternates = alternates.filter(alt => !alt.endsWith(".md") && !alt.includes("markdown"));
|
|
771
770
|
for (const altUrl of feedAlternates.slice(0, 2)) {
|
|
772
771
|
const resolved = altUrl.startsWith("http") ? altUrl : new URL(altUrl, finalUrl).href;
|
|
773
772
|
const altResult = await loadPage(resolved, { timeout, signal });
|
|
@@ -984,7 +983,7 @@ function getDomain(url: string): string {
|
|
|
984
983
|
|
|
985
984
|
/** Count non-empty lines */
|
|
986
985
|
function countNonEmptyLines(text: string): number {
|
|
987
|
-
return text.split("\n").filter(
|
|
986
|
+
return text.split("\n").filter(l => l.trim()).length;
|
|
988
987
|
}
|
|
989
988
|
|
|
990
989
|
/** Render fetch call (URL preview) */
|
|
@@ -1037,7 +1036,7 @@ export function renderFetchResult(
|
|
|
1037
1036
|
: contentText;
|
|
1038
1037
|
const lineCount = countNonEmptyLines(contentBody);
|
|
1039
1038
|
const charCount = contentBody.trim().length;
|
|
1040
|
-
const contentLines = contentBody.split("\n").filter(
|
|
1039
|
+
const contentLines = contentBody.split("\n").filter(l => l.trim());
|
|
1041
1040
|
|
|
1042
1041
|
const metadataLines: string[] = [
|
|
1043
1042
|
`${uiTheme.fg("muted", "Content-Type:")} ${details.contentType || "unknown"}`,
|
|
@@ -1061,12 +1060,10 @@ export function renderFetchResult(
|
|
|
1061
1060
|
|
|
1062
1061
|
const previewLimit = expanded ? 12 : 3;
|
|
1063
1062
|
const previewList = applyListLimit(contentLines, { headLimit: previewLimit });
|
|
1064
|
-
const previewLines = previewList.items.map(
|
|
1063
|
+
const previewLines = previewList.items.map(line => truncate(line.trimEnd(), 120, uiTheme.format.ellipsis));
|
|
1065
1064
|
const remaining = Math.max(0, contentLines.length - previewLines.length);
|
|
1066
1065
|
const contentPreviewLines =
|
|
1067
|
-
previewLines.length > 0
|
|
1068
|
-
? previewLines.map((line) => uiTheme.fg("dim", line))
|
|
1069
|
-
: [uiTheme.fg("dim", "(no content)")];
|
|
1066
|
+
previewLines.length > 0 ? previewLines.map(line => uiTheme.fg("dim", line)) : [uiTheme.fg("dim", "(no content)")];
|
|
1070
1067
|
if (remaining > 0) {
|
|
1071
1068
|
const hint = formatExpandHint(uiTheme, expanded, true);
|
|
1072
1069
|
contentPreviewLines.push(
|
package/src/tools/find.ts
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
4
|
-
import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
|
|
5
|
-
import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
6
|
-
import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
7
|
-
import findDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/find.md" with { type: "text" };
|
|
8
|
-
import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
|
|
9
|
-
import { ToolAbortError, ToolError, throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
|
10
|
-
import { renderFileList, renderStatusLine, renderTreeList } from "@oh-my-pi/pi-coding-agent/tui";
|
|
11
|
-
import { ensureTool } from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
|
|
12
4
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
13
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
14
6
|
import { ptree, untilAborted } from "@oh-my-pi/pi-utils";
|
|
15
7
|
import type { Static } from "@sinclair/typebox";
|
|
16
8
|
import { Type } from "@sinclair/typebox";
|
|
17
|
-
|
|
9
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
10
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
|
+
import type { Theme } from "../modes/theme/theme";
|
|
12
|
+
import findDescription from "../prompts/tools/find.md" with { type: "text" };
|
|
13
|
+
import { renderFileList, renderStatusLine, renderTreeList } from "../tui";
|
|
14
|
+
import { ensureTool } from "../utils/tools-manager";
|
|
18
15
|
import type { ToolSession } from ".";
|
|
19
16
|
import { applyListLimit } from "./list-limit";
|
|
17
|
+
import type { OutputMeta } from "./output-meta";
|
|
20
18
|
import { resolveToCwd } from "./path-utils";
|
|
21
19
|
import { formatCount, formatEmptyMessage, formatErrorMessage, PREVIEW_LIMITS } from "./render-utils";
|
|
20
|
+
import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
|
|
22
21
|
import { toolResult } from "./tool-result";
|
|
23
22
|
import { type TruncationResult, truncateHead } from "./truncate";
|
|
24
23
|
|
|
@@ -164,7 +163,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
164
163
|
}
|
|
165
164
|
|
|
166
165
|
// Relativize paths
|
|
167
|
-
const relativized = results.map(
|
|
166
|
+
const relativized = results.map(p => {
|
|
168
167
|
if (p.startsWith(searchPath)) {
|
|
169
168
|
return p.slice(searchPath.length + 1);
|
|
170
169
|
}
|
|
@@ -331,7 +330,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
331
330
|
const indexed = relativized.map((path, idx) => ({ path, mtime: mtimes[idx] }));
|
|
332
331
|
indexed.sort((a, b) => b.mtime - a.mtime);
|
|
333
332
|
relativized.length = 0;
|
|
334
|
-
relativized.push(...indexed.map(
|
|
333
|
+
relativized.push(...indexed.map(item => item.path));
|
|
335
334
|
}
|
|
336
335
|
|
|
337
336
|
const listLimit = applyListLimit(relativized, { limit: effectiveLimit });
|
|
@@ -405,12 +404,12 @@ export const findToolRenderer = {
|
|
|
405
404
|
const details = result.details;
|
|
406
405
|
|
|
407
406
|
if (result.isError || details?.error) {
|
|
408
|
-
const errorText = details?.error || result.content?.find(
|
|
407
|
+
const errorText = details?.error || result.content?.find(c => c.type === "text")?.text || "Unknown error";
|
|
409
408
|
return new Text(formatErrorMessage(errorText, uiTheme), 0, 0);
|
|
410
409
|
}
|
|
411
410
|
|
|
412
411
|
const hasDetailedData = details?.fileCount !== undefined;
|
|
413
|
-
const textContent = result.content?.find(
|
|
412
|
+
const textContent = result.content?.find(c => c.type === "text")?.text;
|
|
414
413
|
|
|
415
414
|
if (!hasDetailedData) {
|
|
416
415
|
if (
|
|
@@ -422,7 +421,7 @@ export const findToolRenderer = {
|
|
|
422
421
|
return new Text(formatEmptyMessage("No files found", uiTheme), 0, 0);
|
|
423
422
|
}
|
|
424
423
|
|
|
425
|
-
const lines = textContent.split("\n").filter(
|
|
424
|
+
const lines = textContent.split("\n").filter(l => l.trim());
|
|
426
425
|
const header = renderStatusLine(
|
|
427
426
|
{
|
|
428
427
|
icon: "success",
|
|
@@ -438,7 +437,7 @@ export const findToolRenderer = {
|
|
|
438
437
|
expanded,
|
|
439
438
|
maxCollapsed: COLLAPSED_LIST_LIMIT,
|
|
440
439
|
itemType: "file",
|
|
441
|
-
renderItem:
|
|
440
|
+
renderItem: line => uiTheme.fg("accent", line),
|
|
442
441
|
},
|
|
443
442
|
uiTheme,
|
|
444
443
|
);
|
|
@@ -468,7 +467,7 @@ export const findToolRenderer = {
|
|
|
468
467
|
|
|
469
468
|
const fileLines = renderFileList(
|
|
470
469
|
{
|
|
471
|
-
files: files.map(
|
|
470
|
+
files: files.map(entry => ({ path: entry, isDirectory: entry.endsWith("/") })),
|
|
472
471
|
expanded,
|
|
473
472
|
maxCollapsed: COLLAPSED_LIST_LIMIT,
|
|
474
473
|
},
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import * as path from "node:path";
|
|
3
3
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
4
|
-
import type { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
|
|
5
|
-
import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
|
|
6
|
-
import type { CustomTool } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
7
|
-
import geminiImageDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/gemini-image.md" with { type: "text" };
|
|
8
|
-
import { detectSupportedImageMimeTypeFromFile } from "@oh-my-pi/pi-coding-agent/utils/mime";
|
|
9
|
-
import { getEnv } from "@oh-my-pi/pi-coding-agent/web/search/auth";
|
|
10
4
|
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
11
5
|
import { type Static, Type } from "@sinclair/typebox";
|
|
12
6
|
import { nanoid } from "nanoid";
|
|
7
|
+
import type { ModelRegistry } from "../config/model-registry";
|
|
8
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
9
|
+
import type { CustomTool } from "../extensibility/custom-tools/types";
|
|
10
|
+
import geminiImageDescription from "../prompts/tools/gemini-image.md" with { type: "text" };
|
|
11
|
+
import { detectSupportedImageMimeTypeFromFile } from "../utils/mime";
|
|
12
|
+
import { getEnv } from "../web/search/auth";
|
|
13
13
|
import { resolveReadPath } from "./path-utils";
|
|
14
14
|
|
|
15
15
|
const DEFAULT_MODEL = "gemini-3-pro-image-preview";
|
|
@@ -151,7 +151,7 @@ function assemblePrompt(params: GeminiImageParams): string {
|
|
|
151
151
|
if (params.style) parts.push(params.style);
|
|
152
152
|
|
|
153
153
|
// Join with periods for sentence structure
|
|
154
|
-
let prompt = `${parts.map(
|
|
154
|
+
let prompt = `${parts.map(p => p.replace(/[.!,;:]+$/, "")).join(". ")}.`;
|
|
155
155
|
|
|
156
156
|
// Text rendering specs
|
|
157
157
|
if (params.text) {
|
|
@@ -160,7 +160,7 @@ function assemblePrompt(params: GeminiImageParams): string {
|
|
|
160
160
|
|
|
161
161
|
// Edit mode: changes and preserve directives
|
|
162
162
|
if (params.changes?.length) {
|
|
163
|
-
prompt += `\n\nChanges:\n${params.changes.map(
|
|
163
|
+
prompt += `\n\nChanges:\n${params.changes.map(c => `- ${c}`).join("\n")}`;
|
|
164
164
|
if (params.preserve) {
|
|
165
165
|
prompt += `\n\nPreserve: ${params.preserve}`;
|
|
166
166
|
}
|
|
@@ -330,8 +330,8 @@ function collectOpenRouterResponseText(message: OpenRouterMessage | undefined):
|
|
|
330
330
|
}
|
|
331
331
|
if (Array.isArray(message.content)) {
|
|
332
332
|
const texts = message.content
|
|
333
|
-
.filter(
|
|
334
|
-
.map(
|
|
333
|
+
.filter(part => part.type === "text")
|
|
334
|
+
.map(part => part.text)
|
|
335
335
|
.filter((text): text is string => Boolean(text));
|
|
336
336
|
const combined = texts.join("\n").trim();
|
|
337
337
|
return combined.length > 0 ? combined : undefined;
|
|
@@ -489,7 +489,7 @@ function getExtensionForMime(mimeType: string): string {
|
|
|
489
489
|
async function saveImageToTemp(image: InlineImageData): Promise<string> {
|
|
490
490
|
const ext = getExtensionForMime(image.mimeType);
|
|
491
491
|
const filename = `omp-image-${nanoid()}.${ext}`;
|
|
492
|
-
const filepath = join(tmpdir(), filename);
|
|
492
|
+
const filepath = path.join(os.tmpdir(), filename);
|
|
493
493
|
await Bun.write(filepath, Buffer.from(image.data, "base64"));
|
|
494
494
|
return filepath;
|
|
495
495
|
}
|
|
@@ -515,7 +515,7 @@ function buildResponseSummary(
|
|
|
515
515
|
}
|
|
516
516
|
|
|
517
517
|
function collectResponseText(parts: GeminiPart[]): string | undefined {
|
|
518
|
-
const texts = parts.map(
|
|
518
|
+
const texts = parts.map(part => part.text).filter((text): text is string => Boolean(text));
|
|
519
519
|
const combined = texts.join("\n").trim();
|
|
520
520
|
return combined.length > 0 ? combined : undefined;
|
|
521
521
|
}
|
package/src/tools/grep.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import nodePath from "node:path";
|
|
2
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
4
|
-
import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
|
|
5
|
-
import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
6
|
-
import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
7
|
-
import grepDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/grep.md" with { type: "text" };
|
|
8
|
-
import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
|
|
9
|
-
import { ToolAbortError, ToolError } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
|
10
|
-
import { renderFileList, renderStatusLine, renderTreeList } from "@oh-my-pi/pi-coding-agent/tui";
|
|
11
|
-
import { ensureTool } from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
|
|
12
|
-
import { untilAborted } from "@oh-my-pi/pi-coding-agent/utils/utils";
|
|
13
4
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
14
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
15
6
|
import { ptree, readLines } from "@oh-my-pi/pi-utils";
|
|
16
7
|
import { Type } from "@sinclair/typebox";
|
|
17
8
|
import { $ } from "bun";
|
|
9
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
10
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
|
+
import type { Theme } from "../modes/theme/theme";
|
|
12
|
+
import grepDescription from "../prompts/tools/grep.md" with { type: "text" };
|
|
13
|
+
import { renderFileList, renderStatusLine, renderTreeList } from "../tui";
|
|
14
|
+
import { ensureTool } from "../utils/tools-manager";
|
|
15
|
+
import { untilAborted } from "../utils/utils";
|
|
18
16
|
import type { ToolSession } from ".";
|
|
19
17
|
import { applyListLimit } from "./list-limit";
|
|
18
|
+
import type { OutputMeta } from "./output-meta";
|
|
20
19
|
import { resolveToCwd } from "./path-utils";
|
|
21
20
|
import { formatCount, formatEmptyMessage, formatErrorMessage, PREVIEW_LIMITS } from "./render-utils";
|
|
21
|
+
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
22
22
|
import { toolResult } from "./tool-result";
|
|
23
23
|
import { DEFAULT_MAX_COLUMN, type TruncationResult, truncateHead, truncateLine } from "./truncate";
|
|
24
24
|
|
|
@@ -73,8 +73,8 @@ export interface GrepOperations {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
const defaultGrepOperations: GrepOperations = {
|
|
76
|
-
isDirectory: async
|
|
77
|
-
readFile:
|
|
76
|
+
isDirectory: async p => (await Bun.file(p).stat()).isDirectory(),
|
|
77
|
+
readFile: p => Bun.file(p).text(),
|
|
78
78
|
};
|
|
79
79
|
|
|
80
80
|
export interface GrepToolOptions {
|
|
@@ -287,7 +287,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
287
287
|
|
|
288
288
|
// For simple output modes (files_with_matches, count), process text directly
|
|
289
289
|
if (effectiveOutputMode === "files_with_matches" || effectiveOutputMode === "count") {
|
|
290
|
-
const stdout = await child.text().catch(
|
|
290
|
+
const stdout = await child.text().catch(x => {
|
|
291
291
|
if (x instanceof ptree.Exception && x.exitCode === 1) {
|
|
292
292
|
return "";
|
|
293
293
|
}
|
|
@@ -303,7 +303,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
303
303
|
const lines = stdout
|
|
304
304
|
.trim()
|
|
305
305
|
.split("\n")
|
|
306
|
-
.filter(
|
|
306
|
+
.filter(line => line.length > 0);
|
|
307
307
|
|
|
308
308
|
if (lines.length === 0) {
|
|
309
309
|
const details: GrepToolDetails = {
|
|
@@ -371,7 +371,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
371
371
|
|
|
372
372
|
// For count mode, format as "path:count"
|
|
373
373
|
if (effectiveOutputMode === "count") {
|
|
374
|
-
const formatted = processedLines.map(
|
|
374
|
+
const formatted = processedLines.map(line => {
|
|
375
375
|
const separatorIndex = line.lastIndexOf(":");
|
|
376
376
|
const relative = formatPath(separatorIndex === -1 ? line : line.slice(0, separatorIndex));
|
|
377
377
|
const count = separatorIndex === -1 ? "0" : line.slice(separatorIndex + 1);
|
|
@@ -383,7 +383,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
383
383
|
matchCount: simpleMatchCount,
|
|
384
384
|
fileCount,
|
|
385
385
|
files: simpleFileList,
|
|
386
|
-
fileMatches: simpleFileList.map(
|
|
386
|
+
fileMatches: simpleFileList.map(path => ({
|
|
387
387
|
path,
|
|
388
388
|
count: simpleFileMatchCounts.get(path) ?? 0,
|
|
389
389
|
})),
|
|
@@ -401,7 +401,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
// For files_with_matches, format paths
|
|
404
|
-
const formatted = processedLines.map(
|
|
404
|
+
const formatted = processedLines.map(line => formatPath(line));
|
|
405
405
|
const output = formatted.join("\n");
|
|
406
406
|
const details: GrepToolDetails = {
|
|
407
407
|
scopePath,
|
|
@@ -547,7 +547,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
547
547
|
matchCount,
|
|
548
548
|
fileCount: files.size,
|
|
549
549
|
files: fileList,
|
|
550
|
-
fileMatches: fileList.map(
|
|
550
|
+
fileMatches: fileList.map(path => ({
|
|
551
551
|
path,
|
|
552
552
|
count: fileMatchCounts.get(path) ?? 0,
|
|
553
553
|
})),
|
|
@@ -632,18 +632,18 @@ export const grepToolRenderer = {
|
|
|
632
632
|
const details = result.details;
|
|
633
633
|
|
|
634
634
|
if (result.isError || details?.error) {
|
|
635
|
-
const errorText = details?.error || result.content?.find(
|
|
635
|
+
const errorText = details?.error || result.content?.find(c => c.type === "text")?.text || "Unknown error";
|
|
636
636
|
return new Text(formatErrorMessage(errorText, uiTheme), 0, 0);
|
|
637
637
|
}
|
|
638
638
|
|
|
639
639
|
const hasDetailedData = details?.matchCount !== undefined || details?.fileCount !== undefined;
|
|
640
640
|
|
|
641
641
|
if (!hasDetailedData) {
|
|
642
|
-
const textContent = result.content?.find(
|
|
642
|
+
const textContent = result.content?.find(c => c.type === "text")?.text;
|
|
643
643
|
if (!textContent || textContent === "No matches found") {
|
|
644
644
|
return new Text(formatEmptyMessage("No matches found", uiTheme), 0, 0);
|
|
645
645
|
}
|
|
646
|
-
const lines = textContent.split("\n").filter(
|
|
646
|
+
const lines = textContent.split("\n").filter(line => line.trim() !== "");
|
|
647
647
|
const description = args?.pattern ?? undefined;
|
|
648
648
|
const header = renderStatusLine(
|
|
649
649
|
{ icon: "success", title: "Grep", description, meta: [formatCount("item", lines.length)] },
|
|
@@ -655,7 +655,7 @@ export const grepToolRenderer = {
|
|
|
655
655
|
expanded,
|
|
656
656
|
maxCollapsed: COLLAPSED_TEXT_LIMIT,
|
|
657
657
|
itemType: "item",
|
|
658
|
-
renderItem:
|
|
658
|
+
renderItem: line => uiTheme.fg("toolOutput", line),
|
|
659
659
|
},
|
|
660
660
|
uiTheme,
|
|
661
661
|
);
|
|
@@ -699,15 +699,15 @@ export const grepToolRenderer = {
|
|
|
699
699
|
);
|
|
700
700
|
|
|
701
701
|
if (mode === "content") {
|
|
702
|
-
const textContent = result.content?.find(
|
|
703
|
-
const contentLines = textContent.split("\n").filter(
|
|
702
|
+
const textContent = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
703
|
+
const contentLines = textContent.split("\n").filter(line => line.trim().length > 0);
|
|
704
704
|
const matchLines = renderTreeList(
|
|
705
705
|
{
|
|
706
706
|
items: contentLines,
|
|
707
707
|
expanded,
|
|
708
708
|
maxCollapsed: COLLAPSED_TEXT_LIMIT,
|
|
709
709
|
itemType: "match",
|
|
710
|
-
renderItem:
|
|
710
|
+
renderItem: line => uiTheme.fg("toolOutput", line),
|
|
711
711
|
},
|
|
712
712
|
uiTheme,
|
|
713
713
|
);
|
|
@@ -715,11 +715,11 @@ export const grepToolRenderer = {
|
|
|
715
715
|
}
|
|
716
716
|
|
|
717
717
|
const fileEntries: Array<{ path: string; count?: number }> = details?.fileMatches?.length
|
|
718
|
-
? details.fileMatches.map(
|
|
719
|
-
: files.map(
|
|
718
|
+
? details.fileMatches.map(entry => ({ path: entry.path, count: entry.count }))
|
|
719
|
+
: files.map(path => ({ path }));
|
|
720
720
|
const fileLines = renderFileList(
|
|
721
721
|
{
|
|
722
|
-
files: fileEntries.map(
|
|
722
|
+
files: fileEntries.map(entry => ({
|
|
723
723
|
path: entry.path,
|
|
724
724
|
isDirectory: entry.path.endsWith("/"),
|
|
725
725
|
meta: entry.count !== undefined ? `(${entry.count} match${entry.count !== 1 ? "es" : ""})` : undefined,
|
package/src/tools/index.ts
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
|
+
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { logger } from "@oh-my-pi/pi-utils";
|
|
3
|
+
import type { BashInterceptorRule } from "../config/settings-manager";
|
|
4
|
+
import type { InternalUrlRouter } from "../internal-urls";
|
|
5
|
+
import { getPreludeDocs, warmPythonEnvironment } from "../ipy/executor";
|
|
6
|
+
import { checkPythonKernelAvailability } from "../ipy/kernel";
|
|
7
|
+
import { LspTool } from "../lsp";
|
|
8
|
+
import { EditTool } from "../patch";
|
|
9
|
+
import type { ArtifactManager } from "../session/artifacts";
|
|
10
|
+
import { TaskTool } from "../task";
|
|
11
|
+
import type { AgentOutputManager } from "../task/output-manager";
|
|
12
|
+
import type { EventBus } from "../utils/event-bus";
|
|
13
|
+
import { time } from "../utils/timings";
|
|
14
|
+
import { WebSearchTool } from "../web/search";
|
|
15
|
+
import { AskTool } from "./ask";
|
|
16
|
+
import { BashTool } from "./bash";
|
|
17
|
+
import { CalculatorTool } from "./calculator";
|
|
18
|
+
import { CompleteTool } from "./complete";
|
|
19
|
+
import { FetchTool } from "./fetch";
|
|
20
|
+
import { FindTool } from "./find";
|
|
21
|
+
import { GrepTool } from "./grep";
|
|
22
|
+
import { LsTool } from "./ls";
|
|
23
|
+
import { NotebookTool } from "./notebook";
|
|
24
|
+
import { wrapToolsWithMetaNotice } from "./output-meta";
|
|
25
|
+
import { PythonTool } from "./python";
|
|
26
|
+
import { ReadTool } from "./read";
|
|
27
|
+
import { reportFindingTool } from "./review";
|
|
28
|
+
import { loadSshTool } from "./ssh";
|
|
29
|
+
import { TodoWriteTool } from "./todo-write";
|
|
30
|
+
import { WriteTool } from "./write";
|
|
31
|
+
|
|
1
32
|
// Exa MCP tools (22 tools)
|
|
2
|
-
|
|
3
|
-
export
|
|
33
|
+
|
|
34
|
+
export { exaTools } from "../exa";
|
|
35
|
+
export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult } from "../exa/types";
|
|
4
36
|
export {
|
|
5
37
|
type FileDiagnosticsResult,
|
|
6
38
|
type FileFormatResult,
|
|
@@ -11,9 +43,9 @@ export {
|
|
|
11
43
|
type LspWarmupOptions,
|
|
12
44
|
type LspWarmupResult,
|
|
13
45
|
warmupLspServers,
|
|
14
|
-
} from "
|
|
15
|
-
export { EditTool, type EditToolDetails } from "
|
|
16
|
-
export { BUNDLED_AGENTS, TaskTool } from "
|
|
46
|
+
} from "../lsp";
|
|
47
|
+
export { EditTool, type EditToolDetails } from "../patch";
|
|
48
|
+
export { BUNDLED_AGENTS, TaskTool } from "../task";
|
|
17
49
|
export {
|
|
18
50
|
companyWebSearchTools,
|
|
19
51
|
exaWebSearchTools,
|
|
@@ -31,7 +63,7 @@ export {
|
|
|
31
63
|
webSearchCustomTool,
|
|
32
64
|
webSearchDeepTool,
|
|
33
65
|
webSearchLinkedinTool,
|
|
34
|
-
} from "
|
|
66
|
+
} from "../web/search";
|
|
35
67
|
export { AskTool, type AskToolDetails } from "./ask";
|
|
36
68
|
export { BashTool, type BashToolDetails, type BashToolOptions } from "./bash";
|
|
37
69
|
export { CalculatorTool, type CalculatorToolDetails } from "./calculator";
|
|
@@ -59,36 +91,6 @@ export {
|
|
|
59
91
|
} from "./truncate";
|
|
60
92
|
export { WriteTool, type WriteToolDetails } from "./write";
|
|
61
93
|
|
|
62
|
-
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
63
|
-
import type { BashInterceptorRule } from "@oh-my-pi/pi-coding-agent/config/settings-manager";
|
|
64
|
-
import type { InternalUrlRouter } from "@oh-my-pi/pi-coding-agent/internal-urls";
|
|
65
|
-
import { getPreludeDocs, warmPythonEnvironment } from "@oh-my-pi/pi-coding-agent/ipy/executor";
|
|
66
|
-
import { checkPythonKernelAvailability } from "@oh-my-pi/pi-coding-agent/ipy/kernel";
|
|
67
|
-
import { LspTool } from "@oh-my-pi/pi-coding-agent/lsp";
|
|
68
|
-
import { EditTool } from "@oh-my-pi/pi-coding-agent/patch";
|
|
69
|
-
import type { ArtifactManager } from "@oh-my-pi/pi-coding-agent/session/artifacts";
|
|
70
|
-
import { TaskTool } from "@oh-my-pi/pi-coding-agent/task";
|
|
71
|
-
import type { AgentOutputManager } from "@oh-my-pi/pi-coding-agent/task/output-manager";
|
|
72
|
-
import type { EventBus } from "@oh-my-pi/pi-coding-agent/utils/event-bus";
|
|
73
|
-
import { WebSearchTool } from "@oh-my-pi/pi-coding-agent/web/search";
|
|
74
|
-
import { logger } from "@oh-my-pi/pi-utils";
|
|
75
|
-
import { AskTool } from "./ask";
|
|
76
|
-
import { BashTool } from "./bash";
|
|
77
|
-
import { CalculatorTool } from "./calculator";
|
|
78
|
-
import { CompleteTool } from "./complete";
|
|
79
|
-
import { FetchTool } from "./fetch";
|
|
80
|
-
import { FindTool } from "./find";
|
|
81
|
-
import { GrepTool } from "./grep";
|
|
82
|
-
import { LsTool } from "./ls";
|
|
83
|
-
import { NotebookTool } from "./notebook";
|
|
84
|
-
import { wrapToolsWithMetaNotice } from "./output-meta";
|
|
85
|
-
import { PythonTool } from "./python";
|
|
86
|
-
import { ReadTool } from "./read";
|
|
87
|
-
import { reportFindingTool } from "./review";
|
|
88
|
-
import { loadSshTool } from "./ssh";
|
|
89
|
-
import { TodoWriteTool } from "./todo-write";
|
|
90
|
-
import { WriteTool } from "./write";
|
|
91
|
-
|
|
92
94
|
/** Tool type (AgentTool from pi-ai) */
|
|
93
95
|
export type Tool = AgentTool<any, any, any>;
|
|
94
96
|
|
|
@@ -153,26 +155,26 @@ type ToolFactory = (session: ToolSession) => Tool | null | Promise<Tool | null>;
|
|
|
153
155
|
|
|
154
156
|
export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
|
|
155
157
|
ask: AskTool.createIf,
|
|
156
|
-
bash:
|
|
157
|
-
python:
|
|
158
|
-
calc:
|
|
158
|
+
bash: s => new BashTool(s),
|
|
159
|
+
python: s => new PythonTool(s),
|
|
160
|
+
calc: s => new CalculatorTool(s),
|
|
159
161
|
ssh: loadSshTool,
|
|
160
|
-
edit:
|
|
161
|
-
find:
|
|
162
|
-
grep:
|
|
163
|
-
ls:
|
|
162
|
+
edit: s => new EditTool(s),
|
|
163
|
+
find: s => new FindTool(s),
|
|
164
|
+
grep: s => new GrepTool(s),
|
|
165
|
+
ls: s => new LsTool(s),
|
|
164
166
|
lsp: LspTool.createIf,
|
|
165
|
-
notebook:
|
|
166
|
-
read:
|
|
167
|
+
notebook: s => new NotebookTool(s),
|
|
168
|
+
read: s => new ReadTool(s),
|
|
167
169
|
task: TaskTool.create,
|
|
168
|
-
todo_write:
|
|
169
|
-
fetch:
|
|
170
|
-
web_search:
|
|
171
|
-
write:
|
|
170
|
+
todo_write: s => new TodoWriteTool(s),
|
|
171
|
+
fetch: s => new FetchTool(s),
|
|
172
|
+
web_search: s => new WebSearchTool(s),
|
|
173
|
+
write: s => new WriteTool(s),
|
|
172
174
|
};
|
|
173
175
|
|
|
174
176
|
export const HIDDEN_TOOLS: Record<string, ToolFactory> = {
|
|
175
|
-
complete:
|
|
177
|
+
complete: s => new CompleteTool(s),
|
|
176
178
|
report_finding: () => reportFindingTool,
|
|
177
179
|
};
|
|
178
180
|
|
|
@@ -212,6 +214,7 @@ function getPythonModeFromEnv(): PythonToolMode | null {
|
|
|
212
214
|
* Create tools from BUILTIN_TOOLS registry.
|
|
213
215
|
*/
|
|
214
216
|
export async function createTools(session: ToolSession, toolNames?: string[]): Promise<Tool[]> {
|
|
217
|
+
time("createTools:start");
|
|
215
218
|
const includeComplete = session.requireCompleteTool === true;
|
|
216
219
|
const enableLsp = session.enableLsp ?? true;
|
|
217
220
|
const requestedTools = toolNames && toolNames.length > 0 ? [...new Set(toolNames)] : undefined;
|
|
@@ -221,18 +224,21 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
221
224
|
pythonMode !== "bash-only" &&
|
|
222
225
|
(requestedTools === undefined || requestedTools.includes("python") || pythonMode === "ipy-only");
|
|
223
226
|
const isTestEnv = process.env.BUN_ENV === "test" || process.env.NODE_ENV === "test";
|
|
227
|
+
const skipPythonWarm = isTestEnv || process.env.OMP_PYTHON_SKIP_CHECK === "1";
|
|
224
228
|
if (shouldCheckPython) {
|
|
225
229
|
const availability = await checkPythonKernelAvailability(session.cwd);
|
|
230
|
+
time("createTools:pythonCheck");
|
|
226
231
|
pythonAvailable = availability.ok;
|
|
227
232
|
if (!availability.ok) {
|
|
228
233
|
logger.warn("Python kernel unavailable, falling back to bash", {
|
|
229
234
|
reason: availability.reason,
|
|
230
235
|
});
|
|
231
|
-
} else if (!
|
|
236
|
+
} else if (!skipPythonWarm && getPreludeDocs().length === 0) {
|
|
232
237
|
const sessionFile = session.getSessionFile?.() ?? undefined;
|
|
233
238
|
const warmSessionId = sessionFile ? `session:${sessionFile}:cwd:${session.cwd}` : `cwd:${session.cwd}`;
|
|
234
239
|
try {
|
|
235
240
|
await warmPythonEnvironment(session.cwd, warmSessionId, session.settings?.getPythonSharedGateway?.());
|
|
241
|
+
time("createTools:warmPython");
|
|
236
242
|
} catch (err) {
|
|
237
243
|
logger.warn("Failed to warm Python environment", {
|
|
238
244
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -264,22 +270,38 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
|
|
|
264
270
|
requestedTools.push("complete");
|
|
265
271
|
}
|
|
266
272
|
|
|
267
|
-
const filteredRequestedTools = requestedTools?.filter(
|
|
273
|
+
const filteredRequestedTools = requestedTools?.filter(name => name in allTools && isToolAllowed(name));
|
|
268
274
|
|
|
269
275
|
const entries =
|
|
270
276
|
filteredRequestedTools !== undefined
|
|
271
|
-
? filteredRequestedTools.map(
|
|
277
|
+
? filteredRequestedTools.map(name => [name, allTools[name]] as const)
|
|
272
278
|
: [
|
|
273
279
|
...Object.entries(BUILTIN_TOOLS).filter(([name]) => isToolAllowed(name)),
|
|
274
280
|
...(includeComplete ? ([["complete", HIDDEN_TOOLS.complete]] as const) : []),
|
|
275
281
|
];
|
|
276
|
-
|
|
277
|
-
const
|
|
282
|
+
time("createTools:beforeFactories");
|
|
283
|
+
const slowTools: Array<{ name: string; ms: number }> = [];
|
|
284
|
+
const results = await Promise.all(
|
|
285
|
+
entries.map(async ([name, factory]) => {
|
|
286
|
+
const start = performance.now();
|
|
287
|
+
const tool = await factory(session);
|
|
288
|
+
const elapsed = performance.now() - start;
|
|
289
|
+
if (elapsed > 5) {
|
|
290
|
+
slowTools.push({ name, ms: Math.round(elapsed) });
|
|
291
|
+
}
|
|
292
|
+
return { name, tool };
|
|
293
|
+
}),
|
|
294
|
+
);
|
|
295
|
+
time("createTools:afterFactories");
|
|
296
|
+
if (slowTools.length > 0 && process.env.OMP_TIMING === "1") {
|
|
297
|
+
logger.debug("Tool factory timings", { slowTools });
|
|
298
|
+
}
|
|
299
|
+
const tools = results.filter(r => r.tool !== null).map(r => r.tool as Tool);
|
|
278
300
|
const wrappedTools = wrapToolsWithMetaNotice(tools);
|
|
279
301
|
|
|
280
302
|
if (filteredRequestedTools !== undefined) {
|
|
281
303
|
const allowed = new Set(filteredRequestedTools);
|
|
282
|
-
return wrappedTools.filter(
|
|
304
|
+
return wrappedTools.filter(tool => allowed.has(tool.name));
|
|
283
305
|
}
|
|
284
306
|
|
|
285
307
|
return wrappedTools;
|