diff options
| author | Adam Malczewski <[email protected]> | 2026-06-02 16:33:02 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-02 16:33:02 +0900 |
| commit | 0f99a0c92707b44aef7c627012c4711bad5a8efd (patch) | |
| tree | 4b9fdc0895b30339d6501ed6387b02bc364bcdb6 /packages/api/src | |
| parent | c0c08720cceb75b5e635e71190ae1f956f535133 (diff) | |
| download | dispatch-0f99a0c92707b44aef7c627012c4711bad5a8efd.tar.gz dispatch-0f99a0c92707b44aef7c627012c4711bad5a8efd.zip | |
feat: add search_code tool wrapping the cs code-search engine
Add a dedicated, permission-gated search_code tool that wraps boyter/cs
(code spelunker) — a fast, relevance-ranked, structure-aware code search
engine — giving agents a better default than grep/find for exploratory
'where is X / how does Y work' searches (ranked results, snippets, ~5x
smaller payloads).
- packages/core/src/tools/search-code.ts: createSearchCodeTool factory;
-f json invocation, workdir path containment, graceful missing-binary
handling (DISPATCH_CS_BIN override), readable per-file formatted output.
- Wire-up: export from core; register in agent-manager (both child-whitelist
and parent perm paths) behind new perm_search_code; add to summon catalog
+ tools enum; frontend ToolPermissions + settings.
- Docker: build a patched, statically-linked cs (pinned v3.1.0 commit) in a
golang builder stage and bundle at /usr/local/bin/cs.
- docker/cs/luau-declarations.patch: additive Luau declaration table so
--only-declarations / definition ranking works for Roblox .luau files
(upstream has Lua but not Luau). Applied during the Docker build.
- Tests: new search-code.test.ts (stubbed JSON formatting + live-cs
integration, skipped when cs absent); agent-manager/routes mocks +
perm-gating assertions; loader pass-through.
All tests (596), biome, and tsc (core/api/frontend) pass. cs-builder Docker
stage verified to build and produce a working patched binary.
Diffstat (limited to 'packages/api/src')
| -rw-r--r-- | packages/api/src/agent-manager.ts | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/packages/api/src/agent-manager.ts b/packages/api/src/agent-manager.ts index 85dd160..48b869e 100644 --- a/packages/api/src/agent-manager.ts +++ b/packages/api/src/agent-manager.ts @@ -19,6 +19,7 @@ import { createReadTabTool, createRetrieveTool, createRunShellTool, + createSearchCodeTool, createSendToTabTool, createSkillsWatcher, createSummonTool, @@ -75,6 +76,8 @@ const TOOL_DESCRIPTIONS: Record<string, string> = { write_file: "Write content to a file (creates parent directories if needed)", run_shell: "Execute shell commands in the working directory (bash). Returns stdout, stderr, and exit code. Set background=true to run in the background and get a job_id for later retrieval. Do NOT run destructive or irreversible commands unless the user explicitly requests them.", + search_code: + "Search the codebase by query using the 'cs' code search engine (relevance-ranked, structure-aware). Returns the most relevant files first with matching snippets and line numbers. Better than grep/find for exploratory 'where is X / how does Y work' searches; use run_shell with rg for exhaustive exact-match lists.", todo: "Create/maintain a todo list to plan and track work. Declarative whole-list write: send the entire list in `todos` each call (it replaces the previous list). Statuses: pending, in_progress, completed, cancelled.", summon: "Spawn a child agent to work on a task independently. By default blocks until the child finishes. Set background=true to return immediately with an agent_id for later retrieval.", @@ -403,9 +406,10 @@ export class AgentManager { const permSendToTab = getSetting("perm_send_to_tab") === "allow"; const permReadTab = getSetting("perm_read_tab") === "allow"; const permWebSearch = getSetting("perm_web_search") === "allow"; + const permSearchCode = getSetting("perm_search_code") === "allow"; const permYoutubeTranscribe = getSetting("perm_youtube_transcribe") === "allow"; const sysPrompt = getSetting("system_prompt") ?? ""; - const permKey = `${permRead}:${permEdit}:${permBash}:${permSummon}:${permUserAgent}:${permSendToTab}:${permReadTab}:${permWebSearch}:${permYoutubeTranscribe}:${sysPrompt}`; + const permKey = `${permRead}:${permEdit}:${permBash}:${permSummon}:${permUserAgent}:${permSendToTab}:${permReadTab}:${permWebSearch}:${permYoutubeTranscribe}:${permSearchCode}:${sysPrompt}`; // If the override differs or permissions changed, invalidate the cached agent if ( @@ -479,6 +483,12 @@ export class AgentManager { tool: createRunShellTool(workingDirectory, tabAgent.shellStore), }); } + if (allowed.has("search_code")) { + toolEntries.push({ + name: "search_code", + tool: createSearchCodeTool(workingDirectory), + }); + } if (allowed.has("web_search")) { toolEntries.push({ name: "web_search", tool: createWebSearchTool() }); } @@ -565,6 +575,12 @@ export class AgentManager { tool: createRunShellTool(workingDirectory, tabAgent.shellStore), }); } + if (permSearchCode) { + toolEntries.push({ + name: "search_code", + tool: createSearchCodeTool(workingDirectory), + }); + } if (permWebSearch) { toolEntries.push({ name: "web_search", tool: createWebSearchTool() }); } |
