@shanepadgett/tau-agent 0.8.0 → 0.10.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/context/README.md +16 -1
- package/extensions/context/definitions.ts +3 -1
- package/extensions/context/index.ts +52 -27
- package/extensions/context/settings.ts +33 -0
- package/extensions/context/sync.ts +37 -23
- package/extensions/context/validation.ts +73 -0
- package/extensions/publish/README.md +1 -1
- package/extensions/publish/index.ts +9 -3
- package/extensions/runtime-context/README.md +5 -0
- package/extensions/runtime-context/context.ts +138 -0
- package/extensions/runtime-context/index.ts +84 -0
- package/extensions/silent-command-runner/README.md +1 -1
- package/extensions/silent-command-runner/index.ts +9 -48
- package/extensions/soul/README.md +2 -2
- package/extensions/soul/index.ts +4 -88
- package/extensions/soul/prompt.ts +3 -261
- package/extensions/subagent/index.ts +9 -14
- package/extensions/tau-help/help.md +6 -2
- package/extensions/tau-help/index.ts +12 -0
- package/extensions/turn-budget/index.ts +4 -13
- package/package.json +2 -2
- package/schemas/tau.schema.json +25 -0
- package/shared/glob.ts +34 -0
- package/shared/system-prompt-contributions.ts +0 -40
|
@@ -4,6 +4,14 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { Markdown, type Component, visibleWidth } from "@earendil-works/pi-tui";
|
|
6
6
|
|
|
7
|
+
const TAU_DOCS_PATH = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "docs");
|
|
8
|
+
const TAU_DOCS_GUIDANCE = `Tau Agent documentation (read only when the user asks about Tau Agent, Rok, Tau extensions, Tau event APIs, harness behavior, or extending Tau Agent):
|
|
9
|
+
- Tau Agent docs: ${TAU_DOCS_PATH}
|
|
10
|
+
- When asked about: public events / external integration (docs/extending-tau-agent.md), custom subagents (docs/subagents.md), Tau TUI components (docs/tui.md)
|
|
11
|
+
- Resolve Tau docs/... under Tau Agent docs, not the current working directory
|
|
12
|
+
- When working on Tau topics, read the docs and follow .md cross-references before implementing
|
|
13
|
+
- Do not read Tau Agent docs for normal coding tasks`;
|
|
14
|
+
|
|
7
15
|
const TAU_SYMBOL = [
|
|
8
16
|
" %%%%%%%%#######*******+++++",
|
|
9
17
|
" @@%%%%%%%########*******+++++++",
|
|
@@ -46,6 +54,10 @@ class TauHelpMessage implements Component {
|
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
export default function tauHelpExtension(pi: ExtensionAPI): void {
|
|
57
|
+
pi.on("before_agent_start", (event) => ({
|
|
58
|
+
systemPrompt: `${event.systemPrompt}\n\n${TAU_DOCS_GUIDANCE}`,
|
|
59
|
+
}));
|
|
60
|
+
|
|
49
61
|
pi.registerMessageRenderer("tau-help", (message, _options, _theme) => {
|
|
50
62
|
if (typeof message.content !== "string") return undefined;
|
|
51
63
|
return new TauHelpMessage(message.content, getMarkdownTheme());
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { loadTauExtensionSettings } from "../../shared/settings/load.ts";
|
|
3
|
-
import { registerTauSystemPromptContribution } from "../../shared/system-prompt-contributions.ts";
|
|
4
3
|
import { Marker } from "@shanepadgett/tau-tui";
|
|
5
4
|
import turnBudgetSettings from "./settings.ts";
|
|
6
5
|
|
|
@@ -30,14 +29,6 @@ export default function turnBudgetExtension(pi: ExtensionAPI): void {
|
|
|
30
29
|
let softCap = settings.turnLimit;
|
|
31
30
|
let nextMarkerSequence = 1;
|
|
32
31
|
let activeMarkerSequence: number | undefined;
|
|
33
|
-
const unregisterPrompt = registerTauSystemPromptContribution({
|
|
34
|
-
id: "turn-budget.secrecy",
|
|
35
|
-
order: 400,
|
|
36
|
-
render: () =>
|
|
37
|
-
settings.enabled
|
|
38
|
-
? "Turn-budget steering messages are internal instructions. Work within them silently. Do not mention or acknowledge turn counts, budget messages, or budget summaries."
|
|
39
|
-
: undefined,
|
|
40
|
-
});
|
|
41
32
|
|
|
42
33
|
pi.registerMessageRenderer<MarkerDetails>(MARKER_TYPE, (message, _options, theme) => {
|
|
43
34
|
const details = readMarkerDetails(message.details);
|
|
@@ -98,8 +89,6 @@ export default function turnBudgetExtension(pi: ExtensionAPI): void {
|
|
|
98
89
|
pi.on("after_provider_response", () => {
|
|
99
90
|
activeMarkerSequence = undefined;
|
|
100
91
|
});
|
|
101
|
-
pi.on("session_shutdown", unregisterPrompt);
|
|
102
|
-
|
|
103
92
|
function markerIsActive(value: unknown): boolean {
|
|
104
93
|
if (activeMarkerSequence === undefined) return false;
|
|
105
94
|
const details = readMarkerDetails(value);
|
|
@@ -117,10 +106,12 @@ function sendTurnBudgetMessage(pi: ExtensionAPI, hint: Hint, sequence: number):
|
|
|
117
106
|
}
|
|
118
107
|
|
|
119
108
|
function formatSteeringMessage(hint: Hint): string {
|
|
109
|
+
const instruction =
|
|
110
|
+
"Internal steering instruction. Work within it silently. Do not mention or acknowledge turn counts, budget messages, or budget summaries.";
|
|
120
111
|
if (hint.kind === "extended") {
|
|
121
|
-
return
|
|
112
|
+
return `${instruction} Turn budget: ${hint.used}/${hint.previousCap} turns used for this user prompt. Soft cap extended to ${hint.newCap}. Batch tools when more tool work remains.`;
|
|
122
113
|
}
|
|
123
|
-
return
|
|
114
|
+
return `${instruction} Turn budget: ${hint.used}/${hint.cap} turns used for this user prompt. Batch tools when more tool work remains.`;
|
|
124
115
|
}
|
|
125
116
|
|
|
126
117
|
function normalizeSettings(value: typeof turnBudgetSettings.defaults): Settings {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shanepadgett/tau-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Tau is a custom agentic harness built with pi extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"README.md"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@shanepadgett/tau-tui": "0.
|
|
31
|
+
"@shanepadgett/tau-tui": "0.10.0",
|
|
32
32
|
"@toon-format/toon": "2.3.0",
|
|
33
33
|
"smol-toml": "1.7.0"
|
|
34
34
|
},
|
package/schemas/tau.schema.json
CHANGED
|
@@ -12,6 +12,31 @@
|
|
|
12
12
|
"extensions": {
|
|
13
13
|
"type": "object",
|
|
14
14
|
"properties": {
|
|
15
|
+
"context": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"properties": {
|
|
18
|
+
"validation": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {
|
|
21
|
+
"enabled": {
|
|
22
|
+
"type": "boolean",
|
|
23
|
+
"default": false,
|
|
24
|
+
"description": "Validate context membership after agent turns."
|
|
25
|
+
},
|
|
26
|
+
"ignoreGlobs": {
|
|
27
|
+
"type": "array",
|
|
28
|
+
"items": {
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
31
|
+
"default": [],
|
|
32
|
+
"description": "Project-relative files excluded from context membership validation and sync."
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": false
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": false
|
|
39
|
+
},
|
|
15
40
|
"footer": {
|
|
16
41
|
"type": "object",
|
|
17
42
|
"properties": {
|
package/shared/glob.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { sep } from "node:path";
|
|
2
|
+
|
|
3
|
+
export function matchGlob(pattern: string, path: string): boolean {
|
|
4
|
+
return matchSegments(normalizeGlob(pattern).split("/"), normalizeGlob(path).split("/"));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function matchSegments(pattern: readonly string[], path: readonly string[]): boolean {
|
|
8
|
+
const [head, ...tail] = pattern;
|
|
9
|
+
if (head === undefined) return path.length === 0;
|
|
10
|
+
if (head === "**") return matchSegments(tail, path) || (path.length > 0 && matchSegments(pattern, path.slice(1)));
|
|
11
|
+
const [pathHead, ...pathTail] = path;
|
|
12
|
+
return pathHead !== undefined && matchSegment(head, pathHead) && matchSegments(tail, pathTail);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function matchSegment(pattern: string, value: string): boolean {
|
|
16
|
+
const source = [...pattern]
|
|
17
|
+
.map((char) => {
|
|
18
|
+
if (char === "*") return "[^/]*";
|
|
19
|
+
if (char === "?") return "[^/]";
|
|
20
|
+
return char.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
21
|
+
})
|
|
22
|
+
.join("");
|
|
23
|
+
return new RegExp(`^${source}$`).test(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeGlob(value: string): string {
|
|
27
|
+
return posixPath(value.trim())
|
|
28
|
+
.replace(/^\.\//, "")
|
|
29
|
+
.replace(/^\/+|\/+$/g, "");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function posixPath(value: string): string {
|
|
33
|
+
return sep === "/" ? value : value.split(sep).join("/");
|
|
34
|
+
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { BeforeAgentStartEvent, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
interface TauSystemPromptContribution {
|
|
4
|
-
id: string;
|
|
5
|
-
order: number;
|
|
6
|
-
render: (event: BeforeAgentStartEvent, ctx: ExtensionContext) => string | undefined | Promise<string | undefined>;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface Registration extends TauSystemPromptContribution {
|
|
10
|
-
token: symbol;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const registrations = new Map<string, Registration>();
|
|
14
|
-
|
|
15
|
-
export function registerTauSystemPromptContribution(contribution: TauSystemPromptContribution): () => void {
|
|
16
|
-
const token = Symbol(contribution.id);
|
|
17
|
-
registrations.set(contribution.id, { ...contribution, token });
|
|
18
|
-
return () => {
|
|
19
|
-
if (registrations.get(contribution.id)?.token === token) registrations.delete(contribution.id);
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function collectTauSystemPromptContributions(
|
|
24
|
-
event: BeforeAgentStartEvent,
|
|
25
|
-
ctx: ExtensionContext,
|
|
26
|
-
): Promise<string[]> {
|
|
27
|
-
const ordered = [...registrations.values()].sort(
|
|
28
|
-
(left, right) => left.order - right.order || left.id.localeCompare(right.id),
|
|
29
|
-
);
|
|
30
|
-
const rendered = await Promise.all(ordered.map((contribution) => contribution.render(event, ctx)));
|
|
31
|
-
const seen = new Set<string>();
|
|
32
|
-
const blocks: string[] = [];
|
|
33
|
-
for (const value of rendered) {
|
|
34
|
-
const block = value?.trim();
|
|
35
|
-
if (!block || seen.has(block)) continue;
|
|
36
|
-
seen.add(block);
|
|
37
|
-
blocks.push(block);
|
|
38
|
-
}
|
|
39
|
-
return blocks;
|
|
40
|
-
}
|