@shanepadgett/tau-agent 0.39.1 → 0.39.2
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,4 +6,4 @@ Set `extensions.autoCompact.tokenLimit` to change the limit. It defaults to 175,
|
|
|
6
6
|
|
|
7
7
|
After changing this extension, run `/reload` before testing it.
|
|
8
8
|
|
|
9
|
-
Automatic compaction holds attention notifications while it runs and while the hidden continuation resumes the interrupted work. The notification is released only after that resumed work settles.
|
|
9
|
+
Automatic compaction holds attention notifications while it runs and while the hidden continuation resumes the interrupted work. The notification is released only after that resumed work settles. It also pauses silent post-edit checks across the compact so they do not run on incomplete work.
|
|
@@ -14,6 +14,7 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
|
|
|
14
14
|
let sessionVersion = 0;
|
|
15
15
|
let attentionHoldSequence = 0;
|
|
16
16
|
let attentionHoldId: string | undefined;
|
|
17
|
+
let silentCheckPauseId: string | undefined;
|
|
17
18
|
let continuationPending = false;
|
|
18
19
|
|
|
19
20
|
function releaseAttentionHold(disposition: "notify" | "discard"): void {
|
|
@@ -22,6 +23,18 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
|
|
|
22
23
|
if (holdId) emitTauEvent(pi, "tau:attention.hold.release", { id: holdId, disposition });
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
function pauseSilentChecks(): void {
|
|
27
|
+
if (silentCheckPauseId) return;
|
|
28
|
+
silentCheckPauseId = `auto-compact:${++attentionHoldSequence}`;
|
|
29
|
+
emitTauEvent(pi, "tau:silent-command-runner.pause", { id: silentCheckPauseId });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resumeSilentChecks(disposition: "continue" | "settle"): void {
|
|
33
|
+
const pauseId = silentCheckPauseId;
|
|
34
|
+
silentCheckPauseId = undefined;
|
|
35
|
+
if (pauseId) emitTauEvent(pi, "tau:silent-command-runner.resume", { id: pauseId, disposition });
|
|
36
|
+
}
|
|
37
|
+
|
|
25
38
|
pi.on("session_start", async (_event, ctx) => {
|
|
26
39
|
const version = ++sessionVersion;
|
|
27
40
|
const settings = await loadTauExtensionSettings(ctx, autoCompactSettings);
|
|
@@ -31,6 +44,7 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
|
|
|
31
44
|
compacting = false;
|
|
32
45
|
attentionHoldSequence = 0;
|
|
33
46
|
attentionHoldId = undefined;
|
|
47
|
+
silentCheckPauseId = undefined;
|
|
34
48
|
continuationPending = false;
|
|
35
49
|
});
|
|
36
50
|
pi.on("session_shutdown", () => {
|
|
@@ -38,6 +52,7 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
|
|
|
38
52
|
armed = true;
|
|
39
53
|
compacting = false;
|
|
40
54
|
attentionHoldId = undefined;
|
|
55
|
+
silentCheckPauseId = undefined;
|
|
41
56
|
continuationPending = false;
|
|
42
57
|
});
|
|
43
58
|
pi.on("session_tree", () => {
|
|
@@ -64,6 +79,8 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
|
|
|
64
79
|
|
|
65
80
|
armed = false;
|
|
66
81
|
compacting = true;
|
|
82
|
+
// Pause before compact: compact aborts the agent, and that agent_end must not run checks.
|
|
83
|
+
pauseSilentChecks();
|
|
67
84
|
if (ctx.mode !== "print") {
|
|
68
85
|
attentionHoldId = `auto-compact:${++attentionHoldSequence}`;
|
|
69
86
|
emitTauEvent(pi, "tau:attention.hold.acquire", { id: attentionHoldId });
|
|
@@ -72,6 +89,8 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
|
|
|
72
89
|
const continueWork = (): void => {
|
|
73
90
|
if (version !== sessionVersion) return;
|
|
74
91
|
compacting = false;
|
|
92
|
+
// Keep the silent-check baseline across the new agent run started below.
|
|
93
|
+
resumeSilentChecks("continue");
|
|
75
94
|
continuationPending = true;
|
|
76
95
|
pi.sendMessage(
|
|
77
96
|
{
|
|
@@ -90,6 +109,7 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
|
|
|
90
109
|
if (version !== sessionVersion) return;
|
|
91
110
|
compacting = false;
|
|
92
111
|
if (error.name === "AbortError" || error.message === "Compaction cancelled") {
|
|
112
|
+
resumeSilentChecks("settle");
|
|
93
113
|
releaseAttentionHold("notify");
|
|
94
114
|
return;
|
|
95
115
|
}
|
|
@@ -23,3 +23,5 @@ Configure it in Tau settings under `extensions.silentCommandRunner`:
|
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
Passes are notifications only. Failures are shown in chat and sent to the agent. Tau's ready-for-input notification waits for these checks and stays quiet when a failure starts another agent turn.
|
|
26
|
+
|
|
27
|
+
When auto-compact pauses a long run to compact context, checks wait until that work chain finishes. They do not run on the compact abort, and file changes from before the compact still count.
|
|
@@ -2,7 +2,7 @@ import { readdir, stat } from "node:fs/promises";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { type ExecResult, type ExtensionAPI, keyText, type Theme } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { Box, Text } from "@earendil-works/pi-tui";
|
|
5
|
-
import { emitTauEvent } from "../../shared/events.ts";
|
|
5
|
+
import { emitTauEvent, onTauEvent } from "../../shared/events.ts";
|
|
6
6
|
import { matchGlob, posixPath } from "../../shared/glob.ts";
|
|
7
7
|
import { loadTauExtensionSettings } from "../../shared/settings/load.ts";
|
|
8
8
|
import { resolveProjectRoot } from "../../shared/settings/paths.ts";
|
|
@@ -84,11 +84,40 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
|
|
|
84
84
|
let chainActive = false;
|
|
85
85
|
let attentionHoldSequence = 0;
|
|
86
86
|
let attentionHoldId: string | undefined;
|
|
87
|
+
const checkPauses = new Set<string>();
|
|
88
|
+
let settleDeferred = false;
|
|
89
|
+
|
|
90
|
+
function checksPaused(): boolean {
|
|
91
|
+
return checkPauses.size > 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function finalizeChain(): void {
|
|
95
|
+
settleDeferred = false;
|
|
96
|
+
chainActive = false;
|
|
97
|
+
const holdId = attentionHoldId;
|
|
98
|
+
attentionHoldId = undefined;
|
|
99
|
+
if (holdId) emitTauEvent(pi, "tau:attention.hold.release", { id: holdId, disposition: "notify" });
|
|
100
|
+
}
|
|
87
101
|
|
|
88
102
|
pi.registerMessageRenderer<FailureDetails>(MESSAGE_TYPE, (message, { expanded }, theme) =>
|
|
89
103
|
renderFailure(asFailureDetails(message.details), expanded, theme),
|
|
90
104
|
);
|
|
91
105
|
|
|
106
|
+
onTauEvent(pi, "silent-command-runner.pause", "tau:silent-command-runner.pause", ({ id }) => {
|
|
107
|
+
checkPauses.add(id);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
onTauEvent(pi, "silent-command-runner.resume", "tau:silent-command-runner.resume", ({ id, disposition }) => {
|
|
111
|
+
checkPauses.delete(id);
|
|
112
|
+
if (checksPaused()) return;
|
|
113
|
+
if (disposition === "continue") {
|
|
114
|
+
// Compact will start a new agent run on the same work chain; keep baseline + hold.
|
|
115
|
+
settleDeferred = false;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (settleDeferred || chainActive) finalizeChain();
|
|
119
|
+
});
|
|
120
|
+
|
|
92
121
|
pi.on("session_start", async (_event, ctx) => {
|
|
93
122
|
settings = normalizeSettings(await loadTauExtensionSettings(ctx, silentCommandRunnerSettings));
|
|
94
123
|
sessionActive = true;
|
|
@@ -97,6 +126,8 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
|
|
|
97
126
|
chainActive = false;
|
|
98
127
|
attentionHoldSequence = 0;
|
|
99
128
|
attentionHoldId = undefined;
|
|
129
|
+
checkPauses.clear();
|
|
130
|
+
settleDeferred = false;
|
|
100
131
|
});
|
|
101
132
|
|
|
102
133
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
@@ -108,20 +139,24 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
|
|
|
108
139
|
pi.on("agent_start", async (_event, ctx) => {
|
|
109
140
|
const startingChain = !chainActive;
|
|
110
141
|
chainActive = true;
|
|
111
|
-
|
|
142
|
+
settleDeferred = false;
|
|
112
143
|
if (!settings.enabled || settings.commands.length === 0) {
|
|
113
|
-
|
|
144
|
+
if (startingChain) {
|
|
145
|
+
turnStart = Date.now();
|
|
146
|
+
turnPaths = new Set();
|
|
147
|
+
}
|
|
114
148
|
return;
|
|
115
149
|
}
|
|
116
|
-
if (startingChain)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
150
|
+
if (!startingChain) return;
|
|
151
|
+
attentionHoldId = `silent-command-runner:${++attentionHoldSequence}`;
|
|
152
|
+
emitTauEvent(pi, "tau:attention.hold.acquire", { id: attentionHoldId });
|
|
153
|
+
turnStart = Date.now();
|
|
120
154
|
const projectRoot = await resolveProjectRoot(ctx.cwd);
|
|
121
155
|
turnPaths = new Set(await walkFiles(projectRoot));
|
|
122
156
|
});
|
|
123
157
|
|
|
124
158
|
pi.on("agent_end", async (event, ctx) => {
|
|
159
|
+
if (checksPaused()) return;
|
|
125
160
|
if (hasAbortedAssistantMessage(event.messages)) return;
|
|
126
161
|
try {
|
|
127
162
|
await runChangedCommands(ctx.cwd, turnStart, ctx.ui.notify);
|
|
@@ -131,10 +166,12 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
|
|
|
131
166
|
});
|
|
132
167
|
|
|
133
168
|
pi.on("agent_settled", () => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
169
|
+
if (checksPaused()) {
|
|
170
|
+
// Compact aborted this run; keep chain + file baseline until resume.
|
|
171
|
+
settleDeferred = true;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
finalizeChain();
|
|
138
175
|
});
|
|
139
176
|
|
|
140
177
|
pi.on("session_shutdown", () => {
|
|
@@ -144,6 +181,8 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
|
|
|
144
181
|
turnPaths = new Set();
|
|
145
182
|
chainActive = false;
|
|
146
183
|
attentionHoldId = undefined;
|
|
184
|
+
checkPauses.clear();
|
|
185
|
+
settleDeferred = false;
|
|
147
186
|
});
|
|
148
187
|
|
|
149
188
|
async function collectCommandFailures(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shanepadgett/tau-agent",
|
|
3
|
-
"version": "0.39.
|
|
3
|
+
"version": "0.39.2",
|
|
4
4
|
"description": "Tau is a custom agentic harness built with pi extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@ast-grep/wasm": "0.45.1",
|
|
38
|
-
"@shanepadgett/tau-tui": "0.39.
|
|
38
|
+
"@shanepadgett/tau-tui": "0.39.2",
|
|
39
39
|
"@vscode/tree-sitter-wasm": "0.3.1",
|
|
40
40
|
"image-size": "2.0.2",
|
|
41
41
|
"smol-toml": "1.8.0",
|
package/shared/events.ts
CHANGED
|
@@ -16,6 +16,15 @@ export type TauAgentEvents = {
|
|
|
16
16
|
id: string;
|
|
17
17
|
disposition: "notify" | "discard";
|
|
18
18
|
};
|
|
19
|
+
/** Pause silent post-edit checks across a compact that will resume the same work chain. */
|
|
20
|
+
"tau:silent-command-runner.pause": {
|
|
21
|
+
id: string;
|
|
22
|
+
};
|
|
23
|
+
/** End a silent-check pause. continue keeps the chain open; settle finalizes a deferred settle. */
|
|
24
|
+
"tau:silent-command-runner.resume": {
|
|
25
|
+
id: string;
|
|
26
|
+
disposition: "continue" | "settle";
|
|
27
|
+
};
|
|
19
28
|
"tau:file-mutation.applied": {
|
|
20
29
|
source: "patch";
|
|
21
30
|
toolCallId: string;
|