@venturekit-pro/ai 0.0.48 → 0.0.50

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.
Files changed (147) hide show
  1. package/README.md +192 -0
  2. package/dist/agent-loop/index.d.ts +9 -0
  3. package/dist/agent-loop/index.d.ts.map +1 -0
  4. package/dist/agent-loop/index.js +7 -0
  5. package/dist/agent-loop/index.js.map +1 -0
  6. package/dist/agent-loop/registry.d.ts +85 -0
  7. package/dist/agent-loop/registry.d.ts.map +1 -0
  8. package/dist/agent-loop/registry.js +100 -0
  9. package/dist/agent-loop/registry.js.map +1 -0
  10. package/dist/agent-loop/run-agent.d.ts +37 -0
  11. package/dist/agent-loop/run-agent.d.ts.map +1 -0
  12. package/dist/agent-loop/run-agent.js +405 -0
  13. package/dist/agent-loop/run-agent.js.map +1 -0
  14. package/dist/agent-loop/tools.d.ts +10 -0
  15. package/dist/agent-loop/tools.d.ts.map +1 -0
  16. package/dist/agent-loop/tools.js +28 -0
  17. package/dist/agent-loop/tools.js.map +1 -0
  18. package/dist/agent-loop/types.d.ts +175 -0
  19. package/dist/agent-loop/types.d.ts.map +1 -0
  20. package/dist/agent-loop/types.js +8 -0
  21. package/dist/agent-loop/types.js.map +1 -0
  22. package/dist/chat/types.d.ts +4 -2
  23. package/dist/chat/types.d.ts.map +1 -1
  24. package/dist/cost/types.d.ts +15 -0
  25. package/dist/cost/types.d.ts.map +1 -1
  26. package/dist/cost-ledger/migrations/vk_ai_cost_0004_llm_gateway.sql +69 -0
  27. package/dist/cost-ledger/migrations/vk_ai_cost_0005_harness.sql +99 -0
  28. package/dist/cost-ledger/migrations/vk_ai_cost_0006_cache_write_prices.sql +17 -0
  29. package/dist/cost-ledger/migrations/vk_ai_cost_0007_harness_fan_out.sql +47 -0
  30. package/dist/gateway/errors.d.ts +24 -0
  31. package/dist/gateway/errors.d.ts.map +1 -0
  32. package/dist/gateway/errors.js +29 -0
  33. package/dist/gateway/errors.js.map +1 -0
  34. package/dist/gateway/gateway.d.ts +27 -0
  35. package/dist/gateway/gateway.d.ts.map +1 -0
  36. package/dist/gateway/gateway.js +503 -0
  37. package/dist/gateway/gateway.js.map +1 -0
  38. package/dist/gateway/index.d.ts +13 -0
  39. package/dist/gateway/index.d.ts.map +1 -0
  40. package/dist/gateway/index.js +10 -0
  41. package/dist/gateway/index.js.map +1 -0
  42. package/dist/gateway/policies.d.ts +32 -0
  43. package/dist/gateway/policies.d.ts.map +1 -0
  44. package/dist/gateway/policies.js +45 -0
  45. package/dist/gateway/policies.js.map +1 -0
  46. package/dist/gateway/postgres.d.ts +55 -0
  47. package/dist/gateway/postgres.d.ts.map +1 -0
  48. package/dist/gateway/postgres.js +127 -0
  49. package/dist/gateway/postgres.js.map +1 -0
  50. package/dist/gateway/pricing.d.ts +11 -0
  51. package/dist/gateway/pricing.d.ts.map +1 -0
  52. package/dist/gateway/pricing.js +47 -0
  53. package/dist/gateway/pricing.js.map +1 -0
  54. package/dist/gateway/routing.d.ts +25 -0
  55. package/dist/gateway/routing.d.ts.map +1 -0
  56. package/dist/gateway/routing.js +23 -0
  57. package/dist/gateway/routing.js.map +1 -0
  58. package/dist/gateway/types.d.ts +225 -0
  59. package/dist/gateway/types.d.ts.map +1 -0
  60. package/dist/gateway/types.js +7 -0
  61. package/dist/gateway/types.js.map +1 -0
  62. package/dist/generate/anthropic.d.ts +38 -0
  63. package/dist/generate/anthropic.d.ts.map +1 -0
  64. package/dist/generate/anthropic.js +446 -0
  65. package/dist/generate/anthropic.js.map +1 -0
  66. package/dist/generate/client.d.ts +9 -0
  67. package/dist/generate/client.d.ts.map +1 -0
  68. package/dist/generate/client.js +44 -0
  69. package/dist/generate/client.js.map +1 -0
  70. package/dist/generate/google.d.ts +39 -0
  71. package/dist/generate/google.d.ts.map +1 -0
  72. package/dist/generate/google.js +372 -0
  73. package/dist/generate/google.js.map +1 -0
  74. package/dist/generate/http.d.ts +48 -0
  75. package/dist/generate/http.d.ts.map +1 -0
  76. package/dist/generate/http.js +180 -0
  77. package/dist/generate/http.js.map +1 -0
  78. package/dist/generate/index.d.ts +13 -0
  79. package/dist/generate/index.d.ts.map +1 -0
  80. package/dist/generate/index.js +12 -0
  81. package/dist/generate/index.js.map +1 -0
  82. package/dist/generate/openai.d.ts +29 -0
  83. package/dist/generate/openai.d.ts.map +1 -0
  84. package/dist/generate/openai.js +314 -0
  85. package/dist/generate/openai.js.map +1 -0
  86. package/dist/generate/perplexity.d.ts +27 -0
  87. package/dist/generate/perplexity.d.ts.map +1 -0
  88. package/dist/generate/perplexity.js +208 -0
  89. package/dist/generate/perplexity.js.map +1 -0
  90. package/dist/generate/types.d.ts +253 -0
  91. package/dist/generate/types.d.ts.map +1 -0
  92. package/dist/generate/types.js +19 -0
  93. package/dist/generate/types.js.map +1 -0
  94. package/dist/harness/define.d.ts +15 -0
  95. package/dist/harness/define.d.ts.map +1 -0
  96. package/dist/harness/define.js +38 -0
  97. package/dist/harness/define.js.map +1 -0
  98. package/dist/harness/harness.d.ts +29 -0
  99. package/dist/harness/harness.d.ts.map +1 -0
  100. package/dist/harness/harness.js +1287 -0
  101. package/dist/harness/harness.js.map +1 -0
  102. package/dist/harness/index.d.ts +14 -0
  103. package/dist/harness/index.d.ts.map +1 -0
  104. package/dist/harness/index.js +10 -0
  105. package/dist/harness/index.js.map +1 -0
  106. package/dist/harness/memory-store.d.ts +8 -0
  107. package/dist/harness/memory-store.d.ts.map +1 -0
  108. package/dist/harness/memory-store.js +270 -0
  109. package/dist/harness/memory-store.js.map +1 -0
  110. package/dist/harness/postgres-store.d.ts +12 -0
  111. package/dist/harness/postgres-store.d.ts.map +1 -0
  112. package/dist/harness/postgres-store.js +368 -0
  113. package/dist/harness/postgres-store.js.map +1 -0
  114. package/dist/harness/scheduler.d.ts +12 -0
  115. package/dist/harness/scheduler.d.ts.map +1 -0
  116. package/dist/harness/scheduler.js +23 -0
  117. package/dist/harness/scheduler.js.map +1 -0
  118. package/dist/harness/store.d.ts +172 -0
  119. package/dist/harness/store.d.ts.map +1 -0
  120. package/dist/harness/store.js +21 -0
  121. package/dist/harness/store.js.map +1 -0
  122. package/dist/harness/types.d.ts +312 -0
  123. package/dist/harness/types.d.ts.map +1 -0
  124. package/dist/harness/types.js +11 -0
  125. package/dist/harness/types.js.map +1 -0
  126. package/dist/index.d.ts +12 -0
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +11 -0
  129. package/dist/index.js.map +1 -1
  130. package/dist/model-catalog/crud.d.ts.map +1 -1
  131. package/dist/model-catalog/crud.js +33 -2
  132. package/dist/model-catalog/crud.js.map +1 -1
  133. package/dist/model-catalog/types.d.ts +20 -0
  134. package/dist/model-catalog/types.d.ts.map +1 -1
  135. package/dist/tracing/index.d.ts +68 -0
  136. package/dist/tracing/index.d.ts.map +1 -0
  137. package/dist/tracing/index.js +72 -0
  138. package/dist/tracing/index.js.map +1 -0
  139. package/dist/tracing/recording.d.ts +23 -0
  140. package/dist/tracing/recording.d.ts.map +1 -0
  141. package/dist/tracing/recording.js +49 -0
  142. package/dist/tracing/recording.js.map +1 -0
  143. package/package.json +7 -4
  144. package/src/cost-ledger/migrations/vk_ai_cost_0004_llm_gateway.sql +69 -0
  145. package/src/cost-ledger/migrations/vk_ai_cost_0005_harness.sql +99 -0
  146. package/src/cost-ledger/migrations/vk_ai_cost_0006_cache_write_prices.sql +17 -0
  147. package/src/cost-ledger/migrations/vk_ai_cost_0007_harness_fan_out.sql +47 -0
package/README.md CHANGED
@@ -33,6 +33,11 @@ npm install @pinecone-database/pinecone
33
33
  - **Vector stores** — store and query vectors with Pinecone, pgvector, or in-memory
34
34
  - **RAG pipelines** — chunking, retrieval, and context building for retrieval-augmented generation
35
35
  - **Agents** — AI agents with tool use via OpenAI function calling
36
+ - **`generate`** — one provider-neutral model call (Anthropic, OpenAI, Gemini, Perplexity's Agent API): function tools, native web search with citations, structured output, file inputs, prompt caching, streaming (Perplexity: one-shot only)
37
+ - **LLM gateway** — the single call path: routing (tiers, fallbacks), catalog prices, policies, credentials, retries, cost ledger and audit trail
38
+ - **Agent loop** — a bounded tool-use loop on the gateway (`runAgent`)
39
+ - **Harness** — durable, versioned graphs of nodes on Postgres: retries, gates, map nodes, cancellation, budgets, events
40
+ - **Tracing** — OpenTelemetry GenAI spans through any tracer you pass
36
41
 
37
42
  ## Embeddings
38
43
 
@@ -135,6 +140,193 @@ console.log(result.output, result.usage, result.cost);
135
140
  Pair with `withFallback` / `retryWithBackoff` from the fallback module to add
136
141
  primary→backup routing or exponential-backoff retries.
137
142
 
143
+ ## LLM Gateway
144
+
145
+ Every text-model call of an app goes through one gateway, which, per call:
146
+ routes (`[model, ...fallbacks]`, or a `tier` mapped by `route`) → resolves
147
+ the catalog key (prices, max tokens, timeout) → runs the policies (a denial
148
+ skips to the next candidate; a policy that throws denies) → gets the API key
149
+ (platform or the tenant's own) → calls with retries on 429 / 5xx, then falls
150
+ back → records one ledger row per billed call and one audit row per call.
151
+
152
+ ```typescript
153
+ import { createLlmGateway, createPostgresGatewaySinks, budgetPolicy, tierRoute } from '@venturekit-pro/ai';
154
+
155
+ const gateway = createLlmGateway({
156
+ catalog: { find: (key) => catalog.get(key) }, // ModelDescriptor by catalog key
157
+ credentials: ({ context, model }) => ({ apiKey: keyFor(context.tenantId, model.provider), source: 'platform' }),
158
+ policies: [budgetPolicy({ check: async (ctx) => ({ allowed: await hasCredits(ctx.tenantId) }) })],
159
+ sinks: createPostgresGatewaySinks(query, { retentionDays: 90 }),
160
+ route: tierRoute({ resolve: ({ tier, context }) => tierKeys(context.tenantId, tier) }),
161
+ });
162
+
163
+ const answer = await gateway.generate(
164
+ { tenantId, feature: 'support-reply', correlationId: `ticket:${ticketId}` },
165
+ {
166
+ model: 'claude-sonnet', // a catalog key — or `tier: 'balanced'`
167
+ fallbacks: ['gpt-mini'],
168
+ messages: [
169
+ { role: 'system', content: KERNEL_AND_BRAND, cache: true }, // cache the stable prefix
170
+ { role: 'user', content: question },
171
+ ],
172
+ webSearch: { maxUses: 3 },
173
+ responseFormat: { type: 'json_schema', name: 'reply', schema: replySchema },
174
+ },
175
+ );
176
+ // answer.text / .json / .toolCalls / .citations / .usage / .cost / .attempts
177
+ ```
178
+
179
+ - **Streaming** — `gateway.stream(context, request)` yields `text`, `tool_call`
180
+ and `search` events, then one `done` with the priced, recorded result.
181
+ Retries and fallbacks only happen before the first event.
182
+ - **Prompt caching** — `cache: true` on a message marks the end of the stable
183
+ prefix (Anthropic `cache_control`, 5 minutes or `cache: { ttl: '1h' }`);
184
+ OpenAI and Gemini cache prefixes on their own (`cache: { key }` becomes
185
+ OpenAI's `prompt_cache_key`). Cache reads and writes come back in the usage
186
+ and are priced from the catalog (`cost_per_1k_cached_input`,
187
+ `cost_per_1k_cache_write`, `cost_per_1k_cache_write_1h`).
188
+ - `listLlmCalls(query, { correlationId })` reads the audit trail of an
189
+ operation; `purgeExpiredLlmCalls(query)` deletes rows past their retention.
190
+
191
+ ## Agent Loop
192
+
193
+ A bounded tool loop on the gateway: the model calls tools (and native web
194
+ search) until it answers or a step / tool-call / cost / time limit makes it
195
+ wrap up with one last call.
196
+
197
+ ```typescript
198
+ import { runAgent, defineAgentTool, toolResult } from '@venturekit-pro/ai';
199
+
200
+ const lookup = defineAgentTool<{ query: string }>({
201
+ definition: { name: 'lookup', description: 'Search our articles', inputSchema: { type: 'object', properties: { query: { type: 'string' } }, required: ['query'] } },
202
+ parse: (args) => ({ query: String(args.query) }),
203
+ execute: async ({ query }) => toolResult({ content: await searchArticles(query), data: { query } }),
204
+ });
205
+
206
+ const result = await runAgent({
207
+ client: gateway.client({ tenantId, feature: 'research' }),
208
+ request: { model: 'claude-sonnet', webSearch: { maxUses: 5 } },
209
+ messages: [{ role: 'user', content: 'What changed in EV charging prices this year?' }],
210
+ tools: [lookup],
211
+ limits: { maxSteps: 10, maxToolCalls: 12, timeoutMs: 5 * 60_000 },
212
+ stream: true, // emits `text.delta` events
213
+ onEvent: (event) => log(event),
214
+ });
215
+ // result.text, .stopReason ('done' | 'budget' | 'length'), .steps, .toolCalls, .usage, .cost
216
+ ```
217
+
218
+ A tool that spends itself (a model call, a paid API) reports it with
219
+ `toolResult({ content, cost, usage })`: it counts in the agent's totals and
220
+ cost limit, and is reported apart as `result.toolCost`.
221
+
222
+ ### One tool registry for agents and MCP
223
+
224
+ Define each tool once — input schema (Zod, or anything with `safeParse`),
225
+ optional output schema, a token-efficient `format`, a permission class
226
+ (`pure` · `read_tenant` · `read_untrusted` · `write_paid`; nothing that
227
+ approves, publishes or messages) — and serve it to both:
228
+
229
+ ```typescript
230
+ import { createToolRegistry, defineRegistryTool } from '@venturekit-pro/ai';
231
+ import { zodToJsonSchema, handleMcpRequest } from '@venturekit/mcp';
232
+ import { z, type ZodType } from 'zod';
233
+
234
+ const search = defineRegistryTool({
235
+ name: 'corpus.search',
236
+ description: 'Search the published articles',
237
+ permission: 'read_tenant',
238
+ input: z.object({ query: z.string() }),
239
+ format: (out: Hit[]) => out.map((h) => h.title),
240
+ run: (args, ctx: { tenantId: string }) => searchCorpus(ctx.tenantId, args.query),
241
+ });
242
+ const registry = createToolRegistry([search], {
243
+ toJsonSchema: (schema) => zodToJsonSchema(schema as ZodType),
244
+ });
245
+
246
+ registry.forAgent({ tenantId }, { permissions: ['read_tenant'] }); // AgentTool[] — names become `corpus_search`
247
+ const mcpTools = registry.forMcp<ZodType>(); // McpToolRegistry for @venturekit/mcp
248
+ ```
249
+
250
+ The tenant scope is the caller's context — the harness or the MCP server's
251
+ `createContext` — never an argument the model supplies.
252
+
253
+ ## Harness
254
+
255
+ Durable, versioned graphs. One queue message per node attempt: lease → run →
256
+ one atomic commit (output, next node, events) → schedule the next task. Gates
257
+ wait with nothing in flight; map nodes checkpoint each item; failed attempts
258
+ retry with backoff; `sweep()` re-sends lost tasks and recovers dead workers;
259
+ `cancel()` aborts a running node through `ctx.signal`.
260
+
261
+ ```typescript
262
+ import { createHarness, createPostgresHarnessStore, defineGraph, defineNode } from '@venturekit-pro/ai';
263
+
264
+ const article = defineGraph({
265
+ key: 'article.write',
266
+ version: 1,
267
+ start: 'draft',
268
+ nodes: [
269
+ defineNode({
270
+ id: 'draft',
271
+ kind: 'agent',
272
+ label: 'Writing the draft',
273
+ tier: 'best',
274
+ retry: { maxAttempts: 2 },
275
+ next: 'review',
276
+ run: async (ctx) => (await ctx.runAgent({ request: {}, messages: draftPrompt(ctx.input()) })).text,
277
+ }),
278
+ defineNode({ id: 'review', kind: 'gate', label: 'Ready for you', decisions: ['approve', 'reject'], next: ({ output }) => ((output as { decision: string }).decision === 'approve' ? 'publish' : null) }),
279
+ defineNode({ id: 'publish', kind: 'emit', label: 'Publishing', retry: { maxAttempts: 1 }, run: (ctx) => publish(ctx.require<string>('draft')) }),
280
+ ],
281
+ });
282
+
283
+ const harness = createHarness({
284
+ store: createPostgresHarnessStore(query), // migration vk_ai_cost_0005
285
+ scheduler: { enqueue: (task, opts) => queue.send(task, opts?.delayMs) }, // your queue → harness.execute(task)
286
+ graphs: [article],
287
+ gateway,
288
+ });
289
+
290
+ const run = await harness.start({ graph: 'article.write', input: { topic }, context: { tenantId } });
291
+ await harness.resume(run.id, { decision: 'approve' });
292
+ ```
293
+
294
+ In a node, `ctx.generate` / `ctx.stream` / `ctx.runAgent` go through the
295
+ gateway with the run's context, an idempotency key per attempt and the run's
296
+ spend; tool calls become `tool.called` events; `ctx.progress()` feeds live
297
+ status, and `ctx.state(s)` records the node's state with its
298
+ `detail(s)` line ("3 of 8 sources"). `harness.events(runId, { afterSeq })`
299
+ reads the timeline. `meta` carries app data with a node (artifact contracts,
300
+ tool lists); the harness ignores it.
301
+
302
+ - **Which failures retry** — `retry: { maxAttempts: 3, on: ['rate_limit', 'timeout', 'schema'] }`
303
+ (or a predicate). Categories come from `retryCategory(err)`: 429 →
304
+ `rate_limit`, 5xx → `server`, timeouts, network failures, and errors
305
+ thrown with `category: 'schema'` (an answer that broke its contract).
306
+ Fatal errors (`NodeFatalError`, policy denials, 4xx) never retry.
307
+ - **Fan-out** — a map node with `dispatch: 'tasks'` sends one queue message
308
+ per item (`{ runId, step, attempt, item }`, at most `concurrency` in
309
+ flight). Each item has its own lease, timeout, retries and checkpoint;
310
+ the join counter makes exactly one item — the last — commit the node,
311
+ with the outputs in item order and the items' spend. A failed item fails
312
+ the run; `retry()` redoes only the items not done; `sweep()` re-sends lost
313
+ item tasks and recovers dead item workers (migration `vk_ai_cost_0007`).
314
+ Items and outputs must be JSON. The default, `dispatch: 'inline'`, runs
315
+ the items inside the node attempt.
316
+
317
+ ## Tracing
318
+
319
+ Pass any OpenTelemetry tracer — `trace.getTracer('venturekit-ai')` from
320
+ `@opentelemetry/api` fits as is — as `tracer` to the gateway, `runAgent` or
321
+ the harness. `otelTracer()` returns the tracer of the SDK registered in the
322
+ process (the AWS Lambda layer that `lambda.otel` in `@venturekit/infra`
323
+ adds registers one), or `undefined`, without importing anything. Spans: `harness.node <graph>/<node>` per node attempt,
324
+ `invoke_agent <name>`, `execute_tool <tool>`, and `chat <model>` per gateway
325
+ call with the GenAI semantic-convention attributes (`gen_ai.provider.name`,
326
+ `gen_ai.usage.*` with cache reads and writes, finish reasons, time to first
327
+ chunk) plus `vk.ai.*` (cost, call id, tenant, feature, fallback).
328
+ `createRecordingTracer()` keeps spans in memory for tests.
329
+
138
330
  ## Image Generation
139
331
 
140
332
  Provider-neutral text-to-image (currently Google Imagen), returning raw image
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Agent loop — a bounded, provider-neutral tool-use loop. See `./run-agent.ts`.
3
+ */
4
+ export { runAgent, AgentRunError } from './run-agent.js';
5
+ export { defineAgentTool, toolResult, isToolResult } from './tools.js';
6
+ export { createToolRegistry, defineRegistryTool, toModelName } from './registry.js';
7
+ export type { ToolPermission, ToolSchema, ToolSchemaOutput, ToolRunContext, RegistryTool, RegistryMcpTool, ToolFilter, ToolRegistry, } from './registry.js';
8
+ export type { AgentToolContext, ToolSpend, ToolResult, AgentTool, AgentLimits, AgentLimitHit, AgentStopReason, AgentStepResult, AgentToolCallResult, AgentEvent, RunAgentOptions, AgentRunResult, } from './types.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent-loop/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACpF,YAAY,EACV,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Agent loop — a bounded, provider-neutral tool-use loop. See `./run-agent.ts`.
3
+ */
4
+ export { runAgent, AgentRunError } from './run-agent.js';
5
+ export { defineAgentTool, toolResult, isToolResult } from './tools.js';
6
+ export { createToolRegistry, defineRegistryTool, toModelName } from './registry.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent-loop/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Tool registry — one definition per tool, served to internal agents
3
+ * (`forAgent`) and to an MCP server (`forMcp`, the `@venturekit/mcp`
4
+ * `McpTool` shape).
5
+ *
6
+ * Every tool has an input schema (any schema with Zod's `safeParse` —
7
+ * Zod fits as is), an optional output schema checked before anyone sees
8
+ * the result, a token-efficient `format` for models, and a permission
9
+ * class. The tenant scope is the caller's context, bound by the harness
10
+ * or the MCP server — never an argument the model supplies.
11
+ *
12
+ * There is deliberately no class that approves, publishes, schedules,
13
+ * deletes or messages externally: those are gates or system graphs.
14
+ */
15
+ import type { AgentTool } from './types.js';
16
+ /**
17
+ * `pure` (no I/O) · `read_tenant` (the tenant's own data) ·
18
+ * `read_untrusted` (the open web — results are untrusted input) ·
19
+ * `write_paid` (creates something that costs money, e.g. an image).
20
+ */
21
+ export type ToolPermission = 'pure' | 'read_tenant' | 'read_untrusted' | 'write_paid';
22
+ /** Any schema with Zod's `safeParse`. */
23
+ export interface ToolSchema<T> {
24
+ safeParse(value: unknown): {
25
+ success: true;
26
+ data: T;
27
+ } | {
28
+ success: false;
29
+ error: {
30
+ message: string;
31
+ };
32
+ };
33
+ }
34
+ export type ToolSchemaOutput<S> = S extends ToolSchema<infer T> ? T : never;
35
+ /** What a registry tool runs with: the caller's context plus the call's signal. */
36
+ export type ToolRunContext<C> = C & {
37
+ signal: AbortSignal;
38
+ /** Who is calling: an internal agent or an MCP client. */
39
+ via: 'agent' | 'mcp';
40
+ };
41
+ export interface RegistryTool<S extends ToolSchema<any> = ToolSchema<any>, O = unknown, C = unknown> {
42
+ /** `[a-zA-Z0-9_.-]`, ≤ 64 chars. Dots become `_` for model providers (`web.read` → `web_read`). */
43
+ name: string;
44
+ description: string;
45
+ permission: ToolPermission;
46
+ input: S;
47
+ output?: ToolSchema<O>;
48
+ /** The result as models should read it (shorter, no internal ids). Default: the result. */
49
+ format?(output: O): unknown;
50
+ /** Per-call timeout for agents. Default 60 s. */
51
+ timeoutMs?: number;
52
+ run(args: ToolSchemaOutput<S>, ctx: ToolRunContext<C>): Promise<O>;
53
+ }
54
+ /** Declare a registry tool; keeps the input type from the schema to `run`. */
55
+ export declare function defineRegistryTool<S extends ToolSchema<any>, O, C>(tool: RegistryTool<S, O, C>): RegistryTool<S, O, C>;
56
+ /** The `@venturekit/mcp` `McpTool` shape (structural: no dependency on the package). */
57
+ export interface RegistryMcpTool<S, C> {
58
+ name: string;
59
+ description: string;
60
+ inputSchema: S;
61
+ run(args: unknown, ctx: C): Promise<unknown>;
62
+ }
63
+ export interface ToolFilter {
64
+ names?: string[];
65
+ permissions?: ToolPermission[];
66
+ }
67
+ export interface ToolRegistry<C> {
68
+ readonly tools: ReadonlyArray<RegistryTool<ToolSchema<any>, any, C>>;
69
+ get(name: string): RegistryTool<ToolSchema<any>, any, C> | undefined;
70
+ /** Agent tools bound to `ctx` (the tenant scope). */
71
+ forAgent(ctx: C, filter?: ToolFilter): AgentTool[];
72
+ /**
73
+ * MCP tools keyed by name; the MCP server's `createContext` supplies
74
+ * `ctx`. Name your schema type so the result fits `McpToolRegistry`:
75
+ * `registry.forMcp<ZodType>()`.
76
+ */
77
+ forMcp<S = ToolSchema<any>>(filter?: ToolFilter): Record<string, RegistryMcpTool<S, C>>;
78
+ }
79
+ export declare function createToolRegistry<C>(tools: Array<RegistryTool<any, any, C>>, options: {
80
+ /** Input schema → JSON Schema for the model (e.g. `zodToJsonSchema` from `@venturekit/mcp`). */
81
+ toJsonSchema(schema: ToolSchema<unknown>): object;
82
+ }): ToolRegistry<C>;
83
+ /** Provider tool names allow `[a-zA-Z0-9_-]` only. */
84
+ export declare function toModelName(name: string): string;
85
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/agent-loop/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,aAAa,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAStF,yCAAyC;AACzC,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,SAAS,CACP,KAAK,EAAE,OAAO,GACb;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CAChF;AAED,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE5E,mFAAmF;AACnF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,0DAA0D;IAC1D,GAAG,EAAE,OAAO,GAAG,KAAK,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,YAAY,CAC3B,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,EAC3C,CAAC,GAAG,OAAO,EACX,CAAC,GAAG,OAAO;IAEX,mGAAmG;IACnG,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,cAAc,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC;IACT,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACvB,2FAA2F;IAC3F,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC;IAC5B,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACpE;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAChE,IAAI,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAC1B,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAEvB;AAED,wFAAwF;AACxF,MAAM,WAAW,eAAe,CAAC,CAAC,EAAE,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC;IACf,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACrE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC;IACrE,qDAAqD;IACrD,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,EAAE,CAAC;IACnD;;;;OAIG;IACH,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;CACzF;AAID,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EACvC,OAAO,EAAE;IACP,gGAAgG;IAChG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;CACnD,GACA,YAAY,CAAC,CAAC,CAAC,CAmFjB;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Tool registry — one definition per tool, served to internal agents
3
+ * (`forAgent`) and to an MCP server (`forMcp`, the `@venturekit/mcp`
4
+ * `McpTool` shape).
5
+ *
6
+ * Every tool has an input schema (any schema with Zod's `safeParse` —
7
+ * Zod fits as is), an optional output schema checked before anyone sees
8
+ * the result, a token-efficient `format` for models, and a permission
9
+ * class. The tenant scope is the caller's context, bound by the harness
10
+ * or the MCP server — never an argument the model supplies.
11
+ *
12
+ * There is deliberately no class that approves, publishes, schedules,
13
+ * deletes or messages externally: those are gates or system graphs.
14
+ */
15
+ import { isToolResult, toolResult } from './tools.js';
16
+ const PERMISSIONS = [
17
+ 'pure',
18
+ 'read_tenant',
19
+ 'read_untrusted',
20
+ 'write_paid',
21
+ ];
22
+ /** Declare a registry tool; keeps the input type from the schema to `run`. */
23
+ export function defineRegistryTool(tool) {
24
+ return tool;
25
+ }
26
+ const NAME = /^[a-zA-Z0-9_.-]{1,64}$/;
27
+ export function createToolRegistry(tools, options) {
28
+ const byName = new Map();
29
+ const modelNames = new Set();
30
+ for (const tool of tools) {
31
+ if (!NAME.test(tool.name))
32
+ throw new Error(`[ai/tools] '${tool.name}' is not a valid tool name ([a-zA-Z0-9_.-], ≤ 64)`);
33
+ if (byName.has(tool.name))
34
+ throw new Error(`[ai/tools] tool '${tool.name}' is registered twice`);
35
+ if (!PERMISSIONS.includes(tool.permission))
36
+ throw new Error(`[ai/tools] tool '${tool.name}' has an unknown permission class '${String(tool.permission)}'`);
37
+ const modelName = toModelName(tool.name);
38
+ if (modelNames.has(modelName))
39
+ throw new Error(`[ai/tools] '${tool.name}' clashes with another tool as '${modelName}'`);
40
+ modelNames.add(modelName);
41
+ byName.set(tool.name, tool);
42
+ }
43
+ const select = (filter) => [...byName.values()].filter((t) => (!filter?.names || filter.names.includes(t.name)) &&
44
+ (!filter?.permissions || filter.permissions.includes(t.permission)));
45
+ const parse = (tool, args) => {
46
+ const parsed = tool.input.safeParse(args);
47
+ if (!parsed.success)
48
+ throw new Error(`Invalid arguments for ${tool.name}: ${parsed.error.message}`);
49
+ return parsed.data;
50
+ };
51
+ const finish = (tool, out) => {
52
+ const value = isToolResult(out) ? out.content : out;
53
+ if (tool.output) {
54
+ const checked = tool.output.safeParse(value);
55
+ if (!checked.success)
56
+ throw new Error(`${tool.name} returned an invalid result: ${checked.error.message}`);
57
+ }
58
+ const formatted = tool.format ? tool.format(value) : value;
59
+ return isToolResult(out) ? toolResult({ ...out, content: formatted }) : formatted;
60
+ };
61
+ return {
62
+ tools: [...byName.values()],
63
+ get: (name) => byName.get(name),
64
+ forAgent(ctx, filter) {
65
+ return select(filter).map((tool) => ({
66
+ definition: {
67
+ name: toModelName(tool.name),
68
+ description: tool.description,
69
+ inputSchema: options.toJsonSchema(tool.input),
70
+ },
71
+ parse: (args) => parse(tool, args),
72
+ ...(tool.timeoutMs !== undefined ? { timeoutMs: tool.timeoutMs } : {}),
73
+ execute: async (args, toolCtx) => finish(tool, await tool.run(args, { ...ctx, signal: toolCtx.signal, via: 'agent' })),
74
+ }));
75
+ },
76
+ forMcp(filter) {
77
+ return Object.fromEntries(select(filter).map((tool) => [
78
+ tool.name,
79
+ {
80
+ name: tool.name,
81
+ description: tool.description,
82
+ inputSchema: tool.input,
83
+ run: async (args, ctx) => {
84
+ const out = finish(tool, await tool.run(parse(tool, args), {
85
+ ...ctx,
86
+ signal: new AbortController().signal,
87
+ via: 'mcp',
88
+ }));
89
+ return isToolResult(out) ? out.content : out;
90
+ },
91
+ },
92
+ ]));
93
+ },
94
+ };
95
+ }
96
+ /** Provider tool names allow `[a-zA-Z0-9_-]` only. */
97
+ export function toModelName(name) {
98
+ return name.replace(/\./g, '_');
99
+ }
100
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/agent-loop/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * `runAgent` — a bounded tool-use loop on the gateway's `generate`.
3
+ *
4
+ * each step: model call (tools + native web search) → run the function
5
+ * tools it asked for, in order → answer them → next step
6
+ *
7
+ * Limits are soft: when steps, tool calls, cost or time run out, the
8
+ * model gets one last call without tool use and is told to answer from
9
+ * what it has (`stopReason: 'budget'`). A hard stop (cancellation, the
10
+ * wall clock passing its limit mid-call, a gateway error) throws an
11
+ * `AgentRunError` carrying the conversation and spend so far.
12
+ *
13
+ * Every step is one gateway call with a stable idempotency key
14
+ * (`<key>:s<step>`); tool errors go back to the model as error results
15
+ * instead of failing the run.
16
+ */
17
+ import type { GenerateMessage, GenerateUsage } from '../generate/types.js';
18
+ import type { AgentRunResult, RunAgentOptions } from './types.js';
19
+ type Cost = {
20
+ costUsd: number;
21
+ costMicroUsd: number;
22
+ };
23
+ /** A hard stop, with the conversation and spend so far. `name` stays `AbortError` on cancellation. */
24
+ export declare class AgentRunError extends Error {
25
+ readonly snapshot: {
26
+ messages: GenerateMessage[];
27
+ usage: GenerateUsage;
28
+ cost: Cost | null;
29
+ toolCost: Cost | null;
30
+ steps: number;
31
+ toolCalls: number;
32
+ };
33
+ constructor(message: string, cause: unknown, snapshot: AgentRunError['snapshot']);
34
+ }
35
+ export declare function runAgent(options: RunAgentOptions): Promise<AgentRunResult>;
36
+ export {};
37
+ //# sourceMappingURL=run-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-agent.d.ts","sourceRoot":"","sources":["../../src/agent-loop/run-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAGV,cAAc,EAId,eAAe,EAChB,MAAM,YAAY,CAAC;AAepB,KAAK,IAAI,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,sGAAsG;AACtG,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,EAAE,eAAe,EAAE,CAAC;QAC5B,KAAK,EAAE,aAAa,CAAC;QACrB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;QAClB,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;gBAEU,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC;CAMjF;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA8BhF"}