@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,777 @@
|
|
|
1
|
+
import type { AgentInstance } from "@/agents/types";
|
|
2
|
+
import type { ConversationStore } from "@/conversations/ConversationStore";
|
|
3
|
+
import type { NDKAgentLesson } from "@/events/NDKAgentLesson";
|
|
4
|
+
import { PromptBuilder } from "@/prompts/core/PromptBuilder";
|
|
5
|
+
import type { MCPManager } from "@/services/mcp/MCPManager";
|
|
6
|
+
import type { NudgeToolPermissions, NudgeData, WhitelistItem } from "@/services/nudge";
|
|
7
|
+
import type { SkillData } from "@/services/skill";
|
|
8
|
+
import { PromptCompilerService, type LessonComment } from "@/services/prompt-compiler";
|
|
9
|
+
import { getNDK } from "@/nostr";
|
|
10
|
+
import { config } from "@/services/ConfigService";
|
|
11
|
+
import { getProjectContext } from "@/services/projects";
|
|
12
|
+
import { ReportService } from "@/services/reports";
|
|
13
|
+
import { SchedulerService } from "@/services/scheduling";
|
|
14
|
+
import { formatLessonsWithReminder } from "@/utils/lessonFormatter";
|
|
15
|
+
import { logger } from "@/utils/logger";
|
|
16
|
+
import type { NDKProject } from "@nostr-dev-kit/ndk";
|
|
17
|
+
import type { ModelMessage } from "ai";
|
|
18
|
+
|
|
19
|
+
// Import fragment registration manifest
|
|
20
|
+
import "@/prompts/fragments"; // This auto-registers all fragments
|
|
21
|
+
import { fetchAgentMcpResources } from "@/prompts/fragments/26-mcp-resources";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Module-level cache for PromptCompilerService instances per project+agent.
|
|
25
|
+
* Prevents duplicate LLM calls when multiple system prompt builds occur for the same agent.
|
|
26
|
+
* The cache holds compilers for the process lifetime — memory is bounded by agent count × projects.
|
|
27
|
+
*
|
|
28
|
+
* KEY FORMAT: `${projectCacheKey}:${agentPubkey}` to prevent cross-project contamination
|
|
29
|
+
* when the same agent pubkey is active in multiple concurrent projects.
|
|
30
|
+
*/
|
|
31
|
+
const promptCompilerCache = new Map<string, PromptCompilerService>();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* In-flight promise cache to prevent race conditions when multiple concurrent
|
|
35
|
+
* prompt builds try to create compilers simultaneously for the same project+agent.
|
|
36
|
+
* This ensures only one compiler is created per project+agent combination.
|
|
37
|
+
*/
|
|
38
|
+
const inFlightCompilerPromises = new Map<string, Promise<PromptCompilerService | undefined>>();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Set of project IDs that have already emitted a "missing d-tag" warning.
|
|
42
|
+
* Used to implement warn-once behavior and prevent log spam on hot paths.
|
|
43
|
+
*/
|
|
44
|
+
const warnedMissingDTagProjects = new Set<string>();
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Apply updates to an existing PromptCompilerService.
|
|
48
|
+
* Adds new comments and updates lessons, triggering recompilation if needed.
|
|
49
|
+
*/
|
|
50
|
+
function applyCompilerUpdates(
|
|
51
|
+
compiler: PromptCompilerService,
|
|
52
|
+
comments: LessonComment[],
|
|
53
|
+
lessons: NDKAgentLesson[]
|
|
54
|
+
): void {
|
|
55
|
+
// Add comments (de-duplicated internally by addComment)
|
|
56
|
+
for (const comment of comments) {
|
|
57
|
+
compiler.addComment(comment);
|
|
58
|
+
}
|
|
59
|
+
// Update lessons - compiler detects staleness and triggers recompilation as needed
|
|
60
|
+
compiler.updateLessons(lessons);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* List of scheduling-related tools that trigger the scheduled tasks context
|
|
65
|
+
*/
|
|
66
|
+
const SCHEDULING_TOOLS = ["schedule_task", "schedule_task_cancel", "schedule_tasks_list"] as const;
|
|
67
|
+
|
|
68
|
+
export interface BuildSystemPromptOptions {
|
|
69
|
+
// Required data
|
|
70
|
+
agent: AgentInstance;
|
|
71
|
+
project: NDKProject;
|
|
72
|
+
conversation: ConversationStore;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Project directory (normal git repository root).
|
|
76
|
+
* Example: ~/tenex/{dTag}
|
|
77
|
+
* Worktrees are in .worktrees/ subdirectory.
|
|
78
|
+
*/
|
|
79
|
+
projectBasePath?: string;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Working directory for code execution.
|
|
83
|
+
* - Default branch: same as projectBasePath (~/tenex/{dTag})
|
|
84
|
+
* - Feature branch: ~/tenex/{dTag}/.worktrees/feature_branch/
|
|
85
|
+
* This is displayed as "Absolute Path" in the system prompt.
|
|
86
|
+
*/
|
|
87
|
+
workingDirectory?: string;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Current git branch name.
|
|
91
|
+
* Example: "master", "feature/branch-name", "research/foo"
|
|
92
|
+
*/
|
|
93
|
+
currentBranch?: string;
|
|
94
|
+
|
|
95
|
+
// Optional runtime data
|
|
96
|
+
availableAgents?: AgentInstance[];
|
|
97
|
+
agentLessons?: Map<string, NDKAgentLesson[]>;
|
|
98
|
+
/** Comments on agent lessons (kind 1111 NIP-22 comments) */
|
|
99
|
+
agentComments?: Map<string, LessonComment[]>;
|
|
100
|
+
isProjectManager?: boolean; // Indicates if this agent is the PM
|
|
101
|
+
projectManagerPubkey?: string; // Pubkey of the project manager
|
|
102
|
+
mcpManager?: MCPManager; // MCP manager for this project
|
|
103
|
+
nudgeContent?: string; // Concatenated content from kind:4201 nudge events (legacy)
|
|
104
|
+
/** Individual nudge data for rendering with titles */
|
|
105
|
+
nudges?: NudgeData[];
|
|
106
|
+
/** Tool permissions extracted from nudge events */
|
|
107
|
+
nudgeToolPermissions?: NudgeToolPermissions;
|
|
108
|
+
/** Concatenated content from kind:4202 skill events (legacy) */
|
|
109
|
+
skillContent?: string;
|
|
110
|
+
/** Individual skill data for rendering with files */
|
|
111
|
+
skills?: SkillData[];
|
|
112
|
+
/** Available whitelisted nudges for delegation */
|
|
113
|
+
availableNudges?: WhitelistItem[];
|
|
114
|
+
/** Available whitelisted skills */
|
|
115
|
+
availableSkills?: WhitelistItem[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
export interface SystemMessage {
|
|
120
|
+
message: ModelMessage;
|
|
121
|
+
metadata?: {
|
|
122
|
+
description?: string;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Add lessons to the prompt using the simple fragment approach.
|
|
128
|
+
* Called when PromptCompilerService is not yet ready (still compiling).
|
|
129
|
+
*/
|
|
130
|
+
function addLessonsViaFragment(
|
|
131
|
+
builder: PromptBuilder,
|
|
132
|
+
agent: AgentInstance,
|
|
133
|
+
agentLessons?: Map<string, NDKAgentLesson[]>
|
|
134
|
+
): void {
|
|
135
|
+
builder.add("retrieved-lessons", {
|
|
136
|
+
agent,
|
|
137
|
+
agentLessons: agentLessons || new Map(),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Add core agent fragments.
|
|
143
|
+
* NOTE: Lessons are NOT included here - they are handled separately via either:
|
|
144
|
+
* 1. addLessonsViaFragment() - fallback when compiler not ready
|
|
145
|
+
* 2. PromptCompilerService (TIN-10) - compiled into Effective Agent Instructions
|
|
146
|
+
*/
|
|
147
|
+
async function addCoreAgentFragments(
|
|
148
|
+
builder: PromptBuilder,
|
|
149
|
+
agent: AgentInstance,
|
|
150
|
+
conversation?: ConversationStore,
|
|
151
|
+
mcpManager?: MCPManager
|
|
152
|
+
): Promise<void> {
|
|
153
|
+
// Add referenced article context if present
|
|
154
|
+
if (conversation?.metadata?.referencedArticle) {
|
|
155
|
+
builder.add("referenced-article", conversation.metadata.referencedArticle);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Add scheduled tasks context if agent has scheduling tools
|
|
159
|
+
const hasSchedulingTools = agent.tools.some((tool) =>
|
|
160
|
+
SCHEDULING_TOOLS.includes(tool as (typeof SCHEDULING_TOOLS)[number])
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
if (hasSchedulingTools) {
|
|
164
|
+
try {
|
|
165
|
+
const schedulerService = SchedulerService.getInstance();
|
|
166
|
+
const allTasks = await schedulerService.getTasks();
|
|
167
|
+
builder.add("scheduled-tasks", {
|
|
168
|
+
agent,
|
|
169
|
+
scheduledTasks: allTasks,
|
|
170
|
+
});
|
|
171
|
+
} catch (error) {
|
|
172
|
+
// Scheduler might not be initialized yet, log and continue
|
|
173
|
+
logger.debug("Could not fetch scheduled tasks for prompt:", error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Add todo usage guidance if agent has todo tools
|
|
178
|
+
if (agent.tools.includes("todo_add")) {
|
|
179
|
+
builder.add("todo-usage-guidance", {});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Add memorized reports - retrieved from cache (no async fetch needed)
|
|
183
|
+
// This includes both:
|
|
184
|
+
// 1. Agent-specific memorized reports (memorize=true) - only for the authoring agent
|
|
185
|
+
// 2. Team-memorized reports (memorize_team=true) - for ALL agents in the project
|
|
186
|
+
try {
|
|
187
|
+
const reportService = new ReportService();
|
|
188
|
+
|
|
189
|
+
// Get agent's own memorized reports
|
|
190
|
+
const agentMemorizedReports = reportService.getMemorizedReportsForAgent(agent.pubkey);
|
|
191
|
+
|
|
192
|
+
// Get team-memorized reports (visible to ALL agents)
|
|
193
|
+
const teamMemorizedReports = reportService.getTeamMemorizedReports();
|
|
194
|
+
|
|
195
|
+
// Combine and deduplicate by slug with scope-aware semantics:
|
|
196
|
+
// 1. Team memos ALWAYS take precedence (they must appear for ALL agents)
|
|
197
|
+
// 2. Within each scope (team vs agent), latest publishedAt wins
|
|
198
|
+
// 3. Agent-only reports are only included if no team memo exists with the same slug
|
|
199
|
+
|
|
200
|
+
// Step 1: Deduplicate team reports by slug (latest wins within team scope)
|
|
201
|
+
const teamBySlug = new Map<string, typeof teamMemorizedReports[0]>();
|
|
202
|
+
for (const report of teamMemorizedReports) {
|
|
203
|
+
const existing = teamBySlug.get(report.slug);
|
|
204
|
+
if (!existing || (report.publishedAt || 0) > (existing.publishedAt || 0)) {
|
|
205
|
+
teamBySlug.set(report.slug, report);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Step 2: Deduplicate agent reports by slug (latest wins within agent scope)
|
|
210
|
+
const agentBySlug = new Map<string, typeof agentMemorizedReports[0]>();
|
|
211
|
+
for (const report of agentMemorizedReports) {
|
|
212
|
+
const existing = agentBySlug.get(report.slug);
|
|
213
|
+
if (!existing || (report.publishedAt || 0) > (existing.publishedAt || 0)) {
|
|
214
|
+
agentBySlug.set(report.slug, report);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Step 3: Combine - team memos first, then agent-only (excluding slugs already in team)
|
|
219
|
+
const combinedReports = [
|
|
220
|
+
...Array.from(teamBySlug.values()),
|
|
221
|
+
...Array.from(agentBySlug.values()).filter(r => !teamBySlug.has(r.slug)),
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
if (combinedReports.length > 0) {
|
|
225
|
+
builder.add("memorized-reports", { reports: combinedReports });
|
|
226
|
+
logger.debug("📚 Added memorized reports to system prompt (from cache)", {
|
|
227
|
+
agent: agent.name,
|
|
228
|
+
agentReportsCount: agentMemorizedReports.length,
|
|
229
|
+
teamReportsCount: teamMemorizedReports.length,
|
|
230
|
+
totalCount: combinedReports.length,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
// Report service might fail if no project context
|
|
235
|
+
logger.debug("Could not get memorized reports from cache:", error);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
// Add MCP resources if agent has any MCP tools and mcpManager is available
|
|
240
|
+
if (mcpManager) {
|
|
241
|
+
const resourcesPerServer = await fetchAgentMcpResources(agent.tools, mcpManager);
|
|
242
|
+
if (resourcesPerServer.length > 0) {
|
|
243
|
+
builder.add("mcp-resources", {
|
|
244
|
+
agentPubkey: agent.pubkey,
|
|
245
|
+
mcpEnabled: true,
|
|
246
|
+
resourcesPerServer,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Add RAG collection attribution - shows agents their contributions to RAG collections
|
|
252
|
+
// This uses the provenance tracking metadata (agent_pubkey) from document ingestion
|
|
253
|
+
//
|
|
254
|
+
// OPTIMIZATION: First check if any collections exist using lightweight check
|
|
255
|
+
// to avoid initializing embedding provider when RAG isn't used.
|
|
256
|
+
try {
|
|
257
|
+
const { hasRagCollections, RAGService } = await import("@/services/rag/RAGService");
|
|
258
|
+
|
|
259
|
+
// Fast path: skip full initialization if no collections exist
|
|
260
|
+
// Note: hasRagCollections() returns false on errors and logs them internally
|
|
261
|
+
if (!(await hasRagCollections())) {
|
|
262
|
+
logger.debug("📊 Skipping RAG collection stats - no collections available");
|
|
263
|
+
} else {
|
|
264
|
+
// Collections exist - now we need full service for stats
|
|
265
|
+
const ragService = RAGService.getInstance();
|
|
266
|
+
const collections = await ragService.getAllCollectionStats(agent.pubkey);
|
|
267
|
+
|
|
268
|
+
// Only add the fragment if we have any collection data
|
|
269
|
+
if (collections.length > 0) {
|
|
270
|
+
builder.add("rag-collections", {
|
|
271
|
+
agentPubkey: agent.pubkey,
|
|
272
|
+
collections,
|
|
273
|
+
});
|
|
274
|
+
logger.debug("📊 Added RAG collection stats to system prompt", {
|
|
275
|
+
agent: agent.name,
|
|
276
|
+
collectionsWithContributions: collections.filter(c => c.agentDocCount > 0).length,
|
|
277
|
+
totalCollections: collections.length,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
} catch (error) {
|
|
282
|
+
// RAG service might not be available - skip gracefully
|
|
283
|
+
logger.debug("Could not fetch RAG collection stats for prompt:", error);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Get Effective Agent Instructions SYNCHRONOUSLY using PromptCompilerService (TIN-10).
|
|
289
|
+
*
|
|
290
|
+
* EAGER COMPILATION: This function NEVER blocks on compilation.
|
|
291
|
+
* - If compiled instructions are available (from cache or completed compilation), use them
|
|
292
|
+
* - If compilation isn't ready yet (in progress or not started), use base instructions
|
|
293
|
+
*
|
|
294
|
+
* Compilation is triggered at project startup and runs in the background.
|
|
295
|
+
* Agent execution always gets the "current best" instructions without waiting.
|
|
296
|
+
*
|
|
297
|
+
* @param compiler The PromptCompilerService for this agent
|
|
298
|
+
* @param lessons The agent's lessons (used for fallback formatting if needed)
|
|
299
|
+
* @param baseAgentInstructions The Base Agent Instructions (from agent.instructions)
|
|
300
|
+
* @returns The Effective Agent Instructions (compiled if available, base otherwise)
|
|
301
|
+
*/
|
|
302
|
+
function getEffectiveInstructionsSync(
|
|
303
|
+
compiler: PromptCompilerService,
|
|
304
|
+
lessons: NDKAgentLesson[],
|
|
305
|
+
baseAgentInstructions: string
|
|
306
|
+
): string {
|
|
307
|
+
// Use the synchronous method - NEVER blocks on compilation
|
|
308
|
+
const result = compiler.getEffectiveInstructionsSync();
|
|
309
|
+
|
|
310
|
+
// No span needed here - this is called every RAL and the info is available
|
|
311
|
+
// on the parent agent.execute span or in logs. The instructions_source span
|
|
312
|
+
// was creating 18+ spans per conversation with no debugging value.
|
|
313
|
+
|
|
314
|
+
logger.debug("📋 Retrieved effective instructions synchronously", {
|
|
315
|
+
source: result.source,
|
|
316
|
+
isCompiled: result.isCompiled,
|
|
317
|
+
compiledAt: result.compiledAt,
|
|
318
|
+
instructionsLength: result.instructions.length,
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// If we got compiled instructions, use them
|
|
322
|
+
if (result.isCompiled) {
|
|
323
|
+
return result.instructions;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Not compiled yet - check if we have lessons to format as fallback
|
|
327
|
+
// This provides a better experience than raw base instructions when lessons exist
|
|
328
|
+
if (lessons.length > 0) {
|
|
329
|
+
logger.debug("📋 Using fallback lesson formatting (compilation not ready)", {
|
|
330
|
+
lessonsCount: lessons.length,
|
|
331
|
+
compilationStatus: result.source,
|
|
332
|
+
});
|
|
333
|
+
return formatFallbackLessons(lessons, baseAgentInstructions);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// No lessons and no compiled instructions - just use base
|
|
337
|
+
return baseAgentInstructions;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Fallback lesson formatting: appends formatted lessons to Base Agent Instructions.
|
|
342
|
+
* Used when PromptCompilerService cannot compile (no LLM config, LLM error, etc.)
|
|
343
|
+
*/
|
|
344
|
+
function formatFallbackLessons(lessons: NDKAgentLesson[], baseAgentInstructions: string): string {
|
|
345
|
+
if (lessons.length === 0) {
|
|
346
|
+
return baseAgentInstructions;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const formattedSection = formatLessonsWithReminder(lessons);
|
|
350
|
+
return `${baseAgentInstructions}\n\n${formattedSection}`;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Add agent-specific fragments
|
|
355
|
+
*/
|
|
356
|
+
function addAgentFragments(
|
|
357
|
+
builder: PromptBuilder,
|
|
358
|
+
agent: AgentInstance,
|
|
359
|
+
availableAgents: AgentInstance[],
|
|
360
|
+
projectManagerPubkey?: string,
|
|
361
|
+
availableNudges?: WhitelistItem[],
|
|
362
|
+
availableSkills?: WhitelistItem[]
|
|
363
|
+
): void {
|
|
364
|
+
// Add available nudges and skills for delegation (priority 13, before available-agents)
|
|
365
|
+
if ((availableNudges && availableNudges.length > 0) || (availableSkills && availableSkills.length > 0)) {
|
|
366
|
+
builder.add("available-nudges-and-skills", {
|
|
367
|
+
availableNudges,
|
|
368
|
+
availableSkills,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Add available agents for delegations
|
|
373
|
+
builder.add("available-agents", {
|
|
374
|
+
agents: availableAgents,
|
|
375
|
+
currentAgent: agent,
|
|
376
|
+
projectManagerPubkey,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Add delegation best practices guidance (priority 16, after available-agents)
|
|
380
|
+
builder.add("stay-in-your-lane", {});
|
|
381
|
+
|
|
382
|
+
// Add todo-before-delegation requirement (priority 17, after stay-in-your-lane)
|
|
383
|
+
builder.add("todo-before-delegation", {});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Builds the system prompt messages for an agent, returning an array of messages
|
|
388
|
+
* with optional caching metadata.
|
|
389
|
+
* This is the single source of truth for system prompt generation.
|
|
390
|
+
*/
|
|
391
|
+
export async function buildSystemPromptMessages(
|
|
392
|
+
options: BuildSystemPromptOptions
|
|
393
|
+
): Promise<SystemMessage[]> {
|
|
394
|
+
const messages: SystemMessage[] = [];
|
|
395
|
+
|
|
396
|
+
// Build the main system prompt
|
|
397
|
+
const mainPrompt = await buildMainSystemPrompt(options);
|
|
398
|
+
messages.push({
|
|
399
|
+
message: { role: "system", content: mainPrompt },
|
|
400
|
+
metadata: {
|
|
401
|
+
description: "Main system prompt",
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
return messages;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Get or create a PromptCompilerService instance for an agent within a specific project.
|
|
410
|
+
*
|
|
411
|
+
* Uses a module-level cache to avoid duplicate LLM calls when multiple system prompt
|
|
412
|
+
* builds occur for the same agent (e.g., across multiple RALs or conversations).
|
|
413
|
+
*
|
|
414
|
+
* This is the "lazy/on-demand instantiation" pattern:
|
|
415
|
+
* - Returns cached compiler if available for this project+agent combination
|
|
416
|
+
* - Creates new compiler on cache miss: reads disk cache, triggers background compilation
|
|
417
|
+
* - Returns undefined if NDK is unavailable (fallback to simple lesson fragment)
|
|
418
|
+
*
|
|
419
|
+
* IMPORTANT: Cache is scoped by project cache key + agent pubkey to prevent cross-project
|
|
420
|
+
* contamination when the same agent is active in multiple concurrent projects.
|
|
421
|
+
*
|
|
422
|
+
* @param projectCacheKey Cache key prefix for the project (typically dTag, but may be event ID or fallback value if dTag is missing)
|
|
423
|
+
* @param agentPubkey Agent's public key (used as cache key suffix)
|
|
424
|
+
* @param baseAgentInstructions The Base Agent Instructions from agent.instructions
|
|
425
|
+
* @param agentEventId Optional event ID for the agent definition
|
|
426
|
+
* @param lessons Current lessons for this agent
|
|
427
|
+
* @param comments Current comments for this agent's lessons
|
|
428
|
+
* @param agentSigner Optional signer for kind:0 publishing
|
|
429
|
+
* @param agentName Optional agent name for kind:0 publishing
|
|
430
|
+
* @param agentRole Optional agent role for kind:0 publishing
|
|
431
|
+
* @param projectTitle Optional project title for kind:0 publishing
|
|
432
|
+
*/
|
|
433
|
+
async function getOrCreatePromptCompiler(
|
|
434
|
+
projectCacheKey: string,
|
|
435
|
+
agentPubkey: string,
|
|
436
|
+
baseAgentInstructions: string,
|
|
437
|
+
agentEventId: string | undefined,
|
|
438
|
+
lessons: NDKAgentLesson[],
|
|
439
|
+
comments: LessonComment[],
|
|
440
|
+
agentSigner?: import("@nostr-dev-kit/ndk").NDKPrivateKeySigner,
|
|
441
|
+
agentName?: string,
|
|
442
|
+
agentRole?: string,
|
|
443
|
+
projectTitle?: string
|
|
444
|
+
): Promise<PromptCompilerService | undefined> {
|
|
445
|
+
// Build cache key scoped by project + agent to prevent cross-project contamination
|
|
446
|
+
const cacheKey = `${projectCacheKey}:${agentPubkey}`;
|
|
447
|
+
|
|
448
|
+
// Check cache first
|
|
449
|
+
const cachedCompiler = promptCompilerCache.get(cacheKey);
|
|
450
|
+
if (cachedCompiler) {
|
|
451
|
+
// Update with any new comments/lessons that arrived since last call
|
|
452
|
+
applyCompilerUpdates(cachedCompiler, comments, lessons);
|
|
453
|
+
|
|
454
|
+
logger.debug("📋 Using cached PromptCompilerService", {
|
|
455
|
+
projectCacheKey,
|
|
456
|
+
agentPubkey: agentPubkey.substring(0, 8),
|
|
457
|
+
lessonsCount: lessons.length,
|
|
458
|
+
commentsCount: comments.length,
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
return cachedCompiler;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Check if there's an in-flight creation for this project+agent (race condition guard)
|
|
465
|
+
const inFlightPromise = inFlightCompilerPromises.get(cacheKey);
|
|
466
|
+
if (inFlightPromise) {
|
|
467
|
+
logger.debug("📋 Waiting for in-flight compiler creation", {
|
|
468
|
+
projectCacheKey,
|
|
469
|
+
agentPubkey: agentPubkey.substring(0, 8),
|
|
470
|
+
});
|
|
471
|
+
// Await the in-flight promise, then apply this caller's comments/lessons
|
|
472
|
+
// to ensure concurrent callers' data is not silently lost
|
|
473
|
+
const compiler = await inFlightPromise;
|
|
474
|
+
if (compiler) {
|
|
475
|
+
applyCompilerUpdates(compiler, comments, lessons);
|
|
476
|
+
}
|
|
477
|
+
return compiler;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Create new compiler with single-flight guard
|
|
481
|
+
const creationPromise = (async (): Promise<PromptCompilerService | undefined> => {
|
|
482
|
+
try {
|
|
483
|
+
const ndk = getNDK();
|
|
484
|
+
const { config: loadedConfig } = await config.loadConfig();
|
|
485
|
+
const whitelistArray = loadedConfig.whitelistedPubkeys ?? [];
|
|
486
|
+
|
|
487
|
+
const compiler = new PromptCompilerService(agentPubkey, whitelistArray, ndk);
|
|
488
|
+
|
|
489
|
+
// Set agent metadata for kind:0 publishing (gap 2 fix)
|
|
490
|
+
// This enables the compiler to publish kind:0 events with compiled instructions
|
|
491
|
+
if (agentSigner && agentName && projectTitle) {
|
|
492
|
+
compiler.setAgentMetadata(agentSigner, agentName, agentRole || "", projectTitle);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Load pre-existing comments from ProjectContext
|
|
496
|
+
// This restores comment state that was accumulated by Daemon's handleLessonCommentEvent
|
|
497
|
+
for (const comment of comments) {
|
|
498
|
+
compiler.addComment(comment);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Initialize: loads disk cache into memory and stores base instructions + lessons
|
|
502
|
+
await compiler.initialize(baseAgentInstructions, lessons, agentEventId);
|
|
503
|
+
|
|
504
|
+
// Trigger background compilation (fire and forget) — no-op if cache is fresh
|
|
505
|
+
compiler.triggerCompilation();
|
|
506
|
+
|
|
507
|
+
// Cache for future calls (using project-scoped key)
|
|
508
|
+
promptCompilerCache.set(cacheKey, compiler);
|
|
509
|
+
|
|
510
|
+
logger.debug("📋 Created and cached new PromptCompilerService", {
|
|
511
|
+
projectCacheKey,
|
|
512
|
+
agentPubkey: agentPubkey.substring(0, 8),
|
|
513
|
+
lessonsCount: lessons.length,
|
|
514
|
+
commentsCount: comments.length,
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
return compiler;
|
|
518
|
+
} catch (error) {
|
|
519
|
+
logger.debug("Could not create lazy PromptCompilerService:", error);
|
|
520
|
+
return undefined;
|
|
521
|
+
} finally {
|
|
522
|
+
// Remove from in-flight map once complete (success or failure)
|
|
523
|
+
inFlightCompilerPromises.delete(cacheKey);
|
|
524
|
+
}
|
|
525
|
+
})();
|
|
526
|
+
|
|
527
|
+
// Register in-flight promise to prevent duplicate concurrent creations
|
|
528
|
+
inFlightCompilerPromises.set(cacheKey, creationPromise);
|
|
529
|
+
|
|
530
|
+
return creationPromise;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Builds the main system prompt content.
|
|
535
|
+
*
|
|
536
|
+
* Uses PromptCompilerService (TIN-10) when available to synthesize lessons + comments
|
|
537
|
+
* into Effective Agent Instructions. The result (Base Agent Instructions + Lessons)
|
|
538
|
+
* is then used when building fragments.
|
|
539
|
+
*
|
|
540
|
+
* IMPORTANT: The Effective Agent Instructions should contain ONLY:
|
|
541
|
+
* - Base Agent Instructions (from agent.instructions in Kind 4199 event)
|
|
542
|
+
* - Lessons learned (merged by LLM)
|
|
543
|
+
*
|
|
544
|
+
* Fragments (project context, worktrees, available agents, etc.) are added AFTER compilation.
|
|
545
|
+
*/
|
|
546
|
+
async function buildMainSystemPrompt(options: BuildSystemPromptOptions): Promise<string> {
|
|
547
|
+
const {
|
|
548
|
+
agent,
|
|
549
|
+
project,
|
|
550
|
+
projectBasePath,
|
|
551
|
+
workingDirectory,
|
|
552
|
+
currentBranch,
|
|
553
|
+
availableAgents = [],
|
|
554
|
+
conversation,
|
|
555
|
+
agentLessons,
|
|
556
|
+
agentComments,
|
|
557
|
+
mcpManager,
|
|
558
|
+
nudgeContent,
|
|
559
|
+
nudges,
|
|
560
|
+
nudgeToolPermissions,
|
|
561
|
+
skillContent,
|
|
562
|
+
skills,
|
|
563
|
+
} = options;
|
|
564
|
+
|
|
565
|
+
// Lazily instantiate PromptCompilerService for this agent (TIN-10).
|
|
566
|
+
// Reads from disk cache as fast path; triggers LLM compilation in background on cache miss.
|
|
567
|
+
const lessons = agentLessons?.get(agent.pubkey) || [];
|
|
568
|
+
const comments = agentComments?.get(agent.pubkey) || [];
|
|
569
|
+
const baseAgentInstructions = agent.instructions || "";
|
|
570
|
+
|
|
571
|
+
// Get project context and agent for kind:0 metadata
|
|
572
|
+
const context = getProjectContext();
|
|
573
|
+
const projectTitle = project.tagValue("title") || "Untitled";
|
|
574
|
+
const agentInstance = context.getAgentByPubkey(agent.pubkey);
|
|
575
|
+
// Use project's dTag for cache key scoping. Fall back to event ID if no dTag to avoid
|
|
576
|
+
// cross-project collisions (using a generic "unknown" string would cause collisions).
|
|
577
|
+
const dTag = project.dTag || project.tagValue("d");
|
|
578
|
+
let projectCacheKey: string;
|
|
579
|
+
if (dTag) {
|
|
580
|
+
projectCacheKey = dTag;
|
|
581
|
+
} else {
|
|
582
|
+
// Warn once per project to avoid log spam on hot path
|
|
583
|
+
const projectIdentifier = project.id || project.pubkey || "unknown";
|
|
584
|
+
if (!warnedMissingDTagProjects.has(projectIdentifier)) {
|
|
585
|
+
warnedMissingDTagProjects.add(projectIdentifier);
|
|
586
|
+
logger.warn("⚠️ Project missing d-tag, using event ID for cache key. This may indicate a misconfigured project.", {
|
|
587
|
+
projectId: project.id?.substring(0, 8),
|
|
588
|
+
projectPubkey: project.pubkey?.substring(0, 8),
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
projectCacheKey = project.id || `fallback-${project.pubkey?.substring(0, 16) || "unknown"}`;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const promptCompiler = await getOrCreatePromptCompiler(
|
|
595
|
+
projectCacheKey,
|
|
596
|
+
agent.pubkey,
|
|
597
|
+
baseAgentInstructions,
|
|
598
|
+
agent.eventId,
|
|
599
|
+
lessons,
|
|
600
|
+
comments,
|
|
601
|
+
// Pass agent metadata for kind:0 publishing (gap 2 fix)
|
|
602
|
+
agentInstance?.signer,
|
|
603
|
+
agentInstance?.name ?? agent.name,
|
|
604
|
+
agentInstance?.role ?? "",
|
|
605
|
+
projectTitle
|
|
606
|
+
);
|
|
607
|
+
const usePromptCompiler = !!promptCompiler;
|
|
608
|
+
|
|
609
|
+
// If PromptCompilerService is available, get effective instructions SYNCHRONOUSLY
|
|
610
|
+
// EAGER COMPILATION: This NEVER blocks - uses cached compiled instructions or falls back to base
|
|
611
|
+
let effectiveAgentInstructions: string | undefined;
|
|
612
|
+
if (promptCompiler) {
|
|
613
|
+
// SYNCHRONOUS retrieval - NEVER waits for compilation
|
|
614
|
+
effectiveAgentInstructions = getEffectiveInstructionsSync(
|
|
615
|
+
promptCompiler,
|
|
616
|
+
lessons,
|
|
617
|
+
baseAgentInstructions
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
logger.debug("✅ Retrieved Effective Agent Instructions (sync)", {
|
|
621
|
+
agentName: agent.name,
|
|
622
|
+
baseInstructionsLength: baseAgentInstructions.length,
|
|
623
|
+
effectiveInstructionsLength: effectiveAgentInstructions.length,
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// Create an agent copy with Effective Agent Instructions (if available)
|
|
628
|
+
// This ensures fragments use the compiled version instead of raw Base Agent Instructions
|
|
629
|
+
const agentForFragments: AgentInstance = effectiveAgentInstructions
|
|
630
|
+
? { ...agent, instructions: effectiveAgentInstructions }
|
|
631
|
+
: agent;
|
|
632
|
+
|
|
633
|
+
const systemPromptBuilder = new PromptBuilder();
|
|
634
|
+
|
|
635
|
+
// Add agent identity - use workingDirectory for "Absolute Path" (where the agent operates)
|
|
636
|
+
// NOTE: Uses agentForFragments which has Effective Agent Instructions (lessons merged in)
|
|
637
|
+
systemPromptBuilder.add("agent-identity", {
|
|
638
|
+
agent: agentForFragments,
|
|
639
|
+
projectTitle: project.tagValue("title") || "Unknown Project",
|
|
640
|
+
projectOwnerPubkey: project.pubkey,
|
|
641
|
+
workingDirectory,
|
|
642
|
+
conversationId: conversation.getId(),
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
// Add agent home directory context
|
|
646
|
+
systemPromptBuilder.add("agent-home-directory", { agent: agentForFragments });
|
|
647
|
+
|
|
648
|
+
// Explain <system-reminder> tags before agents encounter them
|
|
649
|
+
systemPromptBuilder.add("system-reminders-explanation", {});
|
|
650
|
+
|
|
651
|
+
// Add global system prompt if configured (ordered by fragment priority)
|
|
652
|
+
systemPromptBuilder.add("global-system-prompt", {});
|
|
653
|
+
|
|
654
|
+
// Add relay configuration context
|
|
655
|
+
systemPromptBuilder.add("relay-configuration", {});
|
|
656
|
+
|
|
657
|
+
// Add meta-project context (other projects this agent belongs to)
|
|
658
|
+
// This gives agents cross-project awareness without overwhelming them
|
|
659
|
+
systemPromptBuilder.add("meta-project-context", {
|
|
660
|
+
agent: agentForFragments,
|
|
661
|
+
currentProjectId: project.tagId(),
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
// Add active conversations context (currently running agents in the project)
|
|
665
|
+
// NOTE: Use project.tagId() (NIP-33 address: "31933:<pubkey>:<d-tag>") for RALRegistry lookups
|
|
666
|
+
// RALRegistry stores entries using tagId(), so lookups must use the same format
|
|
667
|
+
systemPromptBuilder.add("active-conversations", {
|
|
668
|
+
agent: agentForFragments,
|
|
669
|
+
currentConversationId: conversation.getId(),
|
|
670
|
+
projectId: project.tagId(),
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
// Add recent conversations context (short-term memory)
|
|
674
|
+
// NOTE: Use project.tagId() for ConversationStore lookups (directory structure uses full tagId)
|
|
675
|
+
systemPromptBuilder.add("recent-conversations", {
|
|
676
|
+
agent: agentForFragments,
|
|
677
|
+
currentConversationId: conversation.getId(),
|
|
678
|
+
projectId: project.tagId(),
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// Add delegation chain if present (shows agent their position in multi-agent workflow)
|
|
682
|
+
// The chain entries already have full conversation IDs stored - no need to pass currentConversationId
|
|
683
|
+
if (conversation?.metadata?.delegationChain && conversation.metadata.delegationChain.length > 0) {
|
|
684
|
+
systemPromptBuilder.add("delegation-chain", {
|
|
685
|
+
delegationChain: conversation.metadata.delegationChain,
|
|
686
|
+
currentAgentPubkey: agentForFragments.pubkey,
|
|
687
|
+
currentConversationId: conversation.getId(),
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Add nudge content if present (from kind:4201 events referenced by the triggering event)
|
|
692
|
+
// Now supports individual nudge data with tool permissions
|
|
693
|
+
if ((nudges && nudges.length > 0) || (nudgeContent && nudgeContent.trim().length > 0)) {
|
|
694
|
+
systemPromptBuilder.add("nudges", {
|
|
695
|
+
nudgeContent,
|
|
696
|
+
nudges,
|
|
697
|
+
nudgeToolPermissions,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// Add skill content if present (from kind:4202 events referenced by the triggering event)
|
|
702
|
+
// Skills provide transient capabilities and attached files, but do NOT modify tool permissions
|
|
703
|
+
if ((skills && skills.length > 0) || (skillContent && skillContent.trim().length > 0)) {
|
|
704
|
+
systemPromptBuilder.add("skills", {
|
|
705
|
+
skillContent,
|
|
706
|
+
skills,
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// NOTE: agent-todos is NOT included here - it's injected as a late system message
|
|
711
|
+
// in AgentExecutor.executeStreaming() to ensure it appears at the end of messages
|
|
712
|
+
|
|
713
|
+
// Add worktree context if we have the necessary information
|
|
714
|
+
if (workingDirectory && currentBranch && projectBasePath) {
|
|
715
|
+
systemPromptBuilder.add("worktree-context", {
|
|
716
|
+
context: {
|
|
717
|
+
workingDirectory,
|
|
718
|
+
currentBranch,
|
|
719
|
+
projectBasePath,
|
|
720
|
+
agent: agentForFragments,
|
|
721
|
+
},
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Add AGENTS.md guidance - always included to inform agents about the AGENTS.md system
|
|
726
|
+
// When no AGENTS.md exists, the fragment explicitly states so
|
|
727
|
+
if (projectBasePath) {
|
|
728
|
+
try {
|
|
729
|
+
const { agentsMdService } = await import("@/services/agents-md");
|
|
730
|
+
const hasRootAgentsMd = await agentsMdService.hasRootAgentsMd(projectBasePath);
|
|
731
|
+
const rootContent = hasRootAgentsMd
|
|
732
|
+
? await agentsMdService.getRootAgentsMdContent(projectBasePath)
|
|
733
|
+
: null;
|
|
734
|
+
systemPromptBuilder.add("agents-md-guidance", {
|
|
735
|
+
hasRootAgentsMd,
|
|
736
|
+
rootAgentsMdContent: rootContent || undefined,
|
|
737
|
+
});
|
|
738
|
+
} catch (error) {
|
|
739
|
+
// AGENTS.md service not available or error - add fragment with no AGENTS.md state
|
|
740
|
+
logger.debug("Could not check for root AGENTS.md:", error);
|
|
741
|
+
systemPromptBuilder.add("agents-md-guidance", {
|
|
742
|
+
hasRootAgentsMd: false,
|
|
743
|
+
rootAgentsMdContent: undefined,
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
// No project base path - still add fragment to explain AGENTS.md system
|
|
748
|
+
systemPromptBuilder.add("agents-md-guidance", {
|
|
749
|
+
hasRootAgentsMd: false,
|
|
750
|
+
rootAgentsMdContent: undefined,
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// Add core agent fragments using shared composition
|
|
755
|
+
await addCoreAgentFragments(systemPromptBuilder, agentForFragments, conversation, mcpManager);
|
|
756
|
+
|
|
757
|
+
// Handle lessons: ONLY add via fragment if NOT using PromptCompilerService
|
|
758
|
+
// When using compiler, lessons are already merged into Effective Agent Instructions
|
|
759
|
+
if (!usePromptCompiler) {
|
|
760
|
+
// No compiler available - add lessons via fragment
|
|
761
|
+
addLessonsViaFragment(systemPromptBuilder, agentForFragments, agentLessons);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Add agent-specific fragments
|
|
765
|
+
addAgentFragments(
|
|
766
|
+
systemPromptBuilder,
|
|
767
|
+
agentForFragments,
|
|
768
|
+
availableAgents,
|
|
769
|
+
options.projectManagerPubkey,
|
|
770
|
+
options.availableNudges,
|
|
771
|
+
options.availableSkills
|
|
772
|
+
);
|
|
773
|
+
|
|
774
|
+
// Build and return the complete prompt with all fragments
|
|
775
|
+
return systemPromptBuilder.build();
|
|
776
|
+
}
|
|
777
|
+
|