@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,414 @@
1
+ /**
2
+ * Provider Registry - Central registry for all LLM providers
3
+ *
4
+ * This module provides a unified registry for managing LLM providers,
5
+ * supporting both standard AI SDK providers and custom agent providers.
6
+ * Integrates with KeyManager for multi-key rotation and fallback.
7
+ */
8
+
9
+ import { createProviderRegistry } from "ai";
10
+ import type { ProviderRegistryProvider } from "ai";
11
+ import type { ProviderV3 } from "@ai-sdk/provider";
12
+ import { logger } from "@/utils/logger";
13
+ import { keyManager } from "../key-manager";
14
+ import type {
15
+ ILLMProvider,
16
+ ProviderInitConfig,
17
+ ProviderPoolConfig,
18
+ ProviderMetadata,
19
+ ProviderRegistration,
20
+ ProviderRuntimeContext,
21
+ ProviderModelResult,
22
+ } from "../types";
23
+
24
+ /**
25
+ * Provider initialization result
26
+ */
27
+ interface InitializationResult {
28
+ providerId: string;
29
+ success: boolean;
30
+ error?: string;
31
+ }
32
+
33
+ /**
34
+ * Central registry for all LLM providers
35
+ *
36
+ * The registry manages provider lifecycle:
37
+ * 1. Registration - Providers register themselves
38
+ * 2. Initialization - Providers are initialized with API keys
39
+ * 3. Model Creation - Providers create language models on demand
40
+ * 4. Key Rotation - Providers can be re-initialized with a different key on failure
41
+ */
42
+ export class ProviderRegistry {
43
+ private static instance: ProviderRegistry | null = null;
44
+
45
+ private providers: Map<string, ILLMProvider> = new Map();
46
+ private registrations: Map<string, ProviderRegistration> = new Map();
47
+ private providerConfigs: Map<string, ProviderPoolConfig> = new Map();
48
+ private activeApiKeys: Map<string, string> = new Map();
49
+ private aiSdkRegistry: ProviderRegistryProvider | null = null;
50
+ private initialized = false;
51
+
52
+ /**
53
+ * Get the singleton instance
54
+ */
55
+ static getInstance(): ProviderRegistry {
56
+ if (!ProviderRegistry.instance) {
57
+ ProviderRegistry.instance = new ProviderRegistry();
58
+ }
59
+ return ProviderRegistry.instance;
60
+ }
61
+
62
+ /**
63
+ * Reset the singleton (for testing)
64
+ */
65
+ static resetInstance(): void {
66
+ if (ProviderRegistry.instance) {
67
+ ProviderRegistry.instance.reset();
68
+ ProviderRegistry.instance = null;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Register a provider class
74
+ * This should be called during module initialization
75
+ */
76
+ register(registration: ProviderRegistration): void {
77
+ const { metadata } = registration;
78
+
79
+ if (this.registrations.has(metadata.id)) {
80
+ logger.warn(`[ProviderRegistry] Provider "${metadata.id}" already registered, skipping`);
81
+ return;
82
+ }
83
+
84
+ this.registrations.set(metadata.id, registration);
85
+ logger.debug(`[ProviderRegistry] Registered provider: ${metadata.id}`);
86
+ }
87
+
88
+ /**
89
+ * Register multiple providers at once
90
+ */
91
+ registerAll(registrations: ProviderRegistration[]): void {
92
+ for (const reg of registrations) {
93
+ this.register(reg);
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Initialize all registered providers with their configurations.
99
+ * Supports multi-key configs — keys are registered with KeyManager
100
+ * and a single key is selected for each provider's initial setup.
101
+ */
102
+ async initialize(
103
+ configs: Record<string, ProviderPoolConfig>
104
+ ): Promise<InitializationResult[]> {
105
+ const results: InitializationResult[] = [];
106
+ this.providers.clear();
107
+ this.providerConfigs.clear();
108
+ this.activeApiKeys.clear();
109
+
110
+ // Check if mock mode is enabled
111
+ if (process.env.USE_MOCK_LLM === "true") {
112
+ await this.initializeMockProvider();
113
+ }
114
+
115
+ // Register all key pools with KeyManager and initialize providers
116
+ for (const [providerId, registration] of this.registrations) {
117
+ const config = configs[providerId];
118
+ const rawKey = config?.apiKey;
119
+
120
+ // Normalize: treat empty arrays and arrays of only empty strings as "no key"
121
+ const apiKey = Array.isArray(rawKey)
122
+ ? (rawKey.filter(k => k.length > 0).length > 0 ? rawKey : undefined)
123
+ : (rawKey || undefined);
124
+
125
+ // Register keys with KeyManager (handles string | string[])
126
+ if (apiKey) {
127
+ keyManager.registerKeys(providerId, apiKey);
128
+ }
129
+
130
+ // Skip providers without config (unless they don't require API key)
131
+ if (!apiKey && registration.metadata.capabilities.requiresApiKey) {
132
+ continue;
133
+ }
134
+
135
+ // Store the full config for potential re-initialization
136
+ if (config) {
137
+ this.providerConfigs.set(providerId, config);
138
+ }
139
+
140
+ // Select a single key for this initialization
141
+ const selectedKey = apiKey ? keyManager.selectKey(providerId) : undefined;
142
+
143
+ try {
144
+ const provider = new registration.Provider();
145
+ const initConfig: ProviderInitConfig = {
146
+ apiKey: selectedKey,
147
+ baseUrl: config?.baseUrl,
148
+ options: config?.options,
149
+ };
150
+ await provider.initialize(initConfig);
151
+ this.providers.set(providerId, provider);
152
+ if (selectedKey) {
153
+ this.activeApiKeys.set(providerId, selectedKey);
154
+ }
155
+
156
+ results.push({ providerId, success: true });
157
+
158
+ logger.debug(`[ProviderRegistry] Initialized provider: ${providerId}`);
159
+ } catch (error) {
160
+ const errorMessage = error instanceof Error ? error.message : String(error);
161
+ results.push({ providerId, success: false, error: errorMessage });
162
+
163
+ logger.error(`[ProviderRegistry] Failed to initialize provider ${providerId}`, {
164
+ error: errorMessage,
165
+ });
166
+ }
167
+ }
168
+
169
+ // Build the AI SDK registry from standard providers
170
+ this.buildAiSdkRegistry();
171
+
172
+ this.initialized = true;
173
+
174
+ logger.debug(`[ProviderRegistry] Initialized ${this.providers.size} providers: ${Array.from(this.providers.keys()).join(", ")}`);
175
+
176
+ return results;
177
+ }
178
+
179
+ /**
180
+ * Re-initialize a provider with a different API key.
181
+ * Called when a key fails at runtime to attempt fallback.
182
+ *
183
+ * @param providerId The provider to re-initialize
184
+ * @param failedKey The key that failed (will be reported to KeyManager)
185
+ * @returns true if re-initialization succeeded with a new key
186
+ */
187
+ async reinitializeProvider(providerId: string, failedKey: string): Promise<boolean> {
188
+ if (!keyManager.hasMultipleKeys(providerId)) {
189
+ return false;
190
+ }
191
+
192
+ // Report the failure to track key health
193
+ keyManager.reportFailure(providerId, failedKey);
194
+
195
+ // Select a new key (KeyManager will avoid disabled keys)
196
+ const newKey = keyManager.selectKey(providerId);
197
+ if (!newKey || newKey === failedKey) {
198
+ logger.warn(`[ProviderRegistry] No alternative key available for "${providerId}"`);
199
+ return false;
200
+ }
201
+
202
+ const registration = this.registrations.get(providerId);
203
+ const originalConfig = this.providerConfigs.get(providerId);
204
+ if (!registration || !originalConfig) {
205
+ return false;
206
+ }
207
+
208
+ try {
209
+ // Build the new provider FIRST — never tear down before we have a replacement
210
+ const newProvider = new registration.Provider();
211
+ const initConfig: ProviderInitConfig = {
212
+ apiKey: newKey,
213
+ baseUrl: originalConfig.baseUrl,
214
+ options: originalConfig.options,
215
+ };
216
+ await newProvider.initialize(initConfig);
217
+
218
+ // New provider is ready — now swap it in and clean up the old one
219
+ const oldProvider = this.providers.get(providerId);
220
+ this.providers.set(providerId, newProvider);
221
+ this.activeApiKeys.set(providerId, newKey);
222
+
223
+ if (oldProvider) {
224
+ oldProvider.reset();
225
+ }
226
+
227
+ // Rebuild the AI SDK registry to reflect the new provider instance
228
+ this.buildAiSdkRegistry();
229
+
230
+ const keyPreview = newKey.slice(0, 8) + "...";
231
+ logger.info(`[ProviderRegistry] Re-initialized "${providerId}" with key ${keyPreview}`);
232
+ return true;
233
+ } catch (error) {
234
+ const errorMessage = error instanceof Error ? error.message : String(error);
235
+ logger.error(`[ProviderRegistry] Failed to re-initialize "${providerId}"`, {
236
+ error: errorMessage,
237
+ });
238
+ // Old provider remains intact — no downtime
239
+ return false;
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Get the currently active API key for a provider.
245
+ * Used by callers that need to report which key failed.
246
+ */
247
+ getActiveApiKey(providerId: string): string | undefined {
248
+ return this.activeApiKeys.get(providerId);
249
+ }
250
+
251
+ /**
252
+ * Initialize the mock provider for testing
253
+ */
254
+ private async initializeMockProvider(): Promise<void> {
255
+ try {
256
+ const { createMockProvider } = await import("../MockProvider");
257
+ const mockProvider = createMockProvider();
258
+
259
+ // Create a wrapper that satisfies ILLMProvider
260
+ const mockWrapper: ILLMProvider = {
261
+ metadata: {
262
+ id: "mock",
263
+ displayName: "Mock Provider",
264
+ description: "Mock provider for testing",
265
+ category: "standard",
266
+ capabilities: {
267
+ streaming: true,
268
+ toolCalling: true,
269
+ builtInTools: false,
270
+ sessionResumption: false,
271
+ requiresApiKey: false,
272
+ mcpSupport: false,
273
+ },
274
+ defaultModel: "mock-model",
275
+ },
276
+ initialize: async () => {},
277
+ isInitialized: () => true,
278
+ isAvailable: () => true,
279
+ getProviderInstance: () => mockProvider,
280
+ createModel: (modelId) => ({
281
+ model: mockProvider.languageModel(modelId),
282
+ bypassRegistry: false,
283
+ }),
284
+ reset: () => {},
285
+ };
286
+
287
+ this.providers.set("mock", mockWrapper);
288
+ } catch (error) {
289
+ logger.error("[ProviderRegistry] Failed to load MockProvider:", error);
290
+ throw new Error(
291
+ "Mock mode is enabled but MockProvider could not be loaded. " +
292
+ "Make sure test dependencies are installed.",
293
+ { cause: error }
294
+ );
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Build the AI SDK provider registry from initialized standard providers
300
+ */
301
+ private buildAiSdkRegistry(): void {
302
+ const standardProviders: Record<string, ProviderV3> = {};
303
+
304
+ for (const [providerId, provider] of this.providers) {
305
+ // Only include standard providers in the AI SDK registry
306
+ if (provider.metadata.category === "standard") {
307
+ const instance = provider.getProviderInstance();
308
+ if (instance) {
309
+ standardProviders[providerId] = instance as ProviderV3;
310
+ }
311
+ }
312
+ }
313
+
314
+ if (Object.keys(standardProviders).length > 0) {
315
+ this.aiSdkRegistry = createProviderRegistry(standardProviders);
316
+ } else {
317
+ // Create empty registry to avoid null checks
318
+ this.aiSdkRegistry = createProviderRegistry({});
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Get a provider by ID
324
+ */
325
+ getProvider(providerId: string): ILLMProvider | undefined {
326
+ return this.providers.get(providerId);
327
+ }
328
+
329
+ /**
330
+ * Check if a provider is available
331
+ */
332
+ hasProvider(providerId: string): boolean {
333
+ return this.providers.has(providerId) &&
334
+ (this.providers.get(providerId)?.isAvailable() ?? false);
335
+ }
336
+
337
+ /**
338
+ * Get the AI SDK provider registry
339
+ * Used for standard providers that use createProviderRegistry
340
+ */
341
+ getAiSdkRegistry(): ProviderRegistryProvider {
342
+ if (!this.aiSdkRegistry) {
343
+ throw new Error("ProviderRegistry not initialized. Call initialize() first.");
344
+ }
345
+ return this.aiSdkRegistry;
346
+ }
347
+
348
+ /**
349
+ * Create a model from a provider
350
+ */
351
+ createModel(
352
+ providerId: string,
353
+ modelId: string,
354
+ context?: ProviderRuntimeContext
355
+ ): ProviderModelResult {
356
+ // In mock mode, always use mock provider
357
+ const actualProviderId = process.env.USE_MOCK_LLM === "true" ? "mock" : providerId;
358
+
359
+ const provider = this.providers.get(actualProviderId);
360
+
361
+ if (!provider) {
362
+ const available = Array.from(this.providers.keys());
363
+ throw new Error(
364
+ `Provider "${actualProviderId}" not available. ` +
365
+ `Initialized providers: ${available.length > 0 ? available.join(", ") : "none"}`
366
+ );
367
+ }
368
+
369
+ return provider.createModel(modelId, context);
370
+ }
371
+
372
+ /**
373
+ * Get all available providers
374
+ */
375
+ getAvailableProviders(): ProviderMetadata[] {
376
+ return Array.from(this.providers.values())
377
+ .filter(p => p.isAvailable())
378
+ .map(p => p.metadata);
379
+ }
380
+
381
+ /**
382
+ * Get all registered providers (even if not initialized)
383
+ */
384
+ getRegisteredProviders(): ProviderMetadata[] {
385
+ return Array.from(this.registrations.values()).map(r => r.metadata);
386
+ }
387
+
388
+ /**
389
+ * Check if the registry is initialized
390
+ */
391
+ isInitialized(): boolean {
392
+ return this.initialized;
393
+ }
394
+
395
+ /**
396
+ * Reset the registry
397
+ */
398
+ reset(): void {
399
+ for (const provider of this.providers.values()) {
400
+ provider.reset();
401
+ }
402
+ this.providers.clear();
403
+ this.providerConfigs.clear();
404
+ this.activeApiKeys.clear();
405
+ this.aiSdkRegistry = null;
406
+ this.initialized = false;
407
+ keyManager.reset();
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Export singleton instance
413
+ */
414
+ export const providerRegistry = ProviderRegistry.getInstance();
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Provider Registry Index
3
+ *
4
+ * Exports the provider registry and related utilities.
5
+ */
6
+
7
+ export { ProviderRegistry, providerRegistry } from "./ProviderRegistry";
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Anthropic Provider
3
+ *
4
+ * Direct access to Anthropic's Claude models.
5
+ * Supports both API keys (sk-ant-api*) and OAuth setup-tokens (sk-ant-oat*)
6
+ * from `claude setup-token` for Claude Code Max subscription auth.
7
+ *
8
+ * https://www.anthropic.com/
9
+ */
10
+
11
+ import { createAnthropic } from "@ai-sdk/anthropic";
12
+ import { logger } from "@/utils/logger";
13
+ import type { ProviderInitConfig, ProviderMetadata } from "../types";
14
+ import { StandardProvider } from "../base/StandardProvider";
15
+ import { PROVIDER_IDS } from "../provider-ids";
16
+
17
+ /**
18
+ * Beta headers required when using OAuth setup-tokens.
19
+ * Without these, Anthropic rejects OAuth Bearer auth with 401.
20
+ */
21
+ const OAUTH_BETAS = [
22
+ "claude-code-20250219",
23
+ "oauth-2025-04-20",
24
+ ];
25
+
26
+ function isOAuthToken(key: string): boolean {
27
+ return key.startsWith("sk-ant-oat");
28
+ }
29
+
30
+ /**
31
+ * Anthropic provider implementation
32
+ */
33
+ export class AnthropicProvider extends StandardProvider {
34
+ static readonly METADATA: ProviderMetadata = StandardProvider.createMetadata(
35
+ PROVIDER_IDS.ANTHROPIC,
36
+ "Anthropic",
37
+ "Direct access to Claude models",
38
+ "standard",
39
+ "claude-sonnet-4-20250514",
40
+ {
41
+ streaming: true,
42
+ toolCalling: true,
43
+ requiresApiKey: true,
44
+ },
45
+ "https://docs.anthropic.com/"
46
+ );
47
+
48
+ get metadata(): ProviderMetadata {
49
+ return AnthropicProvider.METADATA;
50
+ }
51
+
52
+ protected createProviderInstance(config: ProviderInitConfig): unknown {
53
+ if (!config.apiKey) {
54
+ throw new Error("Anthropic requires an API key or setup-token");
55
+ }
56
+
57
+ if (isOAuthToken(config.apiKey)) {
58
+ logger.info("[AnthropicProvider] Using OAuth setup-token auth (Claude Code Max subscription)");
59
+ return createAnthropic({
60
+ authToken: config.apiKey,
61
+ headers: {
62
+ "anthropic-beta": OAUTH_BETAS.join(","),
63
+ },
64
+ });
65
+ }
66
+
67
+ return createAnthropic({
68
+ apiKey: config.apiKey,
69
+ });
70
+ }
71
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Ollama Provider
3
+ *
4
+ * Run open-source LLMs locally with Ollama.
5
+ * https://ollama.ai/
6
+ */
7
+
8
+ import { createOllama } from "ollama-ai-provider-v2";
9
+ import type { ProviderInitConfig, ProviderMetadata } from "../types";
10
+ import { StandardProvider } from "../base/StandardProvider";
11
+ import { PROVIDER_IDS } from "../provider-ids";
12
+
13
+ /**
14
+ * Ollama provider implementation
15
+ */
16
+ export class OllamaProvider extends StandardProvider {
17
+ static readonly METADATA: ProviderMetadata = StandardProvider.createMetadata(
18
+ PROVIDER_IDS.OLLAMA,
19
+ "Ollama",
20
+ "Run open-source LLMs locally",
21
+ "standard",
22
+ "llama3.1:8b",
23
+ {
24
+ streaming: true,
25
+ toolCalling: true,
26
+ requiresApiKey: false, // Ollama uses a base URL instead of API key
27
+ },
28
+ "https://ollama.ai/"
29
+ );
30
+
31
+ get metadata(): ProviderMetadata {
32
+ return OllamaProvider.METADATA;
33
+ }
34
+
35
+ protected createProviderInstance(config: ProviderInitConfig): unknown {
36
+ // For Ollama, apiKey is actually the base URL
37
+ // The library expects the URL to include /api path
38
+ let baseURL: string | undefined;
39
+
40
+ if (!config.apiKey || config.apiKey === "local") {
41
+ // Use default (library provides http://127.0.0.1:11434/api)
42
+ baseURL = undefined;
43
+ } else {
44
+ // Custom URL - ensure it ends with /api
45
+ baseURL = config.apiKey.endsWith("/api")
46
+ ? config.apiKey
47
+ : `${config.apiKey.replace(/\/$/, "")}/api`;
48
+ }
49
+
50
+ return createOllama(baseURL ? { baseURL } : undefined);
51
+ }
52
+
53
+ /**
54
+ * Ollama is available if initialized (no API key required)
55
+ */
56
+ isAvailable(): boolean {
57
+ return this._initialized;
58
+ }
59
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * OpenAI Provider
3
+ *
4
+ * Direct access to OpenAI's GPT models.
5
+ * https://openai.com/
6
+ */
7
+
8
+ import { createOpenAI } from "@ai-sdk/openai";
9
+ import type { ProviderInitConfig, ProviderMetadata } from "../types";
10
+ import { StandardProvider } from "../base/StandardProvider";
11
+ import { PROVIDER_IDS } from "../provider-ids";
12
+
13
+ /**
14
+ * OpenAI provider implementation
15
+ */
16
+ export class OpenAIProvider extends StandardProvider {
17
+ static readonly METADATA: ProviderMetadata = StandardProvider.createMetadata(
18
+ PROVIDER_IDS.OPENAI,
19
+ "OpenAI",
20
+ "Direct access to GPT models",
21
+ "standard",
22
+ "gpt-4",
23
+ {
24
+ streaming: true,
25
+ toolCalling: true,
26
+ requiresApiKey: true,
27
+ },
28
+ "https://platform.openai.com/docs/"
29
+ );
30
+
31
+ get metadata(): ProviderMetadata {
32
+ return OpenAIProvider.METADATA;
33
+ }
34
+
35
+ protected createProviderInstance(config: ProviderInitConfig): unknown {
36
+ if (!config.apiKey) {
37
+ throw new Error("OpenAI requires an API key");
38
+ }
39
+
40
+ return createOpenAI({
41
+ apiKey: config.apiKey,
42
+ });
43
+ }
44
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * OpenRouter Provider
3
+ *
4
+ * OpenRouter provides access to multiple AI models through a single API.
5
+ * https://openrouter.ai/
6
+ */
7
+
8
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
9
+ import type { LanguageModelUsage } from "ai";
10
+ import type { LanguageModelUsageWithCostUsd } from "../../types";
11
+ import type { ProviderInitConfig, ProviderMetadata } from "../types";
12
+ import { StandardProvider } from "../base/StandardProvider";
13
+ import { PROVIDER_IDS } from "../provider-ids";
14
+
15
+ /**
16
+ * OpenRouter-specific metadata structure
17
+ */
18
+ interface OpenRouterProviderMetadata {
19
+ id?: string;
20
+ usage?: {
21
+ cost?: number;
22
+ promptTokens?: number;
23
+ completionTokens?: number;
24
+ totalTokens?: number;
25
+ promptTokensDetails?: { cachedTokens?: number };
26
+ completionTokensDetails?: { reasoningTokens?: number };
27
+ };
28
+ }
29
+
30
+ /**
31
+ * OpenRouter provider implementation
32
+ */
33
+ export class OpenRouterProvider extends StandardProvider {
34
+ static readonly METADATA: ProviderMetadata = StandardProvider.createMetadata(
35
+ PROVIDER_IDS.OPENROUTER,
36
+ "OpenRouter",
37
+ "Access multiple AI models through a single API",
38
+ "standard",
39
+ "openai/gpt-4",
40
+ {
41
+ streaming: true,
42
+ toolCalling: true,
43
+ requiresApiKey: true,
44
+ },
45
+ "https://openrouter.ai/docs"
46
+ );
47
+
48
+ get metadata(): ProviderMetadata {
49
+ return OpenRouterProvider.METADATA;
50
+ }
51
+
52
+ protected createProviderInstance(config: ProviderInitConfig): unknown {
53
+ if (!config.apiKey) {
54
+ throw new Error("OpenRouter requires an API key");
55
+ }
56
+
57
+ return createOpenRouter({
58
+ apiKey: config.apiKey,
59
+ headers: {
60
+ "X-Title": "TENEX",
61
+ "HTTP-Referer": "https://tenex.chat/",
62
+ },
63
+ });
64
+ }
65
+
66
+ /**
67
+ * Extract usage metadata from OpenRouter provider response
68
+ */
69
+ static extractUsageMetadata(
70
+ model: string,
71
+ totalUsage: LanguageModelUsage | undefined,
72
+ providerMetadata: Record<string, unknown> | undefined
73
+ ): LanguageModelUsageWithCostUsd {
74
+ const metadata = providerMetadata?.openrouter as OpenRouterProviderMetadata | undefined;
75
+ const usage = metadata?.usage;
76
+
77
+ const inputTokens = usage?.promptTokens ?? totalUsage?.inputTokens;
78
+ const outputTokens = usage?.completionTokens ?? totalUsage?.outputTokens;
79
+ const totalTokens = usage?.totalTokens ??
80
+ (inputTokens !== undefined && outputTokens !== undefined
81
+ ? inputTokens + outputTokens
82
+ : undefined);
83
+
84
+ return {
85
+ model,
86
+ inputTokens,
87
+ outputTokens,
88
+ totalTokens,
89
+ costUsd: usage?.cost,
90
+ cachedInputTokens: usage?.promptTokensDetails?.cachedTokens,
91
+ reasoningTokens: usage?.completionTokensDetails?.reasoningTokens,
92
+ } as LanguageModelUsageWithCostUsd;
93
+ }
94
+
95
+ /**
96
+ * Extract OpenRouter generation ID for trace correlation
97
+ */
98
+ static extractGenerationId(
99
+ providerMetadata: Record<string, unknown> | undefined
100
+ ): string | undefined {
101
+ return (providerMetadata?.openrouter as OpenRouterProviderMetadata | undefined)?.id;
102
+ }
103
+ }