vaan-ai 0.1.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/LICENSE +216 -0
- package/README.md +390 -0
- package/dist/src/agent.js +151 -0
- package/dist/src/agent.js.map +1 -0
- package/dist/src/cli/args.js +38 -0
- package/dist/src/cli/args.js.map +1 -0
- package/dist/src/cli/doctor.js +98 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/dotenv.js +58 -0
- package/dist/src/cli/dotenv.js.map +1 -0
- package/dist/src/cli/main.js +138 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/memory-cmd.js +31 -0
- package/dist/src/cli/memory-cmd.js.map +1 -0
- package/dist/src/cli/repl.js +275 -0
- package/dist/src/cli/repl.js.map +1 -0
- package/dist/src/cli/schedule.js +184 -0
- package/dist/src/cli/schedule.js.map +1 -0
- package/dist/src/cli/suggested.js +26 -0
- package/dist/src/cli/suggested.js.map +1 -0
- package/dist/src/cli/trace-cmd.js +69 -0
- package/dist/src/cli/trace-cmd.js.map +1 -0
- package/dist/src/cli/wizard.js +346 -0
- package/dist/src/cli/wizard.js.map +1 -0
- package/dist/src/config.js +130 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/eval/graders.js +145 -0
- package/dist/src/eval/graders.js.map +1 -0
- package/dist/src/eval/report.js +20 -0
- package/dist/src/eval/report.js.map +1 -0
- package/dist/src/eval/runner.js +67 -0
- package/dist/src/eval/runner.js.map +1 -0
- package/dist/src/eval/suites.js +164 -0
- package/dist/src/eval/suites.js.map +1 -0
- package/dist/src/http.js +134 -0
- package/dist/src/http.js.map +1 -0
- package/dist/src/inbox.js +51 -0
- package/dist/src/inbox.js.map +1 -0
- package/dist/src/index.js +180 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/memory/context.js +63 -0
- package/dist/src/memory/context.js.map +1 -0
- package/dist/src/memory/index.js +28 -0
- package/dist/src/memory/index.js.map +1 -0
- package/dist/src/memory/search.js +32 -0
- package/dist/src/memory/search.js.map +1 -0
- package/dist/src/memory/store.js +171 -0
- package/dist/src/memory/store.js.map +1 -0
- package/dist/src/observability/events.js +109 -0
- package/dist/src/observability/events.js.map +1 -0
- package/dist/src/observability/request.js +20 -0
- package/dist/src/observability/request.js.map +1 -0
- package/dist/src/observability/trace.js +149 -0
- package/dist/src/observability/trace.js.map +1 -0
- package/dist/src/paths.js +24 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/permissions/approval.js +80 -0
- package/dist/src/permissions/approval.js.map +1 -0
- package/dist/src/permissions/policy.js +75 -0
- package/dist/src/permissions/policy.js.map +1 -0
- package/dist/src/permissions/rules.js +200 -0
- package/dist/src/permissions/rules.js.map +1 -0
- package/dist/src/prompt.js +114 -0
- package/dist/src/prompt.js.map +1 -0
- package/dist/src/providers/anthropic.js +233 -0
- package/dist/src/providers/anthropic.js.map +1 -0
- package/dist/src/providers/custom.js +46 -0
- package/dist/src/providers/custom.js.map +1 -0
- package/dist/src/providers/google.js +197 -0
- package/dist/src/providers/google.js.map +1 -0
- package/dist/src/providers/index.js +122 -0
- package/dist/src/providers/index.js.map +1 -0
- package/dist/src/providers/ollama.js +44 -0
- package/dist/src/providers/ollama.js.map +1 -0
- package/dist/src/providers/openai.js +193 -0
- package/dist/src/providers/openai.js.map +1 -0
- package/dist/src/providers/shared.js +32 -0
- package/dist/src/providers/shared.js.map +1 -0
- package/dist/src/sandbox/filesystem.js +193 -0
- package/dist/src/sandbox/filesystem.js.map +1 -0
- package/dist/src/sandbox/network.js +119 -0
- package/dist/src/sandbox/network.js.map +1 -0
- package/dist/src/sandbox/process.js +198 -0
- package/dist/src/sandbox/process.js.map +1 -0
- package/dist/src/skills.js +80 -0
- package/dist/src/skills.js.map +1 -0
- package/dist/src/tools/basics.js +41 -0
- package/dist/src/tools/basics.js.map +1 -0
- package/dist/src/tools/code.js +114 -0
- package/dist/src/tools/code.js.map +1 -0
- package/dist/src/tools/files.js +162 -0
- package/dist/src/tools/files.js.map +1 -0
- package/dist/src/tools/git.js +91 -0
- package/dist/src/tools/git.js.map +1 -0
- package/dist/src/tools/grep.js +92 -0
- package/dist/src/tools/grep.js.map +1 -0
- package/dist/src/tools/index.js +66 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/shared.js +11 -0
- package/dist/src/tools/shared.js.map +1 -0
- package/dist/src/tools/web.js +217 -0
- package/dist/src/tools/web.js.map +1 -0
- package/dist/src/types.js +14 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +59 -0
- package/scripts/postinstall.js +47 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// read_file, list_dir, write_file, edit_file.
|
|
2
|
+
//
|
|
3
|
+
// Every one of them goes through two gates, and they answer different
|
|
4
|
+
// questions. `jail` answers *where*: the path is resolved against the workspace
|
|
5
|
+
// and rejected if it lands outside, symlinks included. The permission gate
|
|
6
|
+
// answers *whether*: reading inside the workspace is free, changing anything
|
|
7
|
+
// asks. Only after both does the user see the diff and decide.
|
|
8
|
+
import { mkdirSync } from "node:fs";
|
|
9
|
+
import { dirname, relative } from "node:path";
|
|
10
|
+
import { jail, listEntries, readText, writeText } from "../sandbox/filesystem.js";
|
|
11
|
+
import { readIfExists } from "./shared.js";
|
|
12
|
+
const MAX_DIFF_LINES = 40;
|
|
13
|
+
const show = (workspace, path) => relative(workspace, path) || ".";
|
|
14
|
+
export const readFile = {
|
|
15
|
+
name: "read_file",
|
|
16
|
+
description: "Read a UTF-8 text file inside the workspace. Paths are relative to it. " +
|
|
17
|
+
"Large files are truncated.",
|
|
18
|
+
group: "files",
|
|
19
|
+
parameters: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: { path: { type: "string", description: "Path relative to the workspace." } },
|
|
22
|
+
required: ["path"],
|
|
23
|
+
},
|
|
24
|
+
async run(input, ctx) {
|
|
25
|
+
const path = String(input.path ?? "");
|
|
26
|
+
await ctx.gate.require(ctx.policy.forPath("read_file", path, "read"));
|
|
27
|
+
const result = readText(ctx.workspace, path);
|
|
28
|
+
ctx.trace.record({ kind: "sandbox", op: "read", target: path, ok: true });
|
|
29
|
+
return result.truncated
|
|
30
|
+
? `${result.text}\n\n[truncated — ${result.bytes} bytes total]`
|
|
31
|
+
: result.text;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export const listDir = {
|
|
35
|
+
name: "list_dir",
|
|
36
|
+
description: "List the entries of a directory inside the workspace. " +
|
|
37
|
+
"Directories are shown with a trailing slash.",
|
|
38
|
+
group: "files",
|
|
39
|
+
parameters: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
path: { type: "string", description: "Directory path. Defaults to the workspace root." },
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
async run(input, ctx) {
|
|
46
|
+
const path = String(input.path ?? ".");
|
|
47
|
+
await ctx.gate.require(ctx.policy.forPath("list_dir", path, "read"));
|
|
48
|
+
const target = jail(ctx.workspace, path);
|
|
49
|
+
const { entries, more } = listEntries(ctx.workspace, path);
|
|
50
|
+
ctx.trace.record({ kind: "sandbox", op: "list", target: path, ok: true });
|
|
51
|
+
if (entries.length === 0)
|
|
52
|
+
return `${show(ctx.workspace, target)} is empty.`;
|
|
53
|
+
return entries.join("\n") + (more > 0 ? `\n[${more} more entries]` : "");
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
export const writeFile = {
|
|
57
|
+
name: "write_file",
|
|
58
|
+
description: "Write a UTF-8 text file inside the workspace, replacing it if it exists. " +
|
|
59
|
+
"The user is shown a diff and asked to approve before anything is written. " +
|
|
60
|
+
"Prefer edit_file when you are changing part of an existing file.",
|
|
61
|
+
group: "files",
|
|
62
|
+
parameters: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
path: { type: "string", description: "Path relative to the workspace." },
|
|
66
|
+
content: { type: "string", description: "The complete new contents of the file." },
|
|
67
|
+
},
|
|
68
|
+
required: ["path", "content"],
|
|
69
|
+
},
|
|
70
|
+
async run(input, ctx) {
|
|
71
|
+
const path = String(input.path ?? "");
|
|
72
|
+
const content = String(input.content ?? "");
|
|
73
|
+
return commit(ctx, path, content, "write_file");
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
export const editFile = {
|
|
77
|
+
name: "edit_file",
|
|
78
|
+
description: "Replace an exact string in a file inside the workspace. Use this rather than write_file " +
|
|
79
|
+
"for changes to an existing file: it doesn't require restating the parts you aren't " +
|
|
80
|
+
"changing, so the diff shows only what moved. The old text must appear exactly once " +
|
|
81
|
+
"unless replace_all is true.",
|
|
82
|
+
group: "files",
|
|
83
|
+
parameters: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
path: { type: "string", description: "Path relative to the workspace." },
|
|
87
|
+
old_text: { type: "string", description: "The exact text to replace, including indentation." },
|
|
88
|
+
new_text: { type: "string", description: "What to put in its place." },
|
|
89
|
+
replace_all: { type: "boolean", description: "Replace every occurrence. Default false." },
|
|
90
|
+
},
|
|
91
|
+
required: ["path", "old_text", "new_text"],
|
|
92
|
+
},
|
|
93
|
+
async run(input, ctx) {
|
|
94
|
+
const path = String(input.path ?? "");
|
|
95
|
+
const oldText = String(input.old_text ?? "");
|
|
96
|
+
const newText = String(input.new_text ?? "");
|
|
97
|
+
const all = input.replace_all === true;
|
|
98
|
+
if (!oldText)
|
|
99
|
+
return "old_text was empty. Use write_file to create a file.";
|
|
100
|
+
// Read through the jail so a path outside the workspace fails here rather
|
|
101
|
+
// than after the user has been asked to approve something.
|
|
102
|
+
await ctx.gate.require(ctx.policy.forPath("edit_file", path, "read"));
|
|
103
|
+
const before = readText(ctx.workspace, path).text;
|
|
104
|
+
const occurrences = before.split(oldText).length - 1;
|
|
105
|
+
if (occurrences === 0) {
|
|
106
|
+
return `That exact text isn't in ${path}. Read the file again — whitespace and indentation have to match.`;
|
|
107
|
+
}
|
|
108
|
+
if (occurrences > 1 && !all) {
|
|
109
|
+
return (`That text appears ${occurrences} times in ${path}. Include enough surrounding lines to ` +
|
|
110
|
+
`make it unique, or pass replace_all.`);
|
|
111
|
+
}
|
|
112
|
+
const after = all ? before.split(oldText).join(newText) : before.replace(oldText, newText);
|
|
113
|
+
return commit(ctx, path, after, "edit_file");
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
/** The shared tail of every write: permission, then a diff, then the bytes. */
|
|
117
|
+
async function commit(ctx, path, content, tool) {
|
|
118
|
+
await ctx.gate.require(ctx.policy.forPath(tool, path, "write"));
|
|
119
|
+
const target = jail(ctx.workspace, path);
|
|
120
|
+
const label = show(ctx.workspace, target);
|
|
121
|
+
const before = readIfExists(target);
|
|
122
|
+
if (before === content)
|
|
123
|
+
return `${label} already has exactly that content. Nothing written.`;
|
|
124
|
+
const approved = await ctx.confirm(`${before === undefined ? "Create" : "Modify"} ${label}\n\n${diff(before ?? "", content)}`);
|
|
125
|
+
if (!approved) {
|
|
126
|
+
ctx.trace.record({ kind: "sandbox", op: "write", target: label, ok: false, detail: "declined" });
|
|
127
|
+
return `The user declined the write to ${label}. The file is unchanged.`;
|
|
128
|
+
}
|
|
129
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
130
|
+
writeText(ctx.workspace, path, content);
|
|
131
|
+
const lines = content === "" ? 0 : content.split("\n").length;
|
|
132
|
+
ctx.trace.record({ kind: "sandbox", op: "write", target: label, ok: true, detail: `${lines} lines` });
|
|
133
|
+
return `Wrote ${label} (${lines} lines).`;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* A diff good enough to decide by. Trims the common head and tail and shows
|
|
137
|
+
* what's left. That covers the shape of a normal edit without dragging in a
|
|
138
|
+
* real LCS implementation for a confirmation prompt.
|
|
139
|
+
*/
|
|
140
|
+
export function diff(before, after) {
|
|
141
|
+
const a = before === "" ? [] : before.split("\n");
|
|
142
|
+
const b = after === "" ? [] : after.split("\n");
|
|
143
|
+
let head = 0;
|
|
144
|
+
while (head < a.length && head < b.length && a[head] === b[head])
|
|
145
|
+
head++;
|
|
146
|
+
let endA = a.length;
|
|
147
|
+
let endB = b.length;
|
|
148
|
+
while (endA > head && endB > head && a[endA - 1] === b[endB - 1]) {
|
|
149
|
+
endA--;
|
|
150
|
+
endB--;
|
|
151
|
+
}
|
|
152
|
+
const removed = a.slice(head, endA).map((line) => `- ${line}`);
|
|
153
|
+
const added = b.slice(head, endB).map((line) => `+ ${line}`);
|
|
154
|
+
const body = [...removed, ...added];
|
|
155
|
+
if (body.length === 0)
|
|
156
|
+
return "(no textual change)";
|
|
157
|
+
const shown = body.slice(0, MAX_DIFF_LINES);
|
|
158
|
+
const hidden = body.length - shown.length;
|
|
159
|
+
const context = head > 0 ? [` … ${head} unchanged line${head === 1 ? "" : "s"} above`] : [];
|
|
160
|
+
return [...context, ...shown, ...(hidden > 0 ? [` … ${hidden} more changed lines`] : [])].join("\n");
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/tools/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// git_status, git_diff, git_log — read-only, and that is the whole design.
|
|
2
|
+
//
|
|
3
|
+
// These three answer "what has changed and why", which is what an agent needs
|
|
4
|
+
// before touching a repository. Committing, pushing and branching are not here:
|
|
5
|
+
// they go through run_command, where the exact command is shown and approved.
|
|
6
|
+
// A tool called `git_commit` would be a second, quieter path to the same effect
|
|
7
|
+
// with a friendlier name, and the friendlier name is exactly the problem.
|
|
8
|
+
import { runCommand, summarise } from "../sandbox/process.js";
|
|
9
|
+
const MAX_LINES = 400;
|
|
10
|
+
async function git(ctx, args, label) {
|
|
11
|
+
// Reading a repository is reading the workspace, so it asks for `read` rather
|
|
12
|
+
// than `execute`: no side effects, nothing to approve.
|
|
13
|
+
await ctx.gate.require(ctx.policy.forPath(label, ".", "read"));
|
|
14
|
+
const result = await runCommand({
|
|
15
|
+
command: `git ${args}`,
|
|
16
|
+
workspace: ctx.workspace,
|
|
17
|
+
env: ctx.env,
|
|
18
|
+
timeoutMs: 30_000,
|
|
19
|
+
...(ctx.signal ? { signal: ctx.signal } : {}),
|
|
20
|
+
});
|
|
21
|
+
ctx.trace.record({
|
|
22
|
+
kind: "sandbox",
|
|
23
|
+
op: "git",
|
|
24
|
+
target: args,
|
|
25
|
+
ok: result.code === 0,
|
|
26
|
+
detail: summarise(result),
|
|
27
|
+
});
|
|
28
|
+
if (result.code !== 0) {
|
|
29
|
+
const detail = (result.stderr || result.stdout).trim();
|
|
30
|
+
if (/not a git repository/i.test(detail))
|
|
31
|
+
return "This workspace isn't a git repository.";
|
|
32
|
+
if (/command not found|ENOENT/i.test(detail))
|
|
33
|
+
return "git isn't installed on this machine.";
|
|
34
|
+
return `git ${args} failed: ${detail || `exit ${result.code}`}`;
|
|
35
|
+
}
|
|
36
|
+
const output = result.stdout.trim();
|
|
37
|
+
if (!output)
|
|
38
|
+
return "(nothing to report)";
|
|
39
|
+
const lines = output.split("\n");
|
|
40
|
+
return lines.length <= MAX_LINES
|
|
41
|
+
? output
|
|
42
|
+
: `${lines.slice(0, MAX_LINES).join("\n")}\n[${lines.length - MAX_LINES} more lines]`;
|
|
43
|
+
}
|
|
44
|
+
export const gitStatus = {
|
|
45
|
+
name: "git_status",
|
|
46
|
+
description: "Show which files in the workspace have been modified, staged or left untracked. " +
|
|
47
|
+
"Read-only. Use it before changing anything, to see what was already in flight.",
|
|
48
|
+
group: "git",
|
|
49
|
+
parameters: { type: "object", properties: {} },
|
|
50
|
+
run: (_input, ctx) => git(ctx, "status --short --branch", "git_status"),
|
|
51
|
+
};
|
|
52
|
+
export const gitDiff = {
|
|
53
|
+
name: "git_diff",
|
|
54
|
+
description: "Show the diff of uncommitted changes in the workspace. Read-only. " +
|
|
55
|
+
"Pass staged to see what is already staged instead.",
|
|
56
|
+
group: "git",
|
|
57
|
+
parameters: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
staged: { type: "boolean", description: "Show staged changes instead of unstaged ones." },
|
|
61
|
+
path: { type: "string", description: "Limit the diff to one path." },
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
run(input, ctx) {
|
|
65
|
+
const staged = input.staged === true ? " --staged" : "";
|
|
66
|
+
// Quoted so a path with a space stays one argument; there is no shell to
|
|
67
|
+
// re-split it, so this is the only escaping that has to happen.
|
|
68
|
+
const path = input.path === undefined ? "" : ` -- "${String(input.path).replace(/"/g, "")}"`;
|
|
69
|
+
return git(ctx, `diff${staged}${path}`, "git_diff");
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export const gitLog = {
|
|
73
|
+
name: "git_log",
|
|
74
|
+
description: "Show recent commits in the workspace, newest first. Read-only. " +
|
|
75
|
+
"Use it to find out why something is the way it is.",
|
|
76
|
+
group: "git",
|
|
77
|
+
parameters: {
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
count: { type: "number", description: "How many commits. Default 15, maximum 100." },
|
|
81
|
+
path: { type: "string", description: "Only commits touching this path." },
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
run(input, ctx) {
|
|
85
|
+
const asked = Number(input.count);
|
|
86
|
+
const count = Number.isFinite(asked) ? Math.min(Math.max(Math.trunc(asked), 1), 100) : 15;
|
|
87
|
+
const path = input.path === undefined ? "" : ` -- "${String(input.path).replace(/"/g, "")}"`;
|
|
88
|
+
return git(ctx, `log --oneline --no-decorate -n ${count}${path}`, "git_log");
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/tools/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// search. The tool the trace in the README shows first, because it is what an
|
|
2
|
+
// agent reaches for before it knows which files matter.
|
|
3
|
+
//
|
|
4
|
+
// It walks the workspace rather than shelling out to grep or ripgrep: those
|
|
5
|
+
// aren't installed everywhere, their flags differ between platforms, and
|
|
6
|
+
// spawning one would put an ordinary lookup behind the execute permission for
|
|
7
|
+
// no gain. Reading files inside the workspace is already allowed.
|
|
8
|
+
import { search, walk } from "../sandbox/filesystem.js";
|
|
9
|
+
const MAX_MATCHES = 60;
|
|
10
|
+
const MAX_FILES_LISTED = 100;
|
|
11
|
+
export const searchWorkspace = {
|
|
12
|
+
name: "search",
|
|
13
|
+
description: "Search the workspace for text and get back matching file paths with line numbers. " +
|
|
14
|
+
"Use this to find where something lives before reading files. Skips node_modules, " +
|
|
15
|
+
".git, build output and other generated directories.",
|
|
16
|
+
group: "search",
|
|
17
|
+
parameters: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
query: { type: "string", description: "Text to look for." },
|
|
21
|
+
regex: {
|
|
22
|
+
type: "boolean",
|
|
23
|
+
description: "Treat the query as a regular expression. Default false.",
|
|
24
|
+
},
|
|
25
|
+
path_contains: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Only search files whose path contains this, e.g. \"src/\" or \".ts\".",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ["query"],
|
|
31
|
+
},
|
|
32
|
+
async run(input, ctx) {
|
|
33
|
+
const query = String(input.query ?? "").trim();
|
|
34
|
+
if (!query)
|
|
35
|
+
return "No query given.";
|
|
36
|
+
await ctx.gate.require(ctx.policy.forPath("search", ".", "read"));
|
|
37
|
+
const glob = input.path_contains === undefined ? undefined : String(input.path_contains);
|
|
38
|
+
const matches = search(ctx.workspace, query, {
|
|
39
|
+
regex: input.regex === true,
|
|
40
|
+
limit: MAX_MATCHES,
|
|
41
|
+
...(glob ? { glob } : {}),
|
|
42
|
+
});
|
|
43
|
+
ctx.trace.record({
|
|
44
|
+
kind: "sandbox",
|
|
45
|
+
op: "search",
|
|
46
|
+
target: query,
|
|
47
|
+
ok: true,
|
|
48
|
+
detail: `${matches.length} matches`,
|
|
49
|
+
});
|
|
50
|
+
if (matches.length === 0) {
|
|
51
|
+
return `No matches for "${query}". Generated directories are skipped, so try list_files if you expected one there.`;
|
|
52
|
+
}
|
|
53
|
+
const body = matches.map((match) => `${match.path}:${match.line} ${match.text}`).join("\n");
|
|
54
|
+
return matches.length >= MAX_MATCHES ? `${body}\n[stopped at ${MAX_MATCHES} matches]` : body;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
export const listFiles = {
|
|
58
|
+
name: "list_files",
|
|
59
|
+
description: "List every file in the workspace, skipping generated directories. Use it to get the " +
|
|
60
|
+
"shape of a project in one call rather than walking it with list_dir.",
|
|
61
|
+
group: "search",
|
|
62
|
+
parameters: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
path_contains: { type: "string", description: "Only list paths containing this." },
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
async run(input, ctx) {
|
|
69
|
+
await ctx.gate.require(ctx.policy.forPath("list_files", ".", "read"));
|
|
70
|
+
const filter = input.path_contains === undefined ? "" : String(input.path_contains);
|
|
71
|
+
const all = [];
|
|
72
|
+
for (const path of walk(ctx.workspace)) {
|
|
73
|
+
if (!filter || path.includes(filter))
|
|
74
|
+
all.push(path);
|
|
75
|
+
if (all.length > MAX_FILES_LISTED)
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
ctx.trace.record({
|
|
79
|
+
kind: "sandbox",
|
|
80
|
+
op: "walk",
|
|
81
|
+
target: filter || ".",
|
|
82
|
+
ok: true,
|
|
83
|
+
detail: `${all.length} files`,
|
|
84
|
+
});
|
|
85
|
+
if (all.length === 0)
|
|
86
|
+
return filter ? `No files match "${filter}".` : "The workspace is empty.";
|
|
87
|
+
const shown = all.slice(0, MAX_FILES_LISTED);
|
|
88
|
+
return (shown.sort().join("\n") +
|
|
89
|
+
(all.length > MAX_FILES_LISTED ? `\n[stopped at ${MAX_FILES_LISTED} — narrow with path_contains]` : ""));
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=grep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.js","sourceRoot":"","sources":["../../../src/tools/grep.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// The tool registry, grouped the way the onboarding checkboxes group them.
|
|
2
|
+
//
|
|
3
|
+
// Groups are the unit the user turns on and off, so they are the unit the
|
|
4
|
+
// registry is built from. Turning off `code` removes run_command entirely — the
|
|
5
|
+
// model isn't told about a tool it may not use and then refused, it simply
|
|
6
|
+
// doesn't have one. A capability that is absent can't be talked into existing.
|
|
7
|
+
//
|
|
8
|
+
// Two groups ship declared but empty. `browser` would need a real engine, and
|
|
9
|
+
// `integrations` would need connectors; both are listed here so the onboarding,
|
|
10
|
+
// `/status` and `vaan doctor` can say plainly that they are not configured
|
|
11
|
+
// rather than pretending. An empty group is an honest answer; a tool that
|
|
12
|
+
// fetches a page and calls itself a browser is not.
|
|
13
|
+
import { now, remember } from "./basics.js";
|
|
14
|
+
import { runCommandTool } from "./code.js";
|
|
15
|
+
import { editFile, listDir, readFile, writeFile } from "./files.js";
|
|
16
|
+
import { gitDiff, gitLog, gitStatus } from "./git.js";
|
|
17
|
+
import { listFiles, searchWorkspace } from "./grep.js";
|
|
18
|
+
import { defaultSearchProvider, webFetch, webSearch } from "./web.js";
|
|
19
|
+
export const GROUPS = [
|
|
20
|
+
{ group: "files", label: "Files", note: "read, write and edit inside the workspace", available: true },
|
|
21
|
+
{ group: "search", label: "Search", note: "find text and files in the workspace", available: true },
|
|
22
|
+
{ group: "git", label: "Git", note: "status, diff and log — read-only", available: true },
|
|
23
|
+
{ group: "web", label: "Web", note: "search and fetch public pages", available: true },
|
|
24
|
+
{ group: "code", label: "Code execution", note: "run commands in the sandbox", available: true },
|
|
25
|
+
{ group: "memory", label: "Memory", note: "remember durable facts about you", available: true },
|
|
26
|
+
{ group: "browser", label: "Browser", note: "not configured in this build", available: false },
|
|
27
|
+
{
|
|
28
|
+
group: "integrations",
|
|
29
|
+
label: "External integrations",
|
|
30
|
+
note: "not configured in this build",
|
|
31
|
+
available: false,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
export const DEFAULT_GROUPS = GROUPS.filter((entry) => entry.available).map((entry) => entry.group);
|
|
35
|
+
export function builtinTools(opts = {}) {
|
|
36
|
+
const enabled = new Set(opts.groups ?? DEFAULT_GROUPS);
|
|
37
|
+
const all = [
|
|
38
|
+
now,
|
|
39
|
+
readFile,
|
|
40
|
+
listDir,
|
|
41
|
+
writeFile,
|
|
42
|
+
editFile,
|
|
43
|
+
searchWorkspace,
|
|
44
|
+
listFiles,
|
|
45
|
+
gitStatus,
|
|
46
|
+
gitDiff,
|
|
47
|
+
gitLog,
|
|
48
|
+
webSearch(opts.search ?? defaultSearchProvider()),
|
|
49
|
+
webFetch,
|
|
50
|
+
runCommandTool,
|
|
51
|
+
remember,
|
|
52
|
+
];
|
|
53
|
+
return all.filter((tool) => enabled.has(tool.group));
|
|
54
|
+
}
|
|
55
|
+
/** Which groups actually produced tools, for `/status` and the startup lines. */
|
|
56
|
+
export function activeGroups(tools) {
|
|
57
|
+
return [...new Set(tools.map((tool) => tool.group))];
|
|
58
|
+
}
|
|
59
|
+
export { now, remember } from "./basics.js";
|
|
60
|
+
export { runCommandTool } from "./code.js";
|
|
61
|
+
export { diff, editFile, listDir, readFile, writeFile } from "./files.js";
|
|
62
|
+
export { gitDiff, gitLog, gitStatus } from "./git.js";
|
|
63
|
+
export { listFiles, searchWorkspace } from "./grep.js";
|
|
64
|
+
export { jail, JailError } from "../sandbox/filesystem.js";
|
|
65
|
+
export { braveSearch, duckDuckGo, parseDuckDuckGo, webFetch, webSearch, } from "./web.js";
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
export function readIfExists(path) {
|
|
3
|
+
try {
|
|
4
|
+
return readFileSync(path, "utf8");
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export const clip = (text, max) => text.length <= max ? text : `${text.slice(0, max)}…`;
|
|
11
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/tools/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,GAAW,EAAU,EAAE,CACxD,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC"}
|