@noy-db/in-ai 0.2.0-pre.9 → 0.3.0-pre.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,7 @@ See the [main repository](https://github.com/vLannaAi/noy-db#readme) for setup,
26
26
 
27
27
  - Source — [`packages/in-ai`](https://github.com/vLannaAi/noy-db/tree/main/packages/in-ai)
28
28
  - Issues — [github.com/vLannaAi/noy-db/issues](https://github.com/vLannaAi/noy-db/issues)
29
- - Spec — [`SPEC.md`](https://github.com/vLannaAi/noy-db/blob/main/SPEC.md)
29
+ - Spec — [`SPEC.md`](https://github.com/vLannaAi/noy-db-docs/blob/main/SPEC.md)
30
30
 
31
31
  ## License
32
32
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noy-db/in-ai",
3
- "version": "0.2.0-pre.9",
3
+ "version": "0.3.0-pre.2",
4
4
  "description": "LLM function-calling adapter for noy-db — expose ACL-scoped collections as tool definitions, then dispatch tool calls back to the vault. Format-agnostic (OpenAI, Anthropic, Vercel AI SDK).",
5
5
  "license": "MIT",
6
6
  "author": "vLannaAi <vicio@lanna.ai>",
@@ -17,17 +17,10 @@
17
17
  "sideEffects": false,
18
18
  "exports": {
19
19
  ".": {
20
- "import": {
21
- "types": "./dist/index.d.ts",
22
- "default": "./dist/index.js"
23
- },
24
- "require": {
25
- "types": "./dist/index.d.cts",
26
- "default": "./dist/index.cjs"
27
- }
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
28
22
  }
29
23
  },
30
- "main": "./dist/index.cjs",
31
24
  "module": "./dist/index.js",
32
25
  "types": "./dist/index.d.ts",
33
26
  "files": [
@@ -36,13 +29,13 @@
36
29
  "LICENSE"
37
30
  ],
38
31
  "engines": {
39
- "node": ">=18.0.0"
32
+ "node": ">=22.0.0"
40
33
  },
41
34
  "peerDependencies": {
42
- "@noy-db/hub": "0.2.0-pre.9"
35
+ "@noy-db/hub": "0.3.0-pre.2"
43
36
  },
44
37
  "devDependencies": {
45
- "@noy-db/hub": "0.2.0-pre.9"
38
+ "@noy-db/hub": "0.3.0-pre.2"
46
39
  },
47
40
  "keywords": [
48
41
  "noy-db",
package/dist/index.cjs DELETED
@@ -1,197 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- ToolDeniedError: () => ToolDeniedError,
24
- ToolNotFoundError: () => ToolNotFoundError,
25
- buildToolset: () => buildToolset,
26
- invokeToolCall: () => invokeToolCall,
27
- parseToolName: () => parseToolName
28
- });
29
- module.exports = __toCommonJS(index_exports);
30
- function buildToolset(vault, options = {}) {
31
- const operations = options.operations ?? ["list", "get"];
32
- const label = options.vaultLabel ?? vault.name;
33
- const format = options.format ?? "json-schema";
34
- const allowlist = options.collections ? new Set(options.collections) : null;
35
- const accessible = getAccessibleCollections(vault, allowlist);
36
- const tools = [];
37
- for (const collection of accessible) {
38
- for (const op of operations) {
39
- tools.push(jsonSchemaTool(collection, op, label));
40
- }
41
- }
42
- return tools.map((t) => wrap(t, format));
43
- }
44
- function jsonSchemaTool(collection, op, label) {
45
- switch (op) {
46
- case "list":
47
- return {
48
- name: `${collection}_list`,
49
- description: `List every record in the "${collection}" collection of vault "${label}". Returns an array of records.`,
50
- parameters: { type: "object", properties: {}, required: [] }
51
- };
52
- case "get":
53
- return {
54
- name: `${collection}_get`,
55
- description: `Get a single record from the "${collection}" collection of vault "${label}" by id. Returns null when the id does not exist.`,
56
- parameters: {
57
- type: "object",
58
- properties: { id: { type: "string", description: "Record id." } },
59
- required: ["id"]
60
- }
61
- };
62
- case "put":
63
- return {
64
- name: `${collection}_put`,
65
- description: `Create or replace a record in the "${collection}" collection of vault "${label}". The \`record\` argument is the full record object.`,
66
- parameters: {
67
- type: "object",
68
- properties: {
69
- id: { type: "string", description: "Record id." },
70
- record: { type: "object", description: "Full record body." }
71
- },
72
- required: ["id", "record"]
73
- }
74
- };
75
- case "delete":
76
- return {
77
- name: `${collection}_delete`,
78
- description: `Delete a record by id from the "${collection}" collection of vault "${label}".`,
79
- parameters: {
80
- type: "object",
81
- properties: { id: { type: "string", description: "Record id." } },
82
- required: ["id"]
83
- }
84
- };
85
- case "count":
86
- return {
87
- name: `${collection}_count`,
88
- description: `Count records in the "${collection}" collection of vault "${label}".`,
89
- parameters: { type: "object", properties: {}, required: [] }
90
- };
91
- }
92
- }
93
- function wrap(tool, format) {
94
- switch (format) {
95
- case "json-schema":
96
- return tool;
97
- case "openai":
98
- return { type: "function", function: tool };
99
- case "anthropic":
100
- return {
101
- name: tool.name,
102
- description: tool.description,
103
- input_schema: tool.parameters
104
- };
105
- case "vercel-ai":
106
- return { description: tool.description, parameters: tool.parameters };
107
- }
108
- }
109
- var ToolDeniedError = class extends Error {
110
- toolName;
111
- constructor(toolName, reason) {
112
- super(`Tool call denied: "${toolName}" \u2014 ${reason}`);
113
- this.name = "ToolDeniedError";
114
- this.toolName = toolName;
115
- }
116
- };
117
- var ToolNotFoundError = class extends Error {
118
- toolName;
119
- constructor(toolName) {
120
- super(`Tool call refused: "${toolName}" is not a known tool in this toolset.`);
121
- this.name = "ToolNotFoundError";
122
- this.toolName = toolName;
123
- }
124
- };
125
- async function invokeToolCall(vault, call, options = {}) {
126
- const parsed = parseToolName(call.name);
127
- if (!parsed) {
128
- throw new ToolNotFoundError(call.name);
129
- }
130
- const { collection, op } = parsed;
131
- const allowedOps = options.allowedOperations ?? ["list", "get"];
132
- if (!allowedOps.includes(op)) {
133
- throw new ToolDeniedError(call.name, `operation "${op}" is not in the allowed operations list`);
134
- }
135
- if (options.allowedCollections && !options.allowedCollections.includes(collection)) {
136
- throw new ToolDeniedError(call.name, `collection "${collection}" is not in the allowed list`);
137
- }
138
- const coll = vault.collection(collection);
139
- const id = toIdString(call.args.id);
140
- switch (op) {
141
- case "list":
142
- return coll.list();
143
- case "get":
144
- return coll.get(id);
145
- case "count":
146
- return (await coll.list()).length;
147
- case "put":
148
- return coll.put(id, call.args.record);
149
- case "delete":
150
- return coll.delete(id);
151
- }
152
- }
153
- function toIdString(value) {
154
- if (typeof value === "string") return value;
155
- if (typeof value === "number" || typeof value === "boolean") return String(value);
156
- return "";
157
- }
158
- function parseToolName(name) {
159
- const ops = ["list", "get", "put", "delete", "count"];
160
- for (const op of ops) {
161
- const suffix = `_${op}`;
162
- if (name.endsWith(suffix)) {
163
- const collection = name.slice(0, -suffix.length);
164
- if (collection.length === 0) return null;
165
- return { collection, op };
166
- }
167
- }
168
- return null;
169
- }
170
- function getAccessibleCollections(vault, allowlist) {
171
- const v = vault;
172
- if (typeof v.listCollectionNames === "function") {
173
- const names = v.listCollectionNames();
174
- return names.filter((n) => !n.startsWith("_") && (!allowlist || allowlist.has(n)));
175
- }
176
- const deks = v.keyring?.deks;
177
- if (deks) {
178
- const names = [];
179
- for (const key of deks.keys()) {
180
- if (key.startsWith("_")) continue;
181
- const bare = key.includes("#") ? key.slice(0, key.indexOf("#")) : key;
182
- if (allowlist && !allowlist.has(bare)) continue;
183
- if (!names.includes(bare)) names.push(bare);
184
- }
185
- return names;
186
- }
187
- return allowlist ? [...allowlist] : [];
188
- }
189
- // Annotate the CommonJS export names for ESM import in node:
190
- 0 && (module.exports = {
191
- ToolDeniedError,
192
- ToolNotFoundError,
193
- buildToolset,
194
- invokeToolCall,
195
- parseToolName
196
- });
197
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * **@noy-db/in-ai** — LLM function-calling adapter for noy-db.\n *\n * Exposes ACL-scoped collections as tool definitions that an LLM can\n * call, and dispatches incoming tool calls back to the vault. The\n * permission model carries through: a user whose keyring has only\n * `ro` on `invoices` sees only `invoices.list` / `invoices.get` —\n * never `invoices.put` / `invoices.delete`. The LLM physically\n * cannot emit a tool call the operator isn't authorised for, because\n * the tool doesn't exist in the model's context.\n *\n * ## Two layers\n *\n * 1. **{@link buildToolset}** — walk the vault's accessible\n * collections, emit a `Tool[]` array shaped for the format of\n * your choice (OpenAI, Anthropic, Vercel AI SDK, or the generic\n * JSON-Schema intermediate).\n *\n * 2. **{@link invokeToolCall}** — accept `{ name, args }` from the\n * LLM's response, re-check permissions, dispatch to the vault,\n * and return the result in a format that slots into the next\n * prompt round.\n *\n * ## Security boundary\n *\n * Tool calls are untrusted input. The dispatcher re-checks the\n * caller's permission on every invocation — even though the tool\n * wasn't published to the LLM, a hostile model might attempt a\n * fabricated call. The dispatcher throws `ToolDeniedError` rather\n * than silently ignoring, so the consumer can surface the attempt\n * to the user.\n *\n * @packageDocumentation\n */\n\nimport type { Vault } from '@noy-db/hub'\n\n// ─── Tool formats ───────────────────────────────────────────────────────\n\n/** Generic JSON-Schema-based tool (matches OpenAI's `function` shape). */\nexport interface JsonSchemaTool {\n readonly name: string\n readonly description: string\n readonly parameters: {\n readonly type: 'object'\n readonly properties: Record<string, { type: string; description?: string }>\n readonly required: readonly string[]\n }\n}\n\n/** OpenAI chat.completions tool shape. */\nexport interface OpenAITool {\n readonly type: 'function'\n readonly function: JsonSchemaTool\n}\n\n/** Anthropic Messages API tool shape. */\nexport interface AnthropicTool {\n readonly name: string\n readonly description: string\n readonly input_schema: JsonSchemaTool['parameters']\n}\n\n/** Vercel AI SDK tool shape (generic). */\nexport interface VercelAITool {\n readonly description: string\n readonly parameters: JsonSchemaTool['parameters']\n}\n\nexport type ToolFormat = 'openai' | 'anthropic' | 'vercel-ai' | 'json-schema'\n\n// ─── Toolset options ───────────────────────────────────────────────────\n\nexport interface ToolsetOptions {\n /**\n * Which collections to expose. Default: every collection in the\n * vault the caller has read access to. Pass an explicit allowlist\n * to narrow the surface — common in multi-tenant setups where the\n * LLM should only see a subset.\n */\n readonly collections?: readonly string[]\n /**\n * Which operations to expose per collection. Defaults to `['list',\n * 'get']` — read-only. Add `'put'` / `'delete'` explicitly when you\n * want the LLM to mutate. Permissions are re-checked at dispatch\n * time regardless.\n */\n readonly operations?: readonly ToolOperation[]\n /**\n * Output format. `'json-schema'` is the intermediate shape; the\n * others (`'openai'` / `'anthropic'` / `'vercel-ai'`) are the\n * SDK-specific wrappers.\n */\n readonly format?: ToolFormat\n /**\n * Human-readable vault label inserted into every tool description\n * (e.g. `\"Acme Inc.\"`). Helps the LLM disambiguate multi-vault\n * scenarios. Omit to use the raw vault name.\n */\n readonly vaultLabel?: string\n}\n\nexport type ToolOperation = 'list' | 'get' | 'put' | 'delete' | 'count'\n\n// ─── Tool builder ──────────────────────────────────────────────────────\n\n/** Build an LLM-ready toolset from a vault. */\nexport function buildToolset(\n vault: Vault,\n options: ToolsetOptions = {},\n): readonly (JsonSchemaTool | OpenAITool | AnthropicTool | VercelAITool)[] {\n const operations = options.operations ?? ['list', 'get']\n const label = options.vaultLabel ?? vault.name\n const format = options.format ?? 'json-schema'\n const allowlist = options.collections ? new Set(options.collections) : null\n\n // The Vault surface we use is tiny + safe: enumerate known collection\n // names via vault.describeAccess(). Fall back to caller-supplied\n // allowlist if describeAccess is not available.\n const accessible = getAccessibleCollections(vault, allowlist)\n\n const tools: JsonSchemaTool[] = []\n for (const collection of accessible) {\n for (const op of operations) {\n tools.push(jsonSchemaTool(collection, op, label))\n }\n }\n\n return tools.map(t => wrap(t, format))\n}\n\nfunction jsonSchemaTool(collection: string, op: ToolOperation, label: string): JsonSchemaTool {\n switch (op) {\n case 'list':\n return {\n name: `${collection}_list`,\n description: `List every record in the \"${collection}\" collection of vault \"${label}\". Returns an array of records.`,\n parameters: { type: 'object', properties: {}, required: [] },\n }\n case 'get':\n return {\n name: `${collection}_get`,\n description: `Get a single record from the \"${collection}\" collection of vault \"${label}\" by id. Returns null when the id does not exist.`,\n parameters: {\n type: 'object',\n properties: { id: { type: 'string', description: 'Record id.' } },\n required: ['id'],\n },\n }\n case 'put':\n return {\n name: `${collection}_put`,\n description: `Create or replace a record in the \"${collection}\" collection of vault \"${label}\". The \\`record\\` argument is the full record object.`,\n parameters: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Record id.' },\n record: { type: 'object', description: 'Full record body.' },\n },\n required: ['id', 'record'],\n },\n }\n case 'delete':\n return {\n name: `${collection}_delete`,\n description: `Delete a record by id from the \"${collection}\" collection of vault \"${label}\".`,\n parameters: {\n type: 'object',\n properties: { id: { type: 'string', description: 'Record id.' } },\n required: ['id'],\n },\n }\n case 'count':\n return {\n name: `${collection}_count`,\n description: `Count records in the \"${collection}\" collection of vault \"${label}\".`,\n parameters: { type: 'object', properties: {}, required: [] },\n }\n }\n}\n\nfunction wrap(\n tool: JsonSchemaTool,\n format: ToolFormat,\n): JsonSchemaTool | OpenAITool | AnthropicTool | VercelAITool {\n switch (format) {\n case 'json-schema':\n return tool\n case 'openai':\n return { type: 'function', function: tool }\n case 'anthropic':\n return {\n name: tool.name,\n description: tool.description,\n input_schema: tool.parameters,\n }\n case 'vercel-ai':\n return { description: tool.description, parameters: tool.parameters }\n }\n}\n\n// ─── Dispatch ──────────────────────────────────────────────────────────\n\nexport class ToolDeniedError extends Error {\n readonly toolName: string\n constructor(toolName: string, reason: string) {\n super(`Tool call denied: \"${toolName}\" — ${reason}`)\n this.name = 'ToolDeniedError'\n this.toolName = toolName\n }\n}\n\nexport class ToolNotFoundError extends Error {\n readonly toolName: string\n constructor(toolName: string) {\n super(`Tool call refused: \"${toolName}\" is not a known tool in this toolset.`)\n this.name = 'ToolNotFoundError'\n this.toolName = toolName\n }\n}\n\nexport interface ToolCall {\n readonly name: string\n readonly args: Record<string, unknown>\n}\n\nexport interface InvokeOptions {\n /** Mirror the allowlist used for `buildToolset` — enforced at dispatch. */\n readonly allowedOperations?: readonly ToolOperation[]\n readonly allowedCollections?: readonly string[]\n}\n\n/**\n * Dispatch an LLM-returned tool call against the vault. Caller is\n * expected to pass the same `allowedOperations` / `allowedCollections`\n * they used for `buildToolset`; deviations (including fabricated tool\n * names the LLM invented) throw `ToolNotFoundError` or\n * `ToolDeniedError`.\n */\nexport async function invokeToolCall(\n vault: Vault,\n call: ToolCall,\n options: InvokeOptions = {},\n): Promise<unknown> {\n const parsed = parseToolName(call.name)\n if (!parsed) {\n throw new ToolNotFoundError(call.name)\n }\n const { collection, op } = parsed\n\n const allowedOps = options.allowedOperations ?? ['list', 'get']\n if (!allowedOps.includes(op)) {\n throw new ToolDeniedError(call.name, `operation \"${op}\" is not in the allowed operations list`)\n }\n if (options.allowedCollections && !options.allowedCollections.includes(collection)) {\n throw new ToolDeniedError(call.name, `collection \"${collection}\" is not in the allowed list`)\n }\n\n const coll = vault.collection(collection)\n const id = toIdString(call.args.id)\n switch (op) {\n case 'list':\n return coll.list()\n case 'get':\n return coll.get(id)\n case 'count':\n return (await coll.list()).length\n case 'put':\n return coll.put(id, call.args.record as Record<string, unknown>)\n case 'delete':\n return coll.delete(id)\n }\n}\n\nfunction toIdString(value: unknown): string {\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n return ''\n}\n\n/** Round-trip helper: parse `collection_op` back to its parts. */\nexport function parseToolName(name: string): { collection: string; op: ToolOperation } | null {\n // Operation suffix — take the longest known suffix match so that\n // collection names containing underscores (e.g. `user_profiles`) are\n // still parseable.\n const ops: ToolOperation[] = ['list', 'get', 'put', 'delete', 'count']\n for (const op of ops) {\n const suffix = `_${op}`\n if (name.endsWith(suffix)) {\n const collection = name.slice(0, -suffix.length)\n if (collection.length === 0) return null\n return { collection, op }\n }\n }\n return null\n}\n\n// ─── Vault introspection (duck-typed) ──────────────────────────────────\n\n/**\n * Duck-typed probe for a vault that exposes an accessible-collections\n * API. Every hub version we target ships either `listCollectionNames`\n * or the fallback we use below (the keyring's DEK map).\n */\nfunction getAccessibleCollections(\n vault: Vault,\n allowlist: Set<string> | null,\n): string[] {\n // Preferred path — if the vault exposes an explicit enumeration API.\n const v = vault as unknown as {\n listCollectionNames?: () => string[]\n keyring?: { deks: Map<string, unknown> }\n }\n if (typeof v.listCollectionNames === 'function') {\n const names = v.listCollectionNames()\n return names.filter(n => !n.startsWith('_') && (!allowlist || allowlist.has(n)))\n }\n // Fallback — read the keyring's DEK keys, filtering system collections.\n const deks = v.keyring?.deks\n if (deks) {\n const names: string[] = []\n for (const key of deks.keys()) {\n if (key.startsWith('_')) continue\n // Tier-suffixed DEKs (`collection#N`) — strip the suffix and dedupe.\n const bare = key.includes('#') ? key.slice(0, key.indexOf('#')) : key\n if (allowlist && !allowlist.has(bare)) continue\n if (!names.includes(bare)) names.push(bare)\n }\n return names\n }\n // Last resort — return the allowlist itself (trust the caller).\n return allowlist ? [...allowlist] : []\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts DELETED
@@ -1,130 +0,0 @@
1
- import { Vault } from '@noy-db/hub';
2
-
3
- /**
4
- * **@noy-db/in-ai** — LLM function-calling adapter for noy-db.
5
- *
6
- * Exposes ACL-scoped collections as tool definitions that an LLM can
7
- * call, and dispatches incoming tool calls back to the vault. The
8
- * permission model carries through: a user whose keyring has only
9
- * `ro` on `invoices` sees only `invoices.list` / `invoices.get` —
10
- * never `invoices.put` / `invoices.delete`. The LLM physically
11
- * cannot emit a tool call the operator isn't authorised for, because
12
- * the tool doesn't exist in the model's context.
13
- *
14
- * ## Two layers
15
- *
16
- * 1. **{@link buildToolset}** — walk the vault's accessible
17
- * collections, emit a `Tool[]` array shaped for the format of
18
- * your choice (OpenAI, Anthropic, Vercel AI SDK, or the generic
19
- * JSON-Schema intermediate).
20
- *
21
- * 2. **{@link invokeToolCall}** — accept `{ name, args }` from the
22
- * LLM's response, re-check permissions, dispatch to the vault,
23
- * and return the result in a format that slots into the next
24
- * prompt round.
25
- *
26
- * ## Security boundary
27
- *
28
- * Tool calls are untrusted input. The dispatcher re-checks the
29
- * caller's permission on every invocation — even though the tool
30
- * wasn't published to the LLM, a hostile model might attempt a
31
- * fabricated call. The dispatcher throws `ToolDeniedError` rather
32
- * than silently ignoring, so the consumer can surface the attempt
33
- * to the user.
34
- *
35
- * @packageDocumentation
36
- */
37
-
38
- /** Generic JSON-Schema-based tool (matches OpenAI's `function` shape). */
39
- interface JsonSchemaTool {
40
- readonly name: string;
41
- readonly description: string;
42
- readonly parameters: {
43
- readonly type: 'object';
44
- readonly properties: Record<string, {
45
- type: string;
46
- description?: string;
47
- }>;
48
- readonly required: readonly string[];
49
- };
50
- }
51
- /** OpenAI chat.completions tool shape. */
52
- interface OpenAITool {
53
- readonly type: 'function';
54
- readonly function: JsonSchemaTool;
55
- }
56
- /** Anthropic Messages API tool shape. */
57
- interface AnthropicTool {
58
- readonly name: string;
59
- readonly description: string;
60
- readonly input_schema: JsonSchemaTool['parameters'];
61
- }
62
- /** Vercel AI SDK tool shape (generic). */
63
- interface VercelAITool {
64
- readonly description: string;
65
- readonly parameters: JsonSchemaTool['parameters'];
66
- }
67
- type ToolFormat = 'openai' | 'anthropic' | 'vercel-ai' | 'json-schema';
68
- interface ToolsetOptions {
69
- /**
70
- * Which collections to expose. Default: every collection in the
71
- * vault the caller has read access to. Pass an explicit allowlist
72
- * to narrow the surface — common in multi-tenant setups where the
73
- * LLM should only see a subset.
74
- */
75
- readonly collections?: readonly string[];
76
- /**
77
- * Which operations to expose per collection. Defaults to `['list',
78
- * 'get']` — read-only. Add `'put'` / `'delete'` explicitly when you
79
- * want the LLM to mutate. Permissions are re-checked at dispatch
80
- * time regardless.
81
- */
82
- readonly operations?: readonly ToolOperation[];
83
- /**
84
- * Output format. `'json-schema'` is the intermediate shape; the
85
- * others (`'openai'` / `'anthropic'` / `'vercel-ai'`) are the
86
- * SDK-specific wrappers.
87
- */
88
- readonly format?: ToolFormat;
89
- /**
90
- * Human-readable vault label inserted into every tool description
91
- * (e.g. `"Acme Inc."`). Helps the LLM disambiguate multi-vault
92
- * scenarios. Omit to use the raw vault name.
93
- */
94
- readonly vaultLabel?: string;
95
- }
96
- type ToolOperation = 'list' | 'get' | 'put' | 'delete' | 'count';
97
- /** Build an LLM-ready toolset from a vault. */
98
- declare function buildToolset(vault: Vault, options?: ToolsetOptions): readonly (JsonSchemaTool | OpenAITool | AnthropicTool | VercelAITool)[];
99
- declare class ToolDeniedError extends Error {
100
- readonly toolName: string;
101
- constructor(toolName: string, reason: string);
102
- }
103
- declare class ToolNotFoundError extends Error {
104
- readonly toolName: string;
105
- constructor(toolName: string);
106
- }
107
- interface ToolCall {
108
- readonly name: string;
109
- readonly args: Record<string, unknown>;
110
- }
111
- interface InvokeOptions {
112
- /** Mirror the allowlist used for `buildToolset` — enforced at dispatch. */
113
- readonly allowedOperations?: readonly ToolOperation[];
114
- readonly allowedCollections?: readonly string[];
115
- }
116
- /**
117
- * Dispatch an LLM-returned tool call against the vault. Caller is
118
- * expected to pass the same `allowedOperations` / `allowedCollections`
119
- * they used for `buildToolset`; deviations (including fabricated tool
120
- * names the LLM invented) throw `ToolNotFoundError` or
121
- * `ToolDeniedError`.
122
- */
123
- declare function invokeToolCall(vault: Vault, call: ToolCall, options?: InvokeOptions): Promise<unknown>;
124
- /** Round-trip helper: parse `collection_op` back to its parts. */
125
- declare function parseToolName(name: string): {
126
- collection: string;
127
- op: ToolOperation;
128
- } | null;
129
-
130
- export { type AnthropicTool, type InvokeOptions, type JsonSchemaTool, type OpenAITool, type ToolCall, ToolDeniedError, type ToolFormat, ToolNotFoundError, type ToolOperation, type ToolsetOptions, type VercelAITool, buildToolset, invokeToolCall, parseToolName };