{"_id":"@bernierllc/agent-tool-registry","_rev":"3-308aa327f4761dabd1cbfa09f527cf69","name":"@bernierllc/agent-tool-registry","dist-tags":{"latest":"0.2.1"},"versions":{"0.0.1":{"name":"@bernierllc/agent-tool-registry","version":"0.0.1","keywords":["oidc","trusted-publishing","setup"],"_id":"@bernierllc/agent-tool-registry@0.0.1","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"dist":{"shasum":"0c72342758f9ea9e685eff6e5ec007598b7a2b0d","tarball":"https://registry.npmjs.org/@bernierllc/agent-tool-registry/-/agent-tool-registry-0.0.1.tgz","fileCount":2,"integrity":"sha512-j0RIFKVOF4TJrwXWpvhazcn8A32OMG18iLIBFPjCLYC+6hELREZTyOlhGWVxa3LKhEKhpQS248bowlLoldgEOw==","signatures":[{"sig":"MEUCIFqHLFFtQsSfTSSMTTbLmdFcUvx6qyyL7rSL8/LJytEpAiEA0DveQKoPIL+uU82c6LDD/Tn6m2clgM66tVE8y0Csjz8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2087},"_npmUser":{"name":"mkbernier","email":"mkbernier@gmail.com"},"_npmVersion":"11.12.1","description":"OIDC trusted publishing setup package for @bernierllc/agent-tool-registry","directories":{},"_nodeVersion":"25.9.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/agent-tool-registry_0.0.1_1781312327711_0.4124817624398942","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bernierllc/agent-tool-registry","version":"0.2.0","keywords":["ai","agent","tools","function-calling","permissions","bernierllc"],"author":{"name":"Bernier LLC"},"license":"Bernier LLC","_id":"@bernierllc/agent-tool-registry@0.2.0","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"homepage":"https://github.com/bernierllc/tools#readme","bugs":{"url":"https://github.com/bernierllc/tools/issues"},"dist":{"shasum":"b2bec7406fe1f4b37a23370e414b339eea929166","tarball":"https://registry.npmjs.org/@bernierllc/agent-tool-registry/-/agent-tool-registry-0.2.0.tgz","fileCount":23,"integrity":"sha512-QtizPddlJDu+jzC16prp1KUocXNSFVqxE27Wflo/a5U1/aVQJz5xv+WDB8IWEwO739ZhkvIqrnu3QtxhLkHAnQ==","signatures":[{"sig":"MEUCIHdIOwiY4F2uSuiQZVpvLL4dUWj6WHARVeg+d9gTdDVyAiEA6W38ZOuitZ2wfZejJDHhlm0N1JNA9w5WwKHgKo4ghqM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41998},"main":"dist/index.js","_from":"file:bernierllc-agent-tool-registry-0.2.0.tgz","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"scripts":{"lint":"eslint src/**/*.ts","test":"jest","build":"tsc","clean":"rm -rf dist","prebuild":"npm run clean","test:run":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7e3a160b-3cad-45db-9568-dff72c678f5b"}},"_resolved":"/home/runner/work/tools/tools/packages/core/agent-tool-registry/bernierllc-agent-tool-registry-0.2.0.tgz","_integrity":"sha512-QtizPddlJDu+jzC16prp1KUocXNSFVqxE27Wflo/a5U1/aVQJz5xv+WDB8IWEwO739ZhkvIqrnu3QtxhLkHAnQ==","repository":{"url":"git+https://github.com/bernierllc/tools.git","type":"git","directory":"packages/core/agent-tool-registry"},"_npmVersion":"11.17.0","description":"Typed in-process tool definition, registration, and permission-scoped execution for LLM agent loops","directories":{},"_nodeVersion":"24.16.0","dependencies":{"@bernierllc/logger":"1.7.0","@bernierllc/schema-validator":"3.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.0.0","rimraf":"^5.0.0","ts-jest":"^29.1.2","typescript":"^5.3.3","@types/jest":"^29.5.12","@types/node":"^20.11.19"},"peerDependencies":{"@bernierllc/neverhub-adapter":"^0.4.0"},"peerDependenciesMeta":{"@bernierllc/neverhub-adapter":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agent-tool-registry_0.2.0_1781313843871_0.5967084172684072","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@bernierllc/agent-tool-registry","version":"0.2.1","description":"Typed in-process tool definition, registration, and permission-scoped execution for LLM agent loops","main":"dist/index.js","types":"dist/index.d.ts","keywords":["ai","agent","tools","function-calling","permissions","bernierllc"],"author":{"name":"Bernier LLC"},"license":"Bernier LLC","repository":{"type":"git","url":"git+https://github.com/bernierllc/tools.git","directory":"packages/core/agent-tool-registry"},"dependencies":{"@bernierllc/schema-validator":"3.0.0","@bernierllc/logger":"1.7.1"},"peerDependencies":{"@bernierllc/neverhub-adapter":"^0.4.0"},"peerDependenciesMeta":{"@bernierllc/neverhub-adapter":{"optional":true}},"devDependencies":{"@types/jest":"^29.5.12","@types/node":"^20.11.19","eslint":"^8.0.0","jest":"^29.7.0","rimraf":"^5.0.0","ts-jest":"^29.1.2","typescript":"^5.3.3"},"engines":{"node":">=18.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"scripts":{"build":"tsc","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","lint":"eslint src/**/*.ts","clean":"rm -rf dist","prebuild":"npm run clean","test:run":"jest"},"_id":"@bernierllc/agent-tool-registry@0.2.1","bugs":{"url":"https://github.com/bernierllc/tools/issues"},"homepage":"https://github.com/bernierllc/tools#readme","_integrity":"sha512-5RHLiHOg+fHKnUiPEQQIPYPMDCimKn/k1nS3bNHmshATFdpPXG52pSlaygC6UhgiME5moKE0ZzFYEKMQNf0Bxg==","_resolved":"/home/runner/work/tools/tools/packages/core/agent-tool-registry/bernierllc-agent-tool-registry-0.2.1.tgz","_from":"file:bernierllc-agent-tool-registry-0.2.1.tgz","_nodeVersion":"24.18.0","_npmVersion":"12.0.1","dist":{"integrity":"sha512-5RHLiHOg+fHKnUiPEQQIPYPMDCimKn/k1nS3bNHmshATFdpPXG52pSlaygC6UhgiME5moKE0ZzFYEKMQNf0Bxg==","shasum":"3c4720c7dd1f3e5ae13e556a9b4d33970d63d263","tarball":"https://registry.npmjs.org/@bernierllc/agent-tool-registry/-/agent-tool-registry-0.2.1.tgz","fileCount":23,"unpackedSize":41998,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAihS2aXM8fgZIDnS3UwUVXu0yISni4zuBWZoNyMwGNiAiA14Z+beIZy1mz19gB+tx7jDNDHjvsK0o/ze+vi+4oqpg=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7e3a160b-3cad-45db-9568-dff72c678f5b"}},"directories":{},"maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/agent-tool-registry_0.2.1_1784015470688_0.8378600935782183"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-13T00:58:47.581Z","modified":"2026-07-14T07:51:10.975Z","0.0.1":"2026-06-13T00:58:47.841Z","0.2.0":"2026-06-13T01:24:04.059Z","0.2.1":"2026-07-14T07:51:10.841Z"},"bugs":{"url":"https://github.com/bernierllc/tools/issues"},"author":{"name":"Bernier LLC"},"license":"Bernier LLC","homepage":"https://github.com/bernierllc/tools#readme","keywords":["ai","agent","tools","function-calling","permissions","bernierllc"],"repository":{"type":"git","url":"git+https://github.com/bernierllc/tools.git","directory":"packages/core/agent-tool-registry"},"description":"Typed in-process tool definition, registration, and permission-scoped execution for LLM agent loops","maintainers":[{"name":"alikhan410","email":"mczeyo@gmail.com"},{"name":"mkbernier","email":"mkbernier@gmail.com"}],"readme":"# @bernierllc/agent-tool-registry\n\nTyped in-process tool definition, registration, and permission-scoped execution for LLM agent loops.\n\nCovers the full tool lifecycle: schema definition, registration, permission check at call time, input validation via `@bernierllc/schema-validator`, normalized `ToolResult` output, and before/after execution hooks (for audit logging and changeset recording).\n\n**Distinct from `@bernierllc/mcp-server-core`:** this registry is for tools wired directly into a running agent loop. A one-way `exportToMCPFormat()` adapter converts registered tools into mcp-server-core format when needed.\n\n## Installation\n\n```bash\nnpm install @bernierllc/agent-tool-registry\n```\n\n## Quick Start\n\n```typescript\nimport { createToolRegistry } from '@bernierllc/agent-tool-registry';\n\nconst registry = createToolRegistry();\n\n// Register a tool\nregistry.register({\n  name: 'addService',\n  description: 'Add a new service offering to the organization catalog',\n  inputSchema: {\n    type: 'object',\n    properties: {\n      name: { type: 'string' },\n      price: { type: 'number', minimum: 0 },\n      durationMinutes: { type: 'number', minimum: 1 },\n    },\n    required: ['name', 'price', 'durationMinutes'],\n  },\n  permissions: ['admin:services:write'],\n  async execute(input, context) {\n    const { name, price } = input as { name: string; price: number; durationMinutes: number };\n    // Use context.callerId, context.metadata, etc.\n    return { success: true, message: `Service \"${name}\" added at $${price}` };\n  },\n});\n\n// Execute (called by ai-agent-runtime when the LLM makes a tool call)\nconst result = await registry.execute(\n  'addService',\n  toolCallId,                               // opaque ID from the LLM response\n  { name: 'Haircut', price: 45, durationMinutes: 30 },\n  {\n    conversationId: 'conv-abc',\n    callerId: 'org-123',\n    grantedPermissions: ['admin:services:write'],\n  }\n);\n// result: { success: true, message: 'Service \"Haircut\" added at $45' }\n```\n\n## Execution Pipeline\n\n```\nregistry.execute(name, toolCallId, input, context)\n  ↓\nLookup tool definition → ToolNotFoundError if missing\n  ↓\nPermission check → ToolPermissionError if caller lacks required permissions\n  ↓\nInput validation via schema-validator → ToolInputValidationError if invalid\n  ↓\nFire before-hooks (audit log start, changeset setup)\n  ↓\ntool.execute(input, context) → ToolResult\n  ↓\nFire after-hooks (audit log complete, changeset record)\n  ↓\nReturn ToolResult to caller\n```\n\n## Before/After Hooks\n\n```typescript\nregistry.addHook({\n  before: async (record, context) => {\n    // record: { toolName, toolCallId, input }\n    // context: { conversationId, callerId, grantedPermissions, metadata }\n    await auditLogger.start({ action: record.toolName, callerId: context.callerId });\n  },\n  after: async (record, context) => {\n    // record: { toolName, toolCallId, input, state: 'success' | 'error', output: ToolResult }\n    await auditLogger.complete({ ...record });\n    await metrics.record({ tool: record.toolName, success: record.output?.success });\n  },\n});\n```\n\nHook errors are caught and logged — they never suppress the tool result or rethrow to the caller. Multiple hooks run in registration order.\n\n## Error Classes\n\nAll errors extend `ToolRegistryError` and include `Error.cause` chaining.\n\n| Class | Code | When thrown |\n|---|---|---|\n| `ToolNotFoundError` | `TOOL_NOT_FOUND` | `execute()` called with unregistered name |\n| `ToolPermissionError` | `PERMISSION_DENIED` | Caller lacks a required permission |\n| `ToolInputValidationError` | `INVALID_INPUT` | Input fails JSON Schema validation |\n| `ToolExecutionError` | `EXECUTION_FAILED` | `tool.execute()` threw; original error is `cause` |\n| `DuplicateToolNameError` | `DUPLICATE_TOOL_NAME` | `register()` called with an already-registered name |\n\n```typescript\nimport {\n  ToolNotFoundError,\n  ToolPermissionError,\n  ToolInputValidationError,\n  ToolExecutionError,\n  DuplicateToolNameError,\n  ToolRegistryError,\n} from '@bernierllc/agent-tool-registry';\n\ntry {\n  await registry.execute('myTool', callId, input, context);\n} catch (err) {\n  if (err instanceof ToolPermissionError) {\n    console.error('Missing permissions:', err.context?.missingPermissions);\n  } else if (err instanceof ToolRegistryError) {\n    console.error(`Registry error [${err.code}]:`, err.message, 'caused by:', err.cause);\n  }\n}\n```\n\n## MCP Bridge\n\nExport all registered tools into the format expected by `@bernierllc/mcp-server-core`:\n\n```typescript\nimport { exportToMCPFormat } from '@bernierllc/agent-tool-registry';\n\n// After registering all tools:\nconst mcpTools = exportToMCPFormat(registry);\nmcpServer.registerTools(mcpTools);\n```\n\n`exportToMCPFormat` is a one-way snapshot — call it after all tools are registered.\n\n## API Reference\n\n### `createToolRegistry(logger?: Logger): ToolRegistry`\n\nCreate a new isolated registry. Accepts an optional pre-configured `@bernierllc/logger` instance; omit for a silent no-op logger.\n\n### `registry.register(tool: ToolDefinition): void`\n\nRegister a tool. Throws `DuplicateToolNameError` if the name is already registered.\n\n### `registry.get(name: string): ToolDefinition | undefined`\n\nLook up a tool by name.\n\n### `registry.list(): ToolDefinition[]`\n\nReturn all registered tools.\n\n### `registry.execute(name, toolCallId, input, context): Promise<ToolResult>`\n\nRun the full execution pipeline for a named tool.\n\n### `registry.addHook(hook: ExecutionHook): void`\n\nInstall a before/after hook pair. Both `before` and `after` are optional.\n\n### `exportToMCPFormat(registry: IToolRegistry): MCPToolDefinition[]`\n\nConvert registered tools to mcp-server-core format.\n\n## License\n\nBernier LLC limited-use license. See [LICENSE](./LICENSE).\n","readmeFilename":"README.md"}