@oharness/engine 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/dist/agent/agent.d.ts +196 -0
- package/dist/agent/agent.js +758 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/compaction.d.ts +68 -0
- package/dist/agent/compaction.js +179 -0
- package/dist/agent/compaction.js.map +1 -0
- package/dist/agent/hooks.d.ts +77 -0
- package/dist/agent/hooks.js +152 -0
- package/dist/agent/hooks.js.map +1 -0
- package/dist/agent/memory.d.ts +45 -0
- package/dist/agent/memory.js +147 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/overflow.d.ts +35 -0
- package/dist/agent/overflow.js +69 -0
- package/dist/agent/overflow.js.map +1 -0
- package/dist/agent/permissions.d.ts +181 -0
- package/dist/agent/permissions.js +289 -0
- package/dist/agent/permissions.js.map +1 -0
- package/dist/agent/prompt.d.ts +25 -0
- package/dist/agent/prompt.js +63 -0
- package/dist/agent/prompt.js.map +1 -0
- package/dist/agent/session.d.ts +108 -0
- package/dist/agent/session.js +231 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/settings.d.ts +37 -0
- package/dist/agent/settings.js +113 -0
- package/dist/agent/settings.js.map +1 -0
- package/dist/agent/skills.d.ts +58 -0
- package/dist/agent/skills.js +225 -0
- package/dist/agent/skills.js.map +1 -0
- package/dist/agent/store.d.ts +308 -0
- package/dist/agent/store.js +596 -0
- package/dist/agent/store.js.map +1 -0
- package/dist/agent/subagent.d.ts +44 -0
- package/dist/agent/subagent.js +138 -0
- package/dist/agent/subagent.js.map +1 -0
- package/dist/agent/titles.d.ts +8 -0
- package/dist/agent/titles.js +23 -0
- package/dist/agent/titles.js.map +1 -0
- package/dist/agent/workspace.d.ts +60 -0
- package/dist/agent/workspace.js +156 -0
- package/dist/agent/workspace.js.map +1 -0
- package/dist/artifacts/publish.d.ts +94 -0
- package/dist/artifacts/publish.js +104 -0
- package/dist/artifacts/publish.js.map +1 -0
- package/dist/artifacts/store.d.ts +324 -0
- package/dist/artifacts/store.js +500 -0
- package/dist/artifacts/store.js.map +1 -0
- package/dist/auth/index.d.ts +13 -0
- package/dist/auth/index.js +10 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/manager.d.ts +83 -0
- package/dist/auth/manager.js +266 -0
- package/dist/auth/manager.js.map +1 -0
- package/dist/auth/oauth.d.ts +83 -0
- package/dist/auth/oauth.js +327 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/providers/account.d.ts +59 -0
- package/dist/auth/providers/account.js +282 -0
- package/dist/auth/providers/account.js.map +1 -0
- package/dist/auth/providers/anthropic.d.ts +24 -0
- package/dist/auth/providers/anthropic.js +209 -0
- package/dist/auth/providers/anthropic.js.map +1 -0
- package/dist/auth/providers/generic.d.ts +57 -0
- package/dist/auth/providers/generic.js +155 -0
- package/dist/auth/providers/generic.js.map +1 -0
- package/dist/auth/providers/official.d.ts +3 -0
- package/dist/auth/providers/official.js +90 -0
- package/dist/auth/providers/official.js.map +1 -0
- package/dist/auth/providers/ottoport.d.ts +3 -0
- package/dist/auth/providers/ottoport.js +60 -0
- package/dist/auth/providers/ottoport.js.map +1 -0
- package/dist/auth/store.d.ts +22 -0
- package/dist/auth/store.js +138 -0
- package/dist/auth/store.js.map +1 -0
- package/dist/auth/types.d.ts +167 -0
- package/dist/auth/types.js +16 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/config.d.ts +197 -0
- package/dist/config.js +195 -0
- package/dist/config.js.map +1 -0
- package/dist/core/errors.d.ts +46 -0
- package/dist/core/errors.js +83 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/tokens.d.ts +12 -0
- package/dist/core/tokens.js +56 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core/types.d.ts +91 -0
- package/dist/core/types.js +49 -0
- package/dist/core/types.js.map +1 -0
- package/dist/harness.d.ts +302 -0
- package/dist/harness.js +695 -0
- package/dist/harness.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +55 -0
- package/dist/mcp/client.js +199 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +77 -0
- package/dist/mcp/manager.js +325 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/mcp/oauth.d.ts +63 -0
- package/dist/mcp/oauth.js +302 -0
- package/dist/mcp/oauth.js.map +1 -0
- package/dist/mcp/protocol.d.ts +130 -0
- package/dist/mcp/protocol.js +14 -0
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/registry.d.ts +52 -0
- package/dist/mcp/registry.js +100 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/registry.json +293 -0
- package/dist/mcp/secrets.d.ts +20 -0
- package/dist/mcp/secrets.js +75 -0
- package/dist/mcp/secrets.js.map +1 -0
- package/dist/mcp/transport.d.ts +51 -0
- package/dist/mcp/transport.js +158 -0
- package/dist/mcp/transport.js.map +1 -0
- package/dist/paths.d.ts +37 -0
- package/dist/paths.js +63 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugins.d.ts +55 -0
- package/dist/plugins.js +201 -0
- package/dist/plugins.js.map +1 -0
- package/dist/providers/builtin.d.ts +23 -0
- package/dist/providers/builtin.js +141 -0
- package/dist/providers/builtin.js.map +1 -0
- package/dist/providers/catalog.d.ts +129 -0
- package/dist/providers/catalog.js +254 -0
- package/dist/providers/catalog.js.map +1 -0
- package/dist/providers/catalog.json +472 -0
- package/dist/providers/discovery.d.ts +16 -0
- package/dist/providers/discovery.js +161 -0
- package/dist/providers/discovery.js.map +1 -0
- package/dist/providers/http.d.ts +24 -0
- package/dist/providers/http.js +139 -0
- package/dist/providers/http.js.map +1 -0
- package/dist/providers/index.d.ts +10 -0
- package/dist/providers/index.js +8 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/piai.d.ts +124 -0
- package/dist/providers/piai.js +551 -0
- package/dist/providers/piai.js.map +1 -0
- package/dist/providers/registry.d.ts +65 -0
- package/dist/providers/registry.js +195 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/resilient.d.ts +46 -0
- package/dist/providers/resilient.js +117 -0
- package/dist/providers/resilient.js.map +1 -0
- package/dist/providers/types.d.ts +182 -0
- package/dist/providers/types.js +50 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/schedule/cron.d.ts +35 -0
- package/dist/schedule/cron.js +125 -0
- package/dist/schedule/cron.js.map +1 -0
- package/dist/schedule/scheduler.d.ts +87 -0
- package/dist/schedule/scheduler.js +237 -0
- package/dist/schedule/scheduler.js.map +1 -0
- package/dist/storage/kv.d.ts +56 -0
- package/dist/storage/kv.js +173 -0
- package/dist/storage/kv.js.map +1 -0
- package/dist/storage/migrate.d.ts +11 -0
- package/dist/storage/migrate.js +93 -0
- package/dist/storage/migrate.js.map +1 -0
- package/dist/storage/project.d.ts +9 -0
- package/dist/storage/project.js +57 -0
- package/dist/storage/project.js.map +1 -0
- package/dist/storage/records.d.ts +32 -0
- package/dist/storage/records.js +48 -0
- package/dist/storage/records.js.map +1 -0
- package/dist/sync/client.d.ts +79 -0
- package/dist/sync/client.js +118 -0
- package/dist/sync/client.js.map +1 -0
- package/dist/sync/mirror.d.ts +85 -0
- package/dist/sync/mirror.js +389 -0
- package/dist/sync/mirror.js.map +1 -0
- package/dist/sync/protocol.d.ts +67 -0
- package/dist/sync/protocol.js +16 -0
- package/dist/sync/protocol.js.map +1 -0
- package/dist/sync/settings.d.ts +56 -0
- package/dist/sync/settings.js +60 -0
- package/dist/sync/settings.js.map +1 -0
- package/dist/tools/builtin/artifact.d.ts +16 -0
- package/dist/tools/builtin/artifact.js +134 -0
- package/dist/tools/builtin/artifact.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +3 -0
- package/dist/tools/builtin/bash.js +142 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/fs.d.ts +19 -0
- package/dist/tools/builtin/fs.js +280 -0
- package/dist/tools/builtin/fs.js.map +1 -0
- package/dist/tools/builtin/index.d.ts +22 -0
- package/dist/tools/builtin/index.js +42 -0
- package/dist/tools/builtin/index.js.map +1 -0
- package/dist/tools/builtin/mcp-resource.d.ts +3 -0
- package/dist/tools/builtin/mcp-resource.js +220 -0
- package/dist/tools/builtin/mcp-resource.js.map +1 -0
- package/dist/tools/builtin/memory.d.ts +10 -0
- package/dist/tools/builtin/memory.js +76 -0
- package/dist/tools/builtin/memory.js.map +1 -0
- package/dist/tools/builtin/recall.d.ts +13 -0
- package/dist/tools/builtin/recall.js +163 -0
- package/dist/tools/builtin/recall.js.map +1 -0
- package/dist/tools/builtin/search.d.ts +3 -0
- package/dist/tools/builtin/search.js +240 -0
- package/dist/tools/builtin/search.js.map +1 -0
- package/dist/tools/builtin/skill.d.ts +10 -0
- package/dist/tools/builtin/skill.js +46 -0
- package/dist/tools/builtin/skill.js.map +1 -0
- package/dist/tools/builtin/task.d.ts +9 -0
- package/dist/tools/builtin/task.js +68 -0
- package/dist/tools/builtin/task.js.map +1 -0
- package/dist/tools/builtin/todo.d.ts +20 -0
- package/dist/tools/builtin/todo.js +63 -0
- package/dist/tools/builtin/todo.js.map +1 -0
- package/dist/tools/define.d.ts +19 -0
- package/dist/tools/define.js +39 -0
- package/dist/tools/define.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry.d.ts +39 -0
- package/dist/tools/registry.js +101 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +112 -0
- package/dist/tools/types.js +22 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/util/id.d.ts +9 -0
- package/dist/util/id.js +19 -0
- package/dist/util/id.js.map +1 -0
- package/dist/util/json.d.ts +25 -0
- package/dist/util/json.js +100 -0
- package/dist/util/json.js.map +1 -0
- package/dist/util/jwt.d.ts +74 -0
- package/dist/util/jwt.js +177 -0
- package/dist/util/jwt.js.map +1 -0
- package/dist/util/logger.d.ts +13 -0
- package/dist/util/logger.js +59 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/queue.d.ts +26 -0
- package/dist/util/queue.js +106 -0
- package/dist/util/queue.js.map +1 -0
- package/dist/util/schema.d.ts +17 -0
- package/dist/util/schema.js +98 -0
- package/dist/util/schema.js.map +1 -0
- package/dist/util/shell.d.ts +20 -0
- package/dist/util/shell.js +24 -0
- package/dist/util/shell.js.map +1 -0
- package/official.json +4 -0
- package/package.json +38 -0
- package/skills/artifact-authoring/SKILL.md +81 -0
- package/skills/canvas/SKILL.md +85 -0
- package/skills/skill-authoring/SKILL.md +85 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineTool } from "../define.js";
|
|
3
|
+
import { toolError, toolText } from "../types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Read and write the agent's durable notes.
|
|
6
|
+
*
|
|
7
|
+
* Split into two tools rather than one with a `mode` argument: writing a note
|
|
8
|
+
* is a decision the model should make deliberately, and a single tool whose
|
|
9
|
+
* behaviour flips on a string is one the model gets wrong under pressure.
|
|
10
|
+
*/
|
|
11
|
+
export function createMemoryTools(memory) {
|
|
12
|
+
const read = defineTool({
|
|
13
|
+
name: "memory",
|
|
14
|
+
readOnly: true,
|
|
15
|
+
description: "Read notes recorded in earlier sessions. Call with an id from the memory index " +
|
|
16
|
+
"in the system prompt to read one in full, or with a query to search. The index " +
|
|
17
|
+
"shows summaries only — read the note before relying on it.",
|
|
18
|
+
parameters: z.object({
|
|
19
|
+
id: z.string().optional().describe("Note id to read in full"),
|
|
20
|
+
query: z.string().optional().describe("Text to search summaries, bodies and tags for"),
|
|
21
|
+
}),
|
|
22
|
+
renderTitle: (input) => `Memory(${input.id ?? input.query ?? "all"})`,
|
|
23
|
+
async execute(input) {
|
|
24
|
+
const entries = await memory.load();
|
|
25
|
+
if (entries.length === 0) {
|
|
26
|
+
return toolText("No notes have been recorded yet.");
|
|
27
|
+
}
|
|
28
|
+
if (input.id) {
|
|
29
|
+
const entry = entries.find((candidate) => candidate.id === input.id);
|
|
30
|
+
if (!entry) {
|
|
31
|
+
return toolError(`No note with id "${input.id}". Known ids: ${entries.map((e) => e.id).join(", ")}`);
|
|
32
|
+
}
|
|
33
|
+
return toolText(render(entry));
|
|
34
|
+
}
|
|
35
|
+
const matches = input.query ? await memory.search(input.query) : entries;
|
|
36
|
+
if (matches.length === 0) {
|
|
37
|
+
return toolText(`No note matches "${input.query}".`);
|
|
38
|
+
}
|
|
39
|
+
return toolText(matches.slice(0, 10).map(render).join("\n\n---\n\n"), {
|
|
40
|
+
matched: matches.length,
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
const write = defineTool({
|
|
45
|
+
name: "remember",
|
|
46
|
+
description: "Record something worth carrying into future sessions — a correction, a convention " +
|
|
47
|
+
"this project follows, an approach that worked. Do not record what the code or git " +
|
|
48
|
+
"history already says, or anything that only matters to the current task. Writing " +
|
|
49
|
+
"the same summary again updates the existing note rather than adding a duplicate.",
|
|
50
|
+
parameters: z.object({
|
|
51
|
+
summary: z
|
|
52
|
+
.string()
|
|
53
|
+
.min(4)
|
|
54
|
+
.describe("One line naming the lesson; this is what appears in the index"),
|
|
55
|
+
body: z
|
|
56
|
+
.string()
|
|
57
|
+
.min(4)
|
|
58
|
+
.describe("The note itself: what was learned, why it matters, how to apply it"),
|
|
59
|
+
tags: z.array(z.string()).optional().describe("Tags to help find it later"),
|
|
60
|
+
}),
|
|
61
|
+
renderTitle: (input) => `Remember(${input.summary.slice(0, 40)})`,
|
|
62
|
+
async execute(input) {
|
|
63
|
+
const entry = await memory.remember(input);
|
|
64
|
+
return toolText(`Recorded as \`${entry.id}\`.`, { id: entry.id, file: entry.file });
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
return [read, write];
|
|
68
|
+
}
|
|
69
|
+
function render(entry) {
|
|
70
|
+
const when = entry.createdAt
|
|
71
|
+
? new Date(entry.createdAt).toISOString().slice(0, 10)
|
|
72
|
+
: "unknown date";
|
|
73
|
+
const tags = entry.tags.length > 0 ? ` · ${entry.tags.join(", ")}` : "";
|
|
74
|
+
return `### ${entry.id} (${when}${tags})\n${entry.summary}\n\n${entry.body}`;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/tools/builtin/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ArchivedMessage } from "../../agent/store.ts";
|
|
2
|
+
/** Where the agent loop parks a reader for the current session's archive. */
|
|
3
|
+
export declare const ARCHIVE_READER = "session:archiveReader";
|
|
4
|
+
export type ArchiveReader = () => Promise<ArchivedMessage[]>;
|
|
5
|
+
/**
|
|
6
|
+
* Reach back into conversation history that compaction summarized away.
|
|
7
|
+
*
|
|
8
|
+
* A summary is lossy by construction — the model writing it cannot know which
|
|
9
|
+
* detail will matter twenty turns later. Archiving the originals is only half
|
|
10
|
+
* the fix; the agent also needs a way to ask for them, or it will confidently
|
|
11
|
+
* re-derive things it could have looked up.
|
|
12
|
+
*/
|
|
13
|
+
export declare const recallTool: import("../types.ts").Tool;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { messageText } from "../../core/types.js";
|
|
3
|
+
import { defineTool } from "../define.js";
|
|
4
|
+
import { toolError, toolText } from "../types.js";
|
|
5
|
+
/** Where the agent loop parks a reader for the current session's archive. */
|
|
6
|
+
export const ARCHIVE_READER = "session:archiveReader";
|
|
7
|
+
const MAX_CHARS = 12_000;
|
|
8
|
+
const DEFAULT_LIMIT = 10;
|
|
9
|
+
/**
|
|
10
|
+
* Reach back into conversation history that compaction summarized away.
|
|
11
|
+
*
|
|
12
|
+
* A summary is lossy by construction — the model writing it cannot know which
|
|
13
|
+
* detail will matter twenty turns later. Archiving the originals is only half
|
|
14
|
+
* the fix; the agent also needs a way to ask for them, or it will confidently
|
|
15
|
+
* re-derive things it could have looked up.
|
|
16
|
+
*/
|
|
17
|
+
export const recallTool = defineTool({
|
|
18
|
+
name: "recall",
|
|
19
|
+
description: "Search the archived earlier conversation that was summarized away by compaction. " +
|
|
20
|
+
"Use it when the summary mentions something without the detail you need — an exact " +
|
|
21
|
+
"error message, a file path, a decision and its reasoning. Search by keyword, or fetch " +
|
|
22
|
+
"a specific range with `fromSeq`/`toSeq`. Returns nothing if this session has not been " +
|
|
23
|
+
"compacted yet.",
|
|
24
|
+
readOnly: true,
|
|
25
|
+
parameters: z.object({
|
|
26
|
+
query: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Case-insensitive text to search for across archived messages"),
|
|
30
|
+
fromSeq: z
|
|
31
|
+
.number()
|
|
32
|
+
.int()
|
|
33
|
+
.min(0)
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Start of a sequence range to fetch verbatim"),
|
|
36
|
+
toSeq: z.number().int().min(0).optional().describe("End of the range, inclusive"),
|
|
37
|
+
limit: z
|
|
38
|
+
.number()
|
|
39
|
+
.int()
|
|
40
|
+
.min(1)
|
|
41
|
+
.max(50)
|
|
42
|
+
.optional()
|
|
43
|
+
.describe(`Maximum messages to return (default ${DEFAULT_LIMIT})`),
|
|
44
|
+
}),
|
|
45
|
+
renderTitle: (input) => input.query
|
|
46
|
+
? `Recall(${input.query})`
|
|
47
|
+
: input.fromSeq !== undefined
|
|
48
|
+
? `Recall(#${input.fromSeq}–${input.toSeq ?? input.fromSeq})`
|
|
49
|
+
: "Recall(recent)",
|
|
50
|
+
async execute(input, ctx) {
|
|
51
|
+
const reader = ctx.host.state.get(ARCHIVE_READER);
|
|
52
|
+
if (!reader) {
|
|
53
|
+
return toolError("no archive is available for this session");
|
|
54
|
+
}
|
|
55
|
+
const archive = await reader();
|
|
56
|
+
if (archive.length === 0) {
|
|
57
|
+
return toolText("Nothing has been archived — this conversation has not been compacted, so the full history is already in context.");
|
|
58
|
+
}
|
|
59
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
60
|
+
let matches = archive;
|
|
61
|
+
if (input.fromSeq !== undefined) {
|
|
62
|
+
const to = input.toSeq ?? input.fromSeq;
|
|
63
|
+
matches = archive.filter((entry) => entry.seq >= input.fromSeq && entry.seq <= to);
|
|
64
|
+
}
|
|
65
|
+
else if (input.query) {
|
|
66
|
+
const needle = input.query.toLowerCase();
|
|
67
|
+
matches = archive.filter((entry) => searchableText(entry.message).includes(needle));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// No filter: the most recent archived messages are the likeliest target.
|
|
71
|
+
matches = archive.slice(-limit);
|
|
72
|
+
}
|
|
73
|
+
if (matches.length === 0) {
|
|
74
|
+
return toolText(`No archived message matches ${input.query ? `"${input.query}"` : "that range"}. ` +
|
|
75
|
+
`The archive covers sequences ${archive[0].seq}–${archive[archive.length - 1].seq} ` +
|
|
76
|
+
`(${archive.length} messages).`);
|
|
77
|
+
}
|
|
78
|
+
// Keyword hits are most useful newest-first; an explicit range is not.
|
|
79
|
+
const selected = input.fromSeq !== undefined ? matches.slice(0, limit) : matches.slice(-limit);
|
|
80
|
+
const rendered = [];
|
|
81
|
+
let budget = MAX_CHARS;
|
|
82
|
+
let truncated = 0;
|
|
83
|
+
for (const entry of selected) {
|
|
84
|
+
const block = render(entry);
|
|
85
|
+
if (block.length > budget) {
|
|
86
|
+
truncated = selected.length - rendered.length;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
rendered.push(block);
|
|
90
|
+
budget -= block.length;
|
|
91
|
+
}
|
|
92
|
+
const header = `Archived messages ${matches.length === selected.length ? "" : `(${selected.length} of ${matches.length} matches) `}` +
|
|
93
|
+
`from sequences ${archive[0].seq}–${archive[archive.length - 1].seq}:`;
|
|
94
|
+
const footer = truncated
|
|
95
|
+
? `\n\n… ${truncated} more matching messages omitted for length. Narrow the query or use fromSeq/toSeq.`
|
|
96
|
+
: matches.length > selected.length
|
|
97
|
+
? `\n\n… ${matches.length - selected.length} more matches. Raise \`limit\` or narrow the query.`
|
|
98
|
+
: "";
|
|
99
|
+
return toolText(`${header}\n\n${rendered.join("\n\n")}${footer}`, {
|
|
100
|
+
matched: matches.length,
|
|
101
|
+
returned: rendered.length,
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
/** Everything worth matching a keyword against, including tool traffic. */
|
|
106
|
+
function searchableText(message) {
|
|
107
|
+
const parts = [];
|
|
108
|
+
for (const block of message.content) {
|
|
109
|
+
switch (block.type) {
|
|
110
|
+
case "text":
|
|
111
|
+
parts.push(block.text);
|
|
112
|
+
break;
|
|
113
|
+
case "thinking":
|
|
114
|
+
parts.push(block.thinking);
|
|
115
|
+
break;
|
|
116
|
+
case "tool_call":
|
|
117
|
+
parts.push(block.name, safeJson(block.input));
|
|
118
|
+
break;
|
|
119
|
+
case "tool_result":
|
|
120
|
+
parts.push(block.toolName);
|
|
121
|
+
for (const inner of block.content) {
|
|
122
|
+
if (inner.type === "text")
|
|
123
|
+
parts.push(inner.text);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
case "image":
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return parts.join("\n").toLowerCase();
|
|
131
|
+
}
|
|
132
|
+
function render(entry) {
|
|
133
|
+
const lines = [`#${entry.seq} ${entry.message.role}:`];
|
|
134
|
+
const text = messageText(entry.message).trim();
|
|
135
|
+
if (text)
|
|
136
|
+
lines.push(text);
|
|
137
|
+
for (const block of entry.message.content) {
|
|
138
|
+
if (block.type === "tool_call") {
|
|
139
|
+
lines.push(` → called ${block.name}(${truncate(safeJson(block.input), 300)})`);
|
|
140
|
+
}
|
|
141
|
+
else if (block.type === "tool_result") {
|
|
142
|
+
const body = block.content
|
|
143
|
+
.filter((b) => b.type === "text")
|
|
144
|
+
.map((b) => b.text)
|
|
145
|
+
.join("\n")
|
|
146
|
+
.trim();
|
|
147
|
+
lines.push(` ← ${block.toolName}${block.isError ? " (error)" : ""}: ${truncate(body, 1_500)}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return lines.join("\n");
|
|
151
|
+
}
|
|
152
|
+
function safeJson(value) {
|
|
153
|
+
try {
|
|
154
|
+
return JSON.stringify(value) ?? String(value);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return String(value);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function truncate(value, max) {
|
|
161
|
+
return value.length > max ? `${value.slice(0, max)}…` : value;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=recall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall.js","sourceRoot":"","sources":["../../../src/tools/builtin/recall.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGlD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAItD,MAAM,SAAS,GAAG,MAAM,CAAC;AACzB,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC;IACnC,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,mFAAmF;QACnF,oFAAoF;QACpF,wFAAwF;QACxF,wFAAwF;QACxF,gBAAgB;IAClB,QAAQ,EAAE,IAAI;IACd,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;QACnB,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,8DAA8D,CAAC;QAC3E,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CAAC,6CAA6C,CAAC;QAC1D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QACjF,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CAAC,uCAAuC,aAAa,GAAG,CAAC;KACrE,CAAC;IACF,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CACrB,KAAK,CAAC,KAAK;QACT,CAAC,CAAC,UAAU,KAAK,CAAC,KAAK,GAAG;QAC1B,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS;YAC3B,CAAC,CAAC,WAAW,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,GAAG;YAC7D,CAAC,CAAC,gBAAgB;IAExB,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAgB;QACnC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAA8B,CAAC;QAC/E,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,SAAS,CAAC,0CAA0C,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,MAAM,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,QAAQ,CACb,kHAAkH,CACnH,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,aAAa,CAAC;QAC3C,IAAI,OAAO,GAAG,OAAO,CAAC;QAEtB,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;YACxC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,OAAQ,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;QACtF,CAAC;aAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YACzC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,yEAAyE;YACzE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,QAAQ,CACb,+BAA+B,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI;gBAChF,gCAAgC,OAAO,CAAC,CAAC,CAAE,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,GAAG,GAAG;gBACtF,IAAI,OAAO,CAAC,MAAM,aAAa,CAClC,CAAC;QACJ,CAAC;QAED,uEAAuE;QACvE,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;QAEhF,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,MAAM,GAAG,SAAS,CAAC;QACvB,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5B,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;gBAC1B,SAAS,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;gBAC9C,MAAM;YACR,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;QACzB,CAAC;QAED,MAAM,MAAM,GACV,qBAAqB,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,MAAM,OAAO,OAAO,CAAC,MAAM,YAAY,EAAE;YACrH,kBAAkB,OAAO,CAAC,CAAC,CAAE,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,GAAG,GAAG,CAAC;QAE3E,MAAM,MAAM,GAAG,SAAS;YACtB,CAAC,CAAC,SAAS,SAAS,oFAAoF;YACxG,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM;gBAChC,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,qDAAqD;gBAChG,CAAC,CAAC,EAAE,CAAC;QAET,OAAO,QAAQ,CAAC,GAAG,MAAM,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,EAAE;YAChE,OAAO,EAAE,OAAO,CAAC,MAAM;YACvB,QAAQ,EAAE,QAAQ,CAAC,MAAM;SAC1B,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC;AAEH,2EAA2E;AAC3E,SAAS,cAAc,CAAC,OAAgB;IACtC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,MAAM;gBACT,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACvB,MAAM;YACR,KAAK,UAAU;gBACb,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC3B,MAAM;YACR,KAAK,WAAW;gBACd,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC9C,MAAM;YACR,KAAK,aAAa;gBAChB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC3B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBAClC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;wBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACpD,CAAC;gBACD,MAAM;YACR,KAAK,OAAO;gBACV,MAAM;QACV,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AACxC,CAAC;AAED,SAAS,MAAM,CAAC,KAAsB;IACpC,MAAM,KAAK,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE3B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,cAAc,KAAK,CAAC,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAClF,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO;iBACvB,MAAM,CAAC,CAAC,CAAC,EAAuC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;iBACrE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBAClB,IAAI,CAAC,IAAI,CAAC;iBACV,IAAI,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CACR,OAAO,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CACpF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,GAAW;IAC1C,OAAO,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { glob } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { defineTool } from "../define.js";
|
|
7
|
+
import { toolError, toolText } from "../types.js";
|
|
8
|
+
import { resolvePath } from "./fs.js";
|
|
9
|
+
const MAX_RESULTS = 200;
|
|
10
|
+
const DEFAULT_IGNORES = [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/.git/**",
|
|
13
|
+
"**/dist/**",
|
|
14
|
+
"**/build/**",
|
|
15
|
+
"**/.next/**",
|
|
16
|
+
"**/__pycache__/**",
|
|
17
|
+
"**/.venv/**",
|
|
18
|
+
"**/target/**",
|
|
19
|
+
];
|
|
20
|
+
export const globTool = defineTool({
|
|
21
|
+
name: "glob",
|
|
22
|
+
description: "Find files by glob pattern (e.g. `src/**/*.ts`). Results are sorted by modification time, newest first. Common build and dependency directories are excluded.",
|
|
23
|
+
readOnly: true,
|
|
24
|
+
parameters: z.object({
|
|
25
|
+
pattern: z.string().describe("Glob pattern, relative to the search root"),
|
|
26
|
+
path: z.string().optional().describe("Directory to search in; defaults to the working directory"),
|
|
27
|
+
}),
|
|
28
|
+
renderTitle: (input) => `Glob(${input.pattern})`,
|
|
29
|
+
async execute(input, ctx) {
|
|
30
|
+
let root;
|
|
31
|
+
try {
|
|
32
|
+
root = resolvePath(ctx, input.path ?? ".");
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
return toolError(String(err instanceof Error ? err.message : err));
|
|
36
|
+
}
|
|
37
|
+
const matches = [];
|
|
38
|
+
try {
|
|
39
|
+
for await (const entry of glob(input.pattern, { cwd: root, exclude: excludeFn })) {
|
|
40
|
+
matches.push(path.resolve(root, String(entry)));
|
|
41
|
+
if (matches.length >= MAX_RESULTS * 4)
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
return toolError(`glob failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
47
|
+
}
|
|
48
|
+
if (matches.length === 0)
|
|
49
|
+
return toolText(`No files match ${input.pattern}`);
|
|
50
|
+
// Newest first: the file someone is actively working on is usually the
|
|
51
|
+
// one they mean.
|
|
52
|
+
const withTimes = await Promise.all(matches.map(async (file) => {
|
|
53
|
+
try {
|
|
54
|
+
const info = await stat(file);
|
|
55
|
+
return { file, mtime: info.mtimeMs, isFile: info.isFile() };
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return { file, mtime: 0, isFile: false };
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
61
|
+
const sorted = withTimes
|
|
62
|
+
.filter((entry) => entry.isFile)
|
|
63
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
64
|
+
.slice(0, MAX_RESULTS)
|
|
65
|
+
.map((entry) => path.relative(ctx.cwd, entry.file) || entry.file);
|
|
66
|
+
const truncated = withTimes.length > sorted.length;
|
|
67
|
+
return toolText(sorted.join("\n") + (truncated ? `\n\n… truncated to ${MAX_RESULTS} results.` : ""), { count: sorted.length, truncated });
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
export const grepTool = defineTool({
|
|
71
|
+
name: "grep",
|
|
72
|
+
description: "Search file contents with a regular expression. Uses ripgrep when available. Returns matching lines with file and line number.",
|
|
73
|
+
readOnly: true,
|
|
74
|
+
parameters: z.object({
|
|
75
|
+
pattern: z.string().describe("Regular expression to search for"),
|
|
76
|
+
path: z.string().optional().describe("File or directory to search; defaults to the working directory"),
|
|
77
|
+
glob: z.string().optional().describe("Restrict to files matching this glob, e.g. '*.ts'"),
|
|
78
|
+
caseInsensitive: z.boolean().optional().describe("Case-insensitive match"),
|
|
79
|
+
filesOnly: z.boolean().optional().describe("List matching file paths instead of matching lines"),
|
|
80
|
+
contextLines: z.number().int().min(0).max(10).optional().describe("Lines of context around each match"),
|
|
81
|
+
}),
|
|
82
|
+
renderTitle: (input) => `Grep(${input.pattern})`,
|
|
83
|
+
async execute(input, ctx) {
|
|
84
|
+
let root;
|
|
85
|
+
try {
|
|
86
|
+
root = resolvePath(ctx, input.path ?? ".");
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return toolError(String(err instanceof Error ? err.message : err));
|
|
90
|
+
}
|
|
91
|
+
const viaRipgrep = await runRipgrep(input, root, ctx);
|
|
92
|
+
if (viaRipgrep !== null)
|
|
93
|
+
return viaRipgrep;
|
|
94
|
+
return runJsGrep(input, root, ctx);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
function excludeFn(entry) {
|
|
99
|
+
const name = typeof entry === "string" ? entry : entry.name;
|
|
100
|
+
return DEFAULT_IGNORES.some((pattern) => {
|
|
101
|
+
const dir = pattern.replace("**/", "").replace("/**", "");
|
|
102
|
+
return name === dir;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/** Returns null when ripgrep is unavailable, so the caller can fall back. */
|
|
106
|
+
async function runRipgrep(input, root, ctx) {
|
|
107
|
+
const args = ["--line-number", "--no-heading", "--color", "never", "--max-count", "50"];
|
|
108
|
+
if (input.caseInsensitive)
|
|
109
|
+
args.push("-i");
|
|
110
|
+
if (input.filesOnly)
|
|
111
|
+
args.push("--files-with-matches");
|
|
112
|
+
if (input.contextLines)
|
|
113
|
+
args.push("-C", String(input.contextLines));
|
|
114
|
+
if (input.glob)
|
|
115
|
+
args.push("--glob", input.glob);
|
|
116
|
+
for (const ignore of DEFAULT_IGNORES)
|
|
117
|
+
args.push("--glob", `!${ignore}`);
|
|
118
|
+
args.push("--regexp", input.pattern, root);
|
|
119
|
+
const result = await execCapture("rg", args, ctx.signal);
|
|
120
|
+
if (result === null)
|
|
121
|
+
return null; // rg not installed
|
|
122
|
+
if (result.code === 1 && result.stdout.trim() === "") {
|
|
123
|
+
return toolText(`No matches for /${input.pattern}/`);
|
|
124
|
+
}
|
|
125
|
+
if (result.code > 1) {
|
|
126
|
+
return toolError(`grep failed: ${result.stderr.trim() || `exit ${result.code}`}`);
|
|
127
|
+
}
|
|
128
|
+
return formatMatches(result.stdout, root, ctx, input.pattern);
|
|
129
|
+
}
|
|
130
|
+
async function runJsGrep(input, root, ctx) {
|
|
131
|
+
let regex;
|
|
132
|
+
try {
|
|
133
|
+
regex = new RegExp(input.pattern, input.caseInsensitive ? "i" : "");
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
return toolError(`invalid regular expression: ${err instanceof Error ? err.message : err}`);
|
|
137
|
+
}
|
|
138
|
+
const info = await stat(root).catch(() => null);
|
|
139
|
+
if (!info)
|
|
140
|
+
return toolError(`path not found: ${root}`);
|
|
141
|
+
const files = [];
|
|
142
|
+
if (info.isFile()) {
|
|
143
|
+
files.push(root);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const pattern = input.glob ?? "**/*";
|
|
147
|
+
for await (const entry of glob(pattern, { cwd: root, exclude: excludeFn })) {
|
|
148
|
+
const file = path.resolve(root, String(entry));
|
|
149
|
+
const entryInfo = await stat(file).catch(() => null);
|
|
150
|
+
if (entryInfo?.isFile())
|
|
151
|
+
files.push(file);
|
|
152
|
+
if (files.length > 5_000)
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const lines = [];
|
|
157
|
+
for (const file of files) {
|
|
158
|
+
if (ctx.signal.aborted)
|
|
159
|
+
break;
|
|
160
|
+
let content;
|
|
161
|
+
try {
|
|
162
|
+
content = await readFile(file, "utf8");
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
continue; // binary or unreadable
|
|
166
|
+
}
|
|
167
|
+
if (content.includes("\u0000"))
|
|
168
|
+
continue; // skip binary files
|
|
169
|
+
const fileLines = content.split("\n");
|
|
170
|
+
for (let i = 0; i < fileLines.length; i++) {
|
|
171
|
+
if (!regex.test(fileLines[i]))
|
|
172
|
+
continue;
|
|
173
|
+
if (input.filesOnly) {
|
|
174
|
+
lines.push(file);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
lines.push(`${file}:${i + 1}:${fileLines[i]}`);
|
|
178
|
+
if (lines.length >= MAX_RESULTS)
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
if (lines.length >= MAX_RESULTS)
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
if (lines.length === 0)
|
|
185
|
+
return toolText(`No matches for /${input.pattern}/`);
|
|
186
|
+
return formatMatches(lines.join("\n"), root, ctx, input.pattern);
|
|
187
|
+
}
|
|
188
|
+
function formatMatches(raw, root, ctx, pattern) {
|
|
189
|
+
void root;
|
|
190
|
+
const lines = raw.split("\n").filter((line) => line.trim() !== "");
|
|
191
|
+
const truncated = lines.length > MAX_RESULTS;
|
|
192
|
+
const shown = lines.slice(0, MAX_RESULTS).map((line) => relativize(line, ctx.cwd));
|
|
193
|
+
const footer = truncated
|
|
194
|
+
? `\n\n… ${lines.length - MAX_RESULTS} more matches. Narrow the pattern or scope the search.`
|
|
195
|
+
: "";
|
|
196
|
+
return toolText(shown.join("\n") + footer, {
|
|
197
|
+
matches: lines.length,
|
|
198
|
+
truncated,
|
|
199
|
+
pattern,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function relativize(line, cwd) {
|
|
203
|
+
return line.startsWith(cwd + path.sep) ? line.slice(cwd.length + 1) : line;
|
|
204
|
+
}
|
|
205
|
+
/** Run a command, returning null when the binary does not exist. */
|
|
206
|
+
function execCapture(command, args, signal) {
|
|
207
|
+
return new Promise((resolve) => {
|
|
208
|
+
let child;
|
|
209
|
+
try {
|
|
210
|
+
child = spawn(command, args, { signal });
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
resolve(null);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
let stdout = "";
|
|
217
|
+
let stderr = "";
|
|
218
|
+
let settled = false;
|
|
219
|
+
child.stdout?.on("data", (chunk) => {
|
|
220
|
+
stdout += chunk.toString();
|
|
221
|
+
});
|
|
222
|
+
child.stderr?.on("data", (chunk) => {
|
|
223
|
+
stderr += chunk.toString();
|
|
224
|
+
});
|
|
225
|
+
child.on("error", (err) => {
|
|
226
|
+
if (settled)
|
|
227
|
+
return;
|
|
228
|
+
settled = true;
|
|
229
|
+
resolve(err.code === "ENOENT" ? null : { code: 127, stdout, stderr: String(err) });
|
|
230
|
+
});
|
|
231
|
+
child.on("close", (code) => {
|
|
232
|
+
if (settled)
|
|
233
|
+
return;
|
|
234
|
+
settled = true;
|
|
235
|
+
resolve({ code: code ?? 0, stdout, stderr });
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
export const searchTools = [globTool, grepTool];
|
|
240
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/tools/builtin/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SkillRegistry } from "../../agent/skills.ts";
|
|
2
|
+
import type { Tool } from "../types.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Load a skill's full instructions on demand.
|
|
5
|
+
*
|
|
6
|
+
* Built against a live registry because the description has to name the skills
|
|
7
|
+
* that actually exist — a generic "load a skill" description gives the model
|
|
8
|
+
* nothing to match a task against, and it will never call the tool.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createSkillTool(skills: SkillRegistry): Tool;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { renderSkill } from "../../agent/skills.js";
|
|
3
|
+
import { defineTool } from "../define.js";
|
|
4
|
+
import { toolError, toolText } from "../types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Load a skill's full instructions on demand.
|
|
7
|
+
*
|
|
8
|
+
* Built against a live registry because the description has to name the skills
|
|
9
|
+
* that actually exist — a generic "load a skill" description gives the model
|
|
10
|
+
* nothing to match a task against, and it will never call the tool.
|
|
11
|
+
*/
|
|
12
|
+
export function createSkillTool(skills) {
|
|
13
|
+
const available = skills.list();
|
|
14
|
+
const names = available.map((skill) => skill.name);
|
|
15
|
+
return defineTool({
|
|
16
|
+
name: "skill",
|
|
17
|
+
readOnly: true,
|
|
18
|
+
description: "Load the full instructions for a skill listed in the system prompt. Call this " +
|
|
19
|
+
"before starting work that matches a skill's description — the description is a " +
|
|
20
|
+
"summary, not the instructions. " +
|
|
21
|
+
(names.length > 0
|
|
22
|
+
? `Available: ${names.join(", ")}.`
|
|
23
|
+
: "No skills are currently installed."),
|
|
24
|
+
parameters: z.object({
|
|
25
|
+
name: z
|
|
26
|
+
.string()
|
|
27
|
+
.describe(names.length > 0
|
|
28
|
+
? `Skill to load. One of: ${names.join(", ")}`
|
|
29
|
+
: "Skill name (none are installed)"),
|
|
30
|
+
}),
|
|
31
|
+
renderTitle: (input) => `Skill(${input.name})`,
|
|
32
|
+
async execute(input) {
|
|
33
|
+
const skill = skills.get(input.name);
|
|
34
|
+
if (!skill) {
|
|
35
|
+
return toolError(names.length === 0
|
|
36
|
+
? "No skills are installed. Add one at .oharness/skills/<name>/SKILL.md"
|
|
37
|
+
: `No skill named "${input.name}". Available: ${names.join(", ")}`);
|
|
38
|
+
}
|
|
39
|
+
return toolText(await renderSkill(skill), {
|
|
40
|
+
skill: skill.name,
|
|
41
|
+
directory: skill.directory,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../../../src/tools/builtin/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,MAAqB;IACnD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnD,OAAO,UAAU,CAAC;QAChB,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,IAAI;QACd,WAAW,EACT,gFAAgF;YAChF,iFAAiF;YACjF,iCAAiC;YACjC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;gBACf,CAAC,CAAC,cAAc,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACnC,CAAC,CAAC,oCAAoC,CAAC;QAC3C,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,CAAC;iBACJ,MAAM,EAAE;iBACR,QAAQ,CACP,KAAK,CAAC,MAAM,GAAG,CAAC;gBACd,CAAC,CAAC,0BAA0B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC9C,CAAC,CAAC,iCAAiC,CACtC;SACJ,CAAC;QACF,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,KAAK,CAAC,IAAI,GAAG;QAE9C,KAAK,CAAC,OAAO,CAAC,KAAK;YACjB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,SAAS,CACd,KAAK,CAAC,MAAM,KAAK,CAAC;oBAChB,CAAC,CAAC,sEAAsE;oBACxE,CAAC,CAAC,mBAAmB,KAAK,CAAC,IAAI,iBAAiB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrE,CAAC;YACJ,CAAC;YAED,OAAO,QAAQ,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE;gBACxC,KAAK,EAAE,KAAK,CAAC,IAAI;gBACjB,SAAS,EAAE,KAAK,CAAC,SAAS;aAC3B,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Tool, ToolHost } from "../types.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Spawns a subagent with its own context window and tool set.
|
|
4
|
+
*
|
|
5
|
+
* The description is built at registration time so the model sees the agent
|
|
6
|
+
* types that actually exist in this configuration, rather than a generic
|
|
7
|
+
* placeholder it has to guess against.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createTaskTool(host: Pick<ToolHost, "listSubagentTypes">): Tool;
|