@oh-my-pi/pi-coding-agent 12.18.1 → 12.19.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 +47 -0
- package/package.json +7 -7
- package/src/async/index.ts +1 -0
- package/src/async/job-manager.ts +341 -0
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/list-models.ts +3 -17
- package/src/cli/stats-cli.ts +3 -22
- package/src/cli/web-search-cli.ts +8 -16
- package/src/commit/agentic/agent.ts +6 -9
- package/src/commit/agentic/index.ts +44 -50
- package/src/commit/agentic/state.ts +0 -9
- package/src/commit/agentic/tools/propose-commit.ts +1 -30
- package/src/commit/agentic/tools/schemas.ts +31 -0
- package/src/commit/agentic/tools/split-commit.ts +1 -30
- package/src/commit/agentic/validation.ts +1 -18
- package/src/commit/analysis/conventional.ts +3 -50
- package/src/commit/analysis/summary.ts +2 -13
- package/src/commit/changelog/detect.ts +4 -1
- package/src/commit/changelog/generate.ts +2 -25
- package/src/commit/changelog/index.ts +1 -2
- package/src/commit/cli.ts +4 -12
- package/src/commit/map-reduce/reduce-phase.ts +2 -43
- package/src/commit/pipeline.ts +7 -15
- package/src/commit/utils.ts +44 -0
- package/src/config/prompt-templates.ts +1 -81
- package/src/config/settings-schema.ts +20 -1
- package/src/config.ts +2 -3
- package/src/debug/index.ts +1 -6
- package/src/debug/system-info.ts +2 -6
- package/src/discovery/builtin.ts +5 -9
- package/src/discovery/helpers.ts +0 -26
- package/src/discovery/ssh.ts +1 -8
- package/src/exa/company.ts +8 -39
- package/src/exa/factory.ts +64 -0
- package/src/exa/index.ts +0 -16
- package/src/exa/linkedin.ts +8 -39
- package/src/exa/mcp-client.ts +0 -64
- package/src/exa/researcher.ts +17 -59
- package/src/exa/search.ts +30 -154
- package/src/extensibility/custom-tools/loader.ts +3 -41
- package/src/extensibility/extensions/loader.ts +2 -9
- package/src/extensibility/hooks/loader.ts +3 -20
- package/src/extensibility/hooks/runner.ts +3 -19
- package/src/extensibility/plugins/installer.ts +2 -1
- package/src/extensibility/plugins/loader.ts +29 -117
- package/src/extensibility/skills.ts +2 -89
- package/src/extensibility/slash-commands.ts +1 -63
- package/src/extensibility/utils.ts +38 -0
- package/src/index.ts +9 -25
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/jobs-protocol.ts +118 -0
- package/src/ipy/kernel.ts +2 -0
- package/src/lsp/config.ts +1 -5
- package/src/lsp/lspmux.ts +0 -17
- package/src/lsp/utils.ts +2 -24
- package/src/main.ts +16 -24
- package/src/mcp/client.ts +1 -46
- package/src/mcp/render.ts +8 -1
- package/src/mcp/tool-cache.ts +1 -5
- package/src/mcp/transports/http.ts +2 -7
- package/src/mcp/transports/stdio.ts +2 -7
- package/src/modes/components/bash-execution.ts +2 -16
- package/src/modes/components/extensions/inspector-panel.ts +8 -18
- package/src/modes/components/footer.ts +10 -50
- package/src/modes/components/model-selector.ts +2 -21
- package/src/modes/components/python-execution.ts +2 -16
- package/src/modes/components/settings-selector.ts +1 -10
- package/src/modes/components/status-line/segments.ts +8 -25
- package/src/modes/components/status-line.ts +14 -31
- package/src/modes/components/tool-execution.ts +8 -2
- package/src/modes/controllers/command-controller.ts +71 -30
- package/src/modes/controllers/event-controller.ts +34 -4
- package/src/modes/controllers/mcp-command-controller.ts +3 -34
- package/src/modes/controllers/selector-controller.ts +2 -2
- package/src/modes/controllers/ssh-command-controller.ts +3 -34
- package/src/modes/interactive-mode.ts +6 -2
- package/src/modes/rpc/rpc-client.ts +1 -5
- package/src/modes/shared.ts +73 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +26 -2
- package/src/patch/index.ts +4 -4
- package/src/patch/normalize.ts +22 -65
- package/src/patch/shared.ts +16 -16
- package/src/prompts/system/custom-system-prompt.md +0 -10
- package/src/prompts/system/system-prompt.md +69 -89
- package/src/prompts/tools/async-result.md +5 -0
- package/src/prompts/tools/bash.md +5 -0
- package/src/prompts/tools/cancel-job.md +7 -0
- package/src/prompts/tools/poll-jobs.md +7 -0
- package/src/prompts/tools/task.md +4 -0
- package/src/sdk.ts +70 -6
- package/src/session/agent-session.ts +40 -6
- package/src/session/agent-storage.ts +69 -278
- package/src/session/auth-storage.ts +14 -1430
- package/src/session/session-manager.ts +69 -5
- package/src/session/session-storage.ts +1 -5
- package/src/session/streaming-output.ts +637 -76
- package/src/slash-commands/builtin-registry.ts +8 -0
- package/src/ssh/connection-manager.ts +4 -12
- package/src/ssh/sshfs-mount.ts +3 -7
- package/src/ssh/utils.ts +8 -0
- package/src/system-prompt.ts +24 -90
- package/src/task/executor.ts +11 -1
- package/src/task/index.ts +258 -13
- package/src/task/parallel.ts +32 -0
- package/src/task/render.ts +15 -7
- package/src/task/types.ts +5 -0
- package/src/tools/ask.ts +4 -7
- package/src/tools/bash-interactive.ts +4 -5
- package/src/tools/bash.ts +125 -41
- package/src/tools/cancel-job.ts +93 -0
- package/src/tools/fetch.ts +7 -27
- package/src/tools/find.ts +3 -3
- package/src/tools/gemini-image.ts +15 -14
- package/src/tools/grep.ts +3 -3
- package/src/tools/index.ts +13 -29
- package/src/tools/json-tree.ts +12 -1
- package/src/tools/jtd-to-json-schema.ts +10 -74
- package/src/tools/jtd-to-typescript.ts +10 -72
- package/src/tools/jtd-utils.ts +102 -0
- package/src/tools/notebook.ts +4 -9
- package/src/tools/output-meta.ts +52 -26
- package/src/tools/path-utils.ts +13 -7
- package/src/tools/poll-jobs.ts +178 -0
- package/src/tools/python.ts +32 -35
- package/src/tools/read.ts +61 -82
- package/src/tools/render-utils.ts +8 -159
- package/src/tools/ssh.ts +7 -20
- package/src/tools/submit-result.ts +1 -1
- package/src/tools/tool-errors.ts +0 -30
- package/src/tools/tool-result.ts +1 -2
- package/src/tools/write.ts +8 -10
- package/src/tui/code-cell.ts +8 -3
- package/src/tui/status-line.ts +4 -4
- package/src/tui/types.ts +0 -1
- package/src/tui/utils.ts +1 -14
- package/src/utils/command-args.ts +76 -0
- package/src/utils/file-mentions.ts +15 -19
- package/src/utils/frontmatter.ts +5 -10
- package/src/utils/shell-snapshot.ts +0 -11
- package/src/utils/title-generator.ts +0 -12
- package/src/web/scrapers/artifacthub.ts +7 -16
- package/src/web/scrapers/arxiv.ts +3 -8
- package/src/web/scrapers/aur.ts +8 -22
- package/src/web/scrapers/biorxiv.ts +5 -14
- package/src/web/scrapers/bluesky.ts +13 -36
- package/src/web/scrapers/brew.ts +5 -10
- package/src/web/scrapers/cheatsh.ts +2 -12
- package/src/web/scrapers/chocolatey.ts +63 -26
- package/src/web/scrapers/choosealicense.ts +3 -18
- package/src/web/scrapers/cisa-kev.ts +4 -18
- package/src/web/scrapers/clojars.ts +6 -33
- package/src/web/scrapers/coingecko.ts +25 -33
- package/src/web/scrapers/crates-io.ts +7 -26
- package/src/web/scrapers/crossref.ts +4 -18
- package/src/web/scrapers/devto.ts +11 -41
- package/src/web/scrapers/discogs.ts +7 -10
- package/src/web/scrapers/discourse.ts +6 -31
- package/src/web/scrapers/dockerhub.ts +12 -35
- package/src/web/scrapers/fdroid.ts +8 -33
- package/src/web/scrapers/firefox-addons.ts +10 -34
- package/src/web/scrapers/flathub.ts +7 -24
- package/src/web/scrapers/github-gist.ts +2 -12
- package/src/web/scrapers/github.ts +9 -47
- package/src/web/scrapers/gitlab.ts +130 -185
- package/src/web/scrapers/go-pkg.ts +12 -22
- package/src/web/scrapers/hackage.ts +88 -43
- package/src/web/scrapers/hackernews.ts +25 -45
- package/src/web/scrapers/hex.ts +19 -36
- package/src/web/scrapers/huggingface.ts +26 -91
- package/src/web/scrapers/iacr.ts +3 -8
- package/src/web/scrapers/jetbrains-marketplace.ts +9 -20
- package/src/web/scrapers/lemmy.ts +5 -23
- package/src/web/scrapers/lobsters.ts +16 -28
- package/src/web/scrapers/mastodon.ts +24 -43
- package/src/web/scrapers/maven.ts +6 -21
- package/src/web/scrapers/mdn.ts +7 -11
- package/src/web/scrapers/metacpan.ts +9 -41
- package/src/web/scrapers/musicbrainz.ts +4 -28
- package/src/web/scrapers/npm.ts +8 -25
- package/src/web/scrapers/nuget.ts +14 -37
- package/src/web/scrapers/nvd.ts +6 -28
- package/src/web/scrapers/ollama.ts +7 -34
- package/src/web/scrapers/open-vsx.ts +5 -19
- package/src/web/scrapers/opencorporates.ts +30 -14
- package/src/web/scrapers/openlibrary.ts +49 -33
- package/src/web/scrapers/orcid.ts +4 -18
- package/src/web/scrapers/osv.ts +7 -24
- package/src/web/scrapers/packagist.ts +9 -24
- package/src/web/scrapers/pub-dev.ts +7 -50
- package/src/web/scrapers/pubmed.ts +54 -21
- package/src/web/scrapers/pypi.ts +8 -26
- package/src/web/scrapers/rawg.ts +11 -19
- package/src/web/scrapers/readthedocs.ts +4 -9
- package/src/web/scrapers/reddit.ts +5 -15
- package/src/web/scrapers/repology.ts +8 -20
- package/src/web/scrapers/rfc.ts +5 -14
- package/src/web/scrapers/rubygems.ts +6 -21
- package/src/web/scrapers/searchcode.ts +8 -36
- package/src/web/scrapers/sec-edgar.ts +4 -18
- package/src/web/scrapers/semantic-scholar.ts +15 -35
- package/src/web/scrapers/snapcraft.ts +5 -19
- package/src/web/scrapers/sourcegraph.ts +5 -43
- package/src/web/scrapers/spdx.ts +4 -18
- package/src/web/scrapers/spotify.ts +4 -23
- package/src/web/scrapers/stackoverflow.ts +8 -13
- package/src/web/scrapers/terraform.ts +9 -37
- package/src/web/scrapers/tldr.ts +3 -7
- package/src/web/scrapers/twitter.ts +3 -7
- package/src/web/scrapers/types.ts +105 -27
- package/src/web/scrapers/utils.ts +97 -103
- package/src/web/scrapers/vimeo.ts +7 -27
- package/src/web/scrapers/vscode-marketplace.ts +8 -17
- package/src/web/scrapers/w3c.ts +6 -14
- package/src/web/scrapers/wikidata.ts +5 -19
- package/src/web/scrapers/wikipedia.ts +2 -12
- package/src/web/scrapers/youtube.ts +5 -34
- package/src/web/search/index.ts +0 -9
- package/src/web/search/providers/anthropic.ts +3 -2
- package/src/web/search/providers/brave.ts +3 -18
- package/src/web/search/providers/exa.ts +1 -12
- package/src/web/search/providers/kimi.ts +5 -44
- package/src/web/search/providers/perplexity.ts +1 -12
- package/src/web/search/providers/synthetic.ts +3 -26
- package/src/web/search/providers/utils.ts +36 -0
- package/src/web/search/providers/zai.ts +9 -50
- package/src/web/search/types.ts +0 -28
- package/src/web/search/utils.ts +17 -0
- package/src/tools/output-utils.ts +0 -63
- package/src/tools/truncate.ts +0 -385
- package/src/web/search/auth.ts +0 -178
package/src/task/parallel.ts
CHANGED
|
@@ -82,3 +82,35 @@ export async function mapWithConcurrencyLimit<T, R>(
|
|
|
82
82
|
|
|
83
83
|
return { results, aborted: signal?.aborted ?? false };
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Simple counting semaphore for limiting concurrency across independently-scheduled async work.
|
|
88
|
+
*/
|
|
89
|
+
export class Semaphore {
|
|
90
|
+
#max: number;
|
|
91
|
+
#current = 0;
|
|
92
|
+
#queue: Array<() => void> = [];
|
|
93
|
+
|
|
94
|
+
constructor(max: number) {
|
|
95
|
+
this.#max = Math.max(1, max);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async acquire(): Promise<void> {
|
|
99
|
+
if (this.#current < this.#max) {
|
|
100
|
+
this.#current++;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const { promise, resolve } = Promise.withResolvers<void>();
|
|
104
|
+
this.#queue.push(resolve);
|
|
105
|
+
return promise;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
release(): void {
|
|
109
|
+
const next = this.#queue.shift();
|
|
110
|
+
if (next) {
|
|
111
|
+
next();
|
|
112
|
+
} else {
|
|
113
|
+
this.#current--;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
package/src/task/render.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
9
9
|
import { Container, Text } from "@oh-my-pi/pi-tui";
|
|
10
|
+
import { formatNumber } from "@oh-my-pi/pi-utils";
|
|
10
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
12
|
import type { Theme } from "../modes/theme/theme";
|
|
12
13
|
import {
|
|
@@ -14,7 +15,6 @@ import {
|
|
|
14
15
|
formatDuration,
|
|
15
16
|
formatMoreItems,
|
|
16
17
|
formatStatusIcon,
|
|
17
|
-
formatTokens,
|
|
18
18
|
replaceTabs,
|
|
19
19
|
truncateToWidth,
|
|
20
20
|
} from "../tools/render-utils";
|
|
@@ -518,13 +518,19 @@ function renderAgentProgress(
|
|
|
518
518
|
const taskPreview = truncateToWidth(progress.task, 40);
|
|
519
519
|
statusLine += ` ${theme.fg("muted", taskPreview)}`;
|
|
520
520
|
}
|
|
521
|
-
|
|
521
|
+
if (progress.toolCount > 0) {
|
|
522
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${progress.toolCount} tools`)}`;
|
|
523
|
+
}
|
|
522
524
|
if (progress.tokens > 0) {
|
|
523
|
-
statusLine += `${theme.sep.dot}${theme.fg("dim", `${
|
|
525
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${formatNumber(progress.tokens)} tokens`)}`;
|
|
524
526
|
}
|
|
525
527
|
} else if (progress.status === "completed") {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
+
if (progress.toolCount > 0) {
|
|
529
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${progress.toolCount} tools`)}`;
|
|
530
|
+
}
|
|
531
|
+
if (progress.tokens > 0) {
|
|
532
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${formatNumber(progress.tokens)} tokens`)}`;
|
|
533
|
+
}
|
|
528
534
|
}
|
|
529
535
|
|
|
530
536
|
lines.push(statusLine);
|
|
@@ -744,7 +750,7 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
744
750
|
theme,
|
|
745
751
|
)}`;
|
|
746
752
|
if (result.tokens > 0) {
|
|
747
|
-
statusLine += `${theme.sep.dot}${theme.fg("dim", `${
|
|
753
|
+
statusLine += `${theme.sep.dot}${theme.fg("dim", `${formatNumber(result.tokens)} tokens`)}`;
|
|
748
754
|
}
|
|
749
755
|
statusLine += `${theme.sep.dot}${theme.fg("dim", formatDuration(result.durationMs))}`;
|
|
750
756
|
|
|
@@ -882,7 +888,9 @@ export function renderResult(
|
|
|
882
888
|
|
|
883
889
|
const lines: string[] = [];
|
|
884
890
|
|
|
885
|
-
|
|
891
|
+
const shouldRenderProgress =
|
|
892
|
+
Boolean(details.progress && details.progress.length > 0) && (isPartial || details.results.length === 0);
|
|
893
|
+
if (shouldRenderProgress && details.progress) {
|
|
886
894
|
details.progress.forEach((progress, i) => {
|
|
887
895
|
const isLast = i === details.progress!.length - 1;
|
|
888
896
|
lines.push(...renderAgentProgress(progress, isLast, expanded, theme, spinnerFrame));
|
package/src/task/types.ts
CHANGED
package/src/tools/ask.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { type Theme, theme } from "../modes/theme/theme";
|
|
|
24
24
|
import askDescription from "../prompts/tools/ask.md" with { type: "text" };
|
|
25
25
|
import { renderStatusLine } from "../tui";
|
|
26
26
|
import type { ToolSession } from ".";
|
|
27
|
-
import {
|
|
27
|
+
import { formatErrorMessage, formatMeta, formatTitle } from "./render-utils";
|
|
28
28
|
|
|
29
29
|
// =============================================================================
|
|
30
30
|
// Types
|
|
@@ -75,8 +75,6 @@ export interface AskToolDetails {
|
|
|
75
75
|
|
|
76
76
|
const OTHER_OPTION = "Other (type your own)";
|
|
77
77
|
const RECOMMENDED_SUFFIX = " (Recommended)";
|
|
78
|
-
/** Default timeout in milliseconds (used when settings unavailable) */
|
|
79
|
-
const _DEFAULT_ASK_TIMEOUT_MS = 30000;
|
|
80
78
|
|
|
81
79
|
function getDoneOptionLabel(): string {
|
|
82
80
|
return `${theme.status.success} Done selecting`;
|
|
@@ -381,8 +379,7 @@ interface AskRenderArgs {
|
|
|
381
379
|
|
|
382
380
|
export const askToolRenderer = {
|
|
383
381
|
renderCall(args: AskRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
|
|
384
|
-
const
|
|
385
|
-
const label = ui.title("Ask");
|
|
382
|
+
const label = formatTitle("Ask", uiTheme);
|
|
386
383
|
|
|
387
384
|
// Multi-part questions
|
|
388
385
|
if (args.questions && args.questions.length > 0) {
|
|
@@ -417,14 +414,14 @@ export const askToolRenderer = {
|
|
|
417
414
|
|
|
418
415
|
// Single question
|
|
419
416
|
if (!args.question) {
|
|
420
|
-
return new Text(
|
|
417
|
+
return new Text(formatErrorMessage("No question provided", uiTheme), 0, 0);
|
|
421
418
|
}
|
|
422
419
|
|
|
423
420
|
let text = `${label} ${uiTheme.fg("accent", args.question)}`;
|
|
424
421
|
const meta: string[] = [];
|
|
425
422
|
if (args.multi) meta.push("multi");
|
|
426
423
|
if (args.options?.length) meta.push(`options:${args.options.length}`);
|
|
427
|
-
text +=
|
|
424
|
+
text += formatMeta(meta, uiTheme);
|
|
428
425
|
|
|
429
426
|
if (args.options?.length) {
|
|
430
427
|
for (let i = 0; i < args.options.length; i++) {
|
|
@@ -13,8 +13,7 @@ import type { Terminal as XtermTerminalType } from "@xterm/headless";
|
|
|
13
13
|
import xterm from "@xterm/headless";
|
|
14
14
|
import type { Theme } from "../modes/theme/theme";
|
|
15
15
|
import { OutputSink, type OutputSummary } from "../session/streaming-output";
|
|
16
|
-
import {
|
|
17
|
-
import { replaceTabs } from "./render-utils";
|
|
16
|
+
import { formatStatusIcon, replaceTabs } from "./render-utils";
|
|
18
17
|
|
|
19
18
|
export interface BashInteractiveResult extends OutputSummary {
|
|
20
19
|
exitCode: number | undefined;
|
|
@@ -235,10 +234,10 @@ class BashInteractiveOverlayComponent implements Component {
|
|
|
235
234
|
}
|
|
236
235
|
const statusIcon =
|
|
237
236
|
this.#state === "running"
|
|
238
|
-
?
|
|
237
|
+
? formatStatusIcon("running", this.uiTheme)
|
|
239
238
|
: this.#state === "complete" && this.#exitCode === 0
|
|
240
|
-
?
|
|
241
|
-
:
|
|
239
|
+
? formatStatusIcon("success", this.uiTheme)
|
|
240
|
+
: formatStatusIcon("warning", this.uiTheme);
|
|
242
241
|
const title = this.uiTheme.fg("accent", "Console");
|
|
243
242
|
const statusBadge = `${this.uiTheme.fg("dim", this.uiTheme.format.bracketLeft)}${this.#stateText()}${this.uiTheme.fg("dim", this.uiTheme.format.bracketRight)}`;
|
|
244
243
|
const prefix = `${statusIcon} ${title} `;
|
package/src/tools/bash.ts
CHANGED
|
@@ -5,13 +5,14 @@ import type { Component } from "@oh-my-pi/pi-tui";
|
|
|
5
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
6
6
|
import { $env, isEnoent } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import { getProjectDir } from "@oh-my-pi/pi-utils/dirs";
|
|
8
|
-
import {
|
|
8
|
+
import { Type } from "@sinclair/typebox";
|
|
9
9
|
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
10
10
|
import { type BashResult, executeBash } from "../exec/bash-executor";
|
|
11
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
12
|
import { truncateToVisualLines } from "../modes/components/visual-truncate";
|
|
13
13
|
import type { Theme } from "../modes/theme/theme";
|
|
14
14
|
import bashDescription from "../prompts/tools/bash.md" with { type: "text" };
|
|
15
|
+
import { DEFAULT_MAX_BYTES, TailBuffer } from "../session/streaming-output";
|
|
15
16
|
import { renderStatusLine } from "../tui";
|
|
16
17
|
import { CachedOutputBlock } from "../tui/output-block";
|
|
17
18
|
import type { ToolSession } from ".";
|
|
@@ -19,17 +20,15 @@ import { type BashInteractiveResult, runInteractiveBashPty } from "./bash-intera
|
|
|
19
20
|
import { checkBashInterception } from "./bash-interceptor";
|
|
20
21
|
import { applyHeadTail } from "./bash-normalize";
|
|
21
22
|
import { expandInternalUrls } from "./bash-skill-urls";
|
|
22
|
-
import type
|
|
23
|
-
import { allocateOutputArtifact, createTailBuffer } from "./output-utils";
|
|
23
|
+
import { formatStyledTruncationWarning, type OutputMeta } from "./output-meta";
|
|
24
24
|
import { resolveToCwd } from "./path-utils";
|
|
25
|
-
import {
|
|
25
|
+
import { replaceTabs } from "./render-utils";
|
|
26
26
|
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
27
27
|
import { toolResult } from "./tool-result";
|
|
28
|
-
import { DEFAULT_MAX_BYTES } from "./truncate";
|
|
29
28
|
|
|
30
29
|
export const BASH_DEFAULT_PREVIEW_LINES = 10;
|
|
31
30
|
|
|
32
|
-
const
|
|
31
|
+
const bashSchemaBase = Type.Object({
|
|
33
32
|
command: Type.String({ description: "Command to execute" }),
|
|
34
33
|
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 300)" })),
|
|
35
34
|
cwd: Type.Optional(Type.String({ description: "Working directory (default: cwd)" })),
|
|
@@ -37,10 +36,33 @@ const bashSchema = Type.Object({
|
|
|
37
36
|
tail: Type.Optional(Type.Number({ description: "Return only last N lines of output" })),
|
|
38
37
|
});
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
const bashSchemaWithAsync = Type.Object({
|
|
40
|
+
...bashSchemaBase.properties,
|
|
41
|
+
async: Type.Optional(
|
|
42
|
+
Type.Boolean({
|
|
43
|
+
description: "Run in background; returns immediately with a job ID. Result delivered as follow-up.",
|
|
44
|
+
}),
|
|
45
|
+
),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
type BashToolSchema = typeof bashSchemaBase | typeof bashSchemaWithAsync;
|
|
49
|
+
|
|
50
|
+
export interface BashToolInput {
|
|
51
|
+
command: string;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
cwd?: string;
|
|
54
|
+
head?: number;
|
|
55
|
+
tail?: number;
|
|
56
|
+
async?: boolean;
|
|
57
|
+
}
|
|
41
58
|
|
|
42
59
|
export interface BashToolDetails {
|
|
43
60
|
meta?: OutputMeta;
|
|
61
|
+
async?: {
|
|
62
|
+
state: "running" | "completed" | "failed";
|
|
63
|
+
jobId: string;
|
|
64
|
+
type: "bash";
|
|
65
|
+
};
|
|
44
66
|
}
|
|
45
67
|
|
|
46
68
|
export interface BashToolOptions {}
|
|
@@ -57,26 +79,61 @@ function isInteractiveResult(result: BashResult | BashInteractiveResult): result
|
|
|
57
79
|
*
|
|
58
80
|
* Executes bash commands with optional timeout and working directory.
|
|
59
81
|
*/
|
|
60
|
-
export class BashTool implements AgentTool<
|
|
82
|
+
export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
61
83
|
readonly name = "bash";
|
|
62
84
|
readonly label = "Bash";
|
|
63
85
|
readonly description: string;
|
|
64
|
-
readonly parameters
|
|
86
|
+
readonly parameters: BashToolSchema;
|
|
65
87
|
readonly concurrency = "exclusive";
|
|
88
|
+
readonly #asyncEnabled: boolean;
|
|
66
89
|
|
|
67
90
|
constructor(private readonly session: ToolSession) {
|
|
68
|
-
this
|
|
91
|
+
this.#asyncEnabled = this.session.settings.get("async.enabled");
|
|
92
|
+
this.parameters = this.#asyncEnabled ? bashSchemaWithAsync : bashSchemaBase;
|
|
93
|
+
this.description = renderPromptTemplate(bashDescription, { asyncEnabled: this.#asyncEnabled });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
#formatResultOutput(result: BashResult | BashInteractiveResult, headLines?: number, tailLines?: number): string {
|
|
97
|
+
let outputText = normalizeResultOutput(result);
|
|
98
|
+
const headTailResult = applyHeadTail(outputText, headLines, tailLines);
|
|
99
|
+
if (headTailResult.applied) {
|
|
100
|
+
outputText = headTailResult.text;
|
|
101
|
+
}
|
|
102
|
+
if (!outputText) {
|
|
103
|
+
outputText = "(no output)";
|
|
104
|
+
}
|
|
105
|
+
return outputText;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#buildResultText(result: BashResult | BashInteractiveResult, timeoutSec: number, outputText: string): string {
|
|
109
|
+
if (result.cancelled) {
|
|
110
|
+
throw new ToolError(normalizeResultOutput(result) || "Command aborted");
|
|
111
|
+
}
|
|
112
|
+
if (isInteractiveResult(result) && result.timedOut) {
|
|
113
|
+
throw new ToolError(normalizeResultOutput(result) || `Command timed out after ${timeoutSec} seconds`);
|
|
114
|
+
}
|
|
115
|
+
if (result.exitCode === undefined) {
|
|
116
|
+
throw new ToolError(`${outputText}\n\nCommand failed: missing exit status`);
|
|
117
|
+
}
|
|
118
|
+
if (result.exitCode !== 0) {
|
|
119
|
+
throw new ToolError(`${outputText}\n\nCommand exited with code ${result.exitCode}`);
|
|
120
|
+
}
|
|
121
|
+
return outputText;
|
|
69
122
|
}
|
|
70
123
|
|
|
71
124
|
async execute(
|
|
72
125
|
_toolCallId: string,
|
|
73
|
-
{ command: rawCommand, timeout: rawTimeout = 300, cwd, head, tail }: BashToolInput,
|
|
126
|
+
{ command: rawCommand, timeout: rawTimeout = 300, cwd, head, tail, async: asyncRequested = false }: BashToolInput,
|
|
74
127
|
signal?: AbortSignal,
|
|
75
128
|
onUpdate?: AgentToolUpdateCallback<BashToolDetails>,
|
|
76
129
|
ctx?: AgentToolContext,
|
|
77
130
|
): Promise<AgentToolResult<BashToolDetails>> {
|
|
78
131
|
let command = rawCommand;
|
|
79
132
|
|
|
133
|
+
if (asyncRequested && !this.#asyncEnabled) {
|
|
134
|
+
throw new ToolError("Async bash execution is disabled. Enable async.enabled to use async mode.");
|
|
135
|
+
}
|
|
136
|
+
|
|
80
137
|
// Only apply explicit head/tail params from tool input.
|
|
81
138
|
const headLines = head;
|
|
82
139
|
const tailLines = tail;
|
|
@@ -113,13 +170,64 @@ export class BashTool implements AgentTool<typeof bashSchema, BashToolDetails> {
|
|
|
113
170
|
const timeoutSec = Math.max(1, Math.min(3600, rawTimeout));
|
|
114
171
|
const timeoutMs = timeoutSec * 1000;
|
|
115
172
|
|
|
173
|
+
if (asyncRequested) {
|
|
174
|
+
const manager = this.session.asyncJobManager;
|
|
175
|
+
if (!manager) {
|
|
176
|
+
throw new ToolError("Async job manager unavailable for this session.");
|
|
177
|
+
}
|
|
178
|
+
const label = command.length > 120 ? `${command.slice(0, 117)}...` : command;
|
|
179
|
+
const tailBuffer = new TailBuffer(DEFAULT_MAX_BYTES);
|
|
180
|
+
const jobId = manager.register(
|
|
181
|
+
"bash",
|
|
182
|
+
label,
|
|
183
|
+
async ({ jobId, signal: runSignal, reportProgress }) => {
|
|
184
|
+
const artifactsDir = this.session.getArtifactsDir?.();
|
|
185
|
+
const extraEnv = artifactsDir ? { ARTIFACTS: artifactsDir } : undefined;
|
|
186
|
+
const { path: artifactPath, id: artifactId } =
|
|
187
|
+
(await this.session.allocateOutputArtifact?.("bash")) ?? {};
|
|
188
|
+
try {
|
|
189
|
+
const result = await executeBash(command, {
|
|
190
|
+
cwd: commandCwd,
|
|
191
|
+
sessionKey: this.session.getSessionId?.() ?? undefined,
|
|
192
|
+
timeout: timeoutMs,
|
|
193
|
+
signal: runSignal,
|
|
194
|
+
env: extraEnv,
|
|
195
|
+
artifactPath,
|
|
196
|
+
artifactId,
|
|
197
|
+
onChunk: chunk => {
|
|
198
|
+
tailBuffer.append(chunk);
|
|
199
|
+
void reportProgress(tailBuffer.text(), { async: { state: "running", jobId, type: "bash" } });
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
const outputText = this.#formatResultOutput(result, headLines, tailLines);
|
|
203
|
+
const finalText = this.#buildResultText(result, timeoutSec, outputText);
|
|
204
|
+
await reportProgress(finalText, { async: { state: "completed", jobId, type: "bash" } });
|
|
205
|
+
return finalText;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
208
|
+
await reportProgress(message, { async: { state: "failed", jobId, type: "bash" } });
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
onProgress: (text, details) => {
|
|
214
|
+
onUpdate?.({ content: [{ type: "text", text }], details: details ?? {} });
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
return {
|
|
219
|
+
content: [{ type: "text", text: `Background job ${jobId} started: ${label}` }],
|
|
220
|
+
details: { async: { state: "running", jobId, type: "bash" } },
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
116
224
|
// Track output for streaming updates (tail only)
|
|
117
|
-
const tailBuffer =
|
|
225
|
+
const tailBuffer = new TailBuffer(DEFAULT_MAX_BYTES);
|
|
118
226
|
|
|
119
227
|
// Set up artifacts environment and allocation
|
|
120
228
|
const artifactsDir = this.session.getArtifactsDir?.();
|
|
121
229
|
const extraEnv = artifactsDir ? { ARTIFACTS: artifactsDir } : undefined;
|
|
122
|
-
const { artifactPath, artifactId } = await
|
|
230
|
+
const { path: artifactPath, id: artifactId } = (await this.session.allocateOutputArtifact?.("bash")) ?? {};
|
|
123
231
|
|
|
124
232
|
const usePty =
|
|
125
233
|
this.session.settings.get("bash.virtualTerminal") === "on" &&
|
|
@@ -163,15 +271,8 @@ export class BashTool implements AgentTool<typeof bashSchema, BashToolDetails> {
|
|
|
163
271
|
if (isInteractiveResult(result) && result.timedOut) {
|
|
164
272
|
throw new ToolError(normalizeResultOutput(result) || `Command timed out after ${timeoutSec} seconds`);
|
|
165
273
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const headTailResult = applyHeadTail(outputText, headLines, tailLines);
|
|
169
|
-
if (headTailResult.applied) {
|
|
170
|
-
outputText = headTailResult.text;
|
|
171
|
-
}
|
|
172
|
-
if (!outputText) {
|
|
173
|
-
outputText = "(no output)";
|
|
174
|
-
}
|
|
274
|
+
|
|
275
|
+
const outputText = this.#formatResultOutput(result, headLines, tailLines);
|
|
175
276
|
const details: BashToolDetails = {};
|
|
176
277
|
const resultBuilder = toolResult(details).text(outputText).truncationFromSummary(result, { direction: "tail" });
|
|
177
278
|
if (result.exitCode === undefined) {
|
|
@@ -232,9 +333,6 @@ function formatBashCommand(args: BashRenderArgs, _uiTheme: Theme): string {
|
|
|
232
333
|
return displayWorkdir ? `${prompt} cd ${displayWorkdir} && ${command}` : `${prompt} ${command}`;
|
|
233
334
|
}
|
|
234
335
|
|
|
235
|
-
// Preview line limit when not expanded (matches tool-execution behavior)
|
|
236
|
-
export const BASH_PREVIEW_LINES = 10;
|
|
237
|
-
|
|
238
336
|
export const bashToolRenderer = {
|
|
239
337
|
renderCall(args: BashRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
|
|
240
338
|
const cmdText = formatBashCommand(args, uiTheme);
|
|
@@ -256,7 +354,6 @@ export const bashToolRenderer = {
|
|
|
256
354
|
const isError = result.isError === true;
|
|
257
355
|
const header = renderStatusLine({ icon: isError ? "error" : "success", title: "Bash" }, uiTheme);
|
|
258
356
|
const details = result.details;
|
|
259
|
-
const truncation = details?.meta?.truncation;
|
|
260
357
|
const outputBlock = new CachedOutputBlock();
|
|
261
358
|
|
|
262
359
|
return {
|
|
@@ -281,21 +378,8 @@ export const bashToolRenderer = {
|
|
|
281
378
|
)
|
|
282
379
|
: undefined;
|
|
283
380
|
let warningLine: string | undefined;
|
|
284
|
-
if (truncation && !showingFullOutput) {
|
|
285
|
-
|
|
286
|
-
if (truncation?.artifactId) {
|
|
287
|
-
warnings.push(`Full output: artifact://${truncation.artifactId}`);
|
|
288
|
-
}
|
|
289
|
-
if (truncation.truncatedBy === "lines") {
|
|
290
|
-
warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);
|
|
291
|
-
} else {
|
|
292
|
-
warnings.push(
|
|
293
|
-
`Truncated: ${truncation.outputLines} lines shown (${formatBytes(truncation.outputBytes)} limit)`,
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
if (warnings.length > 0) {
|
|
297
|
-
warningLine = uiTheme.fg("warning", wrapBrackets(warnings.join(". "), uiTheme));
|
|
298
|
-
}
|
|
381
|
+
if (details?.meta?.truncation && !showingFullOutput) {
|
|
382
|
+
warningLine = formatStyledTruncationWarning(details.meta, uiTheme) ?? undefined;
|
|
299
383
|
}
|
|
300
384
|
|
|
301
385
|
const outputLines: string[] = [];
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { type Static, Type } from "@sinclair/typebox";
|
|
3
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
4
|
+
import cancelJobDescription from "../prompts/tools/cancel-job.md" with { type: "text" };
|
|
5
|
+
import type { ToolSession } from "./index";
|
|
6
|
+
|
|
7
|
+
const cancelJobSchema = Type.Object({
|
|
8
|
+
job_id: Type.String({ description: "Background job ID" }),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
type CancelJobParams = Static<typeof cancelJobSchema>;
|
|
12
|
+
|
|
13
|
+
export interface CancelJobToolDetails {
|
|
14
|
+
status: "cancelled" | "not_found" | "already_completed";
|
|
15
|
+
jobId: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class CancelJobTool implements AgentTool<typeof cancelJobSchema, CancelJobToolDetails> {
|
|
19
|
+
readonly name = "cancel_job";
|
|
20
|
+
readonly label = "CancelJob";
|
|
21
|
+
readonly description: string;
|
|
22
|
+
readonly parameters = cancelJobSchema;
|
|
23
|
+
|
|
24
|
+
constructor(private readonly session: ToolSession) {
|
|
25
|
+
this.description = renderPromptTemplate(cancelJobDescription);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static createIf(session: ToolSession): CancelJobTool | null {
|
|
29
|
+
if (!session.settings.get("async.enabled")) return null;
|
|
30
|
+
return new CancelJobTool(session);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async execute(
|
|
34
|
+
_toolCallId: string,
|
|
35
|
+
params: CancelJobParams,
|
|
36
|
+
_signal?: AbortSignal,
|
|
37
|
+
_onUpdate?: AgentToolUpdateCallback<CancelJobToolDetails>,
|
|
38
|
+
_context?: AgentToolContext,
|
|
39
|
+
): Promise<AgentToolResult<CancelJobToolDetails>> {
|
|
40
|
+
const manager = this.session.asyncJobManager;
|
|
41
|
+
if (!manager) {
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{ type: "text", text: "Async execution is disabled; no background jobs are available to cancel." },
|
|
45
|
+
],
|
|
46
|
+
details: {
|
|
47
|
+
status: "not_found",
|
|
48
|
+
jobId: params.job_id,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const existing = manager.getJob(params.job_id);
|
|
54
|
+
if (!existing) {
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: "text", text: `Background job not found: ${params.job_id}` }],
|
|
57
|
+
details: {
|
|
58
|
+
status: "not_found",
|
|
59
|
+
jobId: params.job_id,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (existing.status !== "running") {
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: "text", text: `Background job ${params.job_id} is already ${existing.status}.` }],
|
|
67
|
+
details: {
|
|
68
|
+
status: "already_completed",
|
|
69
|
+
jobId: params.job_id,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const cancelled = manager.cancel(params.job_id);
|
|
75
|
+
if (!cancelled) {
|
|
76
|
+
return {
|
|
77
|
+
content: [{ type: "text", text: `Background job ${params.job_id} is already completed.` }],
|
|
78
|
+
details: {
|
|
79
|
+
status: "already_completed",
|
|
80
|
+
jobId: params.job_id,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
content: [{ type: "text", text: `Cancelled background job ${params.job_id}.` }],
|
|
87
|
+
details: {
|
|
88
|
+
status: "cancelled",
|
|
89
|
+
jobId: params.job_id,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
package/src/tools/fetch.ts
CHANGED
|
@@ -3,13 +3,14 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
3
3
|
import { htmlToMarkdown } from "@oh-my-pi/pi-natives";
|
|
4
4
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
5
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
6
|
-
import { ptree } from "@oh-my-pi/pi-utils";
|
|
6
|
+
import { ptree, truncate } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import { type Static, Type } from "@sinclair/typebox";
|
|
8
8
|
import { parse as parseHtml } from "node-html-parser";
|
|
9
9
|
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
10
10
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
11
|
import { type Theme, theme } from "../modes/theme/theme";
|
|
12
12
|
import fetchDescription from "../prompts/tools/fetch.md" with { type: "text" };
|
|
13
|
+
import { DEFAULT_MAX_BYTES, truncateHead } from "../session/streaming-output";
|
|
13
14
|
import { renderStatusLine } from "../tui";
|
|
14
15
|
import { CachedOutputBlock } from "../tui/output-block";
|
|
15
16
|
import { ensureTool } from "../utils/tools-manager";
|
|
@@ -19,12 +20,10 @@ import { finalizeOutput, loadPage, MAX_OUTPUT_CHARS } from "../web/scrapers/type
|
|
|
19
20
|
import { convertWithMarkitdown, fetchBinary } from "../web/scrapers/utils";
|
|
20
21
|
import type { ToolSession } from ".";
|
|
21
22
|
import { applyListLimit } from "./list-limit";
|
|
22
|
-
import type
|
|
23
|
-
import {
|
|
24
|
-
import { formatExpandHint } from "./render-utils";
|
|
23
|
+
import { formatStyledArtifactReference, type OutputMeta } from "./output-meta";
|
|
24
|
+
import { formatExpandHint, getDomain } from "./render-utils";
|
|
25
25
|
import { ToolAbortError } from "./tool-errors";
|
|
26
26
|
import { toolResult } from "./tool-result";
|
|
27
|
-
import { DEFAULT_MAX_BYTES, truncateHead } from "./truncate";
|
|
28
27
|
|
|
29
28
|
// =============================================================================
|
|
30
29
|
// Types and Constants
|
|
@@ -900,10 +899,10 @@ export class FetchTool implements AgentTool<typeof fetchSchema, FetchToolDetails
|
|
|
900
899
|
};
|
|
901
900
|
|
|
902
901
|
if (needsArtifact) {
|
|
903
|
-
const { artifactPath,
|
|
902
|
+
const { path: artifactPath, id } = (await this.session.allocateOutputArtifact?.("fetch")) ?? {};
|
|
904
903
|
if (artifactPath) {
|
|
905
904
|
await Bun.write(artifactPath, buildOutput(result.content));
|
|
906
|
-
artifactId =
|
|
905
|
+
artifactId = id;
|
|
907
906
|
}
|
|
908
907
|
}
|
|
909
908
|
|
|
@@ -942,23 +941,6 @@ export class FetchTool implements AgentTool<typeof fetchSchema, FetchToolDetails
|
|
|
942
941
|
// TUI Rendering
|
|
943
942
|
// =============================================================================
|
|
944
943
|
|
|
945
|
-
/** Truncate text to max length with ellipsis */
|
|
946
|
-
function truncate(text: string, maxLen: number, ellipsis: string): string {
|
|
947
|
-
if (text.length <= maxLen) return text;
|
|
948
|
-
const sliceLen = Math.max(0, maxLen - ellipsis.length);
|
|
949
|
-
return `${text.slice(0, sliceLen)}${ellipsis}`;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
/** Extract domain from URL */
|
|
953
|
-
function getDomain(url: string): string {
|
|
954
|
-
try {
|
|
955
|
-
const u = new URL(url);
|
|
956
|
-
return u.hostname.replace(/^www\./, "");
|
|
957
|
-
} catch {
|
|
958
|
-
return url;
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
|
|
962
944
|
/** Count non-empty lines */
|
|
963
945
|
function countNonEmptyLines(text: string): number {
|
|
964
946
|
return text.split("\n").filter(l => l.trim()).length;
|
|
@@ -1029,9 +1011,7 @@ export function renderFetchResult(
|
|
|
1029
1011
|
metadataLines.push(`${uiTheme.fg("muted", "Chars:")} ${charCount}`);
|
|
1030
1012
|
if (truncated) {
|
|
1031
1013
|
metadataLines.push(uiTheme.fg("warning", `${uiTheme.status.warning} Output truncated`));
|
|
1032
|
-
if (truncation?.artifactId)
|
|
1033
|
-
metadataLines.push(uiTheme.fg("warning", `Full output: artifact://${truncation.artifactId}`));
|
|
1034
|
-
}
|
|
1014
|
+
if (truncation?.artifactId) metadataLines.push(formatStyledArtifactReference(truncation.artifactId, uiTheme));
|
|
1035
1015
|
}
|
|
1036
1016
|
if (hasNotes) {
|
|
1037
1017
|
metadataLines.push(`${uiTheme.fg("muted", "Notes:")} ${details.notes.join("; ")}`);
|
package/src/tools/find.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { renderPromptTemplate } from "../config/prompt-templates";
|
|
|
11
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
12
|
import type { Theme } from "../modes/theme/theme";
|
|
13
13
|
import findDescription from "../prompts/tools/find.md" with { type: "text" };
|
|
14
|
+
import { type TruncationResult, truncateHead } from "../session/streaming-output";
|
|
14
15
|
import {
|
|
15
16
|
Ellipsis,
|
|
16
17
|
Hasher,
|
|
@@ -22,12 +23,11 @@ import {
|
|
|
22
23
|
} from "../tui";
|
|
23
24
|
import type { ToolSession } from ".";
|
|
24
25
|
import { applyListLimit } from "./list-limit";
|
|
25
|
-
import type
|
|
26
|
+
import { formatFullOutputReference, type OutputMeta } from "./output-meta";
|
|
26
27
|
import { resolveToCwd } from "./path-utils";
|
|
27
28
|
import { formatCount, formatEmptyMessage, formatErrorMessage, PREVIEW_LIMITS } from "./render-utils";
|
|
28
29
|
import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
|
|
29
30
|
import { toolResult } from "./tool-result";
|
|
30
|
-
import { type TruncationResult, truncateHead } from "./truncate";
|
|
31
31
|
|
|
32
32
|
const findSchema = Type.Object({
|
|
33
33
|
pattern: Type.String({ description: "Glob pattern, e.g. '*.ts', 'src/**/*.json', 'lib/*.tsx'" }),
|
|
@@ -506,7 +506,7 @@ export const findToolRenderer = {
|
|
|
506
506
|
if (limits?.resultLimit) truncationReasons.push(`limit ${limits.resultLimit.reached} results`);
|
|
507
507
|
if (truncation) truncationReasons.push(truncation.truncatedBy === "lines" ? "line limit" : "size limit");
|
|
508
508
|
const artifactId = truncation && "artifactId" in truncation ? truncation.artifactId : undefined;
|
|
509
|
-
if (artifactId) truncationReasons.push(
|
|
509
|
+
if (artifactId) truncationReasons.push(formatFullOutputReference(artifactId));
|
|
510
510
|
|
|
511
511
|
const extraLines: string[] = [];
|
|
512
512
|
if (truncationReasons.length > 0) {
|