chat-flow-ardymalihi 1.0.2 → 3.0.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 +2 -0
- package/dist/adapters/intent/IntentMatcher.d.ts +16 -0
- package/dist/adapters/intent/IntentMatcher.d.ts.map +1 -1
- package/dist/adapters/intent/IntentMatcher.js +93 -15
- package/dist/adapters/intent/IntentMatcher.js.map +1 -1
- package/dist/adapters/intent/IntentService.d.ts +4 -5
- package/dist/adapters/intent/IntentService.d.ts.map +1 -1
- package/dist/adapters/intent/IntentService.js +15 -9
- package/dist/adapters/intent/IntentService.js.map +1 -1
- package/dist/adapters/intent/MockIntentService.d.ts +7 -0
- package/dist/adapters/intent/MockIntentService.d.ts.map +1 -0
- package/dist/adapters/intent/MockIntentService.js +36 -0
- package/dist/adapters/intent/MockIntentService.js.map +1 -0
- package/dist/adapters/llm/OllamaLLMAdapter.d.ts +9 -0
- package/dist/adapters/llm/OllamaLLMAdapter.d.ts.map +1 -0
- package/dist/adapters/llm/OllamaLLMAdapter.js +74 -0
- package/dist/adapters/llm/OllamaLLMAdapter.js.map +1 -0
- package/dist/adapters/logger/ConsoleLogger.d.ts +12 -0
- package/dist/adapters/logger/ConsoleLogger.d.ts.map +1 -0
- package/dist/adapters/logger/ConsoleLogger.js +37 -0
- package/dist/adapters/logger/ConsoleLogger.js.map +1 -0
- package/dist/adapters/repository/InMemoryRepository.d.ts +35 -4
- package/dist/adapters/repository/InMemoryRepository.d.ts.map +1 -1
- package/dist/adapters/repository/InMemoryRepository.js +204 -10
- package/dist/adapters/repository/InMemoryRepository.js.map +1 -1
- package/dist/adapters/repository/RedisRepository.d.ts +52 -5
- package/dist/adapters/repository/RedisRepository.d.ts.map +1 -1
- package/dist/adapters/repository/RedisRepository.js +525 -26
- package/dist/adapters/repository/RedisRepository.js.map +1 -1
- package/dist/adapters/storage/RedisAudioStorageAdapter.d.ts +33 -0
- package/dist/adapters/storage/RedisAudioStorageAdapter.d.ts.map +1 -0
- package/dist/adapters/storage/RedisAudioStorageAdapter.js +121 -0
- package/dist/adapters/storage/RedisAudioStorageAdapter.js.map +1 -0
- package/dist/adapters/storage/RedisBufferStorageAdapter.d.ts +14 -0
- package/dist/adapters/storage/RedisBufferStorageAdapter.d.ts.map +1 -0
- package/dist/adapters/storage/RedisBufferStorageAdapter.js +94 -0
- package/dist/adapters/storage/RedisBufferStorageAdapter.js.map +1 -0
- package/dist/adapters/voice/ElevenLabsVoiceAdapter.d.ts +29 -0
- package/dist/adapters/voice/ElevenLabsVoiceAdapter.d.ts.map +1 -0
- package/dist/adapters/voice/ElevenLabsVoiceAdapter.js +75 -0
- package/dist/adapters/voice/ElevenLabsVoiceAdapter.js.map +1 -0
- package/dist/adapters/voice/GeminiMultimodalLiveAdapter.d.ts +77 -0
- package/dist/adapters/voice/GeminiMultimodalLiveAdapter.d.ts.map +1 -0
- package/dist/adapters/voice/GeminiMultimodalLiveAdapter.js +187 -0
- package/dist/adapters/voice/GeminiMultimodalLiveAdapter.js.map +1 -0
- package/dist/adapters/voice/GeminiVoiceAdapter.d.ts +36 -0
- package/dist/adapters/voice/GeminiVoiceAdapter.d.ts.map +1 -0
- package/dist/adapters/voice/GeminiVoiceAdapter.js +134 -0
- package/dist/adapters/voice/GeminiVoiceAdapter.js.map +1 -0
- package/dist/adapters/voice/GoogleTTSAdapter.d.ts +61 -0
- package/dist/adapters/voice/GoogleTTSAdapter.d.ts.map +1 -0
- package/dist/adapters/voice/GoogleTTSAdapter.js +165 -0
- package/dist/adapters/voice/GoogleTTSAdapter.js.map +1 -0
- package/dist/adapters/voice/GoogleVoiceAdapter.d.ts +33 -0
- package/dist/adapters/voice/GoogleVoiceAdapter.d.ts.map +1 -0
- package/dist/adapters/voice/GoogleVoiceAdapter.js +155 -0
- package/dist/adapters/voice/GoogleVoiceAdapter.js.map +1 -0
- package/dist/adapters/voice/HybridVoiceAdapter.d.ts +54 -0
- package/dist/adapters/voice/HybridVoiceAdapter.d.ts.map +1 -0
- package/dist/adapters/voice/HybridVoiceAdapter.js +102 -0
- package/dist/adapters/voice/HybridVoiceAdapter.js.map +1 -0
- package/dist/adapters/voice/LanguageVoiceMapper.d.ts +60 -0
- package/dist/adapters/voice/LanguageVoiceMapper.d.ts.map +1 -0
- package/dist/adapters/voice/LanguageVoiceMapper.js +130 -0
- package/dist/adapters/voice/LanguageVoiceMapper.js.map +1 -0
- package/dist/adapters/voice/VertexVoiceAdapter.d.ts +32 -0
- package/dist/adapters/voice/VertexVoiceAdapter.d.ts.map +1 -0
- package/dist/adapters/voice/VertexVoiceAdapter.js +179 -0
- package/dist/adapters/voice/VertexVoiceAdapter.js.map +1 -0
- package/dist/adapters/webhook/WebhookService.d.ts +47 -0
- package/dist/adapters/webhook/WebhookService.d.ts.map +1 -0
- package/dist/adapters/webhook/WebhookService.js +265 -0
- package/dist/adapters/webhook/WebhookService.js.map +1 -0
- package/dist/adapters/workflow/MockWorkflowAdapter.d.ts.map +1 -1
- package/dist/adapters/workflow/MockWorkflowAdapter.js +12 -1
- package/dist/adapters/workflow/MockWorkflowAdapter.js.map +1 -1
- package/dist/adapters/workflow/WorkflowAdapter.d.ts +55 -0
- package/dist/adapters/workflow/WorkflowAdapter.d.ts.map +1 -0
- package/dist/adapters/workflow/WorkflowAdapter.js +242 -0
- package/dist/adapters/workflow/WorkflowAdapter.js.map +1 -0
- package/dist/adapters/workflow/actions/getSupportHoursAction.d.ts +10 -0
- package/dist/adapters/workflow/actions/getSupportHoursAction.d.ts.map +1 -0
- package/dist/adapters/workflow/actions/getSupportHoursAction.js +33 -0
- package/dist/adapters/workflow/actions/getSupportHoursAction.js.map +1 -0
- package/dist/adapters/workflow/actions/index.d.ts +6 -0
- package/dist/adapters/workflow/actions/index.d.ts.map +1 -0
- package/dist/adapters/workflow/actions/index.js +22 -0
- package/dist/adapters/workflow/actions/index.js.map +1 -0
- package/dist/adapters/workflow/actions/pushOutputResultAction.d.ts +11 -0
- package/dist/adapters/workflow/actions/pushOutputResultAction.d.ts.map +1 -0
- package/dist/adapters/workflow/actions/pushOutputResultAction.js +31 -0
- package/dist/adapters/workflow/actions/pushOutputResultAction.js.map +1 -0
- package/dist/adapters/workflow/actions/setWorkflowMessageAction.d.ts +12 -0
- package/dist/adapters/workflow/actions/setWorkflowMessageAction.d.ts.map +1 -0
- package/dist/adapters/workflow/actions/setWorkflowMessageAction.js +32 -0
- package/dist/adapters/workflow/actions/setWorkflowMessageAction.js.map +1 -0
- package/dist/adapters/workflow/engine/constants.d.ts +3 -0
- package/dist/adapters/workflow/engine/constants.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/constants.js +6 -0
- package/dist/adapters/workflow/engine/constants.js.map +1 -0
- package/dist/adapters/workflow/engine/engine.d.ts +32 -0
- package/dist/adapters/workflow/engine/engine.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/engine.js +623 -0
- package/dist/adapters/workflow/engine/engine.js.map +1 -0
- package/dist/adapters/workflow/engine/event-registry.d.ts +12 -0
- package/dist/adapters/workflow/engine/event-registry.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/event-registry.js +33 -0
- package/dist/adapters/workflow/engine/event-registry.js.map +1 -0
- package/dist/adapters/workflow/engine/interpolator.d.ts +11 -0
- package/dist/adapters/workflow/engine/interpolator.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/interpolator.js +93 -0
- package/dist/adapters/workflow/engine/interpolator.js.map +1 -0
- package/dist/adapters/workflow/engine/registry.d.ts +12 -0
- package/dist/adapters/workflow/engine/registry.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/registry.js +39 -0
- package/dist/adapters/workflow/engine/registry.js.map +1 -0
- package/dist/adapters/workflow/engine/template-registry.d.ts +60 -0
- package/dist/adapters/workflow/engine/template-registry.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/template-registry.js +92 -0
- package/dist/adapters/workflow/engine/template-registry.js.map +1 -0
- package/dist/adapters/workflow/engine/types.d.ts +182 -0
- package/dist/adapters/workflow/engine/types.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/types.js +3 -0
- package/dist/adapters/workflow/engine/types.js.map +1 -0
- package/dist/adapters/workflow/engine/utils/format-utils.d.ts +43 -0
- package/dist/adapters/workflow/engine/utils/format-utils.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/utils/format-utils.js +137 -0
- package/dist/adapters/workflow/engine/utils/format-utils.js.map +1 -0
- package/dist/adapters/workflow/engine/utils/layout-calculator.d.ts +7 -0
- package/dist/adapters/workflow/engine/utils/layout-calculator.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/utils/layout-calculator.js +87 -0
- package/dist/adapters/workflow/engine/utils/layout-calculator.js.map +1 -0
- package/dist/adapters/workflow/engine/utils/slugify.d.ts +2 -0
- package/dist/adapters/workflow/engine/utils/slugify.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/utils/slugify.js +41 -0
- package/dist/adapters/workflow/engine/utils/slugify.js.map +1 -0
- package/dist/adapters/workflow/engine/validator.d.ts +9 -0
- package/dist/adapters/workflow/engine/validator.d.ts.map +1 -0
- package/dist/adapters/workflow/engine/validator.js +425 -0
- package/dist/adapters/workflow/engine/validator.js.map +1 -0
- package/dist/config/ChatFlowConfig.d.ts +7 -0
- package/dist/config/ChatFlowConfig.d.ts.map +1 -1
- package/dist/config/ChatFlowConfig.js +5 -0
- package/dist/config/ChatFlowConfig.js.map +1 -1
- package/dist/core/entities/ConversationSession.d.ts +36 -1
- package/dist/core/entities/ConversationSession.d.ts.map +1 -1
- package/dist/core/entities/ConversationSession.js +78 -1
- package/dist/core/entities/ConversationSession.js.map +1 -1
- package/dist/core/entities/Message.d.ts +5 -2
- package/dist/core/entities/Message.d.ts.map +1 -1
- package/dist/core/entities/Message.js +2 -0
- package/dist/core/entities/Message.js.map +1 -1
- package/dist/core/utils/AudioStreamBuffer.d.ts +33 -0
- package/dist/core/utils/AudioStreamBuffer.d.ts.map +1 -0
- package/dist/core/utils/AudioStreamBuffer.js +55 -0
- package/dist/core/utils/AudioStreamBuffer.js.map +1 -0
- package/dist/core/utils/AudioUtils.d.ts +41 -0
- package/dist/core/utils/AudioUtils.d.ts.map +1 -0
- package/dist/core/utils/AudioUtils.js +188 -0
- package/dist/core/utils/AudioUtils.js.map +1 -0
- package/dist/core/utils/LanguageDetector.d.ts +52 -0
- package/dist/core/utils/LanguageDetector.d.ts.map +1 -0
- package/dist/core/utils/LanguageDetector.js +173 -0
- package/dist/core/utils/LanguageDetector.js.map +1 -0
- package/dist/core/utils/WavUtils.d.ts +14 -0
- package/dist/core/utils/WavUtils.d.ts.map +1 -0
- package/dist/core/utils/WavUtils.js +37 -0
- package/dist/core/utils/WavUtils.js.map +1 -0
- package/dist/demo/cli-demo.js +10 -6
- package/dist/demo/cli-demo.js.map +1 -1
- package/dist/demo/console-chat.js +10 -6
- package/dist/demo/console-chat.js.map +1 -1
- package/dist/demo/interactive-voice-chat.d.ts +2 -0
- package/dist/demo/interactive-voice-chat.d.ts.map +1 -0
- package/dist/demo/interactive-voice-chat.js +180 -0
- package/dist/demo/interactive-voice-chat.js.map +1 -0
- package/dist/demo/voice-demo.d.ts +2 -0
- package/dist/demo/voice-demo.d.ts.map +1 -0
- package/dist/demo/voice-demo.js +188 -0
- package/dist/demo/voice-demo.js.map +1 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -8
- package/dist/index.js.map +1 -1
- package/dist/intent/IntentService.d.ts.map +1 -1
- package/dist/intent/IntentService.js +13 -7
- package/dist/intent/IntentService.js.map +1 -1
- package/dist/intent/MockIntentService.d.ts +2 -1
- package/dist/intent/MockIntentService.d.ts.map +1 -1
- package/dist/intent/MockIntentService.js +9 -3
- package/dist/intent/MockIntentService.js.map +1 -1
- package/dist/interfaces.d.ts +551 -6
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js +19 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/orchestrator/Orchestrator.d.ts +48 -4
- package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/Orchestrator.js +650 -33
- package/dist/orchestrator/Orchestrator.js.map +1 -1
- package/dist/scripts/seed-collaborative-intents.d.ts +2 -0
- package/dist/scripts/seed-collaborative-intents.d.ts.map +1 -0
- package/dist/scripts/seed-collaborative-intents.js +90 -0
- package/dist/scripts/seed-collaborative-intents.js.map +1 -0
- package/dist/scripts/test-isolated-config.d.ts +2 -0
- package/dist/scripts/test-isolated-config.d.ts.map +1 -0
- package/dist/scripts/test-isolated-config.js +80 -0
- package/dist/scripts/test-isolated-config.js.map +1 -0
- package/dist/scripts/verify_redis_intents.js +4 -2
- package/dist/scripts/verify_redis_intents.js.map +1 -1
- package/dist/server/ChatFlowWebSocketServer.d.ts +46 -0
- package/dist/server/ChatFlowWebSocketServer.d.ts.map +1 -0
- package/dist/server/ChatFlowWebSocketServer.js +344 -0
- package/dist/server/ChatFlowWebSocketServer.js.map +1 -0
- package/dist/server/realtime-voice-server.d.ts +2 -0
- package/dist/server/realtime-voice-server.d.ts.map +1 -0
- package/dist/server/realtime-voice-server.js +627 -0
- package/dist/server/realtime-voice-server.js.map +1 -0
- package/dist/src/adapters/intent/IntentMatcher.d.ts +41 -0
- package/dist/src/adapters/intent/IntentMatcher.d.ts.map +1 -0
- package/dist/src/adapters/intent/IntentMatcher.js +167 -0
- package/dist/src/adapters/intent/IntentMatcher.js.map +1 -0
- package/dist/src/adapters/intent/IntentService.d.ts +26 -0
- package/dist/src/adapters/intent/IntentService.d.ts.map +1 -0
- package/dist/src/adapters/intent/IntentService.js +65 -0
- package/dist/src/adapters/intent/IntentService.js.map +1 -0
- package/dist/src/adapters/intent/MockIntentService.d.ts +7 -0
- package/dist/src/adapters/intent/MockIntentService.d.ts.map +1 -0
- package/dist/src/adapters/intent/MockIntentService.js +36 -0
- package/dist/src/adapters/intent/MockIntentService.js.map +1 -0
- package/dist/src/adapters/llm/GeminiLLMAdapter.d.ts +10 -0
- package/dist/src/adapters/llm/GeminiLLMAdapter.d.ts.map +1 -0
- package/dist/src/adapters/llm/GeminiLLMAdapter.js +102 -0
- package/dist/src/adapters/llm/GeminiLLMAdapter.js.map +1 -0
- package/dist/src/adapters/llm/MockLLMAdapter.d.ts +5 -0
- package/dist/src/adapters/llm/MockLLMAdapter.d.ts.map +1 -0
- package/dist/src/adapters/llm/MockLLMAdapter.js +31 -0
- package/dist/src/adapters/llm/MockLLMAdapter.js.map +1 -0
- package/dist/src/adapters/llm/OllamaLLMAdapter.d.ts +9 -0
- package/dist/src/adapters/llm/OllamaLLMAdapter.d.ts.map +1 -0
- package/dist/src/adapters/llm/OllamaLLMAdapter.js +74 -0
- package/dist/src/adapters/llm/OllamaLLMAdapter.js.map +1 -0
- package/dist/src/adapters/logger/ConsoleLogger.d.ts +12 -0
- package/dist/src/adapters/logger/ConsoleLogger.d.ts.map +1 -0
- package/dist/src/adapters/logger/ConsoleLogger.js +37 -0
- package/dist/src/adapters/logger/ConsoleLogger.js.map +1 -0
- package/dist/src/adapters/repository/InMemoryRepository.d.ts +57 -0
- package/dist/src/adapters/repository/InMemoryRepository.d.ts.map +1 -0
- package/dist/src/adapters/repository/InMemoryRepository.js +269 -0
- package/dist/src/adapters/repository/InMemoryRepository.js.map +1 -0
- package/dist/src/adapters/repository/RedisRepository.d.ts +72 -0
- package/dist/src/adapters/repository/RedisRepository.d.ts.map +1 -0
- package/dist/src/adapters/repository/RedisRepository.js +700 -0
- package/dist/src/adapters/repository/RedisRepository.js.map +1 -0
- package/dist/src/adapters/repository/SupabaseRepository.d.ts +60 -0
- package/dist/src/adapters/repository/SupabaseRepository.d.ts.map +1 -0
- package/dist/src/adapters/repository/SupabaseRepository.js +774 -0
- package/dist/src/adapters/repository/SupabaseRepository.js.map +1 -0
- package/dist/src/adapters/storage/RedisAudioStorageAdapter.d.ts +33 -0
- package/dist/src/adapters/storage/RedisAudioStorageAdapter.d.ts.map +1 -0
- package/dist/src/adapters/storage/RedisAudioStorageAdapter.js +121 -0
- package/dist/src/adapters/storage/RedisAudioStorageAdapter.js.map +1 -0
- package/dist/src/adapters/voice/GoogleVoiceAdapter.d.ts +33 -0
- package/dist/src/adapters/voice/GoogleVoiceAdapter.d.ts.map +1 -0
- package/dist/src/adapters/voice/GoogleVoiceAdapter.js +155 -0
- package/dist/src/adapters/voice/GoogleVoiceAdapter.js.map +1 -0
- package/dist/src/adapters/voice/LanguageVoiceMapper.d.ts +60 -0
- package/dist/src/adapters/voice/LanguageVoiceMapper.d.ts.map +1 -0
- package/dist/src/adapters/voice/LanguageVoiceMapper.js +130 -0
- package/dist/src/adapters/voice/LanguageVoiceMapper.js.map +1 -0
- package/dist/src/adapters/voice/VertexVoiceAdapter.d.ts +32 -0
- package/dist/src/adapters/voice/VertexVoiceAdapter.d.ts.map +1 -0
- package/dist/src/adapters/voice/VertexVoiceAdapter.js +179 -0
- package/dist/src/adapters/voice/VertexVoiceAdapter.js.map +1 -0
- package/dist/src/adapters/webhook/WebhookService.d.ts +47 -0
- package/dist/src/adapters/webhook/WebhookService.d.ts.map +1 -0
- package/dist/src/adapters/webhook/WebhookService.js +265 -0
- package/dist/src/adapters/webhook/WebhookService.js.map +1 -0
- package/dist/src/adapters/workflow/MockWorkflowAdapter.d.ts +5 -0
- package/dist/src/adapters/workflow/MockWorkflowAdapter.d.ts.map +1 -0
- package/dist/src/adapters/workflow/MockWorkflowAdapter.js +173 -0
- package/dist/src/adapters/workflow/MockWorkflowAdapter.js.map +1 -0
- package/dist/src/adapters/workflow/WorkflowAdapter.d.ts +55 -0
- package/dist/src/adapters/workflow/WorkflowAdapter.d.ts.map +1 -0
- package/dist/src/adapters/workflow/WorkflowAdapter.js +203 -0
- package/dist/src/adapters/workflow/WorkflowAdapter.js.map +1 -0
- package/dist/src/adapters/workflow/actions/index.d.ts +6 -0
- package/dist/src/adapters/workflow/actions/index.d.ts.map +1 -0
- package/dist/src/adapters/workflow/actions/index.js +22 -0
- package/dist/src/adapters/workflow/actions/index.js.map +1 -0
- package/dist/src/adapters/workflow/actions/pushOutputResultAction.d.ts +11 -0
- package/dist/src/adapters/workflow/actions/pushOutputResultAction.d.ts.map +1 -0
- package/dist/src/adapters/workflow/actions/pushOutputResultAction.js +31 -0
- package/dist/src/adapters/workflow/actions/pushOutputResultAction.js.map +1 -0
- package/dist/src/adapters/workflow/engine/constants.d.ts +3 -0
- package/dist/src/adapters/workflow/engine/constants.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/constants.js +6 -0
- package/dist/src/adapters/workflow/engine/constants.js.map +1 -0
- package/dist/src/adapters/workflow/engine/engine.d.ts +32 -0
- package/dist/src/adapters/workflow/engine/engine.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/engine.js +622 -0
- package/dist/src/adapters/workflow/engine/engine.js.map +1 -0
- package/dist/src/adapters/workflow/engine/event-registry.d.ts +12 -0
- package/dist/src/adapters/workflow/engine/event-registry.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/event-registry.js +33 -0
- package/dist/src/adapters/workflow/engine/event-registry.js.map +1 -0
- package/dist/src/adapters/workflow/engine/interpolator.d.ts +11 -0
- package/dist/src/adapters/workflow/engine/interpolator.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/interpolator.js +93 -0
- package/dist/src/adapters/workflow/engine/interpolator.js.map +1 -0
- package/dist/src/adapters/workflow/engine/registry.d.ts +12 -0
- package/dist/src/adapters/workflow/engine/registry.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/registry.js +39 -0
- package/dist/src/adapters/workflow/engine/registry.js.map +1 -0
- package/dist/src/adapters/workflow/engine/template-registry.d.ts +60 -0
- package/dist/src/adapters/workflow/engine/template-registry.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/template-registry.js +92 -0
- package/dist/src/adapters/workflow/engine/template-registry.js.map +1 -0
- package/dist/src/adapters/workflow/engine/utils/format-utils.d.ts +43 -0
- package/dist/src/adapters/workflow/engine/utils/format-utils.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/utils/format-utils.js +137 -0
- package/dist/src/adapters/workflow/engine/utils/format-utils.js.map +1 -0
- package/dist/src/adapters/workflow/engine/utils/layout-calculator.d.ts +7 -0
- package/dist/src/adapters/workflow/engine/utils/layout-calculator.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/utils/layout-calculator.js +87 -0
- package/dist/src/adapters/workflow/engine/utils/layout-calculator.js.map +1 -0
- package/dist/src/adapters/workflow/engine/utils/slugify.d.ts +2 -0
- package/dist/src/adapters/workflow/engine/utils/slugify.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/utils/slugify.js +41 -0
- package/dist/src/adapters/workflow/engine/utils/slugify.js.map +1 -0
- package/dist/src/adapters/workflow/engine/validator.d.ts +9 -0
- package/dist/src/adapters/workflow/engine/validator.d.ts.map +1 -0
- package/dist/src/adapters/workflow/engine/validator.js +425 -0
- package/dist/src/adapters/workflow/engine/validator.js.map +1 -0
- package/dist/src/api/router.d.ts +3 -0
- package/dist/src/api/router.d.ts.map +1 -0
- package/dist/src/api/router.js +27 -0
- package/dist/src/api/router.js.map +1 -0
- package/dist/src/api/routes/configs.d.ts +3 -0
- package/dist/src/api/routes/configs.d.ts.map +1 -0
- package/dist/src/api/routes/configs.js +110 -0
- package/dist/src/api/routes/configs.js.map +1 -0
- package/dist/src/api/routes/executions.d.ts +3 -0
- package/dist/src/api/routes/executions.d.ts.map +1 -0
- package/dist/src/api/routes/executions.js +77 -0
- package/dist/src/api/routes/executions.js.map +1 -0
- package/dist/src/api/routes/intents.d.ts +3 -0
- package/dist/src/api/routes/intents.d.ts.map +1 -0
- package/dist/src/api/routes/intents.js +128 -0
- package/dist/src/api/routes/intents.js.map +1 -0
- package/dist/src/api/routes/sessions.d.ts +3 -0
- package/dist/src/api/routes/sessions.d.ts.map +1 -0
- package/dist/src/api/routes/sessions.js +105 -0
- package/dist/src/api/routes/sessions.js.map +1 -0
- package/dist/src/api/routes/tenants.d.ts +3 -0
- package/dist/src/api/routes/tenants.d.ts.map +1 -0
- package/dist/src/api/routes/tenants.js +109 -0
- package/dist/src/api/routes/tenants.js.map +1 -0
- package/dist/src/api/routes/users.d.ts +3 -0
- package/dist/src/api/routes/users.d.ts.map +1 -0
- package/dist/src/api/routes/users.js +51 -0
- package/dist/src/api/routes/users.js.map +1 -0
- package/dist/src/api/routes/workflows.d.ts +3 -0
- package/dist/src/api/routes/workflows.d.ts.map +1 -0
- package/dist/src/api/routes/workflows.js +132 -0
- package/dist/src/api/routes/workflows.js.map +1 -0
- package/dist/src/config/ChatFlowConfig.d.ts +66 -0
- package/dist/src/config/ChatFlowConfig.d.ts.map +1 -0
- package/dist/src/config/ChatFlowConfig.js +54 -0
- package/dist/src/config/ChatFlowConfig.js.map +1 -0
- package/dist/src/config/index.d.ts +2 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +7 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/config/swagger.d.ts +2 -0
- package/dist/src/config/swagger.d.ts.map +1 -0
- package/dist/src/config/swagger.js +136 -0
- package/dist/src/config/swagger.js.map +1 -0
- package/dist/src/core/entities/ConversationSession.d.ts +58 -0
- package/dist/src/core/entities/ConversationSession.d.ts.map +1 -0
- package/dist/src/core/entities/ConversationSession.js +160 -0
- package/dist/src/core/entities/ConversationSession.js.map +1 -0
- package/dist/src/core/entities/Message.d.ts +14 -0
- package/dist/src/core/entities/Message.d.ts.map +1 -0
- package/dist/src/core/entities/Message.js +32 -0
- package/dist/src/core/entities/Message.js.map +1 -0
- package/dist/src/core/errors/ChatFlowError.d.ts +71 -0
- package/dist/src/core/errors/ChatFlowError.d.ts.map +1 -0
- package/dist/src/core/errors/ChatFlowError.js +108 -0
- package/dist/src/core/errors/ChatFlowError.js.map +1 -0
- package/dist/src/core/errors/index.d.ts +2 -0
- package/dist/src/core/errors/index.d.ts.map +1 -0
- package/dist/src/core/errors/index.js +15 -0
- package/dist/src/core/errors/index.js.map +1 -0
- package/dist/src/core/utils/AudioUtils.d.ts +41 -0
- package/dist/src/core/utils/AudioUtils.d.ts.map +1 -0
- package/dist/src/core/utils/AudioUtils.js +188 -0
- package/dist/src/core/utils/AudioUtils.js.map +1 -0
- package/dist/src/core/utils/LanguageDetector.d.ts +52 -0
- package/dist/src/core/utils/LanguageDetector.d.ts.map +1 -0
- package/dist/src/core/utils/LanguageDetector.js +173 -0
- package/dist/src/core/utils/LanguageDetector.js.map +1 -0
- package/dist/src/demo/cli-demo.d.ts +2 -0
- package/dist/src/demo/cli-demo.d.ts.map +1 -0
- package/dist/src/demo/cli-demo.js +146 -0
- package/dist/src/demo/cli-demo.js.map +1 -0
- package/dist/src/demo/console-chat.d.ts +2 -0
- package/dist/src/demo/console-chat.d.ts.map +1 -0
- package/dist/src/demo/console-chat.js +148 -0
- package/dist/src/demo/console-chat.js.map +1 -0
- package/dist/src/index.d.ts +27 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +78 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/interfaces.d.ts +663 -0
- package/dist/src/interfaces.d.ts.map +1 -0
- package/dist/src/interfaces.js +36 -0
- package/dist/src/interfaces.js.map +1 -0
- package/dist/src/orchestrator/Orchestrator.d.ts +62 -0
- package/dist/src/orchestrator/Orchestrator.d.ts.map +1 -0
- package/dist/src/orchestrator/Orchestrator.js +697 -0
- package/dist/src/orchestrator/Orchestrator.js.map +1 -0
- package/dist/src/scripts/debug-redis.d.ts +2 -0
- package/dist/src/scripts/debug-redis.d.ts.map +1 -0
- package/dist/src/scripts/debug-redis.js +55 -0
- package/dist/src/scripts/debug-redis.js.map +1 -0
- package/dist/src/scripts/seed-collaborative-intents.d.ts +2 -0
- package/dist/src/scripts/seed-collaborative-intents.d.ts.map +1 -0
- package/dist/src/scripts/seed-collaborative-intents.js +90 -0
- package/dist/src/scripts/seed-collaborative-intents.js.map +1 -0
- package/dist/src/scripts/test-isolated-config.d.ts +2 -0
- package/dist/src/scripts/test-isolated-config.d.ts.map +1 -0
- package/dist/src/scripts/test-isolated-config.js +80 -0
- package/dist/src/scripts/test-isolated-config.js.map +1 -0
- package/dist/src/scripts/verify_memory_intents.d.ts +2 -0
- package/dist/src/scripts/verify_memory_intents.d.ts.map +1 -0
- package/dist/src/scripts/verify_memory_intents.js +45 -0
- package/dist/src/scripts/verify_memory_intents.js.map +1 -0
- package/dist/src/scripts/verify_redis_intents.d.ts +2 -0
- package/dist/src/scripts/verify_redis_intents.d.ts.map +1 -0
- package/dist/src/scripts/verify_redis_intents.js +52 -0
- package/dist/src/scripts/verify_redis_intents.js.map +1 -0
- package/dist/src/server/ChatFlowWebSocketServer.d.ts +42 -0
- package/dist/src/server/ChatFlowWebSocketServer.d.ts.map +1 -0
- package/dist/src/server/ChatFlowWebSocketServer.js +355 -0
- package/dist/src/server/ChatFlowWebSocketServer.js.map +1 -0
- package/dist/src/utils/crypto.d.ts +7 -0
- package/dist/src/utils/crypto.d.ts.map +1 -0
- package/dist/src/utils/crypto.js +35 -0
- package/dist/src/utils/crypto.js.map +1 -0
- package/dist/src/utils/encryption-helpers.d.ts +14 -0
- package/dist/src/utils/encryption-helpers.d.ts.map +1 -0
- package/dist/src/utils/encryption-helpers.js +49 -0
- package/dist/src/utils/encryption-helpers.js.map +1 -0
- package/dist/utils/crypto.d.ts +7 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +35 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/encryption-helpers.d.ts +14 -0
- package/dist/utils/encryption-helpers.d.ts.map +1 -0
- package/dist/utils/encryption-helpers.js +49 -0
- package/dist/utils/encryption-helpers.js.map +1 -0
- package/dist/web/seed-demo-data.d.ts +2 -0
- package/dist/web/seed-demo-data.d.ts.map +1 -0
- package/dist/web/seed-demo-data.js +267 -0
- package/dist/web/seed-demo-data.js.map +1 -0
- package/dist/web/web-server.d.ts +2 -0
- package/dist/web/web-server.d.ts.map +1 -0
- package/dist/web/web-server.js +165 -0
- package/dist/web/web-server.js.map +1 -0
- package/package.json +32 -3
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Orchestrator = void 0;
|
|
4
|
+
const ConversationSession_1 = require("../core/entities/ConversationSession");
|
|
5
|
+
const Message_1 = require("../core/entities/Message");
|
|
6
|
+
const LanguageDetector_1 = require("../core/utils/LanguageDetector");
|
|
7
|
+
const interfaces_1 = require("../interfaces");
|
|
8
|
+
const errors_1 = require("../core/errors");
|
|
9
|
+
const config_1 = require("../config");
|
|
10
|
+
class Orchestrator {
|
|
11
|
+
constructor(repo, llm, intent, workflow, webhookService, voiceAdapter, audioStorage, config) {
|
|
12
|
+
this.repo = repo;
|
|
13
|
+
this.llm = llm;
|
|
14
|
+
this.intent = intent;
|
|
15
|
+
this.workflow = workflow;
|
|
16
|
+
this.webhookService = webhookService;
|
|
17
|
+
this.voiceAdapter = voiceAdapter;
|
|
18
|
+
this.audioStorage = audioStorage;
|
|
19
|
+
this.config = config ? { ...config_1.DEFAULT_CONFIG, ...config } : config_1.DEFAULT_CONFIG;
|
|
20
|
+
this.languageDetector = new LanguageDetector_1.LanguageDetector(llm);
|
|
21
|
+
}
|
|
22
|
+
async createSession(sessionId, mode, agentPrompt, userId, configId) {
|
|
23
|
+
// Business Rule: If userId and configId are provided, validate ownership and resolve prompt
|
|
24
|
+
let resolvedPrompt = agentPrompt;
|
|
25
|
+
let webhookConfig;
|
|
26
|
+
if (userId && configId) {
|
|
27
|
+
console.log(`[Orchestrator] Validating config '${configId}' for user '${userId}'`);
|
|
28
|
+
const config = await this.repo.findConversationConfig(userId, configId);
|
|
29
|
+
if (!config) {
|
|
30
|
+
console.error(`[Orchestrator] Security Alert: Config '${configId}' not found for user '${userId}'`);
|
|
31
|
+
throw new Error('Invalid Configuration: Config does not belong to User');
|
|
32
|
+
}
|
|
33
|
+
// Use the config's system prompt if available, otherwise fall back to passed prompt
|
|
34
|
+
if (config.systemPrompt) {
|
|
35
|
+
resolvedPrompt = config.systemPrompt;
|
|
36
|
+
}
|
|
37
|
+
webhookConfig = config.webhook;
|
|
38
|
+
}
|
|
39
|
+
// Enforce safe voice behavior: Single-turn responses, no narration of actions
|
|
40
|
+
let finalPrompt = resolvedPrompt;
|
|
41
|
+
if (mode === 'VOICE') {
|
|
42
|
+
finalPrompt += `
|
|
43
|
+
|
|
44
|
+
[VOICE INTERFACE INSTRUCTIONS]
|
|
45
|
+
- Provide the full, final answer in a single response.
|
|
46
|
+
- Do NOT narrate your actions (e.g., "Let me check", "One moment") unless you include the result in the same response.
|
|
47
|
+
- If you cannot perform a task, state it clearly immediately.
|
|
48
|
+
- Keep responses concise and suitable for text-to-speech.
|
|
49
|
+
- Do NOT ask "Is there anything else?" or generic follow-up questions. Only ask questions if you need specific information to complete the CURRENT task.
|
|
50
|
+
- If the user says "Thanks" or "Goodbye", just reply with a short closing (e.g., "You're welcome" or "Goodbye") and stop.`;
|
|
51
|
+
}
|
|
52
|
+
const session = new ConversationSession_1.ConversationSession({
|
|
53
|
+
sessionId,
|
|
54
|
+
userId,
|
|
55
|
+
configId,
|
|
56
|
+
mode,
|
|
57
|
+
agentPrompt: finalPrompt,
|
|
58
|
+
conversationMode: 'collaborative' // Default to collaborative mode
|
|
59
|
+
});
|
|
60
|
+
if (webhookConfig) {
|
|
61
|
+
session.setMetadata('webhookConfig', webhookConfig);
|
|
62
|
+
}
|
|
63
|
+
await this.repo.saveSession(session);
|
|
64
|
+
// Initialize Storage (Only for VOICE mode)
|
|
65
|
+
if (this.audioStorage && mode === 'VOICE') {
|
|
66
|
+
await this.audioStorage.initializeSession(sessionId, { userId, configId });
|
|
67
|
+
}
|
|
68
|
+
// Trigger session.started webhook
|
|
69
|
+
await this.webhookService.triggerSessionStarted(session);
|
|
70
|
+
return session;
|
|
71
|
+
}
|
|
72
|
+
async processMessage(sessionId, content, onIntermediateResponse) {
|
|
73
|
+
// 1. Load Session
|
|
74
|
+
const session = await this.repo.findSessionById(sessionId);
|
|
75
|
+
if (!session) {
|
|
76
|
+
throw new errors_1.SessionNotFoundError(sessionId);
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
// 2. Append User Message
|
|
80
|
+
const userMessage = Message_1.Message.user(content);
|
|
81
|
+
session.addMessage(userMessage);
|
|
82
|
+
// 3. Safety Check: Enforce maximum conversation length (system-level protection)
|
|
83
|
+
const MAX_TOTAL_MSG_COUNT = parseInt(process.env.MAX_TOTAL_MSG_COUNT || '60', 10);
|
|
84
|
+
const totalMessages = session.messages.length;
|
|
85
|
+
if (totalMessages > MAX_TOTAL_MSG_COUNT) {
|
|
86
|
+
console.warn(`[Safety] Conversation limit exceeded for session ${sessionId}(${totalMessages} messages).Terminating.`);
|
|
87
|
+
throw new Error(`Conversation limit reached(${MAX_TOTAL_MSG_COUNT} messages).Please start a new session.`);
|
|
88
|
+
}
|
|
89
|
+
// 4. Content Filtering: Blacklisted words (configured per user/config)
|
|
90
|
+
const config = session.configId && session.userId
|
|
91
|
+
? await this.repo.findConversationConfig(session.userId, session.configId)
|
|
92
|
+
: null;
|
|
93
|
+
const blacklistedWords = config?.blacklistedWords || [];
|
|
94
|
+
if (blacklistedWords.length > 0) {
|
|
95
|
+
const cleanContent = content.trim().toLowerCase();
|
|
96
|
+
const isBlacklisted = blacklistedWords.some(word => cleanContent.includes(word.toLowerCase()));
|
|
97
|
+
if (isBlacklisted) {
|
|
98
|
+
console.log(`[Orchestrator] Ignored blacklisted content: "${content}"`);
|
|
99
|
+
throw new Error('Message contains prohibited content.');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Trigger message.user webhook (only for validated messages) - Fire-and-forget
|
|
103
|
+
this.webhookService.triggerUserMessage(session, userMessage).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
104
|
+
// 5. Exit Phrase Detection (universal session termination)
|
|
105
|
+
// Default common exit phrases (English)
|
|
106
|
+
const DEFAULT_EXIT_PHRASES = ['goodbye', 'bye', 'stop session', 'end session', 'quit', 'exit'];
|
|
107
|
+
// Use config-specific exit phrases if available, otherwise use defaults
|
|
108
|
+
// If config provides phrases, merge with defaults to ensure common phrases always work
|
|
109
|
+
const configExitPhrases = config?.exitPhrases || [];
|
|
110
|
+
const EXIT_PHRASES = configExitPhrases.length > 0
|
|
111
|
+
? [...DEFAULT_EXIT_PHRASES, ...configExitPhrases]
|
|
112
|
+
: DEFAULT_EXIT_PHRASES;
|
|
113
|
+
const lowerContent = content.toLowerCase();
|
|
114
|
+
const shouldEndSession = EXIT_PHRASES.some(phrase => lowerContent.includes(phrase));
|
|
115
|
+
if (shouldEndSession) {
|
|
116
|
+
console.log(`[Orchestrator] Exit phrase detected: "${content}"`);
|
|
117
|
+
}
|
|
118
|
+
const newMessages = [];
|
|
119
|
+
// 6. Language Detection (Smart & Optimized) - Will run in PARALLEL with Intent Detection
|
|
120
|
+
let detectedLanguage;
|
|
121
|
+
let languageName;
|
|
122
|
+
let languageChanged = false;
|
|
123
|
+
// Check if multi-lingual mode is enabled
|
|
124
|
+
const multiLingualEnabled = config?.multiLingualMode !== false; // Default true if not specified
|
|
125
|
+
const defaultLanguage = config?.defaultLanguage || 'en';
|
|
126
|
+
const previousLanguage = session.currentLanguage;
|
|
127
|
+
// 7. Check if we're in the middle of parameter collection
|
|
128
|
+
if (session.isCollectingParameters()) {
|
|
129
|
+
return await this.handleParameterCollection(session, content, newMessages);
|
|
130
|
+
}
|
|
131
|
+
// 6 & 8. PARALLEL EXECUTION: Run Language Detection and Intent Detection concurrently
|
|
132
|
+
// Both are independent LLM API calls - running in parallel saves 100-300ms
|
|
133
|
+
console.log(`[Orchestrator] Starting parallel language detection and intent classification...`);
|
|
134
|
+
const [languageResult, intentResult] = await Promise.all([
|
|
135
|
+
// Language Detection Promise
|
|
136
|
+
(async () => {
|
|
137
|
+
if (multiLingualEnabled) {
|
|
138
|
+
const shouldDetect = !previousLanguage ||
|
|
139
|
+
this.languageDetector.hasCharacterSetChanged(content, previousLanguage);
|
|
140
|
+
if (shouldDetect) {
|
|
141
|
+
const languageHints = config?.supportedLanguages;
|
|
142
|
+
const detected = await this.languageDetector.detectLanguage(content, languageHints);
|
|
143
|
+
const name = this.languageDetector.getLanguageName(detected);
|
|
144
|
+
const changed = previousLanguage && previousLanguage !== detected;
|
|
145
|
+
if (changed) {
|
|
146
|
+
console.log(`[Orchestrator] Language switched: ${previousLanguage} → ${detected} (${name})`);
|
|
147
|
+
}
|
|
148
|
+
else if (!previousLanguage) {
|
|
149
|
+
console.log(`[Orchestrator] Language detected: ${detected} (${name})`);
|
|
150
|
+
}
|
|
151
|
+
session.setLanguage(detected);
|
|
152
|
+
if (session.mode === 'VOICE' && this.voiceAdapter && 'setLanguage' in this.voiceAdapter) {
|
|
153
|
+
this.voiceAdapter.setLanguage(detected);
|
|
154
|
+
}
|
|
155
|
+
return { detectedLanguage: detected, languageName: name, languageChanged: !!changed };
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const detected = previousLanguage;
|
|
159
|
+
const name = this.languageDetector.getLanguageName(detected);
|
|
160
|
+
console.log(`[Orchestrator] Using cached language: ${detected} (${name})`);
|
|
161
|
+
return { detectedLanguage: detected, languageName: name, languageChanged: false };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
const detected = defaultLanguage;
|
|
166
|
+
const name = this.languageDetector.getLanguageName(detected);
|
|
167
|
+
if (!session.currentLanguage) {
|
|
168
|
+
console.log(`[Orchestrator] Multi - lingual mode disabled.Using default: ${detected} (${name})`);
|
|
169
|
+
session.setLanguage(detected);
|
|
170
|
+
}
|
|
171
|
+
return { detectedLanguage: detected, languageName: name, languageChanged: false };
|
|
172
|
+
}
|
|
173
|
+
})(),
|
|
174
|
+
// Intent Detection Promise (runs in parallel)
|
|
175
|
+
this.intent.detectIntent(session.getHistory(), session.agentPrompt, session.userId)
|
|
176
|
+
]);
|
|
177
|
+
// Extract results from parallel execution
|
|
178
|
+
detectedLanguage = languageResult.detectedLanguage;
|
|
179
|
+
languageName = languageResult.languageName;
|
|
180
|
+
languageChanged = languageResult.languageChanged;
|
|
181
|
+
// 9. Collaborative mode: handle partial intents
|
|
182
|
+
if (session.conversationMode === 'collaborative' &&
|
|
183
|
+
intentResult.intentName &&
|
|
184
|
+
intentResult.missingRequiredParameters &&
|
|
185
|
+
intentResult.missingRequiredParameters.length > 0 &&
|
|
186
|
+
intentResult.confidence >= this.config.intent.confidenceThreshold) {
|
|
187
|
+
console.log(`[Orchestrator] COLLABORATIVE: Intent '${intentResult.intentName}' detected with missing parameters: ${intentResult.missingRequiredParameters.join(', ')} `);
|
|
188
|
+
return await this.startParameterCollection(session, intentResult, newMessages);
|
|
189
|
+
}
|
|
190
|
+
// 10. Execute workflow if intent is complete and confident
|
|
191
|
+
if (intentResult.intentName && intentResult.confidence >= this.config.intent.confidenceThreshold) {
|
|
192
|
+
console.log(`[Orchestrator] DECISION: Execute Workflow '${intentResult.intentName}'(Confidence ${intentResult.confidence} >= ${this.config.intent.confidenceThreshold})`);
|
|
193
|
+
// VERBAL ACKNOWLEDGMENT (Filler Phrase)
|
|
194
|
+
// Fetch full intent to check for processing messages
|
|
195
|
+
const fullIntent = await this.repo.findIntentByName(intentResult.intentName, session.userId);
|
|
196
|
+
if (fullIntent?.processingMessages && fullIntent.processingMessages.length > 0 && onIntermediateResponse) {
|
|
197
|
+
const randomPhrase = fullIntent.processingMessages[Math.floor(Math.random() * fullIntent.processingMessages.length)];
|
|
198
|
+
console.log(`[Orchestrator] Sending filler phrase: "${randomPhrase}"`);
|
|
199
|
+
// Fire and forget? No, we should wait for it to start ensuring order?
|
|
200
|
+
// Actually, TTS generation takes time. We want to start it concurrently with workflow if possible,
|
|
201
|
+
// BUT if workflow is fast, we might get double audio overlap.
|
|
202
|
+
// Given the goal is "filling silence", we should probably fire it.
|
|
203
|
+
// However, `onIntermediateResponse` will likely queue audio.
|
|
204
|
+
await onIntermediateResponse(randomPhrase);
|
|
205
|
+
}
|
|
206
|
+
// Update User Message Metadata with Detected Intent
|
|
207
|
+
userMessage.metadata = {
|
|
208
|
+
...userMessage.metadata,
|
|
209
|
+
intent: {
|
|
210
|
+
name: intentResult.intentName,
|
|
211
|
+
confidence: intentResult.confidence,
|
|
212
|
+
parameters: intentResult.payload
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
// Trigger intent.detected webhook - Fire-and-forget
|
|
216
|
+
this.webhookService.triggerIntentDetected(session, intentResult).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
217
|
+
if (fullIntent?.skipWorkflow) {
|
|
218
|
+
console.log(`[Orchestrator] Intent '${intentResult.intentName}' marked as skipWorkflow. Skipping execution.`);
|
|
219
|
+
// Inject Intent Context for LLM
|
|
220
|
+
const contextMessage = new Message_1.Message({
|
|
221
|
+
role: interfaces_1.Role.SYSTEM,
|
|
222
|
+
content: `[System Info: User intent '${intentResult.intentName}' detected. This intent is informational/metadata-only (No Workflow). Answer the user naturally based on this intent.]`,
|
|
223
|
+
timestamp: new Date()
|
|
224
|
+
});
|
|
225
|
+
// Transient history
|
|
226
|
+
const transientHistory = [...session.getHistory(), contextMessage];
|
|
227
|
+
const llmResponse = await this.llm.generateResponse(session.agentPrompt, transientHistory);
|
|
228
|
+
const assistantMsg = Message_1.Message.assistant(llmResponse.content);
|
|
229
|
+
session.addMessage(assistantMsg);
|
|
230
|
+
newMessages.push(assistantMsg);
|
|
231
|
+
// Trigger message.bot webhook
|
|
232
|
+
if (this.webhookService) {
|
|
233
|
+
this.webhookService.triggerBotMessage(session, assistantMsg).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// Inject userId into payload for correct workflow lookup
|
|
238
|
+
const workflowPayload = {
|
|
239
|
+
...intentResult.payload,
|
|
240
|
+
userId: session.userId
|
|
241
|
+
};
|
|
242
|
+
const workflowResult = await this.workflow.executeWorkflow(intentResult.intentName, workflowPayload);
|
|
243
|
+
let assistantContent;
|
|
244
|
+
// CHECK: Did the workflow return an explicit final message?
|
|
245
|
+
if (workflowResult.success && workflowResult.data && workflowResult.data.message) {
|
|
246
|
+
console.log(`[Orchestrator] Workflow '${intentResult.intentName}' returned explicit final message. Skipping LLM generation.`);
|
|
247
|
+
assistantContent = workflowResult.data.message;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// Fallback: Use LLM to generate response based on workflow result
|
|
251
|
+
console.log(`[Orchestrator] Workflow '${intentResult.intentName}' executed without explicit final message. Using LLM to generate response.`);
|
|
252
|
+
// Inject Workflow Result
|
|
253
|
+
const workflowContextMessage = new Message_1.Message({
|
|
254
|
+
role: interfaces_1.Role.SYSTEM,
|
|
255
|
+
content: `[System Info: Workflow detected '${intentResult.intentName}'.Execution Result: ${JSON.stringify(workflowResult.data)}. Use this to answer the user.]`,
|
|
256
|
+
timestamp: new Date()
|
|
257
|
+
});
|
|
258
|
+
// Transient history
|
|
259
|
+
const transientHistory = [...session.getHistory(), workflowContextMessage];
|
|
260
|
+
const llmResponse = await this.llm.generateResponse(session.agentPrompt, transientHistory);
|
|
261
|
+
assistantContent = llmResponse.content;
|
|
262
|
+
}
|
|
263
|
+
const assistantMsg = Message_1.Message.assistant(assistantContent);
|
|
264
|
+
session.addMessage(assistantMsg);
|
|
265
|
+
newMessages.push(assistantMsg);
|
|
266
|
+
// Trigger workflow webhook based on success/failure
|
|
267
|
+
if (workflowResult.success) {
|
|
268
|
+
// Update User Message Metadata with Workflow Execution
|
|
269
|
+
userMessage.metadata = {
|
|
270
|
+
...userMessage.metadata,
|
|
271
|
+
workflow: {
|
|
272
|
+
id: intentResult.intentName,
|
|
273
|
+
result: workflowResult.data
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
// Fire-and-forget
|
|
277
|
+
this.webhookService.triggerWorkflowExecuted(session, {
|
|
278
|
+
workflowName: intentResult.intentName,
|
|
279
|
+
parameters: intentResult.payload,
|
|
280
|
+
result: workflowResult
|
|
281
|
+
}).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
282
|
+
}
|
|
283
|
+
else if (workflowResult.error === 'NO_WORKFLOW_MATCHED') {
|
|
284
|
+
// Smart Workflow handling:
|
|
285
|
+
// If no workflow matches, we treat it as "Intent detected but no specific logic".
|
|
286
|
+
// We do NOT fire a failure webhook, but instead let the LLM handle it naturally.
|
|
287
|
+
console.log(`[Orchestrator] Smart Workflow: No workflow found for '${intentResult.intentName}'. Falling back to LLM.`);
|
|
288
|
+
// Inject Context for LLM so it knows intent was detected but handled generically
|
|
289
|
+
const workflowContextMessage = new Message_1.Message({
|
|
290
|
+
role: interfaces_1.Role.SYSTEM,
|
|
291
|
+
content: `[System Info: User intent '${intentResult.intentName}' detected, but no specific workflow is configured. Answer the user naturally based on this intent.]`,
|
|
292
|
+
timestamp: new Date()
|
|
293
|
+
});
|
|
294
|
+
// Transient history
|
|
295
|
+
const transientHistory = [...session.getHistory(), workflowContextMessage];
|
|
296
|
+
const llmResponse = await this.llm.generateResponse(session.agentPrompt, transientHistory);
|
|
297
|
+
assistantContent = llmResponse.content;
|
|
298
|
+
// Note: We intentionally DO NOT update userMessage metadata with 'workflow'
|
|
299
|
+
// and DO NOT trigger workflow.failed or workflow.executed webhooks.
|
|
300
|
+
// This makes the lack of workflow invisible to the outside world (except for the intent detection).
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// Update User Message Metadata with Workflow Failure
|
|
304
|
+
userMessage.metadata = {
|
|
305
|
+
...userMessage.metadata,
|
|
306
|
+
workflow: {
|
|
307
|
+
id: intentResult.intentName,
|
|
308
|
+
error: workflowResult.error
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
// Fire-and-forget
|
|
312
|
+
this.webhookService.triggerWorkflowFailed(session, {
|
|
313
|
+
workflowName: intentResult.intentName,
|
|
314
|
+
parameters: intentResult.payload,
|
|
315
|
+
error: workflowResult.error
|
|
316
|
+
}).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
317
|
+
}
|
|
318
|
+
// Trigger message.bot webhook - Fire-and-forget
|
|
319
|
+
if (this.webhookService) {
|
|
320
|
+
this.webhookService.triggerBotMessage(session, assistantMsg).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
// 11. Fallback to standard LLM with language-specific prompt
|
|
326
|
+
if (intentResult.intentName) {
|
|
327
|
+
console.log(`[Orchestrator] DECISION: Skip Workflow '${intentResult.intentName}'(Confidence ${intentResult.confidence} < ${this.config.intent.confidenceThreshold}).Proceeding with Standard LLM.`);
|
|
328
|
+
// Trigger intent.failed webhook - Fire-and-forget
|
|
329
|
+
this.webhookService.triggerIntentFailed(session, intentResult).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
console.log(`[Orchestrator] DECISION: No Intent Detected.Proceeding with Standard LLM.`);
|
|
333
|
+
}
|
|
334
|
+
// Inject language instruction into system prompt
|
|
335
|
+
const languagePrompt = `${session.agentPrompt} \n\n[LANGUAGE INSTRUCTION]\n - The user is speaking in ${languageName} (${detectedLanguage}).\n - You MUST respond in ${languageName}.\n - Match the user's language exactly.`;
|
|
336
|
+
const llmResponse = await this.llm.generateResponse(languagePrompt, session.getHistory());
|
|
337
|
+
const assistantMsg = Message_1.Message.assistant(llmResponse.content, { detectedLanguage });
|
|
338
|
+
session.addMessage(assistantMsg);
|
|
339
|
+
newMessages.push(assistantMsg);
|
|
340
|
+
// Trigger message.bot webhook - Fire-and-forget
|
|
341
|
+
this.webhookService.triggerBotMessage(session, assistantMsg).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
342
|
+
}
|
|
343
|
+
// 12. Save
|
|
344
|
+
await this.repo.saveSession(session);
|
|
345
|
+
return {
|
|
346
|
+
messages: newMessages,
|
|
347
|
+
metadata: {
|
|
348
|
+
intent: intentResult.intentName,
|
|
349
|
+
confidence: intentResult.confidence,
|
|
350
|
+
workflowExecuted: (intentResult.intentName && intentResult.confidence >= this.config.intent.confidenceThreshold) ? intentResult.intentName : null,
|
|
351
|
+
shouldEndSession: shouldEndSession,
|
|
352
|
+
detectedLanguage: detectedLanguage,
|
|
353
|
+
languageName: languageName,
|
|
354
|
+
languageChanged: languageChanged
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
// Fire-and-forget error webhook
|
|
360
|
+
this.webhookService.triggerErrorOccurred(session, error).catch(e => console.error('[Orchestrator] Webhook failed:', e));
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Start parameter collection for a detected intent with missing parameters
|
|
366
|
+
*/
|
|
367
|
+
async startParameterCollection(session, intentResult, newMessages) {
|
|
368
|
+
// Initialize parameter collection state
|
|
369
|
+
session.startParameterCollection({
|
|
370
|
+
intentName: intentResult.intentName,
|
|
371
|
+
detectedParameters: intentResult.payload || {},
|
|
372
|
+
missingParameters: intentResult.missingRequiredParameters,
|
|
373
|
+
attemptCount: 0,
|
|
374
|
+
initialConfidence: intentResult.confidence
|
|
375
|
+
});
|
|
376
|
+
// Generate clarifying question
|
|
377
|
+
const question = await this.generateClarificationQuestion(session, intentResult.intentName, intentResult.missingRequiredParameters);
|
|
378
|
+
const assistantMsg = Message_1.Message.assistant(question);
|
|
379
|
+
session.addMessage(assistantMsg);
|
|
380
|
+
newMessages.push(assistantMsg);
|
|
381
|
+
await this.repo.saveSession(session);
|
|
382
|
+
return {
|
|
383
|
+
messages: newMessages,
|
|
384
|
+
metadata: {
|
|
385
|
+
intent: intentResult.intentName,
|
|
386
|
+
confidence: intentResult.confidence,
|
|
387
|
+
collectingParameters: true,
|
|
388
|
+
missingParameters: intentResult.missingRequiredParameters
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Handle parameter collection from user response
|
|
394
|
+
*/
|
|
395
|
+
async handleParameterCollection(session, userResponse, newMessages) {
|
|
396
|
+
const collectionState = session.getParameterCollectionState();
|
|
397
|
+
const MAX_ATTEMPTS = 3;
|
|
398
|
+
// Check if max attempts reached
|
|
399
|
+
if (collectionState.attemptCount >= MAX_ATTEMPTS) {
|
|
400
|
+
console.log('[Orchestrator] Max clarification attempts reached. Falling back to LLM.');
|
|
401
|
+
session.clearParameterCollection();
|
|
402
|
+
const llmResponse = await this.llm.generateResponse(session.agentPrompt, session.getHistory());
|
|
403
|
+
const assistantMsg = Message_1.Message.assistant(llmResponse.content);
|
|
404
|
+
session.addMessage(assistantMsg);
|
|
405
|
+
newMessages.push(assistantMsg);
|
|
406
|
+
await this.repo.saveSession(session);
|
|
407
|
+
return {
|
|
408
|
+
messages: newMessages,
|
|
409
|
+
metadata: { maxAttemptsReached: true }
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
// Get the intent definition
|
|
413
|
+
const allIntents = await this.intent.matchIntents(collectionState.intentName, 100);
|
|
414
|
+
const matchedIntent = allIntents.find((m) => m.intent.name === collectionState.intentName);
|
|
415
|
+
if (!matchedIntent) {
|
|
416
|
+
session.clearParameterCollection();
|
|
417
|
+
throw new Error(`Intent ${collectionState.intentName} not found`);
|
|
418
|
+
}
|
|
419
|
+
const intent = matchedIntent.intent;
|
|
420
|
+
// Extract parameters from user response using IntentMatcher
|
|
421
|
+
// We need to access the matcher through the intent service
|
|
422
|
+
// For now, we'll use a simpler approach with the LLM directly
|
|
423
|
+
const extractedParams = await this.extractParametersFromResponse(userResponse, intent, collectionState.missingParameters);
|
|
424
|
+
// Merge with existing parameters
|
|
425
|
+
const allParameters = {
|
|
426
|
+
...collectionState.detectedParameters,
|
|
427
|
+
...extractedParams
|
|
428
|
+
};
|
|
429
|
+
// Check what's still missing
|
|
430
|
+
const stillMissing = collectionState.missingParameters.filter(paramName => {
|
|
431
|
+
const value = allParameters[paramName];
|
|
432
|
+
return value === null || value === undefined || value === '' ||
|
|
433
|
+
(Array.isArray(value) && value.length === 0);
|
|
434
|
+
});
|
|
435
|
+
if (stillMissing.length === 0) {
|
|
436
|
+
// All parameters collected! Execute workflow
|
|
437
|
+
console.log('[Orchestrator] All parameters collected. Executing workflow.');
|
|
438
|
+
session.clearParameterCollection();
|
|
439
|
+
const workflowPayload = {
|
|
440
|
+
...allParameters,
|
|
441
|
+
userId: session.userId
|
|
442
|
+
};
|
|
443
|
+
const workflowResult = await this.workflow.executeWorkflow(collectionState.intentName, workflowPayload);
|
|
444
|
+
const workflowContextMessage = new Message_1.Message({
|
|
445
|
+
role: interfaces_1.Role.SYSTEM,
|
|
446
|
+
content: `[System Info: Workflow detected '${collectionState.intentName}'. Execution Result: ${JSON.stringify(workflowResult.data)}. Use this to answer the user.]`,
|
|
447
|
+
timestamp: new Date()
|
|
448
|
+
});
|
|
449
|
+
// Update the last user message with intent and workflow metadata
|
|
450
|
+
const lastUserMessage = session.messages.slice().reverse().find(m => m.role === interfaces_1.Role.USER);
|
|
451
|
+
if (lastUserMessage) {
|
|
452
|
+
lastUserMessage.metadata = {
|
|
453
|
+
...lastUserMessage.metadata,
|
|
454
|
+
intent: {
|
|
455
|
+
name: collectionState.intentName,
|
|
456
|
+
confidence: collectionState.initialConfidence, // Use original detection confidence
|
|
457
|
+
originalConfidence: collectionState.initialConfidence,
|
|
458
|
+
parameters: allParameters
|
|
459
|
+
},
|
|
460
|
+
workflow: {
|
|
461
|
+
id: collectionState.intentName,
|
|
462
|
+
result: workflowResult.data
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
const transientHistory = [...session.getHistory(), workflowContextMessage];
|
|
467
|
+
const llmResponse = await this.llm.generateResponse(session.agentPrompt, transientHistory);
|
|
468
|
+
const assistantMsg = Message_1.Message.assistant(llmResponse.content);
|
|
469
|
+
session.addMessage(assistantMsg);
|
|
470
|
+
newMessages.push(assistantMsg);
|
|
471
|
+
await this.repo.saveSession(session);
|
|
472
|
+
return {
|
|
473
|
+
messages: newMessages,
|
|
474
|
+
metadata: {
|
|
475
|
+
intent: collectionState.intentName,
|
|
476
|
+
confidence: 1.0, // High confidence after collection
|
|
477
|
+
workflowExecuted: collectionState.intentName,
|
|
478
|
+
parametersCollected: true
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
// Still missing parameters, ask again
|
|
484
|
+
session.updateParameterCollection(extractedParams, stillMissing);
|
|
485
|
+
const question = await this.generateClarificationQuestion(session, collectionState.intentName, stillMissing);
|
|
486
|
+
const assistantMsg = Message_1.Message.assistant(question);
|
|
487
|
+
session.addMessage(assistantMsg);
|
|
488
|
+
newMessages.push(assistantMsg);
|
|
489
|
+
await this.repo.saveSession(session);
|
|
490
|
+
return {
|
|
491
|
+
messages: newMessages,
|
|
492
|
+
metadata: {
|
|
493
|
+
intent: collectionState.intentName,
|
|
494
|
+
collectingParameters: true,
|
|
495
|
+
missingParameters: stillMissing,
|
|
496
|
+
attemptCount: collectionState.attemptCount
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Generate a clarification question for missing parameters
|
|
503
|
+
*/
|
|
504
|
+
async generateClarificationQuestion(session, intentName, missingParameters) {
|
|
505
|
+
// Get intent details for better question generation
|
|
506
|
+
const allIntents = await this.intent.matchIntents(intentName, 100);
|
|
507
|
+
const matchedIntent = allIntents.find((m) => m.intent.name === intentName);
|
|
508
|
+
let fieldInfo = '';
|
|
509
|
+
if (matchedIntent) {
|
|
510
|
+
const fields = [...matchedIntent.intent.required_fields, ...(matchedIntent.intent.optional_fields || [])];
|
|
511
|
+
fieldInfo = missingParameters.map(paramName => {
|
|
512
|
+
const field = fields.find(f => f.name === paramName);
|
|
513
|
+
if (!field)
|
|
514
|
+
return paramName;
|
|
515
|
+
const displayName = field.displayName || paramName;
|
|
516
|
+
const description = field.description || '';
|
|
517
|
+
return `${displayName}${description ? ' (' + description + ')' : ''}`;
|
|
518
|
+
}).join(', ');
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
fieldInfo = missingParameters.join(', ');
|
|
522
|
+
}
|
|
523
|
+
const prompt = `
|
|
524
|
+
You are a helpful assistant collecting information from the user.
|
|
525
|
+
The user wants to perform: ${intentName}
|
|
526
|
+
You need to ask for the following missing information: ${fieldInfo}
|
|
527
|
+
|
|
528
|
+
Generate a natural, friendly question to ask the user for this information.
|
|
529
|
+
Be concise and conversational. Ask for the most important missing parameter first.
|
|
530
|
+
If there are multiple missing parameters, focus on one at a time.
|
|
531
|
+
|
|
532
|
+
Question:`;
|
|
533
|
+
const response = await this.llm.generateContent(prompt);
|
|
534
|
+
return response.trim();
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Extract parameters from user response
|
|
538
|
+
*/
|
|
539
|
+
async extractParametersFromResponse(userResponse, intent, missingParameters) {
|
|
540
|
+
const extractionPrompt = `
|
|
541
|
+
You are a parameter extraction assistant. Extract the following parameters from the user's response.
|
|
542
|
+
|
|
543
|
+
Intent: ${intent.name}
|
|
544
|
+
Missing Parameters: ${missingParameters.join(', ')}
|
|
545
|
+
|
|
546
|
+
User Response: "${userResponse}"
|
|
547
|
+
|
|
548
|
+
For each missing parameter, try to extract its value from the user's response.
|
|
549
|
+
Return ONLY a valid JSON object with the extracted parameters.
|
|
550
|
+
If a parameter is not found, omit it from the response.
|
|
551
|
+
|
|
552
|
+
Example:
|
|
553
|
+
{
|
|
554
|
+
"date": "2024-01-15",
|
|
555
|
+
"time": "14:00"
|
|
556
|
+
}
|
|
557
|
+
`;
|
|
558
|
+
try {
|
|
559
|
+
const response = await this.llm.generateResponse(extractionPrompt, []);
|
|
560
|
+
const content = response.content.trim();
|
|
561
|
+
// Try to parse JSON from the response
|
|
562
|
+
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
563
|
+
if (jsonMatch) {
|
|
564
|
+
return JSON.parse(jsonMatch[0]);
|
|
565
|
+
}
|
|
566
|
+
console.warn('[Orchestrator] Could not extract JSON from LLM response:', content);
|
|
567
|
+
return {};
|
|
568
|
+
}
|
|
569
|
+
catch (error) {
|
|
570
|
+
console.error('[Orchestrator] Error extracting parameters:', error);
|
|
571
|
+
return {};
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Handle incoming voice message (audio input)
|
|
576
|
+
* Converts speech to text, processes the message, and optionally returns audio response
|
|
577
|
+
* @param sessionId Session identifier
|
|
578
|
+
* @param audioBase64 Base64-encoded audio data (WAV format recommended)
|
|
579
|
+
* @returns Transcript, messages, and optional audio response
|
|
580
|
+
*/
|
|
581
|
+
/**
|
|
582
|
+
* Get voice response for any text
|
|
583
|
+
* Useful for converting assistant messages to speech
|
|
584
|
+
* @param text Text to convert to speech
|
|
585
|
+
* @returns Audio data as Uint8Array
|
|
586
|
+
*/
|
|
587
|
+
async getVoiceResponse(text) {
|
|
588
|
+
if (!this.voiceAdapter) {
|
|
589
|
+
throw new Error('Voice adapter not configured. Please provide an IVoiceAdapter when creating the Orchestrator.');
|
|
590
|
+
}
|
|
591
|
+
console.log(`[Orchestrator] Generating voice response for text: "${text.substring(0, 50)}..."`);
|
|
592
|
+
return await this.voiceAdapter.textToSpeech(text);
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Transcribe audio and record it to storage
|
|
596
|
+
*/
|
|
597
|
+
async transcribeAudio(sessionId, audioBase64) {
|
|
598
|
+
if (!this.voiceAdapter)
|
|
599
|
+
throw new Error('Voice adapter missing');
|
|
600
|
+
const transcript = await this.voiceAdapter.speechToText(audioBase64);
|
|
601
|
+
if (this.audioStorage) {
|
|
602
|
+
const buffer = Buffer.from(audioBase64, 'base64');
|
|
603
|
+
// Get format metadata from voice adapter (defaults to WAV if not provided)
|
|
604
|
+
const formatMetadata = this.voiceAdapter.getSTTInputFormat ? this.voiceAdapter.getSTTInputFormat() : { format: 'wav' };
|
|
605
|
+
this.audioStorage.appendAudio(sessionId, buffer, formatMetadata).catch(e => console.error('[Orchestrator] Failed to record user audio', e));
|
|
606
|
+
}
|
|
607
|
+
return transcript;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Synthesize audio and record it to storage
|
|
611
|
+
*/
|
|
612
|
+
async synthesizeResponse(sessionId, text) {
|
|
613
|
+
if (!this.voiceAdapter)
|
|
614
|
+
throw new Error('Voice adapter missing');
|
|
615
|
+
const audio = await this.voiceAdapter.textToSpeech(text);
|
|
616
|
+
if (this.audioStorage) {
|
|
617
|
+
const buffer = Buffer.from(audio);
|
|
618
|
+
// Get format metadata from voice adapter
|
|
619
|
+
const formatMetadata = this.voiceAdapter.getTTSOutputFormat();
|
|
620
|
+
this.audioStorage.appendAudio(sessionId, buffer, formatMetadata).catch(e => console.error('[Orchestrator] Failed to record bot audio', e));
|
|
621
|
+
}
|
|
622
|
+
return audio;
|
|
623
|
+
}
|
|
624
|
+
async completeSession(sessionId, recordingUrl) {
|
|
625
|
+
const session = await this.repo.findSessionById(sessionId);
|
|
626
|
+
if (!session) {
|
|
627
|
+
throw new errors_1.SessionNotFoundError(sessionId);
|
|
628
|
+
}
|
|
629
|
+
// Generate Summary
|
|
630
|
+
const messages = session.getHistory();
|
|
631
|
+
if (messages.length > 0) {
|
|
632
|
+
// Get config to use defaultLanguage for summary
|
|
633
|
+
const config = session.configId && session.userId
|
|
634
|
+
? await this.repo.findConversationConfig(session.userId, session.configId)
|
|
635
|
+
: null;
|
|
636
|
+
const defaultLanguage = config?.defaultLanguage || 'en';
|
|
637
|
+
const languageName = this.languageDetector.getLanguageName(defaultLanguage);
|
|
638
|
+
const transcript = messages.map(m => `${m.role}: ${m.content}`).join('\n');
|
|
639
|
+
const summaryPrompt = `
|
|
640
|
+
Please summarize the following conversation in a concise paragraph in ${languageName}.
|
|
641
|
+
Highlight the main user intent, key actions taken, and the final outcome.
|
|
642
|
+
Respond in ${languageName} language.
|
|
643
|
+
|
|
644
|
+
Conversation:
|
|
645
|
+
${transcript}
|
|
646
|
+
|
|
647
|
+
Summary:`;
|
|
648
|
+
try {
|
|
649
|
+
// If generateContent is available (some adapters might not implement it), use it.
|
|
650
|
+
// Otherwise fallback to generateResponse.
|
|
651
|
+
let summaryText = '';
|
|
652
|
+
if (this.llm.generateContent) {
|
|
653
|
+
summaryText = await this.llm.generateContent(summaryPrompt);
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
const response = await this.llm.generateResponse(summaryPrompt, []);
|
|
657
|
+
summaryText = response.content;
|
|
658
|
+
}
|
|
659
|
+
session.summary = summaryText.trim();
|
|
660
|
+
}
|
|
661
|
+
catch (error) {
|
|
662
|
+
console.error('[Orchestrator] Failed to generate summary:', error);
|
|
663
|
+
session.summary = "Summary generation failed or not supported.";
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
session.summary = "No conversation history to summarize.";
|
|
668
|
+
}
|
|
669
|
+
// Mark as completed
|
|
670
|
+
session.updateStatus(interfaces_1.SessionStatus.COMPLETED);
|
|
671
|
+
// Save (Repository should handle permanent persistence for COMPLETED status)
|
|
672
|
+
await this.repo.saveSession(session);
|
|
673
|
+
// If recordingUrl was not passed but storage exists, try to finalize it now
|
|
674
|
+
if (!recordingUrl && this.audioStorage && session.mode === 'VOICE') {
|
|
675
|
+
try {
|
|
676
|
+
const url = await this.audioStorage.finalizeSession(sessionId);
|
|
677
|
+
console.log(`[Orchestrator] Finalized storage for session ${sessionId}. URL: ${url}`);
|
|
678
|
+
recordingUrl = url; // Update local variable to pass to webhook
|
|
679
|
+
}
|
|
680
|
+
catch (e) {
|
|
681
|
+
console.error('[Orchestrator] Failed to finalize storage', e);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
// Trigger session.ended webhook (includes full transcript and summary)
|
|
685
|
+
await this.webhookService.triggerSessionEnded(session, recordingUrl);
|
|
686
|
+
console.log(`[Orchestrator] Session ${sessionId} completed and summarized.`);
|
|
687
|
+
return session;
|
|
688
|
+
}
|
|
689
|
+
async getSessionAudio(sessionId) {
|
|
690
|
+
if (this.audioStorage) {
|
|
691
|
+
return await this.audioStorage.getSessionAudio(sessionId);
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
exports.Orchestrator = Orchestrator;
|
|
697
|
+
//# sourceMappingURL=Orchestrator.js.map
|