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