@oh-my-pi/pi-coding-agent 15.3.1 → 15.4.1
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 +119 -0
- package/dist/types/cli/auth-gateway-cli.d.ts +1 -1
- package/dist/types/cli/file-processor.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +45 -3
- package/dist/types/config/settings.d.ts +1 -1
- package/dist/types/debug/raw-sse.d.ts +2 -0
- package/dist/types/edit/file-read-cache.d.ts +15 -4
- package/dist/types/edit/index.d.ts +3 -8
- package/dist/types/edit/renderer.d.ts +1 -2
- package/dist/types/eval/__tests__/shared-executors.test.d.ts +1 -0
- package/dist/types/eval/js/shared/local-module-loader.d.ts +16 -0
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +4 -0
- package/dist/types/eval/js/shared/runtime.d.ts +14 -8
- package/dist/types/eval/py/executor.d.ts +1 -2
- package/dist/types/eval/py/kernel.d.ts +6 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -5
- package/dist/types/eval/session-id.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +1 -3
- package/dist/types/hashline/anchors.d.ts +15 -9
- package/dist/types/hashline/constants.d.ts +0 -2
- package/dist/types/hashline/diff.d.ts +1 -2
- package/dist/types/hashline/executor.d.ts +52 -0
- package/dist/types/hashline/hash.d.ts +44 -93
- package/dist/types/hashline/index.d.ts +2 -1
- package/dist/types/hashline/input.d.ts +2 -9
- package/dist/types/hashline/recovery.d.ts +3 -9
- package/dist/types/hashline/tokenizer.d.ts +91 -0
- package/dist/types/hashline/types.d.ts +5 -7
- package/dist/types/modes/components/extensions/types.d.ts +0 -4
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +11 -15
- package/dist/types/session/agent-storage.d.ts +11 -10
- package/dist/types/slash-commands/acp-builtins.d.ts +3 -3
- package/dist/types/slash-commands/types.d.ts +0 -5
- package/dist/types/task/executor.d.ts +2 -0
- package/dist/types/task/types.d.ts +8 -0
- package/dist/types/tool-discovery/tool-index.d.ts +0 -50
- package/dist/types/tools/index.d.ts +2 -8
- package/dist/types/tools/match-line-format.d.ts +4 -4
- package/dist/types/tools/output-schema-validator.d.ts +64 -0
- package/dist/types/tools/review.d.ts +13 -0
- package/dist/types/tools/search-tool-bm25.d.ts +1 -1
- package/dist/types/tools/search.d.ts +4 -3
- package/dist/types/utils/edit-mode.d.ts +1 -1
- package/dist/types/web/kagi.d.ts +4 -2
- package/dist/types/web/parallel.d.ts +4 -3
- package/dist/types/web/scrapers/types.d.ts +2 -1
- package/dist/types/web/search/index.d.ts +12 -4
- package/dist/types/web/search/provider.d.ts +2 -1
- package/dist/types/web/search/providers/anthropic.d.ts +9 -4
- package/dist/types/web/search/providers/base.d.ts +34 -2
- package/dist/types/web/search/providers/brave.d.ts +8 -1
- package/dist/types/web/search/providers/codex.d.ts +13 -9
- package/dist/types/web/search/providers/exa.d.ts +10 -1
- package/dist/types/web/search/providers/gemini.d.ts +20 -23
- package/dist/types/web/search/providers/jina.d.ts +2 -1
- package/dist/types/web/search/providers/kagi.d.ts +4 -1
- package/dist/types/web/search/providers/kimi.d.ts +10 -1
- package/dist/types/web/search/providers/parallel.d.ts +3 -2
- package/dist/types/web/search/providers/perplexity.d.ts +5 -2
- package/dist/types/web/search/providers/searxng.d.ts +2 -1
- package/dist/types/web/search/providers/synthetic.d.ts +5 -8
- package/dist/types/web/search/providers/tavily.d.ts +11 -4
- package/dist/types/web/search/providers/utils.d.ts +8 -6
- package/dist/types/web/search/providers/zai.d.ts +12 -3
- package/package.json +7 -7
- package/src/cli/auth-gateway-cli.ts +71 -2
- package/src/cli/file-processor.ts +12 -2
- package/src/cli.ts +0 -8
- package/src/commands/auth-gateway.ts +2 -0
- package/src/commands/commit.ts +8 -8
- package/src/config/prompt-templates.ts +6 -6
- package/src/config/settings-schema.ts +47 -3
- package/src/config/settings.ts +5 -5
- package/src/debug/raw-sse.ts +68 -3
- package/src/edit/file-read-cache.ts +68 -25
- package/src/edit/index.ts +6 -37
- package/src/edit/renderer.ts +9 -47
- package/src/edit/streaming.ts +43 -56
- package/src/eval/__tests__/shared-executors.test.ts +520 -0
- package/src/eval/js/context-manager.ts +64 -53
- package/src/eval/js/shared/local-module-loader.ts +265 -0
- package/src/eval/js/shared/prelude.txt +4 -0
- package/src/eval/js/shared/rewrite-imports.ts +85 -0
- package/src/eval/js/shared/runtime.ts +129 -86
- package/src/eval/js/worker-core.ts +23 -38
- package/src/eval/py/executor.ts +155 -84
- package/src/eval/py/kernel.ts +10 -1
- package/src/eval/py/prelude.py +22 -24
- package/src/eval/py/runner.py +203 -85
- package/src/eval/py/tool-bridge.ts +17 -10
- package/src/eval/session-id.ts +8 -0
- package/src/exec/bash-executor.ts +27 -16
- package/src/extensibility/extensions/runner.ts +0 -1
- package/src/extensibility/extensions/types.ts +1 -3
- package/src/extensibility/plugins/marketplace/manager.ts +20 -1
- package/src/hashline/anchors.ts +56 -65
- package/src/hashline/apply.ts +29 -31
- package/src/hashline/constants.ts +0 -3
- package/src/hashline/diff-preview.ts +4 -5
- package/src/hashline/diff.ts +30 -4
- package/src/hashline/execute.ts +91 -26
- package/src/hashline/executor.ts +239 -0
- package/src/hashline/grammar.lark +12 -10
- package/src/hashline/hash.ts +69 -114
- package/src/hashline/index.ts +2 -1
- package/src/hashline/input.ts +48 -41
- package/src/hashline/prefixes.ts +21 -11
- package/src/hashline/recovery.ts +63 -71
- package/src/hashline/stream.ts +2 -2
- package/src/hashline/tokenizer.ts +467 -0
- package/src/hashline/types.ts +6 -8
- package/src/internal-urls/docs-index.generated.ts +9 -8
- package/src/lsp/config.ts +87 -22
- package/src/modes/components/extensions/types.ts +0 -5
- package/src/modes/components/session-observer-overlay.ts +11 -2
- package/src/modes/components/tree-selector.ts +10 -2
- package/src/modes/controllers/command-controller.ts +1 -3
- package/src/modes/controllers/extension-ui-controller.ts +10 -11
- package/src/modes/controllers/selector-controller.ts +5 -5
- package/src/modes/types.ts +4 -1
- package/src/modes/utils/ui-helpers.ts +4 -0
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/eval.md +1 -1
- package/src/prompts/tools/hashline.md +73 -94
- package/src/prompts/tools/read.md +4 -4
- package/src/prompts/tools/search.md +3 -3
- package/src/sdk.ts +21 -24
- package/src/session/agent-session.ts +59 -66
- package/src/session/agent-storage.ts +13 -14
- package/src/slash-commands/acp-builtins.ts +3 -3
- package/src/slash-commands/types.ts +0 -6
- package/src/task/executor.ts +55 -57
- package/src/task/index.ts +8 -4
- package/src/task/render.ts +53 -1
- package/src/task/types.ts +8 -0
- package/src/tool-discovery/tool-index.ts +0 -134
- package/src/tools/ast-edit.ts +36 -13
- package/src/tools/ast-grep.ts +45 -4
- package/src/tools/browser/tab-worker.ts +3 -2
- package/src/tools/eval.ts +2 -1
- package/src/tools/fetch.ts +23 -14
- package/src/tools/index.ts +2 -8
- package/src/tools/irc.ts +59 -5
- package/src/tools/jtd-to-json-schema.ts +5 -1
- package/src/tools/match-line-format.ts +5 -7
- package/src/tools/output-schema-validator.ts +132 -0
- package/src/tools/read.ts +142 -63
- package/src/tools/review.ts +23 -0
- package/src/tools/search-tool-bm25.ts +3 -30
- package/src/tools/search.ts +48 -16
- package/src/tools/write.ts +3 -3
- package/src/tools/yield.ts +32 -41
- package/src/utils/edit-mode.ts +1 -2
- package/src/utils/file-mentions.ts +2 -2
- package/src/web/kagi.ts +15 -6
- package/src/web/parallel.ts +9 -6
- package/src/web/scrapers/types.ts +7 -1
- package/src/web/scrapers/youtube.ts +13 -7
- package/src/web/search/index.ts +37 -11
- package/src/web/search/provider.ts +5 -3
- package/src/web/search/providers/anthropic.ts +30 -21
- package/src/web/search/providers/base.ts +35 -2
- package/src/web/search/providers/brave.ts +4 -4
- package/src/web/search/providers/codex.ts +118 -89
- package/src/web/search/providers/exa.ts +3 -2
- package/src/web/search/providers/gemini.ts +58 -155
- package/src/web/search/providers/jina.ts +4 -4
- package/src/web/search/providers/kagi.ts +17 -11
- package/src/web/search/providers/kimi.ts +29 -13
- package/src/web/search/providers/parallel.ts +171 -23
- package/src/web/search/providers/perplexity.ts +38 -37
- package/src/web/search/providers/searxng.ts +3 -1
- package/src/web/search/providers/synthetic.ts +16 -19
- package/src/web/search/providers/tavily.ts +23 -18
- package/src/web/search/providers/utils.ts +11 -17
- package/src/web/search/providers/zai.ts +16 -8
- package/dist/types/hashline/parser.d.ts +0 -7
- package/dist/types/mcp/discoverable-tool-metadata.d.ts +0 -7
- package/dist/types/tools/vim.d.ts +0 -58
- package/dist/types/vim/buffer.d.ts +0 -41
- package/dist/types/vim/commands.d.ts +0 -6
- package/dist/types/vim/engine.d.ts +0 -47
- package/dist/types/vim/parser.d.ts +0 -3
- package/dist/types/vim/render.d.ts +0 -25
- package/dist/types/vim/types.d.ts +0 -182
- package/src/hashline/parser.ts +0 -212
- package/src/mcp/discoverable-tool-metadata.ts +0 -24
- package/src/prompts/tools/vim.md +0 -98
- package/src/tools/vim.ts +0 -949
- package/src/vim/buffer.ts +0 -309
- package/src/vim/commands.ts +0 -382
- package/src/vim/engine.ts +0 -2409
- package/src/vim/parser.ts +0 -134
- package/src/vim/render.ts +0 -252
- package/src/vim/types.ts +0 -197
package/src/task/render.ts
CHANGED
|
@@ -639,7 +639,8 @@ function renderAgentProgress(
|
|
|
639
639
|
}
|
|
640
640
|
}
|
|
641
641
|
|
|
642
|
-
for (const
|
|
642
|
+
for (const toolName in progress.extractedToolData) {
|
|
643
|
+
const dataArray = progress.extractedToolData[toolName];
|
|
643
644
|
// Handle report_finding with tree formatting
|
|
644
645
|
if (toolName === "report_finding") {
|
|
645
646
|
const findings = normalizeReportFindings(dataArray);
|
|
@@ -649,6 +650,11 @@ function renderAgentProgress(
|
|
|
649
650
|
continue;
|
|
650
651
|
}
|
|
651
652
|
|
|
653
|
+
// Nested `task` data has its own dedicated tree renderer below that
|
|
654
|
+
// also merges in the in-flight snapshot — skip the generic inline
|
|
655
|
+
// path so we don't render twice.
|
|
656
|
+
if (toolName === "task") continue;
|
|
657
|
+
|
|
652
658
|
const handler = subprocessToolRegistry.getHandler(toolName);
|
|
653
659
|
if (handler?.renderInline) {
|
|
654
660
|
const displayCount = expanded ? (dataArray as unknown[]).length : 3;
|
|
@@ -671,6 +677,20 @@ function renderAgentProgress(
|
|
|
671
677
|
}
|
|
672
678
|
}
|
|
673
679
|
|
|
680
|
+
// Nested `task` tree: completed sub-calls from `extractedToolData.task` plus
|
|
681
|
+
// the in-flight snapshot (if any). Surfacing this in the live view means
|
|
682
|
+
// the user sees deep-tree progress without waiting for this agent to finish
|
|
683
|
+
// its own turn.
|
|
684
|
+
const completedTaskCalls = (progress.extractedToolData?.task as TaskToolDetails[] | undefined) ?? [];
|
|
685
|
+
const inflight = progress.inflightTaskDetails;
|
|
686
|
+
if (completedTaskCalls.length > 0 || inflight) {
|
|
687
|
+
const snapshots = inflight ? [...completedTaskCalls, inflight] : completedTaskCalls;
|
|
688
|
+
const nestedLines = renderNestedTaskTree(snapshots, expanded, theme, spinnerFrame);
|
|
689
|
+
for (const line of nestedLines) {
|
|
690
|
+
lines.push(`${continuePrefix}${line}`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
674
694
|
// Expanded view: recent output and tools
|
|
675
695
|
if (expanded && progress.status === "running") {
|
|
676
696
|
const output = progress.recentOutput.join("\n");
|
|
@@ -1067,6 +1087,38 @@ function renderNestedTaskResults(detailsList: TaskToolDetails[], expanded: boole
|
|
|
1067
1087
|
return lines;
|
|
1068
1088
|
}
|
|
1069
1089
|
|
|
1090
|
+
/**
|
|
1091
|
+
* Render a list of `TaskToolDetails` snapshots — completed (`results[]`) or
|
|
1092
|
+
* in-flight (`progress[]`) — as an interleaved tree. Used by the live progress
|
|
1093
|
+
* view to surface nested subagent activity while this agent is still running.
|
|
1094
|
+
*/
|
|
1095
|
+
function renderNestedTaskTree(
|
|
1096
|
+
detailsList: TaskToolDetails[],
|
|
1097
|
+
expanded: boolean,
|
|
1098
|
+
theme: Theme,
|
|
1099
|
+
spinnerFrame?: number,
|
|
1100
|
+
): string[] {
|
|
1101
|
+
const lines: string[] = [];
|
|
1102
|
+
for (const details of detailsList) {
|
|
1103
|
+
const hasResults = Boolean(details.results && details.results.length > 0);
|
|
1104
|
+
if (hasResults) {
|
|
1105
|
+
details.results.forEach((result, index) => {
|
|
1106
|
+
const isLast = index === details.results.length - 1;
|
|
1107
|
+
lines.push(...renderAgentResult(result, isLast, expanded, theme));
|
|
1108
|
+
});
|
|
1109
|
+
continue;
|
|
1110
|
+
}
|
|
1111
|
+
const inflight = details.progress;
|
|
1112
|
+
if (inflight && inflight.length > 0) {
|
|
1113
|
+
inflight.forEach((prog, index) => {
|
|
1114
|
+
const isLast = index === inflight.length - 1;
|
|
1115
|
+
lines.push(...renderAgentProgress(prog, isLast, expanded, theme, spinnerFrame));
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
return lines;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1070
1122
|
subprocessToolRegistry.register<TaskToolDetails>("task", {
|
|
1071
1123
|
extractData: event => {
|
|
1072
1124
|
const details = event.result?.details;
|
package/src/task/types.ts
CHANGED
|
@@ -236,6 +236,14 @@ export interface AgentProgress {
|
|
|
236
236
|
attempt: number;
|
|
237
237
|
errorMessage: string;
|
|
238
238
|
};
|
|
239
|
+
/**
|
|
240
|
+
* Snapshot of the most recent `task` tool call's in-flight `TaskToolDetails`,
|
|
241
|
+
* captured from `tool_execution_update`. Lets the parent UI surface live
|
|
242
|
+
* nested-subagent progress while this agent is still inside its own `task`
|
|
243
|
+
* call. Cleared when the call ends — finalized data lives in
|
|
244
|
+
* `extractedToolData.task` after that.
|
|
245
|
+
*/
|
|
246
|
+
inflightTaskDetails?: TaskToolDetails;
|
|
239
247
|
}
|
|
240
248
|
|
|
241
249
|
/** Result from a single agent execution */
|
|
@@ -44,47 +44,6 @@ export interface DiscoverableToolSearchResult {
|
|
|
44
44
|
score: number;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
// ─── Legacy MCP-typed aliases (back-compat) ──────────────────────────────────
|
|
48
|
-
|
|
49
|
-
/** @deprecated Use DiscoverableTool with source === "mcp" */
|
|
50
|
-
export type DiscoverableMCPTool = Pick<
|
|
51
|
-
DiscoverableTool,
|
|
52
|
-
"name" | "label" | "schemaKeys" | "serverName" | "mcpToolName"
|
|
53
|
-
> & { description: string };
|
|
54
|
-
|
|
55
|
-
/** @deprecated Use DiscoverableToolServerSummary */
|
|
56
|
-
export type DiscoverableMCPToolServerSummary = DiscoverableToolServerSummary;
|
|
57
|
-
|
|
58
|
-
/** @deprecated Use DiscoverableToolSummary */
|
|
59
|
-
export type DiscoverableMCPToolSummary = DiscoverableToolSummary;
|
|
60
|
-
|
|
61
|
-
/** Tool object stored on legacy MCP index documents. Carries both legacy `description` and the
|
|
62
|
-
* generic `summary`/`source` so the legacy index is structurally assignable to
|
|
63
|
-
* DiscoverableToolSearchIndex (search functions read termFrequencies, not the tool fields). */
|
|
64
|
-
export type DiscoverableMCPSearchTool = DiscoverableTool & { description: string };
|
|
65
|
-
|
|
66
|
-
/** @deprecated Use DiscoverableToolSearchDocument */
|
|
67
|
-
export interface DiscoverableMCPSearchDocument {
|
|
68
|
-
tool: DiscoverableMCPSearchTool;
|
|
69
|
-
termFrequencies: Map<string, number>;
|
|
70
|
-
length: number;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** @deprecated Use DiscoverableToolSearchIndex.
|
|
74
|
-
* Documents on this index expose `tool.description` (legacy MCP shape) while still being
|
|
75
|
-
* searchable via `searchDiscoverableTools`. */
|
|
76
|
-
export interface DiscoverableMCPSearchIndex {
|
|
77
|
-
documents: DiscoverableMCPSearchDocument[];
|
|
78
|
-
averageLength: number;
|
|
79
|
-
documentFrequencies: Map<string, number>;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** @deprecated Use DiscoverableToolSearchResult */
|
|
83
|
-
export interface DiscoverableMCPSearchResult {
|
|
84
|
-
tool: DiscoverableMCPSearchTool;
|
|
85
|
-
score: number;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
47
|
// ─── BM25 Constants ───────────────────────────────────────────────────────────
|
|
89
48
|
|
|
90
49
|
const BM25_K1 = 1.2;
|
|
@@ -295,96 +254,3 @@ export function searchDiscoverableTools(
|
|
|
295
254
|
.sort((left, right) => right.score - left.score || left.tool.name.localeCompare(right.tool.name))
|
|
296
255
|
.slice(0, limit);
|
|
297
256
|
}
|
|
298
|
-
|
|
299
|
-
// ─── Legacy MCP-specific shims (back-compat wrappers) ────────────────────────
|
|
300
|
-
|
|
301
|
-
/** @deprecated Use getDiscoverableTool */
|
|
302
|
-
export function getDiscoverableMCPTool(tool: AgentTool): DiscoverableMCPTool | null {
|
|
303
|
-
if (!isMCPToolName(tool.name)) return null;
|
|
304
|
-
const toolRecord = tool as AgentTool & {
|
|
305
|
-
label?: string;
|
|
306
|
-
description?: string;
|
|
307
|
-
mcpServerName?: string;
|
|
308
|
-
mcpToolName?: string;
|
|
309
|
-
parameters?: unknown;
|
|
310
|
-
};
|
|
311
|
-
return {
|
|
312
|
-
name: tool.name,
|
|
313
|
-
label: typeof toolRecord.label === "string" ? toolRecord.label : tool.name,
|
|
314
|
-
description: typeof toolRecord.description === "string" ? toolRecord.description : "",
|
|
315
|
-
serverName: typeof toolRecord.mcpServerName === "string" ? toolRecord.mcpServerName : undefined,
|
|
316
|
-
mcpToolName: typeof toolRecord.mcpToolName === "string" ? toolRecord.mcpToolName : undefined,
|
|
317
|
-
schemaKeys: getSchemaPropertyKeys(toolRecord.parameters),
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/** @deprecated Use collectDiscoverableTools with source filter */
|
|
322
|
-
export function collectDiscoverableMCPTools(tools: Iterable<AgentTool>): DiscoverableMCPTool[] {
|
|
323
|
-
const discoverable: DiscoverableMCPTool[] = [];
|
|
324
|
-
for (const tool of tools) {
|
|
325
|
-
const metadata = getDiscoverableMCPTool(tool);
|
|
326
|
-
if (metadata) {
|
|
327
|
-
discoverable.push(metadata);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
return discoverable;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/** @deprecated Use selectDiscoverableToolNamesByServer */
|
|
334
|
-
export function selectDiscoverableMCPToolNamesByServer(
|
|
335
|
-
tools: Iterable<DiscoverableMCPTool>,
|
|
336
|
-
serverNames: ReadonlySet<string>,
|
|
337
|
-
): string[] {
|
|
338
|
-
if (serverNames.size === 0) return [];
|
|
339
|
-
return Array.from(tools)
|
|
340
|
-
.filter(tool => tool.serverName !== undefined && serverNames.has(tool.serverName))
|
|
341
|
-
.map(tool => tool.name);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/** @deprecated Use summarizeDiscoverableTools */
|
|
345
|
-
export function summarizeDiscoverableMCPTools(tools: DiscoverableMCPTool[]): DiscoverableMCPToolSummary {
|
|
346
|
-
const serverToolCounts = new Map<string, number>();
|
|
347
|
-
for (const tool of tools) {
|
|
348
|
-
if (!tool.serverName) continue;
|
|
349
|
-
serverToolCounts.set(tool.serverName, (serverToolCounts.get(tool.serverName) ?? 0) + 1);
|
|
350
|
-
}
|
|
351
|
-
const servers = Array.from(serverToolCounts.entries())
|
|
352
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
353
|
-
.map(([name, toolCount]) => ({ name, toolCount }));
|
|
354
|
-
return {
|
|
355
|
-
servers,
|
|
356
|
-
toolCount: tools.length,
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/** @deprecated Use buildDiscoverableToolSearchIndex.
|
|
361
|
-
* Builds an index whose documents preserve the legacy `description` field on each tool while
|
|
362
|
-
* also carrying the generic `summary` (set from `description`) so the index remains usable
|
|
363
|
-
* with `searchDiscoverableTools`. */
|
|
364
|
-
export function buildDiscoverableMCPSearchIndex(tools: Iterable<DiscoverableMCPTool>): DiscoverableMCPSearchIndex {
|
|
365
|
-
const adapted: DiscoverableMCPSearchTool[] = Array.from(tools).map(t => ({
|
|
366
|
-
name: t.name,
|
|
367
|
-
label: t.label,
|
|
368
|
-
description: t.description,
|
|
369
|
-
summary: t.description,
|
|
370
|
-
source: "mcp" as DiscoverableToolSource,
|
|
371
|
-
serverName: t.serverName,
|
|
372
|
-
mcpToolName: t.mcpToolName,
|
|
373
|
-
schemaKeys: t.schemaKeys,
|
|
374
|
-
}));
|
|
375
|
-
const generic = buildDiscoverableToolSearchIndex(adapted);
|
|
376
|
-
// Documents reference `adapted` tools (with `description`), so the cast is sound.
|
|
377
|
-
return generic as unknown as DiscoverableMCPSearchIndex;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/** @deprecated Use searchDiscoverableTools */
|
|
381
|
-
export function searchDiscoverableMCPTools(
|
|
382
|
-
index: DiscoverableMCPSearchIndex | DiscoverableToolSearchIndex,
|
|
383
|
-
query: string,
|
|
384
|
-
limit: number,
|
|
385
|
-
): DiscoverableMCPSearchResult[] {
|
|
386
|
-
return searchDiscoverableTools(index as DiscoverableToolSearchIndex, query, limit) as DiscoverableMCPSearchResult[];
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/** @deprecated Use formatDiscoverableToolServerSummary */
|
|
390
|
-
export const formatDiscoverableMCPToolServerSummary = formatDiscoverableToolServerSummary;
|
package/src/tools/ast-edit.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Text } from "@oh-my-pi/pi-tui";
|
|
|
6
6
|
import { $envpos, prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import * as z from "zod/v4";
|
|
8
8
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
9
|
-
import {
|
|
9
|
+
import { computeFileHash, formatHashlineHeader } from "../hashline/hash";
|
|
10
10
|
import type { Theme } from "../modes/theme/theme";
|
|
11
11
|
import astEditDescription from "../prompts/tools/ast-edit.md" with { type: "text" };
|
|
12
12
|
import { Ellipsis, fileHyperlink, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
@@ -257,12 +257,26 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
const useHashLines = resolveFileDisplayMode(this.session).hashLines;
|
|
260
|
+
const hashContexts = new Map<string, { fileHash: string }>();
|
|
261
|
+
if (useHashLines) {
|
|
262
|
+
for (const relativePath of fileList) {
|
|
263
|
+
const absolutePath = path.resolve(this.session.cwd, relativePath);
|
|
264
|
+
try {
|
|
265
|
+
const fullText = await Bun.file(absolutePath).text();
|
|
266
|
+
const fileHash = computeFileHash(fullText);
|
|
267
|
+
hashContexts.set(relativePath, { fileHash });
|
|
268
|
+
} catch {
|
|
269
|
+
// Best-effort: if a file disappears between ast-edit and rendering, emit plain line output.
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
260
273
|
const outputLines: string[] = [];
|
|
261
274
|
const displayLines: string[] = [];
|
|
262
275
|
const renderChangesForFile = (relativePath: string): { model: string[]; display: string[] } => {
|
|
263
276
|
const modelOut: string[] = [];
|
|
264
277
|
const displayOut: string[] = [];
|
|
265
278
|
const fileChanges = changesByFile.get(relativePath) ?? [];
|
|
279
|
+
const hashContext = hashContexts.get(relativePath);
|
|
266
280
|
const lineNumberWidth = fileChanges.reduce(
|
|
267
281
|
(width, change) => Math.max(width, String(change.startLine).length),
|
|
268
282
|
0,
|
|
@@ -272,13 +286,9 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
272
286
|
const afterFirstLine = change.after.split("\n", 1)[0] ?? "";
|
|
273
287
|
const beforeLine = beforeFirstLine.slice(0, 120);
|
|
274
288
|
const afterLine = afterFirstLine.slice(0, 120);
|
|
275
|
-
const beforeRef =
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const afterRef = useHashLines
|
|
279
|
-
? `${change.startLine}${computeLineHash(change.startLine, afterFirstLine)}`
|
|
280
|
-
: `${change.startLine}:${change.startColumn}`;
|
|
281
|
-
const lineSeparator = useHashLines ? HL_BODY_SEP : " ";
|
|
289
|
+
const beforeRef = hashContext ? `${change.startLine}` : `${change.startLine}:${change.startColumn}`;
|
|
290
|
+
const afterRef = hashContext ? `${change.startLine}` : `${change.startLine}:${change.startColumn}`;
|
|
291
|
+
const lineSeparator = hashContext ? ":" : " ";
|
|
282
292
|
modelOut.push(`-${beforeRef}${lineSeparator}${beforeLine}`);
|
|
283
293
|
modelOut.push(`+${afterRef}${lineSeparator}${afterLine}`);
|
|
284
294
|
displayOut.push(formatCodeFrameLine("-", change.startLine, beforeLine, lineNumberWidth));
|
|
@@ -291,10 +301,13 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
291
301
|
const grouped = formatGroupedFiles(fileList, relativePath => {
|
|
292
302
|
const rendered = renderChangesForFile(relativePath);
|
|
293
303
|
const count = fileReplacementCounts.get(relativePath) ?? 0;
|
|
304
|
+
const hashContext = hashContexts.get(relativePath);
|
|
305
|
+
const hashSuffix = hashContext ? `#${hashContext.fileHash}` : "";
|
|
294
306
|
return {
|
|
295
|
-
headerSuffix:
|
|
307
|
+
headerSuffix: `${hashSuffix} (${formatCount("replacement", count)})`,
|
|
296
308
|
modelLines: rendered.model,
|
|
297
309
|
displayLines: rendered.display,
|
|
310
|
+
skip: rendered.model.length === 0,
|
|
298
311
|
};
|
|
299
312
|
});
|
|
300
313
|
outputLines.push(...grouped.model);
|
|
@@ -302,6 +315,15 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
302
315
|
} else {
|
|
303
316
|
for (const relativePath of fileList) {
|
|
304
317
|
const rendered = renderChangesForFile(relativePath);
|
|
318
|
+
if (rendered.model.length === 0) continue;
|
|
319
|
+
if (outputLines.length > 0) {
|
|
320
|
+
outputLines.push("");
|
|
321
|
+
displayLines.push("");
|
|
322
|
+
}
|
|
323
|
+
const hashContext = hashContexts.get(relativePath);
|
|
324
|
+
if (hashContext) {
|
|
325
|
+
outputLines.push(formatHashlineHeader(relativePath, hashContext.fileHash));
|
|
326
|
+
}
|
|
305
327
|
outputLines.push(...rendered.model);
|
|
306
328
|
displayLines.push(...rendered.display);
|
|
307
329
|
}
|
|
@@ -499,11 +521,12 @@ export const astEditToolRenderer = {
|
|
|
499
521
|
let contextDir = searchBase ?? "";
|
|
500
522
|
return group.map(line => {
|
|
501
523
|
if (line.startsWith("## ")) {
|
|
502
|
-
// Strip ` (3 replacements)`
|
|
524
|
+
// Strip ` (3 replacements)` and `#hash` suffixes from formatGroupedFiles.
|
|
503
525
|
const fileName = line
|
|
504
526
|
.slice(3)
|
|
505
527
|
.trimEnd()
|
|
506
|
-
.replace(/\s+\([^)]*\)\s*$/, "")
|
|
528
|
+
.replace(/\s+\([^)]*\)\s*$/, "")
|
|
529
|
+
.replace(/#[0-9a-f]+$/, "");
|
|
507
530
|
const absPath = contextDir && fileName ? path.join(contextDir, fileName) : undefined;
|
|
508
531
|
const styled = uiTheme.fg("dim", line);
|
|
509
532
|
return absPath ? fileHyperlink(absPath, styled) : styled;
|
|
@@ -514,14 +537,14 @@ export const astEditToolRenderer = {
|
|
|
514
537
|
.trimEnd()
|
|
515
538
|
.replace(/\s+\([^)]*\)\s*$/, "");
|
|
516
539
|
const isDirectory = raw.endsWith("/");
|
|
517
|
-
const name = raw.replace(/\/$/, "");
|
|
540
|
+
const name = isDirectory ? raw.replace(/\/$/, "") : raw.replace(/#[0-9a-f]+$/, "");
|
|
518
541
|
if (isDirectory) {
|
|
519
542
|
if (searchBase) {
|
|
520
543
|
contextDir = name === "." ? searchBase : path.join(searchBase, name);
|
|
521
544
|
}
|
|
522
545
|
return uiTheme.fg("accent", line);
|
|
523
546
|
}
|
|
524
|
-
// Root-level file with optional
|
|
547
|
+
// Root-level file with optional `#hash` and ` (3 replacements)` suffixes.
|
|
525
548
|
const absPath = searchBase && name ? path.join(searchBase, name) : undefined;
|
|
526
549
|
const styled = uiTheme.fg("accent", line);
|
|
527
550
|
return absPath ? fileHyperlink(absPath, styled) : styled;
|
package/src/tools/ast-grep.ts
CHANGED
|
@@ -5,7 +5,9 @@ import type { Component } from "@oh-my-pi/pi-tui";
|
|
|
5
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
6
6
|
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import * as z from "zod/v4";
|
|
8
|
+
import { getFileReadCache } from "../edit/file-read-cache";
|
|
8
9
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
10
|
+
import { computeFileHash, formatHashlineHeader } from "../hashline/hash";
|
|
9
11
|
import type { Theme } from "../modes/theme/theme";
|
|
10
12
|
import astGrepDescription from "../prompts/tools/ast-grep.md" with { type: "text" };
|
|
11
13
|
import { Ellipsis, fileHyperlink, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
@@ -216,25 +218,43 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
216
218
|
}
|
|
217
219
|
|
|
218
220
|
const useHashLines = resolveFileDisplayMode(this.session).hashLines;
|
|
221
|
+
const hashContexts = new Map<string, { absolutePath: string; fileHash: string }>();
|
|
222
|
+
if (useHashLines) {
|
|
223
|
+
for (const relativePath of fileList) {
|
|
224
|
+
const absolutePath = path.resolve(this.session.cwd, relativePath);
|
|
225
|
+
try {
|
|
226
|
+
const fullText = await Bun.file(absolutePath).text();
|
|
227
|
+
const fileHash = computeFileHash(fullText);
|
|
228
|
+
hashContexts.set(relativePath, { absolutePath, fileHash });
|
|
229
|
+
} catch {
|
|
230
|
+
// Best-effort: if a file disappears between ast-grep and rendering, emit plain line output.
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
219
234
|
const outputLines: string[] = [];
|
|
220
235
|
const displayLines: string[] = [];
|
|
221
236
|
const renderMatchesForFile = (relativePath: string): { model: string[]; display: string[] } => {
|
|
222
237
|
const modelOut: string[] = [];
|
|
223
238
|
const displayOut: string[] = [];
|
|
224
239
|
const fileMatches = matchesByFile.get(relativePath) ?? [];
|
|
240
|
+
const hashContext = hashContexts.get(relativePath);
|
|
225
241
|
const lineNumberWidth = fileMatches.reduce((width, match) => {
|
|
226
242
|
const lineCount = match.text.split("\n").length;
|
|
227
243
|
const endLine = match.startLine + lineCount - 1;
|
|
228
244
|
return Math.max(width, String(match.startLine).length, String(endLine).length);
|
|
229
245
|
}, 0);
|
|
246
|
+
const cacheEntries: Array<readonly [number, string]> = [];
|
|
230
247
|
for (const match of fileMatches) {
|
|
231
248
|
const matchLines = match.text.split("\n");
|
|
232
249
|
for (let index = 0; index < matchLines.length; index++) {
|
|
233
250
|
const lineNumber = match.startLine + index;
|
|
234
251
|
const isMatch = index === 0;
|
|
235
252
|
const line = matchLines[index] ?? "";
|
|
236
|
-
modelOut.push(
|
|
253
|
+
modelOut.push(
|
|
254
|
+
formatMatchLine(lineNumber, line, isMatch, { useHashLines: hashContext !== undefined }),
|
|
255
|
+
);
|
|
237
256
|
displayOut.push(formatCodeFrameLine(isMatch ? "*" : " ", lineNumber, line, lineNumberWidth));
|
|
257
|
+
cacheEntries.push([lineNumber, line] as const);
|
|
238
258
|
}
|
|
239
259
|
if (match.metaVariables && Object.keys(match.metaVariables).length > 0) {
|
|
240
260
|
const serializedMeta = Object.entries(match.metaVariables)
|
|
@@ -246,19 +266,39 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
246
266
|
}
|
|
247
267
|
fileMatchCounts.set(relativePath, (fileMatchCounts.get(relativePath) ?? 0) + 1);
|
|
248
268
|
}
|
|
269
|
+
if (hashContext && cacheEntries.length > 0) {
|
|
270
|
+
getFileReadCache(this.session).recordSparse(hashContext.absolutePath, cacheEntries, {
|
|
271
|
+
fileHash: hashContext.fileHash,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
249
274
|
return { model: modelOut, display: displayOut };
|
|
250
275
|
};
|
|
251
276
|
|
|
252
277
|
if (isDirectory) {
|
|
253
278
|
const grouped = formatGroupedFiles(fileList, relativePath => {
|
|
254
279
|
const rendered = renderMatchesForFile(relativePath);
|
|
255
|
-
|
|
280
|
+
const hashContext = hashContexts.get(relativePath);
|
|
281
|
+
return {
|
|
282
|
+
modelLines: rendered.model,
|
|
283
|
+
displayLines: rendered.display,
|
|
284
|
+
headerSuffix: hashContext ? `#${hashContext.fileHash}` : "",
|
|
285
|
+
skip: rendered.model.length === 0,
|
|
286
|
+
};
|
|
256
287
|
});
|
|
257
288
|
outputLines.push(...grouped.model);
|
|
258
289
|
displayLines.push(...grouped.display);
|
|
259
290
|
} else {
|
|
260
291
|
for (const relativePath of fileList) {
|
|
261
292
|
const rendered = renderMatchesForFile(relativePath);
|
|
293
|
+
if (rendered.model.length === 0) continue;
|
|
294
|
+
if (outputLines.length > 0) {
|
|
295
|
+
outputLines.push("");
|
|
296
|
+
displayLines.push("");
|
|
297
|
+
}
|
|
298
|
+
const hashContext = hashContexts.get(relativePath);
|
|
299
|
+
if (hashContext) {
|
|
300
|
+
outputLines.push(formatHashlineHeader(relativePath, hashContext.fileHash));
|
|
301
|
+
}
|
|
262
302
|
outputLines.push(...rendered.model);
|
|
263
303
|
displayLines.push(...rendered.display);
|
|
264
304
|
}
|
|
@@ -385,7 +425,8 @@ export const astGrepToolRenderer = {
|
|
|
385
425
|
const fileName = line
|
|
386
426
|
.slice(3)
|
|
387
427
|
.trimEnd()
|
|
388
|
-
.replace(/\s+\([^)]*\)\s*$/, "")
|
|
428
|
+
.replace(/\s+\([^)]*\)\s*$/, "")
|
|
429
|
+
.replace(/#[0-9a-f]+$/, "");
|
|
389
430
|
const absPath = contextDir && fileName ? path.join(contextDir, fileName) : undefined;
|
|
390
431
|
const styled = uiTheme.fg("dim", line);
|
|
391
432
|
return absPath ? fileHyperlink(absPath, styled) : styled;
|
|
@@ -396,7 +437,7 @@ export const astGrepToolRenderer = {
|
|
|
396
437
|
.trimEnd()
|
|
397
438
|
.replace(/\s+\([^)]*\)\s*$/, "");
|
|
398
439
|
const isDirectory = raw.endsWith("/");
|
|
399
|
-
const name = raw.replace(/\/$/, "");
|
|
440
|
+
const name = isDirectory ? raw.replace(/\/$/, "") : raw.replace(/#[0-9a-f]+$/, "");
|
|
400
441
|
if (isDirectory) {
|
|
401
442
|
if (searchBase) {
|
|
402
443
|
contextDir = name === "." ? searchBase : path.join(searchBase, name);
|
|
@@ -575,8 +575,10 @@ export class WorkerCore {
|
|
|
575
575
|
if (signal.aborted) onCancel();
|
|
576
576
|
else signal.addEventListener("abort", onCancel, { once: true });
|
|
577
577
|
try {
|
|
578
|
+
const hooks = this.#hooksForActiveRun();
|
|
579
|
+
if (!hooks) throw new ToolError("Browser runtime started without an active run");
|
|
578
580
|
const returnValue = await Promise.race([
|
|
579
|
-
runtime.run(msg.code, `browser-run-${msg.id}.js
|
|
581
|
+
runtime.run(msg.code, `browser-run-${msg.id}.js`, hooks, { runId: msg.id, cwd: msg.session.cwd }),
|
|
580
582
|
cancelRejection,
|
|
581
583
|
]);
|
|
582
584
|
await this.#postReadyInfo();
|
|
@@ -601,7 +603,6 @@ export class WorkerCore {
|
|
|
601
603
|
this.#runtime = new JsRuntime({
|
|
602
604
|
initialCwd: session.cwd,
|
|
603
605
|
sessionId: `browser-tab-${this.#targetId ?? "unknown"}`,
|
|
604
|
-
getHooks: () => this.#hooksForActiveRun(),
|
|
605
606
|
});
|
|
606
607
|
return this.#runtime;
|
|
607
608
|
}
|
package/src/tools/eval.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { prompt } from "@oh-my-pi/pi-utils";
|
|
|
6
6
|
import * as z from "zod/v4";
|
|
7
7
|
import { jsBackend, pythonBackend } from "../eval";
|
|
8
8
|
import type { ExecutorBackend } from "../eval/backend";
|
|
9
|
+
import { defaultEvalSessionId } from "../eval/session-id";
|
|
9
10
|
import type { EvalCellResult, EvalDisplayOutput, EvalLanguage, EvalStatusEvent, EvalToolDetails } from "../eval/types";
|
|
10
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
12
|
import { truncateToVisualLines } from "../modes/components/visual-truncate";
|
|
@@ -347,7 +348,7 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
|
|
|
347
348
|
pushUpdate();
|
|
348
349
|
},
|
|
349
350
|
});
|
|
350
|
-
const sessionId =
|
|
351
|
+
const sessionId = session.getEvalSessionId?.() ?? defaultEvalSessionId(session);
|
|
351
352
|
|
|
352
353
|
for (let i = 0; i < cells.length; i++) {
|
|
353
354
|
const cell = cells[i];
|
package/src/tools/fetch.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type { Settings } from "../config/settings";
|
|
|
10
10
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
11
|
import { type Theme, theme } from "../modes/theme/theme";
|
|
12
12
|
import type { ToolSession } from "../sdk";
|
|
13
|
+
import type { AgentStorage } from "../session/agent-storage";
|
|
13
14
|
import { DEFAULT_MAX_BYTES, truncateHead } from "../session/streaming-output";
|
|
14
15
|
import { renderStatusLine } from "../tui";
|
|
15
16
|
import { CachedOutputBlock } from "../tui/output-block";
|
|
@@ -542,7 +543,8 @@ async function renderHtmlToText(
|
|
|
542
543
|
html: string,
|
|
543
544
|
timeout: number,
|
|
544
545
|
settings: Settings,
|
|
545
|
-
userSignal
|
|
546
|
+
userSignal: AbortSignal | undefined,
|
|
547
|
+
storage: AgentStorage | null,
|
|
546
548
|
): Promise<{ content: string; ok: boolean; method: string }> {
|
|
547
549
|
const signal = ptree.combineSignals(userSignal, timeout * 1000);
|
|
548
550
|
const execOptions = {
|
|
@@ -554,14 +556,18 @@ async function renderHtmlToText(
|
|
|
554
556
|
};
|
|
555
557
|
|
|
556
558
|
// Try Parallel extract first when credentials are configured
|
|
557
|
-
if (settings.get("providers.parallelFetch") &&
|
|
559
|
+
if (settings.get("providers.parallelFetch") && findParallelApiKey(storage)) {
|
|
558
560
|
try {
|
|
559
|
-
const parallelResult = await extractWithParallel(
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
561
|
+
const parallelResult = await extractWithParallel(
|
|
562
|
+
[url],
|
|
563
|
+
{
|
|
564
|
+
objective: "Extract the main content",
|
|
565
|
+
excerpts: true,
|
|
566
|
+
fullContent: false,
|
|
567
|
+
signal,
|
|
568
|
+
},
|
|
569
|
+
storage,
|
|
570
|
+
);
|
|
565
571
|
const firstDocument = parallelResult.results[0];
|
|
566
572
|
if (firstDocument) {
|
|
567
573
|
const content = getParallelExtractContent(firstDocument);
|
|
@@ -682,13 +688,14 @@ type FetchRenderResult = RenderResult & {
|
|
|
682
688
|
async function handleSpecialUrls(
|
|
683
689
|
url: string,
|
|
684
690
|
timeout: number,
|
|
685
|
-
signal
|
|
691
|
+
signal: AbortSignal | undefined,
|
|
692
|
+
storage: AgentStorage | null,
|
|
686
693
|
): Promise<FetchRenderResult | null> {
|
|
687
694
|
for (const handler of specialHandlers) {
|
|
688
695
|
if (signal?.aborted) {
|
|
689
696
|
throw new ToolAbortError();
|
|
690
697
|
}
|
|
691
|
-
const result = await handler(url, timeout, signal);
|
|
698
|
+
const result = await handler(url, timeout, signal, storage);
|
|
692
699
|
if (result) return result;
|
|
693
700
|
}
|
|
694
701
|
return null;
|
|
@@ -706,7 +713,8 @@ async function renderUrl(
|
|
|
706
713
|
timeout: number,
|
|
707
714
|
raw: boolean,
|
|
708
715
|
settings: Settings,
|
|
709
|
-
signal
|
|
716
|
+
signal: AbortSignal | undefined,
|
|
717
|
+
storage: AgentStorage | null,
|
|
710
718
|
): Promise<FetchRenderResult> {
|
|
711
719
|
const notes: string[] = [];
|
|
712
720
|
const fetchedAt = new Date().toISOString();
|
|
@@ -733,7 +741,7 @@ async function renderUrl(
|
|
|
733
741
|
|
|
734
742
|
// Step 1: Try special handlers for known sites (unless raw mode)
|
|
735
743
|
if (!raw) {
|
|
736
|
-
const specialResult = await handleSpecialUrls(url, timeout, signal);
|
|
744
|
+
const specialResult = await handleSpecialUrls(url, timeout, signal, storage);
|
|
737
745
|
if (specialResult) return specialResult;
|
|
738
746
|
}
|
|
739
747
|
|
|
@@ -1051,7 +1059,7 @@ async function renderUrl(
|
|
|
1051
1059
|
}
|
|
1052
1060
|
|
|
1053
1061
|
// 5E: Render HTML with lynx or html2text
|
|
1054
|
-
const htmlResult = await renderHtmlToText(finalUrl, rawContent, timeout, settings, signal);
|
|
1062
|
+
const htmlResult = await renderHtmlToText(finalUrl, rawContent, timeout, settings, signal, storage);
|
|
1055
1063
|
if (!htmlResult.ok) {
|
|
1056
1064
|
notes.push("html rendering failed (lynx/html2text unavailable)");
|
|
1057
1065
|
const output = finalizeOutput(rawContent);
|
|
@@ -1233,7 +1241,8 @@ async function buildReadUrlCacheEntry(
|
|
|
1233
1241
|
throw new ToolAbortError();
|
|
1234
1242
|
}
|
|
1235
1243
|
|
|
1236
|
-
const
|
|
1244
|
+
const storage = session.settings.getStorage();
|
|
1245
|
+
const result = await renderUrl(url, effectiveTimeout, raw, session.settings, signal, storage);
|
|
1237
1246
|
const output = buildUrlReadOutput(result, result.content);
|
|
1238
1247
|
const artifactId = options?.ensureArtifact ? await persistReadUrlArtifact(session, output) : undefined;
|
|
1239
1248
|
|
package/src/tools/index.ts
CHANGED
|
@@ -91,7 +91,6 @@ export * from "./search";
|
|
|
91
91
|
export * from "./search-tool-bm25";
|
|
92
92
|
export * from "./ssh";
|
|
93
93
|
export * from "./todo-write";
|
|
94
|
-
export * from "./vim";
|
|
95
94
|
export * from "./write";
|
|
96
95
|
export * from "./yield";
|
|
97
96
|
|
|
@@ -104,7 +103,6 @@ export type ContextFileEntry = {
|
|
|
104
103
|
depth?: number;
|
|
105
104
|
};
|
|
106
105
|
|
|
107
|
-
export type { DiscoverableMCPTool } from "../mcp/discoverable-tool-metadata";
|
|
108
106
|
export type {
|
|
109
107
|
DiscoverableTool,
|
|
110
108
|
DiscoverableToolSearchIndex,
|
|
@@ -140,6 +138,8 @@ export interface ToolSession {
|
|
|
140
138
|
requireYieldTool?: boolean;
|
|
141
139
|
/** Task recursion depth (0 = top-level, 1 = first child, etc.) */
|
|
142
140
|
taskDepth?: number;
|
|
141
|
+
/** Get shared eval executor session ID. Subagents inherit this to share JS/Python state. */
|
|
142
|
+
getEvalSessionId?: () => string | null;
|
|
143
143
|
/** Get session file */
|
|
144
144
|
getSessionFile: () => string | null;
|
|
145
145
|
/** Get eval kernel owner ID for session-scoped retained-kernel cleanup. */
|
|
@@ -194,12 +194,6 @@ export interface ToolSession {
|
|
|
194
194
|
setTodoPhases?: (phases: TodoPhase[]) => void;
|
|
195
195
|
/** Whether MCP tool discovery is active for this session. */
|
|
196
196
|
isMCPDiscoveryEnabled?: () => boolean;
|
|
197
|
-
/** Get hidden-but-discoverable MCP tools for search_tool_bm25 prompts and fallbacks.
|
|
198
|
-
* @deprecated Use getDiscoverableTools with source filter instead. */
|
|
199
|
-
getDiscoverableMCPTools?: () => import("../mcp/discoverable-tool-metadata").DiscoverableMCPTool[];
|
|
200
|
-
/** Get the cached discoverable MCP search index for search_tool_bm25 execution.
|
|
201
|
-
* @deprecated Use getDiscoverableToolSearchIndex instead. */
|
|
202
|
-
getDiscoverableMCPSearchIndex?: () => import("../tool-discovery/tool-index").DiscoverableMCPSearchIndex;
|
|
203
197
|
/** Get MCP tools activated by prior search_tool_bm25 calls. */
|
|
204
198
|
getSelectedMCPToolNames?: () => string[];
|
|
205
199
|
/** Merge MCP tool selections into the active session tool set. */
|