UNPKG

aetherlight-sdk

Version:

ÆtherLight Application Integration SDK - Add voice control to any application with natural language function calling

109 lines (108 loc) 3.83 kB
"use strict"; /** * ÆtherLight SDK Decorators * * DESIGN DECISION: TypeScript decorators for function registration * WHY: Clean, declarative syntax that auto-generates metadata * * REASONING CHAIN: * 1. @Lumina decorator marks function as voice-accessible * 2. @param decorator provides parameter descriptions * 3. Reflect.metadata stores metadata at compile-time * 4. Client.register() reads metadata at runtime * 5. Sends function schema to ÆtherLight daemon * * PATTERN: Pattern-SDK-001 (Application Integration SDK) */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Lumina = Lumina; exports.param = param; require("reflect-metadata"); /** * @Lumina decorator - Marks method as voice-accessible * * DESIGN DECISION: Decorator stores metadata via reflect-metadata * WHY: Enables runtime inspection of function schema * * USAGE: * ```typescript * @Lumina({ * description: "Search for cases by client name", * examples: ["Find John Doe's cases", "Show Jane Smith's matters"], * tags: ["legal", "search"] * }) * async searchCases(clientName: string): Promise<Case[]> { * return this.database.query('cases', { clientName }); * } * ``` */ function Lumina(metadata) { return function (target, propertyKey, descriptor) { Reflect.defineMetadata('voiceCommand', metadata, target, propertyKey); }; } /** * @param decorator - Provides parameter description * * DESIGN DECISION: Parameter decorator extracts type information * WHY: TypeScript provides compile-time type information via reflection * * REASONING CHAIN: * 1. Decorator executes during class definition * 2. parameterIndex identifies which parameter (0, 1, 2, ...) * 3. design:paramtypes reflects the parameter types * 4. Store array of parameter metadata * 5. Client.register() reads this array * * USAGE: * ```typescript * async searchCases( * @param("Client's full name") clientName: string, * @param("Case status: open, closed, or all") status: 'open' | 'closed' | 'all' * ): Promise<Case[]> { * // ... * } * ``` */ function param(description, required = true) { return function (target, propertyKey, parameterIndex) { const existingParams = Reflect.getMetadata('voiceParams', target, propertyKey) || []; const paramTypes = Reflect.getMetadata('design:paramtypes', target, propertyKey) || []; // Extract parameter name from function signature (best effort) const functionString = target[propertyKey].toString(); const paramMatch = functionString.match(/\(([^)]+)\)/); const paramNames = paramMatch ? paramMatch[1].split(',').map((p) => p.trim().split(/[:\s]/)[0]) : []; existingParams[parameterIndex] = { name: paramNames[parameterIndex] || `param${parameterIndex}`, type: paramTypes[parameterIndex]?.name || 'any', description, required, }; Reflect.defineMetadata('voiceParams', existingParams, target, propertyKey); }; } /** * Helper function to extract parameter names from function * * DESIGN DECISION: Parse function.toString() as fallback * WHY: TypeScript doesn't preserve parameter names in metadata * * NOTE: This is a best-effort approach. Works for simple cases but may fail * with minified code or complex parameter patterns. */ function extractParameterNames(func) { const functionString = func.toString(); const paramMatch = functionString.match(/\(([^)]*)\)/); if (!paramMatch) return []; return paramMatch[1] .split(',') .map(param => { // Handle destructuring, default values, type annotations const cleaned = param.trim().split(/[=:]/)[0].trim(); return cleaned || 'unknown'; }) .filter(name => name !== ''); }