@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,119 @@
|
|
|
1
|
+
import { NDKKind } from "@/nostr/kinds";
|
|
2
|
+
import type { Hexpubkey, NDKFilter } from "@nostr-dev-kit/ndk";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Static utility class for building NDK subscription filters.
|
|
6
|
+
*
|
|
7
|
+
* Each method builds filters for one independent subscription group.
|
|
8
|
+
* The SubscriptionManager calls these individually rather than
|
|
9
|
+
* combining them into a single monolithic filter set.
|
|
10
|
+
*/
|
|
11
|
+
export class SubscriptionFilterBuilder {
|
|
12
|
+
/**
|
|
13
|
+
* Build filters for the static subscription (created once at boot, never recreated).
|
|
14
|
+
* Includes:
|
|
15
|
+
* - Project discovery (kind 31933) from whitelisted pubkeys
|
|
16
|
+
* - Agent config updates (kind 24020) from whitelisted pubkeys
|
|
17
|
+
* - Lesson comments (kind 1111, #K: 4129) from whitelisted pubkeys
|
|
18
|
+
*/
|
|
19
|
+
static buildStaticFilters(whitelistedPubkeys: Set<Hexpubkey>): NDKFilter[] {
|
|
20
|
+
if (whitelistedPubkeys.size === 0) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const authors = Array.from(whitelistedPubkeys);
|
|
25
|
+
|
|
26
|
+
return [
|
|
27
|
+
// Project discovery + agent config updates + agent deletions
|
|
28
|
+
{
|
|
29
|
+
kinds: [31933, NDKKind.TenexAgentConfigUpdate, NDKKind.TenexAgentDelete],
|
|
30
|
+
authors,
|
|
31
|
+
},
|
|
32
|
+
// Lesson comments from whitelisted authors
|
|
33
|
+
// No #p filter — the Daemon uses the E tag to route to the correct agent
|
|
34
|
+
{
|
|
35
|
+
kinds: [NDKKind.Comment],
|
|
36
|
+
"#K": [String(NDKKind.AgentLesson)],
|
|
37
|
+
authors,
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Build filter for events tagging known projects via A-tags
|
|
44
|
+
* Receives all events tagged to our projects — the Daemon decides
|
|
45
|
+
* which events can boot a cold project vs which require a running one
|
|
46
|
+
* @param knownProjects - Set of project IDs (format: "31933:authorPubkey:dTag")
|
|
47
|
+
* @param since - Optional Unix timestamp (seconds) to filter out historical events
|
|
48
|
+
* @returns NDKFilter for project-tagged events or null if no projects
|
|
49
|
+
*/
|
|
50
|
+
static buildProjectTaggedFilter(knownProjects: Set<string>, since?: number): NDKFilter | null {
|
|
51
|
+
if (knownProjects.size === 0) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const filter: NDKFilter = {
|
|
56
|
+
"#a": Array.from(knownProjects),
|
|
57
|
+
limit: 0,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if (since !== undefined) {
|
|
61
|
+
filter.since = since;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return filter;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Build filter for report events (kind 30023 - NDKArticle)
|
|
69
|
+
* Monitors reports tagged with our project
|
|
70
|
+
* @param knownProjects - Set of project A-tags (format: "31933:authorPubkey:dTag")
|
|
71
|
+
* @returns NDKFilter for report events or null if no projects
|
|
72
|
+
*/
|
|
73
|
+
static buildReportFilter(knownProjects: Set<string>): NDKFilter | null {
|
|
74
|
+
if (knownProjects.size === 0) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
kinds: [30023],
|
|
80
|
+
"#a": Array.from(knownProjects),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Build filter for events mentioning agents via P-tags
|
|
86
|
+
* @param agentPubkeys - Set of agent pubkeys to monitor
|
|
87
|
+
* @param since - Optional Unix timestamp (seconds) to filter out historical events
|
|
88
|
+
* @returns NDKFilter for agent mentions or null if no agents
|
|
89
|
+
*/
|
|
90
|
+
static buildAgentMentionsFilter(agentPubkeys: Set<Hexpubkey>, since?: number): NDKFilter | null {
|
|
91
|
+
if (agentPubkeys.size === 0) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const filter: NDKFilter = {
|
|
96
|
+
"#p": Array.from(agentPubkeys),
|
|
97
|
+
limit: 0,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
if (since !== undefined) {
|
|
101
|
+
filter.since = since;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return filter;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Build filter for a single agent's lessons by definition event ID.
|
|
109
|
+
* Uses #e tag to match lessons that reference the agent definition.
|
|
110
|
+
* @param definitionId - Agent definition event ID
|
|
111
|
+
* @returns NDKFilter for this agent's lessons
|
|
112
|
+
*/
|
|
113
|
+
static buildLessonFilter(definitionId: string): NDKFilter {
|
|
114
|
+
return {
|
|
115
|
+
kinds: [NDKKind.AgentLesson],
|
|
116
|
+
"#e": [definitionId],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import { AgentEventDecoder } from "@/nostr/AgentEventDecoder";
|
|
2
|
+
import { logger } from "@/utils/logger";
|
|
3
|
+
import type { Hexpubkey, NDKEvent } from "@nostr-dev-kit/ndk";
|
|
4
|
+
import type { NDKProject } from "@nostr-dev-kit/ndk";
|
|
5
|
+
import type { ProjectRuntime } from "../ProjectRuntime";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Result of routing decision for an event
|
|
9
|
+
*/
|
|
10
|
+
export interface RoutingDecision {
|
|
11
|
+
projectId: string | null;
|
|
12
|
+
method: "a_tag" | "p_tag_agent" | "none";
|
|
13
|
+
matchedTags: string[];
|
|
14
|
+
reason: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Static utility class for daemon-level event routing.
|
|
19
|
+
* Determines which project an event should be routed to based on tags.
|
|
20
|
+
*
|
|
21
|
+
* This is daemon-level routing (event -> project), separate from
|
|
22
|
+
* AgentRouter which handles project-level routing (event -> agent).
|
|
23
|
+
*/
|
|
24
|
+
export class DaemonRouter {
|
|
25
|
+
/**
|
|
26
|
+
* Check if this daemon should trace this event.
|
|
27
|
+
*
|
|
28
|
+
* This balances two concerns:
|
|
29
|
+
* 1. Avoiding noisy traces when multiple daemons share relays
|
|
30
|
+
* 2. Allowing project discovery (bootstrap problem)
|
|
31
|
+
*
|
|
32
|
+
* The key insight: only trace events that this daemon will actually process.
|
|
33
|
+
* - Project events: Always trace from whitelisted authors (for discovery)
|
|
34
|
+
* - Other events: Only trace if we have a runtime OR event can boot one
|
|
35
|
+
*
|
|
36
|
+
* @param event - The event to check
|
|
37
|
+
* @param knownProjects - Map of project IDs this daemon controls
|
|
38
|
+
* @param knownAgentPubkeys - Set of agent pubkeys from project definitions
|
|
39
|
+
* @param whitelistedPubkeys - Array of pubkeys that can create projects
|
|
40
|
+
* @param activeRuntimes - Map of currently active project runtimes
|
|
41
|
+
* @returns true if the event should be traced by this daemon
|
|
42
|
+
*/
|
|
43
|
+
static shouldTraceEvent(
|
|
44
|
+
event: NDKEvent,
|
|
45
|
+
knownProjects: Map<string, NDKProject>,
|
|
46
|
+
knownAgentPubkeys: Set<Hexpubkey>,
|
|
47
|
+
whitelistedPubkeys: Hexpubkey[],
|
|
48
|
+
activeRuntimes: Map<string, ProjectRuntime>
|
|
49
|
+
): boolean {
|
|
50
|
+
// Never-route kinds don't need tracing at all
|
|
51
|
+
if (AgentEventDecoder.isNeverRouteKind(event)) {
|
|
52
|
+
logger.debug("shouldTraceEvent: never-route kind", { kind: event.kind });
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Project events from whitelisted authors should always be traced.
|
|
57
|
+
// This includes new projects we haven't seen yet (avoiding bootstrap problem).
|
|
58
|
+
if (AgentEventDecoder.isProjectEvent(event)) {
|
|
59
|
+
const isWhitelisted = whitelistedPubkeys.includes(event.pubkey);
|
|
60
|
+
logger.debug("shouldTraceEvent: project event", {
|
|
61
|
+
kind: event.kind,
|
|
62
|
+
author: event.pubkey.slice(0, 8),
|
|
63
|
+
isWhitelisted,
|
|
64
|
+
whitelistedCount: whitelistedPubkeys.length,
|
|
65
|
+
});
|
|
66
|
+
return isWhitelisted;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Agent config updates (kind 24020) from whitelisted authors are handled
|
|
70
|
+
// at daemon level (no project routing needed for global updates).
|
|
71
|
+
if (AgentEventDecoder.isConfigUpdate(event)) {
|
|
72
|
+
const isWhitelisted = whitelistedPubkeys.includes(event.pubkey);
|
|
73
|
+
return isWhitelisted;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Lesson events from our agents should be traced if we have a runtime
|
|
77
|
+
// for at least one of their projects.
|
|
78
|
+
if (AgentEventDecoder.isLessonEvent(event)) {
|
|
79
|
+
// Check if this agent's project has an active runtime
|
|
80
|
+
for (const [projectId] of activeRuntimes) {
|
|
81
|
+
if (knownAgentPubkeys.has(event.pubkey)) {
|
|
82
|
+
// Agent is known, check if their project is running
|
|
83
|
+
const project = knownProjects.get(projectId);
|
|
84
|
+
if (project) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// For other events, we need to determine if we'd actually process them.
|
|
93
|
+
// This balances two concerns:
|
|
94
|
+
// 1. Boot events (kind:24000 and kind:1) must be able to start projects
|
|
95
|
+
// 2. Regular events should only trace if we have an active runtime (prevents "other backend" noise)
|
|
96
|
+
|
|
97
|
+
// kind:24000 (TenexBootProject) is an EXPLICIT boot request - always allow if project is known
|
|
98
|
+
// kind:1 (Text) can also boot projects (per routeEventToProject logic)
|
|
99
|
+
const isExplicitBootRequest = event.kind === 24000;
|
|
100
|
+
const canBootProject = event.kind === 1 || event.kind === 24000;
|
|
101
|
+
|
|
102
|
+
if (isExplicitBootRequest) {
|
|
103
|
+
logger.debug("shouldTraceEvent: boot request event", {
|
|
104
|
+
kind: event.kind,
|
|
105
|
+
author: event.pubkey.slice(0, 8),
|
|
106
|
+
aTags: event.tags.filter(t => t[0] === "a").map(t => t[1]),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check if event is authored by one of our agents with an active runtime
|
|
111
|
+
if (knownAgentPubkeys.has(event.pubkey)) {
|
|
112
|
+
// Find if any of our active runtimes contain this agent
|
|
113
|
+
for (const [, runtime] of activeRuntimes) {
|
|
114
|
+
const context = runtime.getContext();
|
|
115
|
+
if (context) {
|
|
116
|
+
const agent = context.agentRegistry.getAllAgents().find(a => a.pubkey === event.pubkey);
|
|
117
|
+
if (agent) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Agent known but no active runtime - don't trace
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Check for a-tags to our projects (NIP-33 addressable event references)
|
|
127
|
+
const aTags = event.tags.filter((t) => t[0] === "a");
|
|
128
|
+
for (const tag of aTags) {
|
|
129
|
+
const aTagValue = tag[1];
|
|
130
|
+
if (aTagValue && knownProjects.has(aTagValue)) {
|
|
131
|
+
// Project is known - trace if:
|
|
132
|
+
// 1. We have an active runtime, OR
|
|
133
|
+
// 2. This event can boot projects (kind:1 or kind:24000)
|
|
134
|
+
// CRITICAL: kind:1 events with explicit A-tags MUST trace even without runtime
|
|
135
|
+
// to prevent cross-project routing bugs when agents exist in multiple projects
|
|
136
|
+
const hasRuntime = activeRuntimes.has(aTagValue);
|
|
137
|
+
if (hasRuntime || canBootProject) {
|
|
138
|
+
logger.debug("shouldTraceEvent: accepting via A-tag", {
|
|
139
|
+
kind: event.kind,
|
|
140
|
+
projectId: aTagValue.slice(0, 30),
|
|
141
|
+
hasRuntime,
|
|
142
|
+
canBootProject,
|
|
143
|
+
});
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
// Known project but no active runtime and cannot boot - don't trace
|
|
147
|
+
logger.debug("shouldTraceEvent: rejecting - known project but no runtime", {
|
|
148
|
+
kind: event.kind,
|
|
149
|
+
projectId: aTagValue.slice(0, 30),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check for P-tags to our agents
|
|
155
|
+
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
156
|
+
for (const tag of pTags) {
|
|
157
|
+
const pubkey = tag[1];
|
|
158
|
+
if (pubkey && knownAgentPubkeys.has(pubkey as Hexpubkey)) {
|
|
159
|
+
// Find if this agent's project has an active runtime
|
|
160
|
+
for (const [, runtime] of activeRuntimes) {
|
|
161
|
+
const context = runtime.getContext();
|
|
162
|
+
if (context) {
|
|
163
|
+
const agent = context.agentRegistry.getAllAgents().find(a => a.pubkey === pubkey);
|
|
164
|
+
if (agent) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Agent known but no active runtime - don't trace
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// No match - don't trace
|
|
175
|
+
logger.debug("shouldTraceEvent: no match found", {
|
|
176
|
+
kind: event.kind,
|
|
177
|
+
author: event.pubkey.slice(0, 8),
|
|
178
|
+
aTags: aTags.map(t => t[1]?.slice(0, 20)),
|
|
179
|
+
pTags: pTags.map(t => t[1]?.slice(0, 8)),
|
|
180
|
+
knownProjectsCount: knownProjects.size,
|
|
181
|
+
activeRuntimesCount: activeRuntimes.size,
|
|
182
|
+
});
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Determine which project an event should be routed to
|
|
188
|
+
* @param event - The event to route
|
|
189
|
+
* @param knownProjects - Map of known project IDs to NDKProject instances
|
|
190
|
+
* @param agentPubkeyToProjects - Map of agent pubkeys to their project IDs
|
|
191
|
+
* @param activeRuntimes - Map of active project runtimes (for agent lookup)
|
|
192
|
+
* @returns Routing decision with target project or null if no match
|
|
193
|
+
*/
|
|
194
|
+
static determineTargetProject(
|
|
195
|
+
event: NDKEvent,
|
|
196
|
+
knownProjects: Map<string, NDKProject>,
|
|
197
|
+
agentPubkeyToProjects: Map<Hexpubkey, Set<string>>,
|
|
198
|
+
activeRuntimes: Map<string, ProjectRuntime>
|
|
199
|
+
): RoutingDecision {
|
|
200
|
+
// Skip routing for global identity kinds (NIP-01, NIP-02)
|
|
201
|
+
// kind:0 (profile metadata) and kind:3 (contact list) are global user/agent identity
|
|
202
|
+
// and should never be routed to specific projects
|
|
203
|
+
if (event.kind === 0 || event.kind === 3) {
|
|
204
|
+
return {
|
|
205
|
+
projectId: null,
|
|
206
|
+
method: "none",
|
|
207
|
+
matchedTags: [],
|
|
208
|
+
reason: `Global identity kind (${event.kind}) - not project-specific`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Check for explicit project A-tags first (highest priority)
|
|
213
|
+
const routingByATag = this.routeByATag(event, knownProjects);
|
|
214
|
+
if (routingByATag) {
|
|
215
|
+
return routingByATag;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Check for agent P-tags (find project by agent pubkey)
|
|
219
|
+
const routingByPTag = this.routeByPTag(
|
|
220
|
+
event,
|
|
221
|
+
knownProjects,
|
|
222
|
+
agentPubkeyToProjects,
|
|
223
|
+
activeRuntimes
|
|
224
|
+
);
|
|
225
|
+
if (routingByPTag) {
|
|
226
|
+
return routingByPTag;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// No match found
|
|
230
|
+
const aTags = event.tags.filter((t) => t[0] === "a");
|
|
231
|
+
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
232
|
+
const projectATags = aTags.filter((t) => t[1]?.startsWith("31933:"));
|
|
233
|
+
|
|
234
|
+
const reason =
|
|
235
|
+
projectATags.length > 0
|
|
236
|
+
? `A-tags found but no matching known projects: ${projectATags.map((t) => t[1]).join(", ")}`
|
|
237
|
+
: pTags.length > 0
|
|
238
|
+
? `P-tags found but no matching agents: ${pTags.map((t) => t[1]?.slice(0, 8)).join(", ")}`
|
|
239
|
+
: "No A-tags or P-tags found";
|
|
240
|
+
|
|
241
|
+
logger.debug("No project match found", {
|
|
242
|
+
eventId: event.id.slice(0, 8),
|
|
243
|
+
reason,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
projectId: null,
|
|
248
|
+
method: "none",
|
|
249
|
+
matchedTags: [],
|
|
250
|
+
reason,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Route event based on `a` tags (explicit project references)
|
|
256
|
+
*/
|
|
257
|
+
private static routeByATag(
|
|
258
|
+
event: NDKEvent,
|
|
259
|
+
knownProjects: Map<string, NDKProject>
|
|
260
|
+
): RoutingDecision | null {
|
|
261
|
+
// NIP-33 addressable events use lowercase 'a' tags only
|
|
262
|
+
const aTags = event.tags.filter((t) => t[0] === "a");
|
|
263
|
+
const projectATags = aTags.filter((t) => t[1]?.startsWith("31933:"));
|
|
264
|
+
|
|
265
|
+
logger.debug("Checking a-tags for project routing", {
|
|
266
|
+
eventId: event.id.slice(0, 8),
|
|
267
|
+
aTagsFound: projectATags.length,
|
|
268
|
+
aTags: projectATags.map((t) => t[1]),
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
for (const tag of projectATags) {
|
|
272
|
+
const aTagValue = tag[1];
|
|
273
|
+
if (aTagValue && knownProjects.has(aTagValue)) {
|
|
274
|
+
const project = knownProjects.get(aTagValue);
|
|
275
|
+
if (!project) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
`Project ${aTagValue} not found in knownProjects despite has() check`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
logger.info("Routing event to project via a-tag", {
|
|
282
|
+
eventId: event.id.slice(0, 8),
|
|
283
|
+
eventKind: event.kind,
|
|
284
|
+
projectId: aTagValue,
|
|
285
|
+
projectTitle: project.tagValue("title"),
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
projectId: aTagValue,
|
|
290
|
+
method: "a_tag",
|
|
291
|
+
matchedTags: [aTagValue],
|
|
292
|
+
reason: `Matched project a-tag: ${aTagValue}`,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (projectATags.length > 0) {
|
|
298
|
+
logger.debug("A-tags found but no matching known projects", {
|
|
299
|
+
eventId: event.id.slice(0, 8),
|
|
300
|
+
projectATags: projectATags.map((t) => t[1]),
|
|
301
|
+
knownProjects: Array.from(knownProjects.keys()),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Route event based on P-tags (agent pubkey references)
|
|
310
|
+
*
|
|
311
|
+
* IMPORTANT: P-tag routing is fallback behavior when A-tag routing fails.
|
|
312
|
+
* When an agent exists in multiple projects, we ONLY route via P-tag if
|
|
313
|
+
* exactly one of those projects has an active runtime. This prevents
|
|
314
|
+
* cross-project routing bugs where an event intended for project A gets
|
|
315
|
+
* routed to project B because B happened to be running.
|
|
316
|
+
*/
|
|
317
|
+
private static routeByPTag(
|
|
318
|
+
event: NDKEvent,
|
|
319
|
+
knownProjects: Map<string, NDKProject>,
|
|
320
|
+
agentPubkeyToProjects: Map<Hexpubkey, Set<string>>,
|
|
321
|
+
activeRuntimes: Map<string, ProjectRuntime>
|
|
322
|
+
): RoutingDecision | null {
|
|
323
|
+
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
324
|
+
|
|
325
|
+
logger.debug("Checking P-tags for agent routing", {
|
|
326
|
+
eventId: event.id.slice(0, 8),
|
|
327
|
+
pTagsFound: pTags.length,
|
|
328
|
+
pTags: pTags.map((t) => t[1]?.slice(0, 8)),
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
for (const tag of pTags) {
|
|
332
|
+
const pubkey = tag[1];
|
|
333
|
+
if (!pubkey) {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Check if this pubkey belongs to any project's agents
|
|
338
|
+
const projectIds = agentPubkeyToProjects.get(pubkey as Hexpubkey);
|
|
339
|
+
if (!projectIds || projectIds.size === 0) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Find which of this agent's projects have active runtimes
|
|
344
|
+
const activeProjectsForAgent: Array<{
|
|
345
|
+
projectId: string;
|
|
346
|
+
project: NDKProject;
|
|
347
|
+
runtime: ProjectRuntime;
|
|
348
|
+
agent: { slug: string; pubkey: string };
|
|
349
|
+
}> = [];
|
|
350
|
+
|
|
351
|
+
for (const projectId of projectIds) {
|
|
352
|
+
const runtime = activeRuntimes.get(projectId);
|
|
353
|
+
if (!runtime) {
|
|
354
|
+
continue; // Project not running - skip
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const project = knownProjects.get(projectId);
|
|
358
|
+
if (!project) {
|
|
359
|
+
logger.warn("routeByPTag: project in agentPubkeyToProjects but not in knownProjects", {
|
|
360
|
+
projectId: projectId.slice(0, 20),
|
|
361
|
+
agentPubkey: pubkey.slice(0, 8),
|
|
362
|
+
});
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const context = runtime.getContext();
|
|
367
|
+
if (!context) {
|
|
368
|
+
logger.warn("routeByPTag: runtime has no context", {
|
|
369
|
+
projectId: projectId.slice(0, 20),
|
|
370
|
+
});
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const agent = context.agentRegistry.getAllAgents().find((a) => a.pubkey === pubkey);
|
|
375
|
+
if (!agent) {
|
|
376
|
+
// Agent might have been removed from this project after mapping was created
|
|
377
|
+
logger.debug("routeByPTag: agent not found in project registry", {
|
|
378
|
+
projectId: projectId.slice(0, 20),
|
|
379
|
+
agentPubkey: pubkey.slice(0, 8),
|
|
380
|
+
});
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
activeProjectsForAgent.push({ projectId, project, runtime, agent });
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// If no active projects found for this agent, skip to next P-tag
|
|
388
|
+
if (activeProjectsForAgent.length === 0) {
|
|
389
|
+
logger.debug("routeByPTag: no active projects for agent", {
|
|
390
|
+
agentPubkey: pubkey.slice(0, 8),
|
|
391
|
+
knownProjectCount: projectIds.size,
|
|
392
|
+
});
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// CRITICAL: Only route via P-tag if there's exactly ONE active project
|
|
397
|
+
// If multiple projects are active with this agent, we can't determine
|
|
398
|
+
// the correct target - the event should have used an A-tag for disambiguation
|
|
399
|
+
if (activeProjectsForAgent.length > 1) {
|
|
400
|
+
logger.warn("routeByPTag: agent exists in multiple active projects - cannot disambiguate without A-tag", {
|
|
401
|
+
eventId: event.id?.slice(0, 8),
|
|
402
|
+
agentPubkey: pubkey.slice(0, 8),
|
|
403
|
+
activeProjects: activeProjectsForAgent.map(p => ({
|
|
404
|
+
projectId: p.projectId.slice(0, 20),
|
|
405
|
+
projectTitle: p.project.tagValue("title"),
|
|
406
|
+
})),
|
|
407
|
+
});
|
|
408
|
+
// Return null to indicate we couldn't route definitively
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Exactly one active project - safe to route
|
|
413
|
+
const { projectId, project, agent } = activeProjectsForAgent[0];
|
|
414
|
+
|
|
415
|
+
logger.info("Routing event to project via agent P-tag", {
|
|
416
|
+
eventId: event.id.slice(0, 8),
|
|
417
|
+
eventKind: event.kind,
|
|
418
|
+
projectId,
|
|
419
|
+
projectTitle: project.tagValue("title"),
|
|
420
|
+
agentPubkey: pubkey.slice(0, 8),
|
|
421
|
+
agentSlug: agent.slug,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
return {
|
|
425
|
+
projectId,
|
|
426
|
+
method: "p_tag_agent",
|
|
427
|
+
matchedTags: [pubkey],
|
|
428
|
+
reason: `Matched agent P-tag: ${pubkey.slice(0, 8)}`,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Check if an event was published by an agent in the system
|
|
437
|
+
* @param event - The event to check
|
|
438
|
+
* @param agentPubkeyToProjects - Map of agent pubkeys to their projects
|
|
439
|
+
* @returns True if the event author is a known agent
|
|
440
|
+
*/
|
|
441
|
+
static isAgentEvent(
|
|
442
|
+
event: NDKEvent,
|
|
443
|
+
agentPubkeyToProjects: Map<Hexpubkey, Set<string>>
|
|
444
|
+
): boolean {
|
|
445
|
+
return agentPubkeyToProjects.has(event.pubkey);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Check if an event has p-tags pointing to system entities (whitelisted pubkeys or other agents)
|
|
450
|
+
* @param event - The event to check
|
|
451
|
+
* @param whitelistedPubkeys - Set of whitelisted user pubkeys
|
|
452
|
+
* @param agentPubkeyToProjects - Map of agent pubkeys to their projects
|
|
453
|
+
* @returns True if the event has p-tags to system entities
|
|
454
|
+
*/
|
|
455
|
+
static hasPTagsToSystemEntities(
|
|
456
|
+
event: NDKEvent,
|
|
457
|
+
whitelistedPubkeys: Hexpubkey[],
|
|
458
|
+
agentPubkeyToProjects: Map<Hexpubkey, Set<string>>
|
|
459
|
+
): boolean {
|
|
460
|
+
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
461
|
+
|
|
462
|
+
for (const tag of pTags) {
|
|
463
|
+
const pubkey = tag[1];
|
|
464
|
+
if (!pubkey) {
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Check if p-tag points to a whitelisted pubkey
|
|
469
|
+
if (whitelistedPubkeys.includes(pubkey as Hexpubkey)) {
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Check if p-tag points to another agent in the system
|
|
474
|
+
if (agentPubkeyToProjects.has(pubkey as Hexpubkey)) {
|
|
475
|
+
return true;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Build project ID from event
|
|
484
|
+
* Format: "31933:authorPubkey:dTag"
|
|
485
|
+
* @param event - Project event (kind 31933)
|
|
486
|
+
* @returns Project ID string
|
|
487
|
+
*/
|
|
488
|
+
static buildProjectId(event: NDKEvent): string {
|
|
489
|
+
return event.tagId();
|
|
490
|
+
}
|
|
491
|
+
}
|