@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,161 @@
|
|
|
1
|
+
import type { ToolExecutionContext } from "@/tools/types";
|
|
2
|
+
import type { AISdkTool } from "@/tools/types";
|
|
3
|
+
import { type ToolResponse, createExpectedError } from "@/tools/utils";
|
|
4
|
+
import { extractAgentMcpServers } from "@/prompts/fragments/26-mcp-resources";
|
|
5
|
+
import { getProjectContext } from "@/services/projects";
|
|
6
|
+
import { tool } from "ai";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Schema for reading an MCP resource
|
|
11
|
+
*/
|
|
12
|
+
const mcpResourceReadSchema = z.object({
|
|
13
|
+
serverName: z.string().describe('MCP server name (e.g., "nostr-provider")'),
|
|
14
|
+
resourceUri: z.string().describe('Resource URI to read (e.g., "file:///path/to/file")'),
|
|
15
|
+
templateParams: z
|
|
16
|
+
.record(z.string(), z.string())
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Parameters for template expansion (e.g., {"pubkey": "abc123"})'),
|
|
19
|
+
description: z.string().describe("Why you are reading this resource"),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Expand a resource URI template with parameters.
|
|
24
|
+
* Replaces {param} placeholders with actual values.
|
|
25
|
+
*/
|
|
26
|
+
function expandUriTemplate(uriTemplate: string, params: Record<string, string>): string {
|
|
27
|
+
let expandedUri = uriTemplate;
|
|
28
|
+
for (const [key, value] of Object.entries(params)) {
|
|
29
|
+
expandedUri = expandedUri.replace(new RegExp(`\\{${key}\\}`, "g"), value);
|
|
30
|
+
}
|
|
31
|
+
return expandedUri;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Core implementation of reading an MCP resource
|
|
36
|
+
*/
|
|
37
|
+
async function executeReadResource(
|
|
38
|
+
input: z.infer<typeof mcpResourceReadSchema>,
|
|
39
|
+
context: ToolExecutionContext
|
|
40
|
+
): Promise<ToolResponse | ReturnType<typeof createExpectedError>> {
|
|
41
|
+
const { serverName, resourceUri, templateParams, description } = input;
|
|
42
|
+
|
|
43
|
+
// Get MCPManager from project context
|
|
44
|
+
const projectContext = getProjectContext();
|
|
45
|
+
const mcpManager = projectContext.mcpManager;
|
|
46
|
+
|
|
47
|
+
if (!mcpManager) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"MCP manager not available. This is a system error - MCP should be initialized."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Validate agent has access to this server
|
|
54
|
+
const agentMcpServers = extractAgentMcpServers(context.agent.tools);
|
|
55
|
+
|
|
56
|
+
if (!agentMcpServers.includes(serverName)) {
|
|
57
|
+
return createExpectedError(
|
|
58
|
+
`You do not have access to MCP server '${serverName}'. ` +
|
|
59
|
+
`You can only read resources from servers you have tools from. ` +
|
|
60
|
+
`Your accessible servers: ${agentMcpServers.length > 0 ? agentMcpServers.join(", ") : "none"}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check if server is running
|
|
65
|
+
const runningServers = mcpManager.getRunningServers();
|
|
66
|
+
if (!runningServers.includes(serverName)) {
|
|
67
|
+
return createExpectedError(
|
|
68
|
+
`MCP server '${serverName}' is not running. ` +
|
|
69
|
+
`Running servers: ${runningServers.length > 0 ? runningServers.join(", ") : "none"}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Expand template if params provided
|
|
74
|
+
const expandedUri = templateParams ? expandUriTemplate(resourceUri, templateParams) : resourceUri;
|
|
75
|
+
|
|
76
|
+
// Check if URI still has unfilled placeholders
|
|
77
|
+
if (expandedUri.includes("{") && expandedUri.includes("}")) {
|
|
78
|
+
return createExpectedError(
|
|
79
|
+
`Resource URI contains unfilled template parameters: ${expandedUri}. ` +
|
|
80
|
+
"Please provide all required parameters via templateParams."
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
// Read the resource
|
|
86
|
+
const result = await mcpManager.readResource(serverName, expandedUri);
|
|
87
|
+
|
|
88
|
+
// Format the content for return
|
|
89
|
+
const formattedContents: string[] = [];
|
|
90
|
+
|
|
91
|
+
for (const content of result.contents) {
|
|
92
|
+
if ("text" in content && typeof content.text === "string") {
|
|
93
|
+
formattedContents.push(content.text);
|
|
94
|
+
} else if ("blob" in content && typeof content.blob === "string") {
|
|
95
|
+
formattedContents.push(
|
|
96
|
+
`[Binary content: ${content.blob.length} bytes, MIME type: ${content.mimeType || "unknown"}]`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
success: true,
|
|
103
|
+
message: `Successfully read resource from MCP server '${serverName}'`,
|
|
104
|
+
resourceUri: expandedUri,
|
|
105
|
+
serverName,
|
|
106
|
+
description,
|
|
107
|
+
content: formattedContents.join("\n\n"),
|
|
108
|
+
mimeType: result.contents[0]?.mimeType,
|
|
109
|
+
};
|
|
110
|
+
} catch (error) {
|
|
111
|
+
// MCP resource not found or other expected errors
|
|
112
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
errorMessage.toLowerCase().includes("not found") ||
|
|
116
|
+
errorMessage.toLowerCase().includes("does not exist")
|
|
117
|
+
) {
|
|
118
|
+
return createExpectedError(
|
|
119
|
+
`Resource '${expandedUri}' not found on MCP server '${serverName}'. ` +
|
|
120
|
+
`Please verify the URI is correct.`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Other MCP errors - return as expected error (user-facing)
|
|
125
|
+
return createExpectedError(
|
|
126
|
+
`Failed to read resource '${expandedUri}' from MCP server '${serverName}': ${errorMessage}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Read content from an MCP resource on-demand.
|
|
133
|
+
*
|
|
134
|
+
* This tool provides immediate access to MCP resource content without setting up
|
|
135
|
+
* a persistent subscription. You can only read resources from MCP servers you have
|
|
136
|
+
* tools from (servers where you have mcp__serverName__* tools).
|
|
137
|
+
*
|
|
138
|
+
* Example use cases:
|
|
139
|
+
* - Read a configuration file from an MCP server
|
|
140
|
+
* - Fetch current state from a resource template
|
|
141
|
+
* - Access documentation or reference data
|
|
142
|
+
*
|
|
143
|
+
* For continuous updates, use rag_subscription_create instead.
|
|
144
|
+
*/
|
|
145
|
+
export function createMcpResourceReadTool(context: ToolExecutionContext): AISdkTool {
|
|
146
|
+
return tool({
|
|
147
|
+
description:
|
|
148
|
+
"Read content from an MCP resource. You can only read resources from MCP servers you have tools from.",
|
|
149
|
+
inputSchema: mcpResourceReadSchema,
|
|
150
|
+
execute: async (input) => {
|
|
151
|
+
const result = await executeReadResource(input, context);
|
|
152
|
+
|
|
153
|
+
// Handle expected error results
|
|
154
|
+
if (typeof result === "object" && "type" in result && result.type === "error-text") {
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return JSON.stringify(result, null, 2);
|
|
159
|
+
},
|
|
160
|
+
}) as AISdkTool;
|
|
161
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { ConversationToolContext } from "@/tools/types";
|
|
2
|
+
import type { AISdkTool } from "@/tools/types";
|
|
3
|
+
import { type ToolResponse, createExpectedError } from "@/tools/utils";
|
|
4
|
+
import { extractAgentMcpServers } from "@/prompts/fragments/26-mcp-resources";
|
|
5
|
+
import { getProjectContext } from "@/services/projects";
|
|
6
|
+
import { McpSubscriptionService } from "@/services/mcp/McpSubscriptionService";
|
|
7
|
+
import { tool } from "ai";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Schema for creating an MCP resource subscription
|
|
12
|
+
*/
|
|
13
|
+
const mcpSubscribeSchema = z.object({
|
|
14
|
+
serverName: z.string().describe('MCP server name (e.g., "nostr-provider")'),
|
|
15
|
+
resourceUri: z.string().describe('Resource URI to subscribe to (e.g., "nostr://feed/global")'),
|
|
16
|
+
description: z.string().describe("Human-readable description of what this subscription monitors"),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validate that a resource URI has a scheme and non-empty path.
|
|
21
|
+
* MCP resource URIs follow standard URI format (e.g., "nostr://feed/global", "file:///path").
|
|
22
|
+
*/
|
|
23
|
+
function isValidResourceUri(uri: string): boolean {
|
|
24
|
+
try {
|
|
25
|
+
// Check basic structure: must have a scheme (protocol) component
|
|
26
|
+
const schemeMatch = /^[a-zA-Z][a-zA-Z0-9+\-.]*:/.test(uri);
|
|
27
|
+
if (!schemeMatch) return false;
|
|
28
|
+
// Must have something after the scheme
|
|
29
|
+
const afterScheme = uri.indexOf(":") + 1;
|
|
30
|
+
return afterScheme < uri.length && uri.substring(afterScheme).trim().length > 0;
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Core implementation of MCP resource subscription
|
|
38
|
+
*/
|
|
39
|
+
async function executeSubscribe(
|
|
40
|
+
input: z.infer<typeof mcpSubscribeSchema>,
|
|
41
|
+
context: ConversationToolContext
|
|
42
|
+
): Promise<ToolResponse | ReturnType<typeof createExpectedError>> {
|
|
43
|
+
const { serverName, resourceUri, description } = input;
|
|
44
|
+
|
|
45
|
+
// Validate URI format upfront
|
|
46
|
+
if (!isValidResourceUri(resourceUri)) {
|
|
47
|
+
return createExpectedError(
|
|
48
|
+
`Invalid resource URI '${resourceUri}'. ` +
|
|
49
|
+
"Resource URIs must have a valid scheme (e.g., 'nostr://feed/global', 'file:///path')."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Get MCPManager from project context
|
|
54
|
+
const projectContext = getProjectContext();
|
|
55
|
+
const mcpManager = projectContext.mcpManager;
|
|
56
|
+
|
|
57
|
+
if (!mcpManager) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
"MCP manager not available. This is a system error - MCP should be initialized."
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Validate agent has access to this server
|
|
64
|
+
const agentMcpServers = extractAgentMcpServers(context.agent.tools);
|
|
65
|
+
|
|
66
|
+
if (!agentMcpServers.includes(serverName)) {
|
|
67
|
+
return createExpectedError(
|
|
68
|
+
`You do not have access to MCP server '${serverName}'. ` +
|
|
69
|
+
"You can only subscribe to resources from servers you have tools from. " +
|
|
70
|
+
`Your accessible servers: ${agentMcpServers.length > 0 ? agentMcpServers.join(", ") : "none"}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check if server is running
|
|
75
|
+
const runningServers = mcpManager.getRunningServers();
|
|
76
|
+
if (!runningServers.includes(serverName)) {
|
|
77
|
+
return createExpectedError(
|
|
78
|
+
`MCP server '${serverName}' is not running. ` +
|
|
79
|
+
`Running servers: ${runningServers.length > 0 ? runningServers.join(", ") : "none"}`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Get conversation details for subscription context
|
|
84
|
+
const conversationStore = context.conversationStore;
|
|
85
|
+
const rootEventId = conversationStore.getRootEventId();
|
|
86
|
+
|
|
87
|
+
if (!rootEventId) {
|
|
88
|
+
return createExpectedError(
|
|
89
|
+
"Cannot create subscription: conversation has no root event. " +
|
|
90
|
+
"This subscription must be created within an active conversation."
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const projectId = projectContext.project.tagId();
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const subscriptionService = McpSubscriptionService.getInstance();
|
|
98
|
+
|
|
99
|
+
const subscription = await subscriptionService.createSubscription({
|
|
100
|
+
agentPubkey: context.agent.pubkey,
|
|
101
|
+
agentSlug: context.agent.slug,
|
|
102
|
+
serverName,
|
|
103
|
+
resourceUri,
|
|
104
|
+
conversationId: context.conversationId,
|
|
105
|
+
rootEventId,
|
|
106
|
+
projectId,
|
|
107
|
+
description,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
success: true,
|
|
112
|
+
message: `Successfully created MCP subscription '${subscription.id}'`,
|
|
113
|
+
subscription: {
|
|
114
|
+
id: subscription.id,
|
|
115
|
+
serverName: subscription.serverName,
|
|
116
|
+
resourceUri: subscription.resourceUri,
|
|
117
|
+
conversationId: subscription.conversationId,
|
|
118
|
+
status: subscription.status,
|
|
119
|
+
description: subscription.description,
|
|
120
|
+
},
|
|
121
|
+
hint: `Use mcp_subscription_stop('${subscription.id}') to cancel this subscription.`,
|
|
122
|
+
};
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
125
|
+
return createExpectedError(
|
|
126
|
+
`Failed to create MCP subscription: ${errorMessage}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Subscribe to MCP resource notifications within the current conversation.
|
|
133
|
+
*
|
|
134
|
+
* When the subscribed resource is updated, a notification will be delivered
|
|
135
|
+
* as a system-reminder message in this conversation, triggering a new
|
|
136
|
+
* agent execution to handle the update.
|
|
137
|
+
*
|
|
138
|
+
* Subscriptions persist across system restarts.
|
|
139
|
+
*/
|
|
140
|
+
export function createMcpSubscribeTool(context: ConversationToolContext): AISdkTool {
|
|
141
|
+
return tool({
|
|
142
|
+
description:
|
|
143
|
+
"Subscribe to MCP resource update notifications. When the resource changes, " +
|
|
144
|
+
"a notification will be delivered to this conversation. " +
|
|
145
|
+
"You can only subscribe to resources from MCP servers you have tools from. " +
|
|
146
|
+
"Subscriptions persist across restarts.",
|
|
147
|
+
inputSchema: mcpSubscribeSchema,
|
|
148
|
+
execute: async (input) => {
|
|
149
|
+
const result = await executeSubscribe(input, context);
|
|
150
|
+
|
|
151
|
+
if (typeof result === "object" && "type" in result && result.type === "error-text") {
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return JSON.stringify(result, null, 2);
|
|
156
|
+
},
|
|
157
|
+
}) as AISdkTool;
|
|
158
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ToolExecutionContext } from "@/tools/types";
|
|
2
|
+
import type { AISdkTool } from "@/tools/types";
|
|
3
|
+
import { type ToolResponse, createExpectedError } from "@/tools/utils";
|
|
4
|
+
import { McpSubscriptionService } from "@/services/mcp/McpSubscriptionService";
|
|
5
|
+
import { tool } from "ai";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Schema for stopping an MCP subscription
|
|
10
|
+
*/
|
|
11
|
+
const mcpSubscriptionStopSchema = z.object({
|
|
12
|
+
subscriptionId: z.string().describe("The subscription ID to stop (returned by mcp_subscribe)"),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Core implementation of stopping an MCP subscription
|
|
17
|
+
*/
|
|
18
|
+
async function executeStop(
|
|
19
|
+
input: z.infer<typeof mcpSubscriptionStopSchema>,
|
|
20
|
+
context: ToolExecutionContext
|
|
21
|
+
): Promise<ToolResponse | ReturnType<typeof createExpectedError>> {
|
|
22
|
+
const { subscriptionId } = input;
|
|
23
|
+
|
|
24
|
+
const subscriptionService = McpSubscriptionService.getInstance();
|
|
25
|
+
const subscription = subscriptionService.getSubscription(subscriptionId);
|
|
26
|
+
|
|
27
|
+
if (!subscription) {
|
|
28
|
+
return createExpectedError(
|
|
29
|
+
`Subscription '${subscriptionId}' not found. ` +
|
|
30
|
+
"Please verify the subscription ID is correct."
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Authorization: only the agent that created the subscription can stop it
|
|
35
|
+
if (subscription.agentPubkey !== context.agent.pubkey) {
|
|
36
|
+
return createExpectedError(
|
|
37
|
+
`You are not authorized to stop subscription '${subscriptionId}'. ` +
|
|
38
|
+
"Only the agent that created the subscription can stop it."
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const success = await subscriptionService.stopSubscription(subscriptionId, context.agent.pubkey);
|
|
43
|
+
|
|
44
|
+
if (!success) {
|
|
45
|
+
return createExpectedError(
|
|
46
|
+
`Failed to stop subscription '${subscriptionId}'.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
message: `Successfully stopped MCP subscription '${subscriptionId}'`,
|
|
53
|
+
subscription: {
|
|
54
|
+
id: subscription.id,
|
|
55
|
+
serverName: subscription.serverName,
|
|
56
|
+
resourceUri: subscription.resourceUri,
|
|
57
|
+
notificationsReceived: subscription.notificationsReceived,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Stop an active MCP resource subscription.
|
|
64
|
+
*
|
|
65
|
+
* This cancels the subscription and cleans up all persisted state.
|
|
66
|
+
* The subscription will no longer deliver notifications.
|
|
67
|
+
*/
|
|
68
|
+
export function createMcpSubscriptionStopTool(context: ToolExecutionContext): AISdkTool {
|
|
69
|
+
return tool({
|
|
70
|
+
description:
|
|
71
|
+
"Stop an active MCP resource subscription. " +
|
|
72
|
+
"Cancels the subscription and removes persisted state. " +
|
|
73
|
+
"No more notifications will be delivered.",
|
|
74
|
+
inputSchema: mcpSubscriptionStopSchema,
|
|
75
|
+
execute: async (input) => {
|
|
76
|
+
const result = await executeStop(input, context);
|
|
77
|
+
|
|
78
|
+
if (typeof result === "object" && "type" in result && result.type === "error-text") {
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return JSON.stringify(result, null, 2);
|
|
83
|
+
},
|
|
84
|
+
}) as AISdkTool;
|
|
85
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nostr Fetch Tool
|
|
3
|
+
*
|
|
4
|
+
* Fetches any nostr event by ID and returns formatted or raw output.
|
|
5
|
+
* Supports various ID formats: nevent, note, naddr, hex, with or without "nostr:" prefix.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ToolExecutionContext } from "@/tools/types";
|
|
9
|
+
import { getNDK } from "@/nostr";
|
|
10
|
+
import { getPubkeyService } from "@/services/PubkeyService";
|
|
11
|
+
import type { AISdkTool } from "@/tools/types";
|
|
12
|
+
import { createExpectedError, isExpectedNotFoundError } from "@/tools/utils";
|
|
13
|
+
import { logger } from "@/utils/logger";
|
|
14
|
+
import { parseNostrEvent } from "@/utils/nostr-entity-parser";
|
|
15
|
+
import { tool } from "ai";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Schema for nostr_fetch tool input
|
|
20
|
+
*/
|
|
21
|
+
const nostrFetchSchema = z.object({
|
|
22
|
+
eventId: z
|
|
23
|
+
.string()
|
|
24
|
+
.describe(
|
|
25
|
+
"The event ID to fetch. Supports nevent, note, naddr, hex format, with or without 'nostr:' prefix"
|
|
26
|
+
),
|
|
27
|
+
format: z
|
|
28
|
+
.enum(["raw", "display"])
|
|
29
|
+
.default("display")
|
|
30
|
+
.describe(
|
|
31
|
+
"Output format: 'raw' returns the raw event JSON, 'display' returns human-readable format"
|
|
32
|
+
),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
type NostrFetchInput = z.infer<typeof nostrFetchSchema>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Format a tag for display
|
|
39
|
+
*/
|
|
40
|
+
function formatTag(tag: string[]): string {
|
|
41
|
+
if (tag.length === 0) return "";
|
|
42
|
+
if (tag.length === 1) return tag[0];
|
|
43
|
+
return `${tag[0]}=${tag.slice(1).join(",")}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Format timestamp to human-readable string
|
|
48
|
+
*/
|
|
49
|
+
function formatTimestamp(unixTimestamp: number): string {
|
|
50
|
+
const date = new Date(unixTimestamp * 1000);
|
|
51
|
+
return date
|
|
52
|
+
.toISOString()
|
|
53
|
+
.replace("T", " ")
|
|
54
|
+
.replace(/\.\d{3}Z$/, " UTC");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Execute the nostr_fetch tool
|
|
59
|
+
* Returns null if event is not found (expected condition)
|
|
60
|
+
*/
|
|
61
|
+
async function executeNostrFetch(input: NostrFetchInput): Promise<string | null> {
|
|
62
|
+
const { eventId, format } = input;
|
|
63
|
+
|
|
64
|
+
const ndk = getNDK();
|
|
65
|
+
|
|
66
|
+
// Use the existing parseNostrEvent utility which handles all formats
|
|
67
|
+
const event = await parseNostrEvent(eventId, ndk);
|
|
68
|
+
|
|
69
|
+
if (!event) {
|
|
70
|
+
// "Event not found" is an expected condition - return null to signal expected error
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Return raw event JSON if requested
|
|
75
|
+
if (format === "raw") {
|
|
76
|
+
return JSON.stringify(event.rawEvent(), null, 2);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Build display format
|
|
80
|
+
const pubkeyService = getPubkeyService();
|
|
81
|
+
const authorName = await pubkeyService.getName(event.pubkey);
|
|
82
|
+
const timestamp = formatTimestamp(event.created_at || 0);
|
|
83
|
+
|
|
84
|
+
// Format tags with bullet points
|
|
85
|
+
const tagsSection =
|
|
86
|
+
event.tags.length > 0
|
|
87
|
+
? `tags:\n${event.tags.map((tag) => ` * ${formatTag(tag)}`).join("\n")}`
|
|
88
|
+
: "tags: (none)";
|
|
89
|
+
|
|
90
|
+
const displayOutput = [
|
|
91
|
+
`Event ID: ${event.id}`,
|
|
92
|
+
`kind: ${event.kind}`,
|
|
93
|
+
`author: @${authorName}`,
|
|
94
|
+
`timestamp: ${timestamp}`,
|
|
95
|
+
"",
|
|
96
|
+
event.content,
|
|
97
|
+
"",
|
|
98
|
+
tagsSection,
|
|
99
|
+
].join("\n");
|
|
100
|
+
|
|
101
|
+
return displayOutput;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Create the nostr_fetch AI SDK tool
|
|
106
|
+
*/
|
|
107
|
+
export function createNostrFetchTool(_context: ToolExecutionContext): AISdkTool {
|
|
108
|
+
const toolInstance = tool({
|
|
109
|
+
description:
|
|
110
|
+
"Fetches any nostr event by ID. Supports nevent, note, naddr, hex format, " +
|
|
111
|
+
"with or without 'nostr:' prefix. Returns either raw JSON or a human-readable display format.",
|
|
112
|
+
|
|
113
|
+
inputSchema: nostrFetchSchema,
|
|
114
|
+
|
|
115
|
+
execute: async (input: NostrFetchInput) => {
|
|
116
|
+
try {
|
|
117
|
+
const result = await executeNostrFetch(input);
|
|
118
|
+
|
|
119
|
+
// "Event not found" is an expected condition - return error-text
|
|
120
|
+
if (result === null) {
|
|
121
|
+
return createExpectedError(`Event not found: ${input.eventId}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return result;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
// Check if this is an expected "not found" error from a different code path
|
|
127
|
+
if (isExpectedNotFoundError(error)) {
|
|
128
|
+
return createExpectedError(`Event not found: ${input.eventId}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
logger.error("Failed to fetch nostr event", { eventId: input.eventId, error });
|
|
132
|
+
throw new Error(
|
|
133
|
+
`Failed to fetch nostr event: ${error instanceof Error ? error.message : String(error)}`,
|
|
134
|
+
{ cause: error }
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
Object.defineProperty(toolInstance, "getHumanReadableContent", {
|
|
141
|
+
value: ({ eventId, format }: NostrFetchInput) => {
|
|
142
|
+
return `Fetching nostr event ${eventId} (format: ${format || "display"})`;
|
|
143
|
+
},
|
|
144
|
+
enumerable: false,
|
|
145
|
+
configurable: true,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
return toolInstance as AISdkTool;
|
|
149
|
+
}
|