@shanepadgett/tau-agent 0.35.0 → 0.37.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/extensions/explore/README.md +2 -2
- package/extensions/explore/guidance.ts +2 -1
- package/extensions/explore/tools/render.ts +9 -15
- package/extensions/explore/tools/show.ts +22 -4
- package/extensions/patch/render.ts +19 -3
- package/extensions/script-runner/index.ts +14 -0
- package/extensions/subagent/agents/scout.md +1 -1
- package/extensions/tau-help/help.md +5 -5
- package/extensions/tool-approval/README.md +22 -0
- package/extensions/tool-approval/allowlist.ts +501 -0
- package/extensions/tool-approval/index.ts +269 -0
- package/extensions/{bash-approval → tool-approval}/settings.ts +3 -3
- package/extensions/web/tool-output.ts +4 -6
- package/package.json +3 -2
- package/schemas/tau.schema.json +16 -16
- package/shared/text.ts +21 -0
- package/extensions/bash-approval/README.md +0 -20
- package/extensions/bash-approval/index.ts +0 -235
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Explore
|
|
2
2
|
|
|
3
|
-
Explore gives Tau 12 structural source tools: outlines, declaration slices, discovery, structural search, graph and relationship queries, impact, and context packs.
|
|
3
|
+
Explore gives Tau 12 structural source tools: outlines, declaration slices, discovery, structural search, graph and relationship queries, impact, and context packs. `show` takes a top-level `targets` array of path + declaration-name objects, with an optional line to disambiguate.
|
|
4
4
|
|
|
5
5
|
Pi keeps ordinary filesystem tools (`ls`, `find`, `grep`, `read`). Explore adds structure on top of supported source languages via in-process tree-sitter (WASM) on every platform supported by the Node runtime. Registered languages share the same tools and exploration workflow.
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ When `explore.read.enabled` is on (default), a full Pi `read` or autoread of a r
|
|
|
11
11
|
## Tools
|
|
12
12
|
|
|
13
13
|
- `outline` — declarations and structure for a file, one-level directory, or recursive subtree (no bodies).
|
|
14
|
-
- `show` — exact signature / docs / declaration / declaration+imports for
|
|
14
|
+
- `show` — exact signature / docs / declaration / declaration+imports for one or more targets in its top-level `targets` array.
|
|
15
15
|
- `discover` — find reusable declarations across a repo/package/subtree by name, kind, or docs (signatures only).
|
|
16
16
|
- `deps` / `reverse_deps` — file import graph forward and reverse.
|
|
17
17
|
- `callers` / `callees` / `references` / `implementations` — symbol relationship sites.
|
|
@@ -4,7 +4,8 @@ const GUIDANCE = `## Explore
|
|
|
4
4
|
Shape-backed languages: \`markdown\`, \`typescript\`, \`tsx\`, \`go\`, \`rust\`, \`c_sharp\`, \`java\`, \`kotlin\`, \`swift\`.
|
|
5
5
|
|
|
6
6
|
Structural tools (\`outline\`, \`show\`, \`discover\`, \`ast_search\`, deps/relationships, \`impact\`, \`context\`) apply to those languages. Other files: harness \`read\` / \`grep\` / \`find\` / \`ls\`.
|
|
7
|
-
Full \`read\` of a large registered source returns outline + follow-up hint, not the body — use ranged \`read\` or \`show
|
|
7
|
+
Full \`read\` of a large registered source returns outline + follow-up hint, not the body — use ranged \`read\` or \`show\`.
|
|
8
|
+
\`show\` always takes a top-level \`targets\` array, even for one declaration: \`{"targets":[{"path":"...","name":"..."}],"view":"declaration"}\`.`;
|
|
8
9
|
|
|
9
10
|
export function registerExploreGuidance(pi: ExtensionAPI): void {
|
|
10
11
|
pi.on("before_agent_start", (event) => ({ systemPrompt: `${event.systemPrompt}\n\n${GUIDANCE}` }));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { formatSize, keyHint, type Theme } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Text, truncateToWidth, visibleWidth, type Component } from "@earendil-works/pi-tui";
|
|
3
3
|
import { formatToolRowTitle, type ToolRowStateStore } from "../../../shared/tool-row-state.ts";
|
|
4
|
+
import { renderToolOutputPreview } from "../../../shared/text.ts";
|
|
4
5
|
|
|
5
6
|
export type ExploreToolDetails = {
|
|
6
7
|
declarationCount: number;
|
|
@@ -94,28 +95,21 @@ export function renderExploreResult(
|
|
|
94
95
|
context: { lastComponent?: Component; isError: boolean },
|
|
95
96
|
): Text {
|
|
96
97
|
const text = (context.lastComponent as Text | undefined) ?? new Text("", 0, 0);
|
|
98
|
+
const output = result.content
|
|
99
|
+
.filter((item): item is { type: string; text: string } => item.type === "text" && typeof item.text === "string")
|
|
100
|
+
.map((item) => item.text)
|
|
101
|
+
.join("\n");
|
|
97
102
|
if (!expanded && !context.isError) {
|
|
98
103
|
const count = result.details?.declarationCount ?? 0;
|
|
99
104
|
const noun = count === 1 ? "declaration" : "declarations";
|
|
100
105
|
const bytes = result.details === undefined ? "" : `, ${formatSize(result.details.returnedBytes)} returned`;
|
|
106
|
+
const summary = theme.fg("muted", `${count} ${noun}${bytes}`);
|
|
107
|
+
const preview = renderToolOutputPreview(output, false, theme);
|
|
101
108
|
text.setText(
|
|
102
|
-
|
|
103
|
-
keyHint("app.tools.expand", "to expand") +
|
|
104
|
-
theme.fg("muted", ")"),
|
|
109
|
+
preview ? `${summary}\n${preview}` : `${summary} (` + keyHint("app.tools.expand", "to expand") + ")",
|
|
105
110
|
);
|
|
106
111
|
return text;
|
|
107
112
|
}
|
|
108
|
-
|
|
109
|
-
.filter((item): item is { type: string; text: string } => item.type === "text" && typeof item.text === "string")
|
|
110
|
-
.map((item) => item.text)
|
|
111
|
-
.join("\n");
|
|
112
|
-
text.setText(
|
|
113
|
-
output
|
|
114
|
-
? output
|
|
115
|
-
.split("\n")
|
|
116
|
-
.map((line) => theme.fg("toolOutput", line))
|
|
117
|
-
.join("\n")
|
|
118
|
-
: "",
|
|
119
|
-
);
|
|
113
|
+
text.setText(renderToolOutputPreview(output, true, theme));
|
|
120
114
|
return text;
|
|
121
115
|
}
|
|
@@ -12,7 +12,7 @@ import { ExploreCallComponent, renderExploreResult, shrinkingListVariants, type
|
|
|
12
12
|
|
|
13
13
|
const showTargetSchema = Type.Object(
|
|
14
14
|
{
|
|
15
|
-
path: Type.String({ description: "Defining file" }),
|
|
15
|
+
path: Type.String({ description: "Defining file for this target" }),
|
|
16
16
|
name: Type.String({ minLength: 1, description: "Decl name; dotted Type.method ok" }),
|
|
17
17
|
line: Type.Optional(Type.Integer({ minimum: 1, description: "1-based line inside decl range" })),
|
|
18
18
|
},
|
|
@@ -23,7 +23,8 @@ const showParams = Type.Object(
|
|
|
23
23
|
{
|
|
24
24
|
targets: Type.Array(showTargetSchema, {
|
|
25
25
|
minItems: 1,
|
|
26
|
-
description:
|
|
26
|
+
description:
|
|
27
|
+
'Required top-level array, even for one declaration. For one target: [{"path":"...","name":"..."}].',
|
|
27
28
|
}),
|
|
28
29
|
view: StringEnum(["signature", "signatureWithDocs", "declaration", "declarationWithImports"] as const, {
|
|
29
30
|
description: "signature | signatureWithDocs | declaration | declarationWithImports",
|
|
@@ -68,13 +69,30 @@ export function createShowTool(rowState: ToolRowStateStore, engineFor: (cwd: str
|
|
|
68
69
|
name: "show",
|
|
69
70
|
label: "show",
|
|
70
71
|
description:
|
|
71
|
-
|
|
72
|
-
promptSnippet: "
|
|
72
|
+
'Show one or more declarations. Arguments always require a top-level `targets` array, even for one target: `{"targets":[{"path":"...","name":"..."}],"view":"declaration"}`. Whole batch fails on any missing/ambiguous target (candidate list, no partials). Views: signature → signatureWithDocs → declaration → declarationWithImports. Over budget throws — request fewer targets (bodies are not truncated).',
|
|
73
|
+
promptSnippet: "Show declarations using a top-level targets array",
|
|
73
74
|
promptGuidelines: [
|
|
75
|
+
"show always requires a top-level targets array, even for one declaration; do not pass path or name at the root.",
|
|
74
76
|
"Cheapest view that answers; declarationWithImports only when edits need imports.",
|
|
75
77
|
"Pin with path and line when names collide — do not guess.",
|
|
76
78
|
],
|
|
77
79
|
parameters: showParams,
|
|
80
|
+
prepareArguments(args) {
|
|
81
|
+
if (args === null || typeof args !== "object" || Array.isArray(args)) {
|
|
82
|
+
return args as Static<typeof showParams>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const input = args as Record<string, unknown>;
|
|
86
|
+
if ("targets" in input || typeof input.path !== "string" || typeof input.name !== "string") {
|
|
87
|
+
return input as Static<typeof showParams>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const { path, name, line, ...rest } = input;
|
|
91
|
+
return {
|
|
92
|
+
...rest,
|
|
93
|
+
targets: [{ path, name, ...(line === undefined ? {} : { line }) }],
|
|
94
|
+
} as Static<typeof showParams>;
|
|
95
|
+
},
|
|
78
96
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
79
97
|
const engine = engineFor(ctx.cwd);
|
|
80
98
|
const abort = signal ?? new AbortController().signal;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { keyHint, type Theme } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Text } from "@earendil-works/pi-tui";
|
|
3
3
|
import { formatToolRowTitle, type ToolRowStateStore } from "../../shared/tool-row-state.js";
|
|
4
4
|
import { type ApplyPatchSummary, deriveStats } from "./executor.ts";
|
|
@@ -23,6 +23,7 @@ const REPLACE_FILE_MARKER = "*** Replace File: ";
|
|
|
23
23
|
const DELETE_FILE_MARKER = "*** Delete File: ";
|
|
24
24
|
const UPDATE_FILE_MARKER = "*** Update File: ";
|
|
25
25
|
const MOVE_TO_MARKER = "*** Move to: ";
|
|
26
|
+
const PATCH_PREVIEW_OPERATIONS = 10;
|
|
26
27
|
|
|
27
28
|
function topLevelDirective(line: string): string {
|
|
28
29
|
return line.trim();
|
|
@@ -156,6 +157,21 @@ function renderOpLine(op: PreviewOp, status: OpStatus | undefined, theme: Theme)
|
|
|
156
157
|
return ind ? `${label} ${ind}` : label;
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
function renderPreviewLines(preview: PreviewOp[], statuses: Map<number, OpStatus> | undefined, theme: Theme): string[] {
|
|
161
|
+
const lines = preview
|
|
162
|
+
.slice(0, PATCH_PREVIEW_OPERATIONS)
|
|
163
|
+
.map((op) => renderOpLine(op, statuses?.get(op.sectionIndex), theme));
|
|
164
|
+
const remaining = preview.length - lines.length;
|
|
165
|
+
if (remaining > 0) {
|
|
166
|
+
lines.push(
|
|
167
|
+
`${theme.fg("muted", `... (${remaining} more operations, ${preview.length} total,`)} ` +
|
|
168
|
+
keyHint("app.tools.expand", "to expand") +
|
|
169
|
+
theme.fg("muted", ")"),
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
return lines;
|
|
173
|
+
}
|
|
174
|
+
|
|
159
175
|
interface RenderCallContext {
|
|
160
176
|
expanded: boolean;
|
|
161
177
|
executionStarted: boolean;
|
|
@@ -198,7 +214,7 @@ export function renderPatchCall(args: { input?: string } | undefined, theme: The
|
|
|
198
214
|
text.setText(header);
|
|
199
215
|
return text;
|
|
200
216
|
}
|
|
201
|
-
const lines = preview
|
|
217
|
+
const lines = renderPreviewLines(preview, undefined, theme);
|
|
202
218
|
text.setText([header, ...lines].join("\n"));
|
|
203
219
|
return text;
|
|
204
220
|
}
|
|
@@ -234,7 +250,7 @@ export function renderPatchResult(
|
|
|
234
250
|
return text;
|
|
235
251
|
}
|
|
236
252
|
|
|
237
|
-
const lines = preview
|
|
253
|
+
const lines = renderPreviewLines(preview, statuses, theme);
|
|
238
254
|
text.setText([header, ...lines].join("\n"));
|
|
239
255
|
return text;
|
|
240
256
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "@earendil-works/pi-coding-agent";
|
|
16
16
|
import { Text } from "@earendil-works/pi-tui";
|
|
17
17
|
import { Type } from "typebox";
|
|
18
|
+
import { renderToolOutputPreview } from "../../shared/text.ts";
|
|
18
19
|
|
|
19
20
|
type Language = "python3" | "node" | "deno";
|
|
20
21
|
|
|
@@ -295,6 +296,19 @@ export default function scriptRunnerExtension(pi: ExtensionAPI): void {
|
|
|
295
296
|
text.setText(body ? `${header}\n${body}` : header);
|
|
296
297
|
return text;
|
|
297
298
|
},
|
|
299
|
+
renderResult(result, options, theme, context) {
|
|
300
|
+
const text = (context.lastComponent as Text | undefined) ?? new Text("", 0, 0);
|
|
301
|
+
if (options.isPartial) {
|
|
302
|
+
text.setText("");
|
|
303
|
+
return text;
|
|
304
|
+
}
|
|
305
|
+
const output = result.content
|
|
306
|
+
.filter((item): item is { type: "text"; text: string } => item.type === "text")
|
|
307
|
+
.map((item) => item.text)
|
|
308
|
+
.join("\n");
|
|
309
|
+
text.setText(renderToolOutputPreview(output, options.expanded || context.isError, theme));
|
|
310
|
+
return text;
|
|
311
|
+
},
|
|
298
312
|
});
|
|
299
313
|
|
|
300
314
|
pi.registerTool(tool);
|
|
@@ -48,7 +48,7 @@ Use cheapest source that proves each returned fact. Skip steps when task supplie
|
|
|
48
48
|
1. **Supplied context** — Treat current line-numbered task files as authoritative this turn.
|
|
49
49
|
2. **Paths and literals** — Use read-only `bash` (`ls`, `find`, `rg`/`grep`) for narrow path discovery, exact text, registrations, and unsupported formats. Use ranged `read` for formatting or source without structural support.
|
|
50
50
|
3. **Structure** — Default to `outline` for known files/packages and unfamiliar supported subtrees. Use `discover` when requested declaration path or exact name is unknown. Use `ast_search` for source shapes.
|
|
51
|
-
4. **Exact declarations** — Use `show` with path + name (+ line when needed). Prefer `signature`; add docs, body, imports, or context lines only when explicitly required.
|
|
51
|
+
4. **Exact declarations** — Use `show` with a top-level `targets` array containing path + name (+ line when needed), even for one declaration. Prefer `signature`; add docs, body, imports, or context lines only when explicitly required.
|
|
52
52
|
5. **Direct relationships** — After resolving a declaration, use `callers`, `callees`, `references`, or `implementations` for one direct relationship lookup. Use `deps` and `reverse_deps` for file imports, not declaration calls.
|
|
53
53
|
|
|
54
54
|
Structural results prove bounded syntax, not runtime dispatch. Preserve exact, inferred, and ambiguous labels emitted by tools. Never convert an ambiguous result into a fact.
|
|
@@ -22,10 +22,6 @@ Names sessions from their first request so saved sessions remain findable.
|
|
|
22
22
|
|
|
23
23
|
Adds `/branch` to create and switch Git branches from the TUI.
|
|
24
24
|
|
|
25
|
-
## bash-approval
|
|
26
|
-
|
|
27
|
-
Reviews every agent `bash` call with a quick-effort model before execution. Set `extensions.bashApproval.autoApprove` to run every reviewer-approved command without another confirmation. The reviewer approves routine local development work. Concrete destructive, system, production, privileged, or security-sensitive effects require human approval with one explanatory paragraph. Reviewer failures fall back to human approval and send an attention notification.
|
|
28
|
-
|
|
29
25
|
## cache-diagnostics
|
|
30
26
|
|
|
31
27
|
Records private prompt-cache fingerprints without storing prompt content. Run `/cache-debug` after suspicious cache misses to write a bounded investigation report under `~/.pi/agent/cache-diagnostics/reports/`.
|
|
@@ -52,7 +48,7 @@ Adds `/effort [quick|standard|deep]` to select effort and a provider from curren
|
|
|
52
48
|
|
|
53
49
|
## explore
|
|
54
50
|
|
|
55
|
-
Structural source tools on in-process tree-sitter (WASM), available on every Node-supported platform. Registers `outline`, `show`, `discover`, `ast_search`, `deps`, `reverse_deps`, `callers`, `callees`, `references`, `implementations`, `impact`, and `context`;
|
|
51
|
+
Structural source tools on in-process tree-sitter (WASM), available on every Node-supported platform. Registers `outline`, `show`, `discover`, `ast_search`, `deps`, `reverse_deps`, `callers`, `callees`, `references`, `implementations`, `impact`, and `context`; `show` takes a top-level `targets` array of path + name objects (+ line when needed). Pi keeps `ls` / `find` / `grep` / `read`. Large full `read`/autoread of registered source (including Markdown) returns outline by default (`explore.read.*`); ranged `read` or `show` for bodies. Disable with `explore.read.enabled: false`.
|
|
56
52
|
|
|
57
53
|
## footer
|
|
58
54
|
|
|
@@ -130,6 +126,10 @@ Adds `/tau-help` to show this guide as rendered Markdown in the chat.
|
|
|
130
126
|
|
|
131
127
|
Adds `/tau`, `/tau init [--global|--project]`, and `/tau doctor` for Tau setup and diagnostics.
|
|
132
128
|
|
|
129
|
+
## tool-approval
|
|
130
|
+
|
|
131
|
+
Reviews agent `bash` and `script_runner` requests before they run. Common read-only bash commands skip review. Set `extensions.toolApproval.autoApprove` to run every reviewer-approved request without another confirmation. Those auto-approvals show a user-only marker. The reviewer approves routine local development work. Concrete destructive, system, production, privileged, or security-sensitive effects require human approval with one explanatory paragraph. Reviewer failures fall back to human approval and send an attention notification.
|
|
132
|
+
|
|
133
133
|
## tool-loader
|
|
134
134
|
|
|
135
135
|
Progressively exposes registered specialist tool groups through `load_tools`. Tau registers `web`, `image`, and `appshot`; project or global package extensions can add groups with `registerDeferredToolGroup()` from `@shanepadgett/tau-agent`. Supported providers can preserve more prompt-cache reuse.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Tool Approval
|
|
2
|
+
|
|
3
|
+
Reviews agent `bash` and `script_runner` requests before they run.
|
|
4
|
+
|
|
5
|
+
Common read-only bash commands skip review and run immediately. Other bash and every `script_runner` request go to a quick-effort model. The reviewer returns a validated decision and one concise paragraph that explains the request.
|
|
6
|
+
|
|
7
|
+
With `autoApprove` enabled, reviewer-approved requests run without another confirmation. Tau shows a user-only marker after those auto-approvals. Common read-only bash that skips review does not get a marker. Routine local development work should be approved, including requests that modify project files or run scripts. The reviewer asks for human approval only when it finds a concrete destructive, system, production, privileged, or security-sensitive effect.
|
|
8
|
+
|
|
9
|
+
When approval is required, Tau shows one paragraph that explains the effect and risk without repeating the request. If the reviewer fails or returns a malformed decision, Tau asks for direct human approval instead of running it automatically. Tau also sends an attention notification when the approval window opens.
|
|
10
|
+
|
|
11
|
+
Configure under `extensions.toolApproval`:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"extensions": {
|
|
16
|
+
"toolApproval": {
|
|
17
|
+
"enabled": true,
|
|
18
|
+
"autoApprove": true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|