@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,111 @@
1
+ import { logger } from "@/utils/logger";
2
+ import type { Span } from "@opentelemetry/api";
3
+
4
+ /**
5
+ * Manages conversation-level metadata for tracing.
6
+ *
7
+ * Instead of long-lived parent spans, this tracks conversation message counts
8
+ * and adds conversation.id attributes to all spans. This allows querying Jaeger
9
+ * for all traces with the same conversation.id to see the full timeline.
10
+ *
11
+ * NOTE: Conversation IDs in Jaeger spans are shortened to 12 characters (PREFIX_LENGTH)
12
+ * for better readability in the Jaeger UI with low collision risk.
13
+ * Use shortenConversationId() from @/utils/conversation-id for consistency.
14
+ *
15
+ * Benefits:
16
+ * - No long-lived spans (avoids OTEL issues with spans that never end)
17
+ * - Immediate visibility in Jaeger (spans export as soon as they complete)
18
+ * - Easy querying: Search for conversation.id tag in Jaeger
19
+ * - Readable UI: Shortened IDs reduce visual clutter
20
+ */
21
+ export class ConversationSpanManager {
22
+ private conversationMessageCounts = new Map<string, number>();
23
+
24
+ constructor() {
25
+ this.startCleanupTimer();
26
+ }
27
+
28
+ /**
29
+ * Increment message count for a conversation and add to span attributes
30
+ */
31
+ incrementMessageCount(conversationId: string, span: Span): void {
32
+ const currentCount = (this.conversationMessageCounts.get(conversationId) || 0) + 1;
33
+ this.conversationMessageCounts.set(conversationId, currentCount);
34
+
35
+ span.setAttributes({
36
+ "conversation.message_sequence": currentCount,
37
+ });
38
+
39
+ logger.debug("Incremented conversation message count", {
40
+ conversationId: conversationId.substring(0, 8),
41
+ messageSequence: currentCount,
42
+ });
43
+ }
44
+
45
+ /**
46
+ * Get total message count for a conversation
47
+ */
48
+ getMessageCount(conversationId: string): number {
49
+ return this.conversationMessageCounts.get(conversationId) || 0;
50
+ }
51
+
52
+ /**
53
+ * Start automatic cleanup timer (not used in this implementation but kept for future)
54
+ */
55
+ private startCleanupTimer(): void {
56
+ // Cleanup not needed with attribute-based approach
57
+ // Message counts are lightweight and don't need cleanup
58
+ }
59
+
60
+ /**
61
+ * Shutdown (no-op for this implementation)
62
+ */
63
+ shutdown(): void {
64
+ logger.info("Shutting down ConversationSpanManager", {
65
+ trackedConversations: this.conversationMessageCounts.size,
66
+ });
67
+ this.conversationMessageCounts.clear();
68
+ }
69
+
70
+ /**
71
+ * Get stats about tracked conversations
72
+ */
73
+ getStats(): {
74
+ trackedConversations: number;
75
+ totalMessages: number;
76
+ } {
77
+ let totalMessages = 0;
78
+
79
+ for (const count of this.conversationMessageCounts.values()) {
80
+ totalMessages += count;
81
+ }
82
+
83
+ return {
84
+ trackedConversations: this.conversationMessageCounts.size,
85
+ totalMessages,
86
+ };
87
+ }
88
+ }
89
+
90
+ // Singleton instance
91
+ let conversationSpanManager: ConversationSpanManager | null = null;
92
+
93
+ /**
94
+ * Get or create the conversation span manager instance
95
+ */
96
+ export function getConversationSpanManager(): ConversationSpanManager {
97
+ if (!conversationSpanManager) {
98
+ conversationSpanManager = new ConversationSpanManager();
99
+ }
100
+ return conversationSpanManager;
101
+ }
102
+
103
+ /**
104
+ * Reset the conversation span manager (for testing)
105
+ */
106
+ export function resetConversationSpanManager(): void {
107
+ if (conversationSpanManager) {
108
+ conversationSpanManager.shutdown();
109
+ }
110
+ conversationSpanManager = null;
111
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * EventLoopMonitor - Tracks event loop lag to identify blocking operations
3
+ *
4
+ * This module monitors the Node.js event loop for blocking/slow operations
5
+ * that could cause unresponsiveness when multiple agents are streaming.
6
+ *
7
+ * DIAGNOSTIC: This is part of the concurrent streaming bottleneck investigation.
8
+ */
9
+
10
+ import { trace } from "@opentelemetry/api";
11
+ import { logger } from "@/utils/logger";
12
+
13
+ interface LagSample {
14
+ timestamp: number;
15
+ lagMs: number;
16
+ activeOperations: number;
17
+ }
18
+
19
+ interface EventLoopStats {
20
+ samples: LagSample[];
21
+ peakLagMs: number;
22
+ avgLagMs: number;
23
+ sampleCount: number;
24
+ blockedCount: number; // samples where lag > threshold
25
+ }
26
+
27
+ const DEFAULT_SAMPLE_INTERVAL_MS = 100; // Sample every 100ms
28
+ const DEFAULT_LAG_THRESHOLD_MS = 50; // Consider >50ms as "blocked"
29
+ const MAX_SAMPLES = 1000; // Keep last 1000 samples
30
+
31
+ class EventLoopMonitor {
32
+ private static instance: EventLoopMonitor;
33
+ private isRunning = false;
34
+ private samples: LagSample[] = [];
35
+ private peakLagMs = 0;
36
+ private totalLagMs = 0;
37
+ private sampleCount = 0;
38
+ private blockedCount = 0;
39
+ private intervalHandle: ReturnType<typeof setInterval> | null = null;
40
+ private lastCheckTime = 0;
41
+ private getActiveOperationsCount: () => number = () => 0;
42
+
43
+ private constructor() {}
44
+
45
+ static getInstance(): EventLoopMonitor {
46
+ if (!EventLoopMonitor.instance) {
47
+ EventLoopMonitor.instance = new EventLoopMonitor();
48
+ }
49
+ return EventLoopMonitor.instance;
50
+ }
51
+
52
+ /**
53
+ * Start monitoring the event loop.
54
+ * @param getActiveOperationsCount - Function to get current active LLM operations count
55
+ * @param sampleIntervalMs - How often to sample (default 100ms)
56
+ * @param lagThresholdMs - What lag value is considered "blocked" (default 50ms)
57
+ */
58
+ start(
59
+ getActiveOperationsCount: () => number,
60
+ sampleIntervalMs = DEFAULT_SAMPLE_INTERVAL_MS,
61
+ lagThresholdMs = DEFAULT_LAG_THRESHOLD_MS
62
+ ): void {
63
+ if (this.isRunning) {
64
+ return;
65
+ }
66
+
67
+ this.getActiveOperationsCount = getActiveOperationsCount;
68
+ this.isRunning = true;
69
+ this.lastCheckTime = Date.now();
70
+
71
+ // Use setInterval but measure actual elapsed time vs expected
72
+ this.intervalHandle = setInterval(() => {
73
+ const now = Date.now();
74
+ const expectedElapsed = sampleIntervalMs;
75
+ const actualElapsed = now - this.lastCheckTime;
76
+ const lag = actualElapsed - expectedElapsed;
77
+
78
+ // Only record positive lag (negative would mean timer fired early)
79
+ const lagMs = Math.max(0, lag);
80
+ const activeOps = this.getActiveOperationsCount();
81
+
82
+ const sample: LagSample = {
83
+ timestamp: now,
84
+ lagMs,
85
+ activeOperations: activeOps,
86
+ };
87
+
88
+ this.samples.push(sample);
89
+ if (this.samples.length > MAX_SAMPLES) {
90
+ this.samples.shift();
91
+ }
92
+
93
+ this.sampleCount++;
94
+ this.totalLagMs += lagMs;
95
+ if (lagMs > this.peakLagMs) {
96
+ this.peakLagMs = lagMs;
97
+ }
98
+ if (lagMs > lagThresholdMs) {
99
+ this.blockedCount++;
100
+
101
+ // Log significant lag events
102
+ if (lagMs > lagThresholdMs * 2) {
103
+ const activeSpan = trace.getActiveSpan();
104
+ activeSpan?.addEvent("event_loop.significant_lag", {
105
+ "lag.ms": lagMs,
106
+ "lag.threshold_ms": lagThresholdMs,
107
+ "concurrent.active_operations": activeOps,
108
+ "process.memory_heap_used_mb": Math.round(
109
+ process.memoryUsage().heapUsed / 1024 / 1024
110
+ ),
111
+ });
112
+
113
+ logger.warn("[EventLoopMonitor] Significant event loop lag detected", {
114
+ lagMs,
115
+ activeOperations: activeOps,
116
+ threshold: lagThresholdMs,
117
+ });
118
+ }
119
+ }
120
+
121
+ this.lastCheckTime = now;
122
+ }, sampleIntervalMs);
123
+
124
+ logger.info("[EventLoopMonitor] Started monitoring", {
125
+ sampleIntervalMs,
126
+ lagThresholdMs,
127
+ });
128
+ }
129
+
130
+ /**
131
+ * Stop monitoring
132
+ */
133
+ stop(): void {
134
+ if (!this.isRunning || !this.intervalHandle) {
135
+ return;
136
+ }
137
+
138
+ clearInterval(this.intervalHandle);
139
+ this.intervalHandle = null;
140
+ this.isRunning = false;
141
+
142
+ logger.info("[EventLoopMonitor] Stopped monitoring");
143
+ }
144
+
145
+ /**
146
+ * Get current statistics
147
+ */
148
+ getStats(): EventLoopStats {
149
+ return {
150
+ samples: [...this.samples],
151
+ peakLagMs: this.peakLagMs,
152
+ avgLagMs: this.sampleCount > 0 ? this.totalLagMs / this.sampleCount : 0,
153
+ sampleCount: this.sampleCount,
154
+ blockedCount: this.blockedCount,
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Get recent samples where lag was above threshold
160
+ */
161
+ getRecentBlockedSamples(thresholdMs = DEFAULT_LAG_THRESHOLD_MS, maxCount = 10): LagSample[] {
162
+ return this.samples
163
+ .filter((s) => s.lagMs > thresholdMs)
164
+ .slice(-maxCount);
165
+ }
166
+
167
+ /**
168
+ * Emit current stats as an OTL span event
169
+ */
170
+ emitStatsEvent(contextLabel: string): void {
171
+ const stats = this.getStats();
172
+ const activeSpan = trace.getActiveSpan();
173
+
174
+ activeSpan?.addEvent("event_loop.stats_snapshot", {
175
+ "stats.context": contextLabel,
176
+ "stats.peak_lag_ms": stats.peakLagMs,
177
+ "stats.avg_lag_ms": Math.round(stats.avgLagMs * 100) / 100,
178
+ "stats.sample_count": stats.sampleCount,
179
+ "stats.blocked_count": stats.blockedCount,
180
+ "stats.blocked_percentage":
181
+ stats.sampleCount > 0
182
+ ? Math.round((stats.blockedCount / stats.sampleCount) * 10000) / 100
183
+ : 0,
184
+ });
185
+ }
186
+
187
+ /**
188
+ * Reset all metrics (for testing)
189
+ */
190
+ reset(): void {
191
+ this.samples = [];
192
+ this.peakLagMs = 0;
193
+ this.totalLagMs = 0;
194
+ this.sampleCount = 0;
195
+ this.blockedCount = 0;
196
+ }
197
+
198
+ /**
199
+ * Check if monitoring is currently active
200
+ */
201
+ isActive(): boolean {
202
+ return this.isRunning;
203
+ }
204
+ }
205
+
206
+ export const eventLoopMonitor = EventLoopMonitor.getInstance();
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Registry to track LLM execution span IDs by trace ID.
3
+ * Allows published events to reference the LLM span that generated their content.
4
+ *
5
+ * When an ai.streamText.doStream span ends, its span ID is stored here keyed by trace ID.
6
+ * When publishing events, we look up the LLM span ID to link directly to the LLM execution.
7
+ */
8
+ const llmSpansByTrace = new Map<string, string>();
9
+
10
+ export function setLLMSpanId(traceId: string, spanId: string): void {
11
+ llmSpansByTrace.set(traceId, spanId);
12
+ }
13
+
14
+ export function getLLMSpanId(traceId: string): string | undefined {
15
+ return llmSpansByTrace.get(traceId);
16
+ }
17
+
18
+ export function clearLLMSpanId(traceId: string): void {
19
+ llmSpansByTrace.delete(traceId);
20
+ }
@@ -0,0 +1,89 @@
1
+ import type { Context } from "@opentelemetry/api";
2
+ import type { ReadableSpan, Span, SpanProcessor } from "@opentelemetry/sdk-trace-base";
3
+
4
+ /**
5
+ * Internal OTEL Span structure - accessing private fields to rewrite span IDs
6
+ * This is necessary because OTEL doesn't expose a way to set spanId after creation
7
+ */
8
+ interface SpanInternals {
9
+ _spanContext?: { spanId: string };
10
+ _parentSpanId?: string;
11
+ _parentSpanContext?: { spanId: string };
12
+ parentSpanContext?: { spanId: string };
13
+ }
14
+
15
+ /**
16
+ * Convert a Nostr hex ID to OpenTelemetry spanID (16 hex chars)
17
+ */
18
+ function nostrIdToSpanId(nostrId: string): string {
19
+ return nostrId.substring(0, 16);
20
+ }
21
+
22
+ /**
23
+ * SpanProcessor that rewrites span IDs for Nostr event processing spans.
24
+ *
25
+ * Problem: OpenTelemetry generates random spanIds, but we derive parentSpanId
26
+ * from Nostr event IDs (e-tags). This causes parent-child relationships to break
27
+ * because the random spanId doesn't match the derived parentSpanId.
28
+ *
29
+ * Solution: For spans with event.id attribute, rewrite their spanId to be
30
+ * deterministically derived from the event ID. This ensures that when another
31
+ * span references this event via e-tag, the parentSpanId will match.
32
+ */
33
+ export class NostrSpanProcessor implements SpanProcessor {
34
+ forceFlush(): Promise<void> {
35
+ return Promise.resolve();
36
+ }
37
+
38
+ shutdown(): Promise<void> {
39
+ return Promise.resolve();
40
+ }
41
+
42
+ onStart(_span: Span, _parentContext: Context): void {
43
+ // Nothing to do on start
44
+ }
45
+
46
+ onEnd(span: ReadableSpan): void {
47
+ // Only rewrite spanIDs for tenex.event.process spans
48
+ // Other spans (tenex.dispatch.chat_message, tenex.delegation.completion_check) share
49
+ // event.id attribute but should NOT have their spanIDs rewritten to avoid collisions
50
+ if (span.name !== "tenex.event.process") {
51
+ return;
52
+ }
53
+
54
+ // Only process spans that have event.id attribute (Nostr event processing spans)
55
+ const eventId = span.attributes["event.id"];
56
+ if (typeof eventId !== "string" || !eventId) {
57
+ return;
58
+ }
59
+
60
+ // Rewrite spanId to be derived from event.id
61
+ const derivedSpanId = nostrIdToSpanId(eventId);
62
+
63
+ // Access internal state - the Span class stores context in _spanContext
64
+ const spanInternal = span as unknown as SpanInternals;
65
+
66
+ // Modify the spanContext's spanId
67
+ if (spanInternal._spanContext) {
68
+ spanInternal._spanContext.spanId = derivedSpanId;
69
+ }
70
+
71
+ // Fix parentSpanId based on event.reply_to
72
+ const replyTo = span.attributes["event.reply_to"];
73
+ if (typeof replyTo === "string" && replyTo) {
74
+ // This is a reply - set parent to the event being replied to
75
+ const derivedParentSpanId = nostrIdToSpanId(replyTo);
76
+
77
+ // Modify the parent span context
78
+ if (spanInternal._parentSpanContext) {
79
+ spanInternal._parentSpanContext.spanId = derivedParentSpanId;
80
+ } else if (spanInternal.parentSpanContext) {
81
+ spanInternal.parentSpanContext.spanId = derivedParentSpanId;
82
+ }
83
+ } else {
84
+ // This is a root message - clear parent context so it becomes a true root span
85
+ spanInternal._parentSpanContext = undefined;
86
+ spanInternal.parentSpanContext = undefined;
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,66 @@
1
+ import type { Context } from "@opentelemetry/api";
2
+ import type { ReadableSpan, SpanProcessor } from "@opentelemetry/sdk-trace-base";
3
+ import type { Span } from "@opentelemetry/sdk-trace-base";
4
+ import { setLLMSpanId } from "./LLMSpanRegistry";
5
+
6
+ /**
7
+ * Span processor that enriches tool call span names with the actual tool name.
8
+ * Transforms generic "ai.toolCall" spans into "ai.toolCall.{toolName}" for better visibility.
9
+ */
10
+ export class ToolCallSpanProcessor implements SpanProcessor {
11
+ onStart(_span: Span, _parentContext: Context): void {
12
+ // This is called when a span starts, but we can't modify the name here
13
+ // because the attributes might not be set yet
14
+ }
15
+
16
+ onEnd(span: ReadableSpan): void {
17
+ // Extract agent context if available
18
+ const agentName = span.attributes?.["agent.name"];
19
+ const agentSlug = span.attributes?.["agent.slug"];
20
+ const agentPrefix = agentSlug || agentName;
21
+
22
+ // Check if this is a tool call span
23
+ if (span.name === "ai.toolCall" && span.attributes) {
24
+ const toolName = span.attributes["ai.toolCall.name"];
25
+
26
+ if (toolName && typeof toolName === "string") {
27
+ // Include agent slug in the span name for better visibility
28
+ const prefix = agentPrefix ? `[${agentPrefix}] ` : "";
29
+ // ReadableSpan has readonly name, but we can mutate it via the underlying object
30
+ (span as ReadableSpan & { name: string }).name = `${prefix}ai.toolCall.${toolName}`;
31
+ }
32
+ }
33
+
34
+ // Also enhance other AI operation spans with more context if available
35
+ if (span.name === "ai.streamText" || span.name === "ai.generateText") {
36
+ const model = span.attributes?.["ai.model.id"];
37
+ if (model && typeof model === "string") {
38
+ const shortModel = model.split("/").pop() || model;
39
+ const prefix = agentPrefix ? `[${agentPrefix}] ` : "";
40
+ (span as ReadableSpan & { name: string }).name = `${prefix}${span.name}.${shortModel}`;
41
+ }
42
+ }
43
+
44
+ // Enhance agent execution spans
45
+ if (span.name === "tenex.agent.execute" && agentPrefix) {
46
+ const phase = span.attributes?.["conversation.phase"];
47
+ const phaseStr = phase ? `.${phase}` : "";
48
+ (span as ReadableSpan & { name: string }).name = `[${agentPrefix}] agent.execute${phaseStr}`;
49
+ }
50
+
51
+ // Capture ai.streamText.doStream span IDs for event linking
52
+ // This allows published events to reference the LLM span that generated their content
53
+ if (span.name === "ai.streamText.doStream") {
54
+ const spanContext = span.spanContext();
55
+ setLLMSpanId(spanContext.traceId, spanContext.spanId);
56
+ }
57
+ }
58
+
59
+ shutdown(): Promise<void> {
60
+ return Promise.resolve();
61
+ }
62
+
63
+ forceFlush(): Promise<void> {
64
+ return Promise.resolve();
65
+ }
66
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Diagnostics Configuration - Feature flag for diagnostic instrumentation
3
+ *
4
+ * Controls whether detailed diagnostic telemetry is collected.
5
+ * Disable in production for performance; enable when investigating issues.
6
+ *
7
+ * Set TENEX_DIAGNOSTICS=true to enable all diagnostic instrumentation.
8
+ */
9
+
10
+ /**
11
+ * Check if diagnostics are enabled via environment variable.
12
+ * Caches the result at module load time.
13
+ */
14
+ export function isDiagnosticsEnabled(): boolean {
15
+ return process.env.TENEX_DIAGNOSTICS === "true";
16
+ }
17
+
18
+ /**
19
+ * Get the diagnostics enabled state (for logging/tracing).
20
+ */
21
+ export function getDiagnosticsState(): { enabled: boolean; source: string } {
22
+ const enabled = isDiagnosticsEnabled();
23
+ return {
24
+ enabled,
25
+ source: enabled ? "TENEX_DIAGNOSTICS=true" : "default (disabled)",
26
+ };
27
+ }
@@ -0,0 +1,120 @@
1
+ import type { ExportResult } from "@opentelemetry/core";
2
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
3
+ import { resourceFromAttributes } from "@opentelemetry/resources";
4
+ import { NodeSDK } from "@opentelemetry/sdk-node";
5
+ import type { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
6
+ import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
7
+ import {
8
+ SEMRESATTRS_SERVICE_NAME,
9
+ SEMRESATTRS_SERVICE_VERSION,
10
+ } from "@opentelemetry/semantic-conventions";
11
+ import { ToolCallSpanProcessor } from "./ToolCallSpanProcessor.js";
12
+ import { NostrSpanProcessor } from "./NostrSpanProcessor.js";
13
+
14
+ const DEFAULT_SERVICE_NAME = "tenex-daemon";
15
+ const DEFAULT_ENDPOINT = "http://localhost:4318/v1/traces";
16
+
17
+ class ErrorHandlingExporterWrapper implements SpanExporter {
18
+ private disabled = false;
19
+
20
+ constructor(
21
+ private traceExporter: OTLPTraceExporter,
22
+ private exporterUrl: string
23
+ ) {}
24
+
25
+ export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {
26
+ // Once disabled, drop all spans silently
27
+ if (this.disabled) {
28
+ resultCallback({ code: 0 }); // ExportResultCode.SUCCESS
29
+ return;
30
+ }
31
+
32
+ this.traceExporter.export(spans, (result) => {
33
+ if (result.error && !this.disabled) {
34
+ const errorMessage = result.error?.message || String(result.error);
35
+ const isConnectionError = errorMessage.includes("ECONNREFUSED") || errorMessage.includes("connect");
36
+ if (isConnectionError) {
37
+ console.warn(`[Telemetry] ⚠️ Collector not available at ${this.exporterUrl}`);
38
+ } else {
39
+ console.error("[Telemetry] Export error:", errorMessage);
40
+ }
41
+ console.warn("[Telemetry] Disabling trace export");
42
+ this.disabled = true;
43
+ }
44
+ resultCallback(result);
45
+ });
46
+ }
47
+
48
+ shutdown(): Promise<void> {
49
+ return this.traceExporter.shutdown();
50
+ }
51
+ }
52
+
53
+ // Create a wrapper processor that enriches span names and fixes Nostr IDs before exporting
54
+ class EnrichedBatchSpanProcessor extends BatchSpanProcessor {
55
+ private enricher = new ToolCallSpanProcessor();
56
+ private nostrProcessor = new NostrSpanProcessor();
57
+
58
+ onEnd(span: ReadableSpan): void {
59
+ // First fix Nostr span IDs (must happen before export)
60
+ this.nostrProcessor.onEnd(span);
61
+ // Then enrich tool call spans
62
+ this.enricher.onEnd(span);
63
+ // Then pass to batch processor
64
+ super.onEnd(span);
65
+ }
66
+ }
67
+
68
+ let sdk: NodeSDK | null = null;
69
+
70
+ function createSDK(serviceName: string, wrappedExporter: SpanExporter): NodeSDK {
71
+ const resource = resourceFromAttributes({
72
+ [SEMRESATTRS_SERVICE_NAME]: serviceName,
73
+ [SEMRESATTRS_SERVICE_VERSION]: process.env.npm_package_version || "0.8.0",
74
+ "deployment.environment": process.env.NODE_ENV || "development",
75
+ });
76
+
77
+ const spanProcessor = new EnrichedBatchSpanProcessor(wrappedExporter, {
78
+ maxQueueSize: 2048,
79
+ maxExportBatchSize: 512,
80
+ scheduledDelayMillis: 5000, // Send every 5 seconds
81
+ });
82
+
83
+ return new NodeSDK({
84
+ resource,
85
+ spanProcessor,
86
+ // NO sampling - capture everything (100%)
87
+ // NO instrumentation filters - capture all
88
+ });
89
+ }
90
+
91
+ export function initializeTelemetry(
92
+ enabled = true,
93
+ serviceName = DEFAULT_SERVICE_NAME,
94
+ endpoint = DEFAULT_ENDPOINT
95
+ ): void {
96
+ if (!enabled) {
97
+ return;
98
+ }
99
+
100
+ // Use environment variable if set, otherwise use config endpoint
101
+ const exporterUrl = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || endpoint;
102
+
103
+ // Create exporter with the configured URL
104
+ const traceExporter = new OTLPTraceExporter({
105
+ url: exporterUrl,
106
+ });
107
+
108
+ // Wrap the exporter with error handling
109
+ const wrappedExporter = new ErrorHandlingExporterWrapper(traceExporter, exporterUrl);
110
+
111
+ sdk = createSDK(serviceName, wrappedExporter);
112
+ sdk.start();
113
+ }
114
+
115
+ export function shutdownTelemetry(): Promise<void> {
116
+ if (!sdk) {
117
+ return Promise.resolve();
118
+ }
119
+ return sdk.shutdown();
120
+ }