@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,701 @@
1
+ import type { StoredAgent } from "@/agents/AgentStorage";
2
+ import { agentStorage } from "@/agents/AgentStorage";
3
+ import { NDKAgentDefinition } from "@/events/NDKAgentDefinition";
4
+ import { logger } from "@/utils/logger";
5
+ import type NDK from "@nostr-dev-kit/ndk";
6
+ import type { NDKEvent, NDKFilter, NDKSubscription } from "@nostr-dev-kit/ndk";
7
+ import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
8
+ import type { ProjectRuntime } from "@/daemon/ProjectRuntime";
9
+
10
+ /**
11
+ * Callback to get all active runtimes for reloading agents.
12
+ * Injected by the Daemon to avoid circular dependencies.
13
+ */
14
+ export type ActiveRuntimesProvider = () => Map<string, ProjectRuntime>;
15
+
16
+ /**
17
+ * Configuration for the AgentDefinitionMonitor.
18
+ */
19
+ export interface AgentDefinitionMonitorConfig {
20
+ /** Pubkeys authorized to publish definition upgrades (in addition to original author) */
21
+ whitelistedPubkeys: string[];
22
+ }
23
+
24
+ /**
25
+ * Tracks which agents are being monitored, keyed by "definitionDTag:definitionAuthor".
26
+ */
27
+ interface MonitoredAgent {
28
+ pubkey: string;
29
+ slug: string;
30
+ definitionDTag: string;
31
+ definitionAuthor: string;
32
+ currentEventId?: string;
33
+ currentCreatedAt?: number;
34
+ }
35
+
36
+ /**
37
+ * AgentDefinitionMonitor - Watches for updated agent definition events (kind:4199)
38
+ * and auto-upgrades active agents when newer definitions are published.
39
+ *
40
+ * ## How It Works
41
+ * 1. On startup, scans all installed agents (regardless of active/inactive status)
42
+ * for those with `definitionDTag` + `definitionAuthor` metadata
43
+ * 2. Creates an NDK subscription for kind:4199 events matching those d-tags
44
+ * 3. When a new event arrives:
45
+ * - Verifies the author is authorized (original author or whitelisted)
46
+ * - Checks the event is actually newer (by `created_at` timestamp)
47
+ * - Updates the StoredAgent IN-PLACE (preserving nsec, slug, pmOverrides, etc.)
48
+ * - Reloads the agent in all active project registries
49
+ * 4. Applies a 5000ms debounce to batch events during initial subscription catch-up
50
+ *
51
+ * ## Identity Preservation
52
+ * The following fields are NEVER overwritten during an upgrade:
53
+ * - nsec (agent's private key / identity)
54
+ * - slug (agent's identifier in projects)
55
+ * - pmOverrides (PM designations)
56
+ * - isPM (global PM flag)
57
+ * - projectOverrides (per-project config)
58
+ * - status (active/inactive)
59
+ *
60
+ * ## Backward Compatibility
61
+ * Agents without `definitionDTag` are silently ignored. They can be upgraded
62
+ * by re-installing them, which will set the tracking fields.
63
+ *
64
+ * @see AgentStorage for persistence
65
+ * @see AgentRegistry.reloadAgent for runtime refresh
66
+ */
67
+ export class AgentDefinitionMonitor {
68
+ private ndk: NDK;
69
+ private config: AgentDefinitionMonitorConfig;
70
+ private getActiveRuntimes: ActiveRuntimesProvider;
71
+
72
+ private subscription: NDKSubscription | null = null;
73
+ private monitoredAgents = new Map<string, MonitoredAgent>(); // key: "dTag:author"
74
+ private isRunning = false;
75
+
76
+ /** Debounce state */
77
+ private pendingEvents = new Map<string, NDKEvent>(); // key: "dTag:author" -> latest event
78
+ private debounceTimer: ReturnType<typeof setTimeout> | null = null;
79
+ private static readonly DEBOUNCE_MS = 5000;
80
+
81
+ constructor(
82
+ ndk: NDK,
83
+ config: AgentDefinitionMonitorConfig,
84
+ getActiveRuntimes: ActiveRuntimesProvider,
85
+ ) {
86
+ this.ndk = ndk;
87
+ this.config = config;
88
+ this.getActiveRuntimes = getActiveRuntimes;
89
+ }
90
+
91
+ /**
92
+ * Start monitoring for agent definition updates.
93
+ * Scans all stored agents and subscribes to relevant kind:4199 events.
94
+ */
95
+ async start(): Promise<void> {
96
+ if (this.isRunning) {
97
+ logger.warn("[AgentDefinitionMonitor] Already running");
98
+ return;
99
+ }
100
+
101
+ logger.info("[AgentDefinitionMonitor] Starting agent definition monitor");
102
+
103
+ // Collect all monitored agents from storage
104
+ await this.collectMonitoredAgents();
105
+
106
+ if (this.monitoredAgents.size === 0) {
107
+ logger.info("[AgentDefinitionMonitor] No agents with definition tracking found, monitor idle");
108
+ this.isRunning = true;
109
+ return;
110
+ }
111
+
112
+ // Subscribe to kind:4199 events for the monitored d-tags
113
+ this.subscribe();
114
+ this.isRunning = true;
115
+
116
+ logger.info("[AgentDefinitionMonitor] Started", {
117
+ monitoredAgents: this.monitoredAgents.size,
118
+ dTags: Array.from(this.monitoredAgents.values()).map(a => a.definitionDTag),
119
+ });
120
+ }
121
+
122
+ /**
123
+ * Stop monitoring and clean up.
124
+ */
125
+ stop(): void {
126
+ if (this.debounceTimer) {
127
+ clearTimeout(this.debounceTimer);
128
+ this.debounceTimer = null;
129
+ }
130
+
131
+ if (this.subscription) {
132
+ this.subscription.stop();
133
+ this.subscription = null;
134
+ }
135
+
136
+ this.pendingEvents.clear();
137
+ this.monitoredAgents.clear();
138
+ this.isRunning = false;
139
+
140
+ logger.info("[AgentDefinitionMonitor] Stopped");
141
+ }
142
+
143
+ /**
144
+ * Refresh the monitored agent list and resubscribe.
145
+ * Call this when new agents are installed that have definition tracking.
146
+ */
147
+ async refresh(): Promise<void> {
148
+ if (!this.isRunning) return;
149
+
150
+ logger.debug("[AgentDefinitionMonitor] Refreshing monitored agent list");
151
+
152
+ // Clear stale pending state from the previous subscription
153
+ if (this.debounceTimer) {
154
+ clearTimeout(this.debounceTimer);
155
+ this.debounceTimer = null;
156
+ }
157
+ this.pendingEvents.clear();
158
+
159
+ // Stop existing subscription
160
+ if (this.subscription) {
161
+ this.subscription.stop();
162
+ this.subscription = null;
163
+ }
164
+
165
+ // Recollect and resubscribe
166
+ await this.collectMonitoredAgents();
167
+
168
+ if (this.monitoredAgents.size > 0) {
169
+ this.subscribe();
170
+ }
171
+
172
+ logger.info("[AgentDefinitionMonitor] Refreshed", {
173
+ monitoredAgents: this.monitoredAgents.size,
174
+ });
175
+ }
176
+
177
+ /**
178
+ * Scan all stored agents and collect those with definition tracking metadata.
179
+ * Runs bootstrapLegacyAgents first to migrate agents missing definitionDTag/definitionAuthor.
180
+ */
181
+ private async collectMonitoredAgents(): Promise<void> {
182
+ this.monitoredAgents.clear();
183
+
184
+ const allAgents = await agentStorage.getAllAgents();
185
+
186
+ // Migrate legacy agents before the main loop so they can be monitored
187
+ await this.bootstrapLegacyAgents(allAgents);
188
+
189
+ for (const agent of allAgents) {
190
+ if (!agent.definitionDTag || !agent.definitionAuthor) {
191
+ logger.debug("[AgentDefinitionMonitor] Skipping agent without definition tracking metadata", {
192
+ slug: agent.slug,
193
+ hasEventId: !!agent.eventId,
194
+ hasDTag: !!agent.definitionDTag,
195
+ hasAuthor: !!agent.definitionAuthor,
196
+ });
197
+ continue;
198
+ }
199
+
200
+ try {
201
+ // Derive pubkey from nsec for the agent
202
+ const signer = new NDKPrivateKeySigner(agent.nsec);
203
+ const pubkey = signer.pubkey;
204
+
205
+ const key = this.buildMonitorKey(agent.definitionDTag, agent.definitionAuthor);
206
+ this.monitoredAgents.set(key, {
207
+ pubkey,
208
+ slug: agent.slug,
209
+ definitionDTag: agent.definitionDTag,
210
+ definitionAuthor: agent.definitionAuthor,
211
+ currentEventId: agent.eventId,
212
+ currentCreatedAt: agent.definitionCreatedAt,
213
+ });
214
+ } catch (error) {
215
+ logger.warn("[AgentDefinitionMonitor] Failed to process agent, skipping", {
216
+ slug: agent.slug,
217
+ definitionDTag: agent.definitionDTag,
218
+ error: error instanceof Error ? error.message : String(error),
219
+ });
220
+ }
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Bootstrap legacy agents that were installed before definitionDTag/definitionAuthor existed.
226
+ *
227
+ * For agents missing these fields but having an eventId (meaning they came from a kind:4199 event):
228
+ * - definitionDTag is inferred from the agent's slug (convention enforced by agents_publish)
229
+ * - definitionAuthor is recovered by fetching the original event from relays
230
+ *
231
+ * Mutations are applied directly to the provided agent objects AND persisted to storage.
232
+ * This ensures the main loop in collectMonitoredAgents sees the updated fields immediately.
233
+ */
234
+ private async bootstrapLegacyAgents(agents: StoredAgent[]): Promise<void> {
235
+ const candidates = agents.filter(
236
+ (a) => a.eventId && (!a.definitionDTag || !a.definitionAuthor),
237
+ );
238
+
239
+ if (candidates.length === 0) return;
240
+
241
+ logger.info("[AgentDefinitionMonitor] Bootstrapping legacy agents", {
242
+ count: candidates.length,
243
+ slugs: candidates.map((a) => a.slug),
244
+ });
245
+
246
+ for (const agent of candidates) {
247
+ try {
248
+ let changed = false;
249
+
250
+ // Infer definitionDTag from slug (convention: d-tag = slug)
251
+ if (!agent.definitionDTag) {
252
+ agent.definitionDTag = agent.slug;
253
+ changed = true;
254
+ logger.info("[AgentDefinitionMonitor] Inferred definitionDTag from slug", {
255
+ slug: agent.slug,
256
+ definitionDTag: agent.definitionDTag,
257
+ });
258
+ }
259
+
260
+ // Recover definitionAuthor by fetching the original event
261
+ if (!agent.definitionAuthor && agent.eventId) {
262
+ try {
263
+ const event = await this.ndk.fetchEvent(agent.eventId);
264
+ if (event) {
265
+ agent.definitionAuthor = event.pubkey;
266
+ // Also backfill definitionCreatedAt if missing
267
+ if (!agent.definitionCreatedAt && event.created_at) {
268
+ agent.definitionCreatedAt = event.created_at;
269
+ }
270
+ changed = true;
271
+ logger.info("[AgentDefinitionMonitor] Recovered definitionAuthor from relay", {
272
+ slug: agent.slug,
273
+ eventId: agent.eventId.substring(0, 12),
274
+ definitionAuthor: agent.definitionAuthor.substring(0, 12),
275
+ });
276
+ } else {
277
+ logger.warn("[AgentDefinitionMonitor] Could not fetch event for legacy agent — skipping author recovery", {
278
+ slug: agent.slug,
279
+ eventId: agent.eventId.substring(0, 12),
280
+ });
281
+ }
282
+ } catch (fetchError) {
283
+ logger.warn("[AgentDefinitionMonitor] Failed to fetch event for legacy agent — skipping author recovery", {
284
+ slug: agent.slug,
285
+ eventId: agent.eventId.substring(0, 12),
286
+ error: fetchError instanceof Error ? fetchError.message : String(fetchError),
287
+ });
288
+ }
289
+ }
290
+
291
+ if (changed) {
292
+ await agentStorage.saveAgent(agent);
293
+ logger.info("[AgentDefinitionMonitor] Migrated legacy agent", {
294
+ slug: agent.slug,
295
+ definitionDTag: agent.definitionDTag,
296
+ definitionAuthor: agent.definitionAuthor?.substring(0, 12) ?? "(unknown)",
297
+ });
298
+ }
299
+ } catch (error) {
300
+ // Never block startup for a single agent's migration failure
301
+ logger.warn("[AgentDefinitionMonitor] Failed to bootstrap legacy agent, skipping", {
302
+ slug: agent.slug,
303
+ error: error instanceof Error ? error.message : String(error),
304
+ });
305
+ }
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Create the NDK subscription for kind:4199 events matching monitored d-tags.
311
+ */
312
+ private subscribe(): void {
313
+ // Collect unique d-tags
314
+ const dTags = new Set<string>();
315
+ for (const agent of this.monitoredAgents.values()) {
316
+ dTags.add(agent.definitionDTag);
317
+ }
318
+
319
+ if (dTags.size === 0) return;
320
+
321
+ const filter: NDKFilter = {
322
+ kinds: [4199 as number],
323
+ "#d": Array.from(dTags),
324
+ };
325
+
326
+ logger.info("[AgentDefinitionMonitor] Subscribing to definition events", {
327
+ dTagCount: dTags.size,
328
+ dTags: Array.from(dTags),
329
+ });
330
+
331
+ this.subscription = this.ndk.subscribe(filter, {
332
+ closeOnEose: false,
333
+ groupable: false,
334
+ onEvent: (event: NDKEvent) => {
335
+ this.handleIncomingEvent(event);
336
+ },
337
+ });
338
+ }
339
+
340
+ /**
341
+ * Handle an incoming kind:4199 event.
342
+ * Filters unauthorized events before staging to prevent them from
343
+ * resetting the debounce timer and deferring legitimate updates.
344
+ * Applies debounce to batch events during initial catch-up.
345
+ */
346
+ private handleIncomingEvent(event: NDKEvent): void {
347
+ const dTag = event.tagValue("d");
348
+ if (!dTag) {
349
+ logger.debug("[AgentDefinitionMonitor] Ignoring event without d-tag", {
350
+ eventId: event.id?.substring(0, 12),
351
+ });
352
+ return;
353
+ }
354
+
355
+ const author = event.pubkey;
356
+
357
+ // Check if this matches a monitored agent (by d-tag, author checked separately)
358
+ const monitoredAgent = this.findMonitoredAgentByDTag(dTag);
359
+ if (!monitoredAgent) {
360
+ logger.debug("[AgentDefinitionMonitor] Event d-tag does not match any monitored agent", {
361
+ dTag,
362
+ author: author?.substring(0, 12),
363
+ });
364
+ return;
365
+ }
366
+
367
+ // Authorization check BEFORE staging — unauthorized events must not
368
+ // reset the debounce timer or displace legitimate pending events
369
+ if (!this.isAuthorized(author, monitoredAgent.definitionAuthor)) {
370
+ logger.debug("[AgentDefinitionMonitor] Ignoring event from unauthorized author", {
371
+ dTag,
372
+ author: author?.substring(0, 12),
373
+ expectedAuthor: monitoredAgent.definitionAuthor.substring(0, 12),
374
+ agentSlug: monitoredAgent.slug,
375
+ });
376
+ return;
377
+ }
378
+
379
+ const key = this.buildMonitorKey(dTag, author);
380
+
381
+ logger.debug("[AgentDefinitionMonitor] New definition event detected", {
382
+ dTag,
383
+ author: author?.substring(0, 12),
384
+ eventId: event.id?.substring(0, 12),
385
+ createdAt: event.created_at,
386
+ });
387
+
388
+ // Store in pending events (keep only the latest per key)
389
+ const existingPending = this.pendingEvents.get(key);
390
+ if (existingPending && existingPending.created_at && event.created_at) {
391
+ if (event.created_at <= existingPending.created_at) {
392
+ logger.debug("[AgentDefinitionMonitor] Skipping older pending event", {
393
+ dTag,
394
+ existingCreatedAt: existingPending.created_at,
395
+ newCreatedAt: event.created_at,
396
+ });
397
+ return;
398
+ }
399
+ }
400
+ this.pendingEvents.set(key, event);
401
+
402
+ // Reset debounce timer
403
+ if (this.debounceTimer) {
404
+ clearTimeout(this.debounceTimer);
405
+ }
406
+
407
+ this.debounceTimer = setTimeout(() => {
408
+ this.processPendingEvents();
409
+ }, AgentDefinitionMonitor.DEBOUNCE_MS);
410
+ }
411
+
412
+ /**
413
+ * Process all pending events after the debounce period.
414
+ */
415
+ private async processPendingEvents(): Promise<void> {
416
+ const pendingEntries = new Map(this.pendingEvents);
417
+ this.pendingEvents.clear();
418
+ this.debounceTimer = null;
419
+
420
+ logger.info("[AgentDefinitionMonitor] Processing pending definition events", {
421
+ count: pendingEntries.size,
422
+ });
423
+
424
+ for (const [key, event] of pendingEntries) {
425
+ try {
426
+ await this.processDefinitionEvent(key, event);
427
+ } catch (error) {
428
+ logger.error("[AgentDefinitionMonitor] Failed to process definition event", {
429
+ key,
430
+ eventId: event.id?.substring(0, 12),
431
+ error: error instanceof Error ? error.message : String(error),
432
+ });
433
+ }
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Process a single definition event: validate, check recency, upgrade, reload.
439
+ * Authorization is already verified in handleIncomingEvent before staging.
440
+ */
441
+ private async processDefinitionEvent(_key: string, event: NDKEvent): Promise<void> {
442
+ const dTag = event.tagValue("d");
443
+ const author = event.pubkey;
444
+
445
+ if (!dTag || !author) {
446
+ logger.warn("[AgentDefinitionMonitor] Event missing d-tag or author, skipping");
447
+ return;
448
+ }
449
+
450
+ // Find the monitored agent by d-tag
451
+ const monitoredAgent = this.findMonitoredAgentByDTag(dTag);
452
+ if (!monitoredAgent) {
453
+ logger.warn("[AgentDefinitionMonitor] No monitored agent found for d-tag", { dTag });
454
+ return;
455
+ }
456
+
457
+ // Skip if this is the exact same event we already have
458
+ if (monitoredAgent.currentEventId === event.id) {
459
+ logger.debug("[AgentDefinitionMonitor] Event is the same as current, skipping", {
460
+ dTag,
461
+ eventId: event.id?.substring(0, 12),
462
+ });
463
+ return;
464
+ }
465
+
466
+ // Load current agent from storage to compare timestamps
467
+ const storedAgent = await agentStorage.loadAgent(monitoredAgent.pubkey);
468
+ if (!storedAgent) {
469
+ logger.warn("[AgentDefinitionMonitor] Monitored agent not found in storage", {
470
+ pubkey: monitoredAgent.pubkey.substring(0, 12),
471
+ slug: monitoredAgent.slug,
472
+ });
473
+ return;
474
+ }
475
+
476
+ // Reject events that are not strictly newer than the stored definition.
477
+ // This prevents out-of-order older events from rolling back fields.
478
+ if (storedAgent.definitionCreatedAt && event.created_at) {
479
+ if (event.created_at <= storedAgent.definitionCreatedAt) {
480
+ logger.debug("[AgentDefinitionMonitor] Skipping event older than current definition", {
481
+ dTag,
482
+ eventId: event.id?.substring(0, 12),
483
+ eventCreatedAt: event.created_at,
484
+ storedCreatedAt: storedAgent.definitionCreatedAt,
485
+ agentSlug: monitoredAgent.slug,
486
+ });
487
+ return;
488
+ }
489
+ }
490
+
491
+ // Apply the upgrade
492
+ await this.upgradeAgent(storedAgent, monitoredAgent, event);
493
+ }
494
+
495
+ /**
496
+ * Check if an author is authorized to publish definition updates.
497
+ */
498
+ private isAuthorized(author: string, originalAuthor: string): boolean {
499
+ // Original author is always authorized
500
+ if (author === originalAuthor) {
501
+ return true;
502
+ }
503
+
504
+ // Check whitelist
505
+ if (this.config.whitelistedPubkeys.includes(author)) {
506
+ logger.debug("[AgentDefinitionMonitor] Author authorized via whitelist", {
507
+ author: author.substring(0, 12),
508
+ });
509
+ return true;
510
+ }
511
+
512
+ return false;
513
+ }
514
+
515
+ /**
516
+ * Upgrade an agent's definition in-place, preserving identity fields.
517
+ */
518
+ private async upgradeAgent(
519
+ storedAgent: StoredAgent,
520
+ monitoredAgent: MonitoredAgent,
521
+ event: NDKEvent,
522
+ ): Promise<void> {
523
+ const agentDef = NDKAgentDefinition.from(event);
524
+
525
+ // Capture before state for logging
526
+ const beforeState = {
527
+ eventId: storedAgent.eventId?.substring(0, 12),
528
+ name: storedAgent.name,
529
+ role: storedAgent.role,
530
+ };
531
+
532
+ // Track which fields actually change
533
+ const changedFields: string[] = [];
534
+
535
+ // Update definition fields (NEVER touch identity fields)
536
+ const newName = agentDef.title || storedAgent.name;
537
+ if (newName !== storedAgent.name) {
538
+ storedAgent.name = newName;
539
+ changedFields.push("name");
540
+ }
541
+
542
+ const newRole = agentDef.role || storedAgent.role;
543
+ if (newRole !== storedAgent.role) {
544
+ storedAgent.role = newRole;
545
+ changedFields.push("role");
546
+ }
547
+
548
+ const newDescription = agentDef.description || undefined;
549
+ if (newDescription !== storedAgent.description) {
550
+ storedAgent.description = newDescription;
551
+ changedFields.push("description");
552
+ }
553
+
554
+ const newInstructions = agentDef.instructions || undefined;
555
+ if (newInstructions !== storedAgent.instructions) {
556
+ storedAgent.instructions = newInstructions;
557
+ changedFields.push("instructions");
558
+ }
559
+
560
+ const newUseCriteria = agentDef.useCriteria || undefined;
561
+ if (newUseCriteria !== storedAgent.useCriteria) {
562
+ storedAgent.useCriteria = newUseCriteria;
563
+ changedFields.push("useCriteria");
564
+ }
565
+
566
+ // Update tool requirements
567
+ const toolTags = event.tags
568
+ .filter((tag) => tag[0] === "tool" && tag[1])
569
+ .map((tag) => tag[1]);
570
+ const newTools = toolTags.length > 0 ? toolTags : undefined;
571
+ const currentTools = storedAgent.default?.tools;
572
+ if (JSON.stringify(newTools) !== JSON.stringify(currentTools)) {
573
+ if (!storedAgent.default) {
574
+ storedAgent.default = {};
575
+ }
576
+ storedAgent.default.tools = newTools;
577
+ changedFields.push("default.tools");
578
+ }
579
+
580
+ // Update eventId to the new event
581
+ const oldEventId = storedAgent.eventId;
582
+ storedAgent.eventId = event.id;
583
+ if (oldEventId !== event.id) {
584
+ changedFields.push("eventId");
585
+ }
586
+
587
+ // Update definitionCreatedAt for future recency checks
588
+ if (event.created_at) {
589
+ const oldCreatedAt = storedAgent.definitionCreatedAt;
590
+ storedAgent.definitionCreatedAt = event.created_at;
591
+ if (oldCreatedAt !== event.created_at) {
592
+ changedFields.push("definitionCreatedAt");
593
+ }
594
+ }
595
+
596
+ // Update the definition author if the event comes from a different (whitelisted) author
597
+ if (event.pubkey !== storedAgent.definitionAuthor) {
598
+ // Only update definitionAuthor if the event d-tag is from a whitelisted pubkey
599
+ // The original author remains canonical unless explicitly overridden
600
+ changedFields.push("definitionAuthor (noted, not overwritten)");
601
+ }
602
+
603
+ if (changedFields.length === 0) {
604
+ logger.info("[AgentDefinitionMonitor] No changes detected in definition update", {
605
+ agentSlug: monitoredAgent.slug,
606
+ dTag: monitoredAgent.definitionDTag,
607
+ eventId: event.id?.substring(0, 12),
608
+ });
609
+ return;
610
+ }
611
+
612
+ // Save the updated agent
613
+ await agentStorage.saveAgent(storedAgent);
614
+
615
+ // Update monitored agent tracking
616
+ monitoredAgent.currentEventId = event.id;
617
+ monitoredAgent.currentCreatedAt = event.created_at;
618
+
619
+ // Capture after state for logging
620
+ const afterState = {
621
+ eventId: storedAgent.eventId?.substring(0, 12),
622
+ name: storedAgent.name,
623
+ role: storedAgent.role,
624
+ };
625
+
626
+ logger.info("[AgentDefinitionMonitor] Upgrading agent definition", {
627
+ agentSlug: monitoredAgent.slug,
628
+ agentPubkey: monitoredAgent.pubkey.substring(0, 12),
629
+ dTag: monitoredAgent.definitionDTag,
630
+ beforeState,
631
+ afterState,
632
+ changedFields,
633
+ newEventId: event.id?.substring(0, 12),
634
+ upgradeTimestamp: new Date().toISOString(),
635
+ });
636
+
637
+ // Reload agent in all active runtimes
638
+ await this.reloadAgentInRuntimes(monitoredAgent.pubkey, monitoredAgent.slug);
639
+ }
640
+
641
+ /**
642
+ * Reload an agent in all active project runtimes that contain it.
643
+ */
644
+ private async reloadAgentInRuntimes(pubkey: string, slug: string): Promise<void> {
645
+ const activeRuntimes = this.getActiveRuntimes();
646
+ let reloadCount = 0;
647
+
648
+ for (const [projectId, runtime] of activeRuntimes) {
649
+ const context = runtime.getContext();
650
+ if (!context) continue;
651
+
652
+ const agent = context.getAgentByPubkey(pubkey);
653
+ if (!agent) continue;
654
+
655
+ try {
656
+ await context.agentRegistry.reloadAgent(pubkey);
657
+ reloadCount++;
658
+
659
+ if (context.statusPublisher) {
660
+ await context.statusPublisher.publishImmediately();
661
+ }
662
+
663
+ logger.debug("[AgentDefinitionMonitor] Reloaded agent in runtime", {
664
+ agentSlug: slug,
665
+ projectId,
666
+ });
667
+ } catch (error) {
668
+ logger.error("[AgentDefinitionMonitor] Failed to reload agent in runtime", {
669
+ agentSlug: slug,
670
+ projectId,
671
+ error: error instanceof Error ? error.message : String(error),
672
+ });
673
+ }
674
+ }
675
+
676
+ logger.info("[AgentDefinitionMonitor] Agent reloaded in runtimes", {
677
+ agentSlug: slug,
678
+ reloadCount,
679
+ totalRuntimes: activeRuntimes.size,
680
+ });
681
+ }
682
+
683
+ /**
684
+ * Find a monitored agent by its d-tag (may match any author).
685
+ */
686
+ private findMonitoredAgentByDTag(dTag: string): MonitoredAgent | undefined {
687
+ for (const agent of this.monitoredAgents.values()) {
688
+ if (agent.definitionDTag === dTag) {
689
+ return agent;
690
+ }
691
+ }
692
+ return undefined;
693
+ }
694
+
695
+ /**
696
+ * Build a unique key for a monitored agent.
697
+ */
698
+ private buildMonitorKey(dTag: string, author: string): string {
699
+ return `${dTag}:${author}`;
700
+ }
701
+ }