@shanepadgett/tau-agent 0.33.1 → 0.35.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/docs/context.md +29 -20
- package/docs/extending-tau-agent.md +63 -24
- package/extensions/appshot/index.ts +112 -111
- package/extensions/aside/README.md +7 -0
- package/extensions/aside/index.ts +168 -0
- package/extensions/aside/panel.ts +83 -0
- package/extensions/bash-approval/README.md +20 -0
- package/extensions/bash-approval/index.ts +235 -0
- package/extensions/bash-approval/settings.ts +24 -0
- package/extensions/branch/index.ts +38 -21
- package/extensions/cache-diagnostics/index.ts +70 -58
- package/extensions/checkpoint/README.md +9 -0
- package/extensions/checkpoint/checkpoint-budget.ts +66 -0
- package/extensions/checkpoint/checkpoint.ts +279 -0
- package/extensions/checkpoint/index.ts +102 -0
- package/extensions/checkpoint/messages.ts +170 -0
- package/extensions/checkpoint/prompt.ts +24 -0
- package/extensions/checkpoint/settings.ts +27 -0
- package/extensions/commit/commit-effort.ts +3 -3
- package/extensions/commit/commit-plan.ts +2 -2
- package/extensions/context/README.md +12 -8
- package/extensions/context/definitions.ts +178 -55
- package/extensions/context/index.ts +192 -160
- package/extensions/context/panel.ts +57 -37
- package/extensions/context/sync.ts +139 -89
- package/extensions/context/validation.ts +37 -25
- package/extensions/effort/README.md +1 -1
- package/extensions/effort/index.ts +3 -3
- package/extensions/effort/state.ts +3 -18
- package/extensions/explore/guidance.ts +6 -47
- package/extensions/explore/index.ts +38 -53
- package/extensions/explore/{ast/read → read}/hook.ts +12 -7
- package/extensions/explore/{ast/tools → tools}/ast-search.ts +15 -19
- package/extensions/explore/{ast/tools → tools}/context.ts +16 -23
- package/extensions/explore/{ast/tools → tools}/deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/discover.ts +15 -17
- package/extensions/explore/{ast/tools → tools}/impact.ts +20 -23
- package/extensions/explore/{ast/tools → tools}/outline.ts +21 -24
- package/extensions/explore/{ast/tools → tools}/relationships.ts +23 -32
- package/extensions/explore/{ast/tools → tools}/render.ts +1 -1
- package/extensions/explore/{ast/tools → tools}/reverse-deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/show.ts +16 -19
- package/extensions/explore/tools/target-params.ts +9 -0
- package/extensions/footer/index.ts +75 -56
- package/extensions/handoff/index.ts +8 -30
- package/extensions/image-gen/index.ts +46 -40
- package/extensions/patch/executor.ts +190 -135
- package/extensions/patch/matcher.ts +82 -48
- package/extensions/patch/parser.ts +149 -105
- package/extensions/patch/render.ts +32 -39
- package/extensions/patch/summary.ts +30 -26
- package/extensions/ready/README.md +7 -0
- package/extensions/ready/index.ts +58 -0
- package/extensions/ready/model.ts +128 -0
- package/extensions/ready/packs.ts +272 -0
- package/extensions/ready/render.ts +445 -0
- package/extensions/ready/scan.ts +760 -0
- package/extensions/reference/index.ts +2 -0
- package/extensions/reference/panel.ts +94 -31
- package/extensions/review/README.md +14 -6
- package/extensions/review/index.ts +58 -99
- package/extensions/review/model.ts +13 -33
- package/extensions/review/session.ts +9 -23
- package/extensions/runtime-context/context.ts +30 -26
- package/extensions/script-runner/README.md +2 -2
- package/extensions/script-runner/index.ts +122 -82
- package/extensions/silent-command-runner/index.ts +38 -23
- package/extensions/soul/README.md +2 -2
- package/extensions/soul/index.ts +4 -4
- package/extensions/soul/prompt.ts +6 -10
- package/extensions/soul/settings.ts +6 -3
- package/extensions/subagent/agents/context-sync.md +185 -33
- package/extensions/subagent/agents/scout.md +2 -2
- package/extensions/subagent/agents/web-research.md +2 -2
- package/extensions/subagent/agents.ts +137 -84
- package/extensions/subagent/cmux-dashboard.ts +39 -30
- package/extensions/subagent/index.ts +79 -59
- package/extensions/subagent/resume.ts +1 -1
- package/extensions/subagent/run.ts +308 -193
- package/extensions/subagent/runtime.ts +781 -343
- package/extensions/tau/index.ts +47 -38
- package/extensions/tau-help/help.md +20 -8
- package/extensions/tool-loader/README.md +4 -2
- package/extensions/tool-loader/index.ts +77 -52
- package/extensions/web/index.ts +6 -3
- package/extensions/web/webfetch.ts +114 -86
- package/package.json +3 -3
- package/schemas/tau.schema.json +38 -35
- package/shared/bounded-text-result.ts +1 -0
- package/shared/checkpoint-visibility.ts +9 -0
- package/shared/events.ts +28 -10
- package/shared/isolated-session.ts +72 -30
- package/shared/model-effort.ts +23 -22
- package/shared/model-fallback/index.ts +66 -41
- package/shared/settings/load.ts +45 -38
- package/shared/temporary-output-store.ts +16 -10
- package/{extensions/explore → src}/ast/adapter.ts +11 -2
- package/{extensions/explore → src}/ast/engine.ts +54 -38
- package/{extensions/explore → src}/ast/format/ast-search.ts +15 -6
- package/{extensions/explore → src}/ast/format/context.ts +3 -6
- package/src/ast/format/deps.ts +94 -0
- package/{extensions/explore → src}/ast/format/discover.ts +2 -2
- package/{extensions/explore → src}/ast/format/impact.ts +9 -11
- package/{extensions/explore → src}/ast/format/outline.ts +2 -2
- package/{extensions/explore → src}/ast/format/relationships.ts +11 -7
- package/{extensions/explore → src}/ast/format/show.ts +1 -1
- package/src/ast/format/targeted-result.ts +20 -0
- package/src/ast/grammars/c_sharp.wasm +0 -0
- package/{extensions/explore → src}/ast/grammars/manifest.json +9 -12
- package/{extensions/explore → src}/ast/grammars/manifest.ts +0 -4
- package/{extensions/explore → src}/ast/graph/file-graph.ts +210 -98
- package/{extensions/explore → src}/ast/graph/relationships.ts +285 -72
- package/{extensions/explore → src}/ast/ir.ts +6 -0
- package/src/ast/languages/csharp-file-deps.ts +90 -0
- package/{extensions/explore → src}/ast/languages/csharp.ts +9 -40
- package/src/ast/languages/dotted-index.ts +131 -0
- package/{extensions/explore → src}/ast/languages/file-dep-util.ts +22 -13
- package/src/ast/languages/fixtures/sample.cs +53 -0
- package/src/ast/languages/fixtures/sample.cs.expected.json +156 -0
- package/src/ast/languages/fixtures/sample.go +37 -0
- package/src/ast/languages/fixtures/sample.go.expected.json +96 -0
- package/src/ast/languages/fixtures/sample.java +40 -0
- package/src/ast/languages/fixtures/sample.java.expected.json +126 -0
- package/src/ast/languages/fixtures/sample.kt +31 -0
- package/src/ast/languages/fixtures/sample.kt.expected.json +134 -0
- package/src/ast/languages/fixtures/sample.md +23 -0
- package/src/ast/languages/fixtures/sample.md.expected.json +44 -0
- package/src/ast/languages/fixtures/sample.rs +54 -0
- package/src/ast/languages/fixtures/sample.rs.expected.json +178 -0
- package/src/ast/languages/fixtures/sample.swift +45 -0
- package/src/ast/languages/fixtures/sample.swift.expected.json +147 -0
- package/src/ast/languages/fixtures/sample.ts +45 -0
- package/src/ast/languages/fixtures/sample.ts.expected.json +141 -0
- package/src/ast/languages/fixtures/sample.tsx +36 -0
- package/src/ast/languages/fixtures/sample.tsx.expected.json +59 -0
- package/{extensions/explore → src}/ast/languages/go-file-deps.ts +6 -0
- package/{extensions/explore → src}/ast/languages/go.ts +21 -3
- package/{extensions/explore → src}/ast/languages/java.ts +5 -38
- package/src/ast/languages/jvm-file-deps.ts +135 -0
- package/{extensions/explore → src}/ast/languages/kotlin.ts +5 -39
- package/{extensions/explore → src}/ast/languages/rust-file-deps.ts +3 -3
- package/{extensions/explore → src}/ast/languages/rust.ts +21 -13
- package/{extensions/explore → src}/ast/languages/swift-file-deps.ts +22 -15
- package/{extensions/explore → src}/ast/languages/swift.ts +9 -39
- package/{extensions/explore → src}/ast/languages/tree.ts +47 -0
- package/{extensions/explore → src}/ast/languages/typescript-file-deps.ts +108 -0
- package/{extensions/explore → src}/ast/languages/typescript-package-surface.ts +4 -3
- package/{extensions/explore → src}/ast/languages/typescript.ts +3 -5
- package/{extensions/explore → src}/ast/markdown.ts +72 -47
- package/{extensions/explore → src}/ast/queries/ast-search.ts +164 -146
- package/{extensions/explore → src}/ast/queries/composite-target.ts +1 -1
- package/{extensions/explore → src}/ast/queries/context.ts +116 -80
- package/{extensions/explore → src}/ast/queries/discover.ts +154 -105
- package/src/ast/queries/impact.ts +291 -0
- package/{extensions/explore → src}/ast/queries/outline.ts +4 -2
- package/{extensions/explore → src}/ast/queries/show.ts +46 -42
- package/{extensions/explore → src}/ast/query.ts +1 -1
- package/{extensions/explore → src}/ast/registry.ts +1 -2
- package/{extensions/explore → src}/ast/scan.ts +1 -1
- package/src/ast/session.ts +50 -0
- package/{extensions/explore → src}/ast/slice.ts +8 -0
- package/{extensions/explore → src/ast}/traverse.ts +32 -20
- package/src/file-injection/index.ts +547 -0
- package/src/image-generation/client.ts +50 -31
- package/src/image-generation/index.ts +177 -134
- package/src/index.ts +2 -0
- package/src/tool-loading/index.ts +58 -0
- package/extensions/context/evidence.ts +0 -517
- package/extensions/context/projection.ts +0 -141
- package/extensions/context/state.ts +0 -30
- package/extensions/context/write-scope.ts +0 -109
- package/extensions/explore/ast/format/deps.ts +0 -86
- package/extensions/explore/ast/grammars/odin.wasm +0 -0
- package/extensions/explore/ast/languages/csharp-file-deps.ts +0 -189
- package/extensions/explore/ast/languages/fixtures/sample.cs +0 -17
- package/extensions/explore/ast/languages/fixtures/sample.java +0 -21
- package/extensions/explore/ast/languages/fixtures/sample.kt +0 -15
- package/extensions/explore/ast/languages/fixtures/sample.odin +0 -28
- package/extensions/explore/ast/languages/fixtures/sample.rs +0 -31
- package/extensions/explore/ast/languages/fixtures/sample.swift +0 -25
- package/extensions/explore/ast/languages/jvm-file-deps.ts +0 -217
- package/extensions/explore/ast/languages/odin-file-deps.ts +0 -175
- package/extensions/explore/ast/languages/odin.ts +0 -407
- package/extensions/explore/ast/queries/impact.ts +0 -250
- package/extensions/explore/outline-injection.ts +0 -151
- package/extensions/explore/read/autoread.ts +0 -118
- package/extensions/review/panel.ts +0 -128
- package/extensions/working-memory/README.md +0 -17
- package/extensions/working-memory/checkpoint.ts +0 -242
- package/extensions/working-memory/index.ts +0 -341
- package/extensions/working-memory/memory.ts +0 -235
- package/extensions/working-memory/render.ts +0 -185
- package/extensions/working-memory/settings.ts +0 -38
- package/extensions/working-memory/state.ts +0 -158
- package/shared/autoread.ts +0 -234
- package/shared/context-messages.ts +0 -19
- package/shared/outline-injection.ts +0 -56
- /package/{extensions/explore → src}/ast/format/composite.ts +0 -0
- /package/{extensions/explore → src}/ast/grammars/kotlin.wasm +0 -0
- /package/{extensions/explore → src}/ast/grammars/swift.wasm +0 -0
- /package/{extensions/explore → src}/ast/identity.ts +0 -0
- /package/{extensions/explore → src}/ast/package-surface.ts +0 -0
- /package/{extensions/explore/ast/read/policy.ts → src/ast/read-policy.ts} +0 -0
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import type { AgentToolResult, Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
3
|
-
import { Marker } from "@shanepadgett/tau-tui";
|
|
4
|
-
import { formatToolRowTitle, type ToolRowStateStore } from "../../shared/tool-row-state.ts";
|
|
5
|
-
import type { WorkingMemoryInput } from "./checkpoint.ts";
|
|
6
|
-
import { parseWorkingMemoryDetails } from "./state.ts";
|
|
7
|
-
|
|
8
|
-
const MAX_ITEMS = 20;
|
|
9
|
-
const MAX_LINE = 240;
|
|
10
|
-
const MAX_TEXT = 4_000;
|
|
11
|
-
|
|
12
|
-
export type WorkingMemoryNudgeDetails =
|
|
13
|
-
| {
|
|
14
|
-
v: 1;
|
|
15
|
-
kind: "automatic";
|
|
16
|
-
tokens: number;
|
|
17
|
-
boundaryTokens: number;
|
|
18
|
-
reminder: number;
|
|
19
|
-
tier: number;
|
|
20
|
-
tierCount: number;
|
|
21
|
-
anchorToolCallId: string | null;
|
|
22
|
-
}
|
|
23
|
-
| {
|
|
24
|
-
v: 1;
|
|
25
|
-
kind: "manual";
|
|
26
|
-
tokens: null;
|
|
27
|
-
boundaryTokens: null;
|
|
28
|
-
reminder: null;
|
|
29
|
-
tier: null;
|
|
30
|
-
tierCount: null;
|
|
31
|
-
anchorToolCallId: string | null;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export function parseWorkingMemoryNudge(value: unknown): WorkingMemoryNudgeDetails | undefined {
|
|
35
|
-
if (!isRecord(value) || value.v !== 1 || (value.kind !== "automatic" && value.kind !== "manual")) return undefined;
|
|
36
|
-
if (value.anchorToolCallId !== null && !nonempty(value.anchorToolCallId)) return undefined;
|
|
37
|
-
if (value.kind === "manual") {
|
|
38
|
-
if (
|
|
39
|
-
value.tokens !== null ||
|
|
40
|
-
value.boundaryTokens !== null ||
|
|
41
|
-
value.reminder !== null ||
|
|
42
|
-
value.tier !== null ||
|
|
43
|
-
value.tierCount !== null
|
|
44
|
-
) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
v: 1,
|
|
49
|
-
kind: "manual",
|
|
50
|
-
tokens: null,
|
|
51
|
-
boundaryTokens: null,
|
|
52
|
-
reminder: null,
|
|
53
|
-
tier: null,
|
|
54
|
-
tierCount: null,
|
|
55
|
-
anchorToolCallId: value.anchorToolCallId,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
if (
|
|
59
|
-
!count(value.tokens, 0) ||
|
|
60
|
-
!count(value.boundaryTokens, 1) ||
|
|
61
|
-
!count(value.reminder, 1) ||
|
|
62
|
-
!count(value.tier, 1, 5) ||
|
|
63
|
-
!count(value.tierCount, 1, 5) ||
|
|
64
|
-
value.boundaryTokens > value.tokens ||
|
|
65
|
-
value.tier > value.tierCount ||
|
|
66
|
-
value.tier !== Math.min(value.reminder, value.tierCount)
|
|
67
|
-
) {
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
v: 1,
|
|
72
|
-
kind: "automatic",
|
|
73
|
-
tokens: value.tokens,
|
|
74
|
-
boundaryTokens: value.boundaryTokens,
|
|
75
|
-
reminder: value.reminder,
|
|
76
|
-
tier: value.tier,
|
|
77
|
-
tierCount: value.tierCount,
|
|
78
|
-
anchorToolCallId: value.anchorToolCallId,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function renderWorkingMemoryNudge(details: unknown, theme: Theme): Marker | undefined {
|
|
83
|
-
const parsed = parseWorkingMemoryNudge(details);
|
|
84
|
-
if (!parsed) return undefined;
|
|
85
|
-
return new Marker({
|
|
86
|
-
theme,
|
|
87
|
-
state: "muted",
|
|
88
|
-
label: "Memory:",
|
|
89
|
-
parts:
|
|
90
|
-
parsed.kind === "manual" ? ["Reassessment requested."] : [formatTokens(parsed.boundaryTokens), "Reassess."],
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function renderWorkingMemoryCall(
|
|
95
|
-
args: WorkingMemoryInput,
|
|
96
|
-
theme: Theme,
|
|
97
|
-
context: {
|
|
98
|
-
rowState: ToolRowStateStore;
|
|
99
|
-
rowId: string;
|
|
100
|
-
invalidate: () => void;
|
|
101
|
-
lastComponent: unknown;
|
|
102
|
-
executionStarted: boolean;
|
|
103
|
-
},
|
|
104
|
-
): Text {
|
|
105
|
-
context.rowState.watch(context.rowId, context.invalidate);
|
|
106
|
-
const component = context.lastComponent instanceof Text ? context.lastComponent : new Text("", 0, 0);
|
|
107
|
-
if (context.executionStarted) {
|
|
108
|
-
component.setText("");
|
|
109
|
-
return component;
|
|
110
|
-
}
|
|
111
|
-
const kept = Array.isArray(args.keep) ? args.keep.length : 0;
|
|
112
|
-
const read = Array.isArray(args.readFiles) ? args.readFiles.length : 0;
|
|
113
|
-
const outlined = Array.isArray(args.outlineFiles) ? args.outlineFiles.length : 0;
|
|
114
|
-
const deferred = Array.isArray(args.deferFiles) ? args.deferFiles.length : 0;
|
|
115
|
-
component.setText(
|
|
116
|
-
`${formatToolRowTitle(context.rowState, context.rowId, "working_memory", theme)} ${theme.fg("muted", `${kept} kept · ${read} read · ${outlined} outline · ${deferred} deferred`)}`,
|
|
117
|
-
);
|
|
118
|
-
return component;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function renderWorkingMemoryResult(
|
|
122
|
-
result: AgentToolResult<unknown>,
|
|
123
|
-
expanded: boolean,
|
|
124
|
-
theme: Theme,
|
|
125
|
-
lastComponent: unknown,
|
|
126
|
-
): Text {
|
|
127
|
-
const component = lastComponent instanceof Text ? lastComponent : new Text("", 0, 0);
|
|
128
|
-
const details = parseWorkingMemoryDetails(result.details);
|
|
129
|
-
if (!details) {
|
|
130
|
-
component.setText(
|
|
131
|
-
theme.fg("warning", bounded(firstText(result) || "working_memory returned invalid details", 1_000)),
|
|
132
|
-
);
|
|
133
|
-
return component;
|
|
134
|
-
}
|
|
135
|
-
let text = theme.fg(
|
|
136
|
-
details.warnings.length === 0 ? "success" : "warning",
|
|
137
|
-
`Checkpoint · kept ${details.retainedRefs.length} · read ${details.readFiles.length} · outlined ${details.outlinedFiles.length} · deferred ${details.deferredFiles.length} · pruned ${details.removedUnits}${details.warnings.length === 0 ? "" : ` · warnings ${details.warnings.length}`}`,
|
|
138
|
-
);
|
|
139
|
-
if (expanded) {
|
|
140
|
-
const lines = [
|
|
141
|
-
bounded(firstText(result), 1_500),
|
|
142
|
-
...details.retainedLabels.map((item) => `${item.ref} ${item.label}: ${item.preview}`),
|
|
143
|
-
...details.readFiles.map((path) => `read: ${path}`),
|
|
144
|
-
...details.outlinedFiles.map((file) => `outlined: ${file.path}`),
|
|
145
|
-
...details.deferredFiles.map((file) => `deferred: ${file.path} — ${file.reason}; when ${file.relevantWhen}`),
|
|
146
|
-
...details.warnings.map((warning) => `warning: ${warning}`),
|
|
147
|
-
].filter(Boolean);
|
|
148
|
-
let remaining = MAX_TEXT - visibleWidth(text);
|
|
149
|
-
for (const line of lines.slice(0, MAX_ITEMS)) {
|
|
150
|
-
if (remaining <= 1) break;
|
|
151
|
-
const styled = theme.fg("dim", bounded(line, MAX_LINE));
|
|
152
|
-
text += `\n${truncateToWidth(styled, remaining - 1, "…")}`;
|
|
153
|
-
remaining -= 1 + Math.min(visibleWidth(styled), remaining - 1);
|
|
154
|
-
}
|
|
155
|
-
if (lines.length > MAX_ITEMS && remaining > 10)
|
|
156
|
-
text += `\n${theme.fg("dim", `… ${lines.length - MAX_ITEMS} more`)}`;
|
|
157
|
-
}
|
|
158
|
-
component.setText(text);
|
|
159
|
-
return component;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function firstText(result: AgentToolResult<unknown>): string {
|
|
163
|
-
for (const part of result.content) if (part.type === "text") return part.text;
|
|
164
|
-
return "";
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function bounded(text: string, maximum: number): string {
|
|
168
|
-
return text.length <= maximum ? text : `${text.slice(0, maximum - 1)}…`;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function formatTokens(tokens: number): string {
|
|
172
|
-
return tokens < 1_000 ? `${tokens}` : `${Math.round(tokens / 1_000)}k`;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function count(value: unknown, minimum: number, maximum = Number.MAX_SAFE_INTEGER): value is number {
|
|
176
|
-
return Number.isSafeInteger(value) && (value as number) >= minimum && (value as number) <= maximum;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function nonempty(value: unknown): value is string {
|
|
180
|
-
return typeof value === "string" && value.length > 0;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
184
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
185
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import { defineTauExtensionSettings } from "../../shared/settings/define.ts";
|
|
3
|
-
|
|
4
|
-
const DEFAULT_NUDGE_INSTRUCTIONS: [string, ...string[]] = [
|
|
5
|
-
"Reassess working memory. Continue coherent exploration when its evidence remains useful; otherwise prune known dead ends, obsolete outputs, and other context with no expected value.",
|
|
6
|
-
"Context is materially larger. Prune stale or bulky irrelevant evidence when safe, but keep active working evidence that would otherwise need to be reread.",
|
|
7
|
-
"Strongly reassess before more broad work. Remove accumulated waste and carry useful information at cheapest sufficient fidelity without scrubbing the active working set.",
|
|
8
|
-
];
|
|
9
|
-
|
|
10
|
-
export default defineTauExtensionSettings({
|
|
11
|
-
key: "workingMemory",
|
|
12
|
-
defaults: {
|
|
13
|
-
enabled: true as boolean,
|
|
14
|
-
nudgeEveryTokens: 40_000 as number,
|
|
15
|
-
nudgeInstructions: DEFAULT_NUDGE_INSTRUCTIONS,
|
|
16
|
-
},
|
|
17
|
-
schema: Type.Object(
|
|
18
|
-
{
|
|
19
|
-
enabled: Type.Optional(Type.Boolean({ default: true, description: "Enable working-memory checkpoints." })),
|
|
20
|
-
nudgeEveryTokens: Type.Optional(
|
|
21
|
-
Type.Integer({
|
|
22
|
-
default: 40_000,
|
|
23
|
-
minimum: 1,
|
|
24
|
-
description: "Active-context token interval between advisory working-memory reminders.",
|
|
25
|
-
}),
|
|
26
|
-
),
|
|
27
|
-
nudgeInstructions: Type.Optional(
|
|
28
|
-
Type.Array(Type.String({ minLength: 1, maxLength: 2_000 }), {
|
|
29
|
-
default: DEFAULT_NUDGE_INSTRUCTIONS,
|
|
30
|
-
minItems: 1,
|
|
31
|
-
maxItems: 5,
|
|
32
|
-
description: "Ordered advisory working-memory instructions. Later reminders repeat final instruction.",
|
|
33
|
-
}),
|
|
34
|
-
),
|
|
35
|
-
},
|
|
36
|
-
{ additionalProperties: false },
|
|
37
|
-
),
|
|
38
|
-
});
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import type { SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
export const WORKING_MEMORY_TOOL = "working_memory";
|
|
4
|
-
|
|
5
|
-
export interface DeferredFile {
|
|
6
|
-
path: string;
|
|
7
|
-
reason: string;
|
|
8
|
-
relevantWhen: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface RetainedLabel {
|
|
12
|
-
ref: string;
|
|
13
|
-
label: string;
|
|
14
|
-
preview: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface WorkingMemoryCheckpointDetailsV2 {
|
|
18
|
-
v: 2;
|
|
19
|
-
anchorToolCallId: string;
|
|
20
|
-
retainedRefs: string[];
|
|
21
|
-
retainedLabels: RetainedLabel[];
|
|
22
|
-
prunedRowIds: string[];
|
|
23
|
-
readFiles: string[];
|
|
24
|
-
outlinedFiles: Array<{ path: string; rowId: string }>;
|
|
25
|
-
deferredFiles: DeferredFile[];
|
|
26
|
-
removedUnits: number;
|
|
27
|
-
warnings: string[];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface ActiveWorkingMemoryState {
|
|
31
|
-
latestAnchorToolCallId: string | undefined;
|
|
32
|
-
retainedRefs: readonly string[];
|
|
33
|
-
prunedRowIds: ReadonlySet<string>;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function parseWorkingMemoryDetails(value: unknown): WorkingMemoryCheckpointDetailsV2 | undefined {
|
|
37
|
-
if (!isRecord(value) || value.v !== 2 || !nonempty(value.anchorToolCallId)) return undefined;
|
|
38
|
-
const keys = [
|
|
39
|
-
"v",
|
|
40
|
-
"anchorToolCallId",
|
|
41
|
-
"retainedRefs",
|
|
42
|
-
"retainedLabels",
|
|
43
|
-
"prunedRowIds",
|
|
44
|
-
"readFiles",
|
|
45
|
-
"outlinedFiles",
|
|
46
|
-
"deferredFiles",
|
|
47
|
-
"removedUnits",
|
|
48
|
-
"warnings",
|
|
49
|
-
];
|
|
50
|
-
if (Object.keys(value).length !== keys.length || !keys.every((key) => Object.hasOwn(value, key))) return undefined;
|
|
51
|
-
const retainedRefs = uniqueStrings(value.retainedRefs);
|
|
52
|
-
const prunedRowIds = uniqueStrings(value.prunedRowIds);
|
|
53
|
-
const readFiles = uniqueStrings(value.readFiles);
|
|
54
|
-
const warnings = strings(value.warnings);
|
|
55
|
-
const retainedLabels = parseRetainedLabels(value.retainedLabels);
|
|
56
|
-
const outlinedFiles = parseOutlinedFiles(value.outlinedFiles);
|
|
57
|
-
const deferredFiles = parseDeferredFiles(value.deferredFiles);
|
|
58
|
-
if (
|
|
59
|
-
!retainedRefs ||
|
|
60
|
-
retainedRefs.length === 0 ||
|
|
61
|
-
!prunedRowIds ||
|
|
62
|
-
!readFiles ||
|
|
63
|
-
!warnings ||
|
|
64
|
-
!retainedLabels ||
|
|
65
|
-
retainedLabels.length !== retainedRefs.length ||
|
|
66
|
-
retainedLabels.some((label, index) => label.ref !== retainedRefs[index]) ||
|
|
67
|
-
!outlinedFiles ||
|
|
68
|
-
!deferredFiles ||
|
|
69
|
-
!Number.isSafeInteger(value.removedUnits) ||
|
|
70
|
-
(value.removedUnits as number) < 0
|
|
71
|
-
) {
|
|
72
|
-
return undefined;
|
|
73
|
-
}
|
|
74
|
-
return {
|
|
75
|
-
v: 2,
|
|
76
|
-
anchorToolCallId: value.anchorToolCallId,
|
|
77
|
-
retainedRefs,
|
|
78
|
-
retainedLabels,
|
|
79
|
-
prunedRowIds,
|
|
80
|
-
readFiles,
|
|
81
|
-
outlinedFiles,
|
|
82
|
-
deferredFiles,
|
|
83
|
-
removedUnits: value.removedUnits as number,
|
|
84
|
-
warnings,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function replayWorkingMemoryState(branch: readonly SessionEntry[], enabled: boolean): ActiveWorkingMemoryState {
|
|
89
|
-
let prunedRowIds = new Set<string>();
|
|
90
|
-
let latestAnchorToolCallId: string | undefined;
|
|
91
|
-
let retainedRefs: readonly string[] = [];
|
|
92
|
-
if (enabled) {
|
|
93
|
-
for (const entry of branch) {
|
|
94
|
-
if (entry.type !== "message" || entry.message.role !== "toolResult") continue;
|
|
95
|
-
if (entry.message.toolName !== WORKING_MEMORY_TOOL) continue;
|
|
96
|
-
const details = parseWorkingMemoryDetails(entry.message.details);
|
|
97
|
-
if (!details || details.anchorToolCallId !== entry.message.toolCallId) continue;
|
|
98
|
-
prunedRowIds = new Set(details.prunedRowIds);
|
|
99
|
-
latestAnchorToolCallId = details.anchorToolCallId;
|
|
100
|
-
retainedRefs = details.retainedRefs;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return { latestAnchorToolCallId, retainedRefs, prunedRowIds };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function parseRetainedLabels(value: unknown): RetainedLabel[] | undefined {
|
|
107
|
-
if (!Array.isArray(value)) return undefined;
|
|
108
|
-
const labels: RetainedLabel[] = [];
|
|
109
|
-
for (const item of value) {
|
|
110
|
-
if (!isRecord(item) || !nonempty(item.ref) || !nonempty(item.label) || typeof item.preview !== "string") {
|
|
111
|
-
return undefined;
|
|
112
|
-
}
|
|
113
|
-
labels.push({ ref: item.ref, label: item.label, preview: item.preview });
|
|
114
|
-
}
|
|
115
|
-
return labels;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function parseOutlinedFiles(value: unknown): Array<{ path: string; rowId: string }> | undefined {
|
|
119
|
-
if (!Array.isArray(value)) return undefined;
|
|
120
|
-
const files: Array<{ path: string; rowId: string }> = [];
|
|
121
|
-
for (const item of value) {
|
|
122
|
-
if (!isRecord(item) || !nonempty(item.path) || !nonempty(item.rowId)) return undefined;
|
|
123
|
-
files.push({ path: item.path, rowId: item.rowId });
|
|
124
|
-
}
|
|
125
|
-
return files;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function parseDeferredFiles(value: unknown): DeferredFile[] | undefined {
|
|
129
|
-
if (!Array.isArray(value)) return undefined;
|
|
130
|
-
const files: DeferredFile[] = [];
|
|
131
|
-
for (const item of value) {
|
|
132
|
-
if (!isRecord(item) || !nonempty(item.path) || !nonempty(item.reason) || !nonempty(item.relevantWhen)) {
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
files.push({ path: item.path, reason: item.reason, relevantWhen: item.relevantWhen });
|
|
136
|
-
}
|
|
137
|
-
return files;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function uniqueStrings(value: unknown): string[] | undefined {
|
|
141
|
-
const parsed = strings(value, true);
|
|
142
|
-
if (!parsed || new Set(parsed).size !== parsed.length) return undefined;
|
|
143
|
-
return parsed;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function strings(value: unknown, requireNonempty = false): string[] | undefined {
|
|
147
|
-
if (!Array.isArray(value)) return undefined;
|
|
148
|
-
if (!value.every((item) => typeof item === "string" && (!requireNonempty || item.length > 0))) return undefined;
|
|
149
|
-
return [...value];
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function nonempty(value: unknown): value is string {
|
|
153
|
-
return typeof value === "string" && value.length > 0;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
157
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
158
|
-
}
|
package/shared/autoread.ts
DELETED
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
|
-
import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import { Marker, type MarkerState } from "@shanepadgett/tau-tui";
|
|
6
|
-
import { onTauEvent, type TauAgentEvents } from "./events.js";
|
|
7
|
-
import { createCompleteFileMeta, type ReadCacheMetaV1 } from "./full-file-knowledge.ts";
|
|
8
|
-
import type { ToolRowStateStore } from "./tool-row-state.js";
|
|
9
|
-
|
|
10
|
-
const AUTOREAD_MESSAGE_TYPE = "tau.autoread";
|
|
11
|
-
|
|
12
|
-
type AutoreadStatus = "reading" | "read" | "failed";
|
|
13
|
-
|
|
14
|
-
export interface AutoreadDetails {
|
|
15
|
-
rowId: string;
|
|
16
|
-
path: string;
|
|
17
|
-
cwd: string;
|
|
18
|
-
source: string;
|
|
19
|
-
batchId: string;
|
|
20
|
-
status: AutoreadStatus;
|
|
21
|
-
error?: string;
|
|
22
|
-
readCache?: ReadCacheMetaV1;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface PreparedAutoreadMessage {
|
|
26
|
-
customType: typeof AUTOREAD_MESSAGE_TYPE;
|
|
27
|
-
content: string;
|
|
28
|
-
display: true;
|
|
29
|
-
details: AutoreadDetails & { status: "read"; readCache: ReadCacheMetaV1 };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export type PrepareAutoreadMessage = (options: {
|
|
33
|
-
rowId: string;
|
|
34
|
-
path: string;
|
|
35
|
-
cwd: string;
|
|
36
|
-
source: string;
|
|
37
|
-
batchId: string;
|
|
38
|
-
signal: AbortSignal | undefined;
|
|
39
|
-
isLifecycleCurrent: () => boolean;
|
|
40
|
-
maximumBytes?: number;
|
|
41
|
-
}) => Promise<PreparedAutoreadMessage>;
|
|
42
|
-
|
|
43
|
-
export async function prepareAutoreadMessage(options: {
|
|
44
|
-
rowId: string;
|
|
45
|
-
path: string;
|
|
46
|
-
cwd: string;
|
|
47
|
-
source: string;
|
|
48
|
-
batchId: string;
|
|
49
|
-
signal: AbortSignal | undefined;
|
|
50
|
-
isLifecycleCurrent: () => boolean;
|
|
51
|
-
maximumBytes?: number;
|
|
52
|
-
}): Promise<PreparedAutoreadMessage> {
|
|
53
|
-
assertPreparationCurrent(options.signal, options.isLifecycleCurrent);
|
|
54
|
-
const pathKey = resolve(options.cwd, options.path);
|
|
55
|
-
const bytes = options.signal ? await readFile(pathKey, { signal: options.signal }) : await readFile(pathKey);
|
|
56
|
-
if (options.maximumBytes !== undefined && bytes.byteLength > options.maximumBytes) {
|
|
57
|
-
throw new Error(`File exceeds the ${options.maximumBytes}-byte complete-file snapshot limit`);
|
|
58
|
-
}
|
|
59
|
-
const content = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
60
|
-
const messageContent = `${options.path}\n${content}`;
|
|
61
|
-
const totalLines = content.split("\n").length;
|
|
62
|
-
const readCache = createCompleteFileMeta({
|
|
63
|
-
pathKey,
|
|
64
|
-
presentation: "plain",
|
|
65
|
-
servedHash: createHash("sha256").update(content, "utf8").digest("hex"),
|
|
66
|
-
mode: "baseline",
|
|
67
|
-
sourceText: content,
|
|
68
|
-
returnedText: messageContent,
|
|
69
|
-
totalLines,
|
|
70
|
-
summary: `${totalLines} lines`,
|
|
71
|
-
}) satisfies ReadCacheMetaV1;
|
|
72
|
-
assertPreparationCurrent(options.signal, options.isLifecycleCurrent);
|
|
73
|
-
return {
|
|
74
|
-
customType: AUTOREAD_MESSAGE_TYPE,
|
|
75
|
-
content: messageContent,
|
|
76
|
-
display: true,
|
|
77
|
-
details: {
|
|
78
|
-
rowId: options.rowId,
|
|
79
|
-
path: options.path,
|
|
80
|
-
cwd: options.cwd,
|
|
81
|
-
source: options.source,
|
|
82
|
-
batchId: options.batchId,
|
|
83
|
-
status: "read",
|
|
84
|
-
readCache,
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function registerAutoread(
|
|
90
|
-
pi: ExtensionAPI,
|
|
91
|
-
rowState: ToolRowStateStore,
|
|
92
|
-
prepare: PrepareAutoreadMessage = prepareAutoreadMessage,
|
|
93
|
-
): void {
|
|
94
|
-
let lifecycleGeneration = 0;
|
|
95
|
-
pi.on("session_start", () => {
|
|
96
|
-
lifecycleGeneration += 1;
|
|
97
|
-
});
|
|
98
|
-
pi.on("session_compact", () => {
|
|
99
|
-
lifecycleGeneration += 1;
|
|
100
|
-
});
|
|
101
|
-
pi.on("session_tree", () => {
|
|
102
|
-
lifecycleGeneration += 1;
|
|
103
|
-
});
|
|
104
|
-
pi.on("session_shutdown", () => {
|
|
105
|
-
lifecycleGeneration += 1;
|
|
106
|
-
});
|
|
107
|
-
onTauEvent(pi, "shared.autoread", "tau:autoread.requested", async (data) => {
|
|
108
|
-
const event = readAutoreadRequestedEvent(data);
|
|
109
|
-
if (!event) return;
|
|
110
|
-
const generation = lifecycleGeneration;
|
|
111
|
-
await Promise.all(
|
|
112
|
-
event.files.map(async (file, index) => {
|
|
113
|
-
const rowId = `${event.batchId}:${index}`;
|
|
114
|
-
const details = {
|
|
115
|
-
rowId,
|
|
116
|
-
path: file.path,
|
|
117
|
-
cwd: event.cwd,
|
|
118
|
-
source: event.source,
|
|
119
|
-
batchId: event.batchId,
|
|
120
|
-
} satisfies Omit<AutoreadDetails, "status" | "error">;
|
|
121
|
-
try {
|
|
122
|
-
const message = await prepare({
|
|
123
|
-
...details,
|
|
124
|
-
signal: undefined,
|
|
125
|
-
isLifecycleCurrent: () => generation === lifecycleGeneration,
|
|
126
|
-
});
|
|
127
|
-
pi.sendMessage(message);
|
|
128
|
-
} catch (error) {
|
|
129
|
-
if (generation !== lifecycleGeneration) return;
|
|
130
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
131
|
-
pi.sendMessage({
|
|
132
|
-
customType: AUTOREAD_MESSAGE_TYPE,
|
|
133
|
-
content: `${file.path}\nAutoread failed: ${message}`,
|
|
134
|
-
display: true,
|
|
135
|
-
details: { ...details, status: "failed", error: message },
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}),
|
|
139
|
-
);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
pi.registerMessageRenderer<AutoreadDetails>(AUTOREAD_MESSAGE_TYPE, (message, _options, theme) => {
|
|
143
|
-
const details = readDetails(message.details);
|
|
144
|
-
if (!details) return undefined;
|
|
145
|
-
return new AutoreadMessageComponent(rowState, details.rowId, details.path, details.status, theme);
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function assertPreparationCurrent(signal: AbortSignal | undefined, isLifecycleCurrent: () => boolean): void {
|
|
150
|
-
signal?.throwIfAborted();
|
|
151
|
-
if (!isLifecycleCurrent()) throw new Error("Autoread preparation crossed a session lifecycle boundary");
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function readAutoreadRequestedEvent(value: unknown): TauAgentEvents["tau:autoread.requested"] | undefined {
|
|
155
|
-
if (!value || typeof value !== "object") return undefined;
|
|
156
|
-
const record = value as Record<string, unknown>;
|
|
157
|
-
if (typeof record.source !== "string") return undefined;
|
|
158
|
-
if (typeof record.cwd !== "string") return undefined;
|
|
159
|
-
if (typeof record.batchId !== "string") return undefined;
|
|
160
|
-
if (record.title !== undefined && typeof record.title !== "string") return undefined;
|
|
161
|
-
if (!Array.isArray(record.files)) return undefined;
|
|
162
|
-
const files: Array<{ path: string }> = [];
|
|
163
|
-
for (const file of record.files) {
|
|
164
|
-
if (!file || typeof file !== "object") return undefined;
|
|
165
|
-
const path = (file as Record<string, unknown>).path;
|
|
166
|
-
if (typeof path !== "string") return undefined;
|
|
167
|
-
files.push({ path });
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
source: record.source,
|
|
172
|
-
...(record.title === undefined ? {} : { title: record.title }),
|
|
173
|
-
cwd: record.cwd,
|
|
174
|
-
batchId: record.batchId,
|
|
175
|
-
files,
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function readDetails(value: unknown): AutoreadDetails | undefined {
|
|
180
|
-
if (!value || typeof value !== "object") return undefined;
|
|
181
|
-
const record = value as Record<string, unknown>;
|
|
182
|
-
if (typeof record.rowId !== "string") return undefined;
|
|
183
|
-
if (typeof record.path !== "string") return undefined;
|
|
184
|
-
if (typeof record.cwd !== "string") return undefined;
|
|
185
|
-
if (typeof record.source !== "string") return undefined;
|
|
186
|
-
if (typeof record.batchId !== "string") return undefined;
|
|
187
|
-
if (record.status !== "reading" && record.status !== "read" && record.status !== "failed") return undefined;
|
|
188
|
-
return {
|
|
189
|
-
rowId: record.rowId,
|
|
190
|
-
path: record.path,
|
|
191
|
-
cwd: record.cwd,
|
|
192
|
-
source: record.source,
|
|
193
|
-
batchId: record.batchId,
|
|
194
|
-
status: record.status,
|
|
195
|
-
...(typeof record.error === "string" ? { error: record.error } : {}),
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
class AutoreadMessageComponent {
|
|
200
|
-
private readonly rowState: ToolRowStateStore;
|
|
201
|
-
private readonly rowId: string;
|
|
202
|
-
private readonly path: string;
|
|
203
|
-
private readonly status: AutoreadStatus;
|
|
204
|
-
private readonly theme: Theme;
|
|
205
|
-
|
|
206
|
-
constructor(rowState: ToolRowStateStore, rowId: string, path: string, status: AutoreadStatus, theme: Theme) {
|
|
207
|
-
this.rowState = rowState;
|
|
208
|
-
this.rowId = rowId;
|
|
209
|
-
this.path = path;
|
|
210
|
-
this.status = status;
|
|
211
|
-
this.theme = theme;
|
|
212
|
-
this.rowState.watch(this.rowId, () => this.invalidate());
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
render(width: number): string[] {
|
|
216
|
-
return new Marker({
|
|
217
|
-
theme: this.theme,
|
|
218
|
-
state: this.markerState(),
|
|
219
|
-
label: "autoread",
|
|
220
|
-
parts: [this.path],
|
|
221
|
-
}).render(width);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
invalidate(): void {
|
|
225
|
-
// Rendering is stateless; this watcher gives the owning custom-message row
|
|
226
|
-
// the invalidation signal needed to redraw after a row-state snapshot.
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
private markerState(): MarkerState {
|
|
230
|
-
if (this.rowState.get(this.rowId) === "pruned") return "warning";
|
|
231
|
-
if (this.status === "failed") return "error";
|
|
232
|
-
return this.status === "reading" ? "busy" : "complete";
|
|
233
|
-
}
|
|
234
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { ContextEvent } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
type ContextMessage = ContextEvent["messages"][number];
|
|
4
|
-
|
|
5
|
-
export const CONTEXT_PROJECTION_TYPE = "tau.context.projection";
|
|
6
|
-
|
|
7
|
-
export function isContextProjectionMessage(message: ContextMessage): boolean {
|
|
8
|
-
return message.role === "custom" && message.customType === CONTEXT_PROJECTION_TYPE;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function isLegacyContextMessage(message: ContextMessage): boolean {
|
|
12
|
-
if (message.role !== "custom") return false;
|
|
13
|
-
if (message.customType !== "tau.injected-context" && message.customType !== "tau.autoread") return false;
|
|
14
|
-
return (
|
|
15
|
-
message.details !== undefined &&
|
|
16
|
-
typeof message.details === "object" &&
|
|
17
|
-
(message.details as Record<string, unknown>).source === "context"
|
|
18
|
-
);
|
|
19
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { emitTauEvent, onTauEvent } from "./events.js";
|
|
3
|
-
|
|
4
|
-
export interface OutlineInjectionDetails {
|
|
5
|
-
v: 1;
|
|
6
|
-
rowId: string;
|
|
7
|
-
path: string;
|
|
8
|
-
cwd: string;
|
|
9
|
-
batchId: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface PreparedOutlineInjection {
|
|
13
|
-
customType: "tau.explore.outline";
|
|
14
|
-
content: string;
|
|
15
|
-
display: true;
|
|
16
|
-
details: OutlineInjectionDetails;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface OutlineInjectionRequest {
|
|
20
|
-
cwd: string;
|
|
21
|
-
batchId: string;
|
|
22
|
-
paths: readonly string[];
|
|
23
|
-
signal: AbortSignal | undefined;
|
|
24
|
-
isLifecycleCurrent(): boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface OutlineInjectionResponse {
|
|
28
|
-
messages: PreparedOutlineInjection[];
|
|
29
|
-
warnings: string[];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export type OutlineInjectionProvider = (request: OutlineInjectionRequest) => Promise<OutlineInjectionResponse>;
|
|
33
|
-
|
|
34
|
-
export function registerOutlineInjectionProvider(pi: ExtensionAPI, provider: OutlineInjectionProvider): () => void {
|
|
35
|
-
return onTauEvent(pi, "shared.outline-injection-provider", "tau:outline-injection.requested", (event) => {
|
|
36
|
-
event.accept(provider(event.request));
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export async function requestOutlineInjections(
|
|
41
|
-
pi: Pick<ExtensionAPI, "events">,
|
|
42
|
-
request: OutlineInjectionRequest,
|
|
43
|
-
): Promise<OutlineInjectionResponse> {
|
|
44
|
-
let response: Promise<OutlineInjectionResponse> | undefined;
|
|
45
|
-
emitTauEvent(pi, "tau:outline-injection.requested", {
|
|
46
|
-
request,
|
|
47
|
-
accept(candidate) {
|
|
48
|
-
response ??= candidate;
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
if (response) return response;
|
|
52
|
-
return {
|
|
53
|
-
messages: [],
|
|
54
|
-
warnings: request.paths.map((path) => `${path}: Explore outline provider is unavailable`),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|