maestro-core 0.1.0

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 (70) hide show
  1. package/README.md +55 -0
  2. package/dist/adapters/ai-sdk.d.ts +60 -0
  3. package/dist/adapters/ai-sdk.d.ts.map +1 -0
  4. package/dist/adapters/ai-sdk.js +86 -0
  5. package/dist/adapters/ai-sdk.js.map +1 -0
  6. package/dist/adapters/mcp-server.d.ts +37 -0
  7. package/dist/adapters/mcp-server.d.ts.map +1 -0
  8. package/dist/adapters/mcp-server.js +99 -0
  9. package/dist/adapters/mcp-server.js.map +1 -0
  10. package/dist/cache-control.d.ts +78 -0
  11. package/dist/cache-control.d.ts.map +1 -0
  12. package/dist/cache-control.js +57 -0
  13. package/dist/cache-control.js.map +1 -0
  14. package/dist/context.d.ts +62 -0
  15. package/dist/context.d.ts.map +1 -0
  16. package/dist/context.js +2 -0
  17. package/dist/context.js.map +1 -0
  18. package/dist/envelope.d.ts +36 -0
  19. package/dist/envelope.d.ts.map +1 -0
  20. package/dist/envelope.js +9 -0
  21. package/dist/envelope.js.map +1 -0
  22. package/dist/index.d.ts +7 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +8 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/ports/audit-store.d.ts +33 -0
  27. package/dist/ports/audit-store.d.ts.map +1 -0
  28. package/dist/ports/audit-store.js +2 -0
  29. package/dist/ports/audit-store.js.map +1 -0
  30. package/dist/ports/clock.d.ts +22 -0
  31. package/dist/ports/clock.d.ts.map +1 -0
  32. package/dist/ports/clock.js +16 -0
  33. package/dist/ports/clock.js.map +1 -0
  34. package/dist/ports/index.d.ts +9 -0
  35. package/dist/ports/index.d.ts.map +1 -0
  36. package/dist/ports/index.js +4 -0
  37. package/dist/ports/index.js.map +1 -0
  38. package/dist/ports/key-provider.d.ts +18 -0
  39. package/dist/ports/key-provider.d.ts.map +1 -0
  40. package/dist/ports/key-provider.js +2 -0
  41. package/dist/ports/key-provider.js.map +1 -0
  42. package/dist/ports/logger.d.ts +25 -0
  43. package/dist/ports/logger.d.ts.map +1 -0
  44. package/dist/ports/logger.js +22 -0
  45. package/dist/ports/logger.js.map +1 -0
  46. package/dist/ports/memory-store.d.ts +32 -0
  47. package/dist/ports/memory-store.d.ts.map +1 -0
  48. package/dist/ports/memory-store.js +2 -0
  49. package/dist/ports/memory-store.js.map +1 -0
  50. package/dist/ports/quota-store.d.ts +63 -0
  51. package/dist/ports/quota-store.d.ts.map +1 -0
  52. package/dist/ports/quota-store.js +2 -0
  53. package/dist/ports/quota-store.js.map +1 -0
  54. package/dist/ports/telemetry-sink.d.ts +71 -0
  55. package/dist/ports/telemetry-sink.d.ts.map +1 -0
  56. package/dist/ports/telemetry-sink.js +11 -0
  57. package/dist/ports/telemetry-sink.js.map +1 -0
  58. package/dist/ports/turn-store.d.ts +62 -0
  59. package/dist/ports/turn-store.d.ts.map +1 -0
  60. package/dist/ports/turn-store.js +2 -0
  61. package/dist/ports/turn-store.js.map +1 -0
  62. package/dist/safe-tool.d.ts +38 -0
  63. package/dist/safe-tool.d.ts.map +1 -0
  64. package/dist/safe-tool.js +16 -0
  65. package/dist/safe-tool.js.map +1 -0
  66. package/dist/tool.d.ts +86 -0
  67. package/dist/tool.d.ts.map +1 -0
  68. package/dist/tool.js +11 -0
  69. package/dist/tool.js.map +1 -0
  70. package/package.json +83 -0
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # maestro-core
2
+
3
+ Runtime kernel for the Maestro agent platform. In-process tool-calling runtime with port-based governance — model-agnostic, transport-agnostic, framework-agnostic kernel that powers user-support chat and tool calling for SaaS products.
4
+
5
+ `0.1.0` ships:
6
+
7
+ - `ToolEnvelope<T>` — uniform success/failure shape every tool returns
8
+ - `defineAgentTool<TInput, TOutput, TCtx>` — tool definition factory with generic context extension
9
+ - `BaseToolContext` — extensible per-request context
10
+ - 8 port interfaces: `TurnStore`, `AuditStore`, `MemoryStore`, `QuotaStore`, `ModelKeyProvider`, `TelemetrySink`, `Clock`, `Logger`
11
+ - `applyCacheBreakpoints` — Anthropic ephemeral prompt-cache helper
12
+ - `captureToolException` — observability hook for tool execute exceptions
13
+ - AI SDK adapter (`maestro-core/adapters/ai-sdk`) — wraps registry into `ToolSet` with audit + cache breakpoint
14
+ - MCP server adapter (`maestro-core/adapters/mcp-server`) — registers the same registry on an MCP server
15
+
16
+ `runChatTurn` (the full streaming orchestrator) lands in `0.2.0`.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pnpm add maestro-core zod
22
+ # optional, for the AI SDK adapter:
23
+ pnpm add ai
24
+ # optional, for the MCP server adapter:
25
+ pnpm add @modelcontextprotocol/sdk
26
+ ```
27
+
28
+ ## Quickstart
29
+
30
+ ```ts
31
+ import { ok, err, defineAgentTool, type BaseToolContext } from 'maestro-core'
32
+ import { z } from 'zod'
33
+
34
+ type MyCtx = BaseToolContext & { role: 'admin' | 'guest' }
35
+
36
+ export const lookupTool = defineAgentTool<z.ZodObject<{ id: z.ZodNumber }>, { name: string }, MyCtx>({
37
+ name: 'lookup',
38
+ description: 'Look up a record by id. Admin only.',
39
+ transports: ['chat'],
40
+ inputSchema: z.object({ id: z.number() }),
41
+ isAvailable: (ctx) => ctx.role === 'admin',
42
+ execute: async (input, ctx) => {
43
+ if (input.id === 0) return err('NOT_FOUND', 'no such record')
44
+ return ok({ name: `record-${input.id}` })
45
+ },
46
+ })
47
+ ```
48
+
49
+ ## Design
50
+
51
+ See [DESIGN.md](https://github.com/costasoftware/maestro/blob/main/DESIGN.md) for the architecture, port interfaces, and migration roadmap.
52
+
53
+ ## License
54
+
55
+ Apache-2.0
@@ -0,0 +1,60 @@
1
+ import { type ToolSet } from 'ai';
2
+ import { type CacheableBlock, type CachedMessages } from '../cache-control.js';
3
+ import type { BaseToolContext } from '../context.js';
4
+ import type { AuditStore } from '../ports/audit-store.js';
5
+ import type { Clock } from '../ports/clock.js';
6
+ import { type ToolExceptionHandler } from '../safe-tool.js';
7
+ import type { AnyAgentToolDefinition } from '../tool.js';
8
+ /**
9
+ * Translate a registry of `AgentToolDefinition`s into a Vercel AI SDK
10
+ * `ToolSet` ready to pass to `streamText` / `generateText`.
11
+ *
12
+ * Filtering happens BEFORE this call: the host runs each tool's
13
+ * `isAvailable(ctx)` + `def.transports.includes(ctx.transport)` to
14
+ * decide what to advertise; only the eligible subset reaches here.
15
+ * Keeping eligibility outside the adapter means hosts can layer their
16
+ * own gates (OAuth scopes, feature flags) on top without forking.
17
+ *
18
+ * Each tool's `execute` is wrapped in try/catch:
19
+ * 1. On success: writes an audit row (if `audit` port provided).
20
+ * 2. On envelope-error (`ok: false`): same audit row, just with the
21
+ * error code/message.
22
+ * 3. On thrown exception: audit row tagged `tool_exception`, calls
23
+ * `onError` for observability, THEN rethrows so the AI SDK marks
24
+ * the tool result as `error` and the model sees it.
25
+ *
26
+ * The last tool in iteration order receives the Anthropic ephemeral
27
+ * cacheControl marker (`applyCacheBreakpoints`). Cross-tenant cache
28
+ * reuse depends on the tool registry bytes being identical across
29
+ * tenants — keep tool descriptions tenant-invariant.
30
+ */
31
+ export interface BuildAiSdkToolsArgs<TCtx extends BaseToolContext> {
32
+ /** Registry already filtered for the active surface + actor + isAvailable. */
33
+ registry: readonly AnyAgentToolDefinition<TCtx>[];
34
+ /** Request context — passed to every `execute` call. */
35
+ ctx: TCtx;
36
+ /** Optional audit port. Calls are fire-and-forget. */
37
+ audit?: AuditStore;
38
+ /** Optional observability hook for thrown exceptions. */
39
+ onError?: ToolExceptionHandler;
40
+ /** Optional clock override (testing). */
41
+ clock?: Clock;
42
+ }
43
+ export declare function buildAiSdkTools<TCtx extends BaseToolContext>(args: BuildAiSdkToolsArgs<TCtx>): ToolSet;
44
+ /**
45
+ * Convenience wrapper: builds the ToolSet AND applies the
46
+ * static-vs-dynamic system-prompt cache breakpoint in one call.
47
+ *
48
+ * Hosts that prefer to manage cache placement themselves (e.g. an
49
+ * adapter combining a multi-segment system prompt with a third-party
50
+ * RAG corpus) should call `buildAiSdkTools` + `applyCacheBreakpoints`
51
+ * separately.
52
+ */
53
+ export declare function buildCachedAiSdkSetup<TCtx extends BaseToolContext>(args: {
54
+ build: BuildAiSdkToolsArgs<TCtx>;
55
+ cache: Omit<CacheableBlock<ToolSet>, 'static'> & {
56
+ static: Omit<CacheableBlock<ToolSet>['static'], 'tools'>;
57
+ };
58
+ }): CachedMessages<ToolSet>;
59
+ export { type ToolSet } from 'ai';
60
+ //# sourceMappingURL=ai-sdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-sdk.d.ts","sourceRoot":"","sources":["../../src/adapters/ai-sdk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,IAAI,CAAA;AAEvC,OAAO,EAAyB,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACrG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAwB,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,mBAAmB,CAAC,IAAI,SAAS,eAAe;IAC7D,8EAA8E;IAC9E,QAAQ,EAAE,SAAS,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAA;IACjD,wDAAwD;IACxD,GAAG,EAAE,IAAI,CAAA;IACT,sDAAsD;IACtD,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,yDAAyD;IACzD,OAAO,CAAC,EAAE,oBAAoB,CAAA;IAC9B,yCAAyC;IACzC,KAAK,CAAC,EAAE,KAAK,CAAA;CAChB;AAED,wBAAgB,eAAe,CAAC,IAAI,SAAS,eAAe,EACxD,IAAI,EAAE,mBAAmB,CAAC,IAAI,CAAC,GAChC,OAAO,CAoET;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,SAAS,eAAe,EAAE,IAAI,EAAE;IACtE,KAAK,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAChC,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,GAAG;QAC7C,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAA;KAC3D,CAAA;CACJ,GAAG,cAAc,CAAC,OAAO,CAAC,CAM1B;AAED,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,IAAI,CAAA"}
@@ -0,0 +1,86 @@
1
+ import { tool } from 'ai';
2
+ import { applyCacheBreakpoints } from '../cache-control.js';
3
+ import { SystemClock } from '../ports/clock.js';
4
+ import { captureToolException } from '../safe-tool.js';
5
+ export function buildAiSdkTools(args) {
6
+ const clock = args.clock ?? new SystemClock();
7
+ const rawTools = {};
8
+ for (const def of args.registry) {
9
+ rawTools[def.name] = tool({
10
+ description: def.description,
11
+ inputSchema: def.inputSchema,
12
+ execute: async (input) => {
13
+ const startedAt = clock.now();
14
+ try {
15
+ const envelope = await def.execute(input, args.ctx);
16
+ if (args.audit) {
17
+ void args.audit.recordToolCall({
18
+ toolName: def.name,
19
+ transport: args.ctx.transport,
20
+ actor: args.ctx.actor,
21
+ tenantId: args.ctx.tenantId,
22
+ principalId: args.ctx.principal?.id ?? null,
23
+ requestId: args.ctx.requestId ?? null,
24
+ input,
25
+ output: envelope.ok
26
+ ? { ok: true }
27
+ : {
28
+ ok: false,
29
+ code: envelope.error.code,
30
+ message: envelope.error.message,
31
+ },
32
+ durationMs: clock.now().getTime() - startedAt.getTime(),
33
+ createdAt: startedAt,
34
+ });
35
+ }
36
+ return envelope;
37
+ }
38
+ catch (e) {
39
+ const message = e instanceof Error ? e.message : String(e);
40
+ if (args.audit) {
41
+ void args.audit.recordToolCall({
42
+ toolName: def.name,
43
+ transport: args.ctx.transport,
44
+ actor: args.ctx.actor,
45
+ tenantId: args.ctx.tenantId,
46
+ principalId: args.ctx.principal?.id ?? null,
47
+ requestId: args.ctx.requestId ?? null,
48
+ input,
49
+ output: { ok: false, code: 'tool_exception', message },
50
+ durationMs: clock.now().getTime() - startedAt.getTime(),
51
+ createdAt: startedAt,
52
+ });
53
+ }
54
+ captureToolException(e, {
55
+ toolName: def.name,
56
+ transport: args.ctx.transport,
57
+ actor: args.ctx.actor,
58
+ tenantId: args.ctx.tenantId,
59
+ principalId: args.ctx.principal?.id ?? null,
60
+ requestId: args.ctx.requestId ?? null,
61
+ }, args.onError);
62
+ throw e;
63
+ }
64
+ },
65
+ });
66
+ }
67
+ return rawTools;
68
+ }
69
+ /**
70
+ * Convenience wrapper: builds the ToolSet AND applies the
71
+ * static-vs-dynamic system-prompt cache breakpoint in one call.
72
+ *
73
+ * Hosts that prefer to manage cache placement themselves (e.g. an
74
+ * adapter combining a multi-segment system prompt with a third-party
75
+ * RAG corpus) should call `buildAiSdkTools` + `applyCacheBreakpoints`
76
+ * separately.
77
+ */
78
+ export function buildCachedAiSdkSetup(args) {
79
+ const tools = buildAiSdkTools(args.build);
80
+ return applyCacheBreakpoints({
81
+ static: { ...args.cache.static, tools },
82
+ dynamic: args.cache.dynamic,
83
+ });
84
+ }
85
+ export {} from 'ai';
86
+ //# sourceMappingURL=ai-sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-sdk.js","sourceRoot":"","sources":["../../src/adapters/ai-sdk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { BaseToolContext } from '../context.js';
3
+ import type { AuditStore } from '../ports/audit-store.js';
4
+ import { type Clock } from '../ports/clock.js';
5
+ import type { AnyAgentToolDefinition } from '../tool.js';
6
+ /**
7
+ * Register a registry of `AgentToolDefinition`s on an MCP server
8
+ * instance. The host owns the `McpServer` lifecycle (per-request in
9
+ * stateless HTTP mode, long-lived in stdio mode) — this adapter only
10
+ * fills the tool list.
11
+ *
12
+ * Filtering (surface, actor scope, OAuth scopes, isAvailable) happens
13
+ * BEFORE this call. Same pattern as `buildAiSdkTools`.
14
+ *
15
+ * On execute:
16
+ * - Success or envelope-error → JSON-stringified envelope returned
17
+ * as `text` content. `isError` mirrors `envelope.ok === false`.
18
+ * - Thrown exception → audit + the host's `onError` hook are
19
+ * called, then a JSON `{ ok: false, error }` payload is returned
20
+ * with `isError: true`. The throw is NOT propagated (MCP SDK
21
+ * expects the handler to resolve with an error result, not
22
+ * throw — different contract from AI SDK).
23
+ */
24
+ export interface RegisterMcpToolsArgs<TCtx extends BaseToolContext> {
25
+ server: McpServer;
26
+ registry: readonly AnyAgentToolDefinition<TCtx>[];
27
+ ctx: TCtx;
28
+ audit?: AuditStore;
29
+ clock?: Clock;
30
+ /**
31
+ * Observability hook for thrown exceptions (Sentry, OTel, etc.).
32
+ * Receives the raw error and a tag bag.
33
+ */
34
+ onError?: (error: unknown, tags: Record<string, unknown>) => void;
35
+ }
36
+ export declare function registerMcpTools<TCtx extends BaseToolContext>(args: RegisterMcpToolsArgs<TCtx>): void;
37
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/adapters/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,oBAAoB,CAAC,IAAI,SAAS,eAAe;IAC9D,MAAM,EAAE,SAAS,CAAA;IACjB,QAAQ,EAAE,SAAS,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAA;IACjD,GAAG,EAAE,IAAI,CAAA;IACT,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,KAAK,CAAA;IACb;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;CACpE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,eAAe,EACzD,IAAI,EAAE,oBAAoB,CAAC,IAAI,CAAC,GACjC,IAAI,CAgFN"}
@@ -0,0 +1,99 @@
1
+ import { SystemClock } from '../ports/clock.js';
2
+ export function registerMcpTools(args) {
3
+ const clock = args.clock ?? new SystemClock();
4
+ for (const def of args.registry) {
5
+ args.server.registerTool(def.name, {
6
+ description: def.description,
7
+ inputSchema: zodToRawShape(def.inputSchema),
8
+ }, async (input) => {
9
+ const startedAt = clock.now();
10
+ try {
11
+ const envelope = await def.execute(input, args.ctx);
12
+ if (args.audit) {
13
+ void args.audit.recordToolCall({
14
+ toolName: def.name,
15
+ transport: args.ctx.transport,
16
+ actor: args.ctx.actor,
17
+ tenantId: args.ctx.tenantId,
18
+ principalId: args.ctx.principal?.id ?? null,
19
+ requestId: args.ctx.requestId ?? null,
20
+ input,
21
+ output: envelope.ok
22
+ ? { ok: true }
23
+ : {
24
+ ok: false,
25
+ code: envelope.error.code,
26
+ message: envelope.error.message,
27
+ },
28
+ durationMs: clock.now().getTime() - startedAt.getTime(),
29
+ createdAt: startedAt,
30
+ });
31
+ }
32
+ return {
33
+ content: [
34
+ { type: 'text', text: JSON.stringify(envelope, null, 2) },
35
+ ],
36
+ isError: !envelope.ok,
37
+ };
38
+ }
39
+ catch (e) {
40
+ const message = e instanceof Error ? e.message : String(e);
41
+ if (args.audit) {
42
+ void args.audit.recordToolCall({
43
+ toolName: def.name,
44
+ transport: args.ctx.transport,
45
+ actor: args.ctx.actor,
46
+ tenantId: args.ctx.tenantId,
47
+ principalId: args.ctx.principal?.id ?? null,
48
+ requestId: args.ctx.requestId ?? null,
49
+ input,
50
+ output: { ok: false, code: 'tool_exception', message },
51
+ durationMs: clock.now().getTime() - startedAt.getTime(),
52
+ createdAt: startedAt,
53
+ });
54
+ }
55
+ if (args.onError) {
56
+ try {
57
+ args.onError(e, {
58
+ toolName: def.name,
59
+ transport: args.ctx.transport,
60
+ actor: args.ctx.actor,
61
+ tenantId: args.ctx.tenantId,
62
+ principalId: args.ctx.principal?.id ?? null,
63
+ requestId: args.ctx.requestId ?? null,
64
+ });
65
+ }
66
+ catch {
67
+ // Observability must never crash the tool result.
68
+ }
69
+ }
70
+ return {
71
+ content: [
72
+ { type: 'text', text: JSON.stringify({ ok: false, error: message }) },
73
+ ],
74
+ isError: true,
75
+ };
76
+ }
77
+ });
78
+ }
79
+ }
80
+ /**
81
+ * The MCP SDK's `registerTool` wants the input schema as a raw Zod
82
+ * shape (`{ key: z.foo() }`), not the wrapped `z.object`. We crack
83
+ * open the internal `_def.shape()` getter to extract it.
84
+ *
85
+ * Unknown / non-object schemas fall through to an empty shape — the
86
+ * MCP server will accept any input for tools that don't declare one,
87
+ * matching the behaviour of barbeiro's original adapter.
88
+ */
89
+ function zodToRawShape(schema) {
90
+ const s = schema;
91
+ if (s && typeof s._def?.shape === 'function') {
92
+ return s._def.shape();
93
+ }
94
+ if (s && typeof s.shape === 'object' && s.shape !== null) {
95
+ return s.shape;
96
+ }
97
+ return {};
98
+ }
99
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/adapters/mcp-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Anthropic prompt-cache breakpoint helper.
3
+ *
4
+ * The model provider supports `cacheControl: { type: 'ephemeral' }`
5
+ * markers — content BEFORE the breakpoint is hashed into the cache key,
6
+ * content AFTER is rendered as a separate uncached segment. 5-minute TTL.
7
+ * Cold call pays cache-write (≈1.25× input rate); hot call pays
8
+ * cache-read (≈10% input rate).
9
+ *
10
+ * The TS-typed boundary between `static` and `dynamic` is the discipline.
11
+ * A developer physically can't put `business.name` into the cached block
12
+ * because the `static` slot only accepts the documented stable fields.
13
+ * Cross-tenant cache reuse is deliberate: tenant-invariant static block
14
+ * means many tenants share the same cache entry; per-tenant data lives
15
+ * in the dynamic segment that the cache key ignores.
16
+ *
17
+ * This helper deals only with the system-prompt + tools shape. The
18
+ * caller passes the result straight to `streamText` / `generateText`
19
+ * (AI SDK) as `system: [...]` and `tools: {...}`.
20
+ *
21
+ * The tools map is kept opaque (`Record<string, unknown>`) so this
22
+ * module has no `ai` dependency; the AI-SDK adapter feeds a properly
23
+ * typed `ToolSet` in, and TypeScript flows the type through.
24
+ */
25
+ export interface CacheableBlock<TTools extends Record<string, unknown>> {
26
+ /**
27
+ * Tenant-stable content — hashed for the cache key. MUST NOT
28
+ * contain user/business names or any per-tenant interpolated
29
+ * strings. Integer ids inside tool parameter descriptions are
30
+ * fine; rendered-into-prose strings are not.
31
+ */
32
+ static: {
33
+ /** Fixed introduction / persona block (surface-level instructions). */
34
+ intro: string;
35
+ /** Help corpus or business catalog static reference block. */
36
+ corpus: string;
37
+ /** Tool registry for this surface. The last tool receives the cacheControl marker. */
38
+ tools: TTools;
39
+ };
40
+ /**
41
+ * Tenant-specific content. Rendered as a separate uncached system
42
+ * segment so it never influences the cache key.
43
+ */
44
+ dynamic: {
45
+ /** Tenant id as an integer-safe shape — never interpolated into cached strings. */
46
+ tenant: {
47
+ id: string;
48
+ timezone: string;
49
+ };
50
+ principal?: {
51
+ id: string;
52
+ };
53
+ /** ISO timestamp for "now" context — varies per turn; must NOT be cached. */
54
+ nowIso: string;
55
+ };
56
+ }
57
+ export interface CachedMessages<TTools extends Record<string, unknown>> {
58
+ /**
59
+ * Two-element array:
60
+ * [0] static system message — carries the Anthropic ephemeral cacheControl marker.
61
+ * [1] dynamic system message — no marker; rendered after the breakpoint.
62
+ */
63
+ system: Array<{
64
+ role: 'system';
65
+ content: string;
66
+ providerOptions?: {
67
+ anthropic?: {
68
+ cacheControl?: {
69
+ type: 'ephemeral';
70
+ };
71
+ };
72
+ };
73
+ }>;
74
+ /** Tool registry — the last tool carries the cacheControl marker. */
75
+ tools: TTools;
76
+ }
77
+ export declare function applyCacheBreakpoints<TTools extends Record<string, unknown>>(input: CacheableBlock<TTools>): CachedMessages<TTools>;
78
+ //# sourceMappingURL=cache-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-control.d.ts","sourceRoot":"","sources":["../src/cache-control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,cAAc,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE;;;;;OAKG;IACH,MAAM,EAAE;QACJ,uEAAuE;QACvE,KAAK,EAAE,MAAM,CAAA;QACb,8DAA8D;QAC9D,MAAM,EAAE,MAAM,CAAA;QACd,sFAAsF;QACtF,KAAK,EAAE,MAAM,CAAA;KAChB,CAAA;IACD;;;OAGG;IACH,OAAO,EAAE;QACL,mFAAmF;QACnF,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAA;QACxC,SAAS,CAAC,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAA;QAC1B,6EAA6E;QAC7E,MAAM,EAAE,MAAM,CAAA;KACjB,CAAA;CACJ;AAED,MAAM,WAAW,cAAc,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE;;;;OAIG;IACH,MAAM,EAAE,KAAK,CAAC;QACV,IAAI,EAAE,QAAQ,CAAA;QACd,OAAO,EAAE,MAAM,CAAA;QACf,eAAe,CAAC,EAAE;YAAE,SAAS,CAAC,EAAE;gBAAE,YAAY,CAAC,EAAE;oBAAE,IAAI,EAAE,WAAW,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;KAC7E,CAAC,CAAA;IACF,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxE,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,GAC9B,cAAc,CAAC,MAAM,CAAC,CA4DxB"}
@@ -0,0 +1,57 @@
1
+ export function applyCacheBreakpoints(input) {
2
+ const { static: st, dynamic: dyn } = input;
3
+ // ── Static system message (cached) ──────────────────────────────────
4
+ const staticContent = st.corpus ? `${st.intro}\n\n${st.corpus}` : st.intro;
5
+ const staticMessage = {
6
+ role: 'system',
7
+ content: staticContent,
8
+ providerOptions: {
9
+ anthropic: { cacheControl: { type: 'ephemeral' } },
10
+ },
11
+ };
12
+ // ── Dynamic system message (uncached) ───────────────────────────────
13
+ const dynamicLines = [
14
+ `Tenant context: tenant_id=${dyn.tenant.id}, timezone=${dyn.tenant.timezone}`,
15
+ ];
16
+ if (dyn.principal?.id !== undefined) {
17
+ dynamicLines.push(`Principal context: principal_id=${dyn.principal.id}`);
18
+ }
19
+ dynamicLines.push(`Current time (ISO): ${dyn.nowIso}`);
20
+ const dynamicMessage = {
21
+ role: 'system',
22
+ content: dynamicLines.join('\n'),
23
+ };
24
+ // ── Tools (cached) ──────────────────────────────────────────────────
25
+ // Clone the registry to avoid mutating the caller's object. Apply the
26
+ // cacheControl marker to the last tool in iteration order. Strip any
27
+ // pre-existing providerOptions on non-last tools so a previously
28
+ // marked registry coming back through here doesn't double-mark.
29
+ const toolKeys = Object.keys(st.tools);
30
+ const markedTools = {};
31
+ for (let i = 0; i < toolKeys.length; i++) {
32
+ const key = toolKeys[i];
33
+ if (key === undefined)
34
+ continue;
35
+ const original = st.tools[key];
36
+ if (original === undefined)
37
+ continue;
38
+ const isLast = i === toolKeys.length - 1;
39
+ if (isLast) {
40
+ markedTools[key] = {
41
+ ...original,
42
+ providerOptions: {
43
+ anthropic: { cacheControl: { type: 'ephemeral' } },
44
+ },
45
+ };
46
+ }
47
+ else {
48
+ const { providerOptions: _drop, ...rest } = original;
49
+ markedTools[key] = rest;
50
+ }
51
+ }
52
+ return {
53
+ system: [staticMessage, dynamicMessage],
54
+ tools: markedTools,
55
+ };
56
+ }
57
+ //# sourceMappingURL=cache-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-control.js","sourceRoot":"","sources":["../src/cache-control.ts"],"names":[],"mappings":"AAmEA,MAAM,UAAU,qBAAqB,CACjC,KAA6B;IAE7B,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,CAAA;IAE1C,uEAAuE;IACvE,MAAM,aAAa,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAA;IAC1E,MAAM,aAAa,GAAG;QAClB,IAAI,EAAE,QAAiB;QACvB,OAAO,EAAE,aAAa;QACtB,eAAe,EAAE;YACb,SAAS,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,WAAoB,EAAE,EAAE;SAC9D;KACJ,CAAA;IAED,uEAAuE;IACvE,MAAM,YAAY,GAAa;QAC3B,6BAA6B,GAAG,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE;KAChF,CAAA;IACD,IAAI,GAAG,CAAC,SAAS,EAAE,EAAE,KAAK,SAAS,EAAE,CAAC;QAClC,YAAY,CAAC,IAAI,CAAC,mCAAmC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAA;IAC5E,CAAC;IACD,YAAY,CAAC,IAAI,CAAC,uBAAuB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;IACtD,MAAM,cAAc,GAAG;QACnB,IAAI,EAAE,QAAiB;QACvB,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;KACnC,CAAA;IAED,uEAAuE;IACvE,sEAAsE;IACtE,qEAAqE;IACrE,iEAAiE;IACjE,gEAAgE;IAChE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;IACtC,MAAM,WAAW,GAAG,EAA6B,CAAA;IAEjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;QACvB,IAAI,GAAG,KAAK,SAAS;YAAE,SAAQ;QAC/B,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC9B,IAAI,QAAQ,KAAK,SAAS;YAAE,SAAQ;QACpC,MAAM,MAAM,GAAG,CAAC,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;QAExC,IAAI,MAAM,EAAE,CAAC;YACT,WAAW,CAAC,GAAG,CAAC,GAAG;gBACf,GAAI,QAAmB;gBACvB,eAAe,EAAE;oBACb,SAAS,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,WAAoB,EAAE,EAAE;iBAC9D;aACJ,CAAA;QACL,CAAC;aAAM,CAAC;YACJ,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,QAEjB,CAAA;YAC3B,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAAA;QAC3B,CAAC;IACL,CAAC;IAED,OAAO;QACH,MAAM,EAAE,CAAC,aAAa,EAAE,cAAc,CAAC;QACvC,KAAK,EAAE,WAAqB;KAC/B,CAAA;AACL,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Per-request context handed to every tool. Built by the host product
3
+ * at the top of the chat-turn handler (route, worker, MCP request) from
4
+ * the authenticated principal + the surface invoking the tool.
5
+ *
6
+ * The base shape is intentionally minimal — everything that is universal
7
+ * to any tool-calling agent system. Hosts extend via intersection at the
8
+ * `defineAgentTool<TInput, TOutput, TCtx>` call site:
9
+ *
10
+ * ```ts
11
+ * type BarbeiroCtx = BaseToolContext & {
12
+ * businessSlug?: string
13
+ * guestPhone?: string
14
+ * role: HelpRole | null
15
+ * }
16
+ *
17
+ * defineAgentTool<Input, Output, BarbeiroCtx>({ ... })
18
+ * ```
19
+ *
20
+ * Per-tool generic param (not TS module augmentation) is the chosen
21
+ * extension mechanism — keeps the augmentation scoped to one tool
22
+ * instead of polluting a shared global interface, so siblings in a
23
+ * future monorepo can't trip over each other's context shapes.
24
+ */
25
+ export interface BaseToolContext {
26
+ /**
27
+ * Opaque tenant scope. The host product owns the meaning
28
+ * (`businessId.toString()`, workspace UUID, org slug, etc.) — kernel
29
+ * never parses it. Used for audit attribution, quota keys, memory
30
+ * scoping, and telemetry tagging.
31
+ */
32
+ tenantId: string;
33
+ /**
34
+ * Authenticated principal, or null for anonymous transports
35
+ * (public widget, voice). `id` is opaque; `kind` is a host-defined
36
+ * string that disambiguates principal populations
37
+ * (`'user'`, `'guest'`, `'service-account'`, `'mcp-client'`, ...).
38
+ */
39
+ principal: {
40
+ id: string;
41
+ kind: string;
42
+ } | null;
43
+ /**
44
+ * Who authorised the call. Logged for governance + abuse detection.
45
+ * String-typed; the host owns the enum.
46
+ */
47
+ actor: string;
48
+ /**
49
+ * Which surface invoked the call (`'chat'`, `'guest-chat'`,
50
+ * `'whatsapp'`, `'mcp'`, ...). Adapters filter the registry by
51
+ * `def.transports.includes(transport)`. String-typed; the host owns
52
+ * the vocabulary.
53
+ */
54
+ transport: string;
55
+ /** IETF BCP-47 locale tag, e.g. `'pt-BR'`. */
56
+ locale: string;
57
+ /** IANA timezone, e.g. `'America/Sao_Paulo'`. */
58
+ timezone: string;
59
+ /** Trace id for cross-system correlation (matches HTTP `x-request-id`). */
60
+ requestId: string;
61
+ }
62
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,eAAe;IAC5B;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAA;IAEhB;;;;;OAKG;IACH,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAE9C;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IAEb;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAA;IAEjB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAA;IAEd,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAA;IAEhB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;CACpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Uniform return shape for every Maestro tool. Wrapping success and failure
3
+ * in the same envelope lets the model recover gracefully ("sorry, that slot
4
+ * was just taken") instead of crashing the whole turn, and lets every adapter
5
+ * (AI SDK, MCP, transports added later) render the result with the same code
6
+ * path.
7
+ */
8
+ export interface ToolMeta {
9
+ /**
10
+ * Set when the host UI already renders a rich card for this tool result.
11
+ * Chat transports with a UI surface read this and tell the model to skip
12
+ * restating the data — preventing the duplicate "card + paragraph saying
13
+ * the same thing" bubble. Advisory only on transports without UI cards
14
+ * (whatsapp, mcp, voice) — those still get the full LLM restatement.
15
+ */
16
+ uiRendered?: string;
17
+ }
18
+ export type ToolEnvelope<T> = {
19
+ ok: true;
20
+ data: T;
21
+ meta?: ToolMeta;
22
+ } | {
23
+ ok: false;
24
+ error: {
25
+ code: string;
26
+ message: string;
27
+ };
28
+ };
29
+ export declare const ok: <T>(data: T, meta?: ToolMeta) => ToolEnvelope<T>;
30
+ export declare const err: (code: string, message: string) => ToolEnvelope<never>;
31
+ export declare function isOk<T>(envelope: ToolEnvelope<T>): envelope is {
32
+ ok: true;
33
+ data: T;
34
+ meta?: ToolMeta;
35
+ };
36
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACrB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,IACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAA;AAE7D,eAAO,MAAM,EAAE,GAAI,CAAC,EAAE,MAAM,CAAC,EAAE,OAAO,QAAQ,KAAG,YAAY,CAAC,CAAC,CACP,CAAA;AAExD,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,YAAY,CAAC,KAAK,CAGpE,CAAA;AAEF,wBAAgB,IAAI,CAAC,CAAC,EAClB,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAC1B,QAAQ,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;CAAE,CAEpD"}
@@ -0,0 +1,9 @@
1
+ export const ok = (data, meta) => meta ? { ok: true, data, meta } : { ok: true, data };
2
+ export const err = (code, message) => ({
3
+ ok: false,
4
+ error: { code, message },
5
+ });
6
+ export function isOk(envelope) {
7
+ return envelope.ok === true;
8
+ }
9
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAsBA,MAAM,CAAC,MAAM,EAAE,GAAG,CAAI,IAAO,EAAE,IAAe,EAAmB,EAAE,CAC/D,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AAExD,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,OAAe,EAAuB,EAAE,CAAC,CAAC;IACxE,EAAE,EAAE,KAAK;IACT,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;CAC3B,CAAC,CAAA;AAEF,MAAM,UAAU,IAAI,CAChB,QAAyB;IAEzB,OAAO,QAAQ,CAAC,EAAE,KAAK,IAAI,CAAA;AAC/B,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type { BaseToolContext } from './context.js';
2
+ export { err, isOk, ok, type ToolEnvelope, type ToolMeta } from './envelope.js';
3
+ export { type AgentToolDefinition, type AnyAgentToolDefinition, defineAgentTool, type ToolCostBand, type ToolKind, } from './tool.js';
4
+ export { applyCacheBreakpoints, type CacheableBlock, type CachedMessages, } from './cache-control.js';
5
+ export { captureToolException, type ToolExceptionHandler, type ToolExceptionTags, } from './safe-tool.js';
6
+ export * from './ports/index.js';
7
+ //# sourceMappingURL=index.d.ts.map