@operor/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.
- package/README.md +78 -0
- package/dist/index.d.ts +611 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2863 -0
- package/dist/index.js.map +1 -0
- package/package.json +33 -0
- package/src/Agent.ts +267 -0
- package/src/AgentLoader.ts +165 -0
- package/src/AgentVersionStore.ts +59 -0
- package/src/Guardrails.ts +60 -0
- package/src/InMemoryStore.ts +89 -0
- package/src/KeywordIntentClassifier.ts +74 -0
- package/src/LLMIntentClassifier.ts +68 -0
- package/src/Operor.ts +2972 -0
- package/src/__tests__/AgentLoader.test.ts +315 -0
- package/src/__tests__/InMemoryStore.test.ts +57 -0
- package/src/guardrails.test.ts +180 -0
- package/src/index.ts +11 -0
- package/src/types.ts +286 -0
- package/test/integration.test.ts +114 -0
- package/tsconfig.json +9 -0
- package/tsdown.config.ts +10 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/Agent.ts","../src/InMemoryStore.ts","../src/KeywordIntentClassifier.ts","../src/Guardrails.ts","../src/AgentLoader.ts","../src/AgentVersionStore.ts","../src/Operor.ts","../src/LLMIntentClassifier.ts"],"sourcesContent":["import EventEmitter from 'eventemitter3';\nimport type {\n AgentConfig,\n ConversationContext,\n AgentResponse,\n ToolCall,\n Tool,\n IncomingMessage,\n Customer,\n} from './types.js';\n\nexport class Agent extends EventEmitter {\n public readonly id: string;\n public readonly name: string;\n public readonly config: AgentConfig;\n private tools: Map<string, Tool> = new Map();\n\n constructor(config: AgentConfig) {\n super();\n this.id = `agent_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.name = config.name;\n this.config = config;\n\n // Register tools\n config.tools?.forEach((tool) => {\n this.tools.set(tool.name, tool);\n });\n }\n\n /**\n * Check if this agent should handle the given intent\n */\n matchesIntent(intent: string): boolean {\n if (!this.config.triggers || this.config.triggers.length === 0) {\n return true; // Match all if no triggers specified\n }\n\n const lowerIntent = intent.toLowerCase();\n return this.config.triggers.some((trigger) =>\n trigger === '*' || lowerIntent.includes(trigger.toLowerCase())\n );\n }\n\n /**\n * Process a message\n */\n async process(context: ConversationContext): Promise<AgentResponse> {\n const startTime = Date.now();\n\n try {\n // For now, simple implementation without LLM\n // In production, this would call LLM with tools\n const response = await this.generateResponse(context);\n const duration = Date.now() - startTime;\n\n return {\n text: response.text,\n toolCalls: response.toolCalls,\n duration,\n cost: 0.001, // Mock cost\n };\n } catch (error) {\n const duration = Date.now() - startTime;\n throw new Error(`Agent processing failed: ${error}`);\n }\n }\n\n /**\n * Generate response (simplified - would use LLM in production)\n */\n private async generateResponse(\n context: ConversationContext\n ): Promise<{ text: string; toolCalls?: ToolCall[] }> {\n const { currentMessage, customer, history } = context;\n const toolCalls: ToolCall[] = [];\n\n // Simple pattern matching for demo\n const text = currentMessage.text.toLowerCase();\n\n // Check for product search patterns\n const productKeywords = ['headphones', 'keyboard', 'mouse', 'cable', 'product', 'electronics', 'stock', 'available', 'carry', 'sell'];\n const matchedKeyword = productKeywords.find(kw => text.includes(kw));\n const hasProductQuery = !!matchedKeyword;\n\n if (hasProductQuery) {\n const searchProductsTool = this.tools.get('search_products');\n if (searchProductsTool) {\n // Extract product name from matched keyword instead of using full message\n const query = matchedKeyword || currentMessage.text;\n\n const toolCall: ToolCall = {\n id: `tool_${Date.now()}`,\n name: 'search_products',\n params: { query, limit: 5 },\n };\n\n try {\n const result = await searchProductsTool.execute({ query, limit: 5 });\n toolCall.result = result;\n toolCall.success = true;\n toolCall.duration = 100;\n toolCalls.push(toolCall);\n } catch (error) {\n toolCall.success = false;\n toolCall.error = String(error);\n toolCalls.push(toolCall);\n }\n }\n }\n\n // Check for order number pattern\n const orderMatch = text.match(/#?(\\d{4,})/);\n if (orderMatch) {\n const orderId = orderMatch[1];\n\n // Try to execute get_order tool if available\n const getOrderTool = this.tools.get('get_order');\n if (getOrderTool) {\n const toolCall: ToolCall = {\n id: `tool_${Date.now()}`,\n name: 'get_order',\n params: { orderId },\n };\n\n try {\n const result = await getOrderTool.execute({ orderId });\n toolCall.result = result;\n toolCall.success = true;\n toolCall.duration = 100;\n toolCalls.push(toolCall);\n\n // Check business rules\n const ruleActions = await this.applyBusinessRules(context, toolCalls);\n\n // Generate response based on tool results\n let responseText = `I found your order #${orderId}.\\n\\n`;\n responseText += `Status: ${result.status}\\n`;\n\n if (result.tracking) {\n responseText += `Tracking: ${result.tracking}\\n`;\n }\n\n if (ruleActions.length > 0) {\n for (const action of ruleActions) {\n if (action.type === 'discount_created') {\n responseText += `\\nI apologize for the delay! I've created a ${action.percent}% discount code for you: ${action.code} (valid ${action.validDays} days)`;\n }\n }\n }\n\n // Append product search results if both tools were called\n if (hasProductQuery) {\n const searchResult = toolCalls.find(tc => tc.name === 'search_products');\n if (searchResult?.success && searchResult.result?.found > 0) {\n responseText += `\\n\\nI also found ${searchResult.result.found} product(s) matching your search:\\n\\n`;\n for (const product of searchResult.result.products) {\n responseText += `• ${product.title} by ${product.vendor} - $${product.price}`;\n if (!product.available) responseText += ' (Out of stock)';\n responseText += '\\n';\n }\n }\n }\n\n return { text: responseText, toolCalls };\n } catch (error) {\n toolCall.success = false;\n toolCall.error = String(error);\n toolCalls.push(toolCall);\n }\n }\n }\n\n // If we have product search results but no order, generate product-only response\n if (hasProductQuery && toolCalls.some(tc => tc.name === 'search_products')) {\n const searchResult = toolCalls.find(tc => tc.name === 'search_products');\n if (searchResult?.success) {\n let responseText = '';\n if (searchResult.result?.found > 0) {\n responseText = `I found ${searchResult.result.found} product(s) matching your search:\\n\\n`;\n for (const product of searchResult.result.products) {\n responseText += `• ${product.title} by ${product.vendor} - $${product.price}`;\n if (!product.available) responseText += ' (Out of stock)';\n responseText += '\\n';\n }\n } else {\n responseText = `I couldn't find any products matching \"${matchedKeyword}\". Would you like to try a different search?`;\n }\n return { text: responseText, toolCalls };\n }\n }\n\n // Check if this is a greeting or first message\n const greetings = ['hello', 'hi', 'hey', 'good morning', 'good afternoon', 'good evening'];\n const isGreeting = greetings.some(g => text.trim().startsWith(g));\n const isFirstMessage = !history || history.length === 0;\n\n // Only introduce on first message or explicit greeting\n if (isFirstMessage || isGreeting) {\n return {\n text: `Hi ${customer.name || 'there'}! I'm ${this.name}. ${this.config.purpose || 'How can I help you today?'}`,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n };\n }\n\n // For follow-up messages, provide a helpful response without re-introducing\n return {\n text: `I understand. How can I assist you further?`,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n };\n }\n\n /**\n * Apply business rules\n */\n private async applyBusinessRules(\n context: ConversationContext,\n toolResults: ToolCall[]\n ): Promise<any[]> {\n const actions: any[] = [];\n\n if (!this.config.rules) return actions;\n\n for (const rule of this.config.rules) {\n try {\n const shouldApply = await rule.condition(context, toolResults);\n if (shouldApply) {\n const action = await rule.action(context, toolResults);\n actions.push(action);\n\n // Execute action tools if needed\n if (action.toolName && this.tools.has(action.toolName)) {\n const tool = this.tools.get(action.toolName)!;\n const result = await tool.execute(action.params);\n action.result = result;\n }\n }\n } catch (error) {\n console.error(`Rule \"${rule.name}\" failed:`, error);\n }\n }\n\n return actions;\n }\n\n /**\n * Get agent configuration\n */\n getConfig(): AgentConfig {\n return { ...this.config };\n }\n\n /**\n * Get available tools\n */\n getTools(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * Register tools dynamically (e.g., from integrations)\n */\n registerTools(tools: Tool[]): void {\n tools.forEach((tool) => {\n this.tools.set(tool.name, tool);\n });\n }\n}\n","import type { Customer, ConversationMessage, MemoryStore } from './types.js';\n\n/**\n * Default in-memory implementation of MemoryStore.\n * Data is lost on restart. Used as the default when no external store is provided.\n */\nexport class InMemoryStore implements MemoryStore {\n private customers: Map<string, Customer> = new Map();\n private phoneIndex: Map<string, string> = new Map();\n private conversations: Map<string, ConversationMessage[]> = new Map();\n private settings: Map<string, string> = new Map();\n\n async initialize(): Promise<void> {}\n\n async getCustomer(id: string): Promise<Customer | null> {\n return this.customers.get(id) || null;\n }\n\n async getCustomerByPhone(phone: string): Promise<Customer | null> {\n const customerId = this.phoneIndex.get(phone);\n if (!customerId) return null;\n return this.customers.get(customerId) || null;\n }\n\n async upsertCustomer(customer: Customer): Promise<void> {\n this.customers.set(customer.id, customer);\n if (customer.phone) {\n this.phoneIndex.set(customer.phone, customer.id);\n }\n }\n\n async getHistory(customerId: string, limit = 50, agentId?: string): Promise<ConversationMessage[]> {\n const key = agentId ? `${customerId}:${agentId}` : customerId;\n const history = this.conversations.get(key) || [];\n return history.slice(-limit);\n }\n\n async addMessage(customerId: string, message: ConversationMessage, agentId?: string): Promise<void> {\n const key = agentId ? `${customerId}:${agentId}` : customerId;\n if (!this.conversations.has(key)) {\n this.conversations.set(key, []);\n }\n const history = this.conversations.get(key)!;\n history.push(message);\n if (history.length > 50) {\n history.splice(0, history.length - 50);\n }\n }\n\n async clearHistory(customerId?: string, agentId?: string): Promise<{ deletedCount: number }> {\n let deletedCount = 0;\n if (customerId) {\n // Delete matching keys\n for (const [key, messages] of this.conversations) {\n const [cid, aid] = key.includes(':') ? key.split(':') : [key, undefined];\n if (cid === customerId && (!agentId || aid === agentId)) {\n deletedCount += messages.length;\n this.conversations.delete(key);\n }\n }\n } else {\n // Delete all\n for (const messages of this.conversations.values()) {\n deletedCount += messages.length;\n }\n this.conversations.clear();\n }\n return { deletedCount };\n }\n\n async getSetting(key: string): Promise<string | null> {\n return this.settings.get(key) ?? null;\n }\n\n async setSetting(key: string, value: string | null): Promise<void> {\n if (value === null) {\n this.settings.delete(key);\n } else {\n this.settings.set(key, value);\n }\n }\n\n async close(): Promise<void> {\n this.customers.clear();\n this.phoneIndex.clear();\n this.conversations.clear();\n this.settings.clear();\n }\n}\n","import type { Intent, IntentClassifier, AgentConfig, ConversationMessage } from './types.js';\n\n/**\n * Default keyword-based intent classifier.\n * Uses simple keyword matching to classify user messages.\n */\nexport class KeywordIntentClassifier implements IntentClassifier {\n async classify(\n message: string,\n agents: AgentConfig[],\n history?: ConversationMessage[]\n ): Promise<Intent> {\n const lowerText = message.toLowerCase();\n\n // Try to match against agent triggers\n for (const agent of agents) {\n if (!agent.triggers) continue;\n\n for (const trigger of agent.triggers) {\n if (lowerText.includes(trigger.toLowerCase())) {\n return {\n intent: trigger,\n confidence: 0.9,\n entities: {},\n };\n }\n }\n }\n\n // Fallback keyword matching\n if (\n lowerText.includes('order') ||\n lowerText.includes('tracking') ||\n lowerText.includes('where is') ||\n lowerText.includes('delivery')\n ) {\n return {\n intent: 'order_tracking',\n confidence: 0.95,\n entities: {},\n };\n }\n\n if (\n lowerText.includes('product') ||\n lowerText.includes('buy') ||\n lowerText.includes('price')\n ) {\n return {\n intent: 'product_inquiry',\n confidence: 0.9,\n entities: {},\n };\n }\n\n if (\n lowerText.includes('help') ||\n lowerText.includes('support') ||\n lowerText.includes('problem')\n ) {\n return {\n intent: 'support',\n confidence: 0.85,\n entities: {},\n };\n }\n\n return {\n intent: 'general',\n confidence: 0.5,\n entities: {},\n };\n }\n}\n","import type { GuardrailConfig } from './types.js';\n\nexport interface GuardrailCheckResult {\n allowed: boolean;\n reason?: string;\n escalate?: boolean;\n}\n\nexport class GuardrailEngine {\n /**\n * Check incoming message against guardrail config.\n * Returns whether the message is allowed, and whether it should escalate.\n */\n checkInput(message: string, config: GuardrailConfig): GuardrailCheckResult {\n const lowerMessage = message.toLowerCase();\n\n // Check escalation triggers first\n if (config.escalationTriggers) {\n for (const trigger of config.escalationTriggers) {\n if (lowerMessage.includes(trigger.toLowerCase())) {\n return { allowed: false, reason: `Escalation triggered: \"${trigger}\"`, escalate: true };\n }\n }\n }\n\n // Check blocked topics\n if (config.blockedTopics) {\n for (const topic of config.blockedTopics) {\n if (lowerMessage.includes(topic.toLowerCase())) {\n return { allowed: false, reason: `Blocked topic: \"${topic}\"` };\n }\n }\n }\n\n return { allowed: true };\n }\n\n /**\n * Check outgoing response against guardrail config.\n * Returns whether the response is allowed to be sent.\n */\n checkOutput(response: string, config: GuardrailConfig): GuardrailCheckResult {\n // Check max response length\n if (config.maxResponseLength && response.length > config.maxResponseLength) {\n return { allowed: false, reason: `Response exceeds max length (${response.length}/${config.maxResponseLength})` };\n }\n\n // Check blocked topics in response\n if (config.blockedTopics) {\n const lowerResponse = response.toLowerCase();\n for (const topic of config.blockedTopics) {\n if (lowerResponse.includes(topic.toLowerCase())) {\n return { allowed: false, reason: `Response contains blocked topic: \"${topic}\"` };\n }\n }\n }\n\n return { allowed: true };\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport matter from 'gray-matter';\nimport type { AgentConfig, AgentDefinition, GuardrailConfig } from './types.js';\n\n/**\n * YAML frontmatter schema for INSTRUCTIONS.md files.\n */\ninterface AgentFrontmatter {\n name: string;\n purpose?: string;\n triggers?: string[];\n channels?: string[];\n skills?: string[];\n knowledgeBase?: boolean;\n priority?: number;\n escalateTo?: string;\n guardrails?: GuardrailConfig;\n}\n\n/**\n * Loads agent definitions from a file-based directory structure.\n *\n * Expected layout:\n * agents/\n * _defaults/\n * SOUL.md (optional global soul/personality)\n * <agent-name>/\n * INSTRUCTIONS.md (required — YAML frontmatter + markdown body)\n * IDENTITY.md (optional — identity/persona)\n * SOUL.md (optional — overrides _defaults/SOUL.md)\n * USER.md (optional — workspace-level user context)\n */\nexport class AgentLoader {\n private agentsDir: string;\n private workspaceRoot: string;\n\n constructor(workspaceRoot: string, agentsDir?: string) {\n this.workspaceRoot = workspaceRoot;\n this.agentsDir = agentsDir ?? path.join(workspaceRoot, 'agents');\n }\n\n /**\n * Load all agent definitions from the agents directory.\n */\n async loadAll(): Promise<AgentDefinition[]> {\n const entries = await fs.readdir(this.agentsDir, { withFileTypes: true });\n const agentDirs = entries.filter(\n (e) => e.isDirectory() && !e.name.startsWith('_'),\n );\n\n const definitions: AgentDefinition[] = [];\n for (const dir of agentDirs) {\n const def = await this.loadAgent(dir.name);\n if (def) definitions.push(def);\n }\n\n return definitions;\n }\n\n /**\n * Load a single agent definition by directory name.\n */\n async loadAgent(name: string): Promise<AgentDefinition | null> {\n const agentDir = path.join(this.agentsDir, name);\n const instructionsPath = path.join(agentDir, 'INSTRUCTIONS.md');\n\n // INSTRUCTIONS.md is required\n const instructionsRaw = await readFileOrNull(instructionsPath);\n if (instructionsRaw === null) return null;\n\n // Parse frontmatter + body\n const { data: frontmatter, content: body } = matter(instructionsRaw) as {\n data: AgentFrontmatter;\n content: string;\n };\n\n // Read optional files\n const [identity, agentSoul, defaultSoul, userContext] = await Promise.all([\n readFileOrNull(path.join(agentDir, 'IDENTITY.md')),\n readFileOrNull(path.join(agentDir, 'SOUL.md')),\n readFileOrNull(path.join(this.agentsDir, '_defaults', 'SOUL.md')),\n readFileOrNull(path.join(this.workspaceRoot, 'USER.md')),\n ]);\n\n // Build system prompt\n const soul = agentSoul ?? defaultSoul;\n const systemPrompt = buildSystemPrompt({\n identity,\n soul,\n body,\n userContext,\n guardrails: frontmatter.guardrails,\n });\n\n // Build AgentConfig\n const skills = frontmatter.skills;\n const config: AgentConfig = {\n name: frontmatter.name ?? name,\n purpose: frontmatter.purpose,\n triggers: frontmatter.triggers,\n channels: frontmatter.channels,\n skills,\n knowledgeBase: frontmatter.knowledgeBase,\n priority: frontmatter.priority,\n escalateTo: frontmatter.escalateTo,\n guardrails: frontmatter.guardrails,\n systemPrompt,\n _rawInstructions: body.trim() || undefined,\n _rawIdentity: identity?.trim() || undefined,\n _rawSoul: soul?.trim() || undefined,\n };\n\n return { config, systemPrompt, instructionsPath };\n }\n}\n\n/**\n * Read a file and return its contents, or null if it doesn't exist.\n */\nexport async function readFileOrNull(filePath: string): Promise<string | null> {\n try {\n return await fs.readFile(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/**\n * Assemble the system prompt from structured sections.\n */\nexport function buildSystemPrompt(parts: {\n identity: string | null;\n soul: string | null;\n body: string;\n userContext: string | null;\n guardrails?: GuardrailConfig;\n}): string {\n const sections: string[] = [];\n\n if (parts.identity) {\n sections.push(`## Identity\\n\\n${parts.identity.trim()}`);\n }\n\n if (parts.soul) {\n sections.push(`## Soul\\n\\n${parts.soul.trim()}`);\n }\n\n if (parts.body.trim()) {\n sections.push(`## Instructions\\n\\n${parts.body.trim()}`);\n }\n\n if (parts.userContext) {\n sections.push(`## User Context\\n\\n${parts.userContext.trim()}`);\n }\n\n if (parts.guardrails?.systemRules && parts.guardrails.systemRules.length > 0) {\n const rules = parts.guardrails.systemRules\n .map((rule, i) => `${i + 1}. ${rule}`)\n .join('\\n');\n sections.push(`## System Rules\\n\\nYou MUST follow these rules at all times:\\n${rules}`);\n }\n\n return sections.join('\\n\\n');\n}\n","import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface VersionSnapshot {\n timestamp: string;\n instructions?: string;\n identity?: string;\n soul?: string;\n frontmatter?: Record<string, any>;\n editedBy?: string;\n changeDescription?: string;\n}\n\nconst MAX_VERSIONS = 20;\n\nexport class AgentVersionStore {\n private agentsDir?: string;\n private memory = new Map<string, VersionSnapshot[]>();\n\n constructor(agentsDir?: string) {\n this.agentsDir = agentsDir;\n }\n\n async saveVersion(agentName: string, snapshot: VersionSnapshot): Promise<void> {\n const history = await this.loadHistory(agentName);\n history.unshift(snapshot);\n if (history.length > MAX_VERSIONS) history.length = MAX_VERSIONS;\n\n if (this.agentsDir) {\n const dir = path.join(this.agentsDir, '_versions');\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(path.join(dir, `${agentName}.json`), JSON.stringify(history, null, 2));\n } else {\n this.memory.set(agentName, history);\n }\n }\n\n async getHistory(agentName: string, limit?: number): Promise<VersionSnapshot[]> {\n const history = await this.loadHistory(agentName);\n return limit ? history.slice(0, limit) : history;\n }\n\n async getVersion(agentName: string, index: number): Promise<VersionSnapshot | null> {\n const history = await this.loadHistory(agentName);\n return history[index] ?? null;\n }\n\n private async loadHistory(agentName: string): Promise<VersionSnapshot[]> {\n if (this.agentsDir) {\n try {\n const data = await fs.readFile(path.join(this.agentsDir, '_versions', `${agentName}.json`), 'utf-8');\n return JSON.parse(data);\n } catch {\n return [];\n }\n }\n return [...(this.memory.get(agentName) ?? [])];\n }\n}\n","import EventEmitter from 'eventemitter3';\nimport fs from 'fs/promises';\nimport path from 'path';\nimport yaml from 'js-yaml';\nimport { Agent } from './Agent.js';\nimport { InMemoryStore } from './InMemoryStore.js';\nimport { KeywordIntentClassifier } from './KeywordIntentClassifier.js';\nimport { GuardrailEngine } from './Guardrails.js';\nimport { buildSystemPrompt } from './AgentLoader.js';\nimport { AgentVersionStore } from './AgentVersionStore.js';\nimport type { VersionSnapshot } from './AgentVersionStore.js';\nimport type {\n OperorConfig,\n MessageProvider,\n Skill,\n IncomingMessage,\n Customer,\n Intent,\n ConversationContext,\n AgentConfig,\n ConversationMessage,\n MemoryStore,\n IntentClassifier,\n OutgoingMessage,\n} from './types.js';\n\n/**\n * Truncate text at the last sentence boundary within maxLen.\n * Falls back to last whitespace if no sentence-ending punctuation is found.\n */\nfunction truncateAtSentence(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n\n const truncated = text.slice(0, maxLen);\n\n // Try to find the last sentence-ending punctuation (. ! ? or Hebrew ׃)\n const sentenceEnd = Math.max(\n truncated.lastIndexOf('. '),\n truncated.lastIndexOf('! '),\n truncated.lastIndexOf('? '),\n truncated.lastIndexOf('.\\n'),\n truncated.lastIndexOf('!\\n'),\n truncated.lastIndexOf('?\\n'),\n );\n\n if (sentenceEnd > maxLen * 0.5) {\n return truncated.slice(0, sentenceEnd + 1).trimEnd();\n }\n\n // Fall back to last whitespace\n const lastSpace = truncated.lastIndexOf(' ');\n if (lastSpace > maxLen * 0.5) {\n return truncated.slice(0, lastSpace).trimEnd();\n }\n\n // Last resort: hard cut (no \"...\" appended)\n return truncated.trimEnd();\n}\n\n/**\n * Split text into chunks that fit within maxLen, breaking at paragraph\n * boundaries (\\n\\n). Falls back to sentence splitting for oversized paragraphs.\n */\nfunction splitIntoParagraphChunks(text: string, maxLen: number): string[] {\n if (text.length <= maxLen) return [text];\n\n const paragraphs = text.split(/\\n\\n+/);\n const chunks: string[] = [];\n let current = '';\n\n for (const para of paragraphs) {\n const candidate = current ? current + '\\n\\n' + para : para;\n\n if (candidate.length <= maxLen) {\n current = candidate;\n continue;\n }\n\n // Adding this paragraph would exceed maxLen\n if (current) {\n chunks.push(current.trimEnd());\n current = '';\n }\n\n // If the paragraph itself fits, start a new chunk with it\n if (para.length <= maxLen) {\n current = para;\n continue;\n }\n\n // Single paragraph exceeds maxLen — split at sentence boundaries\n let remaining = para;\n while (remaining.length > maxLen) {\n const piece = truncateAtSentence(remaining, maxLen);\n chunks.push(piece.trimEnd());\n remaining = remaining.slice(piece.length).trimStart();\n }\n if (remaining) {\n current = remaining;\n }\n }\n\n if (current) {\n chunks.push(current.trimEnd());\n }\n\n return chunks.filter(Boolean);\n}\n\ninterface PendingEdit {\n agentName: string;\n field: 'instructions' | 'identity' | 'soul';\n section?: string;\n content: string[];\n createdAt: number;\n state: 'capturing' | 'confirming';\n newContent?: string;\n}\n\ninterface PendingQuickstart {\n step: 'question' | 'answer';\n question?: string;\n createdAt: number;\n}\n\ninterface PendingSkillAdd {\n skillName: string;\n envVars: Record<string, string>;\n pendingKeys: string[];\n currentKey: string | null;\n catalogEntry: any;\n createdAt: number;\n}\n\nexport class Operor extends EventEmitter {\n private config: OperorConfig;\n private providers: Map<string, MessageProvider> = new Map();\n private agents: Map<string, Agent> = new Map();\n private skills: Map<string, Skill> = new Map();\n private memory: MemoryStore;\n private intentClassifier: IntentClassifier;\n private isRunning: boolean = false;\n private messageBatches: Map<string, IncomingMessage[]> = new Map();\n private batchTimers: Map<string, ReturnType<typeof setTimeout>> = new Map();\n private batchWindowMs: number = 2000;\n private autoAddAssistantMessages: boolean = true;\n private pendingEdits: Map<string, PendingEdit> = new Map();\n private pendingQuickstarts: Map<string, PendingQuickstart> = new Map();\n private pendingSkillAdds: Map<string, PendingSkillAdd> = new Map();\n private pendingFaqReplacements: Map<string, { question: string; answer: string; replaceId: string; expiresAt: number }> = new Map();\n private versionStore: AgentVersionStore;\n\n constructor(config: OperorConfig = {}) {\n super();\n this.config = config;\n this.memory = config.memory || new InMemoryStore();\n this.intentClassifier = config.intentClassifier || new KeywordIntentClassifier();\n this.batchWindowMs = config.batchWindowMs ?? 2000;\n this.autoAddAssistantMessages = config.autoAddAssistantMessages ?? true;\n this.versionStore = new AgentVersionStore(config.agentsDir);\n this.log('Operor initialized');\n\n // Wire analytics collector (non-blocking)\n if (config.analyticsCollector) {\n config.analyticsCollector.attach(this);\n this.log('Analytics collector attached');\n }\n\n // Wire copilot tracker (non-blocking)\n if (config.copilotTracker) {\n this.on('message:processed', (event: any) => {\n config.copilotTracker!.maybeTrack({\n query: event.message?.text,\n channel: event.message?.channel || event.message?.provider,\n customerPhone: event.message?.from,\n response: event.response,\n }).catch((err: any) => {\n if (config.debug) console.warn('[Copilot] Tracking error:', err?.message);\n });\n });\n }\n }\n\n /**\n * Register a message provider (WhatsApp, Instagram, etc.)\n */\n async addProvider(provider: MessageProvider): Promise<void> {\n this.log(`Adding provider: ${provider.name}`);\n\n // Listen for incoming messages from this provider\n provider.on('message', (message: IncomingMessage) => {\n this.handleIncomingMessage(message).catch((error) => {\n this.log(`Error handling message: ${error}`);\n console.error('❌ Error in handleIncomingMessage:', error);\n this.emit('error', { error, message });\n });\n });\n\n this.providers.set(provider.name, provider);\n this.log(`Provider added: ${provider.name}`);\n }\n\n /**\n * Create and register an agent\n */\n createAgent(config: AgentConfig): Agent {\n this.log(`Creating agent: ${config.name}`);\n const agent = new Agent(config);\n this.agents.set(agent.id, agent);\n this.log(`Agent created: ${config.name} (${agent.id})`);\n return agent;\n }\n\n /**\n * Add a skill (MCP server, etc.)\n */\n async addSkill(skill: Skill): Promise<void> {\n this.log(`Adding skill: ${skill.name}`);\n await skill.initialize();\n this.skills.set(skill.name, skill);\n this.log(`Skill added: ${skill.name}`);\n }\n\n async removeSkill(name: string): Promise<void> {\n const skill = this.skills.get(name);\n if (skill) {\n await skill.close();\n this.skills.delete(name);\n this.log(`Skill removed: ${name}`);\n }\n }\n\n /**\n * Start Operor\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n throw new Error('Operor is already running');\n }\n\n this.log('Starting Operor...');\n\n // Initialize memory store\n await this.memory.initialize();\n\n // Connect all providers\n const providerConnections = Array.from(this.providers.values()).map((p) =>\n p.connect()\n );\n\n await Promise.all(providerConnections);\n\n this.isRunning = true;\n this.log('✅ Operor started successfully');\n this.emit('started');\n }\n\n /**\n * Stop Operor\n */\n async stop(): Promise<void> {\n if (!this.isRunning) return;\n\n this.log('Stopping Operor...');\n\n // Clear pending batch timers\n for (const timer of this.batchTimers.values()) {\n clearTimeout(timer);\n }\n this.batchTimers.clear();\n this.messageBatches.clear();\n\n // Disconnect all providers\n const providerDisconnections = Array.from(this.providers.values()).map(\n (p) => p.disconnect()\n );\n\n await Promise.all(providerDisconnections);\n\n // Detach analytics collector\n if (this.config.analyticsCollector?.detach) {\n this.config.analyticsCollector.detach(this);\n }\n\n // Close memory store\n await this.memory.close();\n\n this.isRunning = false;\n this.log('Operor stopped');\n this.emit('stopped');\n }\n\n /**\n * Handle incoming message from any provider\n */\n private async handleIncomingMessage(\n message: IncomingMessage\n ): Promise<void> {\n this.log(`📱 Incoming message from ${message.from}: \"${message.text}\"`);\n\n // Emit message event\n this.emit('message:received', { message });\n\n // Add to batch (include groupJid to prevent cross-group batching)\n const groupJid = message.metadata?.groupJid;\n const batchKey = groupJid\n ? `${message.provider}:${message.from}:${groupJid}`\n : `${message.provider}:${message.from}`;\n if (!this.messageBatches.has(batchKey)) {\n this.messageBatches.set(batchKey, []);\n }\n this.messageBatches.get(batchKey)!.push(message);\n\n // Clear existing timer\n const existingTimer = this.batchTimers.get(batchKey);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // Set new timer to process batch\n const timer = setTimeout(() => {\n this.processBatch(batchKey).catch((error) => {\n this.log(`Error processing batch: ${error}`);\n console.error('❌ Error in processBatch:', error);\n });\n }, this.batchWindowMs);\n\n this.batchTimers.set(batchKey, timer);\n }\n\n /**\n * Process a batch of messages from the same sender\n */\n private async processBatch(batchKey: string): Promise<void> {\n const messages = this.messageBatches.get(batchKey);\n if (!messages || messages.length === 0) return;\n\n // Clear batch and timer\n this.messageBatches.delete(batchKey);\n this.batchTimers.delete(batchKey);\n\n // Combine messages into one\n const firstMessage = messages[0];\n const combinedText = messages.map((m) => m.text).join('\\n');\n const combinedMessage: IncomingMessage = {\n ...firstMessage,\n text: combinedText,\n };\n\n if (messages.length > 1) {\n this.log(`📦 Batched ${messages.length} messages: \"${combinedText}\"`);\n }\n\n // Pending quickstart interceptor — capture messages during /quickstart flow\n if (this.config.trainingMode?.enabled) {\n const pendingQs = this.pendingQuickstarts.get(combinedMessage.from);\n if (pendingQs) {\n const handled = await this.handlePendingQuickstart(combinedMessage, pendingQs);\n if (handled) return;\n }\n }\n\n // Pending skill add interceptor — capture env var values during /skill add flow\n const pendingSkill = this.pendingSkillAdds.get(combinedMessage.from);\n if (pendingSkill) {\n const handled = await this.handlePendingSkillAdd(combinedMessage, pendingSkill);\n if (handled) return;\n }\n\n // Pending edit interceptor — capture messages before training commands\n if (this.config.trainingMode?.enabled) {\n const pendingEdit = this.pendingEdits.get(combinedMessage.from);\n if (pendingEdit) {\n const handled = await this.handlePendingEdit(combinedMessage, pendingEdit);\n if (handled) return;\n }\n }\n\n // Pending FAQ replacement interceptor — handle \"yes\"/\"no\" for dedup prompt\n if (this.config.trainingMode?.enabled) {\n const faqKey = `faq_replace_${combinedMessage.from}`;\n const pending = this.pendingFaqReplacements.get(faqKey);\n if (pending && Date.now() < pending.expiresAt) {\n const text = combinedMessage.text.trim().toLowerCase();\n const kb = this.config.kb!;\n const provider = this.providers.values().next().value;\n const reply = async (t: string) => { if (provider) await provider.sendMessage(combinedMessage.from, t); };\n\n this.pendingFaqReplacements.delete(faqKey);\n if (text === 'yes') {\n await kb.ingestFaq(pending.question, pending.answer, { forceReplace: true, replaceId: pending.replaceId });\n await reply(`FAQ replaced:\\nQ: ${pending.question}\\nA: ${pending.answer}`);\n } else {\n await kb.ingestFaq(pending.question, pending.answer, { forceReplace: true });\n await reply(`Both FAQs kept. New FAQ added:\\nQ: ${pending.question}\\nA: ${pending.answer}`);\n }\n return;\n } else if (pending) {\n this.pendingFaqReplacements.delete(faqKey); // expired\n }\n }\n\n // Training mode interceptor — check before normal processing\n if (this.config.trainingMode?.enabled) {\n const senderPhone = combinedMessage.from;\n // Normalize comparison: strip leading '+' from both sides so\n // whitelist entry '+85253332683' matches from value '85253332683' and vice versa\n const normalizePhone = (p: string) => p.replace(/^\\+/, '');\n const normalizedSender = normalizePhone(senderPhone);\n const isWhitelisted = this.config.trainingMode.whitelist.some(\n (w) => normalizePhone(w) === normalizedSender\n );\n if (isWhitelisted) {\n const handled = await this.handleTrainingCommand(combinedMessage);\n if (handled) return;\n // Block unrecognized /commands from reaching the LLM (prevents hallucinated responses)\n if (combinedMessage.text.trim().startsWith('/')) {\n await this.sendMessage(combinedMessage.from, combinedMessage.provider, {\n to: combinedMessage.from,\n text: `Unknown command: ${combinedMessage.text.trim().split(/\\s+/)[0]}\\nType /help for available commands.`,\n });\n return;\n }\n }\n }\n\n try {\n // Send typing indicator while processing\n const provider = this.providers.get(combinedMessage.provider);\n if (provider?.sendTypingIndicator) {\n await provider.sendTypingIndicator(combinedMessage.from).catch(() => {});\n }\n\n // 1. Get or create customer\n const customer = await this.getOrCreateCustomer(combinedMessage);\n\n // 2. Load brief global history for intent classification (no agentId)\n const globalHistory = await this.memory.getHistory(customer.id, 5);\n\n // 3. Classify intent\n const intentStart = Date.now();\n const intent = await this.intentClassifier.classify(\n combinedMessage.text,\n Array.from(this.agents.values()).map(a => a.config),\n globalHistory\n );\n this.log(`🧠 Intent: ${intent.intent} (confidence: ${intent.confidence}) in ${((Date.now() - intentStart) / 1000).toFixed(1)}s`);\n\n // 4. Select appropriate agent (filtered by channel, sorted by priority)\n const agent = this.selectAgent(intent, combinedMessage);\n\n if (!agent) {\n this.log('⚠️ No agent matched the intent');\n await this.sendMessage(combinedMessage.from, combinedMessage.provider, {\n to: combinedMessage.from,\n text: \"Sorry, I couldn't understand that. Could you rephrase?\",\n });\n return;\n }\n\n this.log(`🤖 Agent selected: ${agent.name}`);\n\n // 4b. Check input guardrails\n const guardrails = agent.getConfig().guardrails;\n if (guardrails) {\n const guardrailEngine = new GuardrailEngine();\n const inputCheck = guardrailEngine.checkInput(combinedMessage.text, guardrails);\n if (!inputCheck.allowed) {\n this.log(`🛡️ Guardrail blocked input: ${inputCheck.reason}`);\n this.emit('guardrail:blocked', { message: combinedMessage, reason: inputCheck.reason, escalate: !!inputCheck.escalate });\n const replyText = inputCheck.escalate\n ? 'Let me connect you with a human agent for this.'\n : \"I'm not able to help with that topic. Is there something else I can assist you with?\";\n await this.sendMessage(combinedMessage.from, combinedMessage.provider, {\n to: combinedMessage.from,\n text: replyText,\n });\n return;\n }\n }\n\n // 5. Load full agent-scoped history for processing context\n const history = await this.memory.getHistory(customer.id, 50, agent.name);\n\n // 6. Build context\n const context: ConversationContext = {\n customer,\n history,\n currentMessage: combinedMessage,\n intent,\n };\n\n // 7. Process with agent\n const response = await agent.process(context);\n\n this.log(`✉️ Response generated in ${response.duration}ms`);\n\n // 7b. Check output guardrails\n const fullResponseText = response.text;\n if (guardrails) {\n const guardrailEngine = new GuardrailEngine();\n\n // Handle maxResponseLength — split into multiple messages at paragraph boundaries\n if (guardrails.maxResponseLength && response.text.length > guardrails.maxResponseLength) {\n const chunks = splitIntoParagraphChunks(response.text, guardrails.maxResponseLength);\n if (chunks.length > 1) {\n this.log(`📨 Splitting long response (${response.text.length}/${guardrails.maxResponseLength}) into ${chunks.length} messages`);\n // Send all chunks except the last one now\n for (let i = 0; i < chunks.length - 1; i++) {\n await this.sendMessage(combinedMessage.from, combinedMessage.provider, {\n to: combinedMessage.from,\n text: chunks[i],\n });\n }\n // The last chunk goes through the normal send path (with any media attachment)\n response.text = chunks[chunks.length - 1];\n } else {\n response.text = chunks[0];\n }\n }\n\n // Check other guardrails (blocked topics, etc.) — exclude length from this check\n const { maxResponseLength: _mrl, ...otherGuardrails } = guardrails;\n const hasOtherGuardrails = otherGuardrails.blockedTopics?.length || otherGuardrails.escalationTriggers?.length;\n if (hasOtherGuardrails) {\n const outputCheck = guardrailEngine.checkOutput(response.text, otherGuardrails);\n if (!outputCheck.allowed) {\n this.log(`🛡️ Guardrail blocked output: ${outputCheck.reason}`);\n this.emit('guardrail:output_blocked', { message: combinedMessage, reason: outputCheck.reason });\n response.text = 'I apologize, but I\\'m unable to provide that information.';\n }\n }\n }\n\n // Log tool calls\n if (response.toolCalls) {\n for (const toolCall of response.toolCalls) {\n this.log(\n `🔧 Tool: ${toolCall.name}(${JSON.stringify(toolCall.params)})`\n );\n if (toolCall.success) {\n this.log(` ✓ Success (${toolCall.duration}ms)`);\n } else {\n this.log(` ✗ Failed: ${toolCall.error}`);\n }\n }\n }\n\n // 8. Send response\n await this.sendMessage(combinedMessage.from, combinedMessage.provider, {\n to: combinedMessage.from,\n text: response.text,\n ...(response.mediaBuffer && {\n mediaBuffer: response.mediaBuffer,\n mediaFileName: response.mediaFileName,\n mediaMimeType: response.mediaMimeType,\n }),\n });\n\n // Log what was actually sent\n if (response.text) {\n this.log(`📤 Sent: \"${response.text.substring(0, 100)}${response.text.length > 100 ? '...' : ''}\"`);\n }\n\n // 9. Update conversation history (add all batched messages)\n for (const msg of messages) {\n await this.memory.addMessage(customer.id, {\n role: 'user',\n content: msg.text,\n timestamp: msg.timestamp,\n }, agent.name);\n }\n\n // 10. Auto-add assistant message to history if enabled\n if (this.autoAddAssistantMessages) {\n await this.memory.addMessage(customer.id, {\n role: 'assistant',\n content: fullResponseText,\n timestamp: Date.now(),\n toolCalls: response.toolCalls,\n }, agent.name);\n }\n\n // 11. Emit complete event\n this.emit('message:processed', {\n message: combinedMessage,\n response,\n agent: agent.name,\n intent,\n customer,\n toolCalls: response.toolCalls,\n duration: response.duration,\n cost: response.cost,\n });\n } catch (error) {\n this.log(`❌ Error processing message: ${error}`);\n this.emit('error', { error, message: combinedMessage });\n\n // Send error message to user\n await this.sendMessage(combinedMessage.from, combinedMessage.provider, {\n to: combinedMessage.from,\n text: 'Sorry, something went wrong. Please try again.',\n });\n }\n }\n\n /**\n * Get or create customer from message\n */\n private async getOrCreateCustomer(\n message: IncomingMessage\n ): Promise<Customer> {\n let customer = await this.memory.getCustomerByPhone(message.from);\n\n if (!customer) {\n customer = {\n id: `customer_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n phone: message.from,\n name: message.from,\n firstInteraction: new Date(),\n lastInteraction: new Date(),\n };\n\n if (message.channel === 'whatsapp') {\n customer.whatsappId = message.from;\n }\n\n await this.memory.upsertCustomer(customer);\n this.log(`👤 New customer: ${customer.id}`);\n } else {\n customer.lastInteraction = new Date();\n await this.memory.upsertCustomer(customer);\n }\n\n return customer;\n }\n\n /**\n * Handle training commands from whitelisted users.\n * Returns true if the message was a training command, false otherwise.\n */\n private async handleTrainingCommand(message: IncomingMessage): Promise<boolean> {\n const text = message.text.trim();\n\n // Must start with /\n if (!text.startsWith('/')) return false;\n\n const parts = text.split(/\\s+/);\n let command = parts[0].toLowerCase();\n const args = parts.slice(1);\n\n // Normalize aliases before validation\n const commandAliases: Record<string, string> = { '/skill': '/skills' };\n if (commandAliases[command]) command = commandAliases[command];\n\n const validCommands = ['/teach', '/faq', '/kb', '/test', '/status', '/stats', '/help', '/learn-url', '/learn-site', '/learn-file', '/rebuild', '/review', '/export', '/import', '/instructions', '/identity', '/soul', '/config', '/done', '/cancel', '/whitelist', '/quickstart', '/skills', '/model', '/create-skill', '/update-skill', '/clear-history'];\n if (!validCommands.includes(command)) return false;\n\n this.log(`🎓 Training command: ${command} ${args.join(' ')}`);\n\n // Emit training event for external handlers\n this.emit('training:command', { command, args, message });\n\n const reply = async (text: string) => {\n await this.sendMessage(message.from, message.provider, {\n to: message.from,\n text,\n });\n };\n\n const kb = this.config.kb;\n\n if (command === '/help') {\n const showAll = args[0] === 'all';\n\n if (showAll) {\n const helpLines = [\n 'Training commands:',\n ' /teach <question> | <answer> — Add FAQ entry',\n ' /learn-url <url> — Ingest a webpage into KB',\n ' /learn-site <url> — Crawl and ingest a website',\n ' /learn-file — Ingest an attached file (send with caption)',\n ' /faq list — List all FAQ entries',\n ' /faq search <query> — Search FAQ entries',\n ' /faq delete <id> — Delete an FAQ entry',\n ' /kb list [page] — List ingested documents (URLs, files)',\n ' /export — Export KB bundle as YAML file',\n ' /import — Import KB bundle from YAML file (send with caption)',\n ' /import <url> — Import KB bundle from a URL',\n ' /test <message> — Test KB response',\n ' /rebuild — Rebuild all KB embeddings (after switching provider)',\n ' /status — Show KB stats and bot status',\n ' /stats — 7-day performance summary',\n ' /stats today — Today\\'s performance',\n ' /stats kb — KB-specific analytics',\n ' /help — Show quick help',\n ' /help all — Show this full help message',\n ];\n helpLines.push('',\n 'Agent editor commands:',\n ' /instructions — View instructions summary',\n ' /instructions view [section] — View full or section',\n ' /instructions edit [section] — Edit instructions',\n ' /instructions history — Version history',\n ' /instructions rollback [n] — Revert to version n',\n ' /identity — View identity',\n ' /identity edit — Edit identity',\n ' /soul — View soul',\n ' /soul edit — Edit soul',\n ' /config show — View agent config',\n ' /config set <key> <value> — Set config field',\n ' /config add <key> <value> — Add to array field',\n ' /config remove <key> <value> — Remove from array field',\n ' /done — Finish editing (in edit mode)',\n ' /cancel — Cancel editing',\n );\n if (this.config.copilotHandler) {\n helpLines.push(' /review — Review unanswered questions (Copilot)');\n helpLines.push(' /review help — See all review commands');\n }\n helpLines.push('',\n 'Admin commands:',\n ' /whitelist — View whitelisted phone numbers',\n ' /whitelist add <phone> — Add a phone number',\n ' /whitelist remove <phone> — Remove a phone number',\n ' /clear-history — Clear your conversation history',\n );\n helpLines.push('',\n 'Skills:',\n ' /skills — List registered skills and tools',\n ' /skills info <name> — Show skill details',\n ' /skills catalog [category] — Browse available skills',\n ' /skills add <name> — Install a skill from the catalog',\n ' /skills remove <name> — Remove a skill',\n ' /create-skill <name> | <instructions> — Create a prompt skill',\n ' /update-skill <name> | <instructions> — Update a prompt skill',\n );\n helpLines.push('',\n 'Model management:',\n ' /model — Show current LLM provider and model',\n ' /model list — List available models per provider',\n ' /model set <provider/model> — Switch LLM model',\n ' /model key <provider> <key> — Add API key for a provider',\n );\n await reply(helpLines.join('\\n'));\n } else {\n const quickLines = [\n 'Quick start:',\n ' /teach <question> | <answer> — Add FAQ entry',\n ' /test <message> — Test how your bot responds',\n ' /status — Show bot status and KB stats',\n ' /learn-url <url> — Ingest a webpage',\n ' /learn-file — Ingest an attached document',\n ' /skills — List registered skills and tools',\n ' /skills catalog — Browse available skills',\n ' /quickstart — Guided first FAQ setup',\n ' /help all — See all commands',\n '',\n 'Example: /teach What are your hours? | We\\'re open 9am-5pm Mon-Fri',\n ];\n await reply(quickLines.join('\\n'));\n }\n return true;\n }\n\n // /quickstart command — guided 3-step FAQ teaching\n if (command === '/quickstart') {\n if (!kb) {\n await reply('Knowledge Base is not enabled. Set KB_ENABLED=true to use /quickstart.');\n return true;\n }\n this.pendingQuickstarts.set(message.from, {\n step: 'question',\n createdAt: Date.now(),\n });\n await reply('Let\\'s teach your agent its first FAQ!\\n\\nStep 1/3: What question do your customers ask?\\n\\n(Send the question, or /cancel to abort)');\n return true;\n }\n\n // /whitelist command — does NOT require KB\n if (command === '/whitelist') {\n await this.handleWhitelistCommand(message, args, reply);\n return true;\n }\n\n // /skills command — does NOT require KB\n if (command === '/skills') {\n await this.handleSkillsCommand(message, args, reply);\n return true;\n }\n\n // /create-skill and /update-skill commands — do NOT require KB\n if (command === '/create-skill') {\n await this.handleCreateSkillCommand(message, args, reply);\n return true;\n }\n if (command === '/update-skill') {\n await this.handleUpdateSkillCommand(message, args, reply);\n return true;\n }\n\n // Instruction editor commands — do NOT require KB\n if (command === '/instructions' || command === '/identity' || command === '/soul' || command === '/config' || command === '/done' || command === '/cancel') {\n try {\n if (command === '/instructions') {\n await this.handleInstructionsCommand(message, args, reply);\n } else if (command === '/identity') {\n await this.handleFieldViewOrEdit('identity', message, args, reply);\n } else if (command === '/soul') {\n await this.handleFieldViewOrEdit('soul', message, args, reply);\n } else if (command === '/config') {\n await this.handleConfigCommand(message, args, reply);\n } else {\n await reply('No active edit session. Use /instructions edit, /identity edit, or /soul edit to start.');\n }\n } catch (error: any) {\n this.log(`Training command error: ${error.message}`);\n await reply(`Error: ${error.message}`);\n }\n return true;\n }\n\n // /model command — does NOT require KB\n if (command === '/model') {\n try {\n await this.handleModelCommand(args, reply);\n } catch (error: any) {\n this.log(`Training command error: ${error.message}`);\n await reply(`Error: ${error.message}`);\n }\n return true;\n }\n\n // /clear-history command — does NOT require KB\n if (command === '/clear-history') {\n if (!this.memory?.clearHistory) {\n await reply('Clear history is not supported by the current memory store.');\n return true;\n }\n try {\n const customer = await this.memory.getCustomerByPhone?.(message.from);\n if (!customer) {\n await reply('No conversation history found for your number.');\n return true;\n }\n const { deletedCount } = await this.memory.clearHistory(customer.id);\n await reply(`Cleared ${deletedCount} message(s) from your conversation history.`);\n } catch (error: any) {\n this.log(`Training command error: ${error.message}`);\n await reply(`Error clearing history: ${error.message}`);\n }\n return true;\n }\n\n // All other commands require KB\n if (!kb) {\n await reply('Knowledge Base is not enabled. Set KB_ENABLED=true and configure embedding settings to use training commands.');\n return true;\n }\n\n // Copilot /review command — delegate to copilot handler\n if (command === '/review') {\n if (this.config.copilotHandler) {\n await this.config.copilotHandler.handleCommand(command, args.join(' '), message.from, reply);\n } else {\n await reply('Training Copilot is not available. If COPILOT_ENABLED=true is set, check startup logs for initialization errors.');\n }\n return true;\n }\n\n try {\n if (command === '/teach') {\n const raw = args.join(' ');\n const sepIndex = raw.indexOf('|');\n if (sepIndex === -1) {\n await reply('Usage: /teach <question> | <answer>');\n return true;\n }\n // Strip optional surrounding quotes so `/teach \"q\" | \"a\"` works the same as `/teach q | a`\n const stripQuotes = (s: string) => s.replace(/^[\"']|[\"']$/g, '');\n const question = stripQuotes(raw.slice(0, sepIndex).trim());\n const answer = stripQuotes(raw.slice(sepIndex + 1).trim());\n if (!question || !answer) {\n await reply('Usage: /teach <question> | <answer>');\n return true;\n }\n const doc = await kb.ingestFaq(question, answer);\n\n // FAQ dedup: if similar FAQ exists, prompt admin to confirm replacement\n if (doc.existingMatch) {\n const match = doc.existingMatch;\n // Store pending replacement info for this conversation\n const pendingKey = `faq_replace_${msg.from}`;\n this.pendingFaqReplacements.set(pendingKey, {\n question,\n answer,\n replaceId: match.id,\n expiresAt: Date.now() + 120_000, // 2 min TTL\n });\n await reply(\n `Similar FAQ already exists (${(match.score * 100).toFixed(0)}% match):\\n` +\n `Q: ${match.question}\\n` +\n `A: ${match.answer}\\n\\n` +\n `Reply \"yes\" to replace it with your new answer, or \"no\" to keep both.`\n );\n return true;\n }\n\n await reply(`FAQ added (${doc.id.slice(0, 8)}...):\\nQ: ${question}\\nA: ${answer}`);\n // Warn if answer uses \"you/your\" which may sound wrong from the bot's perspective\n const perspectivePattern = /\\b(your name|you are\\s+\\w+|you work|you're\\s+\\w+)\\b/i;\n if (perspectivePattern.test(answer)) {\n await reply(\n '⚠️ Heads up: This answer uses \"you/your\" which may sound odd coming from the bot. '\n + 'Consider rephrasing (e.g., \"my name is...\" instead of \"your name is...\").'\n );\n }\n }\n\n else if (command === '/faq') {\n const subcommand = args[0]?.toLowerCase();\n\n if (subcommand === 'list') {\n const docs = await kb.listDocuments();\n const faqs = docs.filter(d => d.sourceType === 'faq');\n if (faqs.length === 0) {\n await reply('No FAQ entries found.');\n } else {\n const lines = faqs.map(d =>\n `[${d.id.slice(0, 8)}] ${d.title || d.content.slice(0, 60)}`\n );\n await reply(`FAQ entries (${faqs.length}):\\n${lines.join('\\n')}`);\n }\n }\n\n else if (subcommand === 'search') {\n const query = args.slice(1).join(' ');\n if (!query) {\n await reply('Usage: /faq search <query>');\n return true;\n }\n const result = await kb.retrieve(query);\n if (result.results.length === 0) {\n await reply(`No results for \"${query}\".`);\n } else {\n const lines = result.results.slice(0, 5).map((r, i) =>\n `${i + 1}. [${r.score.toFixed(2)}] ${r.document.title || r.chunk.content.slice(0, 60)}`\n );\n await reply(`Search results for \"${query}\":\\n${lines.join('\\n')}`);\n }\n }\n\n else if (subcommand === 'delete') {\n const id = args[1];\n if (!id) {\n await reply('Usage: /faq delete <id>');\n return true;\n }\n // Support partial ID matching\n const docs = await kb.listDocuments();\n const match = docs.find(d => d.id === id || d.id.startsWith(id));\n if (!match) {\n await reply(`No document found with ID starting with \"${id}\".`);\n } else {\n await kb.deleteDocument(match.id);\n await reply(`Deleted: ${match.title || match.id.slice(0, 8)}`);\n }\n }\n\n else {\n await reply('Usage: /faq list | /faq search <query> | /faq delete <id>');\n }\n }\n\n else if (command === '/kb') {\n const subcommand = args[0]?.toLowerCase();\n\n if (subcommand === 'list') {\n const page = parseInt(args[1]) || 1;\n const PAGE_SIZE = 10;\n const docs = await kb.listDocuments();\n const nonFaq = docs.filter(d => d.sourceType !== 'faq');\n\n if (nonFaq.length === 0) {\n await reply('No KB documents found. Use /learn-url, /learn-site, or /learn-file to add content.');\n } else {\n const totalPages = Math.ceil(nonFaq.length / PAGE_SIZE);\n const safePage = Math.max(1, Math.min(page, totalPages));\n const slice = nonFaq.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE);\n\n const lines = slice.map(d => {\n const label = d.title || d.sourceUrl || d.fileName || d.content.slice(0, 60);\n const truncLabel = label.length > 60 ? label.slice(0, 57) + '...' : label;\n const source = d.sourceUrl\n ? `\\n ${d.sourceUrl.length > 60 ? d.sourceUrl.slice(0, 57) + '...' : d.sourceUrl}`\n : d.fileName ? `\\n ${d.fileName}` : '';\n return `[${d.id.slice(0, 8)}] ${d.sourceType} — ${truncLabel}${source}`;\n });\n\n let header = `KB Documents (${nonFaq.length} total`;\n if (totalPages > 1) header += `, page ${safePage}/${totalPages}`;\n header += '):';\n\n let msg = `${header}\\n${lines.join('\\n')}`;\n if (totalPages > 1 && safePage < totalPages) {\n msg += `\\n\\nSend /kb list ${safePage + 1} for next page.`;\n }\n await reply(msg);\n }\n } else {\n await reply('Unknown /kb command. Available: /kb list');\n }\n }\n\n else if (command === '/test') {\n const query = args.join(' ');\n if (!query) {\n await reply('Usage: /test <message>');\n return true;\n }\n const result = await kb.retrieve(query);\n if (result.results.length === 0) {\n await reply(`No KB match for: \"${query}\"`);\n } else {\n const top = result.results[0];\n const matchType = result.isFaqMatch ? 'FAQ direct match' : 'KB search';\n await reply(`Test: \"${query}\"\\nMatch type: ${matchType}\\nScore: ${top.score.toFixed(2)}\\nContent: ${top.chunk.content.slice(0, 200)}`);\n }\n }\n\n else if (command === '/stats') {\n const analyticsStore = this.getAnalyticsStore();\n if (!analyticsStore) {\n await reply('Analytics is not enabled. Set ANALYTICS_ENABLED=true to track metrics.');\n return true;\n }\n\n const subcommand = args[0]?.toLowerCase();\n\n if (subcommand === 'kb') {\n // KB-specific analytics\n const now = Date.now();\n const range = { from: now - 7 * 24 * 60 * 60 * 1000, to: now };\n const kbStats = await analyticsStore.getKbStats(range);\n const total = kbStats.totalQueries;\n\n const lines = [\n '📚 *KB Analytics (last 7 days)*',\n '',\n `🔍 ${total} total queries`,\n ];\n\n if (total > 0) {\n const faqPct = kbStats.faqHitRate.toFixed(0);\n const nonFaqCount = total - kbStats.faqHits;\n const hybridPct = ((nonFaqCount / total) * 100).toFixed(0);\n const missCount = kbStats.topMisses?.reduce((s: number, m: any) => s + m.count, 0) || 0;\n const noMatchPct = ((missCount / total) * 100).toFixed(0);\n\n lines.push(`⚡ FAQ fast-path: ${faqPct}%`);\n lines.push(`🔄 Hybrid search: ${hybridPct}%`);\n lines.push(`❌ No match: ${noMatchPct}%`);\n lines.push(`📊 Avg top score: ${kbStats.avgTopScore.toFixed(2)}`);\n }\n\n if (kbStats.topFaqHits && kbStats.topFaqHits.length > 0) {\n lines.push('');\n lines.push('🎯 *Top FAQ hits:*');\n for (const hit of kbStats.topFaqHits.slice(0, 5)) {\n lines.push(` ${hit.count}x — ${hit.intent}`);\n }\n }\n\n if (kbStats.topMisses && kbStats.topMisses.length > 0) {\n lines.push('');\n lines.push('❓ *Top misses:*');\n for (const miss of kbStats.topMisses.slice(0, 5)) {\n lines.push(` ${miss.count}x [${miss.avgScore.toFixed(2)}] — ${miss.intent}`);\n }\n }\n\n await reply(lines.join('\\n'));\n } else {\n // General stats — /stats or /stats today\n const isToday = subcommand === 'today';\n const now = Date.now();\n const range = isToday\n ? { from: new Date(new Date().setHours(0, 0, 0, 0)).getTime(), to: now }\n : { from: now - 7 * 24 * 60 * 60 * 1000, to: now };\n\n const summary = await analyticsStore.getSummary(range);\n const label = isToday ? 'today' : 'last 7 days';\n\n const noAnswerCount = Math.round((summary.noAnswerPct / 100) * summary.totalMessages);\n const avgPerDay = Math.round(summary.avgPerDay);\n\n const lines = [\n `📊 *Bot Performance (${label})*`,\n '',\n `💬 ${summary.totalMessages} messages from ${summary.uniqueCustomers} customers`,\n ];\n\n if (!isToday && summary.totalMessages > 0 && summary.peakDay) {\n const peakLabel = this.formatDayName(summary.peakDay);\n lines.push(`📈 Avg ${avgPerDay}/day — busiest: ${peakLabel}`);\n }\n\n lines.push('');\n lines.push(`✅ ${summary.kbAnsweredPct.toFixed(0)}% answered by KB`);\n lines.push(`🤖 ${summary.llmFallbackPct.toFixed(0)}% needed LLM`);\n lines.push(`❌ ${summary.noAnswerPct.toFixed(0)}% couldn't answer (${noAnswerCount} msgs)`);\n lines.push('');\n lines.push(`⚡ Avg response: ${(summary.avgResponseTime / 1000).toFixed(1)}s`);\n lines.push(`🎯 FAQ hit rate: ${summary.faqHitRate.toFixed(0)}%`);\n lines.push('');\n lines.push(`👥 ${summary.newCustomers} new customers${isToday ? ' today' : ' this week'}`);\n lines.push(`🔄 ${summary.returningCustomers} returning customers`);\n\n if (summary.pendingReviews > 0) {\n lines.push('');\n lines.push(`📋 ${summary.pendingReviews} questions pending review`);\n lines.push('→ /review to start teaching');\n }\n\n await reply(lines.join('\\n'));\n }\n }\n\n else if (command === '/status') {\n const stats = await kb.getStats();\n const statusLines = [\n '📦 *Knowledge Base Status:*',\n ` Documents: ${stats.documentCount}`,\n ` Chunks: ${stats.chunkCount}`,\n ` Embedding dimensions: ${stats.embeddingDimensions}`,\n ` DB size: ${(stats.dbSizeBytes / 1024).toFixed(1)} KB`,\n ];\n\n // Append bot usage summary from analytics if available\n const analyticsStore = this.getAnalyticsStore();\n if (analyticsStore) {\n try {\n const summary = await analyticsStore.getSummary();\n statusLines.push('');\n statusLines.push('🤖 *Bot Status:*');\n statusLines.push(` Total messages processed: ${summary.totalMessages}`);\n statusLines.push(` Unique customers: ${summary.uniqueCustomers}`);\n if (summary.pendingReviews > 0) {\n statusLines.push(` Pending reviews: ${summary.pendingReviews}`);\n }\n const uptime = process.uptime();\n const uptimeStr = uptime >= 86400\n ? `${Math.floor(uptime / 86400)}d ${Math.floor((uptime % 86400) / 3600)}h`\n : uptime >= 3600\n ? `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m`\n : `${Math.floor(uptime / 60)}m`;\n statusLines.push(` Uptime: ${uptimeStr}`);\n } catch {\n // Analytics query failed — skip silently\n }\n }\n\n await reply(statusLines.join('\\n'));\n }\n\n else if (command === '/learn-url') {\n const url = args[0];\n if (!url) {\n await reply('Usage: /learn-url <url>');\n return true;\n }\n if (!kb.ingestUrl) {\n await reply('URL ingestion is not available. Ensure the KB runtime supports ingestUrl.');\n return true;\n }\n try {\n new URL(url);\n } catch {\n await reply(`Invalid URL: ${url}`);\n return true;\n }\n await reply(`Ingesting URL: ${url}...`);\n const result = await kb.ingestUrl(url);\n const countLabel = (result as any).faqCount ? `${(result as any).faqCount} Q&A pairs` : `${result.chunks} chunks`;\n await reply(`Done! Added \"${result.title || url}\" (${countLabel}).`);\n }\n\n else if (command === '/learn-site') {\n const url = args[0];\n if (!url) {\n await reply('Usage: /learn-site <url>');\n return true;\n }\n if (!kb.ingestSite) {\n await reply('Site ingestion is not available. Ensure the KB runtime supports ingestSite.');\n return true;\n }\n try {\n new URL(url);\n } catch {\n await reply(`Invalid URL: ${url}`);\n return true;\n }\n await reply(`Crawling site: ${url} (this may take a while)...`);\n let lastProgressUpdate = 0;\n const result = await kb.ingestSite(url, {\n maxDepth: 2,\n maxPages: 50,\n onProgress: (crawled, total, pageUrl) => {\n // Send progress update every 5 pages\n if (crawled - lastProgressUpdate >= 5) {\n lastProgressUpdate = crawled;\n const shortUrl = pageUrl.length > 60 ? pageUrl.slice(0, 57) + '...' : pageUrl;\n reply(`Crawling page ${crawled}/${total}: ${shortUrl}`);\n }\n },\n });\n await reply(`Done! Crawled ${result.documents} pages (${result.chunks} total chunks).`);\n }\n\n else if (command === '/learn-file') {\n if (!kb.ingestFile) {\n await reply('File ingestion is not available. Ensure the KB runtime supports ingestFile.');\n return true;\n }\n if (!message.mediaBuffer || !message.mediaFileName) {\n await reply('No file attached. Send a document (PDF, DOCX, TXT, CSV, etc.) with /learn-file as the caption.');\n return true;\n }\n await reply(`Ingesting file: ${message.mediaFileName}...`);\n const result = await kb.ingestFile(message.mediaBuffer, message.mediaFileName);\n await reply(`Done! Added \"${result.title || message.mediaFileName}\" (${result.chunks} chunks).`);\n }\n\n else if (command === '/rebuild') {\n if (!kb.rebuild) {\n await reply('Rebuild is not available. Ensure the KB runtime supports rebuild.');\n return true;\n }\n await reply('Rebuilding KB embeddings... This may take a while.');\n const result = await kb.rebuild();\n await reply([\n 'Rebuild complete!',\n ` Documents: ${result.documentsRebuilt}`,\n ` Chunks: ${result.chunksRebuilt}`,\n ` Old dimensions: ${result.oldDimensions}`,\n ` New dimensions: ${result.newDimensions}`,\n ].join('\\n'));\n }\n\n else if (command === '/export') {\n await this.handleExportCommand(message, args);\n }\n\n else if (command === '/import') {\n await this.handleImportCommand(message, args);\n }\n\n } catch (error: any) {\n this.log(`Training command error: ${error.message}`);\n await reply(`Error: ${error.message}`);\n }\n\n return true;\n }\n\n /**\n * Handle /export command — generates YAML bundle and sends as file attachment\n */\n private async handleExportCommand(message: IncomingMessage, args: string[]): Promise<void> {\n const kb = this.config.kb!;\n\n const reply = async (text: string) => {\n await this.sendMessage(message.from, message.provider, {\n to: message.from,\n text,\n });\n };\n\n const replyWithFile = async (text: string, buffer: Buffer, fileName: string, mimeType: string) => {\n await this.sendMessage(message.from, message.provider, {\n to: message.from,\n text,\n mediaBuffer: buffer,\n mediaFileName: fileName,\n mediaMimeType: mimeType,\n });\n };\n\n try {\n await reply('Generating export bundle...');\n\n // Gather KB data\n const docs = await kb.listDocuments();\n const faqs = docs.filter(d => d.sourceType === 'faq');\n const nonFaqDocs = docs.filter(d => d.sourceType !== 'faq');\n\n // Extract FAQ question/answer pairs\n const faqEntries = faqs.map(d => {\n const content = d.content;\n const aIndex = content.indexOf('\\nA: ');\n if (aIndex !== -1 && content.startsWith('Q: ')) {\n return {\n question: content.slice(3, aIndex).trim(),\n answer: content.slice(aIndex + 4).trim(),\n };\n }\n // Fallback: use title as question, full content as answer\n return { question: (d.title || content).trim(), answer: content.trim() };\n });\n\n // Extract document references (no full content — too large)\n const documentRefs = nonFaqDocs.map(d => {\n const ref: Record<string, any> = {\n title: d.title || undefined,\n sourceType: d.sourceType,\n };\n if (d.sourceUrl) ref.sourceUrl = d.sourceUrl;\n if (d.fileName) ref.fileName = d.fileName;\n return ref;\n });\n\n // Get first agent's config for metadata\n const agentList = Array.from(this.agents.values());\n const firstAgent = agentList[0];\n const agentConfig = firstAgent?.getConfig();\n\n // Build the export bundle\n const bundle: Record<string, any> = {\n version: 1,\n exported_at: new Date().toISOString(),\n };\n\n if (agentConfig) {\n const agentSection: Record<string, any> = { name: agentConfig.name };\n if (agentConfig.purpose) agentSection.purpose = agentConfig.purpose;\n if (agentConfig.triggers?.length) agentSection.triggers = agentConfig.triggers;\n if (agentConfig.channels?.length) agentSection.channels = agentConfig.channels;\n if (agentConfig.skills?.length) agentSection.skills = agentConfig.skills;\n if (agentConfig.knowledgeBase != null) agentSection.knowledgeBase = agentConfig.knowledgeBase;\n if (agentConfig.priority != null) agentSection.priority = agentConfig.priority;\n if (agentConfig.escalateTo) agentSection.escalateTo = agentConfig.escalateTo;\n if (agentConfig._rawInstructions) agentSection.instructions = agentConfig._rawInstructions;\n if (agentConfig._rawIdentity) agentSection.identity = agentConfig._rawIdentity;\n if (agentConfig._rawSoul) agentSection.soul = agentConfig._rawSoul;\n bundle.agent = agentSection;\n\n if (agentConfig.guardrails) {\n const g: Record<string, any> = {};\n if (agentConfig.guardrails.blockedTopics?.length) g.blockedTopics = agentConfig.guardrails.blockedTopics;\n if (agentConfig.guardrails.systemRules?.length) g.systemRules = agentConfig.guardrails.systemRules;\n if (agentConfig.guardrails.escalationTriggers?.length) g.escalationTriggers = agentConfig.guardrails.escalationTriggers;\n if (agentConfig.guardrails.maxResponseLength) g.maxResponseLength = agentConfig.guardrails.maxResponseLength;\n if (Object.keys(g).length > 0) bundle.guardrails = g;\n }\n }\n\n bundle.faqs = faqEntries;\n if (documentRefs.length > 0) {\n bundle.documents = documentRefs;\n }\n\n // Include prompt skills from registered skills\n const promptSkills = Array.from(this.skills.values())\n .filter((s) => typeof (s as any).getContent === 'function')\n .map((s) => {\n const cfg = (s as any).getConfig?.() || {};\n const entry: Record<string, any> = { name: s.name, content: (s as any).getContent() };\n if (cfg.summary) entry.summary = cfg.summary;\n if (cfg.tags?.length) entry.tags = cfg.tags;\n if (cfg.author) entry.author = cfg.author;\n return entry;\n });\n if (promptSkills.length > 0) {\n bundle.promptSkills = promptSkills;\n }\n\n const yamlStr = '# operor-export-v1\\n' + yaml.dump(bundle, { lineWidth: -1, noRefs: true });\n const yamlBuffer = Buffer.from(yamlStr, 'utf-8');\n const fileName = `operor-export-${new Date().toISOString().slice(0, 10)}.yaml`;\n\n // Check if /export gist was requested\n if (args[0]?.toLowerCase() === 'gist') {\n const token = process.env.GITHUB_GIST_TOKEN;\n if (!token) {\n await reply('GitHub token not configured. Set GITHUB_GIST_TOKEN env var to use /export gist.');\n return;\n }\n try {\n const res = await fetch('https://api.github.com/gists', {\n method: 'POST',\n headers: {\n 'Authorization': `token ${token}`,\n 'Content-Type': 'application/json',\n 'Accept': 'application/vnd.github.v3+json',\n },\n body: JSON.stringify({\n description: `Operor Export - ${new Date().toISOString().slice(0, 10)}`,\n public: false,\n files: { [fileName]: { content: yamlStr } },\n }),\n });\n if (!res.ok) {\n const errText = await res.text();\n await reply(`GitHub Gist creation failed (${res.status}): ${errText.slice(0, 200)}`);\n return;\n }\n const gist = await res.json() as { html_url: string; files: Record<string, { raw_url: string }> };\n const rawUrl = gist.files[fileName]?.raw_url || gist.html_url;\n await reply([\n `Export published to GitHub Gist!`,\n `${faqEntries.length} FAQs, ${documentRefs.length} document references.`,\n ``,\n `View: ${gist.html_url}`,\n `Import URL: ${rawUrl}`,\n ``,\n `Share this URL with others: /import ${rawUrl}`,\n ].join('\\n'));\n } catch (err: any) {\n await reply(`Error creating GitHub Gist: ${err.message}`);\n }\n return;\n }\n\n // Send as file attachment\n await replyWithFile(\n `Export complete! ${faqEntries.length} FAQs, ${documentRefs.length} document references.`,\n yamlBuffer,\n fileName,\n 'text/yaml',\n );\n } catch (error: any) {\n this.log(`Export error: ${error.message}`);\n await reply(`Error: ${error.message}`);\n }\n }\n\n /**\n * Handle /import command — imports YAML bundle from file attachment or URL\n */\n private async handleImportCommand(message: IncomingMessage, args: string[]): Promise<void> {\n const kb = this.config.kb!;\n\n const reply = async (text: string) => {\n await this.sendMessage(message.from, message.provider, {\n to: message.from,\n text,\n });\n };\n\n try {\n let yamlStr: string | null = null;\n\n // Option 1: File attachment\n if (message.mediaBuffer && message.mediaFileName) {\n yamlStr = message.mediaBuffer.toString('utf-8');\n }\n // Option 2: URL argument\n else if (args[0]) {\n const url = args[0];\n try {\n new URL(url);\n } catch {\n await reply(`Invalid URL: ${url}`);\n return;\n }\n await reply(`Fetching bundle from ${url}...`);\n const res = await fetch(url);\n if (!res.ok) {\n await reply(`Failed to fetch URL (${res.status}): ${res.statusText}`);\n return;\n }\n yamlStr = await res.text();\n }\n // No input provided\n else {\n await reply('Usage: /import <url> — or send a YAML file with /import as caption.');\n return;\n }\n\n // Parse and validate YAML\n let bundle: any;\n try {\n bundle = yaml.load(yamlStr);\n } catch (err: any) {\n await reply(`Invalid YAML: ${err.message}`);\n return;\n }\n\n if (!bundle || typeof bundle !== 'object') {\n await reply('Invalid bundle: expected a YAML object.');\n return;\n }\n\n if (bundle.version !== 1) {\n await reply(`Unsupported bundle version: ${bundle.version}. Expected version 1.`);\n return;\n }\n\n const faqs = bundle.faqs;\n if (!Array.isArray(faqs)) {\n await reply('Invalid bundle: missing or invalid \"faqs\" array.');\n return;\n }\n\n // Import FAQs\n await reply(`Importing ${faqs.length} FAQs...`);\n let imported = 0;\n let skipped = 0;\n for (const faq of faqs) {\n const question = typeof faq.question === 'string' ? faq.question.trim() : '';\n const answer = typeof faq.answer === 'string' ? faq.answer.trim() : '';\n if (question && answer) {\n await kb.ingestFaq(question, answer);\n imported++;\n } else {\n skipped++;\n }\n }\n\n // Summarize document references\n const docRefs = Array.isArray(bundle.documents) ? bundle.documents : [];\n const urlRefs = docRefs.filter((d: any) => d.sourceType === 'url' && d.sourceUrl);\n\n const lines = [`Import complete! ${imported} FAQs imported.`];\n if (skipped > 0) lines.push(`${skipped} FAQs skipped (missing question or answer).`);\n if (docRefs.length > 0) {\n lines.push(`${docRefs.length} document reference(s) found:`);\n for (const ref of docRefs) {\n if (ref.sourceUrl) {\n lines.push(` - ${ref.title || ref.sourceUrl} (${ref.sourceType})`);\n } else if (ref.fileName) {\n lines.push(` - ${ref.fileName} (${ref.sourceType})`);\n }\n }\n if (urlRefs.length > 0) {\n lines.push(`\\nTo re-ingest URLs, send /learn-url for each.`);\n }\n }\n\n // Import agent instructions if present\n const bundleAgent = bundle.agent;\n if (bundleAgent && (bundleAgent.instructions || bundleAgent.identity || bundleAgent.soul)) {\n const agentsDir = this.config.agentsDir;\n const agentName = bundleAgent.name || 'support';\n\n if (agentsDir) {\n // Write agent files to disk\n const agentDir = path.join(agentsDir, agentName);\n await fs.mkdir(agentDir, { recursive: true });\n\n // Reconstruct INSTRUCTIONS.md with YAML frontmatter\n if (bundleAgent.instructions) {\n const frontmatter: Record<string, any> = { name: agentName };\n if (bundleAgent.purpose) frontmatter.purpose = bundleAgent.purpose;\n if (bundleAgent.triggers?.length) frontmatter.triggers = bundleAgent.triggers;\n if (bundleAgent.channels?.length) frontmatter.channels = bundleAgent.channels;\n if (bundleAgent.skills?.length) frontmatter.skills = bundleAgent.skills;\n if (bundleAgent.knowledgeBase != null) frontmatter.knowledgeBase = bundleAgent.knowledgeBase;\n if (bundleAgent.priority != null) frontmatter.priority = bundleAgent.priority;\n if (bundleAgent.escalateTo) frontmatter.escalateTo = bundleAgent.escalateTo;\n if (bundle.guardrails) frontmatter.guardrails = bundle.guardrails;\n\n const yamlFrontmatter = yaml.dump(frontmatter, { lineWidth: -1, noRefs: true }).trim();\n const instructionsContent = `---\\n${yamlFrontmatter}\\n---\\n\\n${bundleAgent.instructions.trim()}\\n`;\n await fs.writeFile(path.join(agentDir, 'INSTRUCTIONS.md'), instructionsContent, 'utf-8');\n }\n\n if (bundleAgent.identity) {\n await fs.writeFile(path.join(agentDir, 'IDENTITY.md'), bundleAgent.identity.trim() + '\\n', 'utf-8');\n }\n\n if (bundleAgent.soul) {\n await fs.writeFile(path.join(agentDir, 'SOUL.md'), bundleAgent.soul.trim() + '\\n', 'utf-8');\n }\n\n lines.push(`Agent instructions written to ${agentDir}.`);\n } else {\n // No agentsDir — update the in-memory agent's config\n const agentList = Array.from(this.agents.values());\n const targetAgent = agentList.find(a => a.getConfig().name === agentName) || agentList[0];\n if (targetAgent) {\n // Mutate the agent's config directly — getConfig() returns a shallow copy,\n // so we must use the public config property to persist changes.\n if (bundleAgent.instructions) targetAgent.config._rawInstructions = bundleAgent.instructions;\n if (bundleAgent.identity) targetAgent.config._rawIdentity = bundleAgent.identity;\n if (bundleAgent.soul) targetAgent.config._rawSoul = bundleAgent.soul;\n lines.push('Agent instructions applied in-memory.');\n }\n }\n }\n\n // Import prompt skills if present\n if (Array.isArray(bundle.promptSkills) && bundle.promptSkills.length > 0) {\n const mod = this.config.skillsModule;\n if (mod) {\n try {\n const skillsConfig = mod.loadSkillsConfig();\n let added = 0;\n for (const ps of bundle.promptSkills) {\n if (!ps.name || !ps.content) continue;\n if (skillsConfig.skills.find((s: any) => s.name === ps.name)) continue;\n skillsConfig.skills.push({ type: 'prompt', name: ps.name, content: ps.content, summary: ps.summary, tags: ps.tags, author: ps.author, enabled: true });\n added++;\n }\n if (added > 0) {\n mod.saveSkillsConfig(skillsConfig);\n lines.push(`${added} prompt skill(s) imported to mcp.json.`);\n }\n } catch (err: any) {\n lines.push(`Warning: failed to import prompt skills: ${err.message}`);\n }\n }\n }\n\n await reply(lines.join('\\n'));\n } catch (error: any) {\n this.log(`Import error: ${error.message}`);\n await reply(`Error: ${error.message}`);\n }\n }\n\n /**\n * Handle messages when sender has an active edit session.\n */\n private async handlePendingEdit(message: IncomingMessage, edit: PendingEdit): Promise<boolean> {\n const text = message.text.trim();\n const reply = async (t: string) => {\n await this.sendMessage(message.from, message.provider, { to: message.from, text: t });\n };\n\n // Check TTL (2 minutes)\n if (Date.now() - edit.createdAt > 120_000) {\n this.pendingEdits.delete(message.from);\n await reply('Edit session expired (2 min timeout). Start again with /instructions edit, /identity edit, or /soul edit.');\n return true;\n }\n\n if (edit.state === 'confirming') {\n if (text.toLowerCase() === 'yes') {\n await this.applyEdit(message.from, edit, reply);\n } else {\n this.pendingEdits.delete(message.from);\n await reply('Edit cancelled.');\n }\n return true;\n }\n\n // State: capturing\n if (text === '/cancel') {\n this.pendingEdits.delete(message.from);\n await reply('Edit cancelled.');\n return true;\n }\n\n if (text === '/done') {\n const newContent = edit.content.join('\\n');\n const agent = this.getFirstAgent();\n if (!agent) { await reply('No agent found.'); return true; }\n\n const fieldMap = { instructions: '_rawInstructions', identity: '_rawIdentity', soul: '_rawSoul' } as const;\n const current = (agent.config as any)[fieldMap[edit.field]] || '(empty)';\n\n let currentDisplay = current;\n let newDisplay = newContent;\n if (edit.field === 'instructions' && edit.section) {\n currentDisplay = this.extractSection(current, edit.section) || '(section not found)';\n newDisplay = newContent;\n }\n\n // Truncate for display\n const maxDisplay = 1500;\n if (currentDisplay.length > maxDisplay) currentDisplay = currentDisplay.slice(0, maxDisplay) + '\\n...';\n if (newDisplay.length > maxDisplay) newDisplay = newDisplay.slice(0, maxDisplay) + '\\n...';\n\n edit.state = 'confirming';\n await reply(`*CURRENT ${edit.field}${edit.section ? ` (${edit.section})` : ''}:*\\n${currentDisplay}\\n\\n*NEW:*\\n${newDisplay}\\n\\nSend \"yes\" to apply or anything else to cancel.`);\n return true;\n }\n\n // Capture content\n edit.content.push(text);\n return true;\n }\n\n /**\n * Apply a confirmed edit.\n */\n private async applyEdit(sender: string, edit: PendingEdit, reply: (t: string) => Promise<void>): Promise<void> {\n this.pendingEdits.delete(sender);\n const agent = this.getFirstAgent();\n if (!agent) { await reply('No agent found.'); return; }\n\n const newContent = edit.content.join('\\n');\n const fieldMap = { instructions: '_rawInstructions', identity: '_rawIdentity', soul: '_rawSoul' } as const;\n const rawKey = fieldMap[edit.field];\n\n // Save version before editing\n await this.versionStore.saveVersion(edit.agentName, {\n timestamp: new Date().toISOString(),\n instructions: agent.config._rawInstructions,\n identity: agent.config._rawIdentity,\n soul: agent.config._rawSoul,\n frontmatter: this.extractFrontmatter(agent.config),\n editedBy: sender,\n changeDescription: `Edit ${edit.field}${edit.section ? ` section \"${edit.section}\"` : ''}`,\n });\n\n // Apply edit\n if (edit.field === 'instructions' && edit.section) {\n const current = agent.config._rawInstructions || '';\n agent.config._rawInstructions = this.replaceSection(current, edit.section, newContent);\n } else {\n (agent.config as any)[rawKey] = newContent;\n }\n\n // Rebuild system prompt\n this.rebuildAgentSystemPrompt(agent);\n\n // Write to disk if agentsDir configured\n await this.writeAgentFiles(edit.agentName, agent);\n\n await reply(`${edit.field} updated successfully.`);\n }\n\n /**\n * Handle messages when sender has an active /quickstart session.\n */\n private async handlePendingQuickstart(message: IncomingMessage, qs: PendingQuickstart): Promise<boolean> {\n const text = message.text.trim();\n const reply = async (t: string) => {\n await this.sendMessage(message.from, message.provider, { to: message.from, text: t });\n };\n\n // Check TTL (2 minutes)\n if (Date.now() - qs.createdAt > 120_000) {\n this.pendingQuickstarts.delete(message.from);\n await reply('Quickstart session expired (2 min timeout). Send /quickstart to try again.');\n return true;\n }\n\n if (text === '/cancel') {\n this.pendingQuickstarts.delete(message.from);\n await reply('Quickstart cancelled.');\n return true;\n }\n\n const kb = this.config.kb;\n if (!kb) {\n this.pendingQuickstarts.delete(message.from);\n await reply('Knowledge Base is not available.');\n return true;\n }\n\n if (qs.step === 'question') {\n qs.question = text;\n qs.step = 'answer';\n qs.createdAt = Date.now(); // reset TTL\n await reply(`Got it!\\n\\nStep 2/3: What should the agent answer?\\n\\nQ: \"${text}\"\\n\\n(Send the answer, or /cancel to abort)`);\n return true;\n }\n\n if (qs.step === 'answer') {\n const question = qs.question!;\n const answer = text;\n this.pendingQuickstarts.delete(message.from);\n\n // Step 3: auto-teach + auto-test\n try {\n const doc = await kb.ingestFaq(question, answer);\n const result = await kb.retrieve(question);\n const top = result.results[0];\n const score = top ? top.score.toFixed(2) : 'N/A';\n const matchType = result.isFaqMatch ? 'FAQ direct match' : 'KB search';\n\n await reply([\n 'Step 3/3: Teaching & testing...',\n '',\n `FAQ added (${doc.id.slice(0, 8)}...)`,\n ` Q: ${question}`,\n ` A: ${answer}`,\n '',\n `Test result: ${matchType} (score: ${score})`,\n '',\n 'Your agent just learned its first answer! Try sending the question as a regular message to see it in action.',\n '',\n 'Next steps:',\n ' /teach <question> | <answer> — add more FAQs',\n ' /test <message> — test KB responses',\n ' /help — see all commands',\n ].join('\\n'));\n } catch (error: any) {\n await reply(`Error during quickstart: ${error.message}`);\n }\n return true;\n }\n\n return false;\n }\n\n /**\n * Add assistant response to conversation history (public API for manual use)\n */\n async addAssistantMessage(customerId: string, text: string, toolCalls?: any[]): Promise<void> {\n await this.memory.addMessage(customerId, {\n role: 'assistant',\n content: text,\n timestamp: Date.now(),\n toolCalls,\n });\n }\n\n private async handleInstructionsCommand(message: IncomingMessage, args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n const agent = this.getFirstAgent();\n if (!agent) { await reply('No agent found.'); return; }\n const sub = args[0]?.toLowerCase();\n const raw = agent.config._rawInstructions || '';\n\n if (sub === 'edit') {\n const section = args.slice(1).join(' ') || undefined;\n this.pendingEdits.set(message.from, {\n agentName: agent.config.name, field: 'instructions', section,\n content: [], createdAt: Date.now(), state: 'capturing',\n });\n const label = section ? `section \"${section}\"` : 'full instructions';\n await reply(`Editing ${label}. Send your new content, then /done to apply or /cancel to abort. (2 min timeout)`);\n return;\n }\n\n if (sub === 'view') {\n const section = args.slice(1).join(' ') || undefined;\n let content = section ? (this.extractSection(raw, section) || `Section \"${section}\" not found.`) : raw;\n if (!content.trim()) { await reply('Instructions are empty.'); return; }\n // Paginate at 2500 chars\n if (content.length > 2500) {\n await reply(content.slice(0, 2500) + '\\n\\n(truncated — send /instructions view again for full)');\n } else {\n await reply(content);\n }\n return;\n }\n\n if (sub === 'history') {\n const history = await this.versionStore.getHistory(agent.config.name, 10);\n if (history.length === 0) { await reply('No version history.'); return; }\n const lines = history.map((v, i) =>\n `${i}. ${v.timestamp} — ${v.changeDescription || 'no description'}${v.editedBy ? ` (by ${v.editedBy})` : ''}`\n );\n await reply(`Version history:\\n${lines.join('\\n')}`);\n return;\n }\n\n if (sub === 'rollback') {\n const n = args[1] != null ? parseInt(args[1]) : 0;\n const version = await this.versionStore.getVersion(agent.config.name, n);\n if (!version) { await reply(`Version ${n} not found.`); return; }\n\n // Save current as new version before rollback\n await this.versionStore.saveVersion(agent.config.name, {\n timestamp: new Date().toISOString(),\n instructions: agent.config._rawInstructions,\n identity: agent.config._rawIdentity,\n soul: agent.config._rawSoul,\n frontmatter: this.extractFrontmatter(agent.config),\n editedBy: message.from,\n changeDescription: `Rollback to version ${n}`,\n });\n\n if (version.instructions !== undefined) agent.config._rawInstructions = version.instructions;\n if (version.identity !== undefined) agent.config._rawIdentity = version.identity;\n if (version.soul !== undefined) agent.config._rawSoul = version.soul;\n this.rebuildAgentSystemPrompt(agent);\n await this.writeAgentFiles(agent.config.name, agent);\n await reply(`Rolled back to version ${n} (${version.timestamp}).`);\n return;\n }\n\n // Default: summary — show sections list\n if (!raw.trim()) { await reply('Instructions are empty.'); return; }\n const sections = this.parseSections(raw);\n if (sections.length === 0) {\n await reply(`Instructions (${raw.length} chars):\\n${raw.slice(0, 500)}${raw.length > 500 ? '\\n...' : ''}`);\n } else {\n const lines = sections.map(s => ` ${s.heading} (${s.content.length} chars)`);\n await reply(`Instructions sections:\\n${lines.join('\\n')}\\n\\nUse /instructions view [section] to see details.`);\n }\n }\n\n private async handleFieldViewOrEdit(\n field: 'identity' | 'soul', message: IncomingMessage, args: string[], reply: (t: string) => Promise<void>,\n ): Promise<void> {\n const agent = this.getFirstAgent();\n if (!agent) { await reply('No agent found.'); return; }\n const rawKey = field === 'identity' ? '_rawIdentity' : '_rawSoul';\n const current = (agent.config as any)[rawKey] || '';\n\n if (args[0]?.toLowerCase() === 'edit') {\n this.pendingEdits.set(message.from, {\n agentName: agent.config.name, field, content: [], createdAt: Date.now(), state: 'capturing',\n });\n await reply(`Editing ${field}. Send your new content, then /done to apply or /cancel to abort. (2 min timeout)`);\n return;\n }\n\n // View\n if (!current.trim()) { await reply(`${field} is empty.`); return; }\n if (current.length > 2500) {\n await reply(current.slice(0, 2500) + '\\n\\n(truncated)');\n } else {\n await reply(current);\n }\n }\n\n private async handleConfigCommand(message: IncomingMessage, args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n const agent = this.getFirstAgent();\n if (!agent) { await reply('No agent found.'); return; }\n const sub = args[0]?.toLowerCase();\n\n if (sub === 'show' || !sub) {\n const c = agent.config;\n const lines = [\n `*Agent Config: ${c.name}*`,\n ` purpose: ${c.purpose || '(not set)'}`,\n ` triggers: ${c.triggers?.join(', ') || '(none)'}`,\n ` channels: ${c.channels?.join(', ') || '(all)'}`,\n ` skills: ${c.skills?.join(', ') || '(none)'}`,\n ` knowledgeBase: ${c.knowledgeBase ?? false}`,\n ` priority: ${c.priority ?? 0}`,\n ` escalateTo: ${c.escalateTo || '(not set)'}`,\n ];\n if (c.guardrails) {\n lines.push(` maxResponseLength: ${c.guardrails.maxResponseLength ?? '(not set)'}`);\n lines.push(` blockedTopics: ${c.guardrails.blockedTopics?.join(', ') || '(none)'}`);\n lines.push(` escalationTriggers: ${c.guardrails.escalationTriggers?.join(', ') || '(none)'}`);\n lines.push(` systemRules: ${c.guardrails.systemRules?.length || 0} rules`);\n }\n await reply(lines.join('\\n'));\n return;\n }\n\n if (sub === 'set') {\n const key = args[1];\n const value = args.slice(2).join(' ');\n if (!key || !value) { await reply('Usage: /config set <key> <value>'); return; }\n await this.configSet(agent, key, value, message.from, reply);\n return;\n }\n\n if (sub === 'add') {\n const key = args[1];\n const value = args.slice(2).join(' ');\n if (!key || !value) { await reply('Usage: /config add <key> <value>'); return; }\n await this.configArrayOp(agent, 'add', key, value, message.from, reply);\n return;\n }\n\n if (sub === 'remove') {\n const key = args[1];\n const value = args.slice(2).join(' ');\n if (!key || !value) { await reply('Usage: /config remove <key> <value>'); return; }\n await this.configArrayOp(agent, 'remove', key, value, message.from, reply);\n return;\n }\n\n await reply('Usage: /config show | /config set <key> <value> | /config add <key> <value> | /config remove <key> <value>');\n }\n\n private async handleModelCommand(args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n const llm = this.config.llmProvider;\n if (!llm || !llm.getConfig) {\n await reply('LLM provider not available. Configure LLM_PROVIDER and LLM_API_KEY first.');\n return;\n }\n\n const sub = args[0]?.toLowerCase();\n\n // /model or /model show — display current model\n if (!sub || sub === 'show') {\n const cfg = llm.getConfig();\n const key = cfg.apiKey;\n const masked = key ? key.slice(0, 6) + '...' + key.slice(-4) : '(not set)';\n const lines = [\n '*Current LLM Config*',\n ` provider: ${cfg.provider}`,\n ` model: ${cfg.model || '(default)'}`,\n ` apiKey: ${masked}`,\n ];\n await reply(lines.join('\\n'));\n return;\n }\n\n // /model list — show available models\n if (sub === 'list') {\n if (!llm.getModelCatalog) {\n await reply('Model catalog not available.');\n return;\n }\n const { catalog, defaults } = llm.getModelCatalog();\n const cfg = llm.getConfig();\n const lines = ['*Available Models*', ''];\n for (const [provider, models] of Object.entries(catalog)) {\n const isCurrent = provider === cfg.provider;\n const hasKey = isCurrent || !!llm.getApiKey?.(provider);\n const marker = isCurrent ? ' (active)' : hasKey ? ' (key set)' : '';\n lines.push(`*${provider}*${marker}`);\n for (const m of models) {\n const isDefault = m === (defaults[provider] || '');\n const isActive = isCurrent && (cfg.model === m || (!cfg.model && isDefault));\n const prefix = isActive ? ' → ' : ' ';\n lines.push(`${prefix}${m}${isDefault ? ' (default)' : ''}`);\n }\n lines.push('');\n }\n await reply(lines.join('\\n'));\n return;\n }\n\n // /model set <provider/model> or /model set <model>\n if (sub === 'set') {\n const value = args.slice(1).join(' ').trim();\n if (!value) {\n await reply('Usage: /model set <provider/model> or /model set <model>');\n return;\n }\n\n let provider: string | undefined;\n let model: string;\n\n if (value.includes('/')) {\n const slashIdx = value.indexOf('/');\n provider = value.slice(0, slashIdx);\n model = value.slice(slashIdx + 1);\n } else {\n model = value;\n }\n\n const cfg = llm.getConfig();\n const targetProvider = provider || cfg.provider;\n\n // Validate provider\n const validProviders = ['openai', 'anthropic', 'google', 'groq', 'ollama'];\n if (!validProviders.includes(targetProvider)) {\n await reply(`Unknown provider: ${targetProvider}\\nValid: ${validProviders.join(', ')}`);\n return;\n }\n\n // Check API key availability when switching providers\n if (provider && provider !== cfg.provider) {\n const key = llm.getApiKey?.(provider);\n if (!key) {\n await reply(`No API key for ${provider}. Use /model key ${provider} <key> first.`);\n return;\n }\n llm.setConfig({ provider: provider as any, model, apiKey: key });\n } else {\n llm.setConfig({ model });\n }\n\n // Persist via memory store\n const memory = this.config.memory;\n if (memory?.setSetting) {\n await memory.setSetting('llm_provider', targetProvider);\n await memory.setSetting('llm_model', model);\n }\n\n await reply(`Model switched to *${targetProvider}/${model}*`);\n return;\n }\n\n // /model key <provider> <key> — store API key\n if (sub === 'key') {\n const provider = args[1]?.toLowerCase();\n const key = args[2];\n if (!provider || !key) {\n await reply('Usage: /model key <provider> <api-key>');\n return;\n }\n const validProviders = ['openai', 'anthropic', 'google', 'groq', 'ollama'];\n if (!validProviders.includes(provider)) {\n await reply(`Unknown provider: ${provider}\\nValid: ${validProviders.join(', ')}`);\n return;\n }\n llm.setApiKey(provider, key);\n\n // Persist\n const memory = this.config.memory;\n if (memory?.setSetting) {\n await memory.setSetting(`llm_apikey_${provider}`, key);\n }\n\n const masked = key.slice(0, 6) + '...' + key.slice(-4);\n await reply(`API key for *${provider}* saved: ${masked}`);\n return;\n }\n\n await reply('Usage: /model | /model list | /model set <provider/model> | /model key <provider> <key>');\n }\n\n /**\n * Select agent based on intent.\n * Sorts by priority (higher first), then specificity (fewer triggers = more specific).\n * Agents with triggers: ['*'] are treated as fallback (checked last).\n */\n private selectAgent(intent: Intent, message: IncomingMessage): Agent | null {\n // Filter by channel first\n const channelFiltered = Array.from(this.agents.values()).filter((agent) => {\n const cfg = agent.getConfig();\n if (cfg.channels && cfg.channels.length > 0) {\n return cfg.channels.includes(message.channel) || cfg.channels.includes(message.provider);\n }\n return true;\n });\n\n // Separate wildcard fallback agents from specific agents\n const specific: Agent[] = [];\n const fallback: Agent[] = [];\n\n for (const agent of channelFiltered) {\n const cfg = agent.getConfig();\n const triggers = cfg.triggers || [];\n if (triggers.length === 1 && triggers[0] === '*') {\n fallback.push(agent);\n } else {\n specific.push(agent);\n }\n }\n\n // Sort by priority (higher first), then specificity (fewer triggers = more specific)\n const sortByPriority = (a: Agent, b: Agent) => {\n const pa = a.getConfig().priority ?? 0;\n const pb = b.getConfig().priority ?? 0;\n if (pb !== pa) return pb - pa;\n const ta = a.getConfig().triggers?.length ?? 0;\n const tb = b.getConfig().triggers?.length ?? 0;\n return ta - tb;\n };\n\n specific.sort(sortByPriority);\n fallback.sort(sortByPriority);\n\n // Try specific agents first\n for (const agent of specific) {\n if (agent.matchesIntent(intent.intent)) {\n return agent;\n }\n }\n\n // Fall back to wildcard agents\n for (const agent of fallback) {\n return agent;\n }\n\n return null;\n }\n\n /**\n * Send message via provider\n */\n private async sendMessage(\n to: string,\n providerName: string,\n message: OutgoingMessage\n ): Promise<void> {\n const provider = this.providers.get(providerName);\n if (!provider) {\n throw new Error(`Provider not found: ${providerName}`);\n }\n\n await provider.sendMessage(to, message);\n }\n\n /**\n * Get all agents\n */\n getAgents(): Agent[] {\n return Array.from(this.agents.values());\n }\n\n /**\n * Get all skills\n */\n getSkills(): Skill[] {\n return Array.from(this.skills.values());\n }\n\n /**\n * Check if running\n */\n isActive(): boolean {\n return this.isRunning;\n }\n\n /**\n * Get the analytics store (if configured) for querying metrics\n */\n getAnalyticsStore(): any {\n return this.config.analyticsStore ?? null;\n }\n\n private async configSet(agent: Agent, key: string, value: string, sender: string, reply: (t: string) => Promise<void>): Promise<void> {\n const scalarKeys: Record<string, (v: string) => any> = {\n purpose: (v) => v,\n maxResponseLength: (v) => parseInt(v),\n priority: (v) => parseInt(v),\n escalateTo: (v) => v,\n knowledgeBase: (v) => v === 'true',\n };\n const parser = scalarKeys[key];\n if (!parser) { await reply(`Unknown config key \"${key}\". Valid: ${Object.keys(scalarKeys).join(', ')}`); return; }\n\n await this.versionStore.saveVersion(agent.config.name, {\n timestamp: new Date().toISOString(),\n instructions: agent.config._rawInstructions,\n identity: agent.config._rawIdentity,\n soul: agent.config._rawSoul,\n frontmatter: this.extractFrontmatter(agent.config),\n editedBy: sender,\n changeDescription: `Set ${key} = ${value}`,\n });\n\n const parsed = parser(value);\n if (key === 'maxResponseLength') {\n agent.config.guardrails = agent.config.guardrails || {};\n agent.config.guardrails.maxResponseLength = parsed;\n } else {\n (agent.config as any)[key] = parsed;\n }\n\n await this.writeAgentFrontmatter(agent.config.name, agent);\n await reply(`Config updated: ${key} = ${value}`);\n }\n\n private async configArrayOp(agent: Agent, op: 'add' | 'remove', key: string, value: string, sender: string, reply: (t: string) => Promise<void>): Promise<void> {\n const arrayKeys: Record<string, { get: () => string[], set: (v: string[]) => void }> = {\n triggers: { get: () => agent.config.triggers || [], set: (v) => { agent.config.triggers = v; } },\n channels: { get: () => agent.config.channels || [], set: (v) => { agent.config.channels = v; } },\n skills: { get: () => agent.config.skills || [], set: (v) => { agent.config.skills = v; } },\n blockedTopics: {\n get: () => agent.config.guardrails?.blockedTopics || [],\n set: (v) => { agent.config.guardrails = agent.config.guardrails || {}; agent.config.guardrails.blockedTopics = v; },\n },\n escalationTriggers: {\n get: () => agent.config.guardrails?.escalationTriggers || [],\n set: (v) => { agent.config.guardrails = agent.config.guardrails || {}; agent.config.guardrails.escalationTriggers = v; },\n },\n systemRules: {\n get: () => agent.config.guardrails?.systemRules || [],\n set: (v) => { agent.config.guardrails = agent.config.guardrails || {}; agent.config.guardrails.systemRules = v; },\n },\n };\n const accessor = arrayKeys[key];\n if (!accessor) { await reply(`Unknown array key \"${key}\". Valid: ${Object.keys(arrayKeys).join(', ')}`); return; }\n\n await this.versionStore.saveVersion(agent.config.name, {\n timestamp: new Date().toISOString(),\n instructions: agent.config._rawInstructions,\n identity: agent.config._rawIdentity,\n soul: agent.config._rawSoul,\n frontmatter: this.extractFrontmatter(agent.config),\n editedBy: sender,\n changeDescription: `${op} ${key}: ${value}`,\n });\n\n const arr = accessor.get();\n if (op === 'add') {\n if (!arr.includes(value)) arr.push(value);\n accessor.set(arr);\n } else {\n accessor.set(arr.filter(v => v !== value));\n }\n\n // Rebuild system prompt if systemRules changed\n if (key === 'systemRules') this.rebuildAgentSystemPrompt(agent);\n\n await this.writeAgentFrontmatter(agent.config.name, agent);\n await reply(`Config updated: ${op} \"${value}\" ${op === 'add' ? 'to' : 'from'} ${key}`);\n }\n\n private async handleWhitelistCommand(message: IncomingMessage, args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n const whitelist = this.config.trainingMode?.whitelist;\n if (!whitelist) {\n await reply('Training mode whitelist is not configured.');\n return;\n }\n\n const normalizePhone = (p: string) => p.replace(/[\\s\\-+]/g, '');\n const formatPhone = (p: string) => p.startsWith('+') ? p : `+${p}`;\n const sub = args[0]?.toLowerCase();\n\n if (!sub || sub === 'list') {\n if (whitelist.length === 0) {\n await reply('Whitelist is empty.');\n } else {\n const lines = whitelist.map(p => ` ${formatPhone(p)}`);\n await reply(`Whitelisted numbers (${whitelist.length}):\\n${lines.join('\\n')}`);\n }\n return;\n }\n\n if (sub === 'add') {\n const phone = args.slice(1).join('').trim();\n if (!phone) {\n await reply('Usage: /whitelist add <phone>');\n return;\n }\n const normalized = normalizePhone(phone);\n const alreadyExists = whitelist.some(w => normalizePhone(w) === normalized);\n if (alreadyExists) {\n await reply(`${formatPhone(phone)} is already whitelisted.`);\n return;\n }\n whitelist.push(phone.startsWith('+') ? phone : `+${phone}`);\n await this.persistWhitelist();\n await reply(`Added ${formatPhone(phone)} to whitelist.`);\n return;\n }\n\n if (sub === 'remove') {\n const phone = args.slice(1).join('').trim();\n if (!phone) {\n await reply('Usage: /whitelist remove <phone>');\n return;\n }\n const normalized = normalizePhone(phone);\n const senderNormalized = normalizePhone(message.from);\n if (normalized === senderNormalized) {\n await reply('You cannot remove yourself from the whitelist.');\n return;\n }\n const idx = whitelist.findIndex(w => normalizePhone(w) === normalized);\n if (idx === -1) {\n await reply(`${formatPhone(phone)} is not in the whitelist.`);\n return;\n }\n whitelist.splice(idx, 1);\n await this.persistWhitelist();\n await reply(`Removed ${formatPhone(phone)} from whitelist.`);\n return;\n }\n\n await reply('Usage: /whitelist | /whitelist add <phone> | /whitelist remove <phone>');\n }\n\n private async handleSkillsCommand(message: IncomingMessage, args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n const skills = Array.from(this.skills.values());\n const sub = args[0]?.toLowerCase();\n\n if (sub === 'info') {\n const name = args.slice(1).join(' ').trim();\n if (!name) {\n await reply('Usage: /skills info <name>');\n return;\n }\n const skill = this.skills.get(name);\n if (!skill) {\n const available = skills.map(s => s.name).join(', ') || 'none';\n await reply(`Skill \"${name}\" not found. Available: ${available}`);\n return;\n }\n const isPrompt = typeof (skill as any).getContent === 'function';\n if (isPrompt) {\n const cfg = (skill as any).getConfig?.() || {};\n const content = (skill as any).getContent() || '';\n const preview = content.length > 300 ? content.slice(0, 300) + '...' : content;\n const lines = [\n `📝 *Prompt Skill: ${skill.name}*`,\n ` Status: ${skill.isReady() ? 'ready' : 'not ready'}`,\n ` Type: prompt`,\n ];\n if (cfg.summary) lines.push(` Summary: ${cfg.summary}`);\n if (cfg.tags?.length) lines.push(` Tags: ${cfg.tags.join(', ')}`);\n if (cfg.author) lines.push(` Author: ${cfg.author}`);\n lines.push('', ' Content:', ` ${preview}`);\n await reply(lines.join('\\n'));\n } else {\n const tools = Object.values(skill.tools);\n const lines = [\n `🔧 *Skill: ${skill.name}*`,\n ` Status: ${skill.isReady() ? 'ready' : 'not ready'}`,\n ` Tools: ${tools.length}`,\n ];\n for (const tool of tools) {\n lines.push('');\n lines.push(` *${tool.name}*`);\n if (tool.description) lines.push(` ${tool.description}`);\n const params = Object.entries(tool.parameters);\n if (params.length > 0) {\n lines.push(' Parameters:');\n for (const [pName, pDef] of params) {\n const p = pDef as Record<string, any>;\n const req = p.required ? ' (required)' : '';\n const type = p.type ? ` [${p.type}]` : '';\n lines.push(` ${pName}${type}${req}${p.description ? ' — ' + p.description : ''}`);\n }\n }\n }\n await reply(lines.join('\\n'));\n }\n return;\n }\n\n if (sub === 'catalog' || sub === 'browse') {\n await this.handleSkillCatalog(args.slice(1), reply);\n return;\n }\n\n if (sub === 'add') {\n await this.handleSkillAdd(message, args.slice(1), reply);\n return;\n }\n\n if (sub === 'remove') {\n await this.handleSkillRemove(args.slice(1), reply);\n return;\n }\n\n // Default: list all skills\n if (skills.length === 0) {\n await reply('No skills registered. Use /skills catalog to browse available skills, or /create-skill to create a prompt skill.');\n return;\n }\n const lines = [`🔧 *Registered Skills (${skills.length}):*`];\n for (const skill of skills) {\n const status = skill.isReady() ? '✅' : '⏳';\n const isPrompt = typeof (skill as any).getContent === 'function';\n if (isPrompt) {\n lines.push(` ${status} 📝 ${skill.name} — prompt skill`);\n } else {\n const toolNames = Object.keys(skill.tools);\n lines.push(` ${status} ${skill.name} — ${toolNames.length} tool${toolNames.length !== 1 ? 's' : ''}: ${toolNames.join(', ')}`);\n }\n }\n lines.push('');\n lines.push('Use /skills info <name> for details, /skills catalog to browse, /skills add <name> to install, /create-skill to create a prompt skill.');\n await reply(lines.join('\\n'));\n }\n\n private async handleCreateSkillCommand(message: IncomingMessage, args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n // Usage: /create-skill <name> | <content>\n const raw = args.join(' ');\n const pipeIdx = raw.indexOf('|');\n if (pipeIdx === -1 || !raw.trim()) {\n await reply('Usage: /create-skill <name> | <instructions>\\n\\nExample: /create-skill sentiment-monitor | Monitor customer sentiment and flag negative interactions for review.');\n return;\n }\n\n const name = raw.slice(0, pipeIdx).trim();\n const content = raw.slice(pipeIdx + 1).trim();\n if (!name || !content) {\n await reply('Both name and content are required.\\nUsage: /create-skill <name> | <instructions>');\n return;\n }\n\n const mod = this.config.skillsModule;\n if (!mod) {\n await reply('Skills module not available. Make sure @operor/skills is installed.');\n return;\n }\n\n try {\n const config = mod.loadSkillsConfig();\n const exists = config.skills.find((s: any) => s.name === name);\n if (exists) {\n await reply(`A skill named \"${name}\" already exists. Remove it first or choose a different name.`);\n return;\n }\n\n const promptSkillConfig = { type: 'prompt' as const, name, content, enabled: true };\n config.skills.push(promptSkillConfig);\n mod.saveSkillsConfig(config);\n\n // Auto-add skill to all agents' skills lists so it activates on hot-reload\n const agents = Array.from(this.agents.values());\n for (const agent of agents) {\n const cfg = agent.getConfig();\n if (cfg.skills && !cfg.skills.includes(name)) {\n cfg.skills.push(name);\n agent.config.skills = cfg.skills;\n }\n }\n\n // Persist to INSTRUCTIONS.md frontmatter and save version snapshot\n for (const agent of agents) {\n await this.versionStore.saveVersion(agent.config.name, {\n timestamp: new Date().toISOString(),\n instructions: agent.config._rawInstructions,\n identity: agent.config._rawIdentity,\n soul: agent.config._rawSoul,\n frontmatter: this.extractFrontmatter(agent.config),\n editedBy: message.from,\n changeDescription: `add skills: ${name}`,\n });\n await this.writeAgentFrontmatter(agent.config.name, agent);\n }\n\n await reply(`📝 Prompt skill \"${name}\" created and added to your agent(s).\\nSaving to mcp.json triggers hot-reload — skill is now active.`);\n } catch (err: any) {\n await reply(`Failed to create skill: ${err.message}`);\n }\n }\n\n private async handleUpdateSkillCommand(message: IncomingMessage, args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n // Usage: /update-skill <name> | <content>\n const raw = args.join(' ');\n const pipeIdx = raw.indexOf('|');\n if (pipeIdx === -1 || !raw.trim()) {\n await reply('Usage: /update-skill <name> | <instructions>\\n\\nExample: /update-skill sentiment-monitor | Updated instructions for monitoring sentiment.');\n return;\n }\n\n const name = raw.slice(0, pipeIdx).trim();\n const content = raw.slice(pipeIdx + 1).trim();\n if (!name || !content) {\n await reply('Both name and content are required.\\nUsage: /update-skill <name> | <instructions>');\n return;\n }\n\n const mod = this.config.skillsModule;\n if (!mod) {\n await reply('Skills module not available. Make sure @operor/skills is installed.');\n return;\n }\n\n try {\n const config = mod.loadSkillsConfig();\n const existing = config.skills.find((s: any) => s.name === name);\n if (!existing) {\n await reply(`Skill \"${name}\" not found. Use /skills to list registered skills.`);\n return;\n }\n if (existing.type !== 'prompt') {\n await reply(`Skill \"${name}\" is not a prompt skill (type: ${existing.type}). Only prompt skills can be updated with this command.`);\n return;\n }\n\n existing.content = content;\n mod.saveSkillsConfig(config);\n\n // Save version snapshot\n const agents = Array.from(this.agents.values());\n for (const agent of agents) {\n await this.versionStore.saveVersion(agent.config.name, {\n timestamp: new Date().toISOString(),\n instructions: agent.config._rawInstructions,\n identity: agent.config._rawIdentity,\n soul: agent.config._rawSoul,\n frontmatter: this.extractFrontmatter(agent.config),\n editedBy: message.from,\n changeDescription: `update skill: ${name}`,\n });\n }\n\n await reply(`📝 Prompt skill \"${name}\" updated.\\nSaving to mcp.json triggers hot-reload — changes are now active.`);\n } catch (err: any) {\n await reply(`Failed to update skill: ${err.message}`);\n }\n }\n\n private async handleSkillCatalog(args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n const mod = this.config.skillsModule;\n if (!mod) {\n await reply('Skill catalog is not available. Make sure @operor/skills is installed.');\n return;\n }\n const catalog = mod.loadSkillCatalog();\n\n const filter = args[0]?.toLowerCase();\n const validCategories = ['commerce', 'payments', 'crm', 'support', 'marketing', 'search', 'communication', 'productivity'];\n\n let entries = catalog.skills as any[];\n let categoryFilter: string | undefined;\n if (filter) {\n if (validCategories.includes(filter)) {\n categoryFilter = filter;\n entries = entries.filter((s: any) => s.category === filter);\n } else {\n // Text search fallback across name, description, category\n entries = entries.filter((s: any) =>\n s.name?.toLowerCase().includes(filter) ||\n s.description?.toLowerCase().includes(filter) ||\n s.category?.toLowerCase().includes(filter) ||\n s.displayName?.toLowerCase().includes(filter)\n );\n }\n }\n\n if (entries.length === 0) {\n await reply(filter ? `No skills found matching \"${filter}\".` : 'Skill catalog is empty.');\n return;\n }\n\n // Group by category\n const grouped: Record<string, any[]> = {};\n for (const entry of entries) {\n const cat = entry.category || 'other';\n if (!grouped[cat]) grouped[cat] = [];\n grouped[cat].push(entry);\n }\n\n const lines = [`📦 *Skill Catalog (${entries.length} skills):*`];\n for (const [cat, catSkills] of Object.entries(grouped)) {\n lines.push('');\n lines.push(`*${cat.charAt(0).toUpperCase() + cat.slice(1)}:*`);\n for (const s of catSkills) {\n const installed = this.skills.has(s.name) ? ' ✅' : '';\n const badge = s.maturity === 'official' ? ' 🏷️' : '';\n const typeTag = s.type === 'prompt' ? ' 📝' : '';\n lines.push(` ${s.displayName || s.name}${badge}${typeTag}${installed} — ${s.description}`);\n lines.push(` → /skills add ${s.name}`);\n }\n }\n lines.push('');\n if (!categoryFilter) {\n lines.push(`Filter by category: /skills catalog <${validCategories.join('|')}>`);\n }\n await reply(lines.join('\\n'));\n }\n\n private async handleSkillAdd(message: IncomingMessage, args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n const name = args[0]?.trim();\n if (!name) {\n await reply('Usage: /skills add <name>\\n\\nBrowse available skills with /skills catalog');\n return;\n }\n\n // Check if already installed (runtime or mcp.json)\n if (this.skills.has(name)) {\n await reply(`Skill \"${name}\" is already installed and active.`);\n return;\n }\n\n // Look up in catalog\n const mod = this.config.skillsModule;\n if (!mod) {\n await reply('Skill catalog is not available. Make sure @operor/skills is installed.');\n return;\n }\n\n // Also check mcp.json for already-configured skills\n const root = this.config.projectRoot;\n const existingConfig = mod.loadSkillsConfig(root);\n if (existingConfig.skills.some((s: any) => s.name === name)) {\n await reply(`Skill \"${name}\" already exists in mcp.json. Restart to activate.`);\n return;\n }\n const catalog = mod.loadSkillCatalog();\n const entry = mod.findSkillInCatalog(catalog, name);\n if (!entry) {\n // Suggest similar skills\n const allNames = catalog.skills.map((s: any) => s.name);\n const suggestions = allNames.filter((n: string) =>\n n.includes(name) || name.includes(n)\n );\n const msg = suggestions.length > 0\n ? `Skill \"${name}\" not found. Did you mean: ${suggestions.join(', ')}?`\n : `Skill \"${name}\" not found in catalog. Use /skills catalog to browse available skills.`;\n await reply(msg);\n return;\n }\n\n // Prompt skills install directly — no env vars or tools\n if (entry.type === 'prompt') {\n await reply(`📝 *Adding prompt skill: ${entry.displayName}*\\n ${entry.description}\\n\\nInstalling...`);\n await this.installSkillFromCatalog(entry, {}, reply);\n return;\n }\n\n // Show skill info\n const envKeys = Object.keys(entry.envVars || {});\n const requiredKeys = envKeys.filter((k: string) => entry.envVars[k].required);\n\n const lines = [\n `📦 *Adding: ${entry.displayName}*`,\n ` ${entry.description}`,\n ` Category: ${entry.category} | Maturity: ${entry.maturity}`,\n ` Tools: ${(entry.tools || []).map((t: any) => t.name).join(', ')}`,\n ];\n\n if (entry.docsUrl) {\n lines.push(` Docs: ${entry.docsUrl}`);\n }\n\n if (requiredKeys.length === 0) {\n // No env vars needed — install directly\n await reply(lines.join('\\n') + '\\n\\nNo API keys required. Installing...');\n await this.installSkillFromCatalog(entry, {}, reply);\n return;\n }\n\n // Start env var capture flow\n lines.push('');\n lines.push('*Required API keys:*');\n for (const key of requiredKeys) {\n const spec = entry.envVars[key];\n lines.push(` ${key} — ${spec.description}${spec.placeholder ? ` (e.g. ${spec.placeholder})` : ''}`);\n }\n lines.push('');\n lines.push(`Please send the value for *${requiredKeys[0]}*:`);\n lines.push('(Send \"cancel\" to abort)');\n\n this.pendingSkillAdds.set(message.from, {\n skillName: name,\n envVars: {},\n pendingKeys: [...requiredKeys],\n currentKey: requiredKeys[0],\n catalogEntry: entry,\n createdAt: Date.now(),\n });\n\n await reply(lines.join('\\n'));\n }\n\n private async handlePendingSkillAdd(message: IncomingMessage, pending: PendingSkillAdd): Promise<boolean> {\n const reply = async (text: string) => {\n await this.sendMessage(message.from, message.provider, { to: message.from, text });\n };\n\n // Timeout after 5 minutes\n if (Date.now() - pending.createdAt > 5 * 60 * 1000) {\n this.pendingSkillAdds.delete(message.from);\n await reply('Skill add session expired (5 min timeout). Send /skills add <name> to try again.');\n return true;\n }\n\n const text = message.text.trim();\n\n if (text.toLowerCase() === 'cancel' || text.toLowerCase() === '/cancel') {\n this.pendingSkillAdds.delete(message.from);\n await reply('Skill installation cancelled.');\n return true;\n }\n\n if (!pending.currentKey) {\n this.pendingSkillAdds.delete(message.from);\n return false;\n }\n\n // Store the value for the current key\n pending.envVars[pending.currentKey] = text;\n pending.pendingKeys.shift();\n\n if (pending.pendingKeys.length > 0) {\n // Ask for next key\n pending.currentKey = pending.pendingKeys[0];\n const spec = pending.catalogEntry.envVars[pending.currentKey];\n await reply(`Got it. Now send the value for *${pending.currentKey}*:${spec?.placeholder ? ` (e.g. ${spec.placeholder})` : ''}`);\n return true;\n }\n\n // All keys collected — install\n this.pendingSkillAdds.delete(message.from);\n await reply('All keys received. Installing skill...');\n await this.installSkillFromCatalog(pending.catalogEntry, pending.envVars, reply);\n return true;\n }\n\n private async installSkillFromCatalog(entry: any, envVars: Record<string, string>, reply: (t: string) => Promise<void>): Promise<void> {\n try {\n const mod = this.config.skillsModule;\n if (!mod) { await reply('Skill catalog is not available.'); return; }\n const config = mod.catalogEntryToConfig(entry);\n\n // Merge actual env var values into the config\n if (config.env && Object.keys(envVars).length > 0) {\n for (const [key, value] of Object.entries(envVars)) {\n config.env[key] = value;\n }\n }\n\n // Save to mcp.json\n const root = this.config.projectRoot;\n const skillsConfig = mod.loadSkillsConfig(root);\n const existingIdx = skillsConfig.skills.findIndex((s: any) => s.name === config.name);\n if (existingIdx >= 0) {\n skillsConfig.skills[existingIdx] = config;\n } else {\n skillsConfig.skills.push(config);\n }\n mod.saveSkillsConfig(skillsConfig, root);\n\n // Add skill to all agents' skills lists and persist to INSTRUCTIONS.md\n const agents = Array.from(this.agents.values());\n for (const agent of agents) {\n const cfg = agent.getConfig();\n if (cfg.skills && !cfg.skills.includes(config.name)) {\n cfg.skills.push(config.name);\n agent.config.skills = cfg.skills;\n }\n await this.writeAgentFrontmatter(agent.config.name, agent);\n }\n\n await reply(`✅ *${entry.displayName}* added to mcp.json and enabled.\\n\\nRestart the agent to activate the skill, or use /reload if available.`);\n } catch (err: any) {\n await reply(`Failed to install skill: ${err.message}`);\n }\n }\n\n private async handleSkillRemove(args: string[], reply: (t: string) => Promise<void>): Promise<void> {\n const name = args[0]?.trim();\n if (!name) {\n await reply('Usage: /skills remove <name>');\n return;\n }\n\n try {\n const mod = this.config.skillsModule;\n if (!mod) { await reply('Skill catalog is not available.'); return; }\n const root = this.config.projectRoot;\n const skillsConfig = mod.loadSkillsConfig(root);\n const idx = skillsConfig.skills.findIndex((s: any) => s.name === name);\n\n if (idx < 0) {\n const available = skillsConfig.skills.map((s: any) => s.name).join(', ') || 'none';\n await reply(`Skill \"${name}\" not found in mcp.json. Configured: ${available}`);\n return;\n }\n\n skillsConfig.skills.splice(idx, 1);\n mod.saveSkillsConfig(skillsConfig, root);\n\n // Remove from runtime if loaded\n if (this.skills.has(name)) {\n await this.removeSkill(name);\n }\n\n // Remove skill from all agents' skills lists and persist to INSTRUCTIONS.md\n const agents = Array.from(this.agents.values());\n for (const agent of agents) {\n const cfg = agent.getConfig();\n if (cfg.skills) {\n const skillIdx = cfg.skills.indexOf(name);\n if (skillIdx >= 0) {\n cfg.skills.splice(skillIdx, 1);\n agent.config.skills = cfg.skills;\n }\n }\n await this.writeAgentFrontmatter(agent.config.name, agent);\n }\n\n await reply(`✅ Skill \"${name}\" removed from mcp.json.`);\n } catch (err: any) {\n await reply(`Failed to remove skill: ${err.message}`);\n }\n }\n\n private async persistWhitelist(): Promise<void> {\n const whitelist = this.config.trainingMode?.whitelist;\n if (!whitelist) return;\n if (this.memory.setSetting) {\n await this.memory.setSetting('training_whitelist', whitelist.join(','));\n }\n }\n\n /**\n * Format a date string (YYYY-MM-DD) to a day name (e.g. \"Monday\")\n */\n private formatDayName(dateStr: string): string {\n try {\n const d = new Date(dateStr + 'T00:00:00');\n return d.toLocaleDateString('en-US', { weekday: 'long' });\n } catch {\n return dateStr;\n }\n }\n\n /**\n * Log helper\n */\n private getFirstAgent(): Agent | null {\n const agents = Array.from(this.agents.values());\n return agents[0] ?? null;\n }\n\n private rebuildAgentSystemPrompt(agent: Agent): void {\n agent.config.systemPrompt = buildSystemPrompt({\n identity: agent.config._rawIdentity || null,\n soul: agent.config._rawSoul || null,\n body: agent.config._rawInstructions || '',\n userContext: null,\n guardrails: agent.config.guardrails,\n });\n }\n\n private async writeAgentFiles(agentName: string, agent: Agent): Promise<void> {\n const agentsDir = this.config.agentsDir;\n if (!agentsDir) return;\n const agentDir = path.join(agentsDir, agentName);\n await fs.mkdir(agentDir, { recursive: true });\n\n // Write INSTRUCTIONS.md with frontmatter\n const fm = this.extractFrontmatter(agent.config);\n const yamlFm = yaml.dump(fm, { lineWidth: -1, noRefs: true }).trim();\n const body = agent.config._rawInstructions || '';\n await fs.writeFile(path.join(agentDir, 'INSTRUCTIONS.md'), `---\\n${yamlFm}\\n---\\n\\n${body.trim()}\\n`, 'utf-8');\n\n if (agent.config._rawIdentity) {\n await fs.writeFile(path.join(agentDir, 'IDENTITY.md'), agent.config._rawIdentity.trim() + '\\n', 'utf-8');\n }\n if (agent.config._rawSoul) {\n await fs.writeFile(path.join(agentDir, 'SOUL.md'), agent.config._rawSoul.trim() + '\\n', 'utf-8');\n }\n }\n\n private async writeAgentFrontmatter(agentName: string, agent: Agent): Promise<void> {\n const agentsDir = this.config.agentsDir;\n if (!agentsDir) return;\n const agentDir = path.join(agentsDir, agentName);\n await fs.mkdir(agentDir, { recursive: true });\n const fm = this.extractFrontmatter(agent.config);\n const yamlFm = yaml.dump(fm, { lineWidth: -1, noRefs: true }).trim();\n const body = agent.config._rawInstructions || '';\n await fs.writeFile(path.join(agentDir, 'INSTRUCTIONS.md'), `---\\n${yamlFm}\\n---\\n\\n${body.trim()}\\n`, 'utf-8');\n }\n\n private extractSection(text: string, sectionName: string): string | null {\n const sections = this.parseSections(text);\n const match = sections.find(s => s.heading.toLowerCase().includes(sectionName.toLowerCase()));\n return match?.content || null;\n }\n\n private replaceSection(text: string, sectionName: string, newContent: string): string {\n const sections = this.parseSections(text);\n const idx = sections.findIndex(s => s.heading.toLowerCase().includes(sectionName.toLowerCase()));\n if (idx === -1) return text;\n sections[idx].content = newContent;\n return sections.map(s => `${s.heading}\\n\\n${s.content}`).join('\\n\\n');\n }\n\n private parseSections(text: string): Array<{ heading: string; content: string }> {\n const lines = text.split('\\n');\n const sections: Array<{ heading: string; content: string }> = [];\n let currentHeading: string | null = null;\n let currentContent: string[] = [];\n\n for (const line of lines) {\n if (line.match(/^##\\s+/)) {\n if (currentHeading) {\n sections.push({ heading: currentHeading, content: currentContent.join('\\n').trim() });\n }\n currentHeading = line;\n currentContent = [];\n } else if (currentHeading) {\n currentContent.push(line);\n }\n }\n\n if (currentHeading) {\n sections.push({ heading: currentHeading, content: currentContent.join('\\n').trim() });\n }\n\n return sections;\n }\n\n private extractFrontmatter(config: AgentConfig): Record<string, any> {\n const fm: Record<string, any> = { name: config.name };\n if (config.purpose) fm.purpose = config.purpose;\n if (config.triggers?.length) fm.triggers = config.triggers;\n if (config.channels?.length) fm.channels = config.channels;\n if (config.skills?.length) fm.skills = config.skills;\n if (config.knowledgeBase != null) fm.knowledgeBase = config.knowledgeBase;\n if (config.priority != null) fm.priority = config.priority;\n if (config.escalateTo) fm.escalateTo = config.escalateTo;\n if (config.guardrails) fm.guardrails = config.guardrails;\n return fm;\n }\n\n private log(message: string): void {\n if (this.config.debug) {\n console.log(`[Operor] ${message}`);\n }\n }\n}\n","import type { Intent, IntentClassifier, AgentConfig, ConversationMessage } from './types.js';\n\n/**\n * LLM-based intent classifier.\n * Uses an LLM to classify user messages based on agent configurations.\n * Requires an LLM provider (AIProvider from @operor/llm).\n */\nexport class LLMIntentClassifier implements IntentClassifier {\n constructor(private llm: any) {}\n\n async classify(\n message: string,\n agents: AgentConfig[],\n history?: ConversationMessage[]\n ): Promise<Intent> {\n const agentDescriptions = agents\n .map(\n (a) =>\n `- ${a.name}: triggers=[${a.triggers?.join(', ')}], purpose=\"${a.purpose || 'N/A'}\"`\n )\n .join('\\n');\n\n const systemPrompt = `You are an intent classifier for a customer service system. Classify the user message into one of these agent categories:\n\n${agentDescriptions}\n\nRespond with JSON only (no markdown, no code blocks):\n{\n \"intent\": \"trigger_name\",\n \"confidence\": 0.0-1.0,\n \"entities\": {}\n}\n\nChoose the most appropriate trigger from the list above. If none match well, use \"general\".`;\n\n try {\n const response = await this.llm.complete(\n [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: message },\n ],\n { maxTokens: 150, temperature: 0 }\n );\n\n // Parse JSON response\n const text = response.text.trim();\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) {\n throw new Error('No JSON found in LLM response');\n }\n\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n intent: parsed.intent || 'general',\n confidence: parsed.confidence || 0.5,\n entities: parsed.entities || {},\n };\n } catch (error) {\n console.error('LLM intent classification failed:', error);\n // Fallback to general intent\n return {\n intent: 'general',\n confidence: 0.3,\n entities: {},\n };\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@operor/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent OS Core - AI Agent Operating System",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"eventemitter3": "^5.0.1",
|
|
16
|
+
"gray-matter": "^4.0.3",
|
|
17
|
+
"js-yaml": "^4.1.1",
|
|
18
|
+
"zod": "^4.0.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/js-yaml": "^4.0.9",
|
|
22
|
+
"tsdown": "^0.20.3",
|
|
23
|
+
"typescript": "^5.7.0",
|
|
24
|
+
"vitest": "^4.0.0",
|
|
25
|
+
"@operor/provider-mock": "0.1.0",
|
|
26
|
+
"@operor/testing": "0.1.0"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsdown",
|
|
30
|
+
"dev": "tsdown --watch",
|
|
31
|
+
"test": "vitest"
|
|
32
|
+
}
|
|
33
|
+
}
|