@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,166 @@
|
|
|
1
|
+
import type { AISdkTool, ToolExecutionContext } from "@/tools/types";
|
|
2
|
+
import type { EventContext, LessonIntent } from "@/nostr/types";
|
|
3
|
+
import { getProjectContext, isProjectContextInitialized } from "@/services/projects";
|
|
4
|
+
import { RAGService } from "@/services/rag/RAGService";
|
|
5
|
+
import { logger } from "@/utils/logger";
|
|
6
|
+
import { tool } from "ai";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
9
|
+
const lessonLearnSchema = z.object({
|
|
10
|
+
title: z.string().describe("Brief title/description of what this lesson is about"),
|
|
11
|
+
lesson: z.string().describe("The key insight or lesson learned - be concise and actionable"),
|
|
12
|
+
detailed: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("Detailed version with richer explanation when deeper context is needed"),
|
|
16
|
+
category: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe(
|
|
20
|
+
"Single category for filing this lesson (e.g., 'architecture', 'debugging', 'user-preferences')"
|
|
21
|
+
),
|
|
22
|
+
hashtags: z
|
|
23
|
+
.array(z.string())
|
|
24
|
+
.default([])
|
|
25
|
+
.describe("Hashtags for easier sorting and discovery (e.g., ['async', 'error-handling'])"),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
type LessonLearnInput = z.infer<typeof lessonLearnSchema>;
|
|
29
|
+
type LessonLearnOutput = {
|
|
30
|
+
message: string;
|
|
31
|
+
eventId: string;
|
|
32
|
+
title: string;
|
|
33
|
+
hasDetailed: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Core implementation - extracted from existing execute function
|
|
37
|
+
async function executeLessonLearn(
|
|
38
|
+
input: LessonLearnInput,
|
|
39
|
+
context: ToolExecutionContext
|
|
40
|
+
): Promise<LessonLearnOutput> {
|
|
41
|
+
const { title, lesson, detailed, category, hashtags } = input;
|
|
42
|
+
|
|
43
|
+
logger.info("Agent recording new lesson", {
|
|
44
|
+
agent: context.agent.name,
|
|
45
|
+
agentPubkey: context.agent.pubkey,
|
|
46
|
+
title,
|
|
47
|
+
lessonLength: lesson.length,
|
|
48
|
+
conversationId: context.conversationId,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Create lesson intent
|
|
52
|
+
const intent: LessonIntent = {
|
|
53
|
+
title,
|
|
54
|
+
lesson,
|
|
55
|
+
detailed,
|
|
56
|
+
category,
|
|
57
|
+
hashtags,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Create event context
|
|
61
|
+
// Note: encodeLesson only uses addStandardTags which needs model/ralNumber
|
|
62
|
+
// rootEvent.id is not used by lesson encoding
|
|
63
|
+
const eventContext: EventContext = {
|
|
64
|
+
triggeringEvent: context.triggeringEvent,
|
|
65
|
+
rootEvent: {},
|
|
66
|
+
conversationId: context.conversationId,
|
|
67
|
+
model: context.agent.llmConfig,
|
|
68
|
+
ralNumber: context.ralNumber,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Use shared AgentPublisher instance from context to create and publish the lesson
|
|
72
|
+
const lessonEvent = await context.agentPublisher.lesson(intent, eventContext);
|
|
73
|
+
|
|
74
|
+
// Add lesson to RAG collection for semantic search
|
|
75
|
+
try {
|
|
76
|
+
const ragService = RAGService.getInstance();
|
|
77
|
+
|
|
78
|
+
// Ensure the lessons collection exists
|
|
79
|
+
try {
|
|
80
|
+
await ragService.createCollection("lessons");
|
|
81
|
+
} catch (error) {
|
|
82
|
+
// Collection might already exist, which is fine
|
|
83
|
+
logger.debug("Lessons collection might already exist", { error });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Add the lesson to the RAG collection
|
|
87
|
+
const lessonContent = detailed || lesson;
|
|
88
|
+
|
|
89
|
+
// Get projectId for project-scoped search isolation
|
|
90
|
+
let projectId: string | undefined;
|
|
91
|
+
if (isProjectContextInitialized()) {
|
|
92
|
+
try {
|
|
93
|
+
projectId = getProjectContext().project.tagId();
|
|
94
|
+
} catch {
|
|
95
|
+
// Project context not available - lesson will lack project scoping
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await ragService.addDocuments("lessons", [
|
|
100
|
+
{
|
|
101
|
+
id: lessonEvent.encode(),
|
|
102
|
+
content: lessonContent,
|
|
103
|
+
metadata: {
|
|
104
|
+
title,
|
|
105
|
+
category,
|
|
106
|
+
hashtags: hashtags.length > 0 ? hashtags : undefined,
|
|
107
|
+
agentPubkey: context.agent.pubkey,
|
|
108
|
+
agentName: context.agent.name,
|
|
109
|
+
timestamp: Date.now(),
|
|
110
|
+
hasDetailed: !!detailed,
|
|
111
|
+
type: "lesson",
|
|
112
|
+
...(projectId && { projectId }),
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
logger.info("Lesson added to RAG collection", {
|
|
118
|
+
title,
|
|
119
|
+
eventId: lessonEvent.encode(),
|
|
120
|
+
agentName: context.agent.name,
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
// Don't fail the tool if RAG integration fails
|
|
124
|
+
logger.warn("Failed to add lesson to RAG collection", { error, title });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const message = `Lesson recorded: "${title}"${detailed ? " (with detailed version)" : ""}\n\nThis lesson will be available in future conversations to help avoid similar issues.`;
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
message,
|
|
131
|
+
eventId: lessonEvent.encode(),
|
|
132
|
+
title,
|
|
133
|
+
hasDetailed: !!detailed,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// AI SDK tool factory
|
|
138
|
+
export function createLessonLearnTool(context: ToolExecutionContext): AISdkTool {
|
|
139
|
+
return tool({
|
|
140
|
+
description: `Record new lessons and insights for future reference. Use for content ABOUT YOUR BEHAVIOR, such as:
|
|
141
|
+
- Patterns in how you approach tasks
|
|
142
|
+
- Debugging workflows that work well
|
|
143
|
+
- User preferences and communication styles
|
|
144
|
+
- Behavioral adjustments when user requests changes
|
|
145
|
+
- Performance patterns in your tool usage
|
|
146
|
+
- Things to do differently in future work
|
|
147
|
+
|
|
148
|
+
Use when the user instructs you to remember something about YOUR BEHAVIOR or PREFERENCES, or when the user instructs you to change some behavior. Lessons persist across conversations and help build institutional memory. Include both concise lesson and detailed explanation when complexity warrants it. Categorize and tag appropriately for future discovery. Lessons become immediately available via lesson_get.
|
|
149
|
+
|
|
150
|
+
**CRITICAL:** Only use this for content ABOUT YOUR BEHAVIOR. For content about the project itself, use report_write instead.
|
|
151
|
+
|
|
152
|
+
**NEVER use for:**
|
|
153
|
+
- Project conventions or patterns
|
|
154
|
+
- Architecture documentation
|
|
155
|
+
- Technical specifications
|
|
156
|
+
- Design decisions
|
|
157
|
+
- API documentation
|
|
158
|
+
- Any content that would help others understand the project
|
|
159
|
+
|
|
160
|
+
See also: report_write (for project documentation)`,
|
|
161
|
+
inputSchema: lessonLearnSchema,
|
|
162
|
+
execute: async (input: LessonLearnInput) => {
|
|
163
|
+
return await executeLessonLearn(input, context);
|
|
164
|
+
},
|
|
165
|
+
}) as AISdkTool;
|
|
166
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { NDKAgentLesson } from "@/events/NDKAgentLesson";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Standard output shape for lesson retrieval operations.
|
|
5
|
+
* Consolidates the lesson data structure to avoid duplication between lesson_get and lessons_list.
|
|
6
|
+
*/
|
|
7
|
+
export type FormattedLessonOutput = {
|
|
8
|
+
eventId: string;
|
|
9
|
+
title: string;
|
|
10
|
+
lesson: string;
|
|
11
|
+
detailed?: string;
|
|
12
|
+
category?: string;
|
|
13
|
+
hashtags?: string[];
|
|
14
|
+
hasDetailed: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Formats a lesson into the standard output shape.
|
|
19
|
+
* Used by both lesson_get and lessons_list to ensure consistent formatting.
|
|
20
|
+
*
|
|
21
|
+
* @param lesson - The NDKAgentLesson to format
|
|
22
|
+
* @param eventId - The event ID (may differ from lesson.id if normalized)
|
|
23
|
+
* @returns Formatted lesson output
|
|
24
|
+
*/
|
|
25
|
+
export function formatLessonOutput(
|
|
26
|
+
lesson: NDKAgentLesson,
|
|
27
|
+
eventId: string
|
|
28
|
+
): FormattedLessonOutput {
|
|
29
|
+
return {
|
|
30
|
+
eventId,
|
|
31
|
+
title: lesson.title || "Untitled",
|
|
32
|
+
lesson: lesson.lesson || lesson.content,
|
|
33
|
+
detailed: lesson.detailed,
|
|
34
|
+
category: lesson.category,
|
|
35
|
+
hashtags: lesson.hashtags,
|
|
36
|
+
hasDetailed: !!lesson.detailed,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { AISdkTool, ToolExecutionContext } from "@/tools/types";
|
|
2
|
+
import { getProjectContext } from "@/services/projects";
|
|
3
|
+
import { RAGService } from "@/services/rag/RAGService";
|
|
4
|
+
import { createExpectedError } from "@/tools/utils";
|
|
5
|
+
import { logger } from "@/utils/logger";
|
|
6
|
+
import { normalizeLessonEventId } from "@/utils/nostr-entity-parser";
|
|
7
|
+
import { getNDK } from "@/nostr/ndkClient";
|
|
8
|
+
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
9
|
+
import { tool } from "ai";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
const lessonDeleteSchema = z.object({
|
|
13
|
+
eventId: z.string().describe(
|
|
14
|
+
"Nostr event ID of the lesson to delete. Supports full 64-char hex ID, 12-char hex prefix, or NIP-19 formats (note1.../nevent1...)."
|
|
15
|
+
),
|
|
16
|
+
reason: z.string().optional().describe(
|
|
17
|
+
"Optional reason for deleting the lesson"
|
|
18
|
+
),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
type LessonDeleteInput = z.infer<typeof lessonDeleteSchema>;
|
|
22
|
+
|
|
23
|
+
interface LessonDeleteOutput {
|
|
24
|
+
success: boolean;
|
|
25
|
+
eventId: string;
|
|
26
|
+
title: string;
|
|
27
|
+
message: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Type for expected error results
|
|
31
|
+
type LessonDeleteResult = LessonDeleteOutput | { type: "error-text"; text: string };
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Core implementation of lesson deletion functionality.
|
|
35
|
+
* Uses NIP-09 event deletion to mark the lesson as deleted.
|
|
36
|
+
*/
|
|
37
|
+
async function executeLessonDelete(
|
|
38
|
+
input: LessonDeleteInput,
|
|
39
|
+
context: ToolExecutionContext
|
|
40
|
+
): Promise<LessonDeleteResult> {
|
|
41
|
+
const { eventId: inputEventId, reason } = input;
|
|
42
|
+
|
|
43
|
+
const projectContext = getProjectContext();
|
|
44
|
+
|
|
45
|
+
// Get all lessons for normalization and lookup
|
|
46
|
+
const allLessons = projectContext.getAllLessons();
|
|
47
|
+
|
|
48
|
+
// Normalize the input to a canonical 64-char hex ID
|
|
49
|
+
const normalizeResult = normalizeLessonEventId(inputEventId, allLessons);
|
|
50
|
+
if (!normalizeResult.success) {
|
|
51
|
+
return createExpectedError(normalizeResult.error);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const eventId = normalizeResult.eventId;
|
|
55
|
+
|
|
56
|
+
logger.info("🗑️ Agent deleting lesson", {
|
|
57
|
+
agent: context.agent.name,
|
|
58
|
+
agentPubkey: context.agent.pubkey,
|
|
59
|
+
inputEventId,
|
|
60
|
+
resolvedEventId: eventId,
|
|
61
|
+
reason,
|
|
62
|
+
conversationId: context.conversationId,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Find the lesson by event ID - only allow deleting own lessons
|
|
66
|
+
const agentLessons = projectContext.getLessonsForAgent(context.agent.pubkey);
|
|
67
|
+
const lesson = agentLessons.find((l) => l.id === eventId);
|
|
68
|
+
|
|
69
|
+
if (!lesson) {
|
|
70
|
+
// Check if the lesson exists but belongs to another agent
|
|
71
|
+
const globalLesson = allLessons.find((l) => l.id === eventId);
|
|
72
|
+
if (globalLesson) {
|
|
73
|
+
return createExpectedError(
|
|
74
|
+
`Cannot delete lesson "${eventId}": You can only delete your own lessons.`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return createExpectedError(`No lesson found with event ID: "${eventId}"`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const lessonTitle = lesson.title || "Untitled";
|
|
81
|
+
|
|
82
|
+
// Create NIP-09 deletion event manually and sign with agent's signer
|
|
83
|
+
// We can't use lesson.delete() directly because the lesson's NDK instance
|
|
84
|
+
// doesn't have the agent's signer attached
|
|
85
|
+
const ndk = getNDK();
|
|
86
|
+
const deleteEvent = new NDKEvent(ndk);
|
|
87
|
+
deleteEvent.kind = 5; // NIP-09 deletion event kind
|
|
88
|
+
deleteEvent.tags = [["e", eventId]]; // Reference the event being deleted
|
|
89
|
+
deleteEvent.content = reason || "";
|
|
90
|
+
|
|
91
|
+
// Sign with the agent's signer and publish
|
|
92
|
+
// Per error handling contract: unexpected failures should throw
|
|
93
|
+
await context.agent.sign(deleteEvent);
|
|
94
|
+
await deleteEvent.publish();
|
|
95
|
+
|
|
96
|
+
logger.info("✅ Lesson deletion event published", {
|
|
97
|
+
agent: context.agent.name,
|
|
98
|
+
agentPubkey: context.agent.pubkey,
|
|
99
|
+
eventId,
|
|
100
|
+
title: lessonTitle,
|
|
101
|
+
reason,
|
|
102
|
+
conversationId: context.conversationId,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Remove from RAG collection
|
|
106
|
+
try {
|
|
107
|
+
const ragService = RAGService.getInstance();
|
|
108
|
+
await ragService.deleteDocumentById("lessons", lesson.encode());
|
|
109
|
+
|
|
110
|
+
logger.info("📚 Lesson removed from RAG collection", {
|
|
111
|
+
eventId,
|
|
112
|
+
title: lessonTitle,
|
|
113
|
+
agent: context.agent.name,
|
|
114
|
+
});
|
|
115
|
+
} catch (error) {
|
|
116
|
+
// Don't fail the tool if RAG cleanup fails - the lesson is already deleted
|
|
117
|
+
logger.warn("Failed to remove lesson from RAG collection", {
|
|
118
|
+
error,
|
|
119
|
+
eventId,
|
|
120
|
+
title: lessonTitle,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Remove from project context cache (also triggers prompt recompilation)
|
|
125
|
+
projectContext.removeLesson(context.agent.pubkey, eventId);
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
success: true,
|
|
129
|
+
eventId,
|
|
130
|
+
title: lessonTitle,
|
|
131
|
+
message: `Lesson "${lessonTitle}" has been deleted${reason ? ` (reason: ${reason})` : ""}.`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Create an AI SDK tool for deleting lessons
|
|
137
|
+
*/
|
|
138
|
+
export function createLessonDeleteTool(context: ToolExecutionContext): AISdkTool {
|
|
139
|
+
const aiTool = tool({
|
|
140
|
+
description:
|
|
141
|
+
"Delete a lesson by its Nostr event ID. This creates a deletion event (NIP-09) " +
|
|
142
|
+
"to mark the lesson as deleted. Only lessons created by the calling agent can be deleted.\n\n" +
|
|
143
|
+
"Supports multiple ID formats:\n" +
|
|
144
|
+
"- Full 64-character hex IDs\n" +
|
|
145
|
+
"- 12-character hex prefixes\n" +
|
|
146
|
+
"- NIP-19 formats: note1..., nevent1...\n" +
|
|
147
|
+
"- nostr: prefixed versions of all the above\n\n" +
|
|
148
|
+
"Use when a lesson is no longer relevant, contains outdated information, or was recorded in error.",
|
|
149
|
+
inputSchema: lessonDeleteSchema,
|
|
150
|
+
execute: async (input: LessonDeleteInput) => {
|
|
151
|
+
return await executeLessonDelete(input, context);
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
Object.defineProperty(aiTool, "getHumanReadableContent", {
|
|
156
|
+
value: ({ eventId }: LessonDeleteInput) => {
|
|
157
|
+
return `Deleting lesson: ${eventId}`;
|
|
158
|
+
},
|
|
159
|
+
enumerable: false,
|
|
160
|
+
configurable: true,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return aiTool as AISdkTool;
|
|
164
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { ToolExecutionContext } from "@/tools/types";
|
|
2
|
+
import { getProjectContext } from "@/services/projects";
|
|
3
|
+
import type { AISdkTool } from "@/tools/types";
|
|
4
|
+
import { createExpectedError } from "@/tools/utils";
|
|
5
|
+
import { logger } from "@/utils/logger";
|
|
6
|
+
import { normalizeLessonEventId } from "@/utils/nostr-entity-parser";
|
|
7
|
+
import { formatLessonOutput, type FormattedLessonOutput } from "./lesson-formatter";
|
|
8
|
+
import { tool } from "ai";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
|
|
11
|
+
const lessonGetSchema = z.object({
|
|
12
|
+
eventId: z.string().describe("Nostr event ID of the lesson to retrieve. Supports full 64-char hex ID, 12-char hex prefix, or NIP-19 formats (note1.../nevent1...)."),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
type LessonGetInput = z.infer<typeof lessonGetSchema>;
|
|
16
|
+
|
|
17
|
+
// Type for expected error results
|
|
18
|
+
type LessonGetResult = FormattedLessonOutput | { type: "error-text"; text: string };
|
|
19
|
+
|
|
20
|
+
// Core implementation - fetches lesson by event ID
|
|
21
|
+
// Returns error-text for expected "not found" conditions
|
|
22
|
+
async function executeLessonGet(
|
|
23
|
+
input: LessonGetInput,
|
|
24
|
+
context: ToolExecutionContext
|
|
25
|
+
): Promise<LessonGetResult> {
|
|
26
|
+
const { eventId: inputEventId } = input;
|
|
27
|
+
|
|
28
|
+
const projectContext = getProjectContext();
|
|
29
|
+
|
|
30
|
+
// Get all lessons upfront for both normalization fallback and lookup
|
|
31
|
+
const allLessons = projectContext.getAllLessons();
|
|
32
|
+
|
|
33
|
+
// Normalize the input to a canonical 64-char hex ID
|
|
34
|
+
// Supports: hex IDs, hex prefixes, note1..., nevent1..., nostr: prefixed versions
|
|
35
|
+
const normalizeResult = normalizeLessonEventId(inputEventId, allLessons);
|
|
36
|
+
if (!normalizeResult.success) {
|
|
37
|
+
// Invalid event ID format is an expected user error - return error-text
|
|
38
|
+
return createExpectedError(normalizeResult.error);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const eventId = normalizeResult.eventId;
|
|
42
|
+
|
|
43
|
+
logger.info("📖 Agent retrieving lesson by event ID", {
|
|
44
|
+
agent: context.agent.name,
|
|
45
|
+
agentPubkey: context.agent.pubkey,
|
|
46
|
+
inputEventId,
|
|
47
|
+
resolvedEventId: eventId,
|
|
48
|
+
conversationId: context.conversationId,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Find lesson by event ID - first try agent-specific, then global
|
|
52
|
+
const agentLessons = projectContext.getLessonsForAgent(context.agent.pubkey);
|
|
53
|
+
let lesson = agentLessons.find((l) => l.id === eventId);
|
|
54
|
+
let isGlobalMatch = false;
|
|
55
|
+
|
|
56
|
+
if (!lesson) {
|
|
57
|
+
// Fall back to global search (in case agent pubkey doesn't match exactly)
|
|
58
|
+
lesson = allLessons.find((l) => l.id === eventId);
|
|
59
|
+
isGlobalMatch = true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!lesson) {
|
|
63
|
+
// "Lesson not found" is an expected condition - return error-text
|
|
64
|
+
return createExpectedError(`No lesson found with event ID: "${eventId}"`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
logger.info("✅ Successfully retrieved lesson", {
|
|
68
|
+
agent: context.agent.name,
|
|
69
|
+
agentPubkey: context.agent.pubkey,
|
|
70
|
+
eventId,
|
|
71
|
+
title: lesson.title,
|
|
72
|
+
hasDetailed: !!lesson.detailed,
|
|
73
|
+
source: isGlobalMatch ? "global" : "agent",
|
|
74
|
+
conversationId: context.conversationId,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return formatLessonOutput(lesson, eventId);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// AI SDK tool factory
|
|
81
|
+
export function createLessonGetTool(context: ToolExecutionContext): AISdkTool {
|
|
82
|
+
const aiTool = tool({
|
|
83
|
+
description:
|
|
84
|
+
"Retrieve a lesson by its Nostr event ID. Supports multiple formats:\n" +
|
|
85
|
+
"- Full 64-character hex IDs\n" +
|
|
86
|
+
"- 12-character hex prefixes\n" +
|
|
87
|
+
"- NIP-19 formats: note1..., nevent1...\n" +
|
|
88
|
+
"- nostr: prefixed versions of all the above\n\n" +
|
|
89
|
+
"Returns full lesson content including detailed explanations if available. Use when you need to recall specific knowledge or patterns that have been previously documented.",
|
|
90
|
+
inputSchema: lessonGetSchema,
|
|
91
|
+
execute: async (input: LessonGetInput) => {
|
|
92
|
+
return await executeLessonGet(input, context);
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
Object.defineProperty(aiTool, "getHumanReadableContent", {
|
|
97
|
+
value: ({ eventId }: LessonGetInput) => {
|
|
98
|
+
return `Reading lesson: ${eventId}`;
|
|
99
|
+
},
|
|
100
|
+
enumerable: false,
|
|
101
|
+
configurable: true,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return aiTool as AISdkTool;
|
|
105
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { AISdkTool, ToolExecutionContext } from "@/tools/types";
|
|
2
|
+
import { getProjectContext } from "@/services/projects";
|
|
3
|
+
import { logger } from "@/utils/logger";
|
|
4
|
+
import { createExpectedError } from "@/tools/utils";
|
|
5
|
+
import { formatLessonOutput } from "./lesson-formatter";
|
|
6
|
+
import { tool } from "ai";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
9
|
+
const lessonsListSchema = z.object({
|
|
10
|
+
agentPubkey: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe(
|
|
14
|
+
"Optional agent pubkey to filter lessons by. If not provided, returns only your own lessons."
|
|
15
|
+
),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
type LessonsListInput = z.infer<typeof lessonsListSchema>;
|
|
19
|
+
|
|
20
|
+
type LessonSummary = {
|
|
21
|
+
eventId: string;
|
|
22
|
+
title: string;
|
|
23
|
+
lesson: string;
|
|
24
|
+
category?: string;
|
|
25
|
+
hashtags?: string[];
|
|
26
|
+
author: string; // Agent slug or pubkey fallback
|
|
27
|
+
hasDetailed: boolean;
|
|
28
|
+
createdAt?: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type LessonsListOutput = {
|
|
32
|
+
success: boolean;
|
|
33
|
+
lessons: LessonSummary[];
|
|
34
|
+
totalCount: number;
|
|
35
|
+
agentFilter?: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type LessonsListResult = LessonsListOutput | { type: "error-text"; text: string };
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Normalizes a pubkey string: trims whitespace and lowercases.
|
|
42
|
+
* Returns the normalized value, or undefined if input is empty/whitespace.
|
|
43
|
+
*/
|
|
44
|
+
function normalizePubkey(pubkey: string | undefined): string | undefined {
|
|
45
|
+
if (!pubkey) return undefined;
|
|
46
|
+
const trimmed = pubkey.trim();
|
|
47
|
+
if (trimmed === "") return undefined;
|
|
48
|
+
return trimmed.toLowerCase();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Validates that a string is a valid hex pubkey (64 hex characters).
|
|
53
|
+
* Returns null if valid, error message if invalid.
|
|
54
|
+
* Expects pre-normalized input (trimmed, lowercased).
|
|
55
|
+
*/
|
|
56
|
+
function validateAgentPubkey(pubkey: string, originalInput: string): string | null {
|
|
57
|
+
// Must be exactly 64 hex characters (already lowercased)
|
|
58
|
+
if (!/^[0-9a-f]{64}$/.test(pubkey)) {
|
|
59
|
+
return `Invalid agent pubkey format: "${originalInput}". Expected 64-character hex string`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Core implementation - list lessons for the project
|
|
67
|
+
*/
|
|
68
|
+
async function executeLessonsList(
|
|
69
|
+
input: LessonsListInput,
|
|
70
|
+
context: ToolExecutionContext
|
|
71
|
+
): Promise<LessonsListResult> {
|
|
72
|
+
const { agentPubkey } = input;
|
|
73
|
+
|
|
74
|
+
// Normalize the input pubkey once - trim whitespace and lowercase
|
|
75
|
+
const normalizedInputPubkey = normalizePubkey(agentPubkey);
|
|
76
|
+
|
|
77
|
+
// Validate agentPubkey if provided (after normalization)
|
|
78
|
+
if (agentPubkey !== undefined) {
|
|
79
|
+
// Check if normalization resulted in empty (whitespace-only input)
|
|
80
|
+
if (normalizedInputPubkey === undefined) {
|
|
81
|
+
return createExpectedError("Agent pubkey cannot be empty");
|
|
82
|
+
}
|
|
83
|
+
const validationError = validateAgentPubkey(normalizedInputPubkey, agentPubkey);
|
|
84
|
+
if (validationError) {
|
|
85
|
+
return createExpectedError(validationError);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Determine effective pubkey: use normalized input or default to calling agent
|
|
90
|
+
const effectivePubkey = normalizedInputPubkey ?? context.agent.pubkey;
|
|
91
|
+
|
|
92
|
+
logger.info("📚 Listing lessons", {
|
|
93
|
+
agent: context.agent.name,
|
|
94
|
+
agentFilter: effectivePubkey,
|
|
95
|
+
conversationId: context.conversationId,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const projectContext = getProjectContext();
|
|
99
|
+
|
|
100
|
+
// Get lessons based on filter
|
|
101
|
+
const rawLessons = projectContext.getLessonsForAgent(effectivePubkey);
|
|
102
|
+
|
|
103
|
+
// Transform lessons to summary format
|
|
104
|
+
const lessons: LessonSummary[] = rawLessons.map((lesson) => {
|
|
105
|
+
// Try to resolve author pubkey to agent slug (matching reports_list pattern)
|
|
106
|
+
const agent = projectContext.getAgentByPubkey(lesson.pubkey);
|
|
107
|
+
const authorSlug = agent?.slug ?? lesson.pubkey;
|
|
108
|
+
|
|
109
|
+
// Use shared formatter for consistent lesson formatting
|
|
110
|
+
const formatted = formatLessonOutput(lesson, lesson.id);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
...formatted,
|
|
114
|
+
author: authorSlug,
|
|
115
|
+
createdAt: lesson.created_at,
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Sort by creation date, most recent first
|
|
120
|
+
lessons.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
|
|
121
|
+
|
|
122
|
+
logger.info("✅ Lessons listed successfully", {
|
|
123
|
+
total: lessons.length,
|
|
124
|
+
agent: context.agent.name,
|
|
125
|
+
agentFilter: effectivePubkey,
|
|
126
|
+
conversationId: context.conversationId,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
success: true,
|
|
131
|
+
lessons,
|
|
132
|
+
totalCount: lessons.length,
|
|
133
|
+
agentFilter: effectivePubkey,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* AI SDK tool factory
|
|
139
|
+
*/
|
|
140
|
+
export function createLessonsListTool(context: ToolExecutionContext): AISdkTool {
|
|
141
|
+
return tool({
|
|
142
|
+
description:
|
|
143
|
+
"List lessons learned by agents in the project. Returns only your own lessons by default, " +
|
|
144
|
+
"including title, full lesson content, category, hashtags, and author (agent slug). " +
|
|
145
|
+
"Optionally filter by agent pubkey to see lessons from a specific agent. " +
|
|
146
|
+
"Results are sorted by creation date (most recent first). Use this to discover what lessons are available. " +
|
|
147
|
+
"For lessons with detailed explanations, use lesson_get to retrieve the full detailed content.",
|
|
148
|
+
inputSchema: lessonsListSchema,
|
|
149
|
+
execute: async (input: LessonsListInput) => {
|
|
150
|
+
return await executeLessonsList(input, context);
|
|
151
|
+
},
|
|
152
|
+
}) as AISdkTool;
|
|
153
|
+
}
|