Adding a New Tool (Level A)
This project uses Level A tools:
- Tool handlers are implemented in code (safe, reviewable).
- Tool availability is dynamic (protocol-driven + admin overrides) and is kept in sync between:
- LangChain tool list (what the agent can call)
prompt injection (what the model is told is available)
The Source of Truth (what to edit)
1) Register the tool (catalog + UI metadata)
File: backend/src/config/toolCatalog.ts
- Add the new tool id to the
ToolIdunion. - Add a
toolCatalogentry withlabel,description,category,mode, andaccessdefaults. - Keep
enabled: trueif it’s allowed to run in production.
Admins can still disable it at runtime via the enablement override system.
2) Add the input schema (shared by executor + LangChain)
File: backend/src/services/tools/toolSchemas.ts
- Add a Zod schema for the tool input.
- Add it to
TOOL_SCHEMA_BY_ID[toolId].
This is critical: the schema is used for both tool execution validation and LangChain tool argument validation.
3) Implement the tool handler (execution)
File: backend/src/services/toolExecutor.service.ts
- Add a new entry in the
executorsmap:schema: use the schema fromtoolSchemas.tsrequiresFile: set if it needs uploadshandler: implement the actual logic
Tool execution enforces:
- Enablement override (admin can disable tools at runtime)
- Access policy (
allowedProtocols,targetScope) plus DB overrides
4) Add prompt metadata (optional, but recommended)
File: backend/src/services/tools/toolCompilation.service.ts
- Add an entry to
TOOL_PROMPT_META[toolId]with:descriptionargs(human-readable argument descriptions)example(optional)
This improves the quality of tool use because the agent sees clearer tool docs inside prompts.
Make the tool available to a protocol
Tools are dynamically selected per turn by the compiler.
Option A (recommended): allowlist tools per protocol
Update the protocol definition:
- Field:
protocol.toolConfig.allowedTools - Add your tool id to the array.
If a protocol does not specify allowedTools, the system falls back to a default conversational tool set.
Option B: keep default set
If your tool is meant to be universally available, add it to the default list:
- File:
backend/src/services/tools/toolCompilation.service.ts - Constant:
DEFAULT_CONVERSATIONAL_TOOLS
Admin overrides (runtime controls)
Enable/disable tools without redeploy
Admin API:
GET /api/admin/tool-enablementPUT /api/admin/tool-enablement/:toolIdwith{ "enabled": true|false|null }DELETE /api/admin/tool-enablement/:toolId(reset to code default)
Notes:
- Level A safety: if a tool is
enabled: falsein code, admin overrides do not resurrect it.
Restrict tools by protocol / scope
Admin API:
GET /api/admin/tool-permissionsPUT /api/admin/tool-permissions/:toolIdwith{ allowedProtocols, targetScope }DELETE /api/admin/tool-permissions/:toolId(reset)
Checklist (copy/paste)
- [ ] Add tool id + catalog entry in
backend/src/config/toolCatalog.ts - [ ] Add Zod schema +
TOOL_SCHEMA_BY_IDentry inbackend/src/services/tools/toolSchemas.ts - [ ] Add executor handler in
backend/src/services/toolExecutor.service.ts - [ ] Add prompt meta in
backend/src/services/tools/toolCompilation.service.ts(recommended) - [ ] Add tool to protocol allowlist (
protocol.toolConfig.allowedTools) or default set - [ ] Verify tool appears in prompt
- [ ] Verify tool appears in LangChain tool list and runs successfully
- [ ] (Optional) Add/adjust tool access + enablement via admin UI