@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,677 @@
1
+ import { NDKAgentLesson } from "@/events/NDKAgentLesson";
2
+ import type { LanguageModelUsageWithCostUsd } from "@/llm/types";
3
+ import { NDKKind } from "@/nostr/kinds";
4
+ import { getNDK } from "@/nostr/ndkClient";
5
+ import { getProjectContext } from "@/services/projects";
6
+ import { shortenConversationId } from "@/utils/conversation-id";
7
+ import { logger } from "@/utils/logger";
8
+ import { NDKEvent } from "@nostr-dev-kit/ndk";
9
+ import { nip19 } from "nostr-tools";
10
+ import type {
11
+ AskIntent,
12
+ CompletionIntent,
13
+ ConversationIntent,
14
+ DelegationIntent,
15
+ DelegationMarkerIntent,
16
+ ErrorIntent,
17
+ EventContext,
18
+ InterventionReviewIntent,
19
+ LessonIntent,
20
+ ToolUseIntent,
21
+ } from "./types";
22
+
23
+ /**
24
+ * Centralized module for encoding and decoding agent event semantics.
25
+ * This module codifies the tagging structures and their meanings,
26
+ * ensuring consistent event creation and interpretation across the system.
27
+ */
28
+
29
+ /**
30
+ * Encodes agent intents into properly tagged Nostr events.
31
+ * All tagging logic is centralized here for consistency and testability.
32
+ */
33
+ export class AgentEventEncoder {
34
+ /**
35
+ * Add conversation tags consistently to any event.
36
+ * Just e-tags the root event - no reply threading.
37
+ */
38
+ private addConversationTags(event: NDKEvent, context: EventContext): void {
39
+ if (context.rootEvent.id) {
40
+ event.tag(["e", context.rootEvent.id]);
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Determine the correct recipient pubkey for a completion event.
46
+ *
47
+ * Uses pre-resolved completionRecipientPubkey from context when available.
48
+ * This supports delegation chain routing where completions must route back
49
+ * to the immediate delegator, not the event that happened to trigger the
50
+ * current execution (e.g., a user responding to an ask).
51
+ *
52
+ * The recipient resolution is done by createEventContext() in EventContextService
53
+ * (services/event-context/, layer 3) which has access to ConversationStore. This
54
+ * method just uses the pre-resolved value or falls back to triggeringEvent.pubkey
55
+ * for direct conversations.
56
+ *
57
+ * @param context - The event context containing completionRecipientPubkey or triggeringEvent
58
+ * @returns The pubkey to use for the completion p-tag
59
+ */
60
+ private getCompletionRecipientPubkey(context: EventContext): string {
61
+ // Use pre-resolved recipient if available (set by createEventContext from delegation chain)
62
+ if (context.completionRecipientPubkey) {
63
+ logger.debug("Completion routing via pre-resolved recipient", {
64
+ conversationId: context.conversationId.substring(0, 12),
65
+ recipientPubkey: context.completionRecipientPubkey.substring(0, 8),
66
+ triggeringEventPubkey: context.triggeringEvent.pubkey.substring(0, 8),
67
+ usingPreResolved: context.completionRecipientPubkey !== context.triggeringEvent.pubkey,
68
+ });
69
+ return context.completionRecipientPubkey;
70
+ }
71
+
72
+ // No pre-resolved recipient - fall back to triggering event pubkey
73
+ // This is the correct behavior for direct user conversations
74
+ return context.triggeringEvent.pubkey;
75
+ }
76
+
77
+ /**
78
+ * Forward branch tag from triggering event to reply event.
79
+ * Ensures agents carry forward the branch context from the message they're replying to.
80
+ */
81
+ public forwardBranchTag(event: NDKEvent, context: EventContext): void {
82
+ const branchTag = context.triggeringEvent.tags.find((tag) => tag[0] === "branch" && tag[1]);
83
+ if (branchTag) {
84
+ event.tag(["branch", branchTag[1]]);
85
+ logger.debug("Forwarding branch tag", {
86
+ branch: branchTag[1],
87
+ fromEvent: context.triggeringEvent.id?.substring(0, 8),
88
+ });
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Encode a completion intent into a tagged event.
94
+ * Completions have p-tag (triggers notification) and status=completed.
95
+ *
96
+ * IMPORTANT: For delegation contexts, the p-tag targets the immediate delegator
97
+ * (second-to-last entry in the delegation chain), NOT the triggeringEvent.pubkey.
98
+ * This ensures completions route back up the delegation stack even when RAL state
99
+ * is lost and the execution restarts with a fresh triggeringEvent (e.g., after
100
+ * a human responds to an "ask" hours later).
101
+ */
102
+ encodeCompletion(intent: CompletionIntent, context: EventContext): NDKEvent {
103
+ const event = new NDKEvent(getNDK());
104
+ event.kind = NDKKind.Text; // kind:1
105
+ event.content = intent.content;
106
+
107
+ this.addConversationTags(event, context);
108
+
109
+ // Determine the correct p-tag recipient
110
+ const recipientPubkey = this.getCompletionRecipientPubkey(context);
111
+ event.tag(["p", recipientPubkey]);
112
+ event.tag(["status", "completed"]);
113
+
114
+ if (intent.usage) {
115
+ this.addLLMUsageTags(event, intent.usage);
116
+ }
117
+
118
+ // Note: LLM runtime (incremental) is added via addStandardTags() using context.llmRuntime
119
+ this.addStandardTags(event, context);
120
+
121
+ // For completion events, add llm-runtime-total tag when available
122
+ // This preserves semantic contract:
123
+ // - llm-runtime = incremental runtime since last publish (from addStandardTags)
124
+ // - llm-runtime-total = total accumulated runtime (completion-specific)
125
+ if (context.llmRuntimeTotal !== undefined && context.llmRuntimeTotal > 0) {
126
+ event.tag(["llm-runtime-total", context.llmRuntimeTotal.toString(), "ms"]);
127
+ }
128
+
129
+ this.forwardBranchTag(event, context);
130
+
131
+ logger.debug("Encoded completion event", {
132
+ eventId: event.id,
133
+ recipientPubkey: recipientPubkey.substring(0, 8),
134
+ triggeringEventPubkey: context.triggeringEvent.pubkey?.substring(0, 8),
135
+ conversationId: context.conversationId?.substring(0, 12),
136
+ });
137
+
138
+ return event;
139
+ }
140
+
141
+ /**
142
+ * Encode a conversation intent into a tagged event.
143
+ * Conversations have NO p-tag (no notification) - used for mid-loop responses.
144
+ */
145
+ encodeConversation(intent: ConversationIntent, context: EventContext): NDKEvent {
146
+ const event = new NDKEvent(getNDK());
147
+ event.kind = NDKKind.Text; // kind:1 - same as completion
148
+ event.content = intent.content;
149
+
150
+ this.addConversationTags(event, context);
151
+ // NO p-tag - that's the difference from completion
152
+ // NO status tag
153
+
154
+ if (intent.isReasoning) {
155
+ event.tag(["reasoning"]);
156
+ }
157
+
158
+ if (intent.usage) {
159
+ this.addLLMUsageTags(event, intent.usage);
160
+ }
161
+
162
+ this.addStandardTags(event, context);
163
+ this.forwardBranchTag(event, context);
164
+
165
+ return event;
166
+ }
167
+
168
+ /**
169
+ * Prepend recipient identifiers to message content for delegation.
170
+ * Uses agent slugs for known agents, npub format for external recipients.
171
+ */
172
+ private prependRecipientsToContent(content: string, recipients: string[]): string {
173
+ // Check if content already starts with nostr:npub or @slug patterns
174
+ const hasNostrPrefix = content.startsWith("nostr:");
175
+ const hasSlugPrefix = content.match(/^@[\w-]+:/);
176
+
177
+ if (hasNostrPrefix || hasSlugPrefix) {
178
+ return content;
179
+ }
180
+
181
+ // Get project context to look up agents
182
+ const projectCtx = getProjectContext();
183
+ const agentRegistry = projectCtx.agentRegistry;
184
+
185
+ // Build recipient identifiers
186
+ const recipientIdentifiers = recipients.map((pubkey) => {
187
+ // Check if this pubkey belongs to an agent in the system
188
+ const agent = agentRegistry.getAgentByPubkey(pubkey);
189
+ if (agent) {
190
+ return `@${agent.slug}`;
191
+ }
192
+
193
+ // For external recipients, use nostr:npub format
194
+ try {
195
+ const npub = nip19.npubEncode(pubkey);
196
+ return `nostr:${npub}`;
197
+ } catch (error) {
198
+ logger.warn("Failed to encode pubkey to npub", { pubkey, error });
199
+ return `nostr:${pubkey}`; // Fallback to hex if encoding fails
200
+ }
201
+ });
202
+
203
+ // Prepend recipients to content
204
+ return `${recipientIdentifiers.join(", ")}: ${content}`;
205
+ }
206
+
207
+ /**
208
+ * Encode a delegation intent into kind:1 conversation events.
209
+ * Creates one event per delegation, each with its own content and tags.
210
+ */
211
+ encodeDelegation(intent: DelegationIntent, context: EventContext): NDKEvent[] {
212
+ return intent.delegations.map((delegation) => {
213
+ const event = new NDKEvent(getNDK());
214
+ event.kind = NDKKind.Text; // kind:1 - unified conversation format
215
+
216
+ // Prepend recipient to the content
217
+ event.content = this.prependRecipientsToContent(delegation.request, [
218
+ delegation.recipient,
219
+ ]);
220
+
221
+ event.created_at = Math.floor(Date.now() / 1000) + 1; // we publish one second into the future because it looks more natural when the agent says "I will delegate to..." and then the delegation shows up
222
+
223
+ // No e-tag: delegation events are separate conversations
224
+ // The recipient starts a fresh conversation thread
225
+
226
+ // Add recipient as p-tag
227
+ event.tag(["p", delegation.recipient]);
228
+
229
+ // Branch metadata if provided (for worktree support)
230
+ if (delegation.branch) {
231
+ event.tag(["branch", delegation.branch]);
232
+ }
233
+
234
+ // Add standard metadata
235
+ this.addStandardTags(event, context);
236
+
237
+ // Forward branch tag from triggering event if not explicitly set
238
+ if (!delegation.branch) {
239
+ this.forwardBranchTag(event, context);
240
+ }
241
+
242
+ logger.debug("Encoded delegation request", {
243
+ recipient: delegation.recipient.substring(0, 8),
244
+ });
245
+
246
+ return event;
247
+ });
248
+ }
249
+
250
+ /**
251
+ * Encode an Ask intent into a kind:1 event using the multi-question format.
252
+ * Creates an event that asks questions to the project manager/human user.
253
+ */
254
+ encodeAsk(intent: AskIntent, context: EventContext): NDKEvent {
255
+ const event = new NDKEvent(getNDK());
256
+ event.kind = NDKKind.Text; // kind:1 - unified conversation format
257
+ event.content = intent.context;
258
+
259
+ // Add conversation tags
260
+ this.addConversationTags(event, context);
261
+
262
+ // Get project owner to ask the question to
263
+ const projectCtx = getProjectContext();
264
+ const ownerPubkey = projectCtx?.project?.pubkey;
265
+
266
+ if (ownerPubkey) {
267
+ event.tag(["p", ownerPubkey]);
268
+ }
269
+
270
+ // Add title tag
271
+ event.tag(["title", intent.title]);
272
+
273
+ // Add question/multiselect tags
274
+ for (const question of intent.questions) {
275
+ if (question.type === "question") {
276
+ const tag = ["question", question.title, question.question];
277
+ if (question.suggestions) {
278
+ tag.push(...question.suggestions);
279
+ }
280
+ event.tag(tag);
281
+ } else if (question.type === "multiselect") {
282
+ const tag = ["multiselect", question.title, question.question];
283
+ if (question.options) {
284
+ tag.push(...question.options);
285
+ }
286
+ event.tag(tag);
287
+ }
288
+ }
289
+
290
+ // Mark this as an ask event
291
+ event.tag(["intent", "ask"]);
292
+
293
+ // Add standard metadata
294
+ this.addStandardTags(event, context);
295
+
296
+ // Forward branch tag from triggering event
297
+ this.forwardBranchTag(event, context);
298
+
299
+ logger.debug("Encoded ask event", {
300
+ title: intent.title,
301
+ questionCount: intent.questions.length,
302
+ recipient: ownerPubkey?.substring(0, 8),
303
+ });
304
+
305
+ return event;
306
+ }
307
+
308
+ /**
309
+ * Add standard metadata tags that all agent events should have.
310
+ * Centralizes common tagging logic.
311
+ */
312
+ public addStandardTags(event: NDKEvent, context: EventContext): void {
313
+ this.aTagProject(event);
314
+
315
+ // LLM metadata
316
+ if (context.model) {
317
+ // Handle both string and object formats (some providers return {model: "..."})
318
+ const modelString =
319
+ typeof context.model === "string"
320
+ ? context.model
321
+ : (context.model as { model?: string }).model;
322
+ if (modelString) {
323
+ event.tag(["llm-model", modelString]);
324
+ }
325
+ }
326
+ // Add cost metadata if available
327
+ if (context.cost !== undefined) {
328
+ // Format cost to avoid scientific notation and ensure proper decimal representation
329
+ // Use toFixed with enough precision (10 decimal places) then remove trailing zeros
330
+ const formattedCost = context.cost.toFixed(10).replace(/\.?0+$/, "");
331
+ event.tag(["llm-cost-usd", formattedCost]);
332
+ }
333
+ if (context.executionTime) {
334
+ event.tag(["execution-time", context.executionTime.toString()]);
335
+ }
336
+
337
+ // LLM runtime (incremental since last publish)
338
+ if (context.llmRuntime !== undefined && context.llmRuntime > 0) {
339
+ event.tag(["llm-runtime", context.llmRuntime.toString(), "ms"]);
340
+ }
341
+
342
+ // LLM runtime total (for completion events - used by delegation aggregation)
343
+ if (context.llmRuntimeTotal !== undefined && context.llmRuntimeTotal > 0) {
344
+ event.tag(["llm-runtime-total", context.llmRuntimeTotal.toString(), "ms"]);
345
+ }
346
+
347
+ // RAL metadata
348
+ event.tag(["llm-ral", context.ralNumber.toString()]);
349
+ }
350
+
351
+ /**
352
+ * Encode an error intent into an error event.
353
+ * Error events act as finalization: they have p-tag (triggers notification) and status=completed.
354
+ */
355
+ encodeError(intent: ErrorIntent, context: EventContext): NDKEvent {
356
+ const event = new NDKEvent(getNDK());
357
+ event.kind = NDKKind.Text; // kind:1 - unified conversation format
358
+ event.content = intent.message;
359
+
360
+ // Add conversation tags
361
+ this.addConversationTags(event, context);
362
+
363
+ // Mark as error
364
+ event.tag(["error", intent.errorType || "system"]);
365
+
366
+ // Error events are finalization events - notify the user
367
+ event.tag(["p", context.triggeringEvent.pubkey]);
368
+ event.tag(["status", "completed"]);
369
+
370
+ // Add standard metadata
371
+ this.addStandardTags(event, context);
372
+
373
+ // Forward branch tag from triggering event
374
+ this.forwardBranchTag(event, context);
375
+
376
+ return event;
377
+ }
378
+
379
+ /**
380
+ * Add LLM usage metadata tags to an event.
381
+ * Centralizes the encoding of usage information from AI SDK's LanguageModelUsageWithCostUsd.
382
+ */
383
+ private addLLMUsageTags(event: NDKEvent, usage: LanguageModelUsageWithCostUsd): void {
384
+ if (usage.inputTokens !== undefined) {
385
+ event.tag(["llm-prompt-tokens", usage.inputTokens.toString()]);
386
+ }
387
+ if (usage.outputTokens !== undefined) {
388
+ event.tag(["llm-completion-tokens", usage.outputTokens.toString()]);
389
+ }
390
+ if (usage.totalTokens !== undefined) {
391
+ event.tag(["llm-total-tokens", usage.totalTokens.toString()]);
392
+ } else if (usage.inputTokens !== undefined && usage.outputTokens !== undefined) {
393
+ // Fallback: calculate total if not provided
394
+ event.tag(["llm-total-tokens", (usage.inputTokens + usage.outputTokens).toString()]);
395
+ }
396
+
397
+ if (usage.costUsd !== undefined) {
398
+ event.tag(["llm-cost-usd", usage.costUsd.toString()]);
399
+ }
400
+
401
+ // Add additional usage metadata if available
402
+ if ("reasoningTokens" in usage && usage.reasoningTokens !== undefined) {
403
+ event.tag(["llm-reasoning-tokens", String(usage.reasoningTokens)]);
404
+ }
405
+ if ("cachedInputTokens" in usage && usage.cachedInputTokens !== undefined) {
406
+ event.tag(["llm-cached-input-tokens", String(usage.cachedInputTokens)]);
407
+ }
408
+ if ("contextWindow" in usage && usage.contextWindow !== undefined) {
409
+ event.tag(["llm-context-window", String(usage.contextWindow)]);
410
+ }
411
+ }
412
+
413
+ aTagProject(event: NDKEvent): undefined {
414
+ const projectCtx = getProjectContext();
415
+ event.tag(projectCtx.project.tagReference());
416
+ }
417
+
418
+ /**
419
+ * p-tags the project owner
420
+ */
421
+ pTagProjectOwner(event: NDKEvent): undefined {
422
+ const projectCtx = getProjectContext();
423
+ event.tag(["p", projectCtx.project.pubkey]);
424
+ }
425
+
426
+ /**
427
+ * Encode a lesson learned intent.
428
+ */
429
+ encodeLesson(
430
+ intent: LessonIntent,
431
+ context: EventContext,
432
+ agent: { eventId?: string }
433
+ ): NDKAgentLesson {
434
+ const lessonEvent = new NDKAgentLesson(getNDK());
435
+
436
+ // Set core properties
437
+ lessonEvent.title = intent.title;
438
+ lessonEvent.lesson = intent.lesson;
439
+
440
+ // Set optional properties
441
+ if (intent.detailed) {
442
+ lessonEvent.detailed = intent.detailed;
443
+ }
444
+ if (intent.category) {
445
+ lessonEvent.category = intent.category;
446
+ }
447
+ if (intent.hashtags && intent.hashtags.length > 0) {
448
+ lessonEvent.hashtags = intent.hashtags;
449
+ }
450
+
451
+ // Add reference to the agent event if available
452
+ if (agent.eventId) {
453
+ lessonEvent.agentDefinitionId = agent.eventId;
454
+ }
455
+
456
+ // Add standard metadata including project tag
457
+ this.addStandardTags(lessonEvent, context);
458
+
459
+ return lessonEvent;
460
+ }
461
+
462
+ /**
463
+ * Encode a follow-up event to a previous delegation response.
464
+ * Creates a threaded reply that maintains conversation context.
465
+ *
466
+ * @param responseEvent The event being responded to
467
+ * @param message The follow-up message content
468
+ * @param context Event context for standard tags
469
+ * @returns The encoded follow-up event
470
+ */
471
+ encodeFollowUp(responseEvent: NDKEvent, message: string, context: EventContext): NDKEvent {
472
+ // Create a reply to the response event to maintain thread
473
+ const followUpEvent = responseEvent.reply();
474
+
475
+ // Handle e-tag to avoid deep nesting
476
+ const eTagVal = responseEvent.tagValue("e");
477
+ if (eTagVal) {
478
+ followUpEvent.removeTag("e");
479
+ followUpEvent.tags.push(["e", eTagVal]); // Root thread tag
480
+ }
481
+
482
+ // Prepend recipient to content for follow-ups (single recipient)
483
+ const recipientPubkey = responseEvent.pubkey;
484
+ followUpEvent.content = this.prependRecipientsToContent(message, [recipientPubkey]);
485
+
486
+ // Clean out p-tags and add recipient
487
+ followUpEvent.tags = followUpEvent.tags.filter((t) => t[0] !== "p");
488
+ followUpEvent.tag(responseEvent.author);
489
+
490
+ // Add standard metadata (project tag, model, cost, execution time, ral number)
491
+ this.addStandardTags(followUpEvent, context);
492
+
493
+ // Forward branch tag from response event
494
+ const branchTag = responseEvent.tags.find((tag) => tag[0] === "branch" && tag[1]);
495
+ if (branchTag) {
496
+ followUpEvent.tag(["branch", branchTag[1]]);
497
+ }
498
+
499
+ return followUpEvent;
500
+ }
501
+
502
+ /**
503
+ * Encode a tool usage event.
504
+ * Creates an event that tracks tool invocation with output.
505
+ */
506
+ encodeToolUse(intent: ToolUseIntent, context: EventContext): NDKEvent {
507
+ const event = new NDKEvent(getNDK());
508
+ event.kind = NDKKind.Text; // kind:1 - unified conversation format
509
+ event.content = intent.content;
510
+
511
+ // Add conversation tags
512
+ this.addConversationTags(event, context);
513
+
514
+ // Add tool usage tags
515
+ event.tag(["tool", intent.toolName]);
516
+
517
+ // Add tool-args tag with JSON serialization
518
+ // If args are provided and can be serialized, add them
519
+ // If the serialized args are > 100k chars, add empty tag
520
+ if (intent.args !== undefined) {
521
+ try {
522
+ const serialized = JSON.stringify(intent.args);
523
+ if (serialized.length <= 100000) {
524
+ event.tag(["tool-args", serialized]);
525
+ } else {
526
+ event.tag(["tool-args"]);
527
+ }
528
+ } catch {
529
+ // If serialization fails, add empty tag
530
+ event.tag(["tool-args"]);
531
+ }
532
+ }
533
+
534
+ // Add q-tags for referenced events (e.g., delegation event IDs)
535
+ // Using "q" (quote) tag to indicate these are referenced/quoted events
536
+ if (intent.referencedEventIds) {
537
+ for (const eventId of intent.referencedEventIds) {
538
+ event.tag(["q", eventId]);
539
+ }
540
+ }
541
+
542
+ // Add a-tags for referenced addressable events (e.g., NDKArticle reports)
543
+ // Format: "30023:pubkey:d-tag" for kind 30023 addressable events
544
+ if (intent.referencedAddressableEvents) {
545
+ for (const addressableRef of intent.referencedAddressableEvents) {
546
+ event.tag(["a", addressableRef]);
547
+ }
548
+ }
549
+
550
+ // Add standard metadata
551
+ this.addStandardTags(event, context);
552
+
553
+ // Forward branch tag from triggering event
554
+ this.forwardBranchTag(event, context);
555
+
556
+ // Add LLM usage tags if available (cumulative from previous steps)
557
+ if (intent.usage) {
558
+ this.addLLMUsageTags(event, intent.usage);
559
+ }
560
+
561
+ return event;
562
+ }
563
+
564
+ /**
565
+ * Encode an intervention review request event.
566
+ * This is used by the InterventionService when a user hasn't responded
567
+ * to an agent's completion within the configured timeout.
568
+ *
569
+ * Event structure:
570
+ * - kind: 1 (text note)
571
+ * - content: Review request message with human-readable names (pre-resolved by caller)
572
+ * - tags:
573
+ * - ["p", targetPubkey] - The intervention agent to notify
574
+ * - ["context", "intervention-review"] - Context marker
575
+ * - ["e", conversationId] - Reference to the conversation (short form already in content)
576
+ * - ["a", projectTag] - Project reference (added internally via aTagProject)
577
+ *
578
+ * Note: This method does NOT call addStandardTags() since intervention events
579
+ * are not part of an agent execution context. However, the project tag is
580
+ * added internally via aTagProject() for proper project association.
581
+ *
582
+ * Names (userName, agentName) are pre-resolved by the caller (InterventionPublisher)
583
+ * to avoid layer violations - AgentEventEncoder (layer 2) cannot import PubkeyService (layer 3).
584
+ */
585
+ encodeInterventionReview(intent: InterventionReviewIntent): NDKEvent {
586
+ const event = new NDKEvent(getNDK());
587
+ event.kind = NDKKind.Text; // kind:1
588
+
589
+ const shortConversationId = shortenConversationId(intent.conversationId);
590
+
591
+ event.content = `Conversation ${shortConversationId} has completed and ${intent.userName} hasn't responded. ${intent.agentName} finished their work. Please review and decide if action is needed.`;
592
+
593
+ // Target intervention agent
594
+ event.tag(["p", intent.targetPubkey]);
595
+
596
+ // Context marker for intervention routing
597
+ event.tag(["context", "intervention-review"]);
598
+
599
+ // Reference to the conversation (e-tag for event reference)
600
+ event.tag(["e", intent.conversationId]);
601
+
602
+ // Add project tag (intervention events need project association)
603
+ this.aTagProject(event);
604
+
605
+ logger.debug("Encoded intervention review event", {
606
+ targetPubkey: intent.targetPubkey.substring(0, 8),
607
+ conversationId: shortConversationId,
608
+ userName: intent.userName,
609
+ agentName: intent.agentName,
610
+ });
611
+
612
+ return event;
613
+ }
614
+
615
+ /**
616
+ * Encode a delegation marker event.
617
+ * Delegation markers track the lifecycle of delegation conversations.
618
+ *
619
+ * Event structure:
620
+ * - kind: 4203 (DelegationMarker) - custom kind for delegation lifecycle tracking
621
+ * - content: Empty string (markers have no text content)
622
+ * - tags:
623
+ * - ["delegation-marker", status] - Marker type and status
624
+ * - ["e", delegationConversationId] - Reference to the delegation conversation
625
+ * - ["e", parentConversationId] - Reference to the parent conversation
626
+ * - ["p", recipientPubkey] - The agent that received the delegation
627
+ * - ["initiated-at", timestamp] - When delegation was initiated (optional)
628
+ * - ["completed-at", timestamp] - When delegation completed (optional, for completed/aborted)
629
+ * - ["abort-reason", reason] - Abort reason (optional, for aborted)
630
+ * - ["a", projectTag] - Project reference (added internally via aTagProject)
631
+ */
632
+ encodeDelegationMarker(intent: DelegationMarkerIntent): NDKEvent {
633
+ const event = new NDKEvent(getNDK());
634
+ event.kind = NDKKind.DelegationMarker; // kind:4203 - dedicated kind prevents spam filtering
635
+
636
+ // Markers have no text content
637
+ event.content = "";
638
+
639
+ // Add delegation marker tag with status
640
+ event.tag(["delegation-marker", intent.status]);
641
+
642
+ // Add delegation conversation reference
643
+ event.tag(["e", intent.delegationConversationId]);
644
+
645
+ // Add parent conversation reference
646
+ event.tag(["e", intent.parentConversationId]);
647
+
648
+ // Add recipient agent pubkey
649
+ event.tag(["p", intent.recipientPubkey]);
650
+
651
+ // Add timestamp tags
652
+ if (intent.initiatedAt !== undefined) {
653
+ event.tag(["initiated-at", intent.initiatedAt.toString()]);
654
+ }
655
+
656
+ if (intent.completedAt !== undefined) {
657
+ event.tag(["completed-at", intent.completedAt.toString()]);
658
+ }
659
+
660
+ // Add abort reason if present
661
+ if (intent.abortReason) {
662
+ event.tag(["abort-reason", intent.abortReason]);
663
+ }
664
+
665
+ // Add project tag
666
+ this.aTagProject(event);
667
+
668
+ logger.debug("Encoded delegation marker event", {
669
+ delegationConversationId: intent.delegationConversationId.substring(0, 12),
670
+ parentConversationId: intent.parentConversationId.substring(0, 12),
671
+ recipientPubkey: intent.recipientPubkey.substring(0, 8),
672
+ status: intent.status,
673
+ });
674
+
675
+ return event;
676
+ }
677
+ }