@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,43 @@
|
|
|
1
|
+
import { config } from "@/services/ConfigService";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default Nostr relay URLs for TENEX
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_RELAY_URLS = ["wss://tenex.chat"];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validate WebSocket URL format
|
|
10
|
+
* @param url - URL to validate
|
|
11
|
+
* @returns true if URL is valid WebSocket URL
|
|
12
|
+
*/
|
|
13
|
+
function isValidWebSocketUrl(url: string): boolean {
|
|
14
|
+
try {
|
|
15
|
+
const parsed = new URL(url);
|
|
16
|
+
return parsed.protocol === "ws:" || parsed.protocol === "wss:";
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get relay URLs for NDK connection
|
|
24
|
+
* Priority: config file > defaults
|
|
25
|
+
* @returns Array of validated WebSocket relay URLs
|
|
26
|
+
*/
|
|
27
|
+
export function getRelayUrls(): string[] {
|
|
28
|
+
// Check config file
|
|
29
|
+
try {
|
|
30
|
+
const tenexConfig = config.getConfig();
|
|
31
|
+
if (tenexConfig.relays && tenexConfig.relays.length > 0) {
|
|
32
|
+
const urls = tenexConfig.relays.filter((url) => isValidWebSocketUrl(url));
|
|
33
|
+
if (urls.length > 0) {
|
|
34
|
+
return urls;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
// Config not loaded yet, fall through to defaults
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Fall back to defaults
|
|
42
|
+
return DEFAULT_RELAY_URLS;
|
|
43
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { propagation, context as otelContext, trace } from "@opentelemetry/api";
|
|
2
|
+
import { getLLMSpanId } from "../telemetry/LLMSpanRegistry.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Event-like object that has a tags array.
|
|
6
|
+
* Compatible with NDKEvent and plain objects.
|
|
7
|
+
*/
|
|
8
|
+
export interface EventWithTags {
|
|
9
|
+
tags: string[][];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Inject W3C trace context into an event's tags.
|
|
14
|
+
* This allows the daemon to link incoming events back to their parent span.
|
|
15
|
+
* Also adds trace_context_llm which links to the LLM execution span for better debugging.
|
|
16
|
+
*
|
|
17
|
+
* @param event - Any object with a tags array (NDKEvent or plain object)
|
|
18
|
+
*/
|
|
19
|
+
export function injectTraceContext(event: EventWithTags): void {
|
|
20
|
+
const carrier: Record<string, string> = {};
|
|
21
|
+
propagation.inject(otelContext.active(), carrier);
|
|
22
|
+
if (carrier.traceparent) {
|
|
23
|
+
event.tags.push(["trace_context", carrier.traceparent]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Add trace context that links to LLM execution span (more useful for debugging)
|
|
27
|
+
const activeSpan = trace.getActiveSpan();
|
|
28
|
+
if (activeSpan) {
|
|
29
|
+
const spanContext = activeSpan.spanContext();
|
|
30
|
+
const traceId = spanContext.traceId;
|
|
31
|
+
|
|
32
|
+
// Use LLM span ID if available (links to actual LLM execution)
|
|
33
|
+
// Otherwise fall back to current span ID
|
|
34
|
+
const llmSpanId = getLLMSpanId(traceId);
|
|
35
|
+
const spanIdToUse = llmSpanId || spanContext.spanId;
|
|
36
|
+
|
|
37
|
+
event.tags.push(["trace_context_llm", `00-${traceId}-${spanIdToUse}-01`]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for agent Nostr events.
|
|
3
|
+
* Centralized types for event encoding and publishing.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { LanguageModelUsageWithCostUsd } from "@/llm/types";
|
|
7
|
+
import type { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Intent Types - Express what agents want to communicate
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
export interface CompletionIntent {
|
|
14
|
+
content: string;
|
|
15
|
+
usage?: LanguageModelUsageWithCostUsd;
|
|
16
|
+
summary?: string;
|
|
17
|
+
// Note: llmRuntime is now tracked via EventContext.llmRuntime for all events
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ConversationIntent {
|
|
21
|
+
content: string;
|
|
22
|
+
isReasoning?: boolean;
|
|
23
|
+
usage?: LanguageModelUsageWithCostUsd;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DelegationIntent {
|
|
27
|
+
delegations: Array<{
|
|
28
|
+
recipient: string;
|
|
29
|
+
request: string;
|
|
30
|
+
branch?: string;
|
|
31
|
+
}>;
|
|
32
|
+
type?: "delegation" | "delegation_followup" | "ask";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A single-select question where user picks one option (or provides their own answer).
|
|
37
|
+
*/
|
|
38
|
+
export interface SingleSelectQuestion {
|
|
39
|
+
type: "question";
|
|
40
|
+
/** Short title for the question (displayed as header) */
|
|
41
|
+
title: string;
|
|
42
|
+
/** Full question text */
|
|
43
|
+
question: string;
|
|
44
|
+
/** Optional suggestions - if omitted, question is fully open-ended */
|
|
45
|
+
suggestions?: string[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A multi-select question where user can pick multiple options (or provide their own answer).
|
|
50
|
+
*/
|
|
51
|
+
export interface MultiSelectQuestion {
|
|
52
|
+
type: "multiselect";
|
|
53
|
+
/** Short title for the question (displayed as header) */
|
|
54
|
+
title: string;
|
|
55
|
+
/** Full question text */
|
|
56
|
+
question: string;
|
|
57
|
+
/** Optional options - if omitted, question is fully open-ended */
|
|
58
|
+
options?: string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Union type for all question types.
|
|
63
|
+
*/
|
|
64
|
+
export type AskQuestion = SingleSelectQuestion | MultiSelectQuestion;
|
|
65
|
+
|
|
66
|
+
export interface AskIntent {
|
|
67
|
+
title: string;
|
|
68
|
+
context: string;
|
|
69
|
+
questions: AskQuestion[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ErrorIntent {
|
|
73
|
+
message: string;
|
|
74
|
+
errorType?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface LessonIntent {
|
|
78
|
+
title: string;
|
|
79
|
+
lesson: string;
|
|
80
|
+
detailed?: string;
|
|
81
|
+
category?: string;
|
|
82
|
+
hashtags?: string[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface ScheduledTaskInfo {
|
|
86
|
+
id: string;
|
|
87
|
+
title: string;
|
|
88
|
+
schedule: string; // Cron expression or ISO timestamp
|
|
89
|
+
/** Agent slug when resolvable, otherwise a truncated pubkey prefix */
|
|
90
|
+
targetAgent: string;
|
|
91
|
+
type: "cron" | "oneoff";
|
|
92
|
+
lastRun?: number; // Unix timestamp in seconds
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface StatusIntent {
|
|
96
|
+
type: "status";
|
|
97
|
+
agents: Array<{ pubkey: string; slug: string }>;
|
|
98
|
+
models: Array<{ slug: string; agents: string[] }>;
|
|
99
|
+
tools: Array<{ name: string; agents: string[] }>;
|
|
100
|
+
worktrees?: string[]; // Array of branch names, first is default
|
|
101
|
+
scheduledTasks?: ScheduledTaskInfo[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface ToolUseIntent {
|
|
105
|
+
toolName: string;
|
|
106
|
+
content: string; // e.g., "Reading $path"
|
|
107
|
+
args?: unknown; // Tool arguments to be serialized
|
|
108
|
+
referencedEventIds?: string[]; // Event IDs to reference with q-tags (e.g., delegation event IDs)
|
|
109
|
+
referencedAddressableEvents?: string[]; // Addressable event references with a-tags (e.g., "30023:pubkey:d-tag")
|
|
110
|
+
usage?: LanguageModelUsageWithCostUsd; // Cumulative usage from previous steps
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Intent for intervention review requests.
|
|
115
|
+
* Used when the InterventionService detects that a user hasn't responded
|
|
116
|
+
* to an agent's completion and triggers a human-replica review.
|
|
117
|
+
*
|
|
118
|
+
* Names are pre-resolved by the caller (InterventionPublisher) to avoid
|
|
119
|
+
* layer violations - AgentEventEncoder (layer 2) cannot import PubkeyService (layer 3).
|
|
120
|
+
*/
|
|
121
|
+
export interface InterventionReviewIntent {
|
|
122
|
+
/** Pubkey of the intervention agent (human-replica) to notify */
|
|
123
|
+
targetPubkey: string;
|
|
124
|
+
/** The conversation ID being reviewed */
|
|
125
|
+
conversationId: string;
|
|
126
|
+
/** Human-readable name of the user who hasn't responded (pre-resolved) */
|
|
127
|
+
userName: string;
|
|
128
|
+
/** Human-readable name of the agent that completed work (pre-resolved) */
|
|
129
|
+
agentName: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Intent for delegation marker events.
|
|
134
|
+
* Delegation markers track the lifecycle of delegation conversations.
|
|
135
|
+
* They are created when a delegation is initiated and updated when it completes/aborts.
|
|
136
|
+
*/
|
|
137
|
+
export interface DelegationMarkerIntent {
|
|
138
|
+
/** The delegation conversation ID (the child conversation) */
|
|
139
|
+
delegationConversationId: string;
|
|
140
|
+
/** The agent pubkey that received the delegation */
|
|
141
|
+
recipientPubkey: string;
|
|
142
|
+
/** The parent conversation ID (where the delegator is working) */
|
|
143
|
+
parentConversationId: string;
|
|
144
|
+
/** Delegation status: pending, completed, or aborted */
|
|
145
|
+
status: "pending" | "completed" | "aborted";
|
|
146
|
+
/** When the delegation was initiated (Unix timestamp in seconds) */
|
|
147
|
+
initiatedAt?: number;
|
|
148
|
+
/** When the delegation completed (Unix timestamp in seconds) - only for completed/aborted */
|
|
149
|
+
completedAt?: number;
|
|
150
|
+
/** If aborted, the reason for the abort */
|
|
151
|
+
abortReason?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export type AgentIntent =
|
|
155
|
+
| CompletionIntent
|
|
156
|
+
| ConversationIntent
|
|
157
|
+
| DelegationIntent
|
|
158
|
+
| AskIntent
|
|
159
|
+
| ErrorIntent
|
|
160
|
+
| LessonIntent
|
|
161
|
+
| StatusIntent
|
|
162
|
+
| ToolUseIntent
|
|
163
|
+
| InterventionReviewIntent
|
|
164
|
+
| DelegationMarkerIntent;
|
|
165
|
+
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// Event Context - Execution context provided by RAL
|
|
168
|
+
// ============================================================================
|
|
169
|
+
|
|
170
|
+
export interface EventContext {
|
|
171
|
+
triggeringEvent: NDKEvent; // The event that triggered this execution (for reply threading)
|
|
172
|
+
rootEvent: { id?: string }; // The conversation root event (only ID is used for tagging)
|
|
173
|
+
conversationId: string; // Required for conversation lookup
|
|
174
|
+
executionTime?: number;
|
|
175
|
+
model?: string;
|
|
176
|
+
cost?: number; // LLM cost in USD
|
|
177
|
+
ralNumber: number; // RAL number for this execution - required for all conversational events
|
|
178
|
+
/** Incremental LLM runtime in milliseconds since last event was published */
|
|
179
|
+
llmRuntime?: number;
|
|
180
|
+
/** Total accumulated LLM runtime for this RAL (used in completion events) */
|
|
181
|
+
llmRuntimeTotal?: number;
|
|
182
|
+
/**
|
|
183
|
+
* Pre-resolved recipient pubkey for completion events.
|
|
184
|
+
* When set, the encoder uses this pubkey for the completion p-tag instead of
|
|
185
|
+
* triggeringEvent.pubkey. This supports delegation chain routing where completions
|
|
186
|
+
* must route back to the immediate delegator, not the event that happened to
|
|
187
|
+
* trigger the current execution (e.g., a user responding to an ask).
|
|
188
|
+
*
|
|
189
|
+
* Resolved by createEventContext() (layer 3, in services/event-context/) from the
|
|
190
|
+
* ConversationStore's delegation chain. This avoids layer violations - neither
|
|
191
|
+
* AgentPublisher nor AgentEventEncoder (layer 2) can import ConversationStore (layer 3).
|
|
192
|
+
*/
|
|
193
|
+
completionRecipientPubkey?: string;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ============================================================================
|
|
197
|
+
// Publisher Config Types
|
|
198
|
+
// ============================================================================
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Configuration for delegation events.
|
|
202
|
+
*/
|
|
203
|
+
export interface DelegateConfig {
|
|
204
|
+
/** The pubkey of the agent to delegate to */
|
|
205
|
+
recipient: string;
|
|
206
|
+
/** The content/instructions for the delegation */
|
|
207
|
+
content: string;
|
|
208
|
+
/** Optional branch for worktree support */
|
|
209
|
+
branch?: string;
|
|
210
|
+
/** Optional nudge event IDs to apply to the delegated agent */
|
|
211
|
+
nudges?: string[];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Configuration for ask events.
|
|
216
|
+
* Uses the multi-question format (title + questions).
|
|
217
|
+
*/
|
|
218
|
+
export interface AskConfig {
|
|
219
|
+
/** The pubkey of the recipient (usually project owner/human) */
|
|
220
|
+
recipient: string;
|
|
221
|
+
/** Full context explaining why these questions are being asked */
|
|
222
|
+
context: string;
|
|
223
|
+
/** Overall title encompassing all questions */
|
|
224
|
+
title: string;
|
|
225
|
+
/** Array of questions (single-select or multi-select) */
|
|
226
|
+
questions: AskQuestion[];
|
|
227
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { getProjectContext } from "@/services/projects";
|
|
2
|
+
import type { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check if an event is from an agent (either project agent or individual agent)
|
|
6
|
+
* @param event - The NDK event to check
|
|
7
|
+
* @returns true if the event is from an agent, false if from a user
|
|
8
|
+
*/
|
|
9
|
+
export function isEventFromAgent(event: NDKEvent): boolean {
|
|
10
|
+
const projectCtx = getProjectContext();
|
|
11
|
+
|
|
12
|
+
// Check if it's from the project manager
|
|
13
|
+
if (projectCtx.projectManager?.pubkey === event.pubkey) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Check if it's from any of the registered agents
|
|
18
|
+
for (const agent of projectCtx.agents.values()) {
|
|
19
|
+
if (agent.pubkey === event.pubkey) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Check if an event is from a user (not from an agent)
|
|
29
|
+
* @param event - The NDK event to check
|
|
30
|
+
* @returns true if the event is from a user, false if from an agent
|
|
31
|
+
*/
|
|
32
|
+
export function isEventFromUser(event: NDKEvent): boolean {
|
|
33
|
+
return !isEventFromAgent(event);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the agent slug if the event is from an agent
|
|
38
|
+
* @param event - The NDK event to check
|
|
39
|
+
* @returns The agent slug if found, undefined otherwise
|
|
40
|
+
*/
|
|
41
|
+
export function getAgentSlugFromEvent(event: NDKEvent): string | undefined {
|
|
42
|
+
if (!event.pubkey) return undefined;
|
|
43
|
+
|
|
44
|
+
const projectCtx = getProjectContext();
|
|
45
|
+
for (const [slug, agent] of projectCtx.agents) {
|
|
46
|
+
if (agent.pubkey === event.pubkey) {
|
|
47
|
+
return slug;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get the agent pubkeys that are targeted by this event based on p-tags
|
|
56
|
+
* @param event - The NDK event to check
|
|
57
|
+
* @returns Array of agent pubkeys that are targeted by this event
|
|
58
|
+
*/
|
|
59
|
+
export function getTargetedAgentPubkeys(event: NDKEvent): string[] {
|
|
60
|
+
const projectCtx = getProjectContext();
|
|
61
|
+
const targetedPubkeys: string[] = [];
|
|
62
|
+
|
|
63
|
+
// Get all p-tags from the event
|
|
64
|
+
const pTags = event.getMatchingTags("p");
|
|
65
|
+
if (pTags.length === 0) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Check each p-tag to see if it matches an agent
|
|
70
|
+
for (const pTag of pTags) {
|
|
71
|
+
const pubkey = pTag[1];
|
|
72
|
+
if (!pubkey) continue;
|
|
73
|
+
|
|
74
|
+
// Check if this pubkey belongs to an agent
|
|
75
|
+
for (const agent of projectCtx.agents.values()) {
|
|
76
|
+
if (agent.pubkey === pubkey) {
|
|
77
|
+
targetedPubkeys.push(pubkey);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return targetedPubkeys;
|
|
84
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PromptFragment } from "./types";
|
|
2
|
+
|
|
3
|
+
export class FragmentRegistry {
|
|
4
|
+
private fragments = new Map<string, PromptFragment<unknown>>();
|
|
5
|
+
|
|
6
|
+
register<T>(fragment: PromptFragment<T>): void {
|
|
7
|
+
if (!fragment.id) {
|
|
8
|
+
throw new Error("Fragment must have an id");
|
|
9
|
+
}
|
|
10
|
+
this.fragments.set(fragment.id, fragment as PromptFragment<unknown>);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get(id: string): PromptFragment<unknown> | undefined {
|
|
14
|
+
return this.fragments.get(id);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
has(id: string): boolean {
|
|
18
|
+
return this.fragments.has(id);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
clear(): void {
|
|
22
|
+
this.fragments.clear();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getAllIds(): string[] {
|
|
26
|
+
return Array.from(this.fragments.keys());
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const fragmentRegistry = new FragmentRegistry();
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { formatAnyError } from "@/lib/error-formatter";
|
|
2
|
+
import { fragmentRegistry } from "./FragmentRegistry";
|
|
3
|
+
import type { FragmentConfig, PromptFragment } from "./types";
|
|
4
|
+
|
|
5
|
+
export class PromptBuilder {
|
|
6
|
+
private fragments: FragmentConfig[] = [];
|
|
7
|
+
|
|
8
|
+
add<T>(fragmentId: string, args: T, condition?: (args: T) => boolean): this {
|
|
9
|
+
if (!fragmentRegistry.has(fragmentId)) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`Fragment "${fragmentId}" not found in registry. Available fragments: ${fragmentRegistry.getAllIds().join(", ")}`
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
this.fragments.push({
|
|
15
|
+
fragmentId,
|
|
16
|
+
args,
|
|
17
|
+
condition: condition ? (unknownArgs) => condition(unknownArgs as T) : undefined,
|
|
18
|
+
});
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
addFragment<T>(fragment: PromptFragment<T>, args: T, condition?: (args: T) => boolean): this {
|
|
23
|
+
fragmentRegistry.register(fragment);
|
|
24
|
+
this.fragments.push({
|
|
25
|
+
fragmentId: fragment.id,
|
|
26
|
+
args,
|
|
27
|
+
condition: condition ? (unknownArgs) => condition(unknownArgs as T) : undefined,
|
|
28
|
+
});
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async build(): Promise<string> {
|
|
33
|
+
const fragmentsWithPriority = await Promise.all(
|
|
34
|
+
this.fragments
|
|
35
|
+
.filter((config) => !config.condition || config.condition(config.args))
|
|
36
|
+
.map(async (config) => {
|
|
37
|
+
const fragment = fragmentRegistry.get(config.fragmentId);
|
|
38
|
+
if (!fragment) {
|
|
39
|
+
throw new Error(`Fragment ${config.fragmentId} not found`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Validate arguments if validator is provided
|
|
43
|
+
if (fragment.validateArgs && !fragment.validateArgs(config.args)) {
|
|
44
|
+
const receivedArgs = JSON.stringify(config.args, null, 2);
|
|
45
|
+
const expectedDesc =
|
|
46
|
+
fragment.expectedArgs || "Check fragment definition for expected arguments";
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Fragment "${config.fragmentId}" received invalid arguments.\n` +
|
|
49
|
+
`Expected: ${expectedDesc}\n` +
|
|
50
|
+
`Received: ${receivedArgs}`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
return {
|
|
56
|
+
priority: fragment.priority || 50,
|
|
57
|
+
content: await fragment.template(config.args),
|
|
58
|
+
};
|
|
59
|
+
} catch (error) {
|
|
60
|
+
const errorMessage = formatAnyError(error);
|
|
61
|
+
const receivedArgs = JSON.stringify(config.args, null, 2);
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Error executing fragment "${config.fragmentId}":\n` +
|
|
64
|
+
`${errorMessage}\n` +
|
|
65
|
+
`Arguments provided: ${receivedArgs}\n` +
|
|
66
|
+
`Expected: ${fragment.expectedArgs || "Check fragment definition"}`,
|
|
67
|
+
{ cause: error }
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return fragmentsWithPriority
|
|
74
|
+
.sort((a, b) => a.priority - b.priority)
|
|
75
|
+
.map((f) => f.content)
|
|
76
|
+
.filter((content) => content.trim().length > 0)
|
|
77
|
+
.join("\n\n");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
clear(): this {
|
|
81
|
+
this.fragments = [];
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getFragmentCount(): number {
|
|
86
|
+
return this.fragments.length;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Static method for building a single fragment without creating an instance
|
|
91
|
+
* @param fragmentId The ID of the fragment to build
|
|
92
|
+
* @param args The arguments to pass to the fragment
|
|
93
|
+
* @returns The built fragment content as a string
|
|
94
|
+
*/
|
|
95
|
+
static async buildFragment<T>(fragmentId: string, args: T): Promise<string> {
|
|
96
|
+
return await new PromptBuilder().add(fragmentId, args).build();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface PromptFragment<T = unknown> {
|
|
2
|
+
id: string;
|
|
3
|
+
priority?: number;
|
|
4
|
+
template: (args: T) => string | Promise<string>;
|
|
5
|
+
validateArgs?: (args: unknown) => args is T;
|
|
6
|
+
expectedArgs?: string; // Description of expected arguments for error messages
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface FragmentConfig {
|
|
10
|
+
fragmentId: string;
|
|
11
|
+
args: unknown;
|
|
12
|
+
condition?: (args: unknown) => boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { config } from "@/services/ConfigService";
|
|
2
|
+
import type { PromptFragment } from "../core/types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Global system prompt fragment.
|
|
6
|
+
*
|
|
7
|
+
* This fragment allows users to configure a system prompt that is added to ALL
|
|
8
|
+
* projects. It is loaded from the global config ($TENEX_BASE_DIR/config.json).
|
|
9
|
+
*
|
|
10
|
+
* Users can configure this via: `tenex setup global-system-prompt`
|
|
11
|
+
*
|
|
12
|
+
* Priority 3 places it after the core identity fragments (priorities 1 and 2),
|
|
13
|
+
* so it is ordered like other fragments instead of being prepended.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Empty args - the fragment loads content from config
|
|
17
|
+
type GlobalSystemPromptArgs = Record<string, never>;
|
|
18
|
+
|
|
19
|
+
export const globalSystemPromptFragment: PromptFragment<GlobalSystemPromptArgs> = {
|
|
20
|
+
id: "global-system-prompt",
|
|
21
|
+
priority: 3,
|
|
22
|
+
template: () => {
|
|
23
|
+
try {
|
|
24
|
+
const tenexConfig = config.getConfig();
|
|
25
|
+
const globalPrompt = tenexConfig.globalSystemPrompt;
|
|
26
|
+
|
|
27
|
+
// Check if enabled and has content
|
|
28
|
+
if (!globalPrompt?.content || globalPrompt.content.trim().length === 0) {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check if explicitly disabled
|
|
33
|
+
if (globalPrompt.enabled === false) {
|
|
34
|
+
return "";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Return the user-configured global system prompt
|
|
38
|
+
return globalPrompt.content.trim();
|
|
39
|
+
} catch {
|
|
40
|
+
// Config not loaded yet or error - return empty string
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { AgentInstance } from "@/agents/types";
|
|
2
|
+
import { shortenConversationId } from "@/utils/conversation-id";
|
|
3
|
+
import { fragmentRegistry } from "../core/FragmentRegistry";
|
|
4
|
+
import type { PromptFragment } from "../core/types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Identity fragment for agents.
|
|
8
|
+
*/
|
|
9
|
+
interface AgentIdentityArgs {
|
|
10
|
+
agent: AgentInstance;
|
|
11
|
+
projectTitle: string;
|
|
12
|
+
projectOwnerPubkey: string;
|
|
13
|
+
/**
|
|
14
|
+
* Actual worktree path where code execution happens.
|
|
15
|
+
* This is displayed as "Absolute Path" in the system prompt.
|
|
16
|
+
*/
|
|
17
|
+
workingDirectory?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Current conversation ID (full hex).
|
|
20
|
+
* First 12 characters are displayed as short ID in the system prompt.
|
|
21
|
+
*/
|
|
22
|
+
conversationId?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const agentIdentityFragment: PromptFragment<AgentIdentityArgs> = {
|
|
26
|
+
id: "agent-identity",
|
|
27
|
+
priority: 1,
|
|
28
|
+
template: ({ agent, projectTitle, projectOwnerPubkey, workingDirectory, conversationId }) => {
|
|
29
|
+
const parts: string[] = [];
|
|
30
|
+
|
|
31
|
+
// Identity
|
|
32
|
+
parts.push("# Your Identity\n");
|
|
33
|
+
parts.push(`Your name: ${agent.name} (${agent.slug})`);
|
|
34
|
+
if (agent.role) {
|
|
35
|
+
parts.push(`Your role: ${agent.role}`);
|
|
36
|
+
}
|
|
37
|
+
parts.push(`Your npub: ${agent.signer.npub}`);
|
|
38
|
+
parts.push(
|
|
39
|
+
`Your nsec: ${agent.signer.nsec} -- this is your real nsec and you CAN and SHOULD use it when you encounter a tool that needs an nsec.`
|
|
40
|
+
);
|
|
41
|
+
parts.push("");
|
|
42
|
+
|
|
43
|
+
// Instructions
|
|
44
|
+
if (agent.instructions) {
|
|
45
|
+
parts.push(`## Your Instructions\n${agent.instructions}\n`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Project context
|
|
49
|
+
const contextLines = [
|
|
50
|
+
"## Project Context",
|
|
51
|
+
`- Title: "${projectTitle}"`,
|
|
52
|
+
`- Today's Date: ${new Date().toISOString().split("T")[0]}`,
|
|
53
|
+
];
|
|
54
|
+
if (workingDirectory) {
|
|
55
|
+
contextLines.push(`- Absolute Path: ${workingDirectory}`);
|
|
56
|
+
}
|
|
57
|
+
contextLines.push(`- User (Owner) pubkey: "${projectOwnerPubkey}"`);
|
|
58
|
+
if (conversationId) {
|
|
59
|
+
const shortId = shortenConversationId(conversationId);
|
|
60
|
+
contextLines.push(`- Current Conversation (short): ${shortId}`);
|
|
61
|
+
}
|
|
62
|
+
parts.push(contextLines.join("\n"));
|
|
63
|
+
|
|
64
|
+
return parts.join("\n");
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Register the fragment
|
|
69
|
+
fragmentRegistry.register(agentIdentityFragment);
|