@happyvertical/smrt-core 0.36.6 → 0.36.8

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 (47) hide show
  1. package/dist/generators/cli.d.ts +4 -22
  2. package/dist/generators/cli.d.ts.map +1 -1
  3. package/dist/generators/cli.js +9 -5
  4. package/dist/generators/cli.js.map +1 -1
  5. package/dist/generators/mcp-runtime-template.d.ts +1 -1
  6. package/dist/generators/mcp-runtime-template.d.ts.map +1 -1
  7. package/dist/generators/mcp-runtime-template.js.map +1 -1
  8. package/dist/generators/mcp.d.ts +16 -4
  9. package/dist/generators/mcp.d.ts.map +1 -1
  10. package/dist/generators/mcp.js +25 -9
  11. package/dist/generators/mcp.js.map +1 -1
  12. package/dist/generators/rest.d.ts +6 -5
  13. package/dist/generators/rest.d.ts.map +1 -1
  14. package/dist/generators/rest.js +8 -5
  15. package/dist/generators/rest.js.map +1 -1
  16. package/dist/generators/swagger.d.ts +12 -2
  17. package/dist/generators/swagger.d.ts.map +1 -1
  18. package/dist/generators/swagger.js +6 -3
  19. package/dist/generators/swagger.js.map +1 -1
  20. package/dist/manifest/static-manifest.js +2 -2
  21. package/dist/manifest/static-manifest.js.map +1 -1
  22. package/dist/manifest/store.js +2 -2
  23. package/dist/manifest/test-manifest-stub.js +2 -2
  24. package/dist/manifest/test-manifest-stub.js.map +1 -1
  25. package/dist/manifest.json +2 -2
  26. package/dist/runtime/client.d.ts +6 -6
  27. package/dist/runtime/client.d.ts.map +1 -1
  28. package/dist/runtime/client.js.map +1 -1
  29. package/dist/runtime/mcp.d.ts +11 -4
  30. package/dist/runtime/mcp.d.ts.map +1 -1
  31. package/dist/runtime/mcp.js.map +1 -1
  32. package/dist/runtime/server.d.ts +29 -5
  33. package/dist/runtime/server.d.ts.map +1 -1
  34. package/dist/runtime/server.js +4 -4
  35. package/dist/runtime/server.js.map +1 -1
  36. package/dist/runtime/types.d.ts +12 -12
  37. package/dist/runtime/types.d.ts.map +1 -1
  38. package/dist/smrt-knowledge.json +4 -4
  39. package/dist/tools/tool-executor.d.ts +19 -5
  40. package/dist/tools/tool-executor.d.ts.map +1 -1
  41. package/dist/tools/tool-executor.js +4 -2
  42. package/dist/tools/tool-executor.js.map +1 -1
  43. package/dist/tools/tool-generator.d.ts +8 -1
  44. package/dist/tools/tool-generator.d.ts.map +1 -1
  45. package/dist/tools/tool-generator.js +10 -11
  46. package/dist/tools/tool-generator.js.map +1 -1
  47. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"tool-executor.js","sources":["../../src/tools/tool-executor.ts"],"sourcesContent":["/**\n * Tool Call Execution for AI Function Calling\n *\n * This module handles runtime execution of AI tool calls on SMRT object instances.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport type { Signal } from '@happyvertical/smrt-types';\nimport { RuntimeError, ValidationError } from '../errors.js';\nimport type { SignalBus } from '../signals/bus.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Tool call structure from AI response\n */\nexport interface ToolCall {\n /**\n * Unique identifier for this tool call\n */\n id: string;\n\n /**\n * Type of tool (always 'function' for now)\n */\n type: 'function';\n\n /**\n * Function details\n */\n function: {\n /**\n * Name of the method to call\n */\n name: string;\n\n /**\n * JSON string of arguments to pass to the method\n */\n arguments: string;\n };\n}\n\n/**\n * Result of executing a tool call\n */\nexport interface ToolCallResult {\n /**\n * Tool call ID for correlation\n */\n id: string;\n\n /**\n * Method name that was called\n */\n methodName: string;\n\n /**\n * Parsed arguments that were used\n */\n arguments: Record<string, any>;\n\n /**\n * Result returned from the method\n */\n result: any;\n\n /**\n * Whether the call succeeded\n */\n success: boolean;\n\n /**\n * Error message if call failed\n */\n error?: string;\n\n /**\n * Execution time in milliseconds\n */\n duration?: number;\n}\n\n/**\n * Validates tool call arguments against method parameters\n *\n * @param methodName - Name of the method being called\n * @param args - Parsed arguments from tool call\n * @param allowedMethods - List of methods AI is allowed to call\n * @throws ValidationError if method not allowed or arguments invalid\n */\nexport function validateToolCall(\n methodName: string,\n args: Record<string, any>,\n allowedMethods: string[],\n): void {\n // Check if method is allowed\n if (!allowedMethods.includes(methodName)) {\n throw ValidationError.invalidValue(\n 'methodName',\n methodName,\n `Method must be one of: ${allowedMethods.join(', ')}`,\n );\n }\n\n // Basic argument validation (could be enhanced)\n if (typeof args !== 'object' || args === null) {\n throw ValidationError.invalidValue(\n 'arguments',\n args,\n 'Arguments must be a valid object',\n );\n }\n}\n\n/**\n * Executes a tool call on an object instance\n *\n * @param instance - Object instance to call method on\n * @param toolCall - Tool call from AI\n * @param allowedMethods - List of methods AI is allowed to call\n * @param signalBus - Optional signal bus for emitting execution events\n * @returns Result of the tool call execution\n */\nexport async function executeToolCall(\n instance: any,\n toolCall: ToolCall,\n allowedMethods: string[],\n signalBus?: SignalBus,\n): Promise<ToolCallResult> {\n const startTime = Date.now();\n const methodName = toolCall.function.name;\n const executionId = signalBus?.generateExecutionId() ?? toolCall.id;\n\n // Declare args outside try blocks so it's accessible in catch block\n let args: Record<string, any> | undefined;\n\n try {\n // Parse arguments\n try {\n args = JSON.parse(toolCall.function.arguments);\n } catch (_parseError) {\n throw ValidationError.invalidValue(\n 'arguments',\n toolCall.function.arguments,\n 'Arguments must be valid JSON',\n );\n }\n\n // Type guard - args is always defined after successful parsing\n if (!args) {\n throw ValidationError.invalidValue(\n 'arguments',\n toolCall.function.arguments,\n 'Arguments must be a valid object',\n );\n }\n\n // Validate tool call\n validateToolCall(methodName, args, allowedMethods);\n\n // Check method exists\n if (typeof instance[methodName] !== 'function') {\n throw RuntimeError.operationFailed(\n `Method '${methodName}' not found on object`,\n );\n }\n\n // Emit start signal\n if (signalBus) {\n const startSignal: Signal = {\n id: executionId,\n objectId: instance.id ?? 'unknown',\n className: instance.constructor?.name ?? 'Unknown',\n method: methodName,\n type: 'start',\n args: [args], // Wrap in array for consistency\n timestamp: new Date(),\n };\n await signalBus.emit(startSignal);\n }\n\n // Execute method\n const result = await instance[methodName](args);\n\n // Emit end signal\n if (signalBus) {\n const endSignal: Signal = {\n id: executionId,\n objectId: instance.id ?? 'unknown',\n className: instance.constructor?.name ?? 'Unknown',\n method: methodName,\n type: 'end',\n args: [args],\n result,\n duration: Date.now() - startTime,\n timestamp: new Date(),\n };\n await signalBus.emit(endSignal);\n }\n\n return {\n id: toolCall.id,\n methodName,\n arguments: args,\n result,\n success: true,\n duration: Date.now() - startTime,\n };\n } catch (error) {\n // Emit error signal\n if (signalBus) {\n const errorSignal: Signal = {\n id: executionId,\n objectId: instance.id ?? 'unknown',\n className: instance.constructor?.name ?? 'Unknown',\n method: methodName,\n type: 'error',\n // Preserve actual args if parsed, otherwise include raw arguments for debugging\n args: [\n typeof args !== 'undefined' ? args : toolCall.function.arguments,\n ],\n error: error instanceof Error ? error : new Error(String(error)),\n duration: Date.now() - startTime,\n timestamp: new Date(),\n };\n await signalBus.emit(errorSignal);\n }\n\n return {\n id: toolCall.id,\n methodName,\n arguments: {},\n result: null,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\n };\n }\n}\n\n/**\n * Executes multiple tool calls in sequence\n *\n * @param instance - Object instance to call methods on\n * @param toolCalls - Array of tool calls from AI\n * @param allowedMethods - List of methods AI is allowed to call\n * @param signalBus - Optional signal bus for emitting execution events\n * @returns Array of tool call results\n */\nexport async function executeToolCalls(\n instance: any,\n toolCalls: ToolCall[],\n allowedMethods: string[],\n signalBus?: SignalBus,\n): Promise<ToolCallResult[]> {\n const results: ToolCallResult[] = [];\n\n for (const toolCall of toolCalls) {\n const result = await executeToolCall(\n instance,\n toolCall,\n allowedMethods,\n signalBus,\n );\n results.push(result);\n\n // Stop on first error if needed\n if (!result.success) {\n logger.warn(`Tool call failed for ${result.methodName}: ${result.error}`);\n // Continue executing other tools (don't break)\n }\n }\n\n return results;\n}\n\n/**\n * Formats tool call results into messages for AI\n *\n * @param results - Tool call execution results\n * @returns Array of tool response messages\n */\nexport function formatToolResults(\n results: ToolCallResult[],\n): Array<{ role: 'tool'; tool_call_id: string; content: string }> {\n return results.map((result) => ({\n role: 'tool' as const,\n tool_call_id: result.id,\n content: result.success\n ? JSON.stringify(result.result)\n : `Error: ${result.error}`,\n }));\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-executor.js","sources":["../../src/tools/tool-executor.ts"],"sourcesContent":["/**\n * Tool Call Execution for AI Function Calling\n *\n * This module handles runtime execution of AI tool calls on SMRT object instances.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport type { Signal } from '@happyvertical/smrt-types';\nimport { RuntimeError, ValidationError } from '../errors.js';\nimport type { SignalBus } from '../signals/bus.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * A dynamically-dispatched tool target (typically a SmrtObject instance, but\n * typed structurally so any object whose method names are resolved at runtime\n * from the AI tool call is accepted). No index signature is declared so plain\n * class instances like `SmrtObject` remain assignable; dynamic method lookup\n * goes through a `Record<string, unknown>` cast at the call boundary.\n */\ninterface ToolCallTarget {\n id?: string | null;\n constructor?: { name?: string };\n}\n\n/**\n * A callable resolved from a {@link ToolCallTarget} by method name. The method\n * is actually invoked with the parsed (untyped JSON) tool-call arguments, so\n * the parameter list is `unknown[]` rather than `never[]`.\n */\ntype InstanceMethod = (...args: unknown[]) => unknown;\n\n/**\n * Tool call structure from AI response\n */\nexport interface ToolCall {\n /**\n * Unique identifier for this tool call\n */\n id: string;\n\n /**\n * Type of tool (always 'function' for now)\n */\n type: 'function';\n\n /**\n * Function details\n */\n function: {\n /**\n * Name of the method to call\n */\n name: string;\n\n /**\n * JSON string of arguments to pass to the method\n */\n arguments: string;\n };\n}\n\n/**\n * Result of executing a tool call\n */\nexport interface ToolCallResult {\n /**\n * Tool call ID for correlation\n */\n id: string;\n\n /**\n * Method name that was called\n */\n methodName: string;\n\n /**\n * Parsed arguments that were used\n */\n arguments: Record<string, unknown>;\n\n /**\n * Result returned from the method\n */\n result: unknown;\n\n /**\n * Whether the call succeeded\n */\n success: boolean;\n\n /**\n * Error message if call failed\n */\n error?: string;\n\n /**\n * Execution time in milliseconds\n */\n duration?: number;\n}\n\n/**\n * Validates tool call arguments against method parameters\n *\n * @param methodName - Name of the method being called\n * @param args - Parsed arguments from tool call\n * @param allowedMethods - List of methods AI is allowed to call\n * @throws ValidationError if method not allowed or arguments invalid\n */\nexport function validateToolCall(\n methodName: string,\n args: Record<string, unknown>,\n allowedMethods: string[],\n): void {\n // Check if method is allowed\n if (!allowedMethods.includes(methodName)) {\n throw ValidationError.invalidValue(\n 'methodName',\n methodName,\n `Method must be one of: ${allowedMethods.join(', ')}`,\n );\n }\n\n // Basic argument validation (could be enhanced)\n if (typeof args !== 'object' || args === null) {\n throw ValidationError.invalidValue(\n 'arguments',\n args,\n 'Arguments must be a valid object',\n );\n }\n}\n\n/**\n * Executes a tool call on an object instance\n *\n * @param instance - Object instance to call method on\n * @param toolCall - Tool call from AI\n * @param allowedMethods - List of methods AI is allowed to call\n * @param signalBus - Optional signal bus for emitting execution events\n * @returns Result of the tool call execution\n */\nexport async function executeToolCall(\n instance: ToolCallTarget,\n toolCall: ToolCall,\n allowedMethods: string[],\n signalBus?: SignalBus,\n): Promise<ToolCallResult> {\n const startTime = Date.now();\n const methodName = toolCall.function.name;\n const executionId = signalBus?.generateExecutionId() ?? toolCall.id;\n\n // Declare args outside try blocks so it's accessible in catch block\n let args: Record<string, unknown> | undefined;\n\n try {\n // Parse arguments\n try {\n args = JSON.parse(toolCall.function.arguments);\n } catch (_parseError) {\n throw ValidationError.invalidValue(\n 'arguments',\n toolCall.function.arguments,\n 'Arguments must be valid JSON',\n );\n }\n\n // Type guard - args is always defined after successful parsing\n if (!args) {\n throw ValidationError.invalidValue(\n 'arguments',\n toolCall.function.arguments,\n 'Arguments must be a valid object',\n );\n }\n\n // Validate tool call\n validateToolCall(methodName, args, allowedMethods);\n\n // Check method exists. The target is dynamically dispatched, so the method\n // is resolved by string index (cast to a record) and the result is\n // `unknown`; narrow it to a callable at this boundary after the runtime\n // `typeof === 'function'` guard.\n const method = (instance as Record<string, unknown>)[methodName];\n if (typeof method !== 'function') {\n throw RuntimeError.operationFailed(\n `Method '${methodName}' not found on object`,\n );\n }\n const invokeMethod = method as InstanceMethod;\n\n // Emit start signal\n if (signalBus) {\n const startSignal: Signal = {\n id: executionId,\n objectId: instance.id ?? 'unknown',\n className: instance.constructor?.name ?? 'Unknown',\n method: methodName,\n type: 'start',\n args: [args], // Wrap in array for consistency\n timestamp: new Date(),\n };\n await signalBus.emit(startSignal);\n }\n\n // Execute method. `.call(instance, …)` preserves the receiver binding of\n // the original member call (`instance[methodName](args)`) — AI-callable\n // methods routinely read/write `this`.\n const result = await invokeMethod.call(instance, args);\n\n // Emit end signal\n if (signalBus) {\n const endSignal: Signal = {\n id: executionId,\n objectId: instance.id ?? 'unknown',\n className: instance.constructor?.name ?? 'Unknown',\n method: methodName,\n type: 'end',\n args: [args],\n result,\n duration: Date.now() - startTime,\n timestamp: new Date(),\n };\n await signalBus.emit(endSignal);\n }\n\n return {\n id: toolCall.id,\n methodName,\n arguments: args,\n result,\n success: true,\n duration: Date.now() - startTime,\n };\n } catch (error) {\n // Emit error signal\n if (signalBus) {\n const errorSignal: Signal = {\n id: executionId,\n objectId: instance.id ?? 'unknown',\n className: instance.constructor?.name ?? 'Unknown',\n method: methodName,\n type: 'error',\n // Preserve actual args if parsed, otherwise include raw arguments for debugging\n args: [\n typeof args !== 'undefined' ? args : toolCall.function.arguments,\n ],\n error: error instanceof Error ? error : new Error(String(error)),\n duration: Date.now() - startTime,\n timestamp: new Date(),\n };\n await signalBus.emit(errorSignal);\n }\n\n return {\n id: toolCall.id,\n methodName,\n arguments: {},\n result: null,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n duration: Date.now() - startTime,\n };\n }\n}\n\n/**\n * Executes multiple tool calls in sequence\n *\n * @param instance - Object instance to call methods on\n * @param toolCalls - Array of tool calls from AI\n * @param allowedMethods - List of methods AI is allowed to call\n * @param signalBus - Optional signal bus for emitting execution events\n * @returns Array of tool call results\n */\nexport async function executeToolCalls(\n instance: ToolCallTarget,\n toolCalls: ToolCall[],\n allowedMethods: string[],\n signalBus?: SignalBus,\n): Promise<ToolCallResult[]> {\n const results: ToolCallResult[] = [];\n\n for (const toolCall of toolCalls) {\n const result = await executeToolCall(\n instance,\n toolCall,\n allowedMethods,\n signalBus,\n );\n results.push(result);\n\n // Stop on first error if needed\n if (!result.success) {\n logger.warn(`Tool call failed for ${result.methodName}: ${result.error}`);\n // Continue executing other tools (don't break)\n }\n }\n\n return results;\n}\n\n/**\n * Formats tool call results into messages for AI\n *\n * @param results - Tool call execution results\n * @returns Array of tool response messages\n */\nexport function formatToolResults(\n results: ToolCallResult[],\n): Array<{ role: 'tool'; tool_call_id: string; content: string }> {\n return results.map((result) => ({\n role: 'tool' as const,\n tool_call_id: result.id,\n content: result.success\n ? JSON.stringify(result.result)\n : `Error: ${result.error}`,\n }));\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,11 @@
1
1
  import { AITool } from '@happyvertical/ai';
2
2
  import { MethodDefinition } from '../scanner/types.js';
3
+ /**
4
+ * A JSON Schema fragment. The shape is open-ended (different keywords appear
5
+ * for primitives, arrays, unions, etc.), so values are `unknown`; callers
6
+ * narrow specific keys (e.g. `.default`) at the point of use.
7
+ */
8
+ type JsonSchema = Record<string, unknown>;
3
9
  /**
4
10
  * Configuration for AI-callable methods
5
11
  */
@@ -26,7 +32,7 @@ export interface AiConfig {
26
32
  * @param tsType - TypeScript type string (e.g., 'string', 'number', '{ foo: string }')
27
33
  * @returns JSON Schema representation
28
34
  */
29
- export declare function convertTypeToJsonSchema(tsType: string): Record<string, any>;
35
+ export declare function convertTypeToJsonSchema(tsType: string): JsonSchema;
30
36
  /**
31
37
  * Determines if a method should be included as an AI-callable tool
32
38
  *
@@ -51,4 +57,5 @@ export declare function generateToolFromMethod(method: MethodDefinition, config?
51
57
  * @returns Array of AITool definitions for LLM function calling
52
58
  */
53
59
  export declare function generateToolManifest(methods: MethodDefinition[], config?: AiConfig): AITool[];
60
+ export {};
54
61
  //# sourceMappingURL=tool-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-generator.d.ts","sourceRoot":"","sources":["../../src/tools/tool-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,GAAG,KAAK,CAAC;IAE7C;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAqE3E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,MAAM,CAAC,EAAE,QAAQ,GAChB,OAAO,CAqCT;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,gBAAgB,EACxB,MAAM,CAAC,EAAE,QAAQ,GAChB,MAAM,CA0CR;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,MAAM,CAAC,EAAE,QAAQ,GAChB,MAAM,EAAE,CAWV"}
1
+ {"version":3,"file":"tool-generator.d.ts","sourceRoot":"","sources":["../../src/tools/tool-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D;;;;GAIG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAgB1C;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,GAAG,KAAK,CAAC;IAE7C;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAqElE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,MAAM,CAAC,EAAE,QAAQ,GAChB,OAAO,CAqCT;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,gBAAgB,EACxB,MAAM,CAAC,EAAE,QAAQ,GAChB,MAAM,CA0CR;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,MAAM,CAAC,EAAE,QAAQ,GAChB,MAAM,EAAE,CAWV"}
@@ -75,23 +75,22 @@ function shouldIncludeMethod(method, config) {
75
75
  return false;
76
76
  }
77
77
  function generateToolFromMethod(method, config) {
78
- const parameters = {
79
- type: "object",
80
- properties: {},
81
- required: []
82
- };
78
+ const properties = {};
79
+ const required = [];
83
80
  for (const param of method.parameters) {
84
- parameters.properties[param.name] = convertTypeToJsonSchema(param.type);
81
+ properties[param.name] = convertTypeToJsonSchema(param.type);
85
82
  if (!param.optional) {
86
- parameters.required.push(param.name);
83
+ required.push(param.name);
87
84
  }
88
85
  if (param.default !== void 0) {
89
- parameters.properties[param.name].default = param.default;
86
+ properties[param.name].default = param.default;
90
87
  }
91
88
  }
92
- if (parameters.required.length === 0) {
93
- delete parameters.required;
94
- }
89
+ const parameters = {
90
+ type: "object",
91
+ properties,
92
+ ...required.length > 0 ? { required } : {}
93
+ };
95
94
  const description = config?.descriptions?.[method.name] || method.description || `Call the ${method.name} method`;
96
95
  return {
97
96
  type: "function",
@@ -1 +1 @@
1
- {"version":3,"file":"tool-generator.js","sources":["../../src/tools/tool-generator.ts"],"sourcesContent":["/**\n * Tool Manifest Generation for AI Function Calling\n *\n * This module converts TypeScript method definitions from the AST scanner\n * into AI tool format at build time for use with LLM function calling.\n */\n\nimport type { AITool } from '@happyvertical/ai';\nimport type { MethodDefinition } from '../scanner/types.js';\n\n/**\n * Configuration for AI-callable methods\n */\nexport interface AiConfig {\n /**\n * Methods that AI can call\n * - Array of method names, e.g., ['analyze', 'validate']\n * - 'public-async' to auto-include all public async methods\n * - 'all' to include all methods (not recommended)\n */\n callable?: string[] | 'public-async' | 'all';\n\n /**\n * Methods to exclude from AI calling (higher priority than callable)\n */\n exclude?: string[];\n\n /**\n * Additional tool descriptions to override method JSDoc\n */\n descriptions?: Record<string, string>;\n}\n\n/**\n * Converts a TypeScript type string to JSON Schema format\n *\n * @param tsType - TypeScript type string (e.g., 'string', 'number', '{ foo: string }')\n * @returns JSON Schema representation\n */\nexport function convertTypeToJsonSchema(tsType: string): Record<string, any> {\n // Remove whitespace\n const cleanType = tsType.trim();\n\n // Primitive types\n if (cleanType === 'string') {\n return { type: 'string' };\n }\n if (cleanType === 'number') {\n return { type: 'number' };\n }\n if (cleanType === 'boolean') {\n return { type: 'boolean' };\n }\n if (cleanType === 'null') {\n return { type: 'null' };\n }\n if (cleanType === 'any' || cleanType === 'unknown') {\n return {}; // No type constraint\n }\n\n // Array types\n if (cleanType.endsWith('[]')) {\n const itemType = cleanType.slice(0, -2);\n return {\n type: 'array',\n items: convertTypeToJsonSchema(itemType),\n };\n }\n\n // Array<T> syntax\n const arrayMatch = cleanType.match(/^Array<(.+)>$/);\n if (arrayMatch) {\n return {\n type: 'array',\n items: convertTypeToJsonSchema(arrayMatch[1]),\n };\n }\n\n // Union types with literal values (e.g., 'shallow' | 'deep')\n if (cleanType.includes('|')) {\n const options = cleanType.split('|').map((s) => s.trim());\n\n // Check if all options are string literals\n if (options.every((opt) => opt.startsWith(\"'\") && opt.endsWith(\"'\"))) {\n return {\n type: 'string',\n enum: options.map((opt) => opt.slice(1, -1)), // Remove quotes\n };\n }\n\n // Mixed union - use oneOf\n return {\n oneOf: options.map(convertTypeToJsonSchema),\n };\n }\n\n // Object types - basic support\n if (cleanType.startsWith('{') && cleanType.endsWith('}')) {\n return { type: 'object' };\n }\n\n // Record<string, any> and similar\n if (cleanType.startsWith('Record<')) {\n return { type: 'object' };\n }\n\n // Default fallback\n return { type: 'string', description: `TypeScript type: ${cleanType}` };\n}\n\n/**\n * Determines if a method should be included as an AI-callable tool\n *\n * @param method - Method definition from AST scanner\n * @param config - AI configuration from @smrt decorator\n * @returns True if method should be callable by AI\n */\nexport function shouldIncludeMethod(\n method: MethodDefinition,\n config?: AiConfig,\n): boolean {\n // Skip if no AI config\n if (!config || !config.callable) {\n return false;\n }\n\n // Check exclusions first (higher priority)\n if (config.exclude?.includes(method.name)) {\n return false;\n }\n\n // Skip private methods always\n if (!method.isPublic) {\n return false;\n }\n\n // Skip static methods (tools operate on instances)\n if (method.isStatic) {\n return false;\n }\n\n // Handle 'all' mode\n if (config.callable === 'all') {\n return true;\n }\n\n // Handle 'public-async' mode\n if (config.callable === 'public-async') {\n return method.async;\n }\n\n // Handle explicit array of method names\n if (Array.isArray(config.callable)) {\n return config.callable.includes(method.name);\n }\n\n return false;\n}\n\n/**\n * Generates an AITool definition from a method definition\n *\n * @param method - Method definition from AST scanner\n * @param config - AI configuration for custom descriptions\n * @returns AITool definition for LLM function calling\n */\nexport function generateToolFromMethod(\n method: MethodDefinition,\n config?: AiConfig,\n): AITool {\n // Build parameters JSON Schema\n const parameters: Record<string, any> = {\n type: 'object',\n properties: {},\n required: [],\n };\n\n for (const param of method.parameters) {\n // Convert parameter type to JSON Schema\n parameters.properties[param.name] = convertTypeToJsonSchema(param.type);\n\n // Add to required if not optional\n if (!param.optional) {\n parameters.required.push(param.name);\n }\n\n // Add default value if present\n if (param.default !== undefined) {\n parameters.properties[param.name].default = param.default;\n }\n }\n\n // Remove empty required array\n if (parameters.required.length === 0) {\n delete parameters.required;\n }\n\n // Get description (custom override or from JSDoc)\n const description =\n config?.descriptions?.[method.name] ||\n method.description ||\n `Call the ${method.name} method`;\n\n return {\n type: 'function',\n function: {\n name: method.name,\n description,\n parameters,\n },\n };\n}\n\n/**\n * Generates tool manifest from method definitions\n *\n * @param methods - Array of method definitions from AST scanner\n * @param config - AI configuration from @smrt decorator\n * @returns Array of AITool definitions for LLM function calling\n */\nexport function generateToolManifest(\n methods: MethodDefinition[],\n config?: AiConfig,\n): AITool[] {\n const tools: AITool[] = [];\n\n for (const method of methods) {\n if (shouldIncludeMethod(method, config)) {\n const tool = generateToolFromMethod(method, config);\n tools.push(tool);\n }\n }\n\n return tools;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-generator.js","sources":["../../src/tools/tool-generator.ts"],"sourcesContent":["/**\n * Tool Manifest Generation for AI Function Calling\n *\n * This module converts TypeScript method definitions from the AST scanner\n * into AI tool format at build time for use with LLM function calling.\n */\n\nimport type { AITool } from '@happyvertical/ai';\nimport type { MethodDefinition } from '../scanner/types.js';\n\n/**\n * A JSON Schema fragment. The shape is open-ended (different keywords appear\n * for primitives, arrays, unions, etc.), so values are `unknown`; callers\n * narrow specific keys (e.g. `.default`) at the point of use.\n */\ntype JsonSchema = Record<string, unknown>;\n\n/**\n * The `parameters` object of a generated tool: a JSON Schema `object` with a\n * `properties` bag (each entry a nested schema) and a `required` name list.\n */\ninterface ToolParametersSchema {\n type: 'object';\n properties: Record<string, JsonSchema>;\n /**\n * Optional so the empty array can be `delete`d (omitting the key from the\n * emitted JSON Schema). It is always present while parameters are collected.\n */\n required?: string[];\n}\n\n/**\n * Configuration for AI-callable methods\n */\nexport interface AiConfig {\n /**\n * Methods that AI can call\n * - Array of method names, e.g., ['analyze', 'validate']\n * - 'public-async' to auto-include all public async methods\n * - 'all' to include all methods (not recommended)\n */\n callable?: string[] | 'public-async' | 'all';\n\n /**\n * Methods to exclude from AI calling (higher priority than callable)\n */\n exclude?: string[];\n\n /**\n * Additional tool descriptions to override method JSDoc\n */\n descriptions?: Record<string, string>;\n}\n\n/**\n * Converts a TypeScript type string to JSON Schema format\n *\n * @param tsType - TypeScript type string (e.g., 'string', 'number', '{ foo: string }')\n * @returns JSON Schema representation\n */\nexport function convertTypeToJsonSchema(tsType: string): JsonSchema {\n // Remove whitespace\n const cleanType = tsType.trim();\n\n // Primitive types\n if (cleanType === 'string') {\n return { type: 'string' };\n }\n if (cleanType === 'number') {\n return { type: 'number' };\n }\n if (cleanType === 'boolean') {\n return { type: 'boolean' };\n }\n if (cleanType === 'null') {\n return { type: 'null' };\n }\n if (cleanType === 'any' || cleanType === 'unknown') {\n return {}; // No type constraint\n }\n\n // Array types\n if (cleanType.endsWith('[]')) {\n const itemType = cleanType.slice(0, -2);\n return {\n type: 'array',\n items: convertTypeToJsonSchema(itemType),\n };\n }\n\n // Array<T> syntax\n const arrayMatch = cleanType.match(/^Array<(.+)>$/);\n if (arrayMatch) {\n return {\n type: 'array',\n items: convertTypeToJsonSchema(arrayMatch[1]),\n };\n }\n\n // Union types with literal values (e.g., 'shallow' | 'deep')\n if (cleanType.includes('|')) {\n const options = cleanType.split('|').map((s) => s.trim());\n\n // Check if all options are string literals\n if (options.every((opt) => opt.startsWith(\"'\") && opt.endsWith(\"'\"))) {\n return {\n type: 'string',\n enum: options.map((opt) => opt.slice(1, -1)), // Remove quotes\n };\n }\n\n // Mixed union - use oneOf\n return {\n oneOf: options.map(convertTypeToJsonSchema),\n };\n }\n\n // Object types - basic support\n if (cleanType.startsWith('{') && cleanType.endsWith('}')) {\n return { type: 'object' };\n }\n\n // Record<string, any> and similar\n if (cleanType.startsWith('Record<')) {\n return { type: 'object' };\n }\n\n // Default fallback\n return { type: 'string', description: `TypeScript type: ${cleanType}` };\n}\n\n/**\n * Determines if a method should be included as an AI-callable tool\n *\n * @param method - Method definition from AST scanner\n * @param config - AI configuration from @smrt decorator\n * @returns True if method should be callable by AI\n */\nexport function shouldIncludeMethod(\n method: MethodDefinition,\n config?: AiConfig,\n): boolean {\n // Skip if no AI config\n if (!config || !config.callable) {\n return false;\n }\n\n // Check exclusions first (higher priority)\n if (config.exclude?.includes(method.name)) {\n return false;\n }\n\n // Skip private methods always\n if (!method.isPublic) {\n return false;\n }\n\n // Skip static methods (tools operate on instances)\n if (method.isStatic) {\n return false;\n }\n\n // Handle 'all' mode\n if (config.callable === 'all') {\n return true;\n }\n\n // Handle 'public-async' mode\n if (config.callable === 'public-async') {\n return method.async;\n }\n\n // Handle explicit array of method names\n if (Array.isArray(config.callable)) {\n return config.callable.includes(method.name);\n }\n\n return false;\n}\n\n/**\n * Generates an AITool definition from a method definition\n *\n * @param method - Method definition from AST scanner\n * @param config - AI configuration for custom descriptions\n * @returns AITool definition for LLM function calling\n */\nexport function generateToolFromMethod(\n method: MethodDefinition,\n config?: AiConfig,\n): AITool {\n // Build parameters JSON Schema. `required` is a guaranteed-present local\n // array while collecting, then attached only when non-empty — avoids both\n // optional-chaining on an invariant and a post-hoc `delete`.\n const properties: ToolParametersSchema['properties'] = {};\n const required: string[] = [];\n\n for (const param of method.parameters) {\n // Convert parameter type to JSON Schema\n properties[param.name] = convertTypeToJsonSchema(param.type);\n\n // Add to required if not optional\n if (!param.optional) {\n required.push(param.name);\n }\n\n // Add default value if present\n if (param.default !== undefined) {\n properties[param.name].default = param.default;\n }\n }\n\n const parameters: ToolParametersSchema = {\n type: 'object',\n properties,\n ...(required.length > 0 ? { required } : {}),\n };\n\n // Get description (custom override or from JSDoc)\n const description =\n config?.descriptions?.[method.name] ||\n method.description ||\n `Call the ${method.name} method`;\n\n return {\n type: 'function',\n function: {\n name: method.name,\n description,\n parameters,\n },\n };\n}\n\n/**\n * Generates tool manifest from method definitions\n *\n * @param methods - Array of method definitions from AST scanner\n * @param config - AI configuration from @smrt decorator\n * @returns Array of AITool definitions for LLM function calling\n */\nexport function generateToolManifest(\n methods: MethodDefinition[],\n config?: AiConfig,\n): AITool[] {\n const tools: AITool[] = [];\n\n for (const method of methods) {\n if (shouldIncludeMethod(method, config)) {\n const tool = generateToolFromMethod(method, config);\n tools.push(tool);\n }\n }\n\n return tools;\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-core",
3
- "version": "0.36.6",
3
+ "version": "0.36.8",
4
4
  "description": "Core AI agent framework with standardized collections, object-relational mapping, and code generators",
5
5
  "author": "HappyVertical",
6
6
  "type": "module",
@@ -153,9 +153,9 @@
153
153
  "tsx": "^4.21.0",
154
154
  "typescript": "^5.9.3",
155
155
  "yaml": "^2.8.2",
156
- "@happyvertical/smrt-config": "0.36.6",
157
- "@happyvertical/smrt-scanner": "0.36.6",
158
- "@happyvertical/smrt-types": "0.36.6"
156
+ "@happyvertical/smrt-types": "0.36.8",
157
+ "@happyvertical/smrt-config": "0.36.8",
158
+ "@happyvertical/smrt-scanner": "0.36.8"
159
159
  },
160
160
  "peerDependencies": {
161
161
  "@huggingface/transformers": ">=3.0.0 <4.0.0",