@tenex-chat/backend 0.9.1
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 +194 -0
- package/dist/backend-wrapper.cjs +3 -0
- package/dist/src/index.js +331928 -0
- package/package.json +103 -0
- package/src/agents/AgentRegistry.ts +418 -0
- package/src/agents/AgentStorage.ts +1133 -0
- package/src/agents/ConfigResolver.ts +229 -0
- package/src/agents/agent-installer.ts +236 -0
- package/src/agents/agent-loader.ts +241 -0
- package/src/agents/constants.ts +82 -0
- package/src/agents/errors.ts +48 -0
- package/src/agents/execution/AgentExecutor.ts +561 -0
- package/src/agents/execution/ExecutionContextFactory.ts +112 -0
- package/src/agents/execution/MessageCompiler.ts +597 -0
- package/src/agents/execution/MessageSyncer.ts +100 -0
- package/src/agents/execution/PostCompletionChecker.ts +278 -0
- package/src/agents/execution/ProgressMonitor.ts +50 -0
- package/src/agents/execution/RALResolver.ts +177 -0
- package/src/agents/execution/SessionManager.ts +181 -0
- package/src/agents/execution/StreamCallbacks.ts +312 -0
- package/src/agents/execution/StreamExecutionHandler.ts +579 -0
- package/src/agents/execution/StreamSetup.ts +313 -0
- package/src/agents/execution/ToolEventHandlers.ts +239 -0
- package/src/agents/execution/ToolExecutionTracker.ts +498 -0
- package/src/agents/execution/ToolResultUtils.ts +97 -0
- package/src/agents/execution/ToolSupervisionWrapper.ts +174 -0
- package/src/agents/execution/constants.ts +16 -0
- package/src/agents/execution/index.ts +3 -0
- package/src/agents/execution/types.ts +96 -0
- package/src/agents/execution/utils.ts +26 -0
- package/src/agents/index.ts +4 -0
- package/src/agents/script-installer.ts +266 -0
- package/src/agents/supervision/SupervisorLLMService.ts +253 -0
- package/src/agents/supervision/SupervisorOrchestrator.ts +471 -0
- package/src/agents/supervision/heuristics/ConsecutiveToolsWithoutTodoHeuristic.ts +73 -0
- package/src/agents/supervision/heuristics/DelegationClaimHeuristic.ts +80 -0
- package/src/agents/supervision/heuristics/HeuristicRegistry.ts +114 -0
- package/src/agents/supervision/heuristics/PendingTodosHeuristic.ts +93 -0
- package/src/agents/supervision/heuristics/SilentAgentHeuristic.ts +54 -0
- package/src/agents/supervision/heuristics/index.ts +5 -0
- package/src/agents/supervision/index.ts +28 -0
- package/src/agents/supervision/registerHeuristics.ts +110 -0
- package/src/agents/supervision/supervisionHealthCheck.ts +123 -0
- package/src/agents/supervision/types.ts +171 -0
- package/src/agents/tool-names.ts +46 -0
- package/src/agents/tool-normalization.ts +184 -0
- package/src/agents/types/index.ts +2 -0
- package/src/agents/types/runtime.ts +74 -0
- package/src/agents/types/storage.ts +145 -0
- package/src/commands/agent/import/index.ts +6 -0
- package/src/commands/agent/import/openclaw-distiller.ts +57 -0
- package/src/commands/agent/import/openclaw-reader.ts +141 -0
- package/src/commands/agent/import/openclaw.ts +154 -0
- package/src/commands/agent/index.ts +6 -0
- package/src/commands/agent.ts +215 -0
- package/src/commands/daemon.ts +198 -0
- package/src/commands/doctor.ts +134 -0
- package/src/commands/setup/embed.ts +228 -0
- package/src/commands/setup/global-system-prompt.ts +223 -0
- package/src/commands/setup/image.ts +179 -0
- package/src/commands/setup/index.ts +16 -0
- package/src/commands/setup/interactive.ts +95 -0
- package/src/commands/setup/llm.ts +38 -0
- package/src/commands/setup/onboarding.ts +294 -0
- package/src/commands/setup/providers.ts +27 -0
- package/src/constants.ts +34 -0
- package/src/conversations/ConversationDiskReader.ts +148 -0
- package/src/conversations/ConversationRegistry.ts +728 -0
- package/src/conversations/ConversationStore.ts +868 -0
- package/src/conversations/MessageBuilder.ts +866 -0
- package/src/conversations/executionTime.ts +62 -0
- package/src/conversations/formatters/DelegationXmlFormatter.ts +64 -0
- package/src/conversations/formatters/ThreadedConversationFormatter.ts +303 -0
- package/src/conversations/formatters/index.ts +9 -0
- package/src/conversations/formatters/utils/MessageFormatter.ts +46 -0
- package/src/conversations/formatters/utils/TimestampFormatter.ts +56 -0
- package/src/conversations/formatters/utils/TreeBuilder.ts +131 -0
- package/src/conversations/formatters/utils/TreeRenderer.ts +49 -0
- package/src/conversations/index.ts +2 -0
- package/src/conversations/persistence/ToolMessageStorage.ts +143 -0
- package/src/conversations/search/ConversationIndexManager.ts +393 -0
- package/src/conversations/search/QueryParser.ts +114 -0
- package/src/conversations/search/SearchEngine.ts +175 -0
- package/src/conversations/search/SnippetExtractor.ts +345 -0
- package/src/conversations/search/embeddings/ConversationEmbeddingService.ts +484 -0
- package/src/conversations/search/embeddings/ConversationIndexingJob.ts +320 -0
- package/src/conversations/search/embeddings/IndexingStateManager.ts +338 -0
- package/src/conversations/search/embeddings/index.ts +18 -0
- package/src/conversations/search/index.ts +49 -0
- package/src/conversations/search/types.ts +124 -0
- package/src/conversations/services/CategoryManager.ts +160 -0
- package/src/conversations/services/ConversationResolver.ts +296 -0
- package/src/conversations/services/ConversationSummarizer.ts +234 -0
- package/src/conversations/services/MetadataDebounceManager.ts +188 -0
- package/src/conversations/services/index.ts +2 -0
- package/src/conversations/types.ts +148 -0
- package/src/conversations/utils/content-utils.ts +69 -0
- package/src/conversations/utils/image-placeholder.ts +281 -0
- package/src/conversations/utils/image-url-utils.ts +171 -0
- package/src/conversations/utils/multimodal-content.ts +90 -0
- package/src/conversations/utils/tool-result-truncator.ts +159 -0
- package/src/daemon/Daemon.ts +1883 -0
- package/src/daemon/ProjectRuntime.ts +657 -0
- package/src/daemon/RestartState.ts +152 -0
- package/src/daemon/RuntimeLifecycle.ts +268 -0
- package/src/daemon/SubscriptionManager.ts +305 -0
- package/src/daemon/UnixSocketTransport.ts +318 -0
- package/src/daemon/filters/SubscriptionFilterBuilder.ts +119 -0
- package/src/daemon/index.ts +9 -0
- package/src/daemon/routing/DaemonRouter.ts +491 -0
- package/src/daemon/types.ts +150 -0
- package/src/daemon/utils/routing-log.ts +76 -0
- package/src/daemon/utils/telemetry.ts +173 -0
- package/src/event-handler/agentDeletion.ts +383 -0
- package/src/event-handler/index.ts +749 -0
- package/src/event-handler/newConversation.ts +165 -0
- package/src/event-handler/project.ts +166 -0
- package/src/event-handler/reply.ts +18 -0
- package/src/events/NDKAgentDefinition.ts +292 -0
- package/src/events/NDKAgentLesson.ts +106 -0
- package/src/events/NDKEventMetadata.ts +34 -0
- package/src/events/NDKMCPTool.ts +60 -0
- package/src/events/NDKProjectStatus.ts +384 -0
- package/src/events/index.ts +4 -0
- package/src/index.ts +126 -0
- package/src/lib/agent-home.ts +334 -0
- package/src/lib/error-formatter.ts +200 -0
- package/src/lib/fs/filesystem.ts +128 -0
- package/src/lib/fs/index.ts +1 -0
- package/src/lib/json-parser.ts +30 -0
- package/src/lib/string.ts +15 -0
- package/src/lib/time.ts +74 -0
- package/src/llm/ChunkHandler.ts +277 -0
- package/src/llm/FinishHandler.ts +250 -0
- package/src/llm/LLMConfigEditor.ts +154 -0
- package/src/llm/LLMServiceFactory.ts +230 -0
- package/src/llm/MessageProcessor.ts +90 -0
- package/src/llm/RecordingState.ts +37 -0
- package/src/llm/StreamPublisher.ts +40 -0
- package/src/llm/TracingUtils.ts +77 -0
- package/src/llm/chunk-validators.ts +57 -0
- package/src/llm/constants.ts +6 -0
- package/src/llm/index.ts +12 -0
- package/src/llm/meta/MetaModelResolver.ts +352 -0
- package/src/llm/meta/index.ts +11 -0
- package/src/llm/middleware/flight-recorder.ts +188 -0
- package/src/llm/providers/MockProvider.ts +332 -0
- package/src/llm/providers/agent/ClaudeCodeProvider.ts +343 -0
- package/src/llm/providers/agent/ClaudeCodeToolsAdapter.ts +203 -0
- package/src/llm/providers/agent/CodexAppServerProvider.ts +214 -0
- package/src/llm/providers/agent/CodexAppServerToolsAdapter.ts +91 -0
- package/src/llm/providers/agent/index.ts +10 -0
- package/src/llm/providers/base/AgentProvider.ts +107 -0
- package/src/llm/providers/base/BaseProvider.ts +114 -0
- package/src/llm/providers/base/StandardProvider.ts +38 -0
- package/src/llm/providers/base/index.ts +9 -0
- package/src/llm/providers/index.ts +106 -0
- package/src/llm/providers/key-manager.ts +238 -0
- package/src/llm/providers/ollama-models.ts +105 -0
- package/src/llm/providers/openrouter-models.ts +102 -0
- package/src/llm/providers/provider-ids.ts +18 -0
- package/src/llm/providers/registry/ProviderRegistry.ts +414 -0
- package/src/llm/providers/registry/index.ts +7 -0
- package/src/llm/providers/standard/AnthropicProvider.ts +71 -0
- package/src/llm/providers/standard/OllamaProvider.ts +59 -0
- package/src/llm/providers/standard/OpenAIProvider.ts +44 -0
- package/src/llm/providers/standard/OpenRouterProvider.ts +103 -0
- package/src/llm/providers/standard/index.ts +10 -0
- package/src/llm/providers/types.ts +194 -0
- package/src/llm/providers/usage-metadata.ts +78 -0
- package/src/llm/service.ts +713 -0
- package/src/llm/types.ts +167 -0
- package/src/llm/utils/ConfigurationManager.ts +650 -0
- package/src/llm/utils/ConfigurationTester.ts +229 -0
- package/src/llm/utils/ModelSelector.ts +212 -0
- package/src/llm/utils/ProviderConfigUI.ts +177 -0
- package/src/llm/utils/claudeCodePromptCompiler.ts +141 -0
- package/src/llm/utils/codex-models.ts +53 -0
- package/src/llm/utils/context-window-cache.ts +30 -0
- package/src/llm/utils/models-dev-cache.ts +267 -0
- package/src/llm/utils/provider-setup.ts +50 -0
- package/src/llm/utils/tool-errors.ts +78 -0
- package/src/llm/utils/usage.ts +74 -0
- package/src/logging/EventRoutingLogger.ts +205 -0
- package/src/nostr/AgentEventDecoder.ts +357 -0
- package/src/nostr/AgentEventEncoder.ts +677 -0
- package/src/nostr/AgentProfilePublisher.ts +657 -0
- package/src/nostr/AgentPublisher.ts +437 -0
- package/src/nostr/BlossomService.ts +226 -0
- package/src/nostr/InterventionPublisher.ts +132 -0
- package/src/nostr/TagExtractor.ts +228 -0
- package/src/nostr/collectEvents.ts +83 -0
- package/src/nostr/constants.ts +38 -0
- package/src/nostr/encryption.ts +26 -0
- package/src/nostr/index.ts +31 -0
- package/src/nostr/keys.ts +17 -0
- package/src/nostr/kinds.ts +37 -0
- package/src/nostr/ndkClient.ts +72 -0
- package/src/nostr/relays.ts +43 -0
- package/src/nostr/trace-context.ts +39 -0
- package/src/nostr/types.ts +227 -0
- package/src/nostr/utils.ts +84 -0
- package/src/prompts/core/FragmentRegistry.ts +30 -0
- package/src/prompts/core/PromptBuilder.ts +98 -0
- package/src/prompts/core/index.ts +3 -0
- package/src/prompts/core/types.ts +13 -0
- package/src/prompts/fragments/00-global-system-prompt.ts +44 -0
- package/src/prompts/fragments/01-agent-identity.ts +69 -0
- package/src/prompts/fragments/02-agent-home-directory.ts +114 -0
- package/src/prompts/fragments/03-system-reminders-explanation.ts +14 -0
- package/src/prompts/fragments/04-relay-configuration.ts +38 -0
- package/src/prompts/fragments/05-delegation-chain.ts +45 -0
- package/src/prompts/fragments/06-agent-todos.ts +74 -0
- package/src/prompts/fragments/06-todo-usage-guidance.ts +34 -0
- package/src/prompts/fragments/07-meta-project-context.ts +234 -0
- package/src/prompts/fragments/08-active-conversations.ts +382 -0
- package/src/prompts/fragments/09-recent-conversations.ts +153 -0
- package/src/prompts/fragments/10-referenced-article.ts +21 -0
- package/src/prompts/fragments/11-nudges.ts +134 -0
- package/src/prompts/fragments/12-skills.ts +127 -0
- package/src/prompts/fragments/13-available-nudges.ts +122 -0
- package/src/prompts/fragments/15-available-agents.ts +53 -0
- package/src/prompts/fragments/16-stay-in-your-lane.ts +41 -0
- package/src/prompts/fragments/17-todo-before-delegation.ts +39 -0
- package/src/prompts/fragments/20-voice-mode.ts +62 -0
- package/src/prompts/fragments/22-scheduled-tasks.ts +175 -0
- package/src/prompts/fragments/24-retrieved-lessons.ts +26 -0
- package/src/prompts/fragments/25-rag-instructions.ts +333 -0
- package/src/prompts/fragments/26-mcp-resources.ts +237 -0
- package/src/prompts/fragments/27-memorized-reports.ts +77 -0
- package/src/prompts/fragments/28-agent-directed-monitoring.ts +32 -0
- package/src/prompts/fragments/29-rag-collections.ts +50 -0
- package/src/prompts/fragments/30-worktree-context.ts +98 -0
- package/src/prompts/fragments/31-agents-md-guidance.ts +96 -0
- package/src/prompts/fragments/32-process-metrics.ts +72 -0
- package/src/prompts/fragments/debug-mode.ts +48 -0
- package/src/prompts/fragments/delegation-completion.ts +44 -0
- package/src/prompts/fragments/index.ts +91 -0
- package/src/prompts/index.ts +21 -0
- package/src/prompts/utils/systemPromptBuilder.ts +777 -0
- package/src/scripts/migrate-prefix-index.ts +157 -0
- package/src/services/AgentDefinitionMonitor.ts +701 -0
- package/src/services/ConfigService.ts +723 -0
- package/src/services/CooldownRegistry.ts +199 -0
- package/src/services/LLMOperationsRegistry.ts +424 -0
- package/src/services/OwnerAgentListService.ts +354 -0
- package/src/services/PubkeyService.ts +308 -0
- package/src/services/agents/AgentMetadataStore.ts +72 -0
- package/src/services/agents/AgentResolution.ts +59 -0
- package/src/services/agents/EscalationService.ts +281 -0
- package/src/services/agents/NDKAgentDiscovery.ts +95 -0
- package/src/services/agents/index.ts +7 -0
- package/src/services/agents-md/AgentsMdService.ts +184 -0
- package/src/services/agents-md/SystemReminderInjector.ts +238 -0
- package/src/services/agents-md/index.ts +11 -0
- package/src/services/apns/APNsClient.ts +203 -0
- package/src/services/apns/APNsService.ts +358 -0
- package/src/services/apns/index.ts +11 -0
- package/src/services/apns/types.ts +80 -0
- package/src/services/compression/CompressionService.ts +445 -0
- package/src/services/compression/compression-schema.ts +28 -0
- package/src/services/compression/compression-types.ts +74 -0
- package/src/services/compression/compression-utils.ts +587 -0
- package/src/services/config/types.ts +394 -0
- package/src/services/dispatch/AgentDispatchService.ts +937 -0
- package/src/services/dispatch/AgentRouter.ts +181 -0
- package/src/services/dispatch/DelegationCompletionHandler.ts +232 -0
- package/src/services/embedding/EmbeddingProvider.ts +188 -0
- package/src/services/embedding/index.ts +5 -0
- package/src/services/event-context/EventContextService.ts +108 -0
- package/src/services/event-context/index.ts +2 -0
- package/src/services/heuristics/ContextBuilder.ts +106 -0
- package/src/services/heuristics/HeuristicEngine.ts +200 -0
- package/src/services/heuristics/formatters.ts +58 -0
- package/src/services/heuristics/index.ts +12 -0
- package/src/services/heuristics/rules/index.ts +25 -0
- package/src/services/heuristics/rules/todoBeforeDelegation.ts +69 -0
- package/src/services/heuristics/rules/todoReminderOnToolUse.ts +63 -0
- package/src/services/heuristics/types.ts +144 -0
- package/src/services/image/ImageGenerationService.ts +389 -0
- package/src/services/image/index.ts +12 -0
- package/src/services/intervention/InterventionService.ts +1352 -0
- package/src/services/intervention/index.ts +7 -0
- package/src/services/mcp/MCPManager.ts +683 -0
- package/src/services/mcp/McpNotificationDelivery.ts +139 -0
- package/src/services/mcp/McpSubscriptionService.ts +653 -0
- package/src/services/mcp/mcpInstaller.ts +130 -0
- package/src/services/nip46/Nip46SigningLog.ts +81 -0
- package/src/services/nip46/Nip46SigningService.ts +467 -0
- package/src/services/nip46/index.ts +4 -0
- package/src/services/nudge/NudgeService.ts +224 -0
- package/src/services/nudge/NudgeWhitelistService.ts +382 -0
- package/src/services/nudge/index.ts +5 -0
- package/src/services/nudge/types.ts +83 -0
- package/src/services/projects/ProjectContext.ts +672 -0
- package/src/services/projects/ProjectContextStore.ts +102 -0
- package/src/services/projects/index.ts +6 -0
- package/src/services/prompt-compiler/index.ts +15 -0
- package/src/services/prompt-compiler/prompt-compiler-service.ts +1143 -0
- package/src/services/pubkey-gate/PubkeyGateService.ts +93 -0
- package/src/services/pubkey-gate/index.ts +1 -0
- package/src/services/rag/EmbeddingProviderFactory.ts +292 -0
- package/src/services/rag/LanceDBMaintenanceService.ts +211 -0
- package/src/services/rag/RAGDatabaseService.ts +173 -0
- package/src/services/rag/RAGOperations.ts +682 -0
- package/src/services/rag/RAGService.ts +240 -0
- package/src/services/rag/RagSubscriptionService.ts +618 -0
- package/src/services/rag/rag-utils.ts +174 -0
- package/src/services/ral/PendingDelegationsRegistry.ts +168 -0
- package/src/services/ral/RALRegistry.ts +2782 -0
- package/src/services/ral/index.ts +4 -0
- package/src/services/ral/types.ts +292 -0
- package/src/services/reports/LocalReportStore.ts +380 -0
- package/src/services/reports/ReportEmbeddingService.ts +430 -0
- package/src/services/reports/ReportService.ts +440 -0
- package/src/services/reports/articleUtils.ts +52 -0
- package/src/services/reports/index.ts +7 -0
- package/src/services/scheduling/SchedulerService.ts +1057 -0
- package/src/services/scheduling/errors.ts +14 -0
- package/src/services/scheduling/index.ts +7 -0
- package/src/services/scheduling/utils.ts +77 -0
- package/src/services/search/SearchProviderRegistry.ts +78 -0
- package/src/services/search/UnifiedSearchService.ts +218 -0
- package/src/services/search/index.ts +47 -0
- package/src/services/search/projectFilter.ts +22 -0
- package/src/services/search/providers/ConversationSearchProvider.ts +48 -0
- package/src/services/search/providers/LessonSearchProvider.ts +75 -0
- package/src/services/search/providers/ReportSearchProvider.ts +49 -0
- package/src/services/search/types.ts +144 -0
- package/src/services/skill/SkillService.ts +482 -0
- package/src/services/skill/index.ts +2 -0
- package/src/services/skill/types.ts +70 -0
- package/src/services/status/OperationsStatusService.ts +276 -0
- package/src/services/status/ProjectStatusService.ts +522 -0
- package/src/services/status/index.ts +11 -0
- package/src/services/storage/PrefixKVStore.ts +242 -0
- package/src/services/storage/index.ts +1 -0
- package/src/services/system-reminder/SystemReminderUtils.ts +96 -0
- package/src/services/system-reminder/index.ts +7 -0
- package/src/services/trust-pubkeys/TrustPubkeyService.ts +325 -0
- package/src/services/trust-pubkeys/index.ts +2 -0
- package/src/telemetry/ConversationSpanManager.ts +111 -0
- package/src/telemetry/EventLoopMonitor.ts +206 -0
- package/src/telemetry/LLMSpanRegistry.ts +20 -0
- package/src/telemetry/NostrSpanProcessor.ts +89 -0
- package/src/telemetry/ToolCallSpanProcessor.ts +66 -0
- package/src/telemetry/diagnostics.ts +27 -0
- package/src/telemetry/setup.ts +120 -0
- package/src/tools/implementations/agents_discover.ts +121 -0
- package/src/tools/implementations/agents_hire.ts +127 -0
- package/src/tools/implementations/agents_list.ts +96 -0
- package/src/tools/implementations/agents_publish.ts +611 -0
- package/src/tools/implementations/agents_read.ts +173 -0
- package/src/tools/implementations/agents_write.ts +200 -0
- package/src/tools/implementations/ask.ts +411 -0
- package/src/tools/implementations/change_model.ts +141 -0
- package/src/tools/implementations/conversation_get.ts +661 -0
- package/src/tools/implementations/conversation_list.ts +377 -0
- package/src/tools/implementations/conversation_search.ts +370 -0
- package/src/tools/implementations/delegate.ts +327 -0
- package/src/tools/implementations/delegate_crossproject.ts +209 -0
- package/src/tools/implementations/delegate_followup.ts +300 -0
- package/src/tools/implementations/fs_edit.ts +162 -0
- package/src/tools/implementations/fs_glob.ts +182 -0
- package/src/tools/implementations/fs_grep.ts +513 -0
- package/src/tools/implementations/fs_read.ts +332 -0
- package/src/tools/implementations/fs_write.ts +113 -0
- package/src/tools/implementations/generate_image.ts +259 -0
- package/src/tools/implementations/home_fs.ts +515 -0
- package/src/tools/implementations/kill.ts +651 -0
- package/src/tools/implementations/learn.ts +166 -0
- package/src/tools/implementations/lesson-formatter.ts +38 -0
- package/src/tools/implementations/lesson_delete.ts +164 -0
- package/src/tools/implementations/lesson_get.ts +105 -0
- package/src/tools/implementations/lessons_list.ts +153 -0
- package/src/tools/implementations/mcp_resource_read.ts +161 -0
- package/src/tools/implementations/mcp_subscribe.ts +158 -0
- package/src/tools/implementations/mcp_subscription_stop.ts +85 -0
- package/src/tools/implementations/nostr_fetch.ts +149 -0
- package/src/tools/implementations/nostr_publish_as_user.ts +353 -0
- package/src/tools/implementations/project_list.ts +146 -0
- package/src/tools/implementations/rag_add_documents.ts +573 -0
- package/src/tools/implementations/rag_create_collection.ts +65 -0
- package/src/tools/implementations/rag_delete_collection.ts +68 -0
- package/src/tools/implementations/rag_list_collections.ts +77 -0
- package/src/tools/implementations/rag_query.ts +107 -0
- package/src/tools/implementations/rag_subscription_create.ts +105 -0
- package/src/tools/implementations/rag_subscription_delete.ts +80 -0
- package/src/tools/implementations/rag_subscription_get.ts +123 -0
- package/src/tools/implementations/rag_subscription_list.ts +128 -0
- package/src/tools/implementations/report_delete.ts +79 -0
- package/src/tools/implementations/report_read.ts +160 -0
- package/src/tools/implementations/report_write.ts +278 -0
- package/src/tools/implementations/reports_list.ts +77 -0
- package/src/tools/implementations/schedule_task.ts +104 -0
- package/src/tools/implementations/schedule_task_cancel.ts +62 -0
- package/src/tools/implementations/schedule_task_once.ts +128 -0
- package/src/tools/implementations/schedule_tasks_list.ts +79 -0
- package/src/tools/implementations/search.ts +160 -0
- package/src/tools/implementations/shell.ts +553 -0
- package/src/tools/implementations/todo.ts +260 -0
- package/src/tools/implementations/upload_blob.ts +381 -0
- package/src/tools/implementations/web_fetch.ts +153 -0
- package/src/tools/implementations/web_search.ts +250 -0
- package/src/tools/registry.ts +670 -0
- package/src/tools/types.ts +177 -0
- package/src/tools/utils.ts +256 -0
- package/src/types/event-ids.ts +320 -0
- package/src/types/index.ts +46 -0
- package/src/utils/agentFetcher.ts +107 -0
- package/src/utils/cli-error.ts +29 -0
- package/src/utils/conversation-id.ts +27 -0
- package/src/utils/conversation-utils.ts +1 -0
- package/src/utils/delegation-chain.ts +357 -0
- package/src/utils/error-handler.ts +42 -0
- package/src/utils/git/gitignore.ts +69 -0
- package/src/utils/git/index.ts +2 -0
- package/src/utils/git/initializeGitRepo.ts +204 -0
- package/src/utils/git/worktree.ts +260 -0
- package/src/utils/lessonFormatter.ts +70 -0
- package/src/utils/lessonTrust.ts +24 -0
- package/src/utils/lockfile.ts +123 -0
- package/src/utils/logger.ts +149 -0
- package/src/utils/nostr-entity-parser.ts +365 -0
- package/src/utils/process.ts +49 -0
- package/src/wrapper.ts +262 -0
- package/tsconfig.json +41 -0
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import { config } from "@/services/ConfigService";
|
|
3
|
+
import { getProjectContext, isProjectContextInitialized } from "@/services/projects";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { handleError } from "@/utils/error-handler";
|
|
6
|
+
import { logger } from "@/utils/logger";
|
|
7
|
+
import { RAGService } from "./RAGService";
|
|
8
|
+
import type { DocumentMetadata } from "./rag-utils";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* RagSubscriptionService - Manages persistent RAG subscriptions to MCP resources
|
|
12
|
+
*
|
|
13
|
+
* This service enables automatic ingestion of MCP resource updates into RAG collections.
|
|
14
|
+
* When a resource is updated, the MCP server sends a notification, which is automatically
|
|
15
|
+
* processed and added to the configured RAG collection.
|
|
16
|
+
*
|
|
17
|
+
* Features:
|
|
18
|
+
* - Persistent subscriptions across restarts
|
|
19
|
+
* - Automatic reconnection on initialization
|
|
20
|
+
* - Error tracking and metrics
|
|
21
|
+
* - Fallback polling support for servers without subscription capabilities
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
type Notification = {
|
|
25
|
+
method: string;
|
|
26
|
+
params: Record<string, unknown>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export enum SubscriptionStatus {
|
|
30
|
+
RUNNING = "RUNNING",
|
|
31
|
+
ERROR = "ERROR",
|
|
32
|
+
STOPPED = "STOPPED",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface RagSubscription {
|
|
36
|
+
subscriptionId: string;
|
|
37
|
+
agentPubkey: string;
|
|
38
|
+
mcpServerId: string;
|
|
39
|
+
resourceUri: string;
|
|
40
|
+
ragCollection: string;
|
|
41
|
+
description: string;
|
|
42
|
+
status: SubscriptionStatus;
|
|
43
|
+
documentsProcessed: number;
|
|
44
|
+
lastDocumentIngested?: string;
|
|
45
|
+
createdAt: number;
|
|
46
|
+
updatedAt: number;
|
|
47
|
+
lastError?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class RagSubscriptionService {
|
|
51
|
+
private static instance: RagSubscriptionService;
|
|
52
|
+
private subscriptions: Map<string, RagSubscription> = new Map();
|
|
53
|
+
private persistencePath: string;
|
|
54
|
+
private ragService: RAGService;
|
|
55
|
+
private isInitialized = false;
|
|
56
|
+
private resourceListeners: Map<string, (notification: Notification) => void> = new Map();
|
|
57
|
+
/** Removal functions returned by MCPManager.addResourceNotificationHandler() */
|
|
58
|
+
private handlerRemovers: Map<string, () => void> = new Map();
|
|
59
|
+
|
|
60
|
+
private constructor() {
|
|
61
|
+
// Use global location for RAG subscriptions since it's a singleton
|
|
62
|
+
const tenexDir = config.getConfigPath();
|
|
63
|
+
this.persistencePath = path.join(tenexDir, "rag_subscriptions.json");
|
|
64
|
+
this.ragService = RAGService.getInstance();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public static getInstance(): RagSubscriptionService {
|
|
68
|
+
if (!RagSubscriptionService.instance) {
|
|
69
|
+
RagSubscriptionService.instance = new RagSubscriptionService();
|
|
70
|
+
}
|
|
71
|
+
return RagSubscriptionService.instance;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Reset the singleton instance (for testing purposes)
|
|
76
|
+
*/
|
|
77
|
+
public static resetInstance(): void {
|
|
78
|
+
RagSubscriptionService.instance = undefined as unknown as RagSubscriptionService;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Initialize the service and restore subscriptions from disk
|
|
83
|
+
*/
|
|
84
|
+
public async initialize(): Promise<void> {
|
|
85
|
+
if (this.isInitialized) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Ensure .tenex directory exists
|
|
91
|
+
const tenexDir = path.dirname(this.persistencePath);
|
|
92
|
+
await fs.mkdir(tenexDir, { recursive: true });
|
|
93
|
+
|
|
94
|
+
// Load existing subscriptions
|
|
95
|
+
await this.loadSubscriptions();
|
|
96
|
+
|
|
97
|
+
// Re-subscribe to all active subscriptions
|
|
98
|
+
for (const subscription of this.subscriptions.values()) {
|
|
99
|
+
if (subscription.status === SubscriptionStatus.RUNNING) {
|
|
100
|
+
await this.setupResourceSubscription(subscription);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.isInitialized = true;
|
|
105
|
+
logger.info(
|
|
106
|
+
`RagSubscriptionService initialized with ${this.subscriptions.size} subscriptions`
|
|
107
|
+
);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
handleError(error, "Failed to initialize RagSubscriptionService", {
|
|
110
|
+
logLevel: "error",
|
|
111
|
+
});
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Create a new RAG subscription
|
|
118
|
+
*/
|
|
119
|
+
public async createSubscription(
|
|
120
|
+
subscriptionId: string,
|
|
121
|
+
agentPubkey: string,
|
|
122
|
+
mcpServerId: string,
|
|
123
|
+
resourceUri: string,
|
|
124
|
+
ragCollection: string,
|
|
125
|
+
description: string
|
|
126
|
+
): Promise<RagSubscription> {
|
|
127
|
+
// Check if subscription already exists
|
|
128
|
+
if (this.subscriptions.has(subscriptionId)) {
|
|
129
|
+
throw new Error(`Subscription with ID '${subscriptionId}' already exists`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Validate resourceUri is a proper URI format
|
|
133
|
+
try {
|
|
134
|
+
new URL(resourceUri);
|
|
135
|
+
} catch {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`Invalid resourceUri: "${resourceUri}". Resource URI must be a valid URI format (e.g., "nostr://feed/pubkey/kinds", "file:///path/to/file"). This appears to be a tool name or invalid format. If you're using a resource template, you must first expand it with parameters to get the actual URI.`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Verify the RAG collection exists
|
|
142
|
+
const collections = await this.ragService.listCollections();
|
|
143
|
+
if (!collections.includes(ragCollection)) {
|
|
144
|
+
throw new Error(`RAG collection '${ragCollection}' does not exist`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Create subscription object
|
|
148
|
+
const subscription: RagSubscription = {
|
|
149
|
+
subscriptionId,
|
|
150
|
+
agentPubkey,
|
|
151
|
+
mcpServerId,
|
|
152
|
+
resourceUri,
|
|
153
|
+
ragCollection,
|
|
154
|
+
description,
|
|
155
|
+
status: SubscriptionStatus.RUNNING,
|
|
156
|
+
documentsProcessed: 0,
|
|
157
|
+
createdAt: Date.now(),
|
|
158
|
+
updatedAt: Date.now(),
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
// Setup MCP resource subscription
|
|
163
|
+
await this.setupResourceSubscription(subscription);
|
|
164
|
+
|
|
165
|
+
// Store subscription
|
|
166
|
+
this.subscriptions.set(subscriptionId, subscription);
|
|
167
|
+
await this.saveSubscriptions();
|
|
168
|
+
|
|
169
|
+
logger.info(`Created RAG subscription '${subscriptionId}' for agent ${agentPubkey}`);
|
|
170
|
+
return subscription;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
subscription.status = SubscriptionStatus.ERROR;
|
|
173
|
+
subscription.lastError = error instanceof Error ? error.message : "Unknown error";
|
|
174
|
+
handleError(error, `Failed to create subscription '${subscriptionId}'`, {
|
|
175
|
+
logLevel: "error",
|
|
176
|
+
});
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Setup MCP resource subscription and listener
|
|
183
|
+
*/
|
|
184
|
+
private async setupResourceSubscription(subscription: RagSubscription): Promise<void> {
|
|
185
|
+
const listenerKey = `${subscription.mcpServerId}:${subscription.resourceUri}`;
|
|
186
|
+
|
|
187
|
+
// Create listener for this resource.
|
|
188
|
+
// IMPORTANT: MCPManager fans out notifications to ALL handlers on a server,
|
|
189
|
+
// so we must filter by URI to avoid cross-subscription contamination.
|
|
190
|
+
const listener = async (notification: { uri: string; content?: string }): Promise<void> => {
|
|
191
|
+
if (notification.uri !== subscription.resourceUri) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
await this.handleResourceUpdate(subscription, {
|
|
195
|
+
method: "notifications/resources/updated",
|
|
196
|
+
params: notification,
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
// Validate that resourceUri is a proper URI format
|
|
202
|
+
try {
|
|
203
|
+
new URL(subscription.resourceUri);
|
|
204
|
+
} catch {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Invalid resourceUri: "${subscription.resourceUri}". Resource URI must be a valid URI format (e.g., "nostr://feed/pubkey/kinds", "file:///path/to/file"). This appears to be a tool name or invalid format. If you're using a resource template, you must first expand it with parameters to get the actual URI.`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Get mcpManager from project context
|
|
211
|
+
const projectCtx = getProjectContext();
|
|
212
|
+
const mcpManager = projectCtx.mcpManager;
|
|
213
|
+
if (!mcpManager) {
|
|
214
|
+
throw new Error("MCPManager not available in project context");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Try to subscribe to resource updates
|
|
218
|
+
let subscriptionSupported = true;
|
|
219
|
+
try {
|
|
220
|
+
// CRITICAL: Register handler FIRST, then subscribe
|
|
221
|
+
const removeHandler = mcpManager.addResourceNotificationHandler(subscription.mcpServerId, listener);
|
|
222
|
+
|
|
223
|
+
// Subscribe to resource updates
|
|
224
|
+
await mcpManager.subscribeToResource(
|
|
225
|
+
subscription.mcpServerId,
|
|
226
|
+
subscription.resourceUri
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
// Store listener reference and removal function for cleanup
|
|
230
|
+
this.resourceListeners.set(
|
|
231
|
+
listenerKey,
|
|
232
|
+
listener as unknown as (notification: Notification) => void
|
|
233
|
+
);
|
|
234
|
+
this.handlerRemovers.set(listenerKey, removeHandler);
|
|
235
|
+
|
|
236
|
+
logger.info(
|
|
237
|
+
`RAG subscription '${subscription.subscriptionId}' active with push notifications. ` +
|
|
238
|
+
`Listening for updates from ${subscription.mcpServerId}:${subscription.resourceUri}`
|
|
239
|
+
);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (
|
|
242
|
+
error instanceof Error &&
|
|
243
|
+
error.message.includes("does not support resource subscriptions")
|
|
244
|
+
) {
|
|
245
|
+
// Server doesn't support subscriptions, gracefully degrade to polling
|
|
246
|
+
subscriptionSupported = false;
|
|
247
|
+
logger.warn(
|
|
248
|
+
`Server '${subscription.mcpServerId}' does not support resource subscriptions. ` +
|
|
249
|
+
`Subscription '${subscription.subscriptionId}' will use polling mode. ` +
|
|
250
|
+
`Call pollResource() manually or set up a polling interval.`
|
|
251
|
+
);
|
|
252
|
+
// Don't exit - gracefully degrade to polling mode
|
|
253
|
+
} else {
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!subscriptionSupported) {
|
|
259
|
+
subscription.lastError = "Server does not support subscriptions - use polling mode";
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
subscription.status = SubscriptionStatus.ERROR;
|
|
263
|
+
subscription.lastError = error instanceof Error ? error.message : "Unknown error";
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Handle resource update notifications
|
|
270
|
+
*/
|
|
271
|
+
private async handleResourceUpdate(
|
|
272
|
+
subscription: RagSubscription,
|
|
273
|
+
notification: Notification
|
|
274
|
+
): Promise<void> {
|
|
275
|
+
try {
|
|
276
|
+
// Extract content from notification
|
|
277
|
+
const content = this.extractContentFromNotification(notification);
|
|
278
|
+
|
|
279
|
+
if (!content) {
|
|
280
|
+
logger.warn(
|
|
281
|
+
`Received empty update for subscription '${subscription.subscriptionId}'`
|
|
282
|
+
);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Build metadata with provenance fields for filtering at query time
|
|
287
|
+
const metadata: DocumentMetadata = {
|
|
288
|
+
// Auto-inject provenance for filtering at query time
|
|
289
|
+
agent_pubkey: subscription.agentPubkey,
|
|
290
|
+
// Subscription-specific metadata
|
|
291
|
+
subscriptionId: subscription.subscriptionId,
|
|
292
|
+
mcpServerId: subscription.mcpServerId,
|
|
293
|
+
resourceUri: subscription.resourceUri,
|
|
294
|
+
timestamp: Date.now(),
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// Add project_id if available from project context (uses NIP-33 address format)
|
|
298
|
+
if (isProjectContextInitialized()) {
|
|
299
|
+
try {
|
|
300
|
+
const projectCtx = getProjectContext();
|
|
301
|
+
const projectId = projectCtx.project.tagId();
|
|
302
|
+
if (projectId) {
|
|
303
|
+
metadata.project_id = projectId;
|
|
304
|
+
}
|
|
305
|
+
} catch (error) {
|
|
306
|
+
logger.debug("Project context error during RAG subscription update", { error });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Add document to RAG collection
|
|
311
|
+
await this.ragService.addDocuments(subscription.ragCollection, [
|
|
312
|
+
{
|
|
313
|
+
content,
|
|
314
|
+
metadata,
|
|
315
|
+
source: `${subscription.mcpServerId}:${subscription.resourceUri}`,
|
|
316
|
+
timestamp: Date.now(),
|
|
317
|
+
},
|
|
318
|
+
]);
|
|
319
|
+
|
|
320
|
+
// Update subscription metrics
|
|
321
|
+
subscription.documentsProcessed++;
|
|
322
|
+
subscription.lastDocumentIngested = content.substring(0, 200); // Store snippet
|
|
323
|
+
subscription.updatedAt = Date.now();
|
|
324
|
+
subscription.status = SubscriptionStatus.RUNNING;
|
|
325
|
+
subscription.lastError = undefined;
|
|
326
|
+
|
|
327
|
+
await this.saveSubscriptions();
|
|
328
|
+
|
|
329
|
+
logger.debug(
|
|
330
|
+
`Processed update for subscription '${subscription.subscriptionId}', total documents: ${subscription.documentsProcessed}`
|
|
331
|
+
);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
subscription.status = SubscriptionStatus.ERROR;
|
|
334
|
+
subscription.lastError = error instanceof Error ? error.message : "Unknown error";
|
|
335
|
+
subscription.updatedAt = Date.now();
|
|
336
|
+
await this.saveSubscriptions();
|
|
337
|
+
|
|
338
|
+
handleError(
|
|
339
|
+
error,
|
|
340
|
+
`Failed to process update for subscription '${subscription.subscriptionId}'`,
|
|
341
|
+
{ logLevel: "error" }
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Extract content from MCP notification
|
|
348
|
+
*/
|
|
349
|
+
private extractContentFromNotification(notification: Notification): string {
|
|
350
|
+
// Handle different notification formats
|
|
351
|
+
if (typeof notification.params === "object" && notification.params !== null) {
|
|
352
|
+
if ("content" in notification.params) {
|
|
353
|
+
return String(notification.params.content);
|
|
354
|
+
}
|
|
355
|
+
if ("data" in notification.params) {
|
|
356
|
+
return JSON.stringify(notification.params.data);
|
|
357
|
+
}
|
|
358
|
+
if ("text" in notification.params) {
|
|
359
|
+
return String(notification.params.text);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Fallback to stringifying the entire params
|
|
364
|
+
return JSON.stringify(notification.params);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* List all subscriptions for an agent
|
|
369
|
+
*/
|
|
370
|
+
public async listSubscriptions(agentPubkey: string): Promise<RagSubscription[]> {
|
|
371
|
+
const agentSubscriptions = Array.from(this.subscriptions.values()).filter(
|
|
372
|
+
(sub) => sub.agentPubkey === agentPubkey
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
return agentSubscriptions;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Get a specific subscription
|
|
380
|
+
*/
|
|
381
|
+
public async getSubscription(
|
|
382
|
+
subscriptionId: string,
|
|
383
|
+
agentPubkey: string
|
|
384
|
+
): Promise<RagSubscription | null> {
|
|
385
|
+
const subscription = this.subscriptions.get(subscriptionId);
|
|
386
|
+
|
|
387
|
+
if (!subscription || subscription.agentPubkey !== agentPubkey) {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return subscription;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Delete a subscription
|
|
396
|
+
*/
|
|
397
|
+
public async deleteSubscription(subscriptionId: string, agentPubkey: string): Promise<boolean> {
|
|
398
|
+
const subscription = this.subscriptions.get(subscriptionId);
|
|
399
|
+
|
|
400
|
+
if (!subscription || subscription.agentPubkey !== agentPubkey) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Clean up MCP resources (best-effort — don't block deletion if MCP server lost state)
|
|
405
|
+
const listenerKey = `${subscription.mcpServerId}:${subscription.resourceUri}`;
|
|
406
|
+
|
|
407
|
+
// Remove notification handler from MCPManager dispatcher
|
|
408
|
+
const removeHandler = this.handlerRemovers.get(listenerKey);
|
|
409
|
+
if (removeHandler) {
|
|
410
|
+
try {
|
|
411
|
+
removeHandler();
|
|
412
|
+
this.handlerRemovers.delete(listenerKey);
|
|
413
|
+
} catch (error) {
|
|
414
|
+
// Keep the map entry on failure so a future retry can re-attempt removal
|
|
415
|
+
logger.warn(`Failed to remove handler for subscription '${subscriptionId}': ${error instanceof Error ? error.message : error}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (this.resourceListeners.has(listenerKey)) {
|
|
420
|
+
try {
|
|
421
|
+
const projectCtx = getProjectContext();
|
|
422
|
+
const mcpManager = projectCtx.mcpManager;
|
|
423
|
+
|
|
424
|
+
if (mcpManager) {
|
|
425
|
+
// Best-effort: unsubscribe from the MCP resource
|
|
426
|
+
await mcpManager.unsubscribeFromResource(
|
|
427
|
+
subscription.mcpServerId,
|
|
428
|
+
subscription.resourceUri
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
} catch (error) {
|
|
432
|
+
// MCP server may have lost subscription state (e.g. after restart).
|
|
433
|
+
// Log and continue — we still need to remove the local record.
|
|
434
|
+
logger.warn(
|
|
435
|
+
`Best-effort MCP unsubscribe failed for subscription '${subscriptionId}': ${error instanceof Error ? error.message : error}`
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
this.resourceListeners.delete(listenerKey);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Always remove the subscription from local state and persist
|
|
443
|
+
this.subscriptions.delete(subscriptionId);
|
|
444
|
+
await this.saveSubscriptions();
|
|
445
|
+
|
|
446
|
+
logger.info(`Deleted subscription '${subscriptionId}'`);
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Load subscriptions from disk
|
|
452
|
+
*/
|
|
453
|
+
private async loadSubscriptions(): Promise<void> {
|
|
454
|
+
try {
|
|
455
|
+
const data = await fs.readFile(this.persistencePath, "utf-8");
|
|
456
|
+
const subscriptions = JSON.parse(data) as RagSubscription[];
|
|
457
|
+
|
|
458
|
+
for (const subscription of subscriptions) {
|
|
459
|
+
this.subscriptions.set(subscription.subscriptionId, subscription);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
logger.debug(`Loaded ${subscriptions.length} subscriptions from disk`);
|
|
463
|
+
} catch (error) {
|
|
464
|
+
// File doesn't exist yet, that's okay
|
|
465
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
466
|
+
handleError(error, "Failed to load subscriptions", { logLevel: "warn" });
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Save subscriptions to disk
|
|
473
|
+
*/
|
|
474
|
+
private async saveSubscriptions(): Promise<void> {
|
|
475
|
+
try {
|
|
476
|
+
const subscriptions = Array.from(this.subscriptions.values());
|
|
477
|
+
await fs.writeFile(this.persistencePath, JSON.stringify(subscriptions, null, 2));
|
|
478
|
+
logger.debug(`Saved ${subscriptions.length} subscriptions to disk`);
|
|
479
|
+
} catch (error) {
|
|
480
|
+
handleError(error, "Failed to save subscriptions", { logLevel: "error" });
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Get statistics for all subscriptions
|
|
486
|
+
*/
|
|
487
|
+
public getStatistics(): {
|
|
488
|
+
total: number;
|
|
489
|
+
running: number;
|
|
490
|
+
error: number;
|
|
491
|
+
stopped: number;
|
|
492
|
+
totalDocuments: number;
|
|
493
|
+
} {
|
|
494
|
+
let running = 0;
|
|
495
|
+
let error = 0;
|
|
496
|
+
let stopped = 0;
|
|
497
|
+
let totalDocuments = 0;
|
|
498
|
+
|
|
499
|
+
for (const subscription of this.subscriptions.values()) {
|
|
500
|
+
totalDocuments += subscription.documentsProcessed;
|
|
501
|
+
|
|
502
|
+
switch (subscription.status) {
|
|
503
|
+
case SubscriptionStatus.RUNNING:
|
|
504
|
+
running++;
|
|
505
|
+
break;
|
|
506
|
+
case SubscriptionStatus.ERROR:
|
|
507
|
+
error++;
|
|
508
|
+
break;
|
|
509
|
+
case SubscriptionStatus.STOPPED:
|
|
510
|
+
stopped++;
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
total: this.subscriptions.size,
|
|
517
|
+
running,
|
|
518
|
+
error,
|
|
519
|
+
stopped,
|
|
520
|
+
totalDocuments,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Manually trigger a resource update for a subscription
|
|
526
|
+
*
|
|
527
|
+
* This is a workaround until MCP SDK supports resources/subscribe.
|
|
528
|
+
* Allows manual polling or webhook-triggered updates to be processed.
|
|
529
|
+
*
|
|
530
|
+
* @param subscriptionId - The subscription to update
|
|
531
|
+
* @param agentPubkey - Agent pubkey for authorization
|
|
532
|
+
* @param content - The resource content to ingest
|
|
533
|
+
*/
|
|
534
|
+
public async manualResourceUpdate(
|
|
535
|
+
subscriptionId: string,
|
|
536
|
+
agentPubkey: string,
|
|
537
|
+
content: string
|
|
538
|
+
): Promise<void> {
|
|
539
|
+
const subscription = this.subscriptions.get(subscriptionId);
|
|
540
|
+
|
|
541
|
+
if (!subscription || subscription.agentPubkey !== agentPubkey) {
|
|
542
|
+
throw new Error(`Subscription '${subscriptionId}' not found or unauthorized`);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Simulate a notification
|
|
546
|
+
const notification: Notification = {
|
|
547
|
+
method: "notifications/resources/updated",
|
|
548
|
+
params: {
|
|
549
|
+
content,
|
|
550
|
+
uri: subscription.resourceUri,
|
|
551
|
+
timestamp: Date.now(),
|
|
552
|
+
},
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
await this.handleResourceUpdate(subscription, notification);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Poll a resource and update the subscription
|
|
560
|
+
*
|
|
561
|
+
* Fetches the current resource content via MCPManager and ingests it.
|
|
562
|
+
* This is a workaround until MCP SDK supports resources/subscribe.
|
|
563
|
+
*
|
|
564
|
+
* @param subscriptionId - The subscription to poll
|
|
565
|
+
* @param agentPubkey - Agent pubkey for authorization
|
|
566
|
+
*/
|
|
567
|
+
public async pollResource(subscriptionId: string, agentPubkey: string): Promise<void> {
|
|
568
|
+
const subscription = this.subscriptions.get(subscriptionId);
|
|
569
|
+
|
|
570
|
+
if (!subscription || subscription.agentPubkey !== agentPubkey) {
|
|
571
|
+
throw new Error(`Subscription '${subscriptionId}' not found or unauthorized`);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
try {
|
|
575
|
+
// Get mcpManager from project context
|
|
576
|
+
const projectCtx = getProjectContext();
|
|
577
|
+
const mcpManager = projectCtx.mcpManager;
|
|
578
|
+
if (!mcpManager) {
|
|
579
|
+
throw new Error("MCPManager not available in project context");
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Read the current resource content
|
|
583
|
+
const result = await mcpManager.readResource(
|
|
584
|
+
subscription.mcpServerId,
|
|
585
|
+
subscription.resourceUri
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
// Extract text content
|
|
589
|
+
for (const content of result.contents) {
|
|
590
|
+
if ("text" in content) {
|
|
591
|
+
// Create notification with the content
|
|
592
|
+
const notification: Notification = {
|
|
593
|
+
method: "notifications/resources/updated",
|
|
594
|
+
params: {
|
|
595
|
+
content: content.text,
|
|
596
|
+
uri: subscription.resourceUri,
|
|
597
|
+
timestamp: Date.now(),
|
|
598
|
+
},
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
await this.handleResourceUpdate(subscription, notification);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
logger.debug(`Polled resource for subscription '${subscriptionId}'`);
|
|
606
|
+
} catch (error) {
|
|
607
|
+
subscription.status = SubscriptionStatus.ERROR;
|
|
608
|
+
subscription.lastError = error instanceof Error ? error.message : "Unknown error";
|
|
609
|
+
subscription.updatedAt = Date.now();
|
|
610
|
+
await this.saveSubscriptions();
|
|
611
|
+
|
|
612
|
+
handleError(error, `Failed to poll resource for subscription '${subscriptionId}'`, {
|
|
613
|
+
logLevel: "error",
|
|
614
|
+
});
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|