@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,234 @@
1
+ import type { ConversationStore } from "@/conversations/ConversationStore";
2
+ import { CategoryManager } from "@/conversations/services";
3
+ import { NDKEventMetadata } from "@/events/NDKEventMetadata";
4
+ import { llmServiceFactory } from "@/llm";
5
+ import { shortenConversationId } from "@/utils/conversation-id";
6
+ import { NDKKind } from "@/nostr/kinds";
7
+ import { getNDK } from "@/nostr/ndkClient";
8
+ import { config } from "@/services/ConfigService";
9
+ import { getPubkeyService } from "@/services/PubkeyService";
10
+ import type { ProjectContext } from "@/services/projects";
11
+ import { ROOT_CONTEXT, SpanStatusCode, context as otelContext, trace } from "@opentelemetry/api";
12
+ import { z } from "zod";
13
+
14
+ const tracer = trace.getTracer("tenex.summarizer");
15
+
16
+ export class ConversationSummarizer {
17
+ private categoryManager: CategoryManager;
18
+
19
+ constructor(private context: ProjectContext) {
20
+ // CategoryManager stores categories in ~/.tenex/data
21
+ this.categoryManager = new CategoryManager(config.getConfigPath());
22
+ this.categoryManager.initialize();
23
+ }
24
+
25
+ async summarizeAndPublish(conversation: ConversationStore): Promise<void> {
26
+ // Create a fresh span using ROOT_CONTEXT to avoid inheriting an ended span
27
+ // This is necessary because summarization runs debounced/async after the main processing span ends
28
+ const span = tracer.startSpan("tenex.summarize", {
29
+ attributes: {
30
+ "conversation.id": shortenConversationId(conversation.id),
31
+ },
32
+ }, ROOT_CONTEXT);
33
+
34
+ // Wrap execution in the new span's context so child operations use this span
35
+ return otelContext.with(trace.setSpan(ROOT_CONTEXT, span), async () => {
36
+ try {
37
+ // Get LLM configuration - use summarization config if set, otherwise default
38
+ const { llms } = await config.loadConfig();
39
+ const configName = llms.summarization || llms.default;
40
+
41
+ if (!configName) {
42
+ console.warn("No LLM configuration available for summarization");
43
+ return;
44
+ }
45
+
46
+ // Use getLLMConfig to resolve meta models automatically
47
+ const summarizationConfig = config.getLLMConfig(configName);
48
+
49
+ // Create LLM service
50
+ const llmService = llmServiceFactory.createService(
51
+ summarizationConfig,
52
+ {
53
+ agentName: "summarizer",
54
+ sessionId: `summarizer-${conversation.id}`,
55
+ }
56
+ );
57
+
58
+ // Prepare conversation content from stored messages
59
+ const messages = conversation.getAllMessages();
60
+ const pubkeyService = getPubkeyService();
61
+
62
+ // Resolve pubkeys to names for all participants
63
+ const textMessages = messages.filter((entry) => entry.messageType === "text");
64
+ const formattedMessages = await Promise.all(
65
+ textMessages.map(async (entry) => {
66
+ const name = await pubkeyService.getName(entry.pubkey);
67
+ return `${name}: ${entry.content}`;
68
+ })
69
+ );
70
+ const conversationContent = formattedMessages.join("\n\n");
71
+
72
+ if (!conversationContent.trim()) {
73
+ console.log("No content to summarize for conversation", conversation.id);
74
+ return;
75
+ }
76
+
77
+ // Get existing categories for consistency
78
+ const existingCategories = await this.categoryManager.getCategories();
79
+ const categoryListText = existingCategories.length > 0
80
+ ? `Existing categories (prefer these for consistency): ${existingCategories.join(", ")}`
81
+ : "No existing categories yet. Create new ones as needed.";
82
+
83
+ // Generate title, summary, and status information
84
+ const { object: result } = await llmService.generateObject(
85
+ [
86
+ {
87
+ role: "system",
88
+ content: `You generate high-signal titles, summaries, status metadata, and category tags for technical conversations.
89
+
90
+ CRITICAL: Base output ONLY on what is explicitly stated in the conversation. Do NOT:
91
+ - Hallucinate success when errors, failures, or problems are mentioned
92
+ - Assume tasks were completed if the conversation shows they failed or are still in progress
93
+ - Invent outcomes not clearly stated in the transcript
94
+
95
+ DENSITY RULES (ENFORCE)
96
+ - Summary max 160 characters (hard limit).
97
+ - No narrative glue: avoid “ensuring”, “including”, “key features”, “focused on”, “review of”, “in order to”, “now complete”, “ready for testing” (unless explicitly stated).
98
+ - No redundancy: summary and status_current_activity must not restate the same fact in different words.
99
+
100
+ TITLE
101
+ - 3–5 words (hard limit), concrete nouns/verbs, no filler.
102
+ - Prefer outcome/topic phrasing.
103
+
104
+ SUMMARY (1 sentence only)
105
+ - Changelog style: state facts only (outcome/state, scope, blockers).
106
+ - For In Progress / Blocked / Waiting: include what is missing or unknown (“Details not provided”).
107
+ - Do not describe process.
108
+
109
+ STATUS
110
+ - status_label: one of "Researching", "In Progress", "Blocked", "Waiting", "Completed", "Failed", "Planning".
111
+ - status_current_activity: one dense clause, consistent with status_label.
112
+ - Do not duplicate the summary.
113
+
114
+ CATEGORIES (CANONICAL-FIRST, SEMANTIC)
115
+ You are given a list of previously used categories below. This list is a CANONICAL SUGGESTION SET, not an allowlist.
116
+ You must actively judge each candidate (including items from the list) using the rules below.
117
+
118
+ Previously used categories:
119
+ ${categoryListText}
120
+
121
+ Selection rules:
122
+ - Prefer an existing category from the list *only if* it is a good semantic fit.
123
+ - A valid category must:
124
+ - Name a stable system concept (component, data model, protocol, UI artifact, subsystem)
125
+ - Remain meaningful months later without task context
126
+ - Have high discriminative value (would not apply to most unrelated conversations)
127
+ - Do NOT select a category just because it exists in the list.
128
+
129
+ Creation rules (to avoid fragmentation):
130
+ - Create a new category ONLY if no existing category fits well.
131
+ - If creating a new category:
132
+ - Use a simple, canonical noun form
133
+ - Avoid re-ordering words that would create near-duplicates
134
+ - Prefer the most general stable concept (e.g., “agent” over “agent-runtime” unless runtime is explicitly the core topic)
135
+
136
+ Rejection rule:
137
+ - If all plausible categories (including those from the list) are low-signal or process-oriented, output [].
138
+
139
+ Before emitting categories, silently verify for each:
140
+ - It maps to an explicit noun phrase in the transcript
141
+ - It passes the “6-months later” test
142
+ - It would not create a near-duplicate of an existing category`,
143
+ },
144
+ {
145
+ role: "user",
146
+ content: `Please generate a title, summary, and status information for this conversation:\n\n${conversationContent}`,
147
+ },
148
+ ],
149
+ z.object({
150
+ title: z.string().describe("A concise title for the conversation (3-5 words)"),
151
+ summary: z
152
+ .string()
153
+ .describe(
154
+ "A 1-sentence, information-dense summary (<=160 chars) of key facts, scope, and blockers"
155
+ ),
156
+ status_label: z
157
+ .string()
158
+ .describe(
159
+ "A concise status label (e.g., 'In Progress', 'Blocked', 'Waiting', 'Completed', 'Failed')"
160
+ ),
161
+ status_current_activity: z
162
+ .string()
163
+ .describe(
164
+ "One dense clause consistent with status_label; no duplication or speculation"
165
+ ),
166
+ categories: z
167
+ .array(z.string())
168
+ .max(3)
169
+ .describe(
170
+ "0-3 category tags. Lowercase singular nouns. Prefer canonical list; create new only if necessary; may be empty []."
171
+ ),
172
+ })
173
+ );
174
+
175
+
176
+
177
+ // Publish metadata event
178
+ const ndk = getNDK();
179
+ const event = new NDKEventMetadata(ndk);
180
+ event.kind = NDKKind.EventMetadata;
181
+ event.setConversationId(conversation.id);
182
+
183
+ // Add metadata tags
184
+ if (result.title) {
185
+ event.tags.push(["title", result.title]);
186
+ }
187
+ if (result.summary) {
188
+ event.tags.push(["summary", result.summary]);
189
+ }
190
+ if (result.status_label) {
191
+ event.tags.push(["status-label", result.status_label]);
192
+ }
193
+ if (result.status_current_activity) {
194
+ event.tags.push(["status-current-activity", result.status_current_activity]);
195
+ }
196
+ if (result.categories && result.categories.length > 0) {
197
+ for (const category of result.categories) {
198
+ event.tags.push(["t", category]);
199
+ }
200
+ }
201
+ event.tags.push(["a", this.context.project.tagId()]); // Project reference
202
+ event.tags.push(["model", summarizationConfig.model]);
203
+
204
+ // Sign and publish with backend signer
205
+ const backendSigner = await config.getBackendSigner();
206
+ await event.sign(backendSigner);
207
+ event.publish();
208
+ console.log(
209
+ `Published metadata for conversation ${conversation.id}: ${result.title}`
210
+ );
211
+
212
+ // Also persist summary to local metadata for prompt fragments
213
+ // This ensures "Recent Conversations" section can display summaries
214
+ conversation.updateMetadata({
215
+ summary: result.summary,
216
+ });
217
+ await conversation.save();
218
+
219
+ // Update category tally for future consistency
220
+ if (result.categories && result.categories.length > 0) {
221
+ await this.categoryManager.updateCategories(result.categories);
222
+ }
223
+
224
+ span.setStatus({ code: SpanStatusCode.OK });
225
+ } catch (error) {
226
+ span.recordException(error as Error);
227
+ span.setStatus({ code: SpanStatusCode.ERROR });
228
+ console.error("Error generating conversation summary:", error);
229
+ } finally {
230
+ span.end();
231
+ }
232
+ });
233
+ }
234
+ }
@@ -0,0 +1,188 @@
1
+ import { logger } from "@/utils/logger";
2
+
3
+ interface DebounceState {
4
+ timerId: NodeJS.Timeout | null;
5
+ firstExecutionDone: boolean;
6
+ maxDeadline: number; // Unix timestamp (ms)
7
+ pendingPublishFn: (() => Promise<void>) | null;
8
+ }
9
+
10
+ const DEBOUNCE_MS = 10_000; // 10 seconds
11
+ const MAX_DELAY_MS = 5 * 60_000; // 5 minutes
12
+
13
+ /**
14
+ * Manages debounced publishing of kind 513 metadata events at conversation level.
15
+ *
16
+ * Strategy:
17
+ * - First execution (or root event): publish immediately
18
+ * - Subsequent executions: debounce by 10 seconds
19
+ * - If another agent starts on same conversation: reset the debounce timer
20
+ * - Max delay of 5 minutes before forcing publication
21
+ */
22
+ class MetadataDebounceManager {
23
+ private debounceStates = new Map<string, DebounceState>();
24
+
25
+ /**
26
+ * Called when an agent STARTS execution on a conversation.
27
+ * Resets any pending debounce timer (but preserves the publish function).
28
+ */
29
+ onAgentStart(conversationId: string): void {
30
+ const state = this.debounceStates.get(conversationId);
31
+ if (state?.timerId) {
32
+ clearTimeout(state.timerId);
33
+ state.timerId = null;
34
+ logger.debug("[MetadataDebounce] Timer reset on agent start", {
35
+ conversationId: conversationId.substring(0, 8),
36
+ });
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Called when an agent COMPLETES execution.
42
+ * Either publishes immediately (first exec or root event) or schedules debounced publish.
43
+ */
44
+ schedulePublish(
45
+ conversationId: string,
46
+ isRootEvent: boolean,
47
+ publishFn: () => Promise<void>
48
+ ): void {
49
+ let state = this.debounceStates.get(conversationId);
50
+
51
+ // First execution or root event: publish immediately
52
+ if (!state || !state.firstExecutionDone || isRootEvent) {
53
+ logger.debug("[MetadataDebounce] Publishing immediately (first/root)", {
54
+ conversationId: conversationId.substring(0, 8),
55
+ isRootEvent,
56
+ isFirstExecution: !state?.firstExecutionDone,
57
+ });
58
+
59
+ // Initialize state
60
+ if (!state) {
61
+ state = {
62
+ timerId: null,
63
+ firstExecutionDone: true,
64
+ maxDeadline: Date.now() + MAX_DELAY_MS,
65
+ pendingPublishFn: null,
66
+ };
67
+ this.debounceStates.set(conversationId, state);
68
+ } else {
69
+ state.firstExecutionDone = true;
70
+ state.maxDeadline = Date.now() + MAX_DELAY_MS;
71
+ }
72
+
73
+ // Publish immediately (fire and forget)
74
+ publishFn().catch((error) => {
75
+ logger.error("[MetadataDebounce] Failed to publish metadata", {
76
+ conversationId: conversationId.substring(0, 8),
77
+ error,
78
+ });
79
+ });
80
+ return;
81
+ }
82
+
83
+ // Subsequent execution: debounce
84
+ // Clear existing timer if any
85
+ if (state.timerId) {
86
+ clearTimeout(state.timerId);
87
+ state.timerId = null;
88
+ }
89
+
90
+ // Update the pending publish function (use latest)
91
+ state.pendingPublishFn = publishFn;
92
+
93
+ const now = Date.now();
94
+
95
+ // Check if we've exceeded max deadline
96
+ if (now >= state.maxDeadline) {
97
+ logger.debug("[MetadataDebounce] Max deadline reached, publishing now", {
98
+ conversationId: conversationId.substring(0, 8),
99
+ });
100
+
101
+ // Reset deadline for next batch
102
+ state.maxDeadline = now + MAX_DELAY_MS;
103
+
104
+ publishFn().catch((error) => {
105
+ logger.error("[MetadataDebounce] Failed to publish metadata", {
106
+ conversationId: conversationId.substring(0, 8),
107
+ error,
108
+ });
109
+ });
110
+ return;
111
+ }
112
+
113
+ // Schedule debounced publish
114
+ const delay = Math.min(DEBOUNCE_MS, state.maxDeadline - now);
115
+
116
+ logger.debug("[MetadataDebounce] Scheduling debounced publish", {
117
+ conversationId: conversationId.substring(0, 8),
118
+ delayMs: delay,
119
+ });
120
+
121
+ state.timerId = setTimeout(() => {
122
+ const currentState = this.debounceStates.get(conversationId);
123
+ if (currentState?.pendingPublishFn) {
124
+ // Reset deadline for next batch
125
+ currentState.maxDeadline = Date.now() + MAX_DELAY_MS;
126
+ currentState.timerId = null;
127
+
128
+ currentState.pendingPublishFn().catch((error) => {
129
+ logger.error("[MetadataDebounce] Failed to publish metadata (debounced)", {
130
+ conversationId: conversationId.substring(0, 8),
131
+ error,
132
+ });
133
+ });
134
+ currentState.pendingPublishFn = null;
135
+ }
136
+ }, delay);
137
+ }
138
+
139
+ /**
140
+ * Mark the first publish as done for a conversation.
141
+ * This ensures subsequent schedulePublish calls will debounce instead of publishing immediately.
142
+ * Use this when doing immediate metadata generation outside the debounce manager.
143
+ */
144
+ markFirstPublishDone(conversationId: string): void {
145
+ let state = this.debounceStates.get(conversationId);
146
+ if (!state) {
147
+ state = {
148
+ timerId: null,
149
+ firstExecutionDone: true,
150
+ maxDeadline: Date.now() + MAX_DELAY_MS,
151
+ pendingPublishFn: null,
152
+ };
153
+ this.debounceStates.set(conversationId, state);
154
+ } else {
155
+ state.firstExecutionDone = true;
156
+ }
157
+ logger.debug("[MetadataDebounce] Marked first publish done", {
158
+ conversationId: conversationId.substring(0, 8),
159
+ });
160
+ }
161
+
162
+ /**
163
+ * Cleanup for a specific conversation. Clears timer without publishing.
164
+ */
165
+ cleanup(conversationId: string): void {
166
+ const state = this.debounceStates.get(conversationId);
167
+ if (state?.timerId) {
168
+ clearTimeout(state.timerId);
169
+ }
170
+ this.debounceStates.delete(conversationId);
171
+ }
172
+
173
+ /**
174
+ * Cleanup all state. Called on shutdown.
175
+ */
176
+ cleanupAll(): void {
177
+ for (const state of this.debounceStates.values()) {
178
+ if (state.timerId) {
179
+ clearTimeout(state.timerId);
180
+ }
181
+ }
182
+ this.debounceStates.clear();
183
+ logger.debug("[MetadataDebounce] All timers cleared on shutdown");
184
+ }
185
+ }
186
+
187
+ // Singleton instance
188
+ export const metadataDebounceManager = new MetadataDebounceManager();
@@ -0,0 +1,2 @@
1
+ export { CategoryManager, type CategoryTally } from "./CategoryManager";
2
+ export { ConversationResolver, type ConversationResolutionResult } from "./ConversationResolver";
@@ -0,0 +1,148 @@
1
+ import type { ToolCallPart, ToolResultPart } from "ai";
2
+ import type { TodoItem } from "@/services/ral/types";
3
+
4
+ export type MessageType = "text" | "tool-call" | "tool-result" | "delegation-marker";
5
+
6
+ /**
7
+ * Marker stored in conversation history to track delegation lifecycle.
8
+ * Markers are created immediately when a delegation is initiated (status: "pending"),
9
+ * and updated when the delegation completes or is aborted.
10
+ * Instead of embedding the full transcript inline, we store a reference
11
+ * and lazily expand it when building messages.
12
+ */
13
+ export interface DelegationMarker {
14
+ /** The delegation conversation ID (used to retrieve transcript) */
15
+ delegationConversationId: string;
16
+ /** The agent pubkey that received the delegation */
17
+ recipientPubkey: string;
18
+ /** The conversation ID of the parent (delegator) - for direct-child validation */
19
+ parentConversationId: string;
20
+ /** When the delegation was initiated (Unix timestamp in seconds) */
21
+ initiatedAt?: number;
22
+ /** When the delegation completed (Unix timestamp in seconds) - only set when completed/aborted */
23
+ completedAt?: number;
24
+ /** Delegation status: pending (in progress), completed (successful), or aborted */
25
+ status: "pending" | "completed" | "aborted";
26
+ /** If aborted, the reason for the abort */
27
+ abortReason?: string;
28
+ }
29
+
30
+ export interface ConversationEntry {
31
+ pubkey: string;
32
+ ral?: number; // Only for agent messages
33
+ content: string; // Text content (for text messages) or empty for tool messages
34
+ messageType: MessageType;
35
+ toolData?: ToolCallPart[] | ToolResultPart[]; // Only for tool-call and tool-result
36
+ eventId?: string; // If published to Nostr
37
+ timestamp?: number; // Unix timestamp (seconds) - from NDKEvent.created_at or Date.now()/1000
38
+ targetedPubkeys?: string[]; // Agent pubkeys this message is directed to (from p-tags)
39
+ /** Original sender pubkey for injected messages (for attribution when sender differs from expected) */
40
+ senderPubkey?: string;
41
+ /**
42
+ * Explicit role override for synthetic entries (e.g., compressed summaries).
43
+ * When present, this role is used instead of deriving from pubkey.
44
+ * Used to ensure compressed summaries are rendered as "system" role, not "user".
45
+ */
46
+ role?: "user" | "assistant" | "tool" | "system";
47
+ /**
48
+ * For delegation-marker messageType: contains the marker data.
49
+ * This allows lazy expansion of delegation transcripts when building messages.
50
+ */
51
+ delegationMarker?: DelegationMarker;
52
+ }
53
+
54
+ export interface Injection {
55
+ targetRal: { pubkey: string; ral: number };
56
+ role: "user" | "system";
57
+ content: string;
58
+ queuedAt: number;
59
+ }
60
+
61
+ /**
62
+ * Deferred injection - a message to be injected on the agent's NEXT turn.
63
+ *
64
+ * Unlike Injection which targets a specific RAL, DeferredInjection is consumed
65
+ * at the START of any future RAL for the target agent. This is used for
66
+ * supervision messages that should NOT block the current completion but should
67
+ * appear in the agent's next conversation turn.
68
+ */
69
+ export interface DeferredInjection {
70
+ /** The agent pubkey this injection is for */
71
+ targetPubkey: string;
72
+ /** The role of the injected message */
73
+ role: "system";
74
+ /** The message content */
75
+ content: string;
76
+ /** When this injection was queued (ms since epoch) */
77
+ queuedAt: number;
78
+ /** Optional source identifier for debugging (e.g., "supervision:consecutive-tools-without-todo") */
79
+ source?: string;
80
+ }
81
+
82
+ /**
83
+ * Represents a participant in the delegation chain.
84
+ * Can be either a human user or an agent.
85
+ */
86
+ export interface DelegationChainEntry {
87
+ /** The pubkey of the participant */
88
+ pubkey: string;
89
+ /** The display name (agent slug or shortened pubkey) */
90
+ displayName: string;
91
+ /** Whether this is the project owner/human user */
92
+ isUser: boolean;
93
+ /** The conversation ID where this delegation occurred (full ID, truncated only at display time) */
94
+ conversationId?: string;
95
+ }
96
+
97
+ export interface ConversationMetadata {
98
+ title?: string;
99
+ branch?: string;
100
+ summary?: string;
101
+ requirements?: string;
102
+ plan?: string;
103
+ projectPath?: string;
104
+ last_user_message?: string;
105
+ statusLabel?: string;
106
+ statusCurrentActivity?: string;
107
+ referencedArticle?: {
108
+ title: string;
109
+ content: string;
110
+ dTag: string;
111
+ };
112
+ /**
113
+ * The delegation chain showing who initiated this conversation.
114
+ * First entry is the original initiator (typically User), last entry is the current agent.
115
+ * Example: [User, pm-wip, execution-coordinator, claude-code]
116
+ */
117
+ delegationChain?: DelegationChainEntry[];
118
+ }
119
+
120
+ export interface RalTracker {
121
+ id: number;
122
+ }
123
+
124
+ export interface ExecutionTime {
125
+ totalSeconds: number;
126
+ currentSessionStart?: number;
127
+ isActive: boolean;
128
+ lastUpdated: number;
129
+ }
130
+
131
+ export interface ConversationState {
132
+ activeRal: Record<string, RalTracker[]>;
133
+ nextRalNumber: Record<string, number>;
134
+ injections: Injection[];
135
+ messages: ConversationEntry[];
136
+ metadata: ConversationMetadata;
137
+ agentTodos: Record<string, TodoItem[]>;
138
+ todoNudgedAgents: string[]; // Agents who have been nudged about todo usage
139
+ blockedAgents: string[];
140
+ executionTime: ExecutionTime;
141
+ /** Meta model variant override per agent - when set, uses this variant instead of keyword detection */
142
+ metaModelVariantOverride?: Record<string, string>; // agentPubkey -> variantName
143
+ /**
144
+ * Deferred injections - messages to be injected on an agent's NEXT turn.
145
+ * Used by supervision for non-blocking nudges that shouldn't prevent completion.
146
+ */
147
+ deferredInjections?: DeferredInjection[];
148
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Content utilities for processing conversation messages
3
+ * Purpose: Strip <thinking>...</thinking> blocks from conversation history; skip messages that are purely thinking blocks.
4
+ * Also filter out events with reasoning tags.
5
+ */
6
+
7
+ import type { NDKEvent } from "@nostr-dev-kit/ndk";
8
+
9
+ /**
10
+ * Regex pattern to match thinking blocks (case-insensitive, multi-line)
11
+ * Matches: <thinking>, <Thinking>, <THINKING> with any attributes and their closing tags
12
+ */
13
+ const THINKING_BLOCK_REGEX = /<thinking\b[^>]*>[\s\S]*?<\/thinking>/gi;
14
+
15
+ /**
16
+ * Remove all thinking blocks from content
17
+ * @param content - The content to process
18
+ * @returns The content with all thinking blocks removed and normalized whitespace (multiple blank lines collapsed to single newline)
19
+ */
20
+ export function stripThinkingBlocks(content: string): string {
21
+ if (!content) return "";
22
+
23
+ // Remove all thinking blocks
24
+ let stripped = content.replace(THINKING_BLOCK_REGEX, "");
25
+
26
+ // Normalize whitespace more carefully:
27
+ // 1. Only collapse multiple spaces that aren't at the beginning of a line (preserve indentation)
28
+ // 2. Collapse multiple blank lines to a single newline
29
+ stripped = stripped
30
+ .split("\n")
31
+ .map((line) => {
32
+ // Only collapse spaces in the middle of lines, not at the start (preserve indentation)
33
+ if (line.trimStart() !== line) {
34
+ // Line has leading whitespace - preserve it
35
+ const leadingWhitespace = line.match(/^\s*/)?.[0] || "";
36
+ const rest = line.slice(leadingWhitespace.length);
37
+ return leadingWhitespace + rest.replace(/ {2,}/g, " ");
38
+ }
39
+ // No leading whitespace - collapse all multiple spaces
40
+ return line.replace(/ {2,}/g, " ");
41
+ })
42
+ .join("\n")
43
+ .replace(/\n\s*\n+/g, "\n") // Collapse 2+ newlines to single newline
44
+ .trim(); // Trim leading/trailing whitespace
45
+
46
+ return stripped;
47
+ }
48
+
49
+ /**
50
+ * Check if content contains only thinking blocks (no other content)
51
+ * @param content - The content to check
52
+ * @returns True if the content is empty after removing thinking blocks
53
+ */
54
+ export function isOnlyThinkingBlocks(content: string): boolean {
55
+ if (!content || content.trim().length === 0) return false; // Empty/whitespace content is not "only thinking blocks"
56
+
57
+ const stripped = stripThinkingBlocks(content);
58
+ return stripped.length === 0;
59
+ }
60
+
61
+ /**
62
+ * Check if an event has a reasoning tag
63
+ * @param event - The NDK event to check
64
+ * @returns True if the event has a ["reasoning"] tag
65
+ */
66
+ export function hasReasoningTag(event: NDKEvent): boolean {
67
+ if (!event.tags) return false;
68
+ return event.tags.some((tag) => tag[0] === "reasoning" && tag.length === 1);
69
+ }