tau-all-agent 0.4.0 → 0.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.
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type AppKeybinding,
|
|
7
7
|
CustomEditor,
|
|
8
8
|
type AgentToolResult,
|
|
9
|
-
type
|
|
9
|
+
type EditToolDetails,
|
|
10
10
|
type ExtensionAPI,
|
|
11
11
|
type ExtensionContext,
|
|
12
12
|
type KeybindingsManager,
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
Loader,
|
|
20
20
|
Text,
|
|
21
21
|
truncateToWidth,
|
|
22
|
+
visibleWidth,
|
|
22
23
|
type AutocompleteProvider,
|
|
23
24
|
type Component,
|
|
24
25
|
type EditorComponent,
|
|
@@ -42,7 +43,7 @@ const FIND_NO_MATCHES_OUTPUT = "No files found matching pattern"; // core/tools/
|
|
|
42
43
|
const LS_EMPTY_DIRECTORY_OUTPUT = "(empty directory)"; // core/tools/ls.ts
|
|
43
44
|
|
|
44
45
|
// PowerShell is intentionally omitted because Tau does not officially support Windows.
|
|
45
|
-
const TOOL_NAMES = ["read", "bash", "grep", "find", "ls"] as const;
|
|
46
|
+
const TOOL_NAMES = ["read", "bash", "write", "edit", "grep", "find", "ls", "websearch"] as const;
|
|
46
47
|
|
|
47
48
|
// --- Types ---
|
|
48
49
|
|
|
@@ -131,9 +132,28 @@ function createToolDisplayRenderers(
|
|
|
131
132
|
base: ToolRenderers,
|
|
132
133
|
getMode: () => Mode | undefined,
|
|
133
134
|
): ToolRenderers {
|
|
135
|
+
const renderCall = base.renderCall;
|
|
134
136
|
return {
|
|
135
137
|
...base,
|
|
136
138
|
|
|
139
|
+
renderCall:
|
|
140
|
+
(name === "bash" || name === "write" || name === "edit") && renderCall
|
|
141
|
+
? (args, theme, context) => {
|
|
142
|
+
const previous = context.lastComponent;
|
|
143
|
+
const component =
|
|
144
|
+
previous instanceof MinimalCallComponent
|
|
145
|
+
? previous
|
|
146
|
+
: new MinimalCallComponent(previous, getMode, theme, name);
|
|
147
|
+
component.nativeComponent = renderCall(args, theme, {
|
|
148
|
+
...context,
|
|
149
|
+
lastComponent: component.nativeComponent,
|
|
150
|
+
});
|
|
151
|
+
component.expanded = context.expanded;
|
|
152
|
+
component.theme = theme;
|
|
153
|
+
return component;
|
|
154
|
+
}
|
|
155
|
+
: renderCall,
|
|
156
|
+
|
|
137
157
|
renderResult(result, options, theme, context) {
|
|
138
158
|
const mode = getMode();
|
|
139
159
|
const renderer = base.renderResult;
|
|
@@ -149,6 +169,7 @@ function createToolDisplayRenderers(
|
|
|
149
169
|
...context,
|
|
150
170
|
lastComponent: component.nativeComponent,
|
|
151
171
|
});
|
|
172
|
+
component.setPaddingX(base.renderShell === "self" ? context.outputPad : 0);
|
|
152
173
|
component.setText(formatMinimalResult(name, result, options, theme, context));
|
|
153
174
|
return component;
|
|
154
175
|
}
|
|
@@ -197,6 +218,43 @@ function reportSaveError(ctx: ExtensionContext, error: unknown): void {
|
|
|
197
218
|
|
|
198
219
|
// --- Minimal rendering ---
|
|
199
220
|
|
|
221
|
+
class MinimalCallComponent implements Component {
|
|
222
|
+
expanded = false;
|
|
223
|
+
|
|
224
|
+
constructor(
|
|
225
|
+
public nativeComponent: Component | undefined,
|
|
226
|
+
private readonly getMode: () => Mode | undefined,
|
|
227
|
+
public theme: Theme,
|
|
228
|
+
private readonly name: ToolName,
|
|
229
|
+
) {}
|
|
230
|
+
|
|
231
|
+
render(width: number): string[] {
|
|
232
|
+
if (width <= 0) return [];
|
|
233
|
+
const lines = this.nativeComponent?.render(width) ?? [];
|
|
234
|
+
// Read the mode here: switching between collapsed modes need not rerun renderCall.
|
|
235
|
+
if (this.getMode() !== "minimal" || this.expanded || lines.length <= 1) return lines;
|
|
236
|
+
|
|
237
|
+
// Edit's native box has padding before its file header.
|
|
238
|
+
const first = lines.findIndex((line) => stripVTControlCharacters(line).trim());
|
|
239
|
+
if (first < 0) return [];
|
|
240
|
+
const header = lines[first]!;
|
|
241
|
+
if (!lines.slice(first + 1).some((line) => stripVTControlCharacters(line).trim()))
|
|
242
|
+
return [header];
|
|
243
|
+
|
|
244
|
+
const hidden = lines.length - first - 1;
|
|
245
|
+
let hint = this.theme.fg(
|
|
246
|
+
"muted",
|
|
247
|
+
this.name === "bash" ? ` … (+${hidden} ${plural(hidden, "line")})` : " …",
|
|
248
|
+
);
|
|
249
|
+
if (visibleWidth(hint) >= width) hint = this.theme.fg("muted", "…");
|
|
250
|
+
return [truncateToWidth(header, width - visibleWidth(hint), "") + hint];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
invalidate(): void {
|
|
254
|
+
this.nativeComponent?.invalidate();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
200
258
|
class MinimalResultComponent extends Text {
|
|
201
259
|
constructor(public nativeComponent: Component | undefined) {
|
|
202
260
|
super("", 0, 0);
|
|
@@ -221,11 +279,18 @@ function formatMinimalResult(
|
|
|
221
279
|
let summary: string;
|
|
222
280
|
switch (name) {
|
|
223
281
|
case "bash":
|
|
224
|
-
|
|
282
|
+
case "websearch":
|
|
283
|
+
summary = textSummary(result);
|
|
225
284
|
break;
|
|
226
285
|
case "read":
|
|
227
286
|
summary = readSummary(result);
|
|
228
287
|
break;
|
|
288
|
+
case "write":
|
|
289
|
+
summary = writeSummary(context.args);
|
|
290
|
+
break;
|
|
291
|
+
case "edit":
|
|
292
|
+
summary = editSummary(result);
|
|
293
|
+
break;
|
|
229
294
|
case "grep":
|
|
230
295
|
summary = grepSummary(result);
|
|
231
296
|
break;
|
|
@@ -240,11 +305,11 @@ function formatMinimalResult(
|
|
|
240
305
|
return theme.fg("muted", `↳ ${summary}`);
|
|
241
306
|
}
|
|
242
307
|
|
|
243
|
-
function
|
|
308
|
+
function textSummary(result: AgentToolResult<any>): string {
|
|
244
309
|
const text = textOutput(result).trim();
|
|
245
310
|
if (!text || text === "(no output)") return "no output";
|
|
246
311
|
|
|
247
|
-
const details = result.details as
|
|
312
|
+
const details = result.details as { truncation?: { outputLines?: number } } | undefined;
|
|
248
313
|
const lines = details?.truncation?.outputLines ?? countLines(text);
|
|
249
314
|
return `${lines} ${plural(lines, "line")}`;
|
|
250
315
|
}
|
|
@@ -261,6 +326,22 @@ function readSummary(result: AgentToolResult<any>): string {
|
|
|
261
326
|
return `${lines} ${plural(lines, "line")}`;
|
|
262
327
|
}
|
|
263
328
|
|
|
329
|
+
function writeSummary(args: unknown): string {
|
|
330
|
+
if (!isObject(args) || typeof args.content !== "string") return "done";
|
|
331
|
+
const lines = countLines(args.content);
|
|
332
|
+
return `${lines} ${plural(lines, "line")}`;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function editSummary(result: AgentToolResult<any>): string {
|
|
336
|
+
const diff = (result.details as EditToolDetails | undefined)?.diff;
|
|
337
|
+
if (typeof diff !== "string") return "done";
|
|
338
|
+
|
|
339
|
+
// Pi's structured diff prefixes changed lines with a sign and line number.
|
|
340
|
+
const added = diff.match(/^\+ *\d+ /gm)?.length ?? 0;
|
|
341
|
+
const removed = diff.match(/^- *\d+ /gm)?.length ?? 0;
|
|
342
|
+
return added || removed ? `+${added} -${removed} ${plural(added + removed, "line")}` : "done";
|
|
343
|
+
}
|
|
344
|
+
|
|
264
345
|
function grepSummary(result: AgentToolResult<any>): string {
|
|
265
346
|
const text = stripTrailingNotice(textOutput(result)).trim();
|
|
266
347
|
if (!text || text === GREP_NO_MATCHES_OUTPUT) {
|
package/package.json
CHANGED