@contractspec/lib.ai-agent 1.46.1 → 1.47.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.
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","names":["toolSample: OperationMetricSample","stepSample: OperationMetricSample","noopTelemetryCollector: TelemetryCollector"],"sources":["../../src/telemetry/adapter.ts"],"sourcesContent":["import type { StepResult, ToolSet } from 'ai';\n\n/**\n * Metric sample compatible with @contractspec/lib.evolution OperationMetricSample.\n */\nexport interface OperationMetricSample {\n operation: { name: string; version: string };\n durationMs: number;\n success: boolean;\n timestamp: Date;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Interface for collecting telemetry metrics.\n *\n * Implementations can send metrics to:\n * - @contractspec/lib.evolution for self-improvement\n * - PostHog for analytics\n * - Custom monitoring systems\n */\nexport interface TelemetryCollector {\n /**\n * Collect a metric sample.\n */\n collect(sample: OperationMetricSample): Promise<void>;\n}\n\n/**\n * Parse agent ID into name and version.\n */\nfunction parseAgentId(agentId: string): { name: string; version: string } {\n const match = agentId.match(/^(.+)\\.v(\\s+)$/);\n if (match) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { name: match[1]!, version: match[2]! };\n }\n return { name: agentId, version: '1.0.0' };\n}\n\n/**\n * Track an agent step for telemetry.\n *\n * Called from ContractSpecAgent.onStepFinish to feed metrics\n * to the evolution engine.\n *\n * @param collector - Telemetry collector\n * @param agentId - Agent identifier (e.g., \"support.bot.v1\")\n * @param step - AI SDK step result\n * @param durationMs - Optional step duration in milliseconds\n */\nexport async function trackAgentStep(\n collector: TelemetryCollector,\n agentId: string,\n step: StepResult<ToolSet>,\n durationMs?: number\n): Promise<void> {\n const { name, version } = parseAgentId(agentId);\n\n // Track tool invocations\n for (const toolCall of step.toolCalls ?? []) {\n const toolSample: OperationMetricSample = {\n operation: { name: `${name}.${toolCall.toolName}`, version },\n durationMs: durationMs ?? 0,\n success:\n step.toolResults?.some(\n (r) => r.toolCallId === toolCall.toolCallId && r.output !== undefined\n ) ?? false,\n timestamp: new Date(),\n metadata: {\n agentId,\n toolName: toolCall.toolName,\n finishReason: step.finishReason,\n },\n };\n await collector.collect(toolSample);\n }\n\n // Track overall step\n const stepSample: OperationMetricSample = {\n operation: { name, version },\n durationMs: durationMs ?? 0,\n success: step.finishReason !== 'error',\n timestamp: new Date(),\n metadata: {\n agentId,\n finishReason: step.finishReason,\n tokenUsage: step.usage,\n toolCallCount: step.toolCalls?.length ?? 0,\n },\n };\n await collector.collect(stepSample);\n}\n\n/**\n * In-memory telemetry collector for testing.\n */\nexport class InMemoryTelemetryCollector implements TelemetryCollector {\n private readonly samples: OperationMetricSample[] = [];\n\n async collect(sample: OperationMetricSample): Promise<void> {\n this.samples.push(sample);\n }\n\n /**\n * Get all collected samples.\n */\n getSamples(): OperationMetricSample[] {\n return [...this.samples];\n }\n\n /**\n * Get samples for a specific operation.\n */\n getSamplesForOperation(operationName: string): OperationMetricSample[] {\n return this.samples.filter((s) => s.operation.name === operationName);\n }\n\n /**\n * Clear all samples.\n */\n clear(): void {\n this.samples.length = 0;\n }\n}\n\n/**\n * Create an in-memory telemetry collector.\n */\nexport function createInMemoryTelemetryCollector(): InMemoryTelemetryCollector {\n return new InMemoryTelemetryCollector();\n}\n\n/**\n * No-op telemetry collector that discards all metrics.\n */\nexport const noopTelemetryCollector: TelemetryCollector = {\n collect: async () => {\n /* noop */\n },\n};\n"],"mappings":";;;;AA+BA,SAAS,aAAa,SAAoD;CACxE,MAAM,QAAQ,QAAQ,MAAM,iBAAiB;AAC7C,KAAI,MAEF,QAAO;EAAE,MAAM,MAAM;EAAK,SAAS,MAAM;EAAK;AAEhD,QAAO;EAAE,MAAM;EAAS,SAAS;EAAS;;;;;;;;;;;;;AAc5C,eAAsB,eACpB,WACA,SACA,MACA,YACe;CACf,MAAM,EAAE,MAAM,YAAY,aAAa,QAAQ;AAG/C,MAAK,MAAM,YAAY,KAAK,aAAa,EAAE,EAAE;EAC3C,MAAMA,aAAoC;GACxC,WAAW;IAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAAY;IAAS;GAC5D,YAAY,cAAc;GAC1B,SACE,KAAK,aAAa,MACf,MAAM,EAAE,eAAe,SAAS,cAAc,EAAE,WAAW,OAC7D,IAAI;GACP,2BAAW,IAAI,MAAM;GACrB,UAAU;IACR;IACA,UAAU,SAAS;IACnB,cAAc,KAAK;IACpB;GACF;AACD,QAAM,UAAU,QAAQ,WAAW;;CAIrC,MAAMC,aAAoC;EACxC,WAAW;GAAE;GAAM;GAAS;EAC5B,YAAY,cAAc;EAC1B,SAAS,KAAK,iBAAiB;EAC/B,2BAAW,IAAI,MAAM;EACrB,UAAU;GACR;GACA,cAAc,KAAK;GACnB,YAAY,KAAK;GACjB,eAAe,KAAK,WAAW,UAAU;GAC1C;EACF;AACD,OAAM,UAAU,QAAQ,WAAW;;;;;AAMrC,IAAa,6BAAb,MAAsE;CACpE,AAAiB,UAAmC,EAAE;CAEtD,MAAM,QAAQ,QAA8C;AAC1D,OAAK,QAAQ,KAAK,OAAO;;;;;CAM3B,aAAsC;AACpC,SAAO,CAAC,GAAG,KAAK,QAAQ;;;;;CAM1B,uBAAuB,eAAgD;AACrE,SAAO,KAAK,QAAQ,QAAQ,MAAM,EAAE,UAAU,SAAS,cAAc;;;;;CAMvE,QAAc;AACZ,OAAK,QAAQ,SAAS;;;;;;AAO1B,SAAgB,mCAA+D;AAC7E,QAAO,IAAI,4BAA4B;;;;;AAMzC,MAAaC,yBAA6C,EACxD,SAAS,YAAY,IAGtB"}
1
+ {"version":3,"file":"adapter.js","names":[],"sources":["../../src/telemetry/adapter.ts"],"sourcesContent":["import type { StepResult, ToolSet } from 'ai';\n\n/**\n * Metric sample compatible with @contractspec/lib.evolution OperationMetricSample.\n */\nexport interface OperationMetricSample {\n operation: { name: string; version: string };\n durationMs: number;\n success: boolean;\n timestamp: Date;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Interface for collecting telemetry metrics.\n *\n * Implementations can send metrics to:\n * - @contractspec/lib.evolution for self-improvement\n * - PostHog for analytics\n * - Custom monitoring systems\n */\nexport interface TelemetryCollector {\n /**\n * Collect a metric sample.\n */\n collect(sample: OperationMetricSample): Promise<void>;\n}\n\n/**\n * Parse agent ID into name and version.\n */\nfunction parseAgentId(agentId: string): { name: string; version: string } {\n const match = agentId.match(/^(.+)\\.v(\\s+)$/);\n if (match) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return { name: match[1]!, version: match[2]! };\n }\n return { name: agentId, version: '1.0.0' };\n}\n\n/**\n * Track an agent step for telemetry.\n *\n * Called from ContractSpecAgent.onStepFinish to feed metrics\n * to the evolution engine.\n *\n * @param collector - Telemetry collector\n * @param agentId - Agent identifier (e.g., \"support.bot.v1\")\n * @param step - AI SDK step result\n * @param durationMs - Optional step duration in milliseconds\n */\nexport async function trackAgentStep(\n collector: TelemetryCollector,\n agentId: string,\n step: StepResult<ToolSet>,\n durationMs?: number\n): Promise<void> {\n const { name, version } = parseAgentId(agentId);\n\n // Track tool invocations\n for (const toolCall of step.toolCalls ?? []) {\n const toolSample: OperationMetricSample = {\n operation: { name: `${name}.${toolCall.toolName}`, version },\n durationMs: durationMs ?? 0,\n success:\n step.toolResults?.some(\n (r) => r.toolCallId === toolCall.toolCallId && r.output !== undefined\n ) ?? false,\n timestamp: new Date(),\n metadata: {\n agentId,\n toolName: toolCall.toolName,\n finishReason: step.finishReason,\n },\n };\n await collector.collect(toolSample);\n }\n\n // Track overall step\n const stepSample: OperationMetricSample = {\n operation: { name, version },\n durationMs: durationMs ?? 0,\n success: step.finishReason !== 'error',\n timestamp: new Date(),\n metadata: {\n agentId,\n finishReason: step.finishReason,\n tokenUsage: step.usage,\n toolCallCount: step.toolCalls?.length ?? 0,\n },\n };\n await collector.collect(stepSample);\n}\n\n/**\n * In-memory telemetry collector for testing.\n */\nexport class InMemoryTelemetryCollector implements TelemetryCollector {\n private readonly samples: OperationMetricSample[] = [];\n\n async collect(sample: OperationMetricSample): Promise<void> {\n this.samples.push(sample);\n }\n\n /**\n * Get all collected samples.\n */\n getSamples(): OperationMetricSample[] {\n return [...this.samples];\n }\n\n /**\n * Get samples for a specific operation.\n */\n getSamplesForOperation(operationName: string): OperationMetricSample[] {\n return this.samples.filter((s) => s.operation.name === operationName);\n }\n\n /**\n * Clear all samples.\n */\n clear(): void {\n this.samples.length = 0;\n }\n}\n\n/**\n * Create an in-memory telemetry collector.\n */\nexport function createInMemoryTelemetryCollector(): InMemoryTelemetryCollector {\n return new InMemoryTelemetryCollector();\n}\n\n/**\n * No-op telemetry collector that discards all metrics.\n */\nexport const noopTelemetryCollector: TelemetryCollector = {\n collect: async () => {\n /* noop */\n },\n};\n"],"mappings":";;;;AA+BA,SAAS,aAAa,SAAoD;CACxE,MAAM,QAAQ,QAAQ,MAAM,iBAAiB;AAC7C,KAAI,MAEF,QAAO;EAAE,MAAM,MAAM;EAAK,SAAS,MAAM;EAAK;AAEhD,QAAO;EAAE,MAAM;EAAS,SAAS;EAAS;;;;;;;;;;;;;AAc5C,eAAsB,eACpB,WACA,SACA,MACA,YACe;CACf,MAAM,EAAE,MAAM,YAAY,aAAa,QAAQ;AAG/C,MAAK,MAAM,YAAY,KAAK,aAAa,EAAE,EAAE;EAC3C,MAAM,aAAoC;GACxC,WAAW;IAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAAY;IAAS;GAC5D,YAAY,cAAc;GAC1B,SACE,KAAK,aAAa,MACf,MAAM,EAAE,eAAe,SAAS,cAAc,EAAE,WAAW,OAC7D,IAAI;GACP,2BAAW,IAAI,MAAM;GACrB,UAAU;IACR;IACA,UAAU,SAAS;IACnB,cAAc,KAAK;IACpB;GACF;AACD,QAAM,UAAU,QAAQ,WAAW;;CAIrC,MAAM,aAAoC;EACxC,WAAW;GAAE;GAAM;GAAS;EAC5B,YAAY,cAAc;EAC1B,SAAS,KAAK,iBAAiB;EAC/B,2BAAW,IAAI,MAAM;EACrB,UAAU;GACR;GACA,cAAc,KAAK;GACnB,YAAY,KAAK;GACjB,eAAe,KAAK,WAAW,UAAU;GAC1C;EACF;AACD,OAAM,UAAU,QAAQ,WAAW;;;;;AAMrC,IAAa,6BAAb,MAAsE;CACpE,AAAiB,UAAmC,EAAE;CAEtD,MAAM,QAAQ,QAA8C;AAC1D,OAAK,QAAQ,KAAK,OAAO;;;;;CAM3B,aAAsC;AACpC,SAAO,CAAC,GAAG,KAAK,QAAQ;;;;;CAM1B,uBAAuB,eAAgD;AACrE,SAAO,KAAK,QAAQ,QAAQ,MAAM,EAAE,UAAU,SAAS,cAAc;;;;;CAMvE,QAAc;AACZ,OAAK,QAAQ,SAAS;;;;;;AAO1B,SAAgB,mCAA+D;AAC7E,QAAO,IAAI,4BAA4B;;;;;AAMzC,MAAa,yBAA6C,EACxD,SAAS,YAAY,IAGtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"knowledge-tool.js","names":["z","allResults: { space: string; content: string; score: number }[]"],"sources":["../../src/tools/knowledge-tool.ts"],"sourcesContent":["import { tool, type Tool } from 'ai';\nimport * as z from 'zod';\nimport type { KnowledgeRetriever } from '@contractspec/lib.knowledge/retriever';\nimport type { AgentKnowledgeRef } from '../spec/spec';\n\n/**\n * Create a knowledge query tool for dynamic RAG.\n *\n * This tool allows the agent to query optional knowledge spaces\n * at runtime. Required knowledge is injected statically via\n * the knowledge injector.\n *\n * @param retriever - The knowledge retriever to use\n * @param knowledgeRefs - Knowledge references from the agent spec\n * @returns AI SDK CoreTool for knowledge queries\n */\nexport function createKnowledgeQueryTool(\n retriever: KnowledgeRetriever,\n knowledgeRefs: AgentKnowledgeRef[]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Tool<any, any> | null {\n // Only include optional (non-required) knowledge spaces\n const optionalSpaces = knowledgeRefs\n .filter((k) => !k.required)\n .map((k) => k.key)\n .filter((key) => retriever.supportsSpace(key));\n\n if (optionalSpaces.length === 0) {\n return null;\n }\n\n // Build space descriptions for the tool\n const spaceDescriptions = knowledgeRefs\n .filter((k) => !k.required && retriever.supportsSpace(k.key))\n .map((k) => `- ${k.key}: ${k.instructions ?? 'Knowledge space'}`)\n .join('\\n');\n\n return tool({\n description: `Query knowledge bases for relevant information. Use this tool when you need to look up specific information that may not be in your context.\n\nAvailable knowledge spaces:\n${spaceDescriptions}`,\n // AI SDK v6 uses inputSchema instead of parameters\n inputSchema: z.object({\n query: z\n .string()\n .describe('The question or search query to find relevant information'),\n spaceKey: z\n .enum(optionalSpaces as [string, ...string[]])\n .optional()\n .describe(\n 'Specific knowledge space to query. If omitted, searches all available spaces.'\n ),\n topK: z\n .number()\n .optional()\n .default(5)\n .describe('Maximum number of results to return'),\n }),\n execute: async ({ query, spaceKey, topK }) => {\n const spacesToSearch = spaceKey ? [spaceKey] : optionalSpaces;\n const allResults: { space: string; content: string; score: number }[] =\n [];\n\n for (const space of spacesToSearch) {\n try {\n const results = await retriever.retrieve(query, {\n spaceKey: space,\n topK: topK ?? 5,\n });\n\n for (const result of results) {\n allResults.push({\n space,\n content: result.content,\n score: result.score,\n });\n }\n } catch (error) {\n // Log but don't fail on individual space errors\n console.warn(`Failed to query knowledge space ${space}:`, error);\n }\n }\n\n if (allResults.length === 0) {\n return 'No relevant information found in the knowledge bases.';\n }\n\n // Sort by score and format results\n allResults.sort((a, b) => b.score - a.score);\n const topResults = allResults.slice(0, topK ?? 5);\n\n return topResults\n .map(\n (r, i) =>\n `[Source ${i + 1} - ${r.space}] (relevance: ${(r.score * 100).toFixed(0)}%)\\n${r.content}`\n )\n .join('\\n\\n---\\n\\n');\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,SAAgB,yBACd,WACA,eAEuB;CAEvB,MAAM,iBAAiB,cACpB,QAAQ,MAAM,CAAC,EAAE,SAAS,CAC1B,KAAK,MAAM,EAAE,IAAI,CACjB,QAAQ,QAAQ,UAAU,cAAc,IAAI,CAAC;AAEhD,KAAI,eAAe,WAAW,EAC5B,QAAO;AAST,QAAO,KAAK;EACV,aAAa;;;EANW,cACvB,QAAQ,MAAM,CAAC,EAAE,YAAY,UAAU,cAAc,EAAE,IAAI,CAAC,CAC5D,KAAK,MAAM,KAAK,EAAE,IAAI,IAAI,EAAE,gBAAgB,oBAAoB,CAChE,KAAK,KAAK;EAQX,aAAaA,IAAE,OAAO;GACpB,OAAOA,IACJ,QAAQ,CACR,SAAS,4DAA4D;GACxE,UAAUA,IACP,KAAK,eAAwC,CAC7C,UAAU,CACV,SACC,gFACD;GACH,MAAMA,IACH,QAAQ,CACR,UAAU,CACV,QAAQ,EAAE,CACV,SAAS,sCAAsC;GACnD,CAAC;EACF,SAAS,OAAO,EAAE,OAAO,UAAU,WAAW;GAC5C,MAAM,iBAAiB,WAAW,CAAC,SAAS,GAAG;GAC/C,MAAMC,aACJ,EAAE;AAEJ,QAAK,MAAM,SAAS,eAClB,KAAI;IACF,MAAM,UAAU,MAAM,UAAU,SAAS,OAAO;KAC9C,UAAU;KACV,MAAM,QAAQ;KACf,CAAC;AAEF,SAAK,MAAM,UAAU,QACnB,YAAW,KAAK;KACd;KACA,SAAS,OAAO;KAChB,OAAO,OAAO;KACf,CAAC;YAEG,OAAO;AAEd,YAAQ,KAAK,mCAAmC,MAAM,IAAI,MAAM;;AAIpE,OAAI,WAAW,WAAW,EACxB,QAAO;AAIT,cAAW,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AAG5C,UAFmB,WAAW,MAAM,GAAG,QAAQ,EAAE,CAG9C,KACE,GAAG,MACF,WAAW,IAAI,EAAE,KAAK,EAAE,MAAM,iBAAiB,EAAE,QAAQ,KAAK,QAAQ,EAAE,CAAC,MAAM,EAAE,UACpF,CACA,KAAK,cAAc;;EAEzB,CAAC"}
1
+ {"version":3,"file":"knowledge-tool.js","names":["z"],"sources":["../../src/tools/knowledge-tool.ts"],"sourcesContent":["import { tool, type Tool } from 'ai';\nimport * as z from 'zod';\nimport type { KnowledgeRetriever } from '@contractspec/lib.knowledge/retriever';\nimport type { AgentKnowledgeRef } from '../spec/spec';\n\n/**\n * Create a knowledge query tool for dynamic RAG.\n *\n * This tool allows the agent to query optional knowledge spaces\n * at runtime. Required knowledge is injected statically via\n * the knowledge injector.\n *\n * @param retriever - The knowledge retriever to use\n * @param knowledgeRefs - Knowledge references from the agent spec\n * @returns AI SDK CoreTool for knowledge queries\n */\nexport function createKnowledgeQueryTool(\n retriever: KnowledgeRetriever,\n knowledgeRefs: AgentKnowledgeRef[]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Tool<any, any> | null {\n // Only include optional (non-required) knowledge spaces\n const optionalSpaces = knowledgeRefs\n .filter((k) => !k.required)\n .map((k) => k.key)\n .filter((key) => retriever.supportsSpace(key));\n\n if (optionalSpaces.length === 0) {\n return null;\n }\n\n // Build space descriptions for the tool\n const spaceDescriptions = knowledgeRefs\n .filter((k) => !k.required && retriever.supportsSpace(k.key))\n .map((k) => `- ${k.key}: ${k.instructions ?? 'Knowledge space'}`)\n .join('\\n');\n\n return tool({\n description: `Query knowledge bases for relevant information. Use this tool when you need to look up specific information that may not be in your context.\n\nAvailable knowledge spaces:\n${spaceDescriptions}`,\n // AI SDK v6 uses inputSchema instead of parameters\n inputSchema: z.object({\n query: z\n .string()\n .describe('The question or search query to find relevant information'),\n spaceKey: z\n .enum(optionalSpaces as [string, ...string[]])\n .optional()\n .describe(\n 'Specific knowledge space to query. If omitted, searches all available spaces.'\n ),\n topK: z\n .number()\n .optional()\n .default(5)\n .describe('Maximum number of results to return'),\n }),\n execute: async ({ query, spaceKey, topK }) => {\n const spacesToSearch = spaceKey ? [spaceKey] : optionalSpaces;\n const allResults: { space: string; content: string; score: number }[] =\n [];\n\n for (const space of spacesToSearch) {\n try {\n const results = await retriever.retrieve(query, {\n spaceKey: space,\n topK: topK ?? 5,\n });\n\n for (const result of results) {\n allResults.push({\n space,\n content: result.content,\n score: result.score,\n });\n }\n } catch (error) {\n // Log but don't fail on individual space errors\n console.warn(`Failed to query knowledge space ${space}:`, error);\n }\n }\n\n if (allResults.length === 0) {\n return 'No relevant information found in the knowledge bases.';\n }\n\n // Sort by score and format results\n allResults.sort((a, b) => b.score - a.score);\n const topResults = allResults.slice(0, topK ?? 5);\n\n return topResults\n .map(\n (r, i) =>\n `[Source ${i + 1} - ${r.space}] (relevance: ${(r.score * 100).toFixed(0)}%)\\n${r.content}`\n )\n .join('\\n\\n---\\n\\n');\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,SAAgB,yBACd,WACA,eAEuB;CAEvB,MAAM,iBAAiB,cACpB,QAAQ,MAAM,CAAC,EAAE,SAAS,CAC1B,KAAK,MAAM,EAAE,IAAI,CACjB,QAAQ,QAAQ,UAAU,cAAc,IAAI,CAAC;AAEhD,KAAI,eAAe,WAAW,EAC5B,QAAO;AAST,QAAO,KAAK;EACV,aAAa;;;EANW,cACvB,QAAQ,MAAM,CAAC,EAAE,YAAY,UAAU,cAAc,EAAE,IAAI,CAAC,CAC5D,KAAK,MAAM,KAAK,EAAE,IAAI,IAAI,EAAE,gBAAgB,oBAAoB,CAChE,KAAK,KAAK;EAQX,aAAaA,IAAE,OAAO;GACpB,OAAOA,IACJ,QAAQ,CACR,SAAS,4DAA4D;GACxE,UAAUA,IACP,KAAK,eAAwC,CAC7C,UAAU,CACV,SACC,gFACD;GACH,MAAMA,IACH,QAAQ,CACR,UAAU,CACV,QAAQ,EAAE,CACV,SAAS,sCAAsC;GACnD,CAAC;EACF,SAAS,OAAO,EAAE,OAAO,UAAU,WAAW;GAC5C,MAAM,iBAAiB,WAAW,CAAC,SAAS,GAAG;GAC/C,MAAM,aACJ,EAAE;AAEJ,QAAK,MAAM,SAAS,eAClB,KAAI;IACF,MAAM,UAAU,MAAM,UAAU,SAAS,OAAO;KAC9C,UAAU;KACV,MAAM,QAAQ;KACf,CAAC;AAEF,SAAK,MAAM,UAAU,QACnB,YAAW,KAAK;KACd;KACA,SAAS,OAAO;KAChB,OAAO,OAAO;KACf,CAAC;YAEG,OAAO;AAEd,YAAQ,KAAK,mCAAmC,MAAM,IAAI,MAAM;;AAIpE,OAAI,WAAW,WAAW,EACxB,QAAO;AAIT,cAAW,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AAG5C,UAFmB,WAAW,MAAM,GAAG,QAAQ,EAAE,CAG9C,KACE,GAAG,MACF,WAAW,IAAI,EAAE,KAAK,EAAE,MAAM,iBAAiB,EAAE,QAAQ,KAAK,QAAQ,EAAE,CAAC,MAAM,EAAE,UACpF,CACA,KAAK,cAAc;;EAEzB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-client.js","names":["StdioClientTransport","combinedTools: Record<string, Tool<unknown, unknown>>"],"sources":["../../src/tools/mcp-client.ts"],"sourcesContent":["import { experimental_createMCPClient } from '@ai-sdk/mcp';\nimport { Experimental_StdioMCPTransport as StdioClientTransport } from '@ai-sdk/mcp/mcp-stdio';\nimport type { Tool } from 'ai';\n\n/**\n * Configuration for connecting to an MCP server.\n */\nexport interface McpClientConfig {\n /** Display name for the MCP server */\n name: string;\n /** Command to spawn the MCP server process */\n command: string;\n /** Arguments to pass to the command */\n args?: string[];\n /** Environment variables for the process */\n env?: Record<string, string>;\n}\n\n/**\n * Result of creating an MCP client with tools.\n */\nexport interface McpClientResult {\n /** AI SDK tools from the MCP server */\n tools: Record<string, Tool<unknown, unknown>>;\n /** Cleanup function to close the connection */\n cleanup: () => Promise<void>;\n}\n\n/**\n * Create AI SDK tools from an MCP server.\n *\n * This adapter allows ContractSpec agents to consume tools\n * from external MCP servers (e.g., filesystem, database, etc.).\n *\n * @param config - MCP server configuration\n * @returns Tools and cleanup function\n *\n * @example\n * ```typescript\n * const { tools, cleanup } = await mcpServerToTools({\n * name: 'filesystem',\n * command: 'npx',\n * args: ['-y', '@modelcontextprotocol/server-filesystem', '/path'],\n * });\n *\n * // Use tools in agent...\n *\n * await cleanup();\n * ```\n */\nexport async function mcpServerToTools(\n config: McpClientConfig\n): Promise<McpClientResult> {\n const transport = new StdioClientTransport({\n command: config.command,\n args: config.args,\n env: config.env,\n });\n\n const client = await experimental_createMCPClient({ transport });\n const tools = await client.tools();\n\n return {\n tools: tools as Record<string, Tool<unknown, unknown>>,\n cleanup: () => client.close(),\n };\n}\n\n/**\n * Create multiple MCP tool sets from configurations.\n *\n * @param configs - Array of MCP server configurations\n * @returns Combined tools and cleanup function\n */\nexport async function createMcpToolsets(\n configs: McpClientConfig[]\n): Promise<McpClientResult> {\n const results = await Promise.all(configs.map(mcpServerToTools));\n\n const combinedTools: Record<string, Tool<unknown, unknown>> = {};\n for (const result of results) {\n Object.assign(combinedTools, result.tools);\n }\n\n return {\n tools: combinedTools,\n cleanup: async () => {\n await Promise.all(results.map((r) => r.cleanup()));\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,eAAsB,iBACpB,QAC0B;CAO1B,MAAM,SAAS,MAAM,6BAA6B,EAAE,WANlC,IAAIA,+BAAqB;EACzC,SAAS,OAAO;EAChB,MAAM,OAAO;EACb,KAAK,OAAO;EACb,CAAC,EAE6D,CAAC;AAGhE,QAAO;EACL,OAHY,MAAM,OAAO,OAAO;EAIhC,eAAe,OAAO,OAAO;EAC9B;;;;;;;;AASH,eAAsB,kBACpB,SAC0B;CAC1B,MAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ,IAAI,iBAAiB,CAAC;CAEhE,MAAMC,gBAAwD,EAAE;AAChE,MAAK,MAAM,UAAU,QACnB,QAAO,OAAO,eAAe,OAAO,MAAM;AAG5C,QAAO;EACL,OAAO;EACP,SAAS,YAAY;AACnB,SAAM,QAAQ,IAAI,QAAQ,KAAK,MAAM,EAAE,SAAS,CAAC,CAAC;;EAErD"}
1
+ {"version":3,"file":"mcp-client.js","names":["StdioClientTransport"],"sources":["../../src/tools/mcp-client.ts"],"sourcesContent":["import { experimental_createMCPClient } from '@ai-sdk/mcp';\nimport { Experimental_StdioMCPTransport as StdioClientTransport } from '@ai-sdk/mcp/mcp-stdio';\nimport type { Tool } from 'ai';\n\n/**\n * Configuration for connecting to an MCP server.\n */\nexport interface McpClientConfig {\n /** Display name for the MCP server */\n name: string;\n /** Command to spawn the MCP server process */\n command: string;\n /** Arguments to pass to the command */\n args?: string[];\n /** Environment variables for the process */\n env?: Record<string, string>;\n}\n\n/**\n * Result of creating an MCP client with tools.\n */\nexport interface McpClientResult {\n /** AI SDK tools from the MCP server */\n tools: Record<string, Tool<unknown, unknown>>;\n /** Cleanup function to close the connection */\n cleanup: () => Promise<void>;\n}\n\n/**\n * Create AI SDK tools from an MCP server.\n *\n * This adapter allows ContractSpec agents to consume tools\n * from external MCP servers (e.g., filesystem, database, etc.).\n *\n * @param config - MCP server configuration\n * @returns Tools and cleanup function\n *\n * @example\n * ```typescript\n * const { tools, cleanup } = await mcpServerToTools({\n * name: 'filesystem',\n * command: 'npx',\n * args: ['-y', '@modelcontextprotocol/server-filesystem', '/path'],\n * });\n *\n * // Use tools in agent...\n *\n * await cleanup();\n * ```\n */\nexport async function mcpServerToTools(\n config: McpClientConfig\n): Promise<McpClientResult> {\n const transport = new StdioClientTransport({\n command: config.command,\n args: config.args,\n env: config.env,\n });\n\n const client = await experimental_createMCPClient({ transport });\n const tools = await client.tools();\n\n return {\n tools: tools as Record<string, Tool<unknown, unknown>>,\n cleanup: () => client.close(),\n };\n}\n\n/**\n * Create multiple MCP tool sets from configurations.\n *\n * @param configs - Array of MCP server configurations\n * @returns Combined tools and cleanup function\n */\nexport async function createMcpToolsets(\n configs: McpClientConfig[]\n): Promise<McpClientResult> {\n const results = await Promise.all(configs.map(mcpServerToTools));\n\n const combinedTools: Record<string, Tool<unknown, unknown>> = {};\n for (const result of results) {\n Object.assign(combinedTools, result.tools);\n }\n\n return {\n tools: combinedTools,\n cleanup: async () => {\n await Promise.all(results.map((r) => r.cleanup()));\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,eAAsB,iBACpB,QAC0B;CAO1B,MAAM,SAAS,MAAM,6BAA6B,EAAE,WANlC,IAAIA,+BAAqB;EACzC,SAAS,OAAO;EAChB,MAAM,OAAO;EACb,KAAK,OAAO;EACb,CAAC,EAE6D,CAAC;AAGhE,QAAO;EACL,OAHY,MAAM,OAAO,OAAO;EAIhC,eAAe,OAAO,OAAO;EAC9B;;;;;;;;AASH,eAAsB,kBACpB,SAC0B;CAC1B,MAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ,IAAI,iBAAiB,CAAC;CAEhE,MAAM,gBAAwD,EAAE;AAChE,MAAK,MAAM,UAAU,QACnB,QAAO,OAAO,eAAe,OAAO,MAAM;AAG5C,QAAO;EACL,OAAO;EACP,SAAS,YAAY;AACnB,SAAM,QAAQ,IAAI,QAAQ,KAAK,MAAM,EAAE,SAAS,CAAC,CAAC;;EAErD"}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-adapter.js","names":["tools: Record<string, Tool<any, any>>"],"sources":["../../src/tools/tool-adapter.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { tool, type Tool } from 'ai';\nimport type { AgentToolConfig } from '../spec/spec';\nimport type { ToolExecutionContext, ToolHandler } from '../types';\nimport { jsonSchemaToZodSafe } from '../schema/json-schema-to-zod';\n\n/**\n * Convert ContractSpec AgentToolConfig to AI SDK CoreTool.\n *\n * @param specTool - The tool configuration from AgentSpec\n * @param handler - The handler function for the tool\n * @param context - Partial context to inject into handler calls\n * @returns AI SDK CoreTool\n */\nexport function specToolToAISDKTool(\n specTool: AgentToolConfig,\n handler: ToolHandler,\n context: Partial<ToolExecutionContext> = {}\n): Tool<any, any> {\n return tool({\n description: specTool.description ?? specTool.name,\n // AI SDK v6 uses inputSchema instead of parameters\n inputSchema: jsonSchemaToZodSafe(specTool.schema),\n // AI SDK v6 native approval support\n needsApproval: specTool.requiresApproval ?? !specTool.automationSafe,\n execute: async (input) => {\n const result = await handler(input, {\n agentId: context.agentId ?? 'unknown',\n sessionId: context.sessionId ?? 'unknown',\n tenantId: context.tenantId,\n actorId: context.actorId,\n metadata: context.metadata,\n signal: context.signal,\n });\n return typeof result === 'string' ? result : JSON.stringify(result);\n },\n });\n}\n\n/**\n * Convert multiple ContractSpec tool configs to AI SDK tools.\n *\n * @param specTools - Array of tool configurations\n * @param handlers - Map of tool name to handler function\n * @param context - Partial context to inject into handler calls\n * @returns Record of AI SDK tools keyed by name\n */\nexport function specToolsToAISDKTools(\n specTools: AgentToolConfig[],\n handlers: Map<string, ToolHandler>,\n context: Partial<ToolExecutionContext> = {}\n): Record<string, Tool<any, any>> {\n const tools: Record<string, Tool<any, any>> = {};\n\n for (const specTool of specTools) {\n const handler = handlers.get(specTool.name);\n if (!handler) {\n throw new Error(`Missing handler for tool: ${specTool.name}`);\n }\n\n tools[specTool.name] = specToolToAISDKTool(specTool, handler, context);\n }\n\n return tools;\n}\n\n/**\n * Type-safe tool handler builder.\n *\n * @example\n * ```typescript\n * const handler = createToolHandler<{ query: string }>((input, ctx) => {\n * return `Searched for: ${input.query}`;\n * });\n * ```\n */\nexport function createToolHandler<TInput = unknown, TOutput = string>(\n handler: (\n input: TInput,\n context: ToolExecutionContext\n ) => Promise<TOutput> | TOutput\n): ToolHandler<TInput, TOutput> {\n return async (input, context) => {\n return handler(input as TInput, context);\n };\n}\n\n/**\n * Build a tool handlers map from an object.\n *\n * @example\n * ```typescript\n * const handlers = buildToolHandlers({\n * search: async (input: { query: string }) => `Found: ${input.query}`,\n * calculate: async (input: { a: number, b: number }) => `${input.a + input.b}`,\n * });\n * ```\n */\nexport function buildToolHandlers(\n handlersObj: Record<string, ToolHandler>\n): Map<string, ToolHandler> {\n return new Map(Object.entries(handlersObj));\n}\n"],"mappings":";;;;;;;;;;;;AAcA,SAAgB,oBACd,UACA,SACA,UAAyC,EAAE,EAC3B;AAChB,QAAO,KAAK;EACV,aAAa,SAAS,eAAe,SAAS;EAE9C,aAAa,oBAAoB,SAAS,OAAO;EAEjD,eAAe,SAAS,oBAAoB,CAAC,SAAS;EACtD,SAAS,OAAO,UAAU;GACxB,MAAM,SAAS,MAAM,QAAQ,OAAO;IAClC,SAAS,QAAQ,WAAW;IAC5B,WAAW,QAAQ,aAAa;IAChC,UAAU,QAAQ;IAClB,SAAS,QAAQ;IACjB,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IACjB,CAAC;AACF,UAAO,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,OAAO;;EAEtE,CAAC;;;;;;;;;;AAWJ,SAAgB,sBACd,WACA,UACA,UAAyC,EAAE,EACX;CAChC,MAAMA,QAAwC,EAAE;AAEhD,MAAK,MAAM,YAAY,WAAW;EAChC,MAAM,UAAU,SAAS,IAAI,SAAS,KAAK;AAC3C,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,6BAA6B,SAAS,OAAO;AAG/D,QAAM,SAAS,QAAQ,oBAAoB,UAAU,SAAS,QAAQ;;AAGxE,QAAO;;;;;;;;;;;;AAaT,SAAgB,kBACd,SAI8B;AAC9B,QAAO,OAAO,OAAO,YAAY;AAC/B,SAAO,QAAQ,OAAiB,QAAQ;;;;;;;;;;;;;;AAe5C,SAAgB,kBACd,aAC0B;AAC1B,QAAO,IAAI,IAAI,OAAO,QAAQ,YAAY,CAAC"}
1
+ {"version":3,"file":"tool-adapter.js","names":[],"sources":["../../src/tools/tool-adapter.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { tool, type Tool } from 'ai';\nimport type { AgentToolConfig } from '../spec/spec';\nimport type { ToolExecutionContext, ToolHandler } from '../types';\nimport { jsonSchemaToZodSafe } from '../schema/json-schema-to-zod';\n\n/**\n * Convert ContractSpec AgentToolConfig to AI SDK CoreTool.\n *\n * @param specTool - The tool configuration from AgentSpec\n * @param handler - The handler function for the tool\n * @param context - Partial context to inject into handler calls\n * @returns AI SDK CoreTool\n */\nexport function specToolToAISDKTool(\n specTool: AgentToolConfig,\n handler: ToolHandler,\n context: Partial<ToolExecutionContext> = {}\n): Tool<any, any> {\n return tool({\n description: specTool.description ?? specTool.name,\n // AI SDK v6 uses inputSchema instead of parameters\n inputSchema: jsonSchemaToZodSafe(specTool.schema),\n // AI SDK v6 native approval support\n needsApproval: specTool.requiresApproval ?? !specTool.automationSafe,\n execute: async (input) => {\n const result = await handler(input, {\n agentId: context.agentId ?? 'unknown',\n sessionId: context.sessionId ?? 'unknown',\n tenantId: context.tenantId,\n actorId: context.actorId,\n metadata: context.metadata,\n signal: context.signal,\n });\n return typeof result === 'string' ? result : JSON.stringify(result);\n },\n });\n}\n\n/**\n * Convert multiple ContractSpec tool configs to AI SDK tools.\n *\n * @param specTools - Array of tool configurations\n * @param handlers - Map of tool name to handler function\n * @param context - Partial context to inject into handler calls\n * @returns Record of AI SDK tools keyed by name\n */\nexport function specToolsToAISDKTools(\n specTools: AgentToolConfig[],\n handlers: Map<string, ToolHandler>,\n context: Partial<ToolExecutionContext> = {}\n): Record<string, Tool<any, any>> {\n const tools: Record<string, Tool<any, any>> = {};\n\n for (const specTool of specTools) {\n const handler = handlers.get(specTool.name);\n if (!handler) {\n throw new Error(`Missing handler for tool: ${specTool.name}`);\n }\n\n tools[specTool.name] = specToolToAISDKTool(specTool, handler, context);\n }\n\n return tools;\n}\n\n/**\n * Type-safe tool handler builder.\n *\n * @example\n * ```typescript\n * const handler = createToolHandler<{ query: string }>((input, ctx) => {\n * return `Searched for: ${input.query}`;\n * });\n * ```\n */\nexport function createToolHandler<TInput = unknown, TOutput = string>(\n handler: (\n input: TInput,\n context: ToolExecutionContext\n ) => Promise<TOutput> | TOutput\n): ToolHandler<TInput, TOutput> {\n return async (input, context) => {\n return handler(input as TInput, context);\n };\n}\n\n/**\n * Build a tool handlers map from an object.\n *\n * @example\n * ```typescript\n * const handlers = buildToolHandlers({\n * search: async (input: { query: string }) => `Found: ${input.query}`,\n * calculate: async (input: { a: number, b: number }) => `${input.a + input.b}`,\n * });\n * ```\n */\nexport function buildToolHandlers(\n handlersObj: Record<string, ToolHandler>\n): Map<string, ToolHandler> {\n return new Map(Object.entries(handlersObj));\n}\n"],"mappings":";;;;;;;;;;;;AAcA,SAAgB,oBACd,UACA,SACA,UAAyC,EAAE,EAC3B;AAChB,QAAO,KAAK;EACV,aAAa,SAAS,eAAe,SAAS;EAE9C,aAAa,oBAAoB,SAAS,OAAO;EAEjD,eAAe,SAAS,oBAAoB,CAAC,SAAS;EACtD,SAAS,OAAO,UAAU;GACxB,MAAM,SAAS,MAAM,QAAQ,OAAO;IAClC,SAAS,QAAQ,WAAW;IAC5B,WAAW,QAAQ,aAAa;IAChC,UAAU,QAAQ;IAClB,SAAS,QAAQ;IACjB,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IACjB,CAAC;AACF,UAAO,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,OAAO;;EAEtE,CAAC;;;;;;;;;;AAWJ,SAAgB,sBACd,WACA,UACA,UAAyC,EAAE,EACX;CAChC,MAAM,QAAwC,EAAE;AAEhD,MAAK,MAAM,YAAY,WAAW;EAChC,MAAM,UAAU,SAAS,IAAI,SAAS,KAAK;AAC3C,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,6BAA6B,SAAS,OAAO;AAG/D,QAAM,SAAS,QAAQ,oBAAoB,UAAU,SAAS,QAAQ;;AAGxE,QAAO;;;;;;;;;;;;AAaT,SAAgB,kBACd,SAI8B;AAC9B,QAAO,OAAO,OAAO,YAAY;AAC/B,SAAO,QAAQ,OAAiB,QAAQ;;;;;;;;;;;;;;AAe5C,SAAgB,kBACd,aAC0B;AAC1B,QAAO,IAAI,IAAI,OAAO,QAAQ,YAAY,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.ai-agent",
3
- "version": "1.46.1",
3
+ "version": "1.47.0",
4
4
  "description": "AI agent orchestration with MCP and tool support",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -12,8 +12,6 @@
12
12
  "typescript"
13
13
  ],
14
14
  "type": "module",
15
- "main": "./dist/index.js",
16
- "module": "./dist/index.js",
17
15
  "types": "./dist/index.d.ts",
18
16
  "files": [
19
17
  "dist",
@@ -33,17 +31,17 @@
33
31
  "test": "bun test"
34
32
  },
35
33
  "dependencies": {
36
- "ai": "6.0.3",
37
- "@ai-sdk/mcp": "1.0.1",
38
- "@ai-sdk/anthropic": "3.0.1",
39
- "@ai-sdk/google": "3.0.1",
40
- "@ai-sdk/mistral": "3.0.1",
41
- "@ai-sdk/openai": "3.0.1",
42
- "@modelcontextprotocol/sdk": "^1.24.3",
43
- "@contractspec/lib.contracts": "1.46.1",
44
- "@contractspec/lib.knowledge": "1.46.1",
34
+ "ai": "6.0.29",
35
+ "@ai-sdk/mcp": "1.0.5",
36
+ "@ai-sdk/anthropic": "3.0.11",
37
+ "@ai-sdk/google": "3.0.6",
38
+ "@ai-sdk/mistral": "3.0.5",
39
+ "@ai-sdk/openai": "3.0.8",
40
+ "@modelcontextprotocol/sdk": "^1.25.2",
41
+ "@contractspec/lib.contracts": "1.47.0",
42
+ "@contractspec/lib.knowledge": "1.47.0",
45
43
  "compare-versions": "^6.1.1",
46
- "zod": "^4.1.13"
44
+ "zod": "^4.3.5"
47
45
  },
48
46
  "peerDependencies": {
49
47
  "@anthropic-ai/claude-agent-sdk": ">=0.1.0",
@@ -58,9 +56,9 @@
58
56
  }
59
57
  },
60
58
  "devDependencies": {
61
- "@contractspec/tool.tsdown": "1.46.1",
62
- "@contractspec/tool.typescript": "1.46.1",
63
- "tsdown": "^0.18.3",
59
+ "@contractspec/tool.tsdown": "1.47.0",
60
+ "@contractspec/tool.typescript": "1.47.0",
61
+ "tsdown": "^0.19.0",
64
62
  "typescript": "^5.9.3"
65
63
  },
66
64
  "exports": {