@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,579 @@
1
+ /**
2
+ * StreamExecutionHandler - Handles LLM streaming execution with event processing
3
+ *
4
+ * This class encapsulates stream event handling and coordinates
5
+ * LLM streaming with message persistence and delegation handling.
6
+ * Callbacks are created via StreamCallbacks module.
7
+ */
8
+
9
+ import { formatAnyError, formatStreamError } from "@/lib/error-formatter";
10
+ import {
11
+ type ChunkTypeChangeEvent,
12
+ type CompleteEvent,
13
+ type ContentEvent,
14
+ type RawChunkEvent,
15
+ type ReasoningEvent,
16
+ type SessionCapturedEvent,
17
+ type StreamErrorEvent,
18
+ } from "@/llm/types";
19
+ import { streamPublisher } from "@/llm";
20
+ import { PROVIDER_IDS } from "@/llm/providers/provider-ids";
21
+ import { shortenConversationId } from "@/utils/conversation-id";
22
+ import type { EventContext } from "@/nostr/types";
23
+ import { llmOpsRegistry } from "@/services/LLMOperationsRegistry";
24
+ import { RALRegistry } from "@/services/ral";
25
+ import type { SkillData } from "@/services/skill";
26
+ import { clearLLMSpanId } from "@/telemetry/LLMSpanRegistry";
27
+ import type { AISdkTool } from "@/tools/types";
28
+ import { createEventContext } from "@/services/event-context";
29
+ import { logger } from "@/utils/logger";
30
+ import { trace } from "@opentelemetry/api";
31
+ import type { LanguageModel, ModelMessage } from "ai";
32
+ import chalk from "chalk";
33
+ import type { LLMService } from "@/llm/service";
34
+ import type { MessageCompiler } from "./MessageCompiler";
35
+ import type { SessionManager } from "./SessionManager";
36
+ import type { ToolExecutionTracker } from "./ToolExecutionTracker";
37
+ import { createPrepareStep } from "./StreamCallbacks";
38
+ import { setupToolEventHandlers } from "./ToolEventHandlers";
39
+ import type { FullRuntimeContext, RALExecutionContext, StreamExecutionResult } from "./types";
40
+ import { extractLastUserMessage } from "./utils";
41
+ import { CompressionService } from "@/services/compression/CompressionService.js";
42
+
43
+ /**
44
+ * Configuration for stream execution
45
+ */
46
+ export interface StreamExecutionConfig {
47
+ context: FullRuntimeContext;
48
+ toolTracker: ToolExecutionTracker;
49
+ ralNumber: number;
50
+ toolsObject: Record<string, AISdkTool>;
51
+ sessionManager: SessionManager;
52
+ llmService: LLMService;
53
+ messageCompiler: MessageCompiler;
54
+ nudgeContent: string;
55
+ /** Concatenated skill content */
56
+ skillContent: string;
57
+ /** Individual skill data for system prompt rendering */
58
+ skills: SkillData[];
59
+ ephemeralMessages: Array<{ role: "user" | "system"; content: string }>;
60
+ abortSignal: AbortSignal;
61
+ metaModelSystemPrompt?: string;
62
+ variantSystemPrompt?: string;
63
+ /** Optional dedicated LLM service for compression operations */
64
+ compressionLlmService?: LLMService;
65
+ }
66
+
67
+ /**
68
+ * Handles all LLM stream event processing and coordination
69
+ */
70
+ export class StreamExecutionHandler {
71
+ private contentBuffer = "";
72
+ private reasoningBuffer = "";
73
+ private result: StreamExecutionResult | undefined;
74
+ private lastUsedVariant: string | undefined;
75
+ private currentModel: LanguageModel | undefined;
76
+ private readonly execContext: RALExecutionContext;
77
+ private readonly executionSpan = trace.getActiveSpan();
78
+
79
+ constructor(private readonly config: StreamExecutionConfig) {
80
+ this.lastUsedVariant = config.context.conversationStore.getMetaModelVariantOverride(
81
+ config.context.agent.pubkey
82
+ );
83
+ this.execContext = { accumulatedMessages: [] };
84
+ }
85
+
86
+ /**
87
+ * Execute the stream and return the result
88
+ */
89
+ async execute(messages: ModelMessage[]): Promise<StreamExecutionResult> {
90
+ const { context, llmService, toolsObject, abortSignal } = this.config;
91
+ const ralRegistry = RALRegistry.getInstance();
92
+ const conversationStore = context.conversationStore;
93
+ const ralNumber = this.config.ralNumber;
94
+
95
+ // Initialize execution context
96
+ this.execContext.accumulatedMessages = messages;
97
+
98
+ // Setup all event handlers
99
+ this.setupEventHandlers();
100
+
101
+ try {
102
+ // Mark this RAL as streaming and start timing LLM runtime
103
+ ralRegistry.setStreaming(context.agent.pubkey, context.conversationId, ralNumber, true);
104
+ const lastUserMessage = extractLastUserMessage(messages);
105
+ ralRegistry.startLLMStream(context.agent.pubkey, context.conversationId, ralNumber, lastUserMessage);
106
+
107
+ // DIAGNOSTIC: Capture process state at stream start for bottleneck analysis
108
+ const memUsage = process.memoryUsage();
109
+ const cpuUsage = process.cpuUsage();
110
+ this.executionSpan?.addEvent("executor.stream_start_process_state", {
111
+ "process.memory_heap_used_mb": Math.round(memUsage.heapUsed / 1024 / 1024),
112
+ "process.memory_heap_total_mb": Math.round(memUsage.heapTotal / 1024 / 1024),
113
+ "process.memory_rss_mb": Math.round(memUsage.rss / 1024 / 1024),
114
+ "process.memory_external_mb": Math.round(memUsage.external / 1024 / 1024),
115
+ "process.cpu_user_ms": Math.round(cpuUsage.user / 1000),
116
+ "process.cpu_system_ms": Math.round(cpuUsage.system / 1000),
117
+ "ral.number": ralNumber,
118
+ "agent.slug": context.agent.slug,
119
+ });
120
+
121
+ // Add TENEX-specific attributes to the active span
122
+ const activeSpan = trace.getActiveSpan();
123
+ if (activeSpan) {
124
+ activeSpan.setAttributes({
125
+ "tenex.agent.slug": context.agent.slug,
126
+ "tenex.agent.name": context.agent.name,
127
+ "tenex.agent.pubkey": context.agent.pubkey,
128
+ "tenex.conversation.id": shortenConversationId(context.conversationId),
129
+ "tenex.ral.number": ralNumber,
130
+ "tenex.delegation.chain":
131
+ conversationStore.metadata.delegationChain
132
+ ?.map((e) => e.displayName)
133
+ .join(" -> ") ?? "",
134
+ });
135
+ }
136
+
137
+ // Subscribe to raw chunks and forward to local streaming socket
138
+ llmService.on("raw-chunk", (event: RawChunkEvent) => {
139
+ logger.debug("[StreamExecutionHandler] raw-chunk received", {
140
+ chunkType: event.chunk.type,
141
+ agentPubkey: context.agent.pubkey.substring(0, 8),
142
+ });
143
+ streamPublisher.write({
144
+ agent_pubkey: context.agent.pubkey,
145
+ conversation_id: context.conversationId,
146
+ data: event.chunk,
147
+ });
148
+ });
149
+
150
+ // Create callbacks using extracted factory functions
151
+ const prepareStep = createPrepareStep({
152
+ context,
153
+ llmService,
154
+ messageCompiler: this.config.messageCompiler,
155
+ ephemeralMessages: this.config.ephemeralMessages,
156
+ nudgeContent: this.config.nudgeContent,
157
+ skillContent: this.config.skillContent,
158
+ skills: this.config.skills,
159
+ ralNumber,
160
+ execContext: this.execContext,
161
+ executionSpan: this.executionSpan,
162
+ modelState: {
163
+ lastUsedVariant: this.lastUsedVariant,
164
+ currentModel: this.currentModel,
165
+ setVariant: (v) => { this.lastUsedVariant = v; },
166
+ setModel: (m) => { this.currentModel = m; },
167
+ },
168
+ });
169
+
170
+ // DIAGNOSTIC: Track when we're about to call stream()
171
+ const streamCallStartTime = Date.now();
172
+ this.executionSpan?.addEvent("executor.stream_call_starting", {
173
+ "stream.call_start_time": streamCallStartTime,
174
+ "stream.messages_count": messages.length,
175
+ "stream.tools_count": Object.keys(toolsObject).length,
176
+ "stream.abort_signal_aborted": abortSignal.aborted,
177
+ "ral.number": ralNumber,
178
+ });
179
+
180
+ await llmService.stream(messages, toolsObject, {
181
+ abortSignal,
182
+ prepareStep,
183
+ });
184
+
185
+ // DIAGNOSTIC: Track when stream() returns with process state comparison
186
+ const streamCallEndTime = Date.now();
187
+ const streamCallDuration = streamCallEndTime - streamCallStartTime;
188
+ const endMemUsage = process.memoryUsage();
189
+ const endCpuUsage = process.cpuUsage(cpuUsage); // Delta since start
190
+ this.executionSpan?.addEvent("executor.stream_call_completed", {
191
+ "stream.call_end_time": streamCallEndTime,
192
+ "stream.call_duration_ms": streamCallDuration,
193
+ "stream.result_set_after_stream": this.result !== undefined,
194
+ "stream.result_kind_after_stream": this.result?.kind ?? "undefined",
195
+ "stream.abort_signal_aborted_after": abortSignal.aborted,
196
+ "ral.number": ralNumber,
197
+ // Process state delta for bottleneck analysis
198
+ "process.memory_heap_delta_mb": Math.round((endMemUsage.heapUsed - memUsage.heapUsed) / 1024 / 1024),
199
+ "process.memory_rss_delta_mb": Math.round((endMemUsage.rss - memUsage.rss) / 1024 / 1024),
200
+ "process.cpu_user_delta_ms": Math.round(endCpuUsage.user / 1000),
201
+ "process.cpu_system_delta_ms": Math.round(endCpuUsage.system / 1000),
202
+ });
203
+
204
+ // Diagnostic: Track when stream method returns
205
+ const streamReturnTime = Date.now();
206
+ this.executionSpan?.addEvent("executor.stream_returned", {
207
+ "stream.return_time": streamReturnTime,
208
+ "stream.result_set": this.result !== undefined,
209
+ "stream.result_kind": this.result?.kind ?? "undefined",
210
+ "ral.number": ralNumber,
211
+ });
212
+ } catch (streamError) {
213
+ await this.handleStreamError(streamError, abortSignal);
214
+ } finally {
215
+ await this.cleanup();
216
+ }
217
+
218
+ // Flush any remaining reasoning buffer
219
+ if (this.reasoningBuffer.trim().length > 0) {
220
+ await this.flushReasoningBuffer();
221
+ }
222
+
223
+ // Handle session persistence for Claude Code
224
+ const { sessionManager, llmService: svc } = this.config;
225
+ if (
226
+ !sessionManager.getSession().sessionId &&
227
+ svc.provider === PROVIDER_IDS.CLAUDE_CODE &&
228
+ this.result?.kind === "complete"
229
+ ) {
230
+ sessionManager.saveLastSentEventId(context.triggeringEvent.id);
231
+ }
232
+
233
+ // Capture accumulated runtime for caller
234
+ const accumulatedRuntime = ralRegistry.getAccumulatedRuntime(
235
+ context.agent.pubkey,
236
+ context.conversationId,
237
+ ralNumber
238
+ );
239
+
240
+ // Diagnostic: Log state right before the critical result check
241
+ const resultCheckTime = Date.now();
242
+ this.executionSpan?.addEvent("executor.result_check", {
243
+ "result.check_time": resultCheckTime,
244
+ "result.is_defined": this.result !== undefined,
245
+ "result.kind": this.result?.kind ?? "undefined",
246
+ "ral.number": ralNumber,
247
+ "stream.accumulated_runtime_ms": accumulatedRuntime,
248
+ "agent.slug": context.agent.slug,
249
+ });
250
+
251
+ if (!this.result) {
252
+ this.executionSpan?.addEvent("executor.result_undefined_error", {
253
+ "error.type": "missing_result",
254
+ "ral.number": ralNumber,
255
+ "stream.accumulated_runtime_ms": accumulatedRuntime,
256
+ "agent.slug": context.agent.slug,
257
+ "agent.pubkey": context.agent.pubkey.substring(0, 8),
258
+ "conversation.id": shortenConversationId(context.conversationId),
259
+ "llm.provider": svc.provider,
260
+ "llm.model": svc.model,
261
+ });
262
+ throw new Error("LLM stream completed without emitting complete or stream-error event");
263
+ }
264
+
265
+ // Set aborted flag and reason if stop signal was triggered
266
+ if (this.result.kind === "complete" && abortSignal.aborted) {
267
+ this.result.aborted = true;
268
+ this.result.abortReason =
269
+ typeof abortSignal.reason === "string" ? abortSignal.reason : undefined;
270
+ }
271
+
272
+ // Add accumulated runtime to result
273
+ if (this.result.kind === "complete") {
274
+ this.result.accumulatedRuntime = accumulatedRuntime;
275
+ }
276
+
277
+ return this.result;
278
+ }
279
+
280
+ /**
281
+ * Setup all event handlers for the LLM service
282
+ */
283
+ private setupEventHandlers(): void {
284
+ const { context, llmService, toolTracker, toolsObject } = this.config;
285
+ const agentPublisher = context.agentPublisher;
286
+ const eventContext = this.createEventContext();
287
+ const ralNumber = this.config.ralNumber;
288
+
289
+ llmService.on("content", (event: ContentEvent) => {
290
+ process.stdout.write(chalk.white(event.delta));
291
+ this.contentBuffer += event.delta;
292
+ });
293
+
294
+ llmService.on("reasoning", (event: ReasoningEvent) => {
295
+ process.stdout.write(chalk.gray(event.delta));
296
+ this.reasoningBuffer += event.delta;
297
+ });
298
+
299
+ llmService.on("chunk-type-change", async (event: ChunkTypeChangeEvent) => {
300
+ if (event.from === "reasoning-delta") {
301
+ await this.flushReasoningBuffer();
302
+ }
303
+ if (event.from === "text-delta") {
304
+ await this.flushContentBuffer();
305
+ }
306
+ });
307
+
308
+ // Track when we register the complete listener
309
+ const completeListenerRegisteredAt = Date.now();
310
+ this.executionSpan?.addEvent("executor.complete_listener_registered", {
311
+ "listener.registered_at": completeListenerRegisteredAt,
312
+ "ral.number": ralNumber,
313
+ });
314
+
315
+ llmService.on("complete", (event: CompleteEvent) => {
316
+ const completeReceivedTime = Date.now();
317
+ const timeSinceRegistration = completeReceivedTime - completeListenerRegisteredAt;
318
+ this.executionSpan?.addEvent("executor.complete_received", {
319
+ "complete.received_at": completeReceivedTime,
320
+ "complete.ms_since_listener_registered": timeSinceRegistration,
321
+ "complete.message_length": event.message?.length ?? 0,
322
+ "complete.steps_count": event.steps?.length ?? 0,
323
+ "complete.finish_reason": event.finishReason ?? "unknown",
324
+ "complete.result_already_set": this.result !== undefined,
325
+ "complete.result_kind": this.result?.kind ?? "none",
326
+ "ral.number": ralNumber,
327
+ });
328
+
329
+ if (!this.result) {
330
+ this.result = {
331
+ kind: "complete",
332
+ event,
333
+ messageCompiler: this.config.messageCompiler,
334
+ accumulatedRuntime: 0,
335
+ };
336
+ this.executionSpan?.addEvent("executor.result_set_to_complete", {
337
+ "ral.number": ralNumber,
338
+ });
339
+ } else {
340
+ this.executionSpan?.addEvent("executor.complete_ignored_result_exists", {
341
+ "existing_result.kind": this.result.kind,
342
+ "ral.number": ralNumber,
343
+ });
344
+ }
345
+
346
+ // Trigger proactive background compression after LLM response
347
+ // Non-blocking - fires and forgets
348
+ this.triggerProactiveCompression();
349
+ });
350
+
351
+ llmService.on("stream-error", async (event: StreamErrorEvent) => {
352
+ const errorReceivedTime = Date.now();
353
+ const timeSinceRegistration = errorReceivedTime - completeListenerRegisteredAt;
354
+ this.executionSpan?.addEvent("executor.stream_error_received", {
355
+ "error.received_at": errorReceivedTime,
356
+ "error.ms_since_listener_registered": timeSinceRegistration,
357
+ "error.message": event.error instanceof Error ? event.error.message : String(event.error),
358
+ "error.type": event.error instanceof Error ? event.error.constructor.name : typeof event.error,
359
+ "error.result_already_set": this.result !== undefined,
360
+ "error.result_kind": this.result?.kind ?? "none",
361
+ "ral.number": ralNumber,
362
+ });
363
+
364
+ logger.error("[StreamExecutionHandler] Stream error from LLMService", event);
365
+ this.result = { kind: "error-handled" };
366
+
367
+ try {
368
+ const { message: errorMessage, errorType } = formatStreamError(event.error);
369
+ await agentPublisher.error({ message: errorMessage, errorType }, eventContext);
370
+ } catch (publishError) {
371
+ logger.error("Failed to publish stream error event", {
372
+ error: formatAnyError(publishError),
373
+ });
374
+ }
375
+ });
376
+
377
+ llmService.on("session-captured", ({ sessionId: capturedSessionId }: SessionCapturedEvent) => {
378
+ this.config.sessionManager.saveSession(capturedSessionId, context.triggeringEvent.id);
379
+ });
380
+
381
+ // Setup tool event handlers via extracted module
382
+ setupToolEventHandlers({
383
+ context,
384
+ llmService,
385
+ toolTracker,
386
+ toolsObject,
387
+ eventContext,
388
+ ralNumber,
389
+ });
390
+ }
391
+
392
+ /**
393
+ * Create event context for publishing
394
+ */
395
+ private createEventContext(): EventContext {
396
+ const { context, llmService } = this.config;
397
+ const eventContext = createEventContext(context, llmService.model);
398
+
399
+ // DIAGNOSTIC: Track event context creation to debug llm-ral=0 issues
400
+ this.executionSpan?.addEvent("executor.event_context_created", {
401
+ "context.ral_number": eventContext.ralNumber,
402
+ "context.conversation_id": eventContext.conversationId ? shortenConversationId(eventContext.conversationId) : "none",
403
+ "context.model": eventContext.model ?? "none",
404
+ "config.ral_number": this.config.ralNumber,
405
+ });
406
+
407
+ return eventContext;
408
+ }
409
+
410
+ /**
411
+ * Flush reasoning buffer to publish interim reasoning
412
+ */
413
+ private async flushReasoningBuffer(): Promise<void> {
414
+ if (this.reasoningBuffer.trim().length > 0) {
415
+ const { context } = this.config;
416
+ const eventContext = this.createEventContext();
417
+ const contentToFlush = this.reasoningBuffer;
418
+
419
+ // Add to conversation store BEFORE publishing - capture index for eventId reconciliation
420
+ const messageIndex = context.conversationStore.addMessage({
421
+ pubkey: context.agent.pubkey,
422
+ ral: this.config.ralNumber,
423
+ content: contentToFlush,
424
+ messageType: "text",
425
+ timestamp: Math.floor(Date.now() / 1000),
426
+ });
427
+
428
+ // Clear buffer BEFORE async publish to prevent re-adding on retry
429
+ this.reasoningBuffer = "";
430
+
431
+ try {
432
+ const event = await context.agentPublisher.conversation(
433
+ { content: contentToFlush, isReasoning: true },
434
+ eventContext
435
+ );
436
+
437
+ // Link the published eventId to the message for loopback deduplication
438
+ if (event.id && messageIndex >= 0) {
439
+ context.conversationStore.setEventId(messageIndex, event.id);
440
+ }
441
+ } catch (publishError) {
442
+ // Log but don't throw - message is already in store, just unlinked
443
+ // The loopback dedup will handle this gracefully (worst case: duplicate display)
444
+ logger.warn("[StreamExecutionHandler] Failed to publish reasoning buffer", {
445
+ error: publishError instanceof Error ? publishError.message : String(publishError),
446
+ ralNumber: this.config.ralNumber,
447
+ agent: context.agent.slug,
448
+ });
449
+ }
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Flush content buffer to publish interim text
455
+ */
456
+ private async flushContentBuffer(): Promise<void> {
457
+ if (this.contentBuffer.trim().length > 0) {
458
+ const { context } = this.config;
459
+ const eventContext = this.createEventContext();
460
+ const contentToFlush = this.contentBuffer;
461
+
462
+ // Add to conversation store BEFORE publishing - capture index for eventId reconciliation
463
+ const messageIndex = context.conversationStore.addMessage({
464
+ pubkey: context.agent.pubkey,
465
+ ral: this.config.ralNumber,
466
+ content: contentToFlush,
467
+ messageType: "text",
468
+ timestamp: Math.floor(Date.now() / 1000),
469
+ });
470
+
471
+ // Clear buffer BEFORE async publish to prevent re-adding on retry
472
+ this.contentBuffer = "";
473
+
474
+ try {
475
+ const event = await context.agentPublisher.conversation(
476
+ { content: contentToFlush },
477
+ eventContext
478
+ );
479
+
480
+ // Link the published eventId to the message for loopback deduplication
481
+ if (event.id && messageIndex >= 0) {
482
+ context.conversationStore.setEventId(messageIndex, event.id);
483
+ }
484
+ } catch (publishError) {
485
+ // Log but don't throw - message is already in store, just unlinked
486
+ // The loopback dedup will handle this gracefully (worst case: duplicate display)
487
+ logger.warn("[StreamExecutionHandler] Failed to publish content buffer", {
488
+ error: publishError instanceof Error ? publishError.message : String(publishError),
489
+ ralNumber: this.config.ralNumber,
490
+ agent: context.agent.slug,
491
+ });
492
+ }
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Handle stream errors
498
+ */
499
+ private async handleStreamError(streamError: unknown, abortSignal: AbortSignal): Promise<void> {
500
+ const { context } = this.config;
501
+ const ralNumber = this.config.ralNumber;
502
+
503
+ if (abortSignal.aborted) {
504
+ this.executionSpan?.addEvent("executor.aborted_by_stop_signal", {
505
+ "ral.number": ralNumber,
506
+ "agent.slug": context.agent.slug,
507
+ "conversation.id": shortenConversationId(context.conversationId),
508
+ });
509
+ logger.info("[StreamExecutionHandler] Execution aborted by stop signal", {
510
+ agent: context.agent.slug,
511
+ ralNumber,
512
+ conversationId: context.conversationId.substring(0, 8),
513
+ });
514
+ throw streamError;
515
+ }
516
+
517
+ if (this.result?.kind !== "error-handled") {
518
+ this.result = { kind: "error-handled" };
519
+ try {
520
+ const { message: errorMessage, errorType } = formatStreamError(streamError);
521
+ const eventContext = this.createEventContext();
522
+ await context.agentPublisher.error({ message: errorMessage, errorType }, eventContext);
523
+ } catch (publishError) {
524
+ logger.error("Failed to publish stream error event", {
525
+ error: formatAnyError(publishError),
526
+ });
527
+ }
528
+ }
529
+ throw streamError;
530
+ }
531
+
532
+ /**
533
+ * Trigger proactive background compression after LLM response.
534
+ * Non-blocking - runs async without blocking the completion flow.
535
+ */
536
+ private triggerProactiveCompression(): void {
537
+ const { context, llmService, compressionLlmService } = this.config;
538
+
539
+ try {
540
+ const compressionService = new CompressionService(
541
+ context.conversationStore,
542
+ llmService,
543
+ compressionLlmService
544
+ );
545
+
546
+ // Fire and forget - non-blocking
547
+ compressionService.maybeCompressAsync(context.conversationId);
548
+
549
+ this.executionSpan?.addEvent("compression.proactive_triggered", {
550
+ "conversation.id": shortenConversationId(context.conversationId),
551
+ });
552
+ } catch (error) {
553
+ // Non-blocking - just log if compression setup fails
554
+ logger.warn("[StreamExecutionHandler] Failed to trigger proactive compression", {
555
+ error: error instanceof Error ? error.message : String(error),
556
+ });
557
+ }
558
+ }
559
+
560
+ /**
561
+ * Cleanup after stream execution
562
+ */
563
+ private async cleanup(): Promise<void> {
564
+ const { context, llmService } = this.config;
565
+ const ralNumber = this.config.ralNumber;
566
+ const ralRegistry = RALRegistry.getInstance();
567
+
568
+ ralRegistry.endLLMStream(context.agent.pubkey, context.conversationId, ralNumber);
569
+ ralRegistry.setStreaming(context.agent.pubkey, context.conversationId, ralNumber, false);
570
+
571
+ llmOpsRegistry.completeOperation(context);
572
+ llmService.removeAllListeners();
573
+
574
+ const currentSpan = trace.getActiveSpan();
575
+ if (currentSpan) {
576
+ clearLLMSpanId(currentSpan.spanContext().traceId);
577
+ }
578
+ }
579
+ }