@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,250 @@
1
+ import type { AISdkTool } from "@/tools/types";
2
+ import { logger } from "@/utils/logger";
3
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
4
+ import type {
5
+ StepResult,
6
+ StreamTextOnFinishCallback,
7
+ } from "ai";
8
+ import type { EventEmitter } from "tseep";
9
+ import { PROVIDER_IDS } from "./providers/provider-ids";
10
+ import { getInvalidToolCalls } from "./utils/tool-errors";
11
+ import { extractUsageMetadata, extractOpenRouterGenerationId } from "./providers/usage-metadata";
12
+ import type { LLMServiceEventMap } from "./types";
13
+
14
+ export interface FinishHandlerConfig {
15
+ provider: string;
16
+ model: string;
17
+ getModelContextWindow: () => number | undefined;
18
+ }
19
+
20
+ export interface FinishHandlerState {
21
+ getCachedContent: () => string;
22
+ clearCachedContent: () => void;
23
+ getLastUserMessage: () => string | undefined;
24
+ clearLastUserMessage: () => void;
25
+ }
26
+
27
+ /**
28
+ * Creates the onFinish handler for LLM streaming.
29
+ * Extracted from LLMService to reduce file size.
30
+ */
31
+ export function createFinishHandler(
32
+ emitter: EventEmitter<LLMServiceEventMap>,
33
+ config: FinishHandlerConfig,
34
+ state: FinishHandlerState
35
+ ): StreamTextOnFinishCallback<Record<string, AISdkTool>> {
36
+ return async (e) => {
37
+ const onFinishStartTime = Date.now();
38
+ const activeSpan = trace.getActiveSpan();
39
+
40
+ // DIAGNOSTIC: Track onFinish lifecycle for debugging race conditions
41
+ activeSpan?.addEvent("llm.onFinish_started", {
42
+ "onFinish.start_time": onFinishStartTime,
43
+ "onFinish.finish_reason": e.finishReason,
44
+ "onFinish.steps_count": e.steps.length,
45
+ "onFinish.text_length": e.text?.length ?? 0,
46
+ "onFinish.cached_content_length": state.getCachedContent().length,
47
+ });
48
+
49
+ try {
50
+ recordInvalidToolCalls(e.steps, "response", config.model, config.provider);
51
+
52
+ // For streaming, use cached content if available.
53
+ // When cachedContentForComplete is empty but e.text has content, it means:
54
+ // - Content was already published as conversation event(s) via chunk-type-change
55
+ // - BUT we still need to re-publish it in the completion event for delegations
56
+ // This creates intentional duplication (conversation + completion both have same text)
57
+ // but ensures delegated agents receive the full response via p-tag on completion.
58
+ //
59
+ // Three-level fallback for finalMessage:
60
+ // 1. Use cachedContent if available (normal case)
61
+ // 2. Use e.text if cachedContent is empty AND e.text is non-empty (fallback when content was already published)
62
+ // 3. Use error message if both are empty (edge case where no content was captured)
63
+ const ERROR_FALLBACK_MESSAGE =
64
+ "There was an error capturing the work done, please review the conversation for the results";
65
+
66
+ const cachedContent = state.getCachedContent();
67
+ const text = e.text ?? "";
68
+
69
+ const fallbackLevel =
70
+ cachedContent.length > 0 ? "cached" :
71
+ text.length > 0 ? "text" :
72
+ "error";
73
+
74
+ const finalMessage =
75
+ fallbackLevel === "cached" ? cachedContent :
76
+ fallbackLevel === "text" ? text :
77
+ ERROR_FALLBACK_MESSAGE;
78
+
79
+ const usedFallbackToText = fallbackLevel === "text";
80
+ const usedErrorFallback = fallbackLevel === "error";
81
+
82
+ emitSessionCapturedFromMetadata(
83
+ emitter,
84
+ config.provider,
85
+ e.providerMetadata as Record<string, unknown> | undefined,
86
+ false
87
+ );
88
+
89
+ // Capture OpenRouter generation ID for trace correlation
90
+ const openrouterGenerationId = extractOpenRouterGenerationId(
91
+ e.providerMetadata as Record<string, unknown> | undefined
92
+ );
93
+ if (openrouterGenerationId) {
94
+ activeSpan?.setAttribute("openrouter.generation_id", openrouterGenerationId);
95
+ }
96
+
97
+ // Extract usage metadata using provider-specific extractor
98
+ const usage = extractUsageMetadata(
99
+ config.provider,
100
+ config.model,
101
+ e.totalUsage,
102
+ e.providerMetadata as Record<string, unknown> | undefined
103
+ );
104
+
105
+ // DIAGNOSTIC: Log right before emitting complete event
106
+ const beforeEmitTime = Date.now();
107
+ activeSpan?.addEvent("llm.complete_will_emit", {
108
+ "complete.message_length": finalMessage.length,
109
+ "complete.cached_content_length": cachedContent.length,
110
+ "complete.e_text_length": text.length,
111
+ "complete.used_fallback_to_e_text": usedFallbackToText,
112
+ "complete.used_error_fallback": usedErrorFallback,
113
+ "complete.usage_input_tokens": usage.inputTokens,
114
+ "complete.usage_output_tokens": usage.outputTokens,
115
+ "complete.finish_reason": e.finishReason,
116
+ "complete.ms_since_onFinish_start": beforeEmitTime - onFinishStartTime,
117
+ });
118
+
119
+ emitter.emit("complete", {
120
+ message: finalMessage,
121
+ steps: e.steps,
122
+ usage: {
123
+ ...usage,
124
+ contextWindow: config.getModelContextWindow(),
125
+ },
126
+ finishReason: e.finishReason,
127
+ });
128
+
129
+ // DIAGNOSTIC: Log after emitting complete event
130
+ const afterEmitTime = Date.now();
131
+ activeSpan?.addEvent("llm.complete_did_emit", {
132
+ "complete.emit_duration_ms": afterEmitTime - beforeEmitTime,
133
+ "complete.total_onFinish_duration_ms": afterEmitTime - onFinishStartTime,
134
+ });
135
+
136
+ // Log the user prompt so we can see what the LLM was answering to
137
+ const lastUserMessage = state.getLastUserMessage();
138
+ if (lastUserMessage) {
139
+ const truncatedPrompt = lastUserMessage.length > 2000
140
+ ? lastUserMessage.substring(0, 2000) + "... [truncated]"
141
+ : lastUserMessage;
142
+ activeSpan?.addEvent("llm.prompt", {
143
+ "prompt.text": truncatedPrompt,
144
+ "prompt.full_length": lastUserMessage.length,
145
+ "prompt.truncated": lastUserMessage.length > 2000,
146
+ });
147
+ }
148
+
149
+ // Log the actual response text so it shows up in Jaeger's Logs section
150
+ // This makes it much easier to see what the LLM actually generated
151
+ if (e.text) {
152
+ // Truncate to avoid massive log entries (OTel has limits)
153
+ const truncatedText = e.text.length > 4000
154
+ ? e.text.substring(0, 4000) + "... [truncated]"
155
+ : e.text;
156
+ activeSpan?.addEvent("llm.response", {
157
+ "response.text": truncatedText,
158
+ "response.full_length": e.text.length,
159
+ "response.truncated": e.text.length > 4000,
160
+ });
161
+ }
162
+
163
+ // Clear cached content after use
164
+ state.clearCachedContent();
165
+ state.clearLastUserMessage();
166
+ } catch (error) {
167
+ const errorTime = Date.now();
168
+ activeSpan?.addEvent("llm.onFinish_error", {
169
+ "error.message": error instanceof Error ? error.message : String(error),
170
+ "error.type": error instanceof Error ? error.constructor.name : typeof error,
171
+ "error.ms_since_onFinish_start": errorTime - onFinishStartTime,
172
+ });
173
+ logger.error("[LLMService] Error in onFinish handler", {
174
+ error: error instanceof Error ? error.message : String(error),
175
+ });
176
+ throw error;
177
+ }
178
+ };
179
+ }
180
+
181
+ /**
182
+ * Record invalid tool calls to the active span
183
+ */
184
+ function recordInvalidToolCalls(
185
+ steps: StepResult<Record<string, AISdkTool>>[],
186
+ logContext: "complete" | "response",
187
+ model: string,
188
+ provider: string
189
+ ): void {
190
+ const activeSpan = trace.getActiveSpan();
191
+ if (!activeSpan) {
192
+ return;
193
+ }
194
+
195
+ const invalidToolCalls = getInvalidToolCalls(steps);
196
+ if (invalidToolCalls.length === 0) {
197
+ return;
198
+ }
199
+
200
+ const logSuffix = logContext === "complete" ? "complete()" : "response";
201
+
202
+ activeSpan.setStatus({
203
+ code: SpanStatusCode.ERROR,
204
+ message: `Invalid tool calls: ${invalidToolCalls.map((tc) => tc.toolName).join(", ")}`,
205
+ });
206
+ activeSpan.setAttribute("error", true);
207
+ activeSpan.setAttribute("error.type", "AI_InvalidToolCall");
208
+ activeSpan.setAttribute("error.invalid_tool_count", invalidToolCalls.length);
209
+ activeSpan.setAttribute(
210
+ "error.invalid_tools",
211
+ invalidToolCalls.map((tc) => tc.toolName).join(", ")
212
+ );
213
+
214
+ for (const invalidTool of invalidToolCalls) {
215
+ activeSpan.addEvent("invalid_tool_call", {
216
+ "tool.name": invalidTool.toolName,
217
+ "error.type": invalidTool.error,
218
+ });
219
+ }
220
+
221
+ logger.error(`[LLMService] Invalid tool calls detected in ${logSuffix}`, {
222
+ invalidToolCalls,
223
+ model,
224
+ provider,
225
+ });
226
+ }
227
+
228
+ /**
229
+ * Emit session-captured event from provider metadata
230
+ */
231
+ function emitSessionCapturedFromMetadata(
232
+ emitter: EventEmitter<LLMServiceEventMap>,
233
+ provider: string,
234
+ providerMetadata: Record<string, unknown> | undefined,
235
+ recordSpanEvent: boolean
236
+ ): void {
237
+ if (provider === PROVIDER_IDS.CODEX_APP_SERVER) {
238
+ const sessionId = (
239
+ providerMetadata?.[PROVIDER_IDS.CODEX_APP_SERVER] as { sessionId?: string } | undefined
240
+ )?.sessionId;
241
+ if (sessionId) {
242
+ if (recordSpanEvent) {
243
+ trace.getActiveSpan()?.addEvent("llm.session_captured", {
244
+ "session.id": sessionId,
245
+ });
246
+ }
247
+ emitter.emit("session-captured", { sessionId });
248
+ }
249
+ }
250
+ }
@@ -0,0 +1,154 @@
1
+ import { config } from "@/services/ConfigService";
2
+ import type { TenexLLMs } from "@/services/config/types";
3
+ import chalk from "chalk";
4
+ import inquirer from "inquirer";
5
+ import { llmServiceFactory } from "./LLMServiceFactory";
6
+ import { ConfigurationManager } from "./utils/ConfigurationManager";
7
+ import { ConfigurationTester } from "./utils/ConfigurationTester";
8
+ import { ProviderConfigUI } from "./utils/ProviderConfigUI";
9
+ import { runProviderSetup } from "./utils/provider-setup";
10
+
11
+ /**
12
+ * Internal type used by editor to work with providers
13
+ * Merges providers with llms for internal convenience
14
+ */
15
+ type LLMConfigWithProviders = TenexLLMs & {
16
+ providers: Record<string, { apiKey: string | string[] }>;
17
+ };
18
+
19
+ /**
20
+ * LLM Configuration Editor - Simple menu orchestrator
21
+ * Note: LLM configs are now global only (no project-level llms.json)
22
+ */
23
+ export class LLMConfigEditor {
24
+ constructor() {}
25
+
26
+ async showMainMenu(): Promise<void> {
27
+ const llmsConfig = await this.loadConfig();
28
+
29
+ console.log(chalk.cyan("\n=== LLM Configuration ===\n"));
30
+ ProviderConfigUI.displayCurrentConfig(llmsConfig);
31
+
32
+ const { action } = await inquirer.prompt([
33
+ {
34
+ type: "select",
35
+ name: "action",
36
+ message: "What would you like to do?",
37
+ choices: [
38
+ { name: "Add new configuration", value: "add" },
39
+ { name: "Create meta model", value: "addMeta" },
40
+ { name: "Delete configuration", value: "delete" },
41
+ {
42
+ name: `Default agents' model: ${llmsConfig.default || "none"}`,
43
+ value: "default",
44
+ },
45
+ {
46
+ name: `Summarization model: ${llmsConfig.summarization || "none"}`,
47
+ value: "summarization",
48
+ },
49
+ {
50
+ name: `Supervision model: ${llmsConfig.supervision || "none"}`,
51
+ value: "supervision",
52
+ },
53
+ {
54
+ name: `Search model: ${llmsConfig.search || "none"}`,
55
+ value: "search",
56
+ },
57
+ {
58
+ name: `Prompt compilation model: ${llmsConfig.promptCompilation || "none"}`,
59
+ value: "promptCompilation",
60
+ },
61
+ {
62
+ name: `Compression model: ${llmsConfig.compression || "none"}`,
63
+ value: "compression",
64
+ },
65
+ { name: "Test configuration", value: "test" },
66
+ { name: "Exit", value: "exit" },
67
+ ],
68
+ },
69
+ ]);
70
+
71
+ if (action === "exit") process.exit(0);
72
+
73
+ if (action === "test") {
74
+ await ConfigurationTester.test(llmsConfig);
75
+ } else {
76
+ // All other actions use ConfigurationManager
77
+ if (action === "add") await ConfigurationManager.add(llmsConfig);
78
+ if (action === "addMeta") await ConfigurationManager.addMetaModel(llmsConfig);
79
+ if (action === "delete") await ConfigurationManager.delete(llmsConfig);
80
+ if (action === "default") await ConfigurationManager.setDefault(llmsConfig);
81
+ if (action === "summarization") await ConfigurationManager.setSummarizationModel(llmsConfig);
82
+ if (action === "supervision") await ConfigurationManager.setSupervisionModel(llmsConfig);
83
+ if (action === "search") await ConfigurationManager.setSearchModel(llmsConfig);
84
+ if (action === "promptCompilation") await ConfigurationManager.setPromptCompilationModel(llmsConfig);
85
+ if (action === "compression") await ConfigurationManager.setCompressionModel(llmsConfig);
86
+ await this.saveConfig(llmsConfig);
87
+ }
88
+
89
+ await this.showMainMenu();
90
+ }
91
+
92
+ async runOnboardingFlow(): Promise<void> {
93
+ console.log(chalk.green("\n🚀 Welcome to TENEX LLM Setup!\n"));
94
+
95
+ const llmsConfig = await this.loadConfig();
96
+ const globalPath = config.getGlobalPath();
97
+
98
+ // Step 1: Configure providers
99
+ console.log(chalk.cyan("Step 1: Configure Provider API Keys"));
100
+ const existingProviders = await config.loadTenexProviders(globalPath);
101
+ const updatedProviders = await runProviderSetup(existingProviders);
102
+ llmsConfig.providers = updatedProviders.providers;
103
+ await this.saveConfig(llmsConfig);
104
+
105
+ // Step 2: Create first configuration
106
+ console.log(chalk.cyan("\nStep 2: Create Your First Configuration"));
107
+ await ConfigurationManager.add(llmsConfig, true);
108
+ await this.saveConfig(llmsConfig);
109
+
110
+ // Step 3: Offer to test
111
+ const { shouldTest } = await inquirer.prompt([
112
+ {
113
+ type: "confirm",
114
+ name: "shouldTest",
115
+ message: "Would you like to test your configuration?",
116
+ default: true,
117
+ },
118
+ ]);
119
+
120
+ if (shouldTest) {
121
+ await ConfigurationTester.test(llmsConfig);
122
+ }
123
+
124
+ console.log(chalk.green("\n✅ LLM configuration complete!"));
125
+ }
126
+
127
+ private async loadConfig(): Promise<LLMConfigWithProviders> {
128
+ const globalPath = config.getGlobalPath();
129
+
130
+ // Load providers and llms separately
131
+ const providersConfig = await config.loadTenexProviders(globalPath);
132
+ const llmsConfig = await config.loadTenexLLMs(globalPath);
133
+
134
+ // Merge for internal editor use
135
+ return {
136
+ ...llmsConfig,
137
+ providers: providersConfig.providers,
138
+ };
139
+ }
140
+
141
+ private async saveConfig(llmsConfig: LLMConfigWithProviders): Promise<void> {
142
+ // Split providers and llms for separate storage
143
+ const { providers, ...llmsWithoutProviders } = llmsConfig;
144
+
145
+ // Save providers to providers.json
146
+ await config.saveGlobalProviders({ providers });
147
+
148
+ // Save llms to llms.json
149
+ await config.saveGlobalLLMs(llmsWithoutProviders as TenexLLMs);
150
+
151
+ // Re-initialize factory with updated providers
152
+ await llmServiceFactory.initializeProviders(providers);
153
+ }
154
+ }
@@ -0,0 +1,230 @@
1
+ /**
2
+ * LLM Service Factory
3
+ *
4
+ * Factory for creating LLM services with proper provider initialization.
5
+ * This module provides a simplified interface that delegates to the
6
+ * modular ProviderRegistry for actual provider management.
7
+ *
8
+ * @see src/llm/providers for individual provider implementations
9
+ */
10
+
11
+ import type { LLMConfiguration } from "@/services/config/types";
12
+ import type { AISdkTool } from "@/tools/types";
13
+ import { logger } from "@/utils/logger";
14
+ import type { LanguageModel, ProviderRegistryProvider } from "ai";
15
+ import type { ClaudeCodeSettings } from "ai-sdk-provider-claude-code";
16
+
17
+ import { LLMService } from "./service";
18
+ import {
19
+ providerRegistry,
20
+ type MCPConfig,
21
+ type ProviderPoolConfig,
22
+ type ProviderRuntimeContext,
23
+ } from "./providers";
24
+ import { PROVIDER_IDS } from "./providers/provider-ids";
25
+ import type { OnStreamStartCallback } from "./types";
26
+
27
+ /**
28
+ * Factory for creating LLM services with proper provider initialization
29
+ *
30
+ * This factory provides a high-level interface for:
31
+ * - Initializing providers from configuration
32
+ * - Creating LLMService instances
33
+ * - Checking provider availability
34
+ *
35
+ * The actual provider management is delegated to the ProviderRegistry.
36
+ */
37
+ export class LLMServiceFactory {
38
+ private initialized = false;
39
+
40
+ /**
41
+ * Initialize providers from configuration
42
+ *
43
+ * @param providerConfigs Map of provider names to their configurations
44
+ * @param options Additional options for initialization
45
+ */
46
+ async initializeProviders(
47
+ providerConfigs: Record<string, { apiKey: string | string[] }>
48
+ ): Promise<void> {
49
+ // Convert to ProviderPoolConfig format
50
+ // apiKey can be a single string or an array — KeyManager handles the rest
51
+ const configs: Record<string, ProviderPoolConfig> = {};
52
+ for (const [name, config] of Object.entries(providerConfigs)) {
53
+ const hasKey = Array.isArray(config?.apiKey)
54
+ ? config.apiKey.length > 0
55
+ : !!config?.apiKey;
56
+
57
+ if (hasKey) {
58
+ configs[name] = {
59
+ apiKey: config.apiKey,
60
+ };
61
+ }
62
+ }
63
+
64
+ // Also ensure agent providers are initialized (they don't need API keys).
65
+ // Add them with empty configs if not already present.
66
+ const agentProviders = [PROVIDER_IDS.CLAUDE_CODE, PROVIDER_IDS.CODEX_APP_SERVER];
67
+ for (const providerId of agentProviders) {
68
+ if (!configs[providerId]) {
69
+ configs[providerId] = {};
70
+ }
71
+ }
72
+
73
+ // Initialize through the registry (which has its own tracing span)
74
+ const results = await providerRegistry.initialize(configs);
75
+
76
+ // Log initialization failures
77
+ const failed = results.filter(r => !r.success);
78
+ if (failed.length > 0) {
79
+ for (const f of failed) {
80
+ logger.error(`[LLMServiceFactory] Failed to initialize provider ${f.providerId}`, {
81
+ error: f.error,
82
+ });
83
+ }
84
+ }
85
+
86
+ this.initialized = true;
87
+ }
88
+
89
+ /**
90
+ * Create an LLM service from a resolved configuration
91
+ *
92
+ * @param config LLM configuration
93
+ * @param context Optional runtime context for agents
94
+ */
95
+ createService(
96
+ config: LLMConfiguration,
97
+ context?: {
98
+ tools?: Record<string, AISdkTool>;
99
+ agentName?: string;
100
+ sessionId?: string;
101
+ /** Working directory path for agent execution */
102
+ workingDirectory?: string;
103
+ /** MCP configuration - passed from services layer to providers */
104
+ mcpConfig?: MCPConfig;
105
+ /** Conversation ID for OpenRouter correlation */
106
+ conversationId?: string;
107
+ /** Callback invoked when Claude Code stream starts, providing the message injector */
108
+ onStreamStart?: OnStreamStartCallback;
109
+ }
110
+ ): LLMService {
111
+ if (!this.initialized) {
112
+ throw new Error("LLMServiceFactory not initialized. Call initializeProviders first.");
113
+ }
114
+
115
+ // Convert agent name to slug format for telemetry
116
+ const agentSlug = context?.agentName
117
+ ? context.agentName.toLowerCase().replace(/\s+/g, "-")
118
+ : undefined;
119
+
120
+ // Determine the actual provider (mock mode handling)
121
+ const actualProvider = process.env.USE_MOCK_LLM === "true" ? "mock" : config.provider;
122
+
123
+ // Build the runtime context for the provider
124
+ const runtimeContext: ProviderRuntimeContext = {
125
+ tools: context?.tools,
126
+ agentName: context?.agentName,
127
+ sessionId: context?.sessionId,
128
+ workingDirectory: context?.workingDirectory,
129
+ mcpConfig: context?.mcpConfig,
130
+ reasoningEffort: (config as { reasoningEffort?: "none" | "low" | "medium" | "high" | "xhigh" }).reasoningEffort,
131
+ onStreamStart: context?.onStreamStart,
132
+ };
133
+
134
+ // Get the provider from the registry
135
+ const provider = providerRegistry.getProvider(actualProvider);
136
+
137
+ if (!provider) {
138
+ const available = providerRegistry.getAvailableProviders().map(p => p.id);
139
+ throw new Error(
140
+ `Provider "${actualProvider}" not available. ` +
141
+ `Initialized providers: ${available.length > 0 ? available.join(", ") : "none"}`
142
+ );
143
+ }
144
+
145
+ // Create the model from the provider
146
+ const modelResult = provider.createModel(config.model, runtimeContext);
147
+
148
+ // Get capabilities from provider metadata
149
+ const capabilities = provider.metadata.capabilities;
150
+
151
+ // For agent providers (claude-code, codex-app-server), use their provider function
152
+ if (modelResult.bypassRegistry && modelResult.providerFunction) {
153
+ return new LLMService(
154
+ null,
155
+ actualProvider,
156
+ config.model,
157
+ capabilities,
158
+ config.temperature,
159
+ config.maxTokens,
160
+ modelResult.providerFunction as (model: string, options?: ClaudeCodeSettings) => LanguageModel,
161
+ modelResult.agentSettings as ClaudeCodeSettings,
162
+ context?.sessionId,
163
+ agentSlug,
164
+ context?.conversationId
165
+ );
166
+ }
167
+
168
+ // For standard providers, use the AI SDK registry
169
+ const registry = providerRegistry.getAiSdkRegistry();
170
+
171
+ return new LLMService(
172
+ registry,
173
+ actualProvider,
174
+ config.model,
175
+ capabilities,
176
+ config.temperature,
177
+ config.maxTokens,
178
+ undefined,
179
+ undefined,
180
+ context?.sessionId,
181
+ agentSlug,
182
+ context?.conversationId
183
+ );
184
+ }
185
+
186
+ /**
187
+ * Check if a provider is available
188
+ */
189
+ hasProvider(providerName: string): boolean {
190
+ return providerRegistry.hasProvider(providerName);
191
+ }
192
+
193
+ /**
194
+ * Get the AI SDK provider registry
195
+ * Useful for direct access to language models
196
+ */
197
+ getRegistry(): ProviderRegistryProvider {
198
+ if (!this.initialized) {
199
+ throw new Error("LLMServiceFactory not initialized. Call initializeProviders first.");
200
+ }
201
+ return providerRegistry.getAiSdkRegistry();
202
+ }
203
+
204
+ /**
205
+ * Get list of available providers
206
+ */
207
+ getAvailableProviders(): string[] {
208
+ return providerRegistry.getAvailableProviders().map(p => p.id);
209
+ }
210
+
211
+ /**
212
+ * Get list of all registered providers (even if not initialized)
213
+ */
214
+ getRegisteredProviders(): string[] {
215
+ return providerRegistry.getRegisteredProviders().map(p => p.id);
216
+ }
217
+
218
+ /**
219
+ * Reset the factory (mainly for testing)
220
+ */
221
+ reset(): void {
222
+ providerRegistry.reset();
223
+ this.initialized = false;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Export singleton instance
229
+ */
230
+ export const llmServiceFactory = new LLMServiceFactory();