@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,661 @@
1
+ import type { ToolExecutionContext } from "@/tools/types";
2
+ import { ConversationStore } from "@/conversations/ConversationStore";
3
+ import { llmServiceFactory } from "@/llm";
4
+ import { config } from "@/services/ConfigService";
5
+ import { getPubkeyService } from "@/services/PubkeyService";
6
+ import type { AISdkTool } from "@/tools/types";
7
+ import { logger } from "@/utils/logger";
8
+ import { isHexPrefix, resolvePrefixToId, PREFIX_LENGTH } from "@/utils/nostr-entity-parser";
9
+ import { tool } from "ai";
10
+ import type { ToolCallPart, ToolResultPart } from "ai";
11
+ import { z } from "zod";
12
+ import { nip19 } from "nostr-tools";
13
+
14
+ /**
15
+ * Normalizes various event ID formats to a canonical 64-char lowercase hex ID.
16
+ *
17
+ * Accepts:
18
+ * - Full 64-character hex IDs
19
+ * - 12-character hex prefixes (resolved via PrefixKVStore)
20
+ * - NIP-19 formats: note1..., nevent1...
21
+ * - nostr: prefixed versions of all the above
22
+ *
23
+ * @param input - The event ID in any supported format
24
+ * @returns The normalized 64-char hex ID, or null if resolution fails
25
+ */
26
+ function normalizeEventId(input: string): string | null {
27
+ const trimmed = input.trim();
28
+
29
+ // Strip nostr: prefix if present
30
+ const cleaned = trimmed.startsWith("nostr:") ? trimmed.slice(6) : trimmed;
31
+
32
+ // 1. Check for full 64-char hex ID
33
+ if (/^[0-9a-f]{64}$/i.test(cleaned)) {
34
+ return cleaned.toLowerCase();
35
+ }
36
+
37
+ // 2. Check for 12-char hex prefix - resolve via PrefixKVStore
38
+ if (isHexPrefix(cleaned)) {
39
+ const resolved = resolvePrefixToId(cleaned);
40
+ return resolved; // Returns null if not found
41
+ }
42
+
43
+ // 3. Try NIP-19 decoding (note1..., nevent1...)
44
+ try {
45
+ const decoded = nip19.decode(cleaned);
46
+ if (decoded.type === "note") {
47
+ return (decoded.data as string).toLowerCase();
48
+ }
49
+ if (decoded.type === "nevent") {
50
+ return (decoded.data as { id: string }).id.toLowerCase();
51
+ }
52
+ } catch {
53
+ // Not a valid NIP-19 format, fall through
54
+ }
55
+
56
+ // Invalid format or resolution failed
57
+ return null;
58
+ }
59
+
60
+ const conversationGetSchema = z.object({
61
+ conversationId: z
62
+ .string()
63
+ .min(1, "conversationId is required")
64
+ .describe("The conversation ID to retrieve. Accepts full 64-char hex IDs (case-insensitive), 12-character hex prefixes, NIP-19 formats (note1..., nevent1...), or nostr: prefixed versions of any format."),
65
+ untilId: z
66
+ .string()
67
+ .optional()
68
+ .describe(
69
+ "Optional message ID to retrieve conversation slice up to and including this message. Accepts full 64-char hex IDs (case-insensitive), 12-character hex prefixes, NIP-19 formats (note1..., nevent1...), or nostr: prefixed versions of any format. Useful for synthetic conversation forks where a new conversation references a parent conversation up to a specific message point."
70
+ ),
71
+ prompt: z
72
+ .string()
73
+ .optional()
74
+ .describe(
75
+ "Optional prompt to analyze the conversation. When provided, the conversation will be processed through an LLM which will provide an explanation based on this prompt. Useful for extracting specific information or getting a summary of the conversation."
76
+ ),
77
+ includeToolResults: z
78
+ .boolean()
79
+ .optional()
80
+ .default(false)
81
+ .describe(
82
+ "Whether to include tool result content in the response. WARNING: This can significantly increase token usage (up to 50k tokens). Tool results are truncated at 10k chars each with a 50k total budget. Only enable if you specifically need to analyze tool outputs."
83
+ ),
84
+ });
85
+
86
+ type ConversationGetInput = z.infer<typeof conversationGetSchema>;
87
+
88
+ interface ConversationGetOutput {
89
+ success: boolean;
90
+ conversation?: Record<string, unknown>;
91
+ explanation?: string;
92
+ message?: string;
93
+ }
94
+
95
+ /**
96
+ * Recursively deep copy an object while handling cycles, BigInts, Maps, Sets, and other edge cases
97
+ */
98
+ function safeDeepCopy(obj: unknown, seen = new WeakSet()): unknown {
99
+ // Handle primitives and special values
100
+ if (obj === null || typeof obj !== "object") {
101
+ if (typeof obj === "bigint") return obj.toString();
102
+ if (typeof obj === "function") return undefined;
103
+ return obj;
104
+ }
105
+
106
+ // Cycle detection
107
+ if (seen.has(obj)) {
108
+ return "[Circular]";
109
+ }
110
+ seen.add(obj);
111
+
112
+ // Handle Arrays
113
+ if (Array.isArray(obj)) {
114
+ return obj.map(item => safeDeepCopy(item, seen));
115
+ }
116
+
117
+ // Handle Maps
118
+ if (obj instanceof Map) {
119
+ const result: Record<string, unknown> = {};
120
+ for (const [key, value] of obj) {
121
+ result[String(key)] = safeDeepCopy(value, seen);
122
+ }
123
+ return result;
124
+ }
125
+
126
+ // Handle Sets
127
+ if (obj instanceof Set) {
128
+ return Array.from(obj).map(item => safeDeepCopy(item, seen));
129
+ }
130
+
131
+ // Handle Dates
132
+ if (obj instanceof Date) {
133
+ return obj.toISOString();
134
+ }
135
+
136
+ // Handle plain Objects
137
+ const result: Record<string, unknown> = {};
138
+ for (const key in obj) {
139
+ // Only process own properties
140
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
141
+ try {
142
+ result[key] = safeDeepCopy((obj as Record<string, unknown>)[key], seen);
143
+ } catch {
144
+ result[key] = "[Access Error]";
145
+ }
146
+ }
147
+ }
148
+ return result;
149
+ }
150
+
151
+ /**
152
+ * Safely copy data while handling circular references, BigInts, Maps, Sets, and other edge cases
153
+ * Uses recursive deep copy with cycle detection instead of JSON.stringify
154
+ */
155
+ function safeCopy<T>(data: T): T {
156
+ try {
157
+ return safeDeepCopy(data) as T;
158
+ } catch {
159
+ // Fallback to string representation if even deep copy fails
160
+ return "[Serialization Failed]" as unknown as T;
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Safely stringify a value, handling BigInt, circular refs, and other edge cases
166
+ * Returns a JSON string representation or "[Unserializable]" on failure
167
+ */
168
+ function safeStringify(value: unknown): string {
169
+ if (value === undefined) return "";
170
+ if (value === null) return "null";
171
+ try {
172
+ return JSON.stringify(value);
173
+ } catch {
174
+ // Handle BigInt, circular references, or other unserializable values
175
+ return '"[Unserializable]"';
176
+ }
177
+ }
178
+
179
+ const MAX_PARAM_LENGTH = 100;
180
+
181
+ /**
182
+ * Format tool input parameters with per-param truncation
183
+ * Each param value is truncated at MAX_PARAM_LENGTH chars
184
+ * Format: param1="value1" param2="value2..." (N chars truncated)
185
+ */
186
+ function formatToolInput(input: unknown): string {
187
+ if (input === undefined || input === null) return "";
188
+
189
+ // If input is not an object, just stringify and truncate the whole thing
190
+ if (typeof input !== "object" || Array.isArray(input)) {
191
+ const str = safeStringify(input);
192
+ if (str.length > MAX_PARAM_LENGTH) {
193
+ const truncated = str.length - MAX_PARAM_LENGTH;
194
+ return `${str.slice(0, MAX_PARAM_LENGTH)}... (${truncated} chars truncated)`;
195
+ }
196
+ return str;
197
+ }
198
+
199
+ // For objects, format each param with truncation
200
+ const parts: string[] = [];
201
+ const obj = input as Record<string, unknown>;
202
+
203
+ for (const [key, value] of Object.entries(obj)) {
204
+ let valueStr: string;
205
+ try {
206
+ valueStr = JSON.stringify(value);
207
+ } catch {
208
+ valueStr = '"[Unserializable]"';
209
+ }
210
+
211
+ if (valueStr.length > MAX_PARAM_LENGTH) {
212
+ const truncated = valueStr.length - MAX_PARAM_LENGTH;
213
+ parts.push(`${key}=${valueStr.slice(0, MAX_PARAM_LENGTH)}... (${truncated} chars truncated)`);
214
+ } else {
215
+ parts.push(`${key}=${valueStr}`);
216
+ }
217
+ }
218
+
219
+ return parts.join(" ");
220
+ }
221
+
222
+ const MAX_LINE_LENGTH = 1500;
223
+
224
+ /**
225
+ * Format a single line with timestamp, sender, target(s), and content
226
+ * Truncates the full line INCLUDING suffix to maxLength chars
227
+ */
228
+ function formatLine(
229
+ relativeSeconds: number,
230
+ from: string,
231
+ targets: string[] | undefined,
232
+ content: string,
233
+ maxLength: number = MAX_LINE_LENGTH
234
+ ): string {
235
+ // Build target string: no target = "", single = "-> @to", multiple = "-> @to1, @to2"
236
+ let targetStr = "";
237
+ if (targets && targets.length > 0) {
238
+ targetStr = ` -> ${targets.map(t => `@${t}`).join(", ")}`;
239
+ }
240
+
241
+ // Escape newlines to preserve single-line format
242
+ const escapedContent = content.replace(/\n/g, "\\n");
243
+
244
+ const line = `[+${relativeSeconds}] [@${from}${targetStr}] ${escapedContent}`;
245
+
246
+ if (line.length > maxLength) {
247
+ // Calculate suffix first, then determine how much content to keep
248
+ // We want: kept_content + suffix <= maxLength
249
+ const truncatedChars = line.length - maxLength;
250
+ const suffix = `... [truncated ${truncatedChars} chars]`;
251
+ const keepLength = Math.max(0, maxLength - suffix.length);
252
+ return line.slice(0, keepLength) + suffix;
253
+ }
254
+ return line;
255
+ }
256
+
257
+ /**
258
+ * Serialize a Conversation object to a JSON-safe plain object
259
+ * Formats messages as a single multi-line string with relative timestamps
260
+ * Format: [+seconds] [@from -> @to] content
261
+ */
262
+ function serializeConversation(
263
+ conversation: ConversationStore,
264
+ options: { includeToolResults?: boolean; untilId?: string } = {}
265
+ ): Record<string, unknown> {
266
+ let messages = conversation.getAllMessages();
267
+ const pubkeyService = getPubkeyService();
268
+
269
+ // Filter messages up to and including untilId if provided
270
+ if (options.untilId) {
271
+ const untilIndex = messages.findIndex(msg => msg.eventId === options.untilId);
272
+ if (untilIndex === -1) {
273
+ // Message not found - return all messages as graceful fallback
274
+ logger.warn("untilId not found in conversation, returning all messages", {
275
+ untilId: options.untilId,
276
+ conversationId: conversation.id,
277
+ });
278
+ } else {
279
+ // Include messages up to and including the untilId message
280
+ messages = messages.slice(0, untilIndex + 1);
281
+ }
282
+ }
283
+
284
+ // Find the first DEFINED timestamp to use as baseline for relative times.
285
+ // This handles edge cases where early messages (e.g., tool-calls synced via
286
+ // MessageSyncer) may lack timestamps. Using the first defined timestamp
287
+ // ensures later messages don't show huge epoch offsets.
288
+ let baselineTimestamp = 0;
289
+ for (const msg of messages) {
290
+ if (msg.timestamp !== undefined) {
291
+ baselineTimestamp = msg.timestamp;
292
+ break;
293
+ }
294
+ }
295
+
296
+ const formattedLines: string[] = [];
297
+
298
+ // Track the last known timestamp for fallback on entries without timestamps.
299
+ // This provides more accurate ordering than always falling back to baseline.
300
+ let lastKnownTimestamp = baselineTimestamp;
301
+
302
+ for (let i = 0; i < messages.length; i++) {
303
+ const entry = messages[i];
304
+ // Use lastKnownTimestamp as fallback when entry.timestamp is undefined.
305
+ // This ensures entries without timestamps (e.g., tool-calls synced via MessageSyncer)
306
+ // appear at their approximate position rather than showing [+0] or huge negative
307
+ // numbers like [+-1771103685].
308
+ const effectiveTimestamp = entry.timestamp ?? lastKnownTimestamp;
309
+ const relativeSeconds = Math.floor(effectiveTimestamp - baselineTimestamp);
310
+
311
+ // Update lastKnownTimestamp if this entry has a defined timestamp
312
+ if (entry.timestamp !== undefined) {
313
+ lastKnownTimestamp = entry.timestamp;
314
+ }
315
+ const from = pubkeyService.getNameSync(entry.pubkey);
316
+ const targets = entry.targetedPubkeys?.map(pk => pubkeyService.getNameSync(pk));
317
+
318
+ if (entry.messageType === "text") {
319
+ // Text messages: straightforward format
320
+ formattedLines.push(formatLine(relativeSeconds, from, targets, entry.content));
321
+ } else if (entry.messageType === "tool-call") {
322
+ // Only include tool calls if includeToolResults is true
323
+ if (!options.includeToolResults) {
324
+ // Skip tool call entries when not including tool results
325
+ continue;
326
+ }
327
+
328
+ // Tool call: look for matching tool-results by toolCallId or adjacency
329
+ const toolData = (entry.toolData ?? []) as ToolCallPart[];
330
+
331
+ // Check if we have toolCallIds to match with
332
+ const hasToolCallIds = toolData.some(tc => tc.toolCallId);
333
+
334
+ // Build a map of toolCallId -> result for matching (when IDs are present)
335
+ const toolResultsMap = new Map<string, ToolResultPart>();
336
+ // Also keep an ordered array for fallback adjacency matching
337
+ let adjacentResults: ToolResultPart[] = [];
338
+ let shouldSkipNext = false;
339
+
340
+ if (i + 1 < messages.length) {
341
+ const nextMsg = messages[i + 1];
342
+ if (nextMsg.messageType === "tool-result" && nextMsg.pubkey === entry.pubkey) {
343
+ const resultData = (nextMsg.toolData ?? []) as ToolResultPart[];
344
+ adjacentResults = resultData;
345
+
346
+ // Build toolCallId map for ID-based matching
347
+ for (const tr of resultData) {
348
+ if (tr.toolCallId) {
349
+ toolResultsMap.set(tr.toolCallId, tr);
350
+ }
351
+ }
352
+ }
353
+ }
354
+
355
+ // Format tool calls with their matched results
356
+ const toolCallParts: string[] = [];
357
+ const matchedResultIds = new Set<string>();
358
+ let adjacentResultIndex = 0;
359
+
360
+ for (const tc of toolData) {
361
+ const toolName = tc.toolName || "unknown";
362
+ const input = tc.input !== undefined ? formatToolInput(tc.input) : "";
363
+ let toolCallStr = `[tool-use ${toolName} ${input}]`;
364
+
365
+ let matchingResult: ToolResultPart | undefined;
366
+
367
+ // Try to find matching result by toolCallId first
368
+ if (tc.toolCallId && toolResultsMap.has(tc.toolCallId)) {
369
+ matchingResult = toolResultsMap.get(tc.toolCallId);
370
+ matchedResultIds.add(tc.toolCallId);
371
+ } else if (!hasToolCallIds && adjacentResultIndex < adjacentResults.length) {
372
+ // Fallback: when no toolCallIds, match by position (adjacency)
373
+ matchingResult = adjacentResults[adjacentResultIndex++];
374
+ }
375
+
376
+ if (matchingResult) {
377
+ const resultContent =
378
+ matchingResult.output !== undefined
379
+ ? safeStringify(matchingResult.output)
380
+ : "";
381
+ toolCallStr += ` [tool-result ${resultContent}]`;
382
+ shouldSkipNext = true;
383
+ }
384
+ toolCallParts.push(toolCallStr);
385
+ }
386
+
387
+ // Skip the next tool-result message if we merged all results
388
+ if (shouldSkipNext && i + 1 < messages.length) {
389
+ const nextMsg = messages[i + 1];
390
+ if (nextMsg.messageType === "tool-result" && nextMsg.pubkey === entry.pubkey) {
391
+ // For ID-based matching, verify all were matched
392
+ // For adjacency-based, we already processed them all
393
+ if (!hasToolCallIds || adjacentResults.every(tr => !tr.toolCallId || matchedResultIds.has(tr.toolCallId))) {
394
+ i++;
395
+ }
396
+ }
397
+ }
398
+
399
+ const content = toolCallParts.join(" ");
400
+ formattedLines.push(formatLine(relativeSeconds, from, targets, content));
401
+ } else if (entry.messageType === "tool-result") {
402
+ // Standalone tool-result (not merged with tool-call)
403
+ // Only show if includeToolResults is true
404
+ if (options.includeToolResults) {
405
+ const resultData = (entry.toolData ?? []) as ToolResultPart[];
406
+ const resultParts: string[] = [];
407
+ for (const tr of resultData) {
408
+ const resultContent =
409
+ tr.output !== undefined ? safeStringify(tr.output) : "";
410
+ resultParts.push(`[tool-result ${resultContent}]`);
411
+ }
412
+ formattedLines.push(formatLine(relativeSeconds, from, targets, resultParts.join(" ")));
413
+ }
414
+ } else if (entry.messageType === "delegation-marker") {
415
+ // Delegation markers: always shown (regardless of includeToolResults)
416
+ const marker = entry.delegationMarker;
417
+
418
+ // Validate required fields - skip gracefully if missing
419
+ if (!marker?.delegationConversationId || !marker?.recipientPubkey || !marker?.status) {
420
+ // Skip malformed delegation marker - don't crash, just omit from output
421
+ continue;
422
+ }
423
+
424
+ const shortConversationId = marker.delegationConversationId.slice(0, PREFIX_LENGTH);
425
+ const recipientName = pubkeyService.getNameSync(marker.recipientPubkey);
426
+
427
+ // Format based on status
428
+ let emoji: string;
429
+ let statusText: string;
430
+ if (marker.status === "pending") {
431
+ emoji = "⏳";
432
+ statusText = "in progress";
433
+ } else if (marker.status === "completed") {
434
+ emoji = "✅";
435
+ statusText = "completed";
436
+ } else {
437
+ emoji = "⚠️";
438
+ statusText = "aborted";
439
+ }
440
+ const content = `${emoji} Delegation ${shortConversationId} → ${recipientName} ${statusText}`;
441
+
442
+ formattedLines.push(formatLine(relativeSeconds, from, targets, content));
443
+ }
444
+ }
445
+
446
+ return {
447
+ id: String(conversation.id),
448
+ title: conversation.title ? String(conversation.title) : undefined,
449
+ executionTime: safeCopy(conversation.executionTime),
450
+ messageCount: messages.length,
451
+ messages: formattedLines.join("\n"),
452
+ };
453
+ }
454
+
455
+ /**
456
+ * Core implementation of conversation retrieval functionality
457
+ */
458
+ async function executeConversationGet(
459
+ input: ConversationGetInput,
460
+ context: ToolExecutionContext
461
+ ): Promise<ConversationGetOutput> {
462
+ if (!input.conversationId) {
463
+ return {
464
+ success: false,
465
+ message: "conversationId is required",
466
+ };
467
+ }
468
+
469
+ // Normalize conversation ID to full 64-char hex
470
+ const targetConversationId = normalizeEventId(input.conversationId);
471
+ if (!targetConversationId) {
472
+ return {
473
+ success: false,
474
+ message: `Could not resolve conversation ID "${input.conversationId}". Expected 64-char hex, 12-char hex prefix, or NIP-19 format (note1.../nevent1...).`,
475
+ };
476
+ }
477
+
478
+ // Normalize untilId if provided - graceful fallback for optional parameter
479
+ let targetUntilId: string | undefined = undefined;
480
+ if (input.untilId) {
481
+ const resolved = normalizeEventId(input.untilId);
482
+ targetUntilId = resolved ?? undefined;
483
+ if (!resolved) {
484
+ logger.warn("Could not resolve untilId, proceeding without filtering", {
485
+ untilId: input.untilId,
486
+ conversationId: targetConversationId,
487
+ agent: context.agent.name,
488
+ });
489
+ // Fall back to undefined - return unfiltered conversation
490
+ targetUntilId = undefined;
491
+ }
492
+ }
493
+
494
+ logger.info("📖 Retrieving conversation", {
495
+ conversationId: targetConversationId,
496
+ isCurrentConversation: targetConversationId === context.conversationId,
497
+ agent: context.agent.name,
498
+ });
499
+
500
+ // Get conversation from ConversationStore
501
+ const conversation =
502
+ targetConversationId === context.conversationId
503
+ ? context.getConversation()
504
+ : ConversationStore.get(targetConversationId);
505
+
506
+ if (!conversation) {
507
+ logger.info("📭 Conversation not found", {
508
+ conversationId: targetConversationId,
509
+ agent: context.agent.name,
510
+ });
511
+
512
+ return {
513
+ success: false,
514
+ message: `Conversation ${targetConversationId} not found`,
515
+ };
516
+ }
517
+
518
+ logger.info("✅ Conversation retrieved successfully", {
519
+ conversationId: conversation.id,
520
+ title: conversation.title,
521
+ messageCount: conversation.getMessageCount(),
522
+ untilId: targetUntilId,
523
+ agent: context.agent.name,
524
+ });
525
+
526
+ const serializedConversation = serializeConversation(conversation, {
527
+ includeToolResults: input.includeToolResults,
528
+ untilId: targetUntilId,
529
+ });
530
+
531
+ // If a prompt is provided, process the conversation through the LLM
532
+ if (input.prompt) {
533
+ try {
534
+ // Get LLM configuration - use summarization config if set, otherwise default
535
+ // Use getLLMConfig to resolve meta models automatically
536
+ const { llms } = await config.loadConfig();
537
+ const configName = llms.summarization || llms.default;
538
+
539
+ if (!configName) {
540
+ logger.warn("No LLM configuration available for conversation analysis");
541
+ return {
542
+ success: true,
543
+ conversation: serializedConversation,
544
+ message: "No LLM configuration available for prompt processing",
545
+ };
546
+ }
547
+
548
+ const llmConfig = config.getLLMConfig(configName);
549
+
550
+ // Create LLM service
551
+ const llmService = llmServiceFactory.createService(llmConfig, {
552
+ agentName: "conversation-analyzer",
553
+ sessionId: `analyzer-${targetConversationId}`,
554
+ });
555
+
556
+ // Format conversation for LLM processing
557
+ const conversationText = JSON.stringify(serializedConversation, null, 2);
558
+
559
+ // Generate explanation using the LLM
560
+ const { object: result } = await llmService.generateObject(
561
+ [
562
+ {
563
+ role: "system",
564
+ content: `You are a helpful assistant that analyzes conversations and provides explanations based on user prompts.
565
+
566
+ CRITICAL REQUIREMENTS:
567
+ 1. VERBATIM QUOTES: You MUST include relevant parts of the conversation verbatim in your response. Quote the exact messages that support your analysis.
568
+ 2. PRESERVE IDENTIFIERS: All IDs, pubkeys, agent slugs, conversation IDs, event IDs, and other addressable data must be preserved exactly as they appear.
569
+ 3. When referencing specific messages or participants, include their identifiers exactly as they appear.
570
+ 4. Do not abbreviate or modify any identifiers - they are essential for traceability and reference.
571
+ 5. Base your analysis ONLY on what is explicitly stated in the conversation.
572
+
573
+ FORMAT: Structure your response with:
574
+ - Your analysis/explanation
575
+ - Verbatim quotes from relevant messages (use quotation marks and attribute to the sender)
576
+ - All referenced identifiers preserved exactly
577
+
578
+ The user will provide a prompt describing what they want to know about the conversation.`,
579
+ },
580
+ {
581
+ role: "user",
582
+ content: `Please analyze the following conversation based on this prompt: "${input.prompt}"
583
+
584
+ IMPORTANT: Include verbatim quotes from the relevant parts of the conversation that support your analysis.
585
+
586
+ CONVERSATION DATA:
587
+ ${conversationText}`,
588
+ },
589
+ ],
590
+ z.object({
591
+ explanation: z
592
+ .string()
593
+ .describe(
594
+ "A detailed explanation based on the user's prompt. MUST include verbatim quotes from relevant messages and preserve all important identifiers."
595
+ ),
596
+ })
597
+ );
598
+
599
+ logger.info("✅ Conversation analyzed with prompt", {
600
+ conversationId: conversation.id,
601
+ promptLength: input.prompt.length,
602
+ agent: context.agent.name,
603
+ });
604
+
605
+ return {
606
+ success: true,
607
+ conversation: serializedConversation,
608
+ explanation: result.explanation,
609
+ };
610
+ } catch (error) {
611
+ logger.error("Failed to process conversation with prompt", {
612
+ conversationId: conversation.id,
613
+ error: error instanceof Error ? error.message : String(error),
614
+ agent: context.agent.name,
615
+ });
616
+
617
+ return {
618
+ success: true,
619
+ conversation: serializedConversation,
620
+ message: `Failed to process prompt: ${error instanceof Error ? error.message : String(error)}`,
621
+ };
622
+ }
623
+ }
624
+
625
+ return {
626
+ success: true,
627
+ conversation: serializedConversation,
628
+ };
629
+ }
630
+
631
+ /**
632
+ * Create an AI SDK tool for retrieving conversations
633
+ */
634
+ export function createConversationGetTool(context: ToolExecutionContext): AISdkTool {
635
+ const aiTool = tool({
636
+ description:
637
+ "Retrieve a conversation by its ID, including all messages/events in the conversation history. Returns conversation info (id, title, messageCount, executionTime) and a formatted messages string. Messages are formatted as: [+seconds] [@from -> @to] content, where seconds is relative to the first message. Tool calls and results can be merged into single lines when includeToolResults is true. Useful for reviewing conversation context, analyzing message history, or debugging agent interactions.",
638
+
639
+ inputSchema: conversationGetSchema,
640
+
641
+ execute: async (input: ConversationGetInput) => {
642
+ return await executeConversationGet(input, context);
643
+ },
644
+ });
645
+
646
+ Object.defineProperty(aiTool, "getHumanReadableContent", {
647
+ value: ({ conversationId, untilId, prompt }: ConversationGetInput) => {
648
+ const target = conversationId
649
+ ? `conversation: ${conversationId}`
650
+ : "conversation (missing id)";
651
+ const upTo = untilId ? ` up to message ${untilId}` : "";
652
+ return prompt
653
+ ? `Analyzing ${target}${upTo} with prompt`
654
+ : `Retrieving ${target}${upTo}`;
655
+ },
656
+ enumerable: false,
657
+ configurable: true,
658
+ });
659
+
660
+ return aiTool as AISdkTool;
661
+ }