@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,93 @@
|
|
|
1
|
+
import { getTrustPubkeyService, type TrustResult } from "@/services/trust-pubkeys";
|
|
2
|
+
import { logger } from "@/utils/logger";
|
|
3
|
+
import { trace } from "@opentelemetry/api";
|
|
4
|
+
import type { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* PubkeyGateService gates incoming events based on pubkey authorization.
|
|
8
|
+
*
|
|
9
|
+
* An event is allowed through if its author's pubkey is trusted by TrustPubkeyService
|
|
10
|
+
* (whitelisted, backend, or known agent). All other events are silently dropped.
|
|
11
|
+
*
|
|
12
|
+
* Design principles:
|
|
13
|
+
* - Fail-closed: if the trust check errors, the event is denied
|
|
14
|
+
* - Sanitized logging: only pubkey prefix + event kind for observability
|
|
15
|
+
* - OpenTelemetry telemetry for audit trail
|
|
16
|
+
* - Sync trust checks for performance (requires backend pubkey cache initialization)
|
|
17
|
+
*/
|
|
18
|
+
export class PubkeyGateService {
|
|
19
|
+
private static instance: PubkeyGateService;
|
|
20
|
+
|
|
21
|
+
private constructor() {}
|
|
22
|
+
|
|
23
|
+
static getInstance(): PubkeyGateService {
|
|
24
|
+
if (!PubkeyGateService.instance) {
|
|
25
|
+
PubkeyGateService.instance = new PubkeyGateService();
|
|
26
|
+
}
|
|
27
|
+
return PubkeyGateService.instance;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check if an incoming event should be allowed through the gate.
|
|
32
|
+
*
|
|
33
|
+
* Uses synchronous trust checks for performance. The backend pubkey cache
|
|
34
|
+
* must be initialized via TrustPubkeyService.initializeBackendPubkeyCache()
|
|
35
|
+
* before calling this method for accurate backend pubkey checks.
|
|
36
|
+
*
|
|
37
|
+
* @param event The incoming NDKEvent to check
|
|
38
|
+
* @returns true if the event should be routed, false if it should be dropped
|
|
39
|
+
*/
|
|
40
|
+
shouldAllowEvent(event: NDKEvent): boolean {
|
|
41
|
+
const pubkey = event.pubkey;
|
|
42
|
+
|
|
43
|
+
if (!pubkey) {
|
|
44
|
+
logger.debug("[PUBKEY_GATE] Event denied: missing pubkey", {
|
|
45
|
+
kind: event.kind,
|
|
46
|
+
});
|
|
47
|
+
this.recordDenied(event, "no_pubkey");
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let trustResult: TrustResult;
|
|
52
|
+
try {
|
|
53
|
+
trustResult = getTrustPubkeyService().isTrustedEventSync(event);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
// Fail-closed: if the trust check errors, deny
|
|
56
|
+
logger.warn("[PUBKEY_GATE] Trust check failed, denying event (fail-closed)", {
|
|
57
|
+
pubkey: pubkey.substring(0, 8),
|
|
58
|
+
kind: event.kind,
|
|
59
|
+
error: error instanceof Error ? error.message : String(error),
|
|
60
|
+
});
|
|
61
|
+
this.recordDenied(event, "error");
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!trustResult.trusted) {
|
|
66
|
+
logger.debug("[PUBKEY_GATE] Event denied: untrusted pubkey", {
|
|
67
|
+
pubkey: pubkey.substring(0, 8),
|
|
68
|
+
kind: event.kind,
|
|
69
|
+
});
|
|
70
|
+
this.recordDenied(event, "untrusted");
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Record a denied event in telemetry for audit trail.
|
|
79
|
+
*/
|
|
80
|
+
private recordDenied(event: NDKEvent, reason: string): void {
|
|
81
|
+
trace.getActiveSpan()?.addEvent("pubkey_gate.denied", {
|
|
82
|
+
"gate.pubkey": event.pubkey?.substring(0, 8) ?? "unknown",
|
|
83
|
+
"gate.kind": event.kind ?? 0,
|
|
84
|
+
"gate.reason": reason,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get the PubkeyGateService singleton instance
|
|
91
|
+
*/
|
|
92
|
+
export const getPubkeyGateService = (): PubkeyGateService =>
|
|
93
|
+
PubkeyGateService.getInstance();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PubkeyGateService, getPubkeyGateService } from "./PubkeyGateService";
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { fileExists, readJsonFile } from "@/lib/fs";
|
|
3
|
+
import { config } from "@/services/ConfigService";
|
|
4
|
+
import { resolveApiKey } from "@/services/config/types";
|
|
5
|
+
import { logger } from "@/utils/logger";
|
|
6
|
+
import {
|
|
7
|
+
type EmbeddingProvider,
|
|
8
|
+
LocalTransformerEmbeddingProvider,
|
|
9
|
+
OpenAIEmbeddingProvider,
|
|
10
|
+
} from "@/services/embedding";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Configuration for embedding providers
|
|
14
|
+
*/
|
|
15
|
+
export interface EmbeddingConfig {
|
|
16
|
+
provider: string; // "local" or any configured provider ID (openai, openrouter, etc.)
|
|
17
|
+
model: string;
|
|
18
|
+
apiKey?: string;
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface EmbeddingConfigOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Path to the project metadata directory (e.g., ~/.tenex/projects/<dTag>)
|
|
25
|
+
*/
|
|
26
|
+
metadataPath?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Path to the project repository root (used to derive project .tenex path)
|
|
29
|
+
*/
|
|
30
|
+
projectPath?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Scope for resolution. "auto" (default) tries project then global.
|
|
33
|
+
* "project" prioritizes project config but will still fall back to global defaults.
|
|
34
|
+
* "global" only reads the global config.
|
|
35
|
+
*/
|
|
36
|
+
scope?: "auto" | "project" | "global";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Raw configuration as it may appear in JSON files
|
|
41
|
+
* Supports both old format (string or partial object) and new format (full object)
|
|
42
|
+
*/
|
|
43
|
+
type RawEmbeddingConfig =
|
|
44
|
+
| string // Old format: just model name
|
|
45
|
+
| { model: string; provider?: never } // Old format: object with just model
|
|
46
|
+
| { provider: string; model: string; apiKey?: string; baseUrl?: string }; // New format
|
|
47
|
+
|
|
48
|
+
function isRawEmbeddingConfig(value: unknown): value is RawEmbeddingConfig {
|
|
49
|
+
if (typeof value === "string") {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof value !== "object" || value === null) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const obj = value as Record<string, unknown>;
|
|
58
|
+
|
|
59
|
+
// Must have a model
|
|
60
|
+
if (!("model" in obj) || typeof obj.model !== "string") {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// If provider is present, must be a string
|
|
65
|
+
if ("provider" in obj && typeof obj.provider !== "string") {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If apiKey is present, must be string
|
|
70
|
+
if ("apiKey" in obj && typeof obj.apiKey !== "string") {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// If baseUrl is present, must be string
|
|
75
|
+
if ("baseUrl" in obj && typeof obj.baseUrl !== "string") {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Factory for creating embedding providers based on configuration
|
|
84
|
+
*/
|
|
85
|
+
export class EmbeddingProviderFactory {
|
|
86
|
+
private static readonly EMBED_CONFIG_FILE = "embed.json";
|
|
87
|
+
private static readonly DEFAULT_CONFIG: EmbeddingConfig = {
|
|
88
|
+
provider: "local",
|
|
89
|
+
model: "Xenova/all-MiniLM-L6-v2",
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Base URLs for known OpenAI-compatible providers
|
|
94
|
+
*/
|
|
95
|
+
private static readonly PROVIDER_BASE_URLS: Record<string, string> = {
|
|
96
|
+
openai: "https://api.openai.com/v1",
|
|
97
|
+
openrouter: "https://openrouter.ai/api/v1",
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Create an embedding provider based on configuration
|
|
102
|
+
*/
|
|
103
|
+
static async create(
|
|
104
|
+
customConfig?: EmbeddingConfig,
|
|
105
|
+
options?: EmbeddingConfigOptions
|
|
106
|
+
): Promise<EmbeddingProvider> {
|
|
107
|
+
const embeddingConfig = customConfig || (await EmbeddingProviderFactory.loadConfiguration(options));
|
|
108
|
+
|
|
109
|
+
logger.debug(`Creating embedding provider: ${embeddingConfig.provider}/${embeddingConfig.model}`);
|
|
110
|
+
|
|
111
|
+
// Local provider
|
|
112
|
+
if (embeddingConfig.provider === "local") {
|
|
113
|
+
return new LocalTransformerEmbeddingProvider(embeddingConfig.model);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// All other providers are treated as OpenAI-compatible
|
|
117
|
+
if (!embeddingConfig.apiKey) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`API key required for ${embeddingConfig.provider}. Configure with 'tenex setup embed'.`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const baseUrl = embeddingConfig.baseUrl ||
|
|
124
|
+
EmbeddingProviderFactory.PROVIDER_BASE_URLS[embeddingConfig.provider] ||
|
|
125
|
+
"https://api.openai.com/v1";
|
|
126
|
+
|
|
127
|
+
return new OpenAIEmbeddingProvider(embeddingConfig.apiKey, embeddingConfig.model, baseUrl);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Load embedding configuration using configured paths.
|
|
132
|
+
* If a project path is provided, project config is tried first, then global.
|
|
133
|
+
* If no paths are provided, falls back to CWD project path (legacy) and then global.
|
|
134
|
+
*/
|
|
135
|
+
static async loadConfiguration(options?: EmbeddingConfigOptions): Promise<EmbeddingConfig> {
|
|
136
|
+
try {
|
|
137
|
+
const basePaths = EmbeddingProviderFactory.resolveConfigBases(options);
|
|
138
|
+
|
|
139
|
+
for (const basePath of basePaths) {
|
|
140
|
+
const configPath = path.join(basePath, EmbeddingProviderFactory.EMBED_CONFIG_FILE);
|
|
141
|
+
if (!(await fileExists(configPath))) continue;
|
|
142
|
+
|
|
143
|
+
const rawConfig = await readJsonFile<unknown>(configPath);
|
|
144
|
+
if (!isRawEmbeddingConfig(rawConfig)) {
|
|
145
|
+
logger.warn(`Invalid embedding config at ${configPath}, using defaults`);
|
|
146
|
+
return EmbeddingProviderFactory.DEFAULT_CONFIG;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
logger.debug(`Loaded embedding config from ${configPath}`);
|
|
150
|
+
return await EmbeddingProviderFactory.parseConfig(rawConfig);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
logger.debug("No embedding configuration found, using defaults");
|
|
154
|
+
return EmbeddingProviderFactory.DEFAULT_CONFIG;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
logger.warn("Failed to load embedding configuration, using defaults", { error });
|
|
157
|
+
return EmbeddingProviderFactory.DEFAULT_CONFIG;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Load provider credentials from providers.json
|
|
163
|
+
*/
|
|
164
|
+
private static async loadProviderCredentials(providerId: string): Promise<{ apiKey?: string; baseUrl?: string }> {
|
|
165
|
+
try {
|
|
166
|
+
const globalPath = config.getGlobalPath();
|
|
167
|
+
const providersConfig = await config.loadTenexProviders(globalPath);
|
|
168
|
+
const providerCreds = providersConfig.providers[providerId];
|
|
169
|
+
return {
|
|
170
|
+
apiKey: resolveApiKey(providerCreds?.apiKey),
|
|
171
|
+
baseUrl: providerCreds?.baseUrl,
|
|
172
|
+
};
|
|
173
|
+
} catch (error) {
|
|
174
|
+
logger.debug(`Failed to load provider credentials for ${providerId}`, { error });
|
|
175
|
+
return {};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Parse and validate embedding configuration
|
|
181
|
+
*/
|
|
182
|
+
private static async parseConfig(raw: RawEmbeddingConfig): Promise<EmbeddingConfig> {
|
|
183
|
+
// Support both old format (just model string) and new format
|
|
184
|
+
if (typeof raw === "string" || (raw?.model && !raw.provider)) {
|
|
185
|
+
// Old format or just model specified
|
|
186
|
+
const modelId = typeof raw === "string" ? raw : raw.model;
|
|
187
|
+
|
|
188
|
+
// Infer provider from model name
|
|
189
|
+
if (modelId.includes("text-embedding")) {
|
|
190
|
+
const creds = await EmbeddingProviderFactory.loadProviderCredentials("openai");
|
|
191
|
+
return {
|
|
192
|
+
provider: "openai",
|
|
193
|
+
model: modelId,
|
|
194
|
+
apiKey: creds.apiKey,
|
|
195
|
+
baseUrl: creds.baseUrl,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
provider: "local",
|
|
201
|
+
model: modelId,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// New format with explicit provider
|
|
206
|
+
const rawConfig = raw as { provider?: string; model?: string; apiKey?: string; baseUrl?: string };
|
|
207
|
+
const provider = rawConfig.provider || "local";
|
|
208
|
+
|
|
209
|
+
// Load credentials from providers.json if not provided inline
|
|
210
|
+
let apiKey = rawConfig.apiKey;
|
|
211
|
+
let baseUrl = rawConfig.baseUrl;
|
|
212
|
+
|
|
213
|
+
if (provider !== "local" && !apiKey) {
|
|
214
|
+
const creds = await EmbeddingProviderFactory.loadProviderCredentials(provider);
|
|
215
|
+
apiKey = creds.apiKey;
|
|
216
|
+
baseUrl = baseUrl || creds.baseUrl;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
provider,
|
|
221
|
+
model: rawConfig.model || EmbeddingProviderFactory.DEFAULT_CONFIG.model,
|
|
222
|
+
apiKey,
|
|
223
|
+
baseUrl,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Save embedding configuration
|
|
229
|
+
*/
|
|
230
|
+
static async saveConfiguration(
|
|
231
|
+
embeddingConfig: EmbeddingConfig,
|
|
232
|
+
scope: "global" | "project" = "global",
|
|
233
|
+
options?: EmbeddingConfigOptions
|
|
234
|
+
): Promise<void> {
|
|
235
|
+
const basePath =
|
|
236
|
+
scope === "global"
|
|
237
|
+
? config.getGlobalPath()
|
|
238
|
+
: EmbeddingProviderFactory.resolveProjectBase(options) ||
|
|
239
|
+
config.getProjectPath(process.cwd());
|
|
240
|
+
|
|
241
|
+
const configPath = path.join(basePath, EmbeddingProviderFactory.EMBED_CONFIG_FILE);
|
|
242
|
+
|
|
243
|
+
// Don't save API key to file - it's stored in providers.json
|
|
244
|
+
const configToSave: { provider: string; model: string; baseUrl?: string } = {
|
|
245
|
+
provider: embeddingConfig.provider,
|
|
246
|
+
model: embeddingConfig.model,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Only save baseUrl if it's a custom one (not the default for the provider)
|
|
250
|
+
const defaultBaseUrl = EmbeddingProviderFactory.PROVIDER_BASE_URLS[embeddingConfig.provider];
|
|
251
|
+
if (embeddingConfig.baseUrl && embeddingConfig.baseUrl !== defaultBaseUrl) {
|
|
252
|
+
configToSave.baseUrl = embeddingConfig.baseUrl;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const { writeJsonFile, ensureDirectory } = await import("@/lib/fs");
|
|
256
|
+
await ensureDirectory(basePath);
|
|
257
|
+
await writeJsonFile(configPath, configToSave);
|
|
258
|
+
|
|
259
|
+
logger.info(
|
|
260
|
+
`Embedding configuration saved to ${scope} config: ${embeddingConfig.provider}/${embeddingConfig.model}`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private static resolveConfigBases(options?: EmbeddingConfigOptions): string[] {
|
|
265
|
+
const scope = options?.scope ?? "auto";
|
|
266
|
+
const bases: string[] = [];
|
|
267
|
+
|
|
268
|
+
if (scope !== "global") {
|
|
269
|
+
const projectBase = EmbeddingProviderFactory.resolveProjectBase(options);
|
|
270
|
+
if (projectBase) {
|
|
271
|
+
bases.push(projectBase);
|
|
272
|
+
} else if (!options) {
|
|
273
|
+
// Legacy fallback to current working directory
|
|
274
|
+
bases.push(config.getProjectPath(process.cwd()));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Always append global as fallback/default
|
|
279
|
+
bases.push(config.getGlobalPath());
|
|
280
|
+
return bases;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private static resolveProjectBase(options?: EmbeddingConfigOptions): string | undefined {
|
|
284
|
+
if (options?.metadataPath) {
|
|
285
|
+
return options.metadataPath;
|
|
286
|
+
}
|
|
287
|
+
if (options?.projectPath) {
|
|
288
|
+
return config.getProjectPath(options.projectPath);
|
|
289
|
+
}
|
|
290
|
+
return undefined;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LanceDBMaintenanceService - Periodic compaction and cleanup
|
|
3
|
+
*
|
|
4
|
+
* Runs optimize() on all LanceDB tables to:
|
|
5
|
+
* - Compact small fragment files into larger ones
|
|
6
|
+
* - Prune old version manifests
|
|
7
|
+
*
|
|
8
|
+
* This prevents fragmentation accumulation from frequent writes.
|
|
9
|
+
* Uses a self-scheduling setTimeout pattern (like ConversationIndexingJob)
|
|
10
|
+
* to prevent overlapping runs.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { logger } from "@/utils/logger";
|
|
14
|
+
import { RAGDatabaseService } from "./RAGDatabaseService";
|
|
15
|
+
|
|
16
|
+
/** Default interval: 2 hours (in milliseconds) */
|
|
17
|
+
const DEFAULT_INTERVAL_MS = 2 * 60 * 60 * 1000;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Cleanup versions older than this duration.
|
|
21
|
+
* We keep 1 day of history for safety; the current version is never removed.
|
|
22
|
+
*/
|
|
23
|
+
const DEFAULT_CLEANUP_OLDER_THAN_DAYS = 1;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Periodic LanceDB maintenance service
|
|
27
|
+
*/
|
|
28
|
+
export class LanceDBMaintenanceService {
|
|
29
|
+
private static instance: LanceDBMaintenanceService | null = null;
|
|
30
|
+
private timer: NodeJS.Timeout | null = null;
|
|
31
|
+
private isRunning = false;
|
|
32
|
+
private isMaintenanceRunning = false;
|
|
33
|
+
private intervalMs: number;
|
|
34
|
+
|
|
35
|
+
private constructor(intervalMs: number = DEFAULT_INTERVAL_MS) {
|
|
36
|
+
this.intervalMs = intervalMs;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get singleton instance
|
|
41
|
+
*/
|
|
42
|
+
public static getInstance(intervalMs?: number): LanceDBMaintenanceService {
|
|
43
|
+
if (!LanceDBMaintenanceService.instance) {
|
|
44
|
+
LanceDBMaintenanceService.instance = new LanceDBMaintenanceService(intervalMs);
|
|
45
|
+
}
|
|
46
|
+
return LanceDBMaintenanceService.instance;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Start the periodic maintenance job
|
|
51
|
+
*/
|
|
52
|
+
public start(): void {
|
|
53
|
+
if (this.isRunning) {
|
|
54
|
+
logger.warn("LanceDBMaintenanceService is already running");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.isRunning = true;
|
|
59
|
+
logger.info("Starting LanceDBMaintenanceService", {
|
|
60
|
+
intervalMs: this.intervalMs,
|
|
61
|
+
intervalHours: this.intervalMs / (60 * 60 * 1000),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Run first maintenance after a short delay (30 seconds)
|
|
65
|
+
// to let the system finish booting
|
|
66
|
+
this.scheduleNextRun(30_000);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Schedule the next maintenance run (self-scheduling to prevent overlaps)
|
|
71
|
+
*/
|
|
72
|
+
private scheduleNextRun(delayMs: number): void {
|
|
73
|
+
if (!this.isRunning) return;
|
|
74
|
+
|
|
75
|
+
this.timer = setTimeout(async () => {
|
|
76
|
+
try {
|
|
77
|
+
await this.runMaintenance();
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logger.error("LanceDB maintenance failed", { error });
|
|
80
|
+
} finally {
|
|
81
|
+
// Schedule next run only after this one completes
|
|
82
|
+
this.scheduleNextRun(this.intervalMs);
|
|
83
|
+
}
|
|
84
|
+
}, delayMs);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Stop the periodic maintenance job
|
|
89
|
+
*/
|
|
90
|
+
public stop(): void {
|
|
91
|
+
if (!this.isRunning) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (this.timer) {
|
|
96
|
+
clearTimeout(this.timer);
|
|
97
|
+
this.timer = null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
this.isRunning = false;
|
|
101
|
+
logger.info("LanceDBMaintenanceService stopped");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Run maintenance on all LanceDB tables
|
|
106
|
+
*/
|
|
107
|
+
private async runMaintenance(): Promise<void> {
|
|
108
|
+
if (this.isMaintenanceRunning) {
|
|
109
|
+
logger.warn("Skipping LanceDB maintenance - previous run still in progress");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this.isMaintenanceRunning = true;
|
|
114
|
+
|
|
115
|
+
// Use a temporary DB service to avoid coupling to RAGService singleton
|
|
116
|
+
// (which requires embedding provider initialization)
|
|
117
|
+
let dbService: RAGDatabaseService | null = null;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
dbService = new RAGDatabaseService();
|
|
121
|
+
const tableNames = await dbService.listTables();
|
|
122
|
+
|
|
123
|
+
if (tableNames.length === 0) {
|
|
124
|
+
logger.debug("No LanceDB tables to optimize");
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
logger.info("Starting LanceDB maintenance", { tableCount: tableNames.length });
|
|
129
|
+
|
|
130
|
+
const cleanupOlderThan = new Date();
|
|
131
|
+
cleanupOlderThan.setDate(cleanupOlderThan.getDate() - DEFAULT_CLEANUP_OLDER_THAN_DAYS);
|
|
132
|
+
|
|
133
|
+
let optimizedCount = 0;
|
|
134
|
+
|
|
135
|
+
for (const tableName of tableNames) {
|
|
136
|
+
try {
|
|
137
|
+
const table = await dbService.getTable(tableName);
|
|
138
|
+
const stats = await table.optimize({
|
|
139
|
+
cleanupOlderThan,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
optimizedCount++;
|
|
143
|
+
logger.info(`Optimized table '${tableName}'`, {
|
|
144
|
+
compaction: stats.compaction,
|
|
145
|
+
prune: stats.prune,
|
|
146
|
+
});
|
|
147
|
+
} catch (error) {
|
|
148
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
149
|
+
logger.error(`Failed to optimize table '${tableName}'`, {
|
|
150
|
+
error: message,
|
|
151
|
+
});
|
|
152
|
+
// Continue with other tables
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
logger.info("LanceDB maintenance complete", {
|
|
157
|
+
tablesOptimized: optimizedCount,
|
|
158
|
+
totalTables: tableNames.length,
|
|
159
|
+
});
|
|
160
|
+
} catch (error) {
|
|
161
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
162
|
+
logger.error("LanceDB maintenance failed", { error: message });
|
|
163
|
+
} finally {
|
|
164
|
+
if (dbService) {
|
|
165
|
+
try {
|
|
166
|
+
await dbService.close();
|
|
167
|
+
} catch (closeError) {
|
|
168
|
+
logger.debug("Failed to close maintenance DB service", { error: closeError });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
this.isMaintenanceRunning = false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Force an immediate maintenance run (for manual triggering)
|
|
177
|
+
*/
|
|
178
|
+
public async forceRun(): Promise<void> {
|
|
179
|
+
await this.runMaintenance();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get current service status
|
|
184
|
+
*/
|
|
185
|
+
public getStatus(): {
|
|
186
|
+
isRunning: boolean;
|
|
187
|
+
isMaintenanceRunning: boolean;
|
|
188
|
+
intervalMs: number;
|
|
189
|
+
} {
|
|
190
|
+
return {
|
|
191
|
+
isRunning: this.isRunning,
|
|
192
|
+
isMaintenanceRunning: this.isMaintenanceRunning,
|
|
193
|
+
intervalMs: this.intervalMs,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Reset singleton instance (for testing)
|
|
199
|
+
*/
|
|
200
|
+
public static resetInstance(): void {
|
|
201
|
+
if (LanceDBMaintenanceService.instance) {
|
|
202
|
+
LanceDBMaintenanceService.instance.stop();
|
|
203
|
+
LanceDBMaintenanceService.instance = null;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Export lazy getter
|
|
209
|
+
export function getLanceDBMaintenanceService(): LanceDBMaintenanceService {
|
|
210
|
+
return LanceDBMaintenanceService.getInstance();
|
|
211
|
+
}
|