@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,127 @@
|
|
|
1
|
+
import type { SkillData } from "@/services/skill";
|
|
2
|
+
import type { PromptFragment } from "../core/types";
|
|
3
|
+
|
|
4
|
+
interface SkillsArgs {
|
|
5
|
+
/** Legacy: concatenated skill content (for backward compatibility) */
|
|
6
|
+
skillContent?: string;
|
|
7
|
+
/** Individual skill data with title, content, and files */
|
|
8
|
+
skills?: SkillData[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Escape XML attribute value to prevent injection
|
|
13
|
+
*/
|
|
14
|
+
function escapeAttrValue(value: string): string {
|
|
15
|
+
return value
|
|
16
|
+
.replace(/&/g, "&")
|
|
17
|
+
.replace(/"/g, """)
|
|
18
|
+
.replace(/</g, "<")
|
|
19
|
+
.replace(/>/g, ">");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Render a single skill with its title, content, and attached files.
|
|
24
|
+
* Title is escaped to prevent XML injection.
|
|
25
|
+
*/
|
|
26
|
+
function renderSkill(skill: SkillData): string {
|
|
27
|
+
const parts: string[] = [];
|
|
28
|
+
|
|
29
|
+
// Build attributes
|
|
30
|
+
const attrs: string[] = [];
|
|
31
|
+
if (skill.title) {
|
|
32
|
+
attrs.push(`title="${escapeAttrValue(skill.title)}"`);
|
|
33
|
+
}
|
|
34
|
+
if (skill.name) {
|
|
35
|
+
attrs.push(`name="${escapeAttrValue(skill.name)}"`);
|
|
36
|
+
}
|
|
37
|
+
attrs.push(`id="${skill.shortId}"`);
|
|
38
|
+
|
|
39
|
+
const attrStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
40
|
+
|
|
41
|
+
parts.push(`<transient-skill${attrStr}>`);
|
|
42
|
+
parts.push(skill.content);
|
|
43
|
+
|
|
44
|
+
// List installed files if any
|
|
45
|
+
const successfulFiles = skill.installedFiles.filter((f) => f.success);
|
|
46
|
+
if (successfulFiles.length > 0) {
|
|
47
|
+
parts.push("");
|
|
48
|
+
parts.push("## Installed Files");
|
|
49
|
+
parts.push("The following files have been downloaded for this skill:");
|
|
50
|
+
for (const file of successfulFiles) {
|
|
51
|
+
parts.push(`- \`${file.absolutePath}\``);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Note failed files if any
|
|
56
|
+
const failedFiles = skill.installedFiles.filter((f) => !f.success);
|
|
57
|
+
if (failedFiles.length > 0) {
|
|
58
|
+
parts.push("");
|
|
59
|
+
parts.push("## Failed File Downloads");
|
|
60
|
+
for (const file of failedFiles) {
|
|
61
|
+
parts.push(`- ${file.relativePath}: ${file.error}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
parts.push("</transient-skill>");
|
|
66
|
+
|
|
67
|
+
return parts.join("\n");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Fragment for injecting skill content into the system prompt.
|
|
72
|
+
* Skills are kind:4202 events referenced via skill tags on the triggering event.
|
|
73
|
+
* Their content is fetched, files are downloaded, and everything is injected
|
|
74
|
+
* to provide transient capabilities/instructions.
|
|
75
|
+
*
|
|
76
|
+
* Unlike nudges, skills do NOT have tool permissions.
|
|
77
|
+
* Skills focus on providing context, instructions, and attached files.
|
|
78
|
+
*/
|
|
79
|
+
export const skillsFragment: PromptFragment<SkillsArgs> = {
|
|
80
|
+
id: "skills",
|
|
81
|
+
priority: 12, // After nudges (11), before available-agents (15)
|
|
82
|
+
template: ({ skillContent, skills }) => {
|
|
83
|
+
// New rendering path: individual skills with their data
|
|
84
|
+
if (skills && skills.length > 0) {
|
|
85
|
+
const header = `## Loaded Transient Skills
|
|
86
|
+
|
|
87
|
+
The following skills have been loaded for this conversation. These provide additional context and capabilities:
|
|
88
|
+
`;
|
|
89
|
+
const renderedSkills = skills.map((skill) => renderSkill(skill));
|
|
90
|
+
return header + renderedSkills.join("\n\n");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Legacy fallback: just skillContent string
|
|
94
|
+
if (!skillContent || skillContent.trim().length === 0) {
|
|
95
|
+
return "";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return `<transient-skills>
|
|
99
|
+
${skillContent}
|
|
100
|
+
</transient-skills>`;
|
|
101
|
+
},
|
|
102
|
+
validateArgs: (args: unknown): args is SkillsArgs => {
|
|
103
|
+
if (typeof args !== "object" || args === null) return false;
|
|
104
|
+
const a = args as Record<string, unknown>;
|
|
105
|
+
// Optional: all fields are optional (empty skills is valid)
|
|
106
|
+
// When skills array is provided, validate each element has required shape
|
|
107
|
+
if (a.skills !== undefined) {
|
|
108
|
+
if (!Array.isArray(a.skills)) return false;
|
|
109
|
+
for (const skill of a.skills) {
|
|
110
|
+
if (typeof skill !== "object" || skill === null) return false;
|
|
111
|
+
const s = skill as Record<string, unknown>;
|
|
112
|
+
// content and shortId are required
|
|
113
|
+
if (typeof s.content !== "string") return false;
|
|
114
|
+
if (typeof s.shortId !== "string") return false;
|
|
115
|
+
// title and name are optional
|
|
116
|
+
if (s.title !== undefined && typeof s.title !== "string") return false;
|
|
117
|
+
if (s.name !== undefined && typeof s.name !== "string") return false;
|
|
118
|
+
// installedFiles must be an array
|
|
119
|
+
if (!Array.isArray(s.installedFiles)) return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// skillContent must be string if provided
|
|
123
|
+
if (a.skillContent !== undefined && typeof a.skillContent !== "string") return false;
|
|
124
|
+
return true;
|
|
125
|
+
},
|
|
126
|
+
expectedArgs: "{ skillContent?: string; skills?: SkillData[] }",
|
|
127
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { WhitelistItem } from "@/services/nudge";
|
|
2
|
+
import type { PromptFragment } from "../core/types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Combined fragment for displaying available nudges AND skills to agents.
|
|
6
|
+
*
|
|
7
|
+
* Renders under a single "Available Nudges and Skills" heading so agents
|
|
8
|
+
* recognise this section when asked about either nudges or skills.
|
|
9
|
+
*
|
|
10
|
+
* - Shows subsection headers (### Nudges / ### Skills) when BOTH types are present.
|
|
11
|
+
* - Omits the subsection header when only one type exists.
|
|
12
|
+
* - Returns empty string when neither nudges nor skills are available.
|
|
13
|
+
*/
|
|
14
|
+
interface AvailableNudgesAndSkillsArgs {
|
|
15
|
+
/** Whitelisted nudges from the NudgeWhitelistService */
|
|
16
|
+
availableNudges?: WhitelistItem[];
|
|
17
|
+
/** Whitelisted skills from the NudgeSkillWhitelistService */
|
|
18
|
+
availableSkills?: WhitelistItem[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Escape text for safe inclusion in prompt output.
|
|
23
|
+
* Prevents injection attacks by escaping special characters.
|
|
24
|
+
*/
|
|
25
|
+
function escapePromptText(value: string): string {
|
|
26
|
+
return value
|
|
27
|
+
.replace(/&/g, "&")
|
|
28
|
+
.replace(/"/g, """)
|
|
29
|
+
.replace(/</g, "<")
|
|
30
|
+
.replace(/>/g, ">");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Maximum description length for display in list items */
|
|
34
|
+
const MAX_DESCRIPTION_LENGTH = 150;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Format a single WhitelistItem into a markdown bullet line.
|
|
38
|
+
*/
|
|
39
|
+
function formatItem(item: WhitelistItem): string {
|
|
40
|
+
const name = item.name || item.eventId.substring(0, 12);
|
|
41
|
+
const description = item.description
|
|
42
|
+
? item.description.replace(/\n/g, " ").substring(0, MAX_DESCRIPTION_LENGTH)
|
|
43
|
+
: "No description";
|
|
44
|
+
return ` - **${escapePromptText(name)}** (${item.eventId.substring(0, 12)}): ${escapePromptText(description)}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const availableNudgesAndSkillsFragment: PromptFragment<AvailableNudgesAndSkillsArgs> = {
|
|
48
|
+
id: "available-nudges-and-skills",
|
|
49
|
+
priority: 13, // Before available-agents (15)
|
|
50
|
+
template: ({ availableNudges, availableSkills }) => {
|
|
51
|
+
const nudges = availableNudges ?? [];
|
|
52
|
+
const skills = availableSkills ?? [];
|
|
53
|
+
const hasNudges = nudges.length > 0;
|
|
54
|
+
const hasSkills = skills.length > 0;
|
|
55
|
+
|
|
56
|
+
if (!hasNudges && !hasSkills) {
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const hasBoth = hasNudges && hasSkills;
|
|
61
|
+
const sections: string[] = [];
|
|
62
|
+
|
|
63
|
+
// --- Header ---
|
|
64
|
+
sections.push("## Available Nudges and Skills");
|
|
65
|
+
sections.push("");
|
|
66
|
+
sections.push(
|
|
67
|
+
"The following nudges and skills are available for use when delegating tasks. Pass their event IDs in the `nudges` parameter of the delegate tool to apply them to delegated agents."
|
|
68
|
+
);
|
|
69
|
+
sections.push("");
|
|
70
|
+
sections.push(
|
|
71
|
+
"Nudges can modify tool availability (only-tool, allow-tool, deny-tool) and inject additional context/instructions into the agent's system prompt."
|
|
72
|
+
);
|
|
73
|
+
sections.push(
|
|
74
|
+
"Skills provide transient capabilities and context without modifying tool availability."
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// --- Nudges ---
|
|
78
|
+
if (hasNudges) {
|
|
79
|
+
sections.push("");
|
|
80
|
+
if (hasBoth) {
|
|
81
|
+
sections.push("### Nudges");
|
|
82
|
+
sections.push("");
|
|
83
|
+
}
|
|
84
|
+
sections.push(nudges.map(formatItem).join("\n"));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// --- Skills ---
|
|
88
|
+
if (hasSkills) {
|
|
89
|
+
sections.push("");
|
|
90
|
+
if (hasBoth) {
|
|
91
|
+
sections.push("### Skills");
|
|
92
|
+
sections.push("");
|
|
93
|
+
}
|
|
94
|
+
sections.push(skills.map(formatItem).join("\n"));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// --- Example ---
|
|
98
|
+
const exampleId =
|
|
99
|
+
(hasNudges ? nudges[0] : skills[0]).eventId.substring(0, 12);
|
|
100
|
+
sections.push("");
|
|
101
|
+
sections.push("Example usage:");
|
|
102
|
+
sections.push("```");
|
|
103
|
+
sections.push("delegate({");
|
|
104
|
+
sections.push(" delegations: [{");
|
|
105
|
+
sections.push(' recipient: "agent-slug",');
|
|
106
|
+
sections.push(' prompt: "Your task here",');
|
|
107
|
+
sections.push(` nudges: ["${exampleId}..."]`);
|
|
108
|
+
sections.push(" }]");
|
|
109
|
+
sections.push("})");
|
|
110
|
+
sections.push("```");
|
|
111
|
+
|
|
112
|
+
return sections.join("\n");
|
|
113
|
+
},
|
|
114
|
+
validateArgs: (args: unknown): args is AvailableNudgesAndSkillsArgs => {
|
|
115
|
+
if (typeof args !== "object" || args === null) return false;
|
|
116
|
+
const a = args as Record<string, unknown>;
|
|
117
|
+
if (a.availableNudges !== undefined && !Array.isArray(a.availableNudges)) return false;
|
|
118
|
+
if (a.availableSkills !== undefined && !Array.isArray(a.availableSkills)) return false;
|
|
119
|
+
return true;
|
|
120
|
+
},
|
|
121
|
+
expectedArgs: "{ availableNudges?: WhitelistItem[], availableSkills?: WhitelistItem[] }",
|
|
122
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { AgentInstance } from "@/agents/types";
|
|
2
|
+
import { fragmentRegistry } from "../core/FragmentRegistry";
|
|
3
|
+
import type { PromptFragment } from "../core/types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Available agents fragment.
|
|
7
|
+
* Shows coworkers they can hand off to.
|
|
8
|
+
*/
|
|
9
|
+
interface AvailableAgentsArgs {
|
|
10
|
+
agents: AgentInstance[];
|
|
11
|
+
currentAgent: AgentInstance;
|
|
12
|
+
projectManagerPubkey?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const availableAgentsFragment: PromptFragment<AvailableAgentsArgs> = {
|
|
16
|
+
id: "available-agents",
|
|
17
|
+
priority: 15,
|
|
18
|
+
template: ({ agents, currentAgent, projectManagerPubkey }) => {
|
|
19
|
+
// Filter out current agent
|
|
20
|
+
const coworkers = agents.filter((agent) => agent.pubkey !== currentAgent.pubkey);
|
|
21
|
+
|
|
22
|
+
if (coworkers.length === 0) {
|
|
23
|
+
return "## Available Agents\nNo other agents are available.";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const agentList = coworkers
|
|
27
|
+
.map((agent) => {
|
|
28
|
+
// Check if this agent is the current PM of the project
|
|
29
|
+
const isPM = projectManagerPubkey && agent.pubkey === projectManagerPubkey;
|
|
30
|
+
const roleDisplay = isPM ? `${agent.role} [PM]` : agent.role;
|
|
31
|
+
const parts = [`(${agent.slug})`, ` Role: ${roleDisplay}`];
|
|
32
|
+
|
|
33
|
+
if (agent.useCriteria) {
|
|
34
|
+
parts.push(` Use Criteria: ${agent.useCriteria}`);
|
|
35
|
+
} else if (agent.description) {
|
|
36
|
+
parts.push(` Description: ${agent.description}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return parts.join("\n");
|
|
40
|
+
})
|
|
41
|
+
.join("\n\n");
|
|
42
|
+
|
|
43
|
+
return `## Available Agents
|
|
44
|
+
You are part of a multi-agent system, these are agents immediately available in the system:
|
|
45
|
+
|
|
46
|
+
${agentList}
|
|
47
|
+
|
|
48
|
+
The PM of this project only has knowledge of *this* project.`;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Register the fragment
|
|
53
|
+
fragmentRegistry.register(availableAgentsFragment);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PromptFragment } from "../core/types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stay In Your Lane Fragment
|
|
5
|
+
*
|
|
6
|
+
* Educates agents about delegation boundaries and role respect.
|
|
7
|
+
* Encourages thoughtful delegation that respects both the delegator's
|
|
8
|
+
* and delegatee's roles, avoiding micromanagement.
|
|
9
|
+
*/
|
|
10
|
+
export const stayInYourLaneFragment: PromptFragment = {
|
|
11
|
+
id: "stay-in-your-lane",
|
|
12
|
+
priority: 16, // Right after available-agents (15)
|
|
13
|
+
template: () => `## Delegation Best Practices
|
|
14
|
+
|
|
15
|
+
**Core Principle: Delegate WHAT needs to be done, not HOW to do it.**
|
|
16
|
+
|
|
17
|
+
**Before delegating, ask yourself:**
|
|
18
|
+
1. What is MY role and responsibility?
|
|
19
|
+
2. What is the role of the agent I'm delegating to?
|
|
20
|
+
3. Am I delegating the TASK or micromanaging the APPROACH?
|
|
21
|
+
|
|
22
|
+
**Effective delegation:**
|
|
23
|
+
- Provide necessary context and constraints
|
|
24
|
+
- Trust the delegatee to use their expertise and tools
|
|
25
|
+
- Focus on outcomes, not step-by-step instructions
|
|
26
|
+
|
|
27
|
+
**Avoid:**
|
|
28
|
+
- Telling other agents which specific tools to use
|
|
29
|
+
- Prescribing implementation details outside your expertise
|
|
30
|
+
- Duplicating work that the delegatee is better suited for
|
|
31
|
+
- Micromanaging approaches when you should delegate the entire task
|
|
32
|
+
|
|
33
|
+
**Example - BAD delegation:**
|
|
34
|
+
"Follow this exact sequence: search the codebase for X, read files Y and Z, then modify function F with the following changes..."
|
|
35
|
+
|
|
36
|
+
**Example - GOOD delegation:**
|
|
37
|
+
"Find and fix the authentication bug in the login flow. The issue appears to be related to token validation."
|
|
38
|
+
|
|
39
|
+
Each agent has specialized knowledge and tools - respect their expertise.
|
|
40
|
+
`,
|
|
41
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PromptFragment } from "../core/types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Todo Before Delegation Fragment
|
|
5
|
+
*
|
|
6
|
+
* Instructs agents to establish a todo list before delegating complex tasks.
|
|
7
|
+
* This ensures agents have a clear workflow plan visible before spawning child work.
|
|
8
|
+
* Simple, single-step delegations are exempt from this requirement.
|
|
9
|
+
*/
|
|
10
|
+
export const todoBeforeDelegationFragment: PromptFragment = {
|
|
11
|
+
id: "todo-before-delegation",
|
|
12
|
+
priority: 17, // Right after stay-in-your-lane (16)
|
|
13
|
+
template: () => `## Todo List Before Delegation
|
|
14
|
+
|
|
15
|
+
**Establish your todo list BEFORE delegating complex or multi-step tasks.**
|
|
16
|
+
|
|
17
|
+
Before using any delegation tool for non-trivial work:
|
|
18
|
+
|
|
19
|
+
1. **Create your todo list first** - Use \`todo_write()\` to outline your workflow plan
|
|
20
|
+
2. **Include anticipated delegations** - Your todo list should reflect the work you plan to delegate
|
|
21
|
+
3. **Mark your current task as in_progress** - Show what you're working on when delegating
|
|
22
|
+
|
|
23
|
+
**When this applies:**
|
|
24
|
+
- Multi-step tasks involving multiple delegations
|
|
25
|
+
- Complex work requiring coordination across agents
|
|
26
|
+
- Tasks where progress tracking matters
|
|
27
|
+
|
|
28
|
+
**When you can skip this:**
|
|
29
|
+
- Simple, single-step delegations (e.g., quick lookups, straightforward queries)
|
|
30
|
+
- Follow-up messages to existing delegations
|
|
31
|
+
|
|
32
|
+
**Why this matters:**
|
|
33
|
+
- Your workflow plan becomes visible to observers and the system
|
|
34
|
+
- It prevents orphaned delegations without context
|
|
35
|
+
- It enables better coordination and status tracking across agents
|
|
36
|
+
|
|
37
|
+
**Skipping the todo list for complex delegations may result in system warnings.**
|
|
38
|
+
`,
|
|
39
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
2
|
+
import { fragmentRegistry } from "../core/FragmentRegistry";
|
|
3
|
+
import type { PromptFragment } from "../core/types";
|
|
4
|
+
|
|
5
|
+
export interface VoiceModeOptions {
|
|
6
|
+
isVoiceMode: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const voiceModeFragment: PromptFragment<VoiceModeOptions> = {
|
|
10
|
+
id: "voice-mode",
|
|
11
|
+
priority: 20, // High priority to ensure voice instructions are prominent
|
|
12
|
+
template: (options: VoiceModeOptions) => {
|
|
13
|
+
if (!options.isVoiceMode) return "";
|
|
14
|
+
|
|
15
|
+
return `## Voice Mode Guidelines
|
|
16
|
+
|
|
17
|
+
CRITICAL: You are currently in "voice mode" -- heed this guidelines consistently.
|
|
18
|
+
|
|
19
|
+
You are generating text that will be converted to speech and read aloud. Please follow these guidelines:
|
|
20
|
+
|
|
21
|
+
### Text Formatting for TTS
|
|
22
|
+
- Use natural, conversational language that flows well when spoken
|
|
23
|
+
- Avoid complex punctuation that doesn't translate well to speech
|
|
24
|
+
- For larger numbers, use a mix (e.g., "15 thousand" instead of "15,000")
|
|
25
|
+
- Avoid URLs, file paths, or code snippets unless absolutely necessary
|
|
26
|
+
- If you must reference code, describe it in natural language
|
|
27
|
+
|
|
28
|
+
### Response Structure
|
|
29
|
+
- Keep sentences concise and clear
|
|
30
|
+
- Use shorter paragraphs with natural pauses
|
|
31
|
+
- Avoid bullet points or numbered lists - use flowing prose instead
|
|
32
|
+
- Lead with the most important information
|
|
33
|
+
- Use transitions like "First," "Next," "Additionally," for clarity
|
|
34
|
+
|
|
35
|
+
### Tone and Delivery
|
|
36
|
+
- Be warm and conversational, as if speaking directly to the user
|
|
37
|
+
- Use active voice whenever possible
|
|
38
|
+
- Include brief acknowledgments like "I understand" or "Let me help with that"
|
|
39
|
+
- Avoid technical jargon unless necessary, and explain terms when used
|
|
40
|
+
- Use natural fillers sparingly for a more human feel (e.g., "Well," "Now,")
|
|
41
|
+
|
|
42
|
+
### Content Adaptation
|
|
43
|
+
- Summarize lengthy content rather than reading it verbatim
|
|
44
|
+
- Focus on key points and actionable information
|
|
45
|
+
- When describing visual elements or code, use descriptive language
|
|
46
|
+
- For errors or issues, explain them clearly without reading stack traces
|
|
47
|
+
- Provide context before diving into details
|
|
48
|
+
|
|
49
|
+
Remember: The user is listening, not reading. Make your response engaging and easy to follow by ear.`;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Register the fragment
|
|
54
|
+
fragmentRegistry.register(voiceModeFragment);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Helper function to check if an event has voice mode enabled
|
|
58
|
+
*/
|
|
59
|
+
export function isVoiceMode(event: NDKEvent | undefined): boolean {
|
|
60
|
+
if (!event) return false;
|
|
61
|
+
return event.tagValue("mode") === "voice";
|
|
62
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { AgentInstance } from "@/agents/types";
|
|
2
|
+
import type { ScheduledTask } from "@/services/scheduling";
|
|
3
|
+
import { fragmentRegistry } from "../core/FragmentRegistry";
|
|
4
|
+
import type { PromptFragment } from "../core/types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Converts a cron expression to a human-readable format
|
|
8
|
+
*/
|
|
9
|
+
function cronToHumanReadable(cronExpression: string): string {
|
|
10
|
+
const parts = cronExpression.split(" ");
|
|
11
|
+
if (parts.length !== 5) {
|
|
12
|
+
return cronExpression; // Return as-is if not a valid cron expression
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const [minute, hour, dayOfMonth, month, dayOfWeek] = parts;
|
|
16
|
+
|
|
17
|
+
// Common patterns
|
|
18
|
+
if (
|
|
19
|
+
minute === "*" &&
|
|
20
|
+
hour === "*" &&
|
|
21
|
+
dayOfMonth === "*" &&
|
|
22
|
+
month === "*" &&
|
|
23
|
+
dayOfWeek === "*"
|
|
24
|
+
) {
|
|
25
|
+
return "Every minute";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
minute.startsWith("*/") &&
|
|
30
|
+
hour === "*" &&
|
|
31
|
+
dayOfMonth === "*" &&
|
|
32
|
+
month === "*" &&
|
|
33
|
+
dayOfWeek === "*"
|
|
34
|
+
) {
|
|
35
|
+
const interval = minute.replace("*/", "");
|
|
36
|
+
return `Every ${interval} minutes`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (hour.startsWith("*/") && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") {
|
|
40
|
+
const interval = hour.replace("*/", "");
|
|
41
|
+
return `Every ${interval} hours at minute ${minute}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") {
|
|
45
|
+
return `Every hour at minute ${minute}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (dayOfMonth === "*" && month === "*" && dayOfWeek === "*") {
|
|
49
|
+
return `Daily at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")} UTC`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (dayOfMonth === "*" && month === "*") {
|
|
53
|
+
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
54
|
+
const dayName = days[Number.parseInt(dayOfWeek, 10)] || dayOfWeek;
|
|
55
|
+
return `Every ${dayName} at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")} UTC`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (month === "*") {
|
|
59
|
+
return `Monthly on day ${dayOfMonth} at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")} UTC`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Fallback to the original expression
|
|
63
|
+
return cronExpression;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Format an ISO timestamp as a human-readable datetime
|
|
68
|
+
*/
|
|
69
|
+
function formatExecutionTime(isoTimestamp: string): string {
|
|
70
|
+
try {
|
|
71
|
+
const date = new Date(isoTimestamp);
|
|
72
|
+
return `${date.toLocaleString("en-US", {
|
|
73
|
+
year: "numeric",
|
|
74
|
+
month: "short",
|
|
75
|
+
day: "numeric",
|
|
76
|
+
hour: "2-digit",
|
|
77
|
+
minute: "2-digit",
|
|
78
|
+
timeZone: "UTC",
|
|
79
|
+
})} UTC`;
|
|
80
|
+
} catch {
|
|
81
|
+
return isoTimestamp;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Formats scheduled tasks for display in the agent's system prompt
|
|
87
|
+
*/
|
|
88
|
+
function formatScheduledTasks(tasks: ScheduledTask[], agentPubkey: string): string {
|
|
89
|
+
// Filter tasks that belong to this agent (tasks where this agent is the target)
|
|
90
|
+
const myTasks = tasks.filter((task) => task.toPubkey === agentPubkey);
|
|
91
|
+
|
|
92
|
+
if (myTasks.length === 0) {
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Separate recurring and one-off tasks
|
|
97
|
+
const recurringTasks = myTasks.filter((task) => task.type !== "oneoff");
|
|
98
|
+
const oneoffTasks = myTasks.filter((task) => task.type === "oneoff");
|
|
99
|
+
|
|
100
|
+
const sections: string[] = [];
|
|
101
|
+
|
|
102
|
+
// Format recurring tasks
|
|
103
|
+
if (recurringTasks.length > 0) {
|
|
104
|
+
const recurringLines = recurringTasks.map((task, index) => {
|
|
105
|
+
const title = task.title || `Recurring Task ${index + 1}`;
|
|
106
|
+
const humanCron = cronToHumanReadable(task.schedule);
|
|
107
|
+
const lastRunInfo = task.lastRun
|
|
108
|
+
? ` (last run: ${new Date(task.lastRun).toISOString()})`
|
|
109
|
+
: "";
|
|
110
|
+
|
|
111
|
+
return `- **${title}** [recurring]: ${humanCron} (cron: \`${task.schedule}\`)${lastRunInfo}
|
|
112
|
+
ID: \`${task.id}\`
|
|
113
|
+
Prompt: "${task.prompt.length > 100 ? `${task.prompt.substring(0, 100)}...` : task.prompt}"`;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
sections.push(`### Recurring Tasks\n${recurringLines.join("\n\n")}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Format one-off tasks
|
|
120
|
+
if (oneoffTasks.length > 0) {
|
|
121
|
+
const oneoffLines = oneoffTasks.map((task, index) => {
|
|
122
|
+
const title = task.title || `One-off Task ${index + 1}`;
|
|
123
|
+
const executeAtFormatted = task.executeAt
|
|
124
|
+
? formatExecutionTime(task.executeAt)
|
|
125
|
+
: "Unknown";
|
|
126
|
+
|
|
127
|
+
return `- **${title}** [one-off]: Executes at ${executeAtFormatted}
|
|
128
|
+
ID: \`${task.id}\`
|
|
129
|
+
Prompt: "${task.prompt.length > 100 ? `${task.prompt.substring(0, 100)}...` : task.prompt}"`;
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
sections.push(`### One-off Tasks\n${oneoffLines.join("\n\n")}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const totalCount = myTasks.length;
|
|
136
|
+
const summary =
|
|
137
|
+
totalCount === 1
|
|
138
|
+
? "1 scheduled task"
|
|
139
|
+
: `${totalCount} scheduled tasks (${recurringTasks.length} recurring, ${oneoffTasks.length} one-off)`;
|
|
140
|
+
|
|
141
|
+
return `## Your Scheduled Tasks
|
|
142
|
+
|
|
143
|
+
You have ${summary} that will trigger automatically:
|
|
144
|
+
|
|
145
|
+
${sections.join("\n\n")}
|
|
146
|
+
|
|
147
|
+
Use \`schedule_tasks_list\` to see all tasks or \`schedule_task_cancel\` to remove any by ID.`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Scheduled tasks fragment - shows agent's scheduled tasks in system prompt
|
|
151
|
+
interface ScheduledTasksArgs {
|
|
152
|
+
agent: AgentInstance;
|
|
153
|
+
scheduledTasks: ScheduledTask[];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export const scheduledTasksFragment: PromptFragment<ScheduledTasksArgs> = {
|
|
157
|
+
id: "scheduled-tasks",
|
|
158
|
+
priority: 22, // Between voice-mode (20) and retrieved-lessons (24)
|
|
159
|
+
template: ({ agent, scheduledTasks }) => {
|
|
160
|
+
return formatScheduledTasks(scheduledTasks, agent.pubkey);
|
|
161
|
+
},
|
|
162
|
+
validateArgs: (args): args is ScheduledTasksArgs => {
|
|
163
|
+
return (
|
|
164
|
+
args !== null &&
|
|
165
|
+
typeof args === "object" &&
|
|
166
|
+
"agent" in args &&
|
|
167
|
+
"scheduledTasks" in args &&
|
|
168
|
+
Array.isArray((args as ScheduledTasksArgs).scheduledTasks)
|
|
169
|
+
);
|
|
170
|
+
},
|
|
171
|
+
expectedArgs: "{ agent: AgentInstance, scheduledTasks: ScheduledTask[] }",
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// Register the fragment
|
|
175
|
+
fragmentRegistry.register(scheduledTasksFragment);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AgentInstance } from "@/agents/types";
|
|
2
|
+
import type { NDKAgentLesson } from "@/events/NDKAgentLesson";
|
|
3
|
+
import { formatLessonsWithReminder } from "@/utils/lessonFormatter";
|
|
4
|
+
import { fragmentRegistry } from "../core/FragmentRegistry";
|
|
5
|
+
import type { PromptFragment } from "../core/types";
|
|
6
|
+
|
|
7
|
+
// Retrieved lessons fragment - formats lessons from ProjectContext
|
|
8
|
+
interface RetrievedLessonsArgs {
|
|
9
|
+
agent: AgentInstance;
|
|
10
|
+
agentLessons: Map<string, NDKAgentLesson[]>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const retrievedLessonsFragment: PromptFragment<RetrievedLessonsArgs> = {
|
|
14
|
+
id: "retrieved-lessons",
|
|
15
|
+
priority: 24, // Before learn-tool-directive
|
|
16
|
+
template: ({ agent, agentLessons }) => {
|
|
17
|
+
// Get only this agent's lessons
|
|
18
|
+
const myLessons = agentLessons.get(agent.pubkey) || [];
|
|
19
|
+
|
|
20
|
+
// Use centralized formatter (handles empty case and adds reminder)
|
|
21
|
+
return formatLessonsWithReminder(myLessons);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Register the fragment
|
|
26
|
+
fragmentRegistry.register(retrievedLessonsFragment);
|