@oh-my-pi/pi-coding-agent 12.19.3 → 13.0.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 +47 -0
- package/package.json +7 -7
- package/src/commit/prompts/analysis-system.md +3 -3
- package/src/commit/prompts/analysis-user.md +14 -14
- package/src/commit/prompts/changelog-system.md +4 -4
- package/src/commit/prompts/changelog-user.md +4 -4
- package/src/commit/prompts/file-observer-system.md +2 -2
- package/src/commit/prompts/file-observer-user.md +2 -2
- package/src/commit/prompts/reduce-system.md +4 -4
- package/src/commit/prompts/reduce-user.md +6 -6
- package/src/commit/prompts/summary-system.md +4 -4
- package/src/commit/prompts/summary-user.md +6 -6
- package/src/discovery/helpers.ts +13 -1
- package/src/internal-urls/docs-index.generated.ts +2 -2
- package/src/internal-urls/index.ts +8 -3
- package/src/internal-urls/local-protocol.ts +223 -0
- package/src/internal-urls/{docs-protocol.ts → pi-protocol.ts} +12 -12
- package/src/internal-urls/router.ts +1 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/ipy/executor.ts +4 -32
- package/src/memories/index.ts +1 -1
- package/src/modes/controllers/event-controller.ts +4 -4
- package/src/modes/interactive-mode.ts +84 -64
- package/src/modes/types.ts +11 -3
- package/src/modes/utils/ui-helpers.ts +5 -3
- package/src/patch/hashline.ts +42 -42
- package/src/patch/index.ts +106 -153
- package/src/patch/shared.ts +21 -51
- package/src/plan-mode/approved-plan.ts +55 -0
- package/src/prompts/agents/designer.md +6 -6
- package/src/prompts/agents/explore.md +4 -4
- package/src/prompts/agents/frontmatter.md +1 -0
- package/src/prompts/agents/init.md +10 -10
- package/src/prompts/agents/plan.md +6 -6
- package/src/prompts/agents/reviewer.md +4 -3
- package/src/prompts/agents/task.md +10 -10
- package/src/prompts/compaction/branch-summary.md +3 -3
- package/src/prompts/compaction/compaction-short-summary.md +7 -7
- package/src/prompts/compaction/compaction-summary-context.md +1 -1
- package/src/prompts/compaction/compaction-summary.md +5 -5
- package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
- package/src/prompts/compaction/compaction-update-summary.md +11 -11
- package/src/prompts/memories/consolidation.md +5 -5
- package/src/prompts/memories/read-path.md +11 -0
- package/src/prompts/memories/stage_one_input.md +1 -1
- package/src/prompts/memories/stage_one_system.md +5 -5
- package/src/prompts/review-request.md +4 -4
- package/src/prompts/system/agent-creation-architect.md +21 -21
- package/src/prompts/system/agent-creation-user.md +2 -2
- package/src/prompts/system/custom-system-prompt.md +6 -6
- package/src/prompts/system/plan-mode-active.md +20 -20
- package/src/prompts/system/plan-mode-approved.md +9 -7
- package/src/prompts/system/plan-mode-reference.md +2 -2
- package/src/prompts/system/plan-mode-subagent.md +8 -8
- package/src/prompts/system/subagent-submit-reminder.md +5 -5
- package/src/prompts/system/subagent-system-prompt.md +9 -9
- package/src/prompts/system/subagent-user-prompt.md +3 -5
- package/src/prompts/system/summarization-system.md +1 -1
- package/src/prompts/system/system-prompt.md +109 -84
- package/src/prompts/system/title-system.md +2 -2
- package/src/prompts/system/ttsr-interrupt.md +2 -2
- package/src/prompts/system/web-search.md +16 -16
- package/src/prompts/tools/ask.md +6 -6
- package/src/prompts/tools/bash.md +9 -9
- package/src/prompts/tools/browser.md +5 -5
- package/src/prompts/tools/cancel-job.md +2 -2
- package/src/prompts/tools/exit-plan-mode.md +13 -10
- package/src/prompts/tools/find.md +2 -2
- package/src/prompts/tools/gemini-image.md +7 -7
- package/src/prompts/tools/grep.md +4 -3
- package/src/prompts/tools/hashline.md +55 -56
- package/src/prompts/tools/patch.md +6 -6
- package/src/prompts/tools/poll-jobs.md +1 -1
- package/src/prompts/tools/python.md +10 -12
- package/src/prompts/tools/read.md +2 -12
- package/src/prompts/tools/replace.md +7 -7
- package/src/prompts/tools/ssh.md +2 -7
- package/src/prompts/tools/task.md +48 -38
- package/src/prompts/tools/todo-write.md +65 -49
- package/src/prompts/tools/web-search.md +2 -2
- package/src/prompts/tools/write.md +4 -3
- package/src/sdk.ts +11 -9
- package/src/session/agent-session.ts +92 -51
- package/src/session/artifacts.ts +1 -1
- package/src/session/messages.ts +1 -0
- package/src/task/agents.ts +1 -0
- package/src/task/index.ts +2 -1
- package/src/task/render.ts +2 -2
- package/src/task/types.ts +1 -0
- package/src/tools/bash-interactive.ts +1 -1
- package/src/tools/bash-skill-urls.ts +3 -2
- package/src/tools/bash.ts +21 -12
- package/src/tools/exit-plan-mode.ts +30 -2
- package/src/tools/grep.ts +131 -75
- package/src/tools/index.ts +13 -3
- package/src/tools/path-utils.ts +2 -1
- package/src/tools/plan-mode-guard.ts +8 -8
- package/src/tools/python.ts +0 -2
- package/src/tools/read.ts +2 -2
- package/src/tools/todo-write.ts +276 -146
- package/src/internal-urls/plan-protocol.ts +0 -95
- package/src/modes/components/todo-display.ts +0 -114
- package/src/prompts/memories/read_path.md +0 -11
package/src/tools/grep.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
|
|
4
|
-
import { type GrepResult, grep } from "@oh-my-pi/pi-natives";
|
|
4
|
+
import { type GrepMatch, type GrepResult, grep } from "@oh-my-pi/pi-natives";
|
|
5
5
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
6
6
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
7
7
|
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
@@ -30,13 +30,13 @@ const grepSchema = Type.Object({
|
|
|
30
30
|
pre: Type.Optional(Type.Number({ description: "Lines of context before matches" })),
|
|
31
31
|
post: Type.Optional(Type.Number({ description: "Lines of context after matches" })),
|
|
32
32
|
multiline: Type.Optional(Type.Boolean({ description: "Enable multiline matching" })),
|
|
33
|
-
limit: Type.Optional(Type.Number({ description: "Limit output to first N matches (default:
|
|
33
|
+
limit: Type.Optional(Type.Number({ description: "Limit output to first N matches (default: 20)" })),
|
|
34
34
|
offset: Type.Optional(Type.Number({ description: "Skip first N entries before applying limit (default: 0)" })),
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
export type GrepToolInput = Static<typeof grepSchema>;
|
|
38
38
|
|
|
39
|
-
const DEFAULT_MATCH_LIMIT =
|
|
39
|
+
const DEFAULT_MATCH_LIMIT = 20;
|
|
40
40
|
|
|
41
41
|
export interface GrepToolDetails {
|
|
42
42
|
truncation?: TruncationResult;
|
|
@@ -130,6 +130,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
130
130
|
|
|
131
131
|
const effectiveOutputMode = "content";
|
|
132
132
|
const effectiveLimit = normalizedLimit ?? DEFAULT_MATCH_LIMIT;
|
|
133
|
+
const internalLimit = Math.min(effectiveLimit * 5, 2000);
|
|
133
134
|
|
|
134
135
|
// Run grep
|
|
135
136
|
let result: GrepResult;
|
|
@@ -143,7 +144,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
143
144
|
multiline: effectiveMultiline,
|
|
144
145
|
hidden: true,
|
|
145
146
|
cache: false,
|
|
146
|
-
maxCount:
|
|
147
|
+
maxCount: internalLimit,
|
|
147
148
|
offset: normalizedOffset > 0 ? normalizedOffset : undefined,
|
|
148
149
|
contextBefore: normalizedContextBefore,
|
|
149
150
|
contextAfter: normalizedContextAfter,
|
|
@@ -167,19 +168,49 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
167
168
|
};
|
|
168
169
|
|
|
169
170
|
// Build output
|
|
171
|
+
const roundRobinSelect = (matches: GrepMatch[], limit: number): GrepMatch[] => {
|
|
172
|
+
if (matches.length <= limit) return matches;
|
|
173
|
+
const fileOrder: string[] = [];
|
|
174
|
+
const byFile = new Map<string, GrepMatch[]>();
|
|
175
|
+
for (const match of matches) {
|
|
176
|
+
if (!byFile.has(match.path)) {
|
|
177
|
+
fileOrder.push(match.path);
|
|
178
|
+
byFile.set(match.path, []);
|
|
179
|
+
}
|
|
180
|
+
byFile.get(match.path)!.push(match);
|
|
181
|
+
}
|
|
182
|
+
const selected: GrepMatch[] = [];
|
|
183
|
+
const indices = new Map<string, number>(fileOrder.map(file => [file, 0]));
|
|
184
|
+
while (selected.length < limit) {
|
|
185
|
+
let anyAdded = false;
|
|
186
|
+
for (const file of fileOrder) {
|
|
187
|
+
if (selected.length >= limit) break;
|
|
188
|
+
const fileMatches = byFile.get(file)!;
|
|
189
|
+
const idx = indices.get(file)!;
|
|
190
|
+
if (idx < fileMatches.length) {
|
|
191
|
+
selected.push(fileMatches[idx]);
|
|
192
|
+
indices.set(file, idx + 1);
|
|
193
|
+
anyAdded = true;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (!anyAdded) break;
|
|
197
|
+
}
|
|
198
|
+
return selected;
|
|
199
|
+
};
|
|
200
|
+
const selectedMatches = isDirectory
|
|
201
|
+
? roundRobinSelect(result.matches, effectiveLimit)
|
|
202
|
+
: result.matches.slice(0, effectiveLimit);
|
|
203
|
+
const matchLimitReached = result.matches.length > effectiveLimit;
|
|
170
204
|
const files = new Set<string>();
|
|
171
205
|
const fileList: string[] = [];
|
|
172
206
|
const fileMatchCounts = new Map<string, number>();
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
files.add(relative);
|
|
178
|
-
fileList.push(relative);
|
|
207
|
+
const recordFile = (relativePath: string) => {
|
|
208
|
+
if (!files.has(relativePath)) {
|
|
209
|
+
files.add(relativePath);
|
|
210
|
+
fileList.push(relativePath);
|
|
179
211
|
}
|
|
180
212
|
};
|
|
181
|
-
|
|
182
|
-
if (result.totalMatches === 0) {
|
|
213
|
+
if (selectedMatches.length === 0) {
|
|
183
214
|
const details: GrepToolDetails = {
|
|
184
215
|
scopePath,
|
|
185
216
|
matchCount: 0,
|
|
@@ -189,100 +220,120 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
|
|
|
189
220
|
};
|
|
190
221
|
return toolResult(details).text("No matches found").done();
|
|
191
222
|
}
|
|
192
|
-
|
|
193
223
|
const outputLines: string[] = [];
|
|
194
224
|
let linesTruncated = false;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
for (const match of result.matches) {
|
|
198
|
-
recordFile(match.path);
|
|
225
|
+
const matchesByFile = new Map<string, GrepMatch[]>();
|
|
226
|
+
for (const match of selectedMatches) {
|
|
199
227
|
const relativePath = formatPath(match.path);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
outputLines.push("");
|
|
228
|
+
recordFile(relativePath);
|
|
229
|
+
if (!matchesByFile.has(relativePath)) {
|
|
230
|
+
matchesByFile.set(relativePath, []);
|
|
204
231
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
232
|
+
matchesByFile.get(relativePath)!.push(match);
|
|
233
|
+
}
|
|
234
|
+
const renderMatchesForFile = (relativePath: string) => {
|
|
235
|
+
const fileMatches = matchesByFile.get(relativePath) ?? [];
|
|
236
|
+
for (const match of fileMatches) {
|
|
237
|
+
const lineNumbers: number[] = [match.lineNumber];
|
|
238
|
+
if (match.contextBefore) {
|
|
239
|
+
for (const ctx of match.contextBefore) {
|
|
240
|
+
lineNumbers.push(ctx.lineNumber);
|
|
241
|
+
}
|
|
211
242
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
243
|
+
if (match.contextAfter) {
|
|
244
|
+
for (const ctx of match.contextAfter) {
|
|
245
|
+
lineNumbers.push(ctx.lineNumber);
|
|
246
|
+
}
|
|
216
247
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
248
|
+
const lineWidth = Math.max(...lineNumbers.map(value => value.toString().length));
|
|
249
|
+
const formatLine = (lineNumber: number, line: string, isMatch: boolean): string => {
|
|
250
|
+
if (useHashLines) {
|
|
251
|
+
const ref = `${lineNumber}#${computeLineHash(lineNumber, line)}`;
|
|
252
|
+
return isMatch ? `>>${ref}:${line}` : ` ${ref}:${line}`;
|
|
253
|
+
}
|
|
254
|
+
const padded = lineNumber.toString().padStart(lineWidth, " ");
|
|
255
|
+
return isMatch ? `>>${padded}:${line}` : ` ${padded}:${line}`;
|
|
256
|
+
};
|
|
257
|
+
if (match.contextBefore) {
|
|
258
|
+
for (const ctx of match.contextBefore) {
|
|
259
|
+
outputLines.push(formatLine(ctx.lineNumber, ctx.line, false));
|
|
260
|
+
}
|
|
224
261
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
262
|
+
outputLines.push(formatLine(match.lineNumber, match.line, true));
|
|
263
|
+
if (match.truncated) {
|
|
264
|
+
linesTruncated = true;
|
|
265
|
+
}
|
|
266
|
+
if (match.contextAfter) {
|
|
267
|
+
for (const ctx of match.contextAfter) {
|
|
268
|
+
outputLines.push(formatLine(ctx.lineNumber, ctx.line, false));
|
|
269
|
+
}
|
|
233
270
|
}
|
|
271
|
+
fileMatchCounts.set(relativePath, (fileMatchCounts.get(relativePath) ?? 0) + 1);
|
|
234
272
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
273
|
+
};
|
|
274
|
+
if (isDirectory) {
|
|
275
|
+
const filesByDirectory = new Map<string, string[]>();
|
|
276
|
+
for (const relativePath of fileList) {
|
|
277
|
+
const directory = path.dirname(relativePath).replace(/\\/g, "/");
|
|
278
|
+
if (!filesByDirectory.has(directory)) {
|
|
279
|
+
filesByDirectory.set(directory, []);
|
|
280
|
+
}
|
|
281
|
+
filesByDirectory.get(directory)!.push(relativePath);
|
|
241
282
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
283
|
+
for (const [directory, directoryFiles] of filesByDirectory) {
|
|
284
|
+
if (directory === ".") {
|
|
285
|
+
for (const relativePath of directoryFiles) {
|
|
286
|
+
if (outputLines.length > 0) {
|
|
287
|
+
outputLines.push("");
|
|
288
|
+
}
|
|
289
|
+
outputLines.push(`# ${path.basename(relativePath)}`);
|
|
290
|
+
renderMatchesForFile(relativePath);
|
|
291
|
+
}
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (outputLines.length > 0) {
|
|
295
|
+
outputLines.push("");
|
|
296
|
+
}
|
|
297
|
+
outputLines.push(`# ${directory}`);
|
|
298
|
+
for (const relativePath of directoryFiles) {
|
|
299
|
+
outputLines.push(`## └─ ${path.basename(relativePath)}`);
|
|
300
|
+
renderMatchesForFile(relativePath);
|
|
247
301
|
}
|
|
248
302
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
303
|
+
} else {
|
|
304
|
+
for (const relativePath of fileList) {
|
|
305
|
+
renderMatchesForFile(relativePath);
|
|
306
|
+
}
|
|
252
307
|
}
|
|
253
|
-
|
|
254
308
|
const rawOutput = outputLines.join("\n");
|
|
255
309
|
const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
256
310
|
const output = truncation.content;
|
|
257
|
-
|
|
258
|
-
const truncated = Boolean(result.limitReached || truncation.truncated || linesTruncated);
|
|
311
|
+
const truncated = Boolean(matchLimitReached || result.limitReached || truncation.truncated || linesTruncated);
|
|
259
312
|
const details: GrepToolDetails = {
|
|
260
313
|
scopePath,
|
|
261
|
-
matchCount:
|
|
262
|
-
fileCount:
|
|
314
|
+
matchCount: selectedMatches.length,
|
|
315
|
+
fileCount: fileList.length,
|
|
263
316
|
files: fileList,
|
|
264
317
|
fileMatches: fileList.map(path => ({
|
|
265
318
|
path,
|
|
266
319
|
count: fileMatchCounts.get(path) ?? 0,
|
|
267
320
|
})),
|
|
268
321
|
truncated,
|
|
269
|
-
matchLimitReached:
|
|
322
|
+
matchLimitReached: matchLimitReached ? effectiveLimit : undefined,
|
|
323
|
+
resultLimitReached: result.limitReached ? internalLimit : undefined,
|
|
270
324
|
};
|
|
271
|
-
|
|
272
325
|
if (truncation.truncated) details.truncation = truncation;
|
|
273
326
|
if (linesTruncated) details.linesTruncated = true;
|
|
274
|
-
|
|
275
327
|
const resultBuilder = toolResult(details)
|
|
276
328
|
.text(output)
|
|
277
329
|
.limits({
|
|
278
|
-
matchLimit:
|
|
330
|
+
matchLimit: matchLimitReached ? effectiveLimit : undefined,
|
|
331
|
+
resultLimit: result.limitReached ? internalLimit : undefined,
|
|
279
332
|
columnMax: linesTruncated ? DEFAULT_MAX_COLUMN : undefined,
|
|
280
333
|
});
|
|
281
|
-
|
|
282
334
|
if (truncation.truncated) {
|
|
283
335
|
resultBuilder.truncation(truncation, { direction: "head" });
|
|
284
336
|
}
|
|
285
|
-
|
|
286
337
|
return resultBuilder.done();
|
|
287
338
|
});
|
|
288
339
|
}
|
|
@@ -428,9 +479,9 @@ export const grepToolRenderer = {
|
|
|
428
479
|
}
|
|
429
480
|
if (current.length > 0) matchGroups.push(current);
|
|
430
481
|
} else {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
matchGroups.push(
|
|
482
|
+
const nonEmpty = rawLines.filter(line => line.trim().length > 0);
|
|
483
|
+
if (nonEmpty.length > 0) {
|
|
484
|
+
matchGroups.push(nonEmpty);
|
|
434
485
|
}
|
|
435
486
|
}
|
|
436
487
|
|
|
@@ -472,7 +523,12 @@ export const grepToolRenderer = {
|
|
|
472
523
|
expanded,
|
|
473
524
|
maxCollapsed,
|
|
474
525
|
itemType: "match",
|
|
475
|
-
renderItem: group =>
|
|
526
|
+
renderItem: group =>
|
|
527
|
+
group.map(line => {
|
|
528
|
+
if (line.startsWith("## ")) return uiTheme.fg("dim", line);
|
|
529
|
+
if (line.startsWith("# ")) return uiTheme.fg("accent", line);
|
|
530
|
+
return uiTheme.fg("toolOutput", line);
|
|
531
|
+
}),
|
|
476
532
|
},
|
|
477
533
|
uiTheme,
|
|
478
534
|
);
|
package/src/tools/index.ts
CHANGED
|
@@ -31,7 +31,7 @@ import { ReadTool } from "./read";
|
|
|
31
31
|
import { reportFindingTool } from "./review";
|
|
32
32
|
import { loadSshTool } from "./ssh";
|
|
33
33
|
import { SubmitResultTool } from "./submit-result";
|
|
34
|
-
import { TodoWriteTool } from "./todo-write";
|
|
34
|
+
import { type TodoPhase, TodoWriteTool } from "./todo-write";
|
|
35
35
|
import { WriteTool } from "./write";
|
|
36
36
|
|
|
37
37
|
// Exa MCP tools (22 tools)
|
|
@@ -70,7 +70,13 @@ export { ReadTool, type ReadToolDetails, type ReadToolInput } from "./read";
|
|
|
70
70
|
export { reportFindingTool, type SubmitReviewDetails } from "./review";
|
|
71
71
|
export { loadSshTool, type SSHToolDetails, SshTool } from "./ssh";
|
|
72
72
|
export { SubmitResultTool } from "./submit-result";
|
|
73
|
-
export {
|
|
73
|
+
export {
|
|
74
|
+
getLatestTodoPhasesFromEntries,
|
|
75
|
+
type TodoItem,
|
|
76
|
+
type TodoPhase,
|
|
77
|
+
TodoWriteTool,
|
|
78
|
+
type TodoWriteToolDetails,
|
|
79
|
+
} from "./todo-write";
|
|
74
80
|
export { WriteTool, type WriteToolDetails, type WriteToolInput } from "./write";
|
|
75
81
|
|
|
76
82
|
/** Tool type (AgentTool from pi-ai) */
|
|
@@ -112,7 +118,7 @@ export interface ToolSession {
|
|
|
112
118
|
getSessionFile: () => string | null;
|
|
113
119
|
/** Get session ID */
|
|
114
120
|
getSessionId?: () => string | null;
|
|
115
|
-
/** Get artifacts directory for artifact:// URLs
|
|
121
|
+
/** Get artifacts directory for artifact:// URLs */
|
|
116
122
|
getArtifactsDir?: () => string | null;
|
|
117
123
|
/** Allocate a new artifact path and ID for session-scoped truncated output. */
|
|
118
124
|
allocateOutputArtifact?: (toolType: string) => Promise<{ id?: string; path?: string }>;
|
|
@@ -140,6 +146,10 @@ export interface ToolSession {
|
|
|
140
146
|
getPlanModeState?: () => PlanModeState | undefined;
|
|
141
147
|
/** Get compact conversation context for subagents (excludes tool results, system prompts) */
|
|
142
148
|
getCompactContext?: () => string;
|
|
149
|
+
/** Get cached todo phases for this session. */
|
|
150
|
+
getTodoPhases?: () => TodoPhase[];
|
|
151
|
+
/** Replace cached todo phases for this session. */
|
|
152
|
+
setTodoPhases?: (phases: TodoPhase[]) => void;
|
|
143
153
|
}
|
|
144
154
|
|
|
145
155
|
type ToolFactory = (session: ToolSession) => Tool | null | Promise<Tool | null>;
|
package/src/tools/path-utils.ts
CHANGED
|
@@ -50,7 +50,8 @@ function normalizeAtPrefix(filePath: string): string {
|
|
|
50
50
|
withoutAt.startsWith("agent://") ||
|
|
51
51
|
withoutAt.startsWith("artifact://") ||
|
|
52
52
|
withoutAt.startsWith("skill://") ||
|
|
53
|
-
withoutAt.startsWith("rule://")
|
|
53
|
+
withoutAt.startsWith("rule://") ||
|
|
54
|
+
withoutAt.startsWith("local://")
|
|
54
55
|
) {
|
|
55
56
|
return withoutAt;
|
|
56
57
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveLocalUrlToPath } from "../internal-urls";
|
|
2
2
|
import type { ToolSession } from ".";
|
|
3
3
|
import { resolveToCwd } from "./path-utils";
|
|
4
4
|
import { ToolError } from "./tool-errors";
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const LOCAL_URL_PREFIX = "local://";
|
|
7
7
|
|
|
8
8
|
export function resolvePlanPath(session: ToolSession, targetPath: string): string {
|
|
9
|
-
if (
|
|
10
|
-
return
|
|
9
|
+
if (targetPath.startsWith(LOCAL_URL_PREFIX)) {
|
|
10
|
+
return resolveLocalUrlToPath(targetPath, {
|
|
11
|
+
getArtifactsDir: session.getArtifactsDir,
|
|
12
|
+
getSessionId: session.getSessionId,
|
|
13
|
+
});
|
|
11
14
|
}
|
|
12
15
|
|
|
13
|
-
return
|
|
14
|
-
getPlansDirectory: () => session.settings.getPlansDirectory(),
|
|
15
|
-
cwd: session.cwd,
|
|
16
|
-
});
|
|
16
|
+
return resolveToCwd(targetPath, session.cwd);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function enforcePlanModeWrite(
|
package/src/tools/python.ts
CHANGED
|
@@ -253,7 +253,6 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
253
253
|
};
|
|
254
254
|
|
|
255
255
|
const sessionFile = this.session.getSessionFile?.() ?? undefined;
|
|
256
|
-
const artifactsDir = this.session.getArtifactsDir?.() ?? undefined;
|
|
257
256
|
const { path: artifactPath, id: artifactId } = (await this.session.allocateOutputArtifact?.("python")) ?? {};
|
|
258
257
|
outputSink = new OutputSink({
|
|
259
258
|
artifactPath,
|
|
@@ -272,7 +271,6 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
272
271
|
kernelMode: this.session.settings.get("python.kernelMode"),
|
|
273
272
|
useSharedGateway: this.session.settings.get("python.sharedGateway"),
|
|
274
273
|
sessionFile: sessionFile ?? undefined,
|
|
275
|
-
artifactsDir: artifactsDir ?? undefined,
|
|
276
274
|
};
|
|
277
275
|
|
|
278
276
|
for (let i = 0; i < cells.length; i++) {
|
package/src/tools/read.ts
CHANGED
|
@@ -582,7 +582,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
582
582
|
|
|
583
583
|
const displayMode = resolveFileDisplayMode(this.session);
|
|
584
584
|
|
|
585
|
-
// Handle internal URLs (agent://, artifact://,
|
|
585
|
+
// Handle internal URLs (agent://, artifact://, memory://, skill://, rule://, local://)
|
|
586
586
|
const internalRouter = this.session.internalRouter;
|
|
587
587
|
if (internalRouter?.canHandle(readPath)) {
|
|
588
588
|
return this.#handleInternalUrl(readPath, offset, limit);
|
|
@@ -841,7 +841,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
841
841
|
}
|
|
842
842
|
|
|
843
843
|
/**
|
|
844
|
-
* Handle internal URLs (agent://, artifact://,
|
|
844
|
+
* Handle internal URLs (agent://, artifact://, memory://, skill://, rule://, local://).
|
|
845
845
|
* Supports pagination via offset/limit but rejects them when query extraction is used.
|
|
846
846
|
*/
|
|
847
847
|
async #handleInternalUrl(url: string, offset?: number, limit?: number): Promise<AgentToolResult<ReadToolDetails>> {
|