@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.
Files changed (427) hide show
  1. package/README.md +194 -0
  2. package/dist/backend-wrapper.cjs +3 -0
  3. package/dist/src/index.js +331928 -0
  4. package/package.json +103 -0
  5. package/src/agents/AgentRegistry.ts +418 -0
  6. package/src/agents/AgentStorage.ts +1133 -0
  7. package/src/agents/ConfigResolver.ts +229 -0
  8. package/src/agents/agent-installer.ts +236 -0
  9. package/src/agents/agent-loader.ts +241 -0
  10. package/src/agents/constants.ts +82 -0
  11. package/src/agents/errors.ts +48 -0
  12. package/src/agents/execution/AgentExecutor.ts +561 -0
  13. package/src/agents/execution/ExecutionContextFactory.ts +112 -0
  14. package/src/agents/execution/MessageCompiler.ts +597 -0
  15. package/src/agents/execution/MessageSyncer.ts +100 -0
  16. package/src/agents/execution/PostCompletionChecker.ts +278 -0
  17. package/src/agents/execution/ProgressMonitor.ts +50 -0
  18. package/src/agents/execution/RALResolver.ts +177 -0
  19. package/src/agents/execution/SessionManager.ts +181 -0
  20. package/src/agents/execution/StreamCallbacks.ts +312 -0
  21. package/src/agents/execution/StreamExecutionHandler.ts +579 -0
  22. package/src/agents/execution/StreamSetup.ts +313 -0
  23. package/src/agents/execution/ToolEventHandlers.ts +239 -0
  24. package/src/agents/execution/ToolExecutionTracker.ts +498 -0
  25. package/src/agents/execution/ToolResultUtils.ts +97 -0
  26. package/src/agents/execution/ToolSupervisionWrapper.ts +174 -0
  27. package/src/agents/execution/constants.ts +16 -0
  28. package/src/agents/execution/index.ts +3 -0
  29. package/src/agents/execution/types.ts +96 -0
  30. package/src/agents/execution/utils.ts +26 -0
  31. package/src/agents/index.ts +4 -0
  32. package/src/agents/script-installer.ts +266 -0
  33. package/src/agents/supervision/SupervisorLLMService.ts +253 -0
  34. package/src/agents/supervision/SupervisorOrchestrator.ts +471 -0
  35. package/src/agents/supervision/heuristics/ConsecutiveToolsWithoutTodoHeuristic.ts +73 -0
  36. package/src/agents/supervision/heuristics/DelegationClaimHeuristic.ts +80 -0
  37. package/src/agents/supervision/heuristics/HeuristicRegistry.ts +114 -0
  38. package/src/agents/supervision/heuristics/PendingTodosHeuristic.ts +93 -0
  39. package/src/agents/supervision/heuristics/SilentAgentHeuristic.ts +54 -0
  40. package/src/agents/supervision/heuristics/index.ts +5 -0
  41. package/src/agents/supervision/index.ts +28 -0
  42. package/src/agents/supervision/registerHeuristics.ts +110 -0
  43. package/src/agents/supervision/supervisionHealthCheck.ts +123 -0
  44. package/src/agents/supervision/types.ts +171 -0
  45. package/src/agents/tool-names.ts +46 -0
  46. package/src/agents/tool-normalization.ts +184 -0
  47. package/src/agents/types/index.ts +2 -0
  48. package/src/agents/types/runtime.ts +74 -0
  49. package/src/agents/types/storage.ts +145 -0
  50. package/src/commands/agent/import/index.ts +6 -0
  51. package/src/commands/agent/import/openclaw-distiller.ts +57 -0
  52. package/src/commands/agent/import/openclaw-reader.ts +141 -0
  53. package/src/commands/agent/import/openclaw.ts +154 -0
  54. package/src/commands/agent/index.ts +6 -0
  55. package/src/commands/agent.ts +215 -0
  56. package/src/commands/daemon.ts +198 -0
  57. package/src/commands/doctor.ts +134 -0
  58. package/src/commands/setup/embed.ts +228 -0
  59. package/src/commands/setup/global-system-prompt.ts +223 -0
  60. package/src/commands/setup/image.ts +179 -0
  61. package/src/commands/setup/index.ts +16 -0
  62. package/src/commands/setup/interactive.ts +95 -0
  63. package/src/commands/setup/llm.ts +38 -0
  64. package/src/commands/setup/onboarding.ts +294 -0
  65. package/src/commands/setup/providers.ts +27 -0
  66. package/src/constants.ts +34 -0
  67. package/src/conversations/ConversationDiskReader.ts +148 -0
  68. package/src/conversations/ConversationRegistry.ts +728 -0
  69. package/src/conversations/ConversationStore.ts +868 -0
  70. package/src/conversations/MessageBuilder.ts +866 -0
  71. package/src/conversations/executionTime.ts +62 -0
  72. package/src/conversations/formatters/DelegationXmlFormatter.ts +64 -0
  73. package/src/conversations/formatters/ThreadedConversationFormatter.ts +303 -0
  74. package/src/conversations/formatters/index.ts +9 -0
  75. package/src/conversations/formatters/utils/MessageFormatter.ts +46 -0
  76. package/src/conversations/formatters/utils/TimestampFormatter.ts +56 -0
  77. package/src/conversations/formatters/utils/TreeBuilder.ts +131 -0
  78. package/src/conversations/formatters/utils/TreeRenderer.ts +49 -0
  79. package/src/conversations/index.ts +2 -0
  80. package/src/conversations/persistence/ToolMessageStorage.ts +143 -0
  81. package/src/conversations/search/ConversationIndexManager.ts +393 -0
  82. package/src/conversations/search/QueryParser.ts +114 -0
  83. package/src/conversations/search/SearchEngine.ts +175 -0
  84. package/src/conversations/search/SnippetExtractor.ts +345 -0
  85. package/src/conversations/search/embeddings/ConversationEmbeddingService.ts +484 -0
  86. package/src/conversations/search/embeddings/ConversationIndexingJob.ts +320 -0
  87. package/src/conversations/search/embeddings/IndexingStateManager.ts +338 -0
  88. package/src/conversations/search/embeddings/index.ts +18 -0
  89. package/src/conversations/search/index.ts +49 -0
  90. package/src/conversations/search/types.ts +124 -0
  91. package/src/conversations/services/CategoryManager.ts +160 -0
  92. package/src/conversations/services/ConversationResolver.ts +296 -0
  93. package/src/conversations/services/ConversationSummarizer.ts +234 -0
  94. package/src/conversations/services/MetadataDebounceManager.ts +188 -0
  95. package/src/conversations/services/index.ts +2 -0
  96. package/src/conversations/types.ts +148 -0
  97. package/src/conversations/utils/content-utils.ts +69 -0
  98. package/src/conversations/utils/image-placeholder.ts +281 -0
  99. package/src/conversations/utils/image-url-utils.ts +171 -0
  100. package/src/conversations/utils/multimodal-content.ts +90 -0
  101. package/src/conversations/utils/tool-result-truncator.ts +159 -0
  102. package/src/daemon/Daemon.ts +1883 -0
  103. package/src/daemon/ProjectRuntime.ts +657 -0
  104. package/src/daemon/RestartState.ts +152 -0
  105. package/src/daemon/RuntimeLifecycle.ts +268 -0
  106. package/src/daemon/SubscriptionManager.ts +305 -0
  107. package/src/daemon/UnixSocketTransport.ts +318 -0
  108. package/src/daemon/filters/SubscriptionFilterBuilder.ts +119 -0
  109. package/src/daemon/index.ts +9 -0
  110. package/src/daemon/routing/DaemonRouter.ts +491 -0
  111. package/src/daemon/types.ts +150 -0
  112. package/src/daemon/utils/routing-log.ts +76 -0
  113. package/src/daemon/utils/telemetry.ts +173 -0
  114. package/src/event-handler/agentDeletion.ts +383 -0
  115. package/src/event-handler/index.ts +749 -0
  116. package/src/event-handler/newConversation.ts +165 -0
  117. package/src/event-handler/project.ts +166 -0
  118. package/src/event-handler/reply.ts +18 -0
  119. package/src/events/NDKAgentDefinition.ts +292 -0
  120. package/src/events/NDKAgentLesson.ts +106 -0
  121. package/src/events/NDKEventMetadata.ts +34 -0
  122. package/src/events/NDKMCPTool.ts +60 -0
  123. package/src/events/NDKProjectStatus.ts +384 -0
  124. package/src/events/index.ts +4 -0
  125. package/src/index.ts +126 -0
  126. package/src/lib/agent-home.ts +334 -0
  127. package/src/lib/error-formatter.ts +200 -0
  128. package/src/lib/fs/filesystem.ts +128 -0
  129. package/src/lib/fs/index.ts +1 -0
  130. package/src/lib/json-parser.ts +30 -0
  131. package/src/lib/string.ts +15 -0
  132. package/src/lib/time.ts +74 -0
  133. package/src/llm/ChunkHandler.ts +277 -0
  134. package/src/llm/FinishHandler.ts +250 -0
  135. package/src/llm/LLMConfigEditor.ts +154 -0
  136. package/src/llm/LLMServiceFactory.ts +230 -0
  137. package/src/llm/MessageProcessor.ts +90 -0
  138. package/src/llm/RecordingState.ts +37 -0
  139. package/src/llm/StreamPublisher.ts +40 -0
  140. package/src/llm/TracingUtils.ts +77 -0
  141. package/src/llm/chunk-validators.ts +57 -0
  142. package/src/llm/constants.ts +6 -0
  143. package/src/llm/index.ts +12 -0
  144. package/src/llm/meta/MetaModelResolver.ts +352 -0
  145. package/src/llm/meta/index.ts +11 -0
  146. package/src/llm/middleware/flight-recorder.ts +188 -0
  147. package/src/llm/providers/MockProvider.ts +332 -0
  148. package/src/llm/providers/agent/ClaudeCodeProvider.ts +343 -0
  149. package/src/llm/providers/agent/ClaudeCodeToolsAdapter.ts +203 -0
  150. package/src/llm/providers/agent/CodexAppServerProvider.ts +214 -0
  151. package/src/llm/providers/agent/CodexAppServerToolsAdapter.ts +91 -0
  152. package/src/llm/providers/agent/index.ts +10 -0
  153. package/src/llm/providers/base/AgentProvider.ts +107 -0
  154. package/src/llm/providers/base/BaseProvider.ts +114 -0
  155. package/src/llm/providers/base/StandardProvider.ts +38 -0
  156. package/src/llm/providers/base/index.ts +9 -0
  157. package/src/llm/providers/index.ts +106 -0
  158. package/src/llm/providers/key-manager.ts +238 -0
  159. package/src/llm/providers/ollama-models.ts +105 -0
  160. package/src/llm/providers/openrouter-models.ts +102 -0
  161. package/src/llm/providers/provider-ids.ts +18 -0
  162. package/src/llm/providers/registry/ProviderRegistry.ts +414 -0
  163. package/src/llm/providers/registry/index.ts +7 -0
  164. package/src/llm/providers/standard/AnthropicProvider.ts +71 -0
  165. package/src/llm/providers/standard/OllamaProvider.ts +59 -0
  166. package/src/llm/providers/standard/OpenAIProvider.ts +44 -0
  167. package/src/llm/providers/standard/OpenRouterProvider.ts +103 -0
  168. package/src/llm/providers/standard/index.ts +10 -0
  169. package/src/llm/providers/types.ts +194 -0
  170. package/src/llm/providers/usage-metadata.ts +78 -0
  171. package/src/llm/service.ts +713 -0
  172. package/src/llm/types.ts +167 -0
  173. package/src/llm/utils/ConfigurationManager.ts +650 -0
  174. package/src/llm/utils/ConfigurationTester.ts +229 -0
  175. package/src/llm/utils/ModelSelector.ts +212 -0
  176. package/src/llm/utils/ProviderConfigUI.ts +177 -0
  177. package/src/llm/utils/claudeCodePromptCompiler.ts +141 -0
  178. package/src/llm/utils/codex-models.ts +53 -0
  179. package/src/llm/utils/context-window-cache.ts +30 -0
  180. package/src/llm/utils/models-dev-cache.ts +267 -0
  181. package/src/llm/utils/provider-setup.ts +50 -0
  182. package/src/llm/utils/tool-errors.ts +78 -0
  183. package/src/llm/utils/usage.ts +74 -0
  184. package/src/logging/EventRoutingLogger.ts +205 -0
  185. package/src/nostr/AgentEventDecoder.ts +357 -0
  186. package/src/nostr/AgentEventEncoder.ts +677 -0
  187. package/src/nostr/AgentProfilePublisher.ts +657 -0
  188. package/src/nostr/AgentPublisher.ts +437 -0
  189. package/src/nostr/BlossomService.ts +226 -0
  190. package/src/nostr/InterventionPublisher.ts +132 -0
  191. package/src/nostr/TagExtractor.ts +228 -0
  192. package/src/nostr/collectEvents.ts +83 -0
  193. package/src/nostr/constants.ts +38 -0
  194. package/src/nostr/encryption.ts +26 -0
  195. package/src/nostr/index.ts +31 -0
  196. package/src/nostr/keys.ts +17 -0
  197. package/src/nostr/kinds.ts +37 -0
  198. package/src/nostr/ndkClient.ts +72 -0
  199. package/src/nostr/relays.ts +43 -0
  200. package/src/nostr/trace-context.ts +39 -0
  201. package/src/nostr/types.ts +227 -0
  202. package/src/nostr/utils.ts +84 -0
  203. package/src/prompts/core/FragmentRegistry.ts +30 -0
  204. package/src/prompts/core/PromptBuilder.ts +98 -0
  205. package/src/prompts/core/index.ts +3 -0
  206. package/src/prompts/core/types.ts +13 -0
  207. package/src/prompts/fragments/00-global-system-prompt.ts +44 -0
  208. package/src/prompts/fragments/01-agent-identity.ts +69 -0
  209. package/src/prompts/fragments/02-agent-home-directory.ts +114 -0
  210. package/src/prompts/fragments/03-system-reminders-explanation.ts +14 -0
  211. package/src/prompts/fragments/04-relay-configuration.ts +38 -0
  212. package/src/prompts/fragments/05-delegation-chain.ts +45 -0
  213. package/src/prompts/fragments/06-agent-todos.ts +74 -0
  214. package/src/prompts/fragments/06-todo-usage-guidance.ts +34 -0
  215. package/src/prompts/fragments/07-meta-project-context.ts +234 -0
  216. package/src/prompts/fragments/08-active-conversations.ts +382 -0
  217. package/src/prompts/fragments/09-recent-conversations.ts +153 -0
  218. package/src/prompts/fragments/10-referenced-article.ts +21 -0
  219. package/src/prompts/fragments/11-nudges.ts +134 -0
  220. package/src/prompts/fragments/12-skills.ts +127 -0
  221. package/src/prompts/fragments/13-available-nudges.ts +122 -0
  222. package/src/prompts/fragments/15-available-agents.ts +53 -0
  223. package/src/prompts/fragments/16-stay-in-your-lane.ts +41 -0
  224. package/src/prompts/fragments/17-todo-before-delegation.ts +39 -0
  225. package/src/prompts/fragments/20-voice-mode.ts +62 -0
  226. package/src/prompts/fragments/22-scheduled-tasks.ts +175 -0
  227. package/src/prompts/fragments/24-retrieved-lessons.ts +26 -0
  228. package/src/prompts/fragments/25-rag-instructions.ts +333 -0
  229. package/src/prompts/fragments/26-mcp-resources.ts +237 -0
  230. package/src/prompts/fragments/27-memorized-reports.ts +77 -0
  231. package/src/prompts/fragments/28-agent-directed-monitoring.ts +32 -0
  232. package/src/prompts/fragments/29-rag-collections.ts +50 -0
  233. package/src/prompts/fragments/30-worktree-context.ts +98 -0
  234. package/src/prompts/fragments/31-agents-md-guidance.ts +96 -0
  235. package/src/prompts/fragments/32-process-metrics.ts +72 -0
  236. package/src/prompts/fragments/debug-mode.ts +48 -0
  237. package/src/prompts/fragments/delegation-completion.ts +44 -0
  238. package/src/prompts/fragments/index.ts +91 -0
  239. package/src/prompts/index.ts +21 -0
  240. package/src/prompts/utils/systemPromptBuilder.ts +777 -0
  241. package/src/scripts/migrate-prefix-index.ts +157 -0
  242. package/src/services/AgentDefinitionMonitor.ts +701 -0
  243. package/src/services/ConfigService.ts +723 -0
  244. package/src/services/CooldownRegistry.ts +199 -0
  245. package/src/services/LLMOperationsRegistry.ts +424 -0
  246. package/src/services/OwnerAgentListService.ts +354 -0
  247. package/src/services/PubkeyService.ts +308 -0
  248. package/src/services/agents/AgentMetadataStore.ts +72 -0
  249. package/src/services/agents/AgentResolution.ts +59 -0
  250. package/src/services/agents/EscalationService.ts +281 -0
  251. package/src/services/agents/NDKAgentDiscovery.ts +95 -0
  252. package/src/services/agents/index.ts +7 -0
  253. package/src/services/agents-md/AgentsMdService.ts +184 -0
  254. package/src/services/agents-md/SystemReminderInjector.ts +238 -0
  255. package/src/services/agents-md/index.ts +11 -0
  256. package/src/services/apns/APNsClient.ts +203 -0
  257. package/src/services/apns/APNsService.ts +358 -0
  258. package/src/services/apns/index.ts +11 -0
  259. package/src/services/apns/types.ts +80 -0
  260. package/src/services/compression/CompressionService.ts +445 -0
  261. package/src/services/compression/compression-schema.ts +28 -0
  262. package/src/services/compression/compression-types.ts +74 -0
  263. package/src/services/compression/compression-utils.ts +587 -0
  264. package/src/services/config/types.ts +394 -0
  265. package/src/services/dispatch/AgentDispatchService.ts +937 -0
  266. package/src/services/dispatch/AgentRouter.ts +181 -0
  267. package/src/services/dispatch/DelegationCompletionHandler.ts +232 -0
  268. package/src/services/embedding/EmbeddingProvider.ts +188 -0
  269. package/src/services/embedding/index.ts +5 -0
  270. package/src/services/event-context/EventContextService.ts +108 -0
  271. package/src/services/event-context/index.ts +2 -0
  272. package/src/services/heuristics/ContextBuilder.ts +106 -0
  273. package/src/services/heuristics/HeuristicEngine.ts +200 -0
  274. package/src/services/heuristics/formatters.ts +58 -0
  275. package/src/services/heuristics/index.ts +12 -0
  276. package/src/services/heuristics/rules/index.ts +25 -0
  277. package/src/services/heuristics/rules/todoBeforeDelegation.ts +69 -0
  278. package/src/services/heuristics/rules/todoReminderOnToolUse.ts +63 -0
  279. package/src/services/heuristics/types.ts +144 -0
  280. package/src/services/image/ImageGenerationService.ts +389 -0
  281. package/src/services/image/index.ts +12 -0
  282. package/src/services/intervention/InterventionService.ts +1352 -0
  283. package/src/services/intervention/index.ts +7 -0
  284. package/src/services/mcp/MCPManager.ts +683 -0
  285. package/src/services/mcp/McpNotificationDelivery.ts +139 -0
  286. package/src/services/mcp/McpSubscriptionService.ts +653 -0
  287. package/src/services/mcp/mcpInstaller.ts +130 -0
  288. package/src/services/nip46/Nip46SigningLog.ts +81 -0
  289. package/src/services/nip46/Nip46SigningService.ts +467 -0
  290. package/src/services/nip46/index.ts +4 -0
  291. package/src/services/nudge/NudgeService.ts +224 -0
  292. package/src/services/nudge/NudgeWhitelistService.ts +382 -0
  293. package/src/services/nudge/index.ts +5 -0
  294. package/src/services/nudge/types.ts +83 -0
  295. package/src/services/projects/ProjectContext.ts +672 -0
  296. package/src/services/projects/ProjectContextStore.ts +102 -0
  297. package/src/services/projects/index.ts +6 -0
  298. package/src/services/prompt-compiler/index.ts +15 -0
  299. package/src/services/prompt-compiler/prompt-compiler-service.ts +1143 -0
  300. package/src/services/pubkey-gate/PubkeyGateService.ts +93 -0
  301. package/src/services/pubkey-gate/index.ts +1 -0
  302. package/src/services/rag/EmbeddingProviderFactory.ts +292 -0
  303. package/src/services/rag/LanceDBMaintenanceService.ts +211 -0
  304. package/src/services/rag/RAGDatabaseService.ts +173 -0
  305. package/src/services/rag/RAGOperations.ts +682 -0
  306. package/src/services/rag/RAGService.ts +240 -0
  307. package/src/services/rag/RagSubscriptionService.ts +618 -0
  308. package/src/services/rag/rag-utils.ts +174 -0
  309. package/src/services/ral/PendingDelegationsRegistry.ts +168 -0
  310. package/src/services/ral/RALRegistry.ts +2782 -0
  311. package/src/services/ral/index.ts +4 -0
  312. package/src/services/ral/types.ts +292 -0
  313. package/src/services/reports/LocalReportStore.ts +380 -0
  314. package/src/services/reports/ReportEmbeddingService.ts +430 -0
  315. package/src/services/reports/ReportService.ts +440 -0
  316. package/src/services/reports/articleUtils.ts +52 -0
  317. package/src/services/reports/index.ts +7 -0
  318. package/src/services/scheduling/SchedulerService.ts +1057 -0
  319. package/src/services/scheduling/errors.ts +14 -0
  320. package/src/services/scheduling/index.ts +7 -0
  321. package/src/services/scheduling/utils.ts +77 -0
  322. package/src/services/search/SearchProviderRegistry.ts +78 -0
  323. package/src/services/search/UnifiedSearchService.ts +218 -0
  324. package/src/services/search/index.ts +47 -0
  325. package/src/services/search/projectFilter.ts +22 -0
  326. package/src/services/search/providers/ConversationSearchProvider.ts +48 -0
  327. package/src/services/search/providers/LessonSearchProvider.ts +75 -0
  328. package/src/services/search/providers/ReportSearchProvider.ts +49 -0
  329. package/src/services/search/types.ts +144 -0
  330. package/src/services/skill/SkillService.ts +482 -0
  331. package/src/services/skill/index.ts +2 -0
  332. package/src/services/skill/types.ts +70 -0
  333. package/src/services/status/OperationsStatusService.ts +276 -0
  334. package/src/services/status/ProjectStatusService.ts +522 -0
  335. package/src/services/status/index.ts +11 -0
  336. package/src/services/storage/PrefixKVStore.ts +242 -0
  337. package/src/services/storage/index.ts +1 -0
  338. package/src/services/system-reminder/SystemReminderUtils.ts +96 -0
  339. package/src/services/system-reminder/index.ts +7 -0
  340. package/src/services/trust-pubkeys/TrustPubkeyService.ts +325 -0
  341. package/src/services/trust-pubkeys/index.ts +2 -0
  342. package/src/telemetry/ConversationSpanManager.ts +111 -0
  343. package/src/telemetry/EventLoopMonitor.ts +206 -0
  344. package/src/telemetry/LLMSpanRegistry.ts +20 -0
  345. package/src/telemetry/NostrSpanProcessor.ts +89 -0
  346. package/src/telemetry/ToolCallSpanProcessor.ts +66 -0
  347. package/src/telemetry/diagnostics.ts +27 -0
  348. package/src/telemetry/setup.ts +120 -0
  349. package/src/tools/implementations/agents_discover.ts +121 -0
  350. package/src/tools/implementations/agents_hire.ts +127 -0
  351. package/src/tools/implementations/agents_list.ts +96 -0
  352. package/src/tools/implementations/agents_publish.ts +611 -0
  353. package/src/tools/implementations/agents_read.ts +173 -0
  354. package/src/tools/implementations/agents_write.ts +200 -0
  355. package/src/tools/implementations/ask.ts +411 -0
  356. package/src/tools/implementations/change_model.ts +141 -0
  357. package/src/tools/implementations/conversation_get.ts +661 -0
  358. package/src/tools/implementations/conversation_list.ts +377 -0
  359. package/src/tools/implementations/conversation_search.ts +370 -0
  360. package/src/tools/implementations/delegate.ts +327 -0
  361. package/src/tools/implementations/delegate_crossproject.ts +209 -0
  362. package/src/tools/implementations/delegate_followup.ts +300 -0
  363. package/src/tools/implementations/fs_edit.ts +162 -0
  364. package/src/tools/implementations/fs_glob.ts +182 -0
  365. package/src/tools/implementations/fs_grep.ts +513 -0
  366. package/src/tools/implementations/fs_read.ts +332 -0
  367. package/src/tools/implementations/fs_write.ts +113 -0
  368. package/src/tools/implementations/generate_image.ts +259 -0
  369. package/src/tools/implementations/home_fs.ts +515 -0
  370. package/src/tools/implementations/kill.ts +651 -0
  371. package/src/tools/implementations/learn.ts +166 -0
  372. package/src/tools/implementations/lesson-formatter.ts +38 -0
  373. package/src/tools/implementations/lesson_delete.ts +164 -0
  374. package/src/tools/implementations/lesson_get.ts +105 -0
  375. package/src/tools/implementations/lessons_list.ts +153 -0
  376. package/src/tools/implementations/mcp_resource_read.ts +161 -0
  377. package/src/tools/implementations/mcp_subscribe.ts +158 -0
  378. package/src/tools/implementations/mcp_subscription_stop.ts +85 -0
  379. package/src/tools/implementations/nostr_fetch.ts +149 -0
  380. package/src/tools/implementations/nostr_publish_as_user.ts +353 -0
  381. package/src/tools/implementations/project_list.ts +146 -0
  382. package/src/tools/implementations/rag_add_documents.ts +573 -0
  383. package/src/tools/implementations/rag_create_collection.ts +65 -0
  384. package/src/tools/implementations/rag_delete_collection.ts +68 -0
  385. package/src/tools/implementations/rag_list_collections.ts +77 -0
  386. package/src/tools/implementations/rag_query.ts +107 -0
  387. package/src/tools/implementations/rag_subscription_create.ts +105 -0
  388. package/src/tools/implementations/rag_subscription_delete.ts +80 -0
  389. package/src/tools/implementations/rag_subscription_get.ts +123 -0
  390. package/src/tools/implementations/rag_subscription_list.ts +128 -0
  391. package/src/tools/implementations/report_delete.ts +79 -0
  392. package/src/tools/implementations/report_read.ts +160 -0
  393. package/src/tools/implementations/report_write.ts +278 -0
  394. package/src/tools/implementations/reports_list.ts +77 -0
  395. package/src/tools/implementations/schedule_task.ts +104 -0
  396. package/src/tools/implementations/schedule_task_cancel.ts +62 -0
  397. package/src/tools/implementations/schedule_task_once.ts +128 -0
  398. package/src/tools/implementations/schedule_tasks_list.ts +79 -0
  399. package/src/tools/implementations/search.ts +160 -0
  400. package/src/tools/implementations/shell.ts +553 -0
  401. package/src/tools/implementations/todo.ts +260 -0
  402. package/src/tools/implementations/upload_blob.ts +381 -0
  403. package/src/tools/implementations/web_fetch.ts +153 -0
  404. package/src/tools/implementations/web_search.ts +250 -0
  405. package/src/tools/registry.ts +670 -0
  406. package/src/tools/types.ts +177 -0
  407. package/src/tools/utils.ts +256 -0
  408. package/src/types/event-ids.ts +320 -0
  409. package/src/types/index.ts +46 -0
  410. package/src/utils/agentFetcher.ts +107 -0
  411. package/src/utils/cli-error.ts +29 -0
  412. package/src/utils/conversation-id.ts +27 -0
  413. package/src/utils/conversation-utils.ts +1 -0
  414. package/src/utils/delegation-chain.ts +357 -0
  415. package/src/utils/error-handler.ts +42 -0
  416. package/src/utils/git/gitignore.ts +69 -0
  417. package/src/utils/git/index.ts +2 -0
  418. package/src/utils/git/initializeGitRepo.ts +204 -0
  419. package/src/utils/git/worktree.ts +260 -0
  420. package/src/utils/lessonFormatter.ts +70 -0
  421. package/src/utils/lessonTrust.ts +24 -0
  422. package/src/utils/lockfile.ts +123 -0
  423. package/src/utils/logger.ts +149 -0
  424. package/src/utils/nostr-entity-parser.ts +365 -0
  425. package/src/utils/process.ts +49 -0
  426. package/src/wrapper.ts +262 -0
  427. 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, "&lt;")
19
+ .replace(/>/g, "&gt;");
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, "&amp;")
28
+ .replace(/"/g, "&quot;")
29
+ .replace(/</g, "&lt;")
30
+ .replace(/>/g, "&gt;");
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);