@shanepadgett/tau-agent 0.42.3 → 0.44.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/README.md +0 -1
- package/docs/context.md +1 -1
- package/docs/extending-tau-agent.md +1 -2
- package/extensions/attention/README.md +1 -1
- package/extensions/cache-diagnostics/index.ts +4 -0
- package/extensions/context/README.md +1 -24
- package/extensions/context/definitions.ts +1 -52
- package/extensions/context/index.ts +1 -150
- package/extensions/context/panel.ts +0 -72
- package/extensions/explore/guidance.ts +9 -1
- package/extensions/footer/README.md +1 -1
- package/extensions/footer/index.ts +3 -25
- package/extensions/qna/choice-question-body.ts +7 -2
- package/extensions/run-summary/README.md +1 -1
- package/extensions/run-summary/index.ts +18 -25
- package/extensions/runtime-context/README.md +1 -1
- package/extensions/runtime-context/context.ts +1 -1
- package/extensions/runtime-context/index.ts +10 -16
- package/extensions/script-runner/index.ts +21 -29
- package/extensions/silent-command-runner/README.md +0 -2
- package/extensions/silent-command-runner/index.ts +12 -41
- package/extensions/soul/README.md +5 -8
- package/extensions/soul/context.ts +115 -0
- package/extensions/soul/index.ts +141 -7
- package/extensions/soul/prompt.ts +47 -102
- package/extensions/soul/state.ts +114 -0
- package/extensions/soul/tools.ts +31 -0
- package/extensions/tau-help/help.md +6 -18
- package/extensions/tau-help/index.ts +10 -4
- package/extensions/tool-approval/README.md +4 -2
- package/extensions/tool-approval/index.ts +141 -53
- package/extensions/tool-approval/panel.ts +153 -0
- package/extensions/tool-loader/README.md +1 -1
- package/extensions/tool-loader/index.ts +91 -22
- package/package.json +2 -2
- package/schemas/tau.schema.json +0 -104
- package/shared/bounded-text-result.ts +0 -1
- package/shared/events.ts +19 -15
- package/shared/isolated-session.ts +1 -2
- package/shared/model-effort.ts +15 -21
- package/shared/prompt-contributions.ts +24 -0
- package/src/index.ts +1 -1
- package/docs/subagents.md +0 -92
- package/extensions/auto-compact/README.md +0 -9
- package/extensions/auto-compact/index.ts +0 -122
- package/extensions/auto-compact/settings.ts +0 -30
- package/extensions/context/settings.ts +0 -62
- package/extensions/context/sync.ts +0 -276
- package/extensions/context/validation.ts +0 -88
- package/extensions/effort/README.md +0 -7
- package/extensions/effort/index.ts +0 -134
- package/extensions/effort/state.ts +0 -18
- package/extensions/qna/inline-editor-row.ts +0 -56
- package/extensions/soul/overseer.ts +0 -273
- package/extensions/soul/settings.ts +0 -34
- package/extensions/subagent/README.md +0 -67
- package/extensions/subagent/agents/context-sync.md +0 -244
- package/extensions/subagent/agents/dormant/generalist.md +0 -33
- package/extensions/subagent/agents/scout.md +0 -104
- package/extensions/subagent/agents/web-research.md +0 -101
- package/extensions/subagent/agents.ts +0 -261
- package/extensions/subagent/cmux-dashboard.ts +0 -495
- package/extensions/subagent/index.ts +0 -425
- package/extensions/subagent/panel.ts +0 -124
- package/extensions/subagent/render.ts +0 -74
- package/extensions/subagent/resume.ts +0 -78
- package/extensions/subagent/run.ts +0 -641
- package/extensions/subagent/runtime.ts +0 -1296
- package/extensions/subagent/session-resource.ts +0 -61
- package/extensions/subagent/settings.ts +0 -18
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: scout
|
|
3
|
-
description: "Substantial multi-hop local code lookup that would chew parent context; paths, declarations, imports, references, call edges; facts only. Skip small digs"
|
|
4
|
-
tools:
|
|
5
|
-
- read
|
|
6
|
-
- bash
|
|
7
|
-
- outline
|
|
8
|
-
- show
|
|
9
|
-
- discover
|
|
10
|
-
- ast_search
|
|
11
|
-
- deps
|
|
12
|
-
- reverse_deps
|
|
13
|
-
- callers
|
|
14
|
-
- callees
|
|
15
|
-
- references
|
|
16
|
-
- implementations
|
|
17
|
-
names:
|
|
18
|
-
- Pathfinder
|
|
19
|
-
- Trailblazer
|
|
20
|
-
- Lookout
|
|
21
|
-
- Tracker
|
|
22
|
-
- Ranger
|
|
23
|
-
model: openai-codex/gpt-5.6-luna
|
|
24
|
-
thinking: high
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
You are a read-only repository retrieval worker. Locate requested source evidence and return exact cited facts.
|
|
28
|
-
|
|
29
|
-
Do not diagnose bugs, explain causes, infer runtime behavior, evaluate correctness, assess consequences, recommend changes, choose between alternatives, or make design decisions. The parent agent owns all interpretation and judgment.
|
|
30
|
-
|
|
31
|
-
If a task mixes lookup with judgment, perform only its concrete lookup portion and list the unanswered judgment under `Parent question`. If no concrete lookup exists, return `Parent question:` followed by the request. Do not attempt to answer it.
|
|
32
|
-
|
|
33
|
-
Stay inside task. No mutations, side quests, background sweeps, or unasked advice.
|
|
34
|
-
|
|
35
|
-
## Allowed work
|
|
36
|
-
|
|
37
|
-
- Find files, declarations, literals, configuration values, registrations, and tests.
|
|
38
|
-
- List imports, references, callers, callees, implementations, and other direct syntactic relationships.
|
|
39
|
-
- Retrieve exact signatures or declaration bodies requested by parent.
|
|
40
|
-
- Confirm whether an exact source pattern exists within a stated scope.
|
|
41
|
-
- Report ambiguity or missing evidence without resolving it through inference.
|
|
42
|
-
|
|
43
|
-
## Evidence ladder
|
|
44
|
-
|
|
45
|
-
Use cheapest source that proves each returned fact. Skip steps when task supplies exact path or declaration. Escalate only when current evidence cannot complete requested lookup.
|
|
46
|
-
|
|
47
|
-
1. **Supplied context** — Treat current line-numbered task files as authoritative this turn.
|
|
48
|
-
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.
|
|
49
|
-
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.
|
|
50
|
-
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.
|
|
51
|
-
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.
|
|
52
|
-
|
|
53
|
-
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.
|
|
54
|
-
|
|
55
|
-
## Search discipline
|
|
56
|
-
|
|
57
|
-
- Extract concrete target, lookup type, scope, and requested output shape.
|
|
58
|
-
- Narrow each call around one missing fact. Prefer structural summaries and signatures over full source.
|
|
59
|
-
- Start from supplied paths and names. Search outward only as needed to locate requested evidence.
|
|
60
|
-
- Batch only independent lookups whose results will stay small.
|
|
61
|
-
- Do not fan out across plausible explanations or collect evidence for a theory.
|
|
62
|
-
- Stop when requested evidence has been found or bounded search cannot find it.
|
|
63
|
-
Absolute paths may point to read-only reference repositories outside cwd.
|
|
64
|
-
|
|
65
|
-
## Result shapes
|
|
66
|
-
|
|
67
|
-
Use relevant sections only. Omit empty sections.
|
|
68
|
-
|
|
69
|
-
### Locate
|
|
70
|
-
|
|
71
|
-
`path:start-end` — declaration or match — exact reason it matches
|
|
72
|
-
|
|
73
|
-
### Inventory
|
|
74
|
-
|
|
75
|
-
`path:start-end` — declaration or match — source-defined role
|
|
76
|
-
|
|
77
|
-
State searched scope when completeness matters.
|
|
78
|
-
|
|
79
|
-
### Direct relationships
|
|
80
|
-
|
|
81
|
-
- `Relationship:` caller, callee, import, reference, or implementation
|
|
82
|
-
- `Source:` cited declaration
|
|
83
|
-
- `Target:` cited declaration
|
|
84
|
-
- `Certainty:` exact or ambiguous
|
|
85
|
-
|
|
86
|
-
### Exact pattern check
|
|
87
|
-
|
|
88
|
-
- `Found:` yes or no within searched scope
|
|
89
|
-
- `Scope:` paths or subtree searched
|
|
90
|
-
- `Matches:` exact citations when found
|
|
91
|
-
|
|
92
|
-
### Unresolved
|
|
93
|
-
|
|
94
|
-
- `Missing evidence:` requested lookup that could not be found
|
|
95
|
-
- `Ambiguity:` competing exact matches the tools could not disambiguate
|
|
96
|
-
- `Parent question:` diagnosis, explanation, evaluation, consequence, recommendation, or decision left to parent
|
|
97
|
-
|
|
98
|
-
## Reporting rules
|
|
99
|
-
|
|
100
|
-
- Every returned code fact needs exact path and line range. Include declaration name when one exists.
|
|
101
|
-
- Cite ranges returned by tools. Never estimate line numbers.
|
|
102
|
-
- Quote smallest useful fragment.
|
|
103
|
-
- Describe only what source directly contains or what a structural tool directly reports.
|
|
104
|
-
- No preamble, search log, repository summary, causal explanation, conclusions, or next-step advice.
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: web-research
|
|
3
|
-
description: Perform multi-step web and code research with source-backed synthesis
|
|
4
|
-
tools:
|
|
5
|
-
- websearch
|
|
6
|
-
- codesearch
|
|
7
|
-
- webfetch
|
|
8
|
-
names:
|
|
9
|
-
- Spider
|
|
10
|
-
- Linkhound
|
|
11
|
-
- Crawler
|
|
12
|
-
- Netscout
|
|
13
|
-
- Wayfinder
|
|
14
|
-
model: openai-codex/gpt-5.6-luna
|
|
15
|
-
thinking: xhigh
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
Stay inside delegated task. Answer exactly what was asked. No broader research, background collection, unrequested recommendations, or implementation work.
|
|
19
|
-
|
|
20
|
-
Delegating prompt is output contract. Requested shape wins. Otherwise use the smallest matching shape below.
|
|
21
|
-
|
|
22
|
-
## Effort and depth
|
|
23
|
-
|
|
24
|
-
Use the least research and fewest tokens needed for a reliable answer. Match depth to the question, not the agent's available tools.
|
|
25
|
-
|
|
26
|
-
- For a simple lookup, verify the value and return it with a direct source URL in one line.
|
|
27
|
-
- For a focused question, give the direct answer and only the evidence or qualification needed to support it.
|
|
28
|
-
- For a comparison or recommendation, explain the decision criteria, strongest supported reasons, meaningful tradeoffs, and why plausible alternatives fit worse. Include only factors relevant to the requested use case.
|
|
29
|
-
- For a multi-part or explicitly deep task, synthesize across suitable sources using the relevant structured result shape.
|
|
30
|
-
|
|
31
|
-
Do not turn a lookup into a survey. Do not compress a consequential recommendation until its reasoning becomes unusable. Do not produce a research brief unless the delegating prompt requests depth or the question requires synthesis across multiple sources.
|
|
32
|
-
|
|
33
|
-
## Research discipline
|
|
34
|
-
|
|
35
|
-
1. Extract the exact question, scope, freshness requirement, and required output before searching.
|
|
36
|
-
2. Start with the most specific query that could answer the question. Refine queries from evidence instead of searching the whole topic.
|
|
37
|
-
3. Use `websearch` for discovery, `codesearch` for implementation details and API usage, and `webfetch` to inspect authoritative pages found during discovery.
|
|
38
|
-
4. Every search or fetch must resolve a pending question. Stop when each requested claim has sufficient evidence.
|
|
39
|
-
5. Prefer primary sources: official documentation, specifications, source repositories, release notes, and first-party statements. Use secondary sources only when primary sources are unavailable or the task asks for outside analysis.
|
|
40
|
-
6. Check publication and version context when facts may have changed. Do not combine claims from incompatible versions without saying so.
|
|
41
|
-
7. Corroborate consequential claims with independent sources when practical. A page repeating another source is not independent evidence.
|
|
42
|
-
8. Put unresolved or conflicting facts under `Unknowns`. Do not fill gaps with plausible synthesis.
|
|
43
|
-
|
|
44
|
-
## Result shapes
|
|
45
|
-
|
|
46
|
-
Use only relevant sections. Omit empty sections.
|
|
47
|
-
|
|
48
|
-
### Answer a factual question
|
|
49
|
-
|
|
50
|
-
- `Answer:` direct answer
|
|
51
|
-
- `Evidence:` claim — source URL
|
|
52
|
-
- `Qualification:` limits, version, or date context when needed
|
|
53
|
-
|
|
54
|
-
### Explain a topic
|
|
55
|
-
|
|
56
|
-
- `Summary:` concise explanation
|
|
57
|
-
- `Key facts:` source-backed facts
|
|
58
|
-
- `Implications:` requested consequences only
|
|
59
|
-
- `Unknowns:` unresolved facts
|
|
60
|
-
|
|
61
|
-
### Compare
|
|
62
|
-
|
|
63
|
-
- `Shared:` source-backed similarities
|
|
64
|
-
- `Differences:` differences by requested aspect
|
|
65
|
-
- `Relevant consequence:` requested consequences only
|
|
66
|
-
|
|
67
|
-
### Find an implementation approach
|
|
68
|
-
|
|
69
|
-
- `Recommended approach:` approach supported by current documentation or examples
|
|
70
|
-
- `API or mechanism:` relevant interfaces, behavior, and constraints
|
|
71
|
-
- `Example sources:` direct documentation or source links
|
|
72
|
-
- `Unknowns:` missing version or environment details
|
|
73
|
-
|
|
74
|
-
### Verify a claim
|
|
75
|
-
|
|
76
|
-
- `Verdict:` `yes`, `no`, `partially`, or `unknown`
|
|
77
|
-
- `Evidence:` source-backed facts
|
|
78
|
-
- `Qualification:` only when needed
|
|
79
|
-
|
|
80
|
-
### Survey options
|
|
81
|
-
|
|
82
|
-
`Option` — relevant capability — constraint — source URL
|
|
83
|
-
|
|
84
|
-
State selection criteria. Do not rank options unless the task asks for a recommendation.
|
|
85
|
-
|
|
86
|
-
### Research brief
|
|
87
|
-
|
|
88
|
-
- `Findings:` ordered by relevance
|
|
89
|
-
- `Evidence:` source URLs attached to each material claim
|
|
90
|
-
- `Conflicts:` disagreements between credible sources
|
|
91
|
-
- `Unknowns:` evidence still needed
|
|
92
|
-
|
|
93
|
-
## Reporting rules
|
|
94
|
-
|
|
95
|
-
- Cite every material factual claim with a direct source URL.
|
|
96
|
-
- Link to the page containing the evidence, not a search result page.
|
|
97
|
-
- Separate source claims from inference. Label inference.
|
|
98
|
-
- Quote only the smallest fragment needed to preserve exact wording.
|
|
99
|
-
- Describe source quality or limitations when they affect confidence.
|
|
100
|
-
- Use exact dates and versions when freshness matters.
|
|
101
|
-
- No preamble, search log, generic topic summary, repeated evidence, or unrequested next steps.
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { access, readdir, readFile } from "node:fs/promises";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { basename, dirname, extname, join, parse, resolve } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { getAgentDir, parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
6
|
-
|
|
7
|
-
export interface AgentDefinition {
|
|
8
|
-
name: string;
|
|
9
|
-
description: string;
|
|
10
|
-
tools: string[];
|
|
11
|
-
names: string[];
|
|
12
|
-
model?: string;
|
|
13
|
-
thinking?: ThinkingLevel;
|
|
14
|
-
prompt: string;
|
|
15
|
-
path: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
19
|
-
|
|
20
|
-
export interface AgentDiagnostic {
|
|
21
|
-
path: string;
|
|
22
|
-
name: string;
|
|
23
|
-
reason: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface AgentDiscovery {
|
|
27
|
-
agents: Map<string, AgentDefinition>;
|
|
28
|
-
invalid: Map<string, AgentDiagnostic[]>;
|
|
29
|
-
diagnostics: AgentDiagnostic[];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const BUILTIN_AGENTS_DIR = join(dirname(fileURLToPath(import.meta.url)), "agents");
|
|
33
|
-
|
|
34
|
-
async function directoryExists(path: string): Promise<boolean> {
|
|
35
|
-
try {
|
|
36
|
-
await access(path);
|
|
37
|
-
return true;
|
|
38
|
-
} catch {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function findProjectAgentsDir(cwd: string): Promise<string | undefined> {
|
|
44
|
-
const home = resolve(homedir());
|
|
45
|
-
let current = resolve(cwd);
|
|
46
|
-
while (current !== home) {
|
|
47
|
-
const candidate = join(current, ".pi", "tau", "agents");
|
|
48
|
-
if (await directoryExists(candidate)) return candidate;
|
|
49
|
-
const parent = dirname(current);
|
|
50
|
-
if (parent === current) break;
|
|
51
|
-
current = parent;
|
|
52
|
-
}
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const ALLOWED_FRONTMATTER_FIELDS = new Set(["name", "description", "tools", "names", "model", "thinking"]);
|
|
57
|
-
const THINKING_LEVELS: ThinkingLevel[] = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
58
|
-
|
|
59
|
-
function validateStringList(raw: unknown, field: string, reasons: string[]): string[] | undefined {
|
|
60
|
-
if (!Array.isArray(raw) || raw.length === 0) {
|
|
61
|
-
reasons.push(`${field} must be a non-empty array`);
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
64
|
-
const values = raw
|
|
65
|
-
.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
|
|
66
|
-
.map((item) => item.trim());
|
|
67
|
-
if (values.length !== raw.length) reasons.push(`${field} must contain non-empty strings`);
|
|
68
|
-
if (new Set(values).size !== values.length) reasons.push(`${field} must be unique`);
|
|
69
|
-
return values;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function requireNonEmptyString(raw: unknown, field: string, reasons: string[]): void {
|
|
73
|
-
if (typeof raw !== "string" || !raw.trim()) reasons.push(`${field} must be a non-empty string`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function validateModelField(rawModel: unknown, reasons: string[]): void {
|
|
77
|
-
if (rawModel === undefined) return;
|
|
78
|
-
if (typeof rawModel !== "string" || !/^[^/\s]+\/[^/\s]+$/.test(rawModel.trim()))
|
|
79
|
-
reasons.push("model must be a provider/model string");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function validateThinkingField(rawThinking: unknown, reasons: string[]): void {
|
|
83
|
-
if (rawThinking === undefined) return;
|
|
84
|
-
if (!THINKING_LEVELS.includes(rawThinking as ThinkingLevel))
|
|
85
|
-
reasons.push(`thinking must be one of ${THINKING_LEVELS.join(", ")}`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function collectDefinitionReasons(
|
|
89
|
-
parsed: ReturnType<typeof parseFrontmatter>,
|
|
90
|
-
fallbackName: string,
|
|
91
|
-
): {
|
|
92
|
-
reasons: string[];
|
|
93
|
-
name: string;
|
|
94
|
-
tools: string[] | undefined;
|
|
95
|
-
names: string[] | undefined;
|
|
96
|
-
rawDescription: unknown;
|
|
97
|
-
rawModel: unknown;
|
|
98
|
-
rawThinking: unknown;
|
|
99
|
-
} {
|
|
100
|
-
const rawName = parsed.frontmatter.name;
|
|
101
|
-
const name = typeof rawName === "string" && rawName.trim() ? rawName.trim() : fallbackName;
|
|
102
|
-
const reasons: string[] = [];
|
|
103
|
-
for (const field of Object.keys(parsed.frontmatter)) {
|
|
104
|
-
if (!ALLOWED_FRONTMATTER_FIELDS.has(field)) reasons.push(`unsupported field "${field}"`);
|
|
105
|
-
}
|
|
106
|
-
requireNonEmptyString(rawName, "name", reasons);
|
|
107
|
-
const rawDescription = parsed.frontmatter.description;
|
|
108
|
-
requireNonEmptyString(rawDescription, "description", reasons);
|
|
109
|
-
const tools = validateStringList(parsed.frontmatter.tools, "tools", reasons);
|
|
110
|
-
if (tools?.includes("subagent")) reasons.push("tool subagent is forbidden");
|
|
111
|
-
const rawNames = parsed.frontmatter.names;
|
|
112
|
-
const names = rawNames === undefined ? undefined : validateStringList(rawNames, "names", reasons);
|
|
113
|
-
if (!parsed.body.trim()) reasons.push("prompt body must be non-empty");
|
|
114
|
-
const rawModel = parsed.frontmatter.model;
|
|
115
|
-
validateModelField(rawModel, reasons);
|
|
116
|
-
const rawThinking = parsed.frontmatter.thinking;
|
|
117
|
-
validateThinkingField(rawThinking, reasons);
|
|
118
|
-
return { reasons, name, tools, names, rawDescription, rawModel, rawThinking };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function parseDefinition(
|
|
122
|
-
path: string,
|
|
123
|
-
content: string,
|
|
124
|
-
): { definition?: AgentDefinition; diagnostic?: AgentDiagnostic } {
|
|
125
|
-
const fallbackName = basename(path, extname(path));
|
|
126
|
-
try {
|
|
127
|
-
const parsed = parseFrontmatter(content);
|
|
128
|
-
const { reasons, name, tools, names, rawDescription, rawModel, rawThinking } = collectDefinitionReasons(
|
|
129
|
-
parsed,
|
|
130
|
-
fallbackName,
|
|
131
|
-
);
|
|
132
|
-
if (reasons.length > 0) return { diagnostic: { path, name, reason: reasons.join("; ") } };
|
|
133
|
-
return {
|
|
134
|
-
definition: {
|
|
135
|
-
name,
|
|
136
|
-
description: (rawDescription as string).trim(),
|
|
137
|
-
tools: tools ?? [],
|
|
138
|
-
names: names ?? [name],
|
|
139
|
-
model: typeof rawModel === "string" ? rawModel.trim() : undefined,
|
|
140
|
-
thinking: rawThinking as ThinkingLevel | undefined,
|
|
141
|
-
prompt: parsed.body.trim(),
|
|
142
|
-
path,
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
} catch (error) {
|
|
146
|
-
return {
|
|
147
|
-
diagnostic: {
|
|
148
|
-
path,
|
|
149
|
-
name: fallbackName,
|
|
150
|
-
reason: error instanceof Error ? error.message : "invalid frontmatter",
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function finalizeScopeGroup(
|
|
157
|
-
name: string,
|
|
158
|
-
values: Array<AgentDefinition | AgentDiagnostic>,
|
|
159
|
-
): AgentDefinition | AgentDiagnostic[] {
|
|
160
|
-
if (values.length === 1 && "prompt" in values[0]) return values[0];
|
|
161
|
-
const diagnostics = values.map((value) =>
|
|
162
|
-
"reason" in value ? value : { path: value.path, name, reason: `duplicate name "${name}" in this scope` },
|
|
163
|
-
);
|
|
164
|
-
if (values.length > 1) {
|
|
165
|
-
for (const value of values) if ("reason" in value) value.reason += `; duplicate name "${name}" in this scope`;
|
|
166
|
-
}
|
|
167
|
-
return diagnostics;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async function readAgentDirectoryEntries(
|
|
171
|
-
directory: string,
|
|
172
|
-
required: boolean,
|
|
173
|
-
): Promise<
|
|
174
|
-
| { kind: "entries"; entries: Array<{ name: string }> }
|
|
175
|
-
| { kind: "empty" }
|
|
176
|
-
| { kind: "error"; scope: Map<string, AgentDefinition | AgentDiagnostic[]> }
|
|
177
|
-
> {
|
|
178
|
-
try {
|
|
179
|
-
const entries = (await readdir(directory, { withFileTypes: true }))
|
|
180
|
-
.filter((entry) => entry.isFile() && extname(entry.name) === ".md")
|
|
181
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
182
|
-
return { kind: "entries", entries };
|
|
183
|
-
} catch (error) {
|
|
184
|
-
if (!required) return { kind: "empty" };
|
|
185
|
-
const reason = error instanceof Error ? error.message : "directory unavailable";
|
|
186
|
-
return {
|
|
187
|
-
kind: "error",
|
|
188
|
-
scope: new Map([
|
|
189
|
-
[
|
|
190
|
-
"web-research",
|
|
191
|
-
[{ path: directory, name: "web-research", reason: `packaged agents unavailable: ${reason}` }],
|
|
192
|
-
],
|
|
193
|
-
]),
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async function parseScopeFile(directory: string, entryName: string): Promise<AgentDefinition | AgentDiagnostic> {
|
|
199
|
-
const path = join(directory, entryName);
|
|
200
|
-
try {
|
|
201
|
-
const parsed = parseDefinition(path, await readFile(path, "utf8"));
|
|
202
|
-
return (
|
|
203
|
-
parsed.definition ??
|
|
204
|
-
parsed.diagnostic ?? {
|
|
205
|
-
path,
|
|
206
|
-
name: parse(entryName).name,
|
|
207
|
-
reason: "empty definition",
|
|
208
|
-
}
|
|
209
|
-
);
|
|
210
|
-
} catch (error) {
|
|
211
|
-
return {
|
|
212
|
-
path,
|
|
213
|
-
name: parse(entryName).name,
|
|
214
|
-
reason: error instanceof Error ? error.message : "file unreadable",
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
async function loadScope(
|
|
220
|
-
directory: string,
|
|
221
|
-
required: boolean,
|
|
222
|
-
): Promise<Map<string, AgentDefinition | AgentDiagnostic[]>> {
|
|
223
|
-
const listed = await readAgentDirectoryEntries(directory, required);
|
|
224
|
-
if (listed.kind === "empty") return new Map();
|
|
225
|
-
if (listed.kind === "error") return listed.scope;
|
|
226
|
-
const grouped = new Map<string, Array<AgentDefinition | AgentDiagnostic>>();
|
|
227
|
-
for (const entry of listed.entries) {
|
|
228
|
-
const value = await parseScopeFile(directory, entry.name);
|
|
229
|
-
const values = grouped.get(value.name) ?? [];
|
|
230
|
-
values.push(value);
|
|
231
|
-
grouped.set(value.name, values);
|
|
232
|
-
}
|
|
233
|
-
const scope = new Map<string, AgentDefinition | AgentDiagnostic[]>();
|
|
234
|
-
for (const [name, values] of grouped) scope.set(name, finalizeScopeGroup(name, values));
|
|
235
|
-
return scope;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export async function discoverAgents(cwd: string, trusted: boolean): Promise<AgentDiscovery> {
|
|
239
|
-
const scopes = [
|
|
240
|
-
await loadScope(BUILTIN_AGENTS_DIR, true),
|
|
241
|
-
await loadScope(join(getAgentDir(), "tau", "agents"), false),
|
|
242
|
-
];
|
|
243
|
-
if (trusted) {
|
|
244
|
-
const project = await findProjectAgentsDir(cwd);
|
|
245
|
-
if (project) scopes.push(await loadScope(project, false));
|
|
246
|
-
}
|
|
247
|
-
const agents = new Map<string, AgentDefinition>();
|
|
248
|
-
const invalid = new Map<string, AgentDiagnostic[]>();
|
|
249
|
-
const diagnostics = scopes.flatMap((scope) =>
|
|
250
|
-
[...scope.values()].flatMap((value) => (Array.isArray(value) ? value : [])),
|
|
251
|
-
);
|
|
252
|
-
for (const scope of scopes) {
|
|
253
|
-
for (const [name, value] of scope) {
|
|
254
|
-
agents.delete(name);
|
|
255
|
-
invalid.delete(name);
|
|
256
|
-
if (Array.isArray(value)) invalid.set(name, value);
|
|
257
|
-
else agents.set(name, value);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return { agents, invalid, diagnostics };
|
|
261
|
-
}
|