From e1c9400567d163f8ec97a2f472fd08742363f5bc Mon Sep 17 00:00:00 2001 From: Serge Ivo Date: Sat, 1 Aug 2026 12:40:52 +1000 Subject: [PATCH] =?UTF-8?q?feat(repo-chat):=20declare=20tools=20as=20data?= =?UTF-8?q?=20=E2=80=94=20first=20exemplar=20of=20the=20creator=20way=20(#?= =?UTF-8?q?51)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migration 0050 sets repo-chat's capabilities.tools to its read-only KB set explicitly, instead of leaning on the hardcoded `repo`-surface special-case in toolNamesFor. repo-chat becomes the first agent built the "creator way" (declared data, not platform conditionals) — the reference example future creators copy. Behavior-preserving: BASE + read-only KB is exactly what the repo surface already resolved to (proven by a new test that resolves the post-migration config and asserts an identical tool set); the surface stays ["repo"] so the Repo tab + technical response style are unchanged. Migration validated with sqlite3 (tools set, surfaces + identity preserved). Part of #58. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../0050_repo_chat_declared_tools.sql | 18 ++++++++++++++++++ workers/api/src/agent-do-tools.test.ts | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 workers/api/migrations/0050_repo_chat_declared_tools.sql 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();