diff --git a/workers/api/migrations/0050_repo_chat_declared_tools.sql b/workers/api/migrations/0050_repo_chat_declared_tools.sql new file mode 100644 index 00000000..2f7cf67e --- /dev/null +++ b/workers/api/migrations/0050_repo_chat_declared_tools.sql @@ -0,0 +1,18 @@ +-- Repo Chat: declare its tool allowlist as DATA (capabilities.tools) instead of +-- relying on the hardcoded `repo`-surface special-case in toolNamesFor. +-- +-- This is the first agent to use the declarative tool catalog (#51 / PR #59) — the +-- "creator way" — so it doubles as the reference example a future creator copies. +-- Behavior-preserving: BASE + read-only KB is exactly what the `repo` surface already +-- resolved to; this only makes that choice explicit + data-driven. The surface stays +-- ["repo"] so the Repo tab and technical response-style are unchanged. +-- +-- Idempotent: re-running re-sets the same JSON; a no-op on databases without the agent. + +UPDATE agents +SET config = json_set( + COALESCE(NULLIF(config, ''), '{}'), + '$.capabilities.tools', + json('["search_knowledge","list_knowledge","read_knowledge"]') +) +WHERE slug = 'repo-chat'; diff --git a/workers/api/src/agent-do-tools.test.ts b/workers/api/src/agent-do-tools.test.ts index 44e7af93..053db90f 100644 --- a/workers/api/src/agent-do-tools.test.ts +++ b/workers/api/src/agent-do-tools.test.ts @@ -6,7 +6,7 @@ import { TOOL_CATALOG, toolNamesFor, } from "./agent-do-tools.js"; -import type { AgentCapabilities } from "./lib/agent-capabilities.js"; +import { agentCapabilities, type AgentCapabilities } from "./lib/agent-capabilities.js"; const caps = (surfaces: AgentCapabilities["surfaces"]): AgentCapabilities => ({ surfaces, @@ -149,6 +149,23 @@ describe("agent tool definition helpers", () => { expect(CREATOR_SELECTABLE_TOOLS.has("submit_job_application")).toBe(false); // legacy }); + it("repo-chat declaring its tools as data resolves identically to the repo-surface default (migration 0050 dogfood)", () => { + // The config shape migration 0050 produces: surface stays "repo", tools now + // declared explicitly. The whole point of the dogfood is that this changes NO + // behavior — it just moves the choice from a hardcoded special-case to data. + const config = JSON.stringify({ + capabilities: { + surfaces: ["repo"], + runtime: null, + workflow: null, + tools: ["search_knowledge", "list_knowledge", "read_knowledge"], + }, + }); + const declared = [...toolNamesFor(agentCapabilities({ slug: "repo-chat", config }))].sort(); + const surfaceDefault = [...toolNamesFor(caps(["repo"]))].sort(); + expect(declared).toEqual(surfaceDefault); + }); + it("returns the complete storage tool name set", () => { const names = storageToolNameSet();