@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,411 @@
1
+ import type { ToolExecutionContext } from "@/tools/types";
2
+ import { getProjectContext } from "@/services/projects";
3
+ import { getPubkeyService } from "@/services/PubkeyService";
4
+ import type { AISdkTool } from "@/tools/types";
5
+ import { logger } from "@/utils/logger";
6
+ import { createEventContext } from "@/services/event-context";
7
+ import { resolveRecipientToPubkey, resolveEscalationTarget } from "@/services/agents";
8
+ import { ConversationStore } from "@/conversations/ConversationStore";
9
+ import { wouldCreateCircularDelegation } from "@/utils/delegation-chain";
10
+ import { tool } from "ai";
11
+ import { z } from "zod";
12
+ import { RALRegistry } from "@/services/ral";
13
+ import type { PendingDelegation } from "@/services/ral/types";
14
+ import { APNsService } from "@/services/apns";
15
+ import { streamPublisher } from "@/llm";
16
+
17
+ /**
18
+ * Schema for a single-select question.
19
+ * User picks one option from suggestions, or provides their own answer.
20
+ */
21
+ const singleSelectQuestionSchema = z.object({
22
+ type: z.literal("question"),
23
+ title: z.string().describe("Short title for the question (displayed as header, max 12 chars recommended)"),
24
+ question: z.string().describe("Full question text with all necessary context"),
25
+ suggestions: z.array(z.string()).optional().describe(
26
+ "Optional suggestions for single-select. If you recommend a specific option, make it the first in the list and add '(Recommended)' suffix. Omit for fully open-ended questions."
27
+ ),
28
+ });
29
+
30
+ /**
31
+ * Schema for a multi-select question.
32
+ * User can pick multiple options, or provide their own answer.
33
+ */
34
+ const multiSelectQuestionSchema = z.object({
35
+ type: z.literal("multiselect"),
36
+ title: z.string().describe("Short title for the question (displayed as header, max 12 chars recommended)"),
37
+ question: z.string().describe("Full question text with all necessary context"),
38
+ options: z.array(z.string()).optional().describe(
39
+ "Optional options for multi-select. User can select multiple. Omit for fully open-ended questions."
40
+ ),
41
+ });
42
+
43
+ /**
44
+ * Union schema for all question types.
45
+ */
46
+ const questionSchema = z.discriminatedUnion("type", [
47
+ singleSelectQuestionSchema,
48
+ multiSelectQuestionSchema,
49
+ ]);
50
+
51
+ /**
52
+ * Main schema for the ask tool.
53
+ * Supports multiple questions of different types in a single ask event.
54
+ */
55
+ const askSchema = z.object({
56
+ title: z.string().describe(
57
+ "A brief title that encompasses all questions being asked (3-5 words). This helps the user quickly understand the topic at a glance."
58
+ ),
59
+ context: z.string().describe(
60
+ "Background information the user needs to understand and answer the questions. " +
61
+ "CRITICAL: The user has NO access to your conversation history - include ALL relevant details, " +
62
+ "prior decisions, constraints, and reasoning. Be comprehensive but concise. " +
63
+ "DO NOT include the questions themselves in this field - questions go ONLY in the 'questions' array below. " +
64
+ "This field is for context/background ONLY."
65
+ ),
66
+ questions: z.array(questionSchema).min(1).describe(
67
+ "Array of questions to ask. Use 'question' type for single-select, 'multiselect' type for multi-select. " +
68
+ "Can mix types. Keep to 1-4 questions per ask event. " +
69
+ "Questions are rendered separately from the context - do NOT duplicate them in the context field."
70
+ ),
71
+ });
72
+
73
+ type AskInput = z.infer<typeof askSchema>;
74
+
75
+ interface AskOutput {
76
+ success: boolean;
77
+ message: string;
78
+ delegationConversationId: string;
79
+ }
80
+
81
+ /**
82
+ * Helper: Format questions with their full details for escalation prompt
83
+ */
84
+ function formatQuestions(questions: AskInput["questions"]): string {
85
+ return questions.map((q, idx) => {
86
+ let formatted = `${idx + 1}. [${q.type}] ${q.title}\n Question: ${q.question}\n`;
87
+ if (q.type === "question" && q.suggestions) {
88
+ formatted += ` Suggestions: ${q.suggestions.join(", ")}\n`;
89
+ } else if (q.type === "multiselect" && q.options) {
90
+ formatted += ` Options: ${q.options.join(", ")}\n`;
91
+ } else {
92
+ formatted += ` Type: Open-ended\n`;
93
+ }
94
+ return formatted;
95
+ }).join("\n");
96
+ }
97
+
98
+ /**
99
+ * Helper: Build escalation prompt for delegating ask to escalation agent
100
+ */
101
+ function buildEscalationPrompt(
102
+ input: AskInput,
103
+ context: ToolExecutionContext,
104
+ agentRole: string,
105
+ delegationChain?: Array<{ displayName: string; pubkey: string }>
106
+ ): string {
107
+ const { title, context: askContext, questions } = input;
108
+
109
+ let chainDisplay = "";
110
+ if (delegationChain && delegationChain.length > 0) {
111
+ chainDisplay = `\n## Delegation Chain\n${delegationChain.map(e => `- ${e.displayName} (${e.pubkey.substring(0, 8)})`).join("\n")}\n`;
112
+ }
113
+
114
+ const formattedQuestions = formatQuestions(questions);
115
+
116
+ return `# Question Escalation Request
117
+
118
+ ## Source
119
+ - Agent: ${context.agent.slug}
120
+ - Role: ${agentRole}
121
+ - Conversation: ${context.conversationId}
122
+ ${chainDisplay}
123
+ ## Questions Requiring Response
124
+
125
+ ### ${title}
126
+ **Context:**
127
+ ${askContext}
128
+
129
+ **Questions:**
130
+ ${formattedQuestions}
131
+
132
+ ## Your Task
133
+ You are acting as the project owner's proxy. Either:
134
+ 1. Answer directly if you can make the decision
135
+ 2. Use ask() to escalate to the actual human if you need their input
136
+
137
+ When responding, provide your answers in a clear format that addresses each question.`;
138
+ }
139
+
140
+ /**
141
+ * Helper: Build prompt summary for delegation tracking
142
+ */
143
+ function buildPromptSummary(input: AskInput): string {
144
+ const { title, context: askContext, questions } = input;
145
+ const questionSummary = questions.map(q => `[${q.title}] ${q.question}`).join("\n");
146
+ return `${title}\n\n${askContext}\n\n---\n\n${questionSummary}`;
147
+ }
148
+
149
+ /**
150
+ * Helper: Get escalation target (agent slug) from config, with validation and auto-add
151
+ *
152
+ * Delegates to EscalationService which handles:
153
+ * - Config reading
154
+ * - Project membership checks
155
+ * - Auto-adding from global storage if needed
156
+ *
157
+ * Returns null if no escalation agent configured, config not loaded, or agent doesn't exist
158
+ */
159
+ async function getEscalationTarget(): Promise<string | null> {
160
+ const result = await resolveEscalationTarget();
161
+ return result?.slug ?? null;
162
+ }
163
+
164
+ async function executeAsk(input: AskInput, context: ToolExecutionContext): Promise<AskOutput> {
165
+ const { title, context: askContext, questions } = input;
166
+
167
+ const projectCtx = getProjectContext();
168
+ const ownerPubkey = projectCtx?.project?.pubkey;
169
+
170
+ if (!ownerPubkey) {
171
+ throw new Error("No project owner configured - cannot determine who to ask");
172
+ }
173
+
174
+ // Check for escalation agent configuration using helper
175
+ // This will auto-add the agent to the project if it exists in storage but not in project
176
+ const escalationAgentSlug = await getEscalationTarget();
177
+
178
+ // If escalation agent is configured AND current agent is not the escalation agent,
179
+ // route through escalation agent instead of directly to user
180
+ if (escalationAgentSlug && context.agent.slug !== escalationAgentSlug) {
181
+ const escalationAgentPubkey = resolveRecipientToPubkey(escalationAgentSlug);
182
+
183
+ if (!escalationAgentPubkey) {
184
+ // This shouldn't happen since getEscalationTarget() validates it,
185
+ // but handle gracefully just in case
186
+ logger.warn("[ask] Escalation agent not found, falling back to direct ask", {
187
+ escalationAgentSlug,
188
+ fromAgent: context.agent.slug,
189
+ });
190
+ // Fall through to normal ask flow
191
+ } else {
192
+ // Get delegation chain for circular delegation check
193
+ const conversationStore = ConversationStore.get(context.conversationId);
194
+ const delegationChain = conversationStore?.metadata?.delegationChain;
195
+
196
+ // Check for circular delegation using stored chain
197
+ if (delegationChain && wouldCreateCircularDelegation(delegationChain, escalationAgentPubkey)) {
198
+ const chainDisplay = delegationChain.map(e => e.displayName).join(" → ");
199
+
200
+ logger.warn("[ask] Circular delegation detected, falling back to direct ask", {
201
+ escalationAgent: escalationAgentSlug,
202
+ targetPubkey: escalationAgentPubkey.substring(0, 8),
203
+ chain: chainDisplay,
204
+ });
205
+
206
+ // Fall through to normal ask flow instead of throwing
207
+ // This allows the question to still be asked directly to the user
208
+ } else {
209
+ // Route through escalation agent
210
+ logger.info("[ask] Routing ask through escalation agent", {
211
+ fromAgent: context.agent.slug,
212
+ escalationAgent: escalationAgentSlug,
213
+ toUser: ownerPubkey.substring(0, 8),
214
+ questionCount: questions.length,
215
+ });
216
+
217
+ // Get full agent info for role
218
+ const fullAgent = projectCtx.getAgentByPubkey(context.agent.pubkey);
219
+ const agentRole = fullAgent?.role || "N/A";
220
+
221
+ // Build escalation prompt using helper
222
+ const escalationPrompt = buildEscalationPrompt(input, context, agentRole, delegationChain);
223
+
224
+ // Delegate to escalation agent
225
+ const eventContext = createEventContext(context);
226
+ const eventId = await context.agentPublisher.delegate({
227
+ recipient: escalationAgentPubkey,
228
+ content: escalationPrompt,
229
+ }, eventContext);
230
+
231
+ // Build prompt summary for delegation tracking using helper
232
+ const promptSummary = buildPromptSummary(input);
233
+
234
+ // Register delegation immediately (like delegate() does)
235
+ const pendingDelegations: PendingDelegation[] = [
236
+ {
237
+ type: "ask" as const,
238
+ delegationConversationId: eventId,
239
+ recipientPubkey: escalationAgentPubkey,
240
+ senderPubkey: context.agent.pubkey,
241
+ prompt: promptSummary,
242
+ ralNumber: context.ralNumber,
243
+ },
244
+ ];
245
+
246
+ RALRegistry.getInstance().mergePendingDelegations(
247
+ context.agent.pubkey,
248
+ context.conversationId,
249
+ context.ralNumber,
250
+ pendingDelegations
251
+ );
252
+
253
+ const conversationStore = ConversationStore.get(context.conversationId);
254
+ if (conversationStore) {
255
+ conversationStore.save();
256
+ }
257
+
258
+ return {
259
+ success: true,
260
+ message: "Question sent, waiting for response",
261
+ delegationConversationId: eventId,
262
+ };
263
+ }
264
+ }
265
+ }
266
+
267
+ // Get human-readable name for the recipient
268
+ const pubkeyService = getPubkeyService();
269
+ const recipientName = await pubkeyService.getName(ownerPubkey);
270
+
271
+ logger.info("[ask] Publishing ask event", {
272
+ fromAgent: context.agent.slug,
273
+ toUser: recipientName,
274
+ toUserPubkey: ownerPubkey.substring(0, 8),
275
+ questionCount: questions.length,
276
+ questionTypes: questions.map(q => q.type),
277
+ });
278
+
279
+ const eventContext = createEventContext(context);
280
+ const askEvent = await context.agentPublisher.ask(
281
+ {
282
+ recipient: ownerPubkey,
283
+ title,
284
+ context: askContext,
285
+ questions,
286
+ },
287
+ eventContext
288
+ );
289
+ const eventId = askEvent.id;
290
+
291
+ // Bug fix: Create ConversationStore for ask conversations to enable transcript retrieval
292
+ // See: naddr1qvzqqqr4gupzqkmm302xww6uyne99rnhl5kjj53wthjypm2qaem9uz9fdf3hzcf0qyghwumn8ghj7ar9dejhstnrdpshgtcqye382emxd9uz6ctndvkhgmm0dskhgunpdeekxunfwp6z6atwv9mxz6tvv93xceg8tzuz2
293
+ try {
294
+ await ConversationStore.create(askEvent);
295
+ } catch (error) {
296
+ // Don't fail the ask tool if transcript storage fails.
297
+ // The ask functionality still works - the delegation is already registered
298
+ // via agentPublisher.ask(). The user will get their question and can respond.
299
+ // Only transcript retrieval will be affected if this fails.
300
+ logger.warn("[ask] Failed to create ConversationStore for ask transcript", {
301
+ eventId: eventId.substring(0, 8),
302
+ error: error instanceof Error ? error.message : String(error),
303
+ });
304
+ }
305
+
306
+ // Send APNs push notification if user is not connected
307
+ try {
308
+ const apnsService = APNsService.getInstance();
309
+ if (apnsService.isEnabled() && !streamPublisher.isConnected()) {
310
+ const bodyPreview = askContext.length > 100 ? askContext.substring(0, 100) + "…" : askContext;
311
+ await apnsService.notifyIfNeeded(ownerPubkey, {
312
+ title: "Agent needs your input",
313
+ body: bodyPreview,
314
+ conversationId: context.conversationId,
315
+ eventId,
316
+ });
317
+ }
318
+ } catch (error) {
319
+ // Don't fail the ask tool if push notification fails
320
+ logger.warn("[ask] Failed to send APNs notification", {
321
+ error: error instanceof Error ? error.message : String(error),
322
+ });
323
+ }
324
+
325
+ // Build prompt summary for delegation tracking using helper
326
+ const promptSummary = buildPromptSummary(input);
327
+
328
+ // Register delegation immediately (like delegate() does)
329
+ const pendingDelegations: PendingDelegation[] = [
330
+ {
331
+ type: "ask" as const,
332
+ delegationConversationId: eventId,
333
+ recipientPubkey: ownerPubkey,
334
+ senderPubkey: context.agent.pubkey,
335
+ prompt: promptSummary,
336
+ ralNumber: context.ralNumber,
337
+ },
338
+ ];
339
+
340
+ RALRegistry.getInstance().mergePendingDelegations(
341
+ context.agent.pubkey,
342
+ context.conversationId,
343
+ context.ralNumber,
344
+ pendingDelegations
345
+ );
346
+
347
+ const conversationStore = ConversationStore.get(context.conversationId);
348
+ if (conversationStore) {
349
+ conversationStore.save();
350
+ }
351
+
352
+ return {
353
+ success: true,
354
+ message: "Question sent, waiting for response",
355
+ delegationConversationId: eventId,
356
+ };
357
+ }
358
+
359
+ export function createAskTool(context: ToolExecutionContext): AISdkTool {
360
+ const aiTool = tool({
361
+ description: `Ask questions to a human user (the project owner) and wait for their response.
362
+
363
+ PURPOSE: Use this tool ONLY to ask questions to humans. Do NOT use it for any other purpose.
364
+
365
+ When to use:
366
+ 1. Gather user preferences or requirements
367
+ 2. Clarify ambiguous instructions
368
+ 3. Get decisions on implementation choices
369
+ 4. Offer choices about what direction to take
370
+
371
+ CRITICAL - Structure your input correctly:
372
+ - "context": Background information ONLY. Do NOT put questions here.
373
+ - "questions": Array of actual questions. Questions are rendered separately by the UI.
374
+
375
+ BAD example (questions in context):
376
+ context: "I found X and Y. Which do you prefer? Also, should I use Z?"
377
+ questions: [...]
378
+
379
+ GOOD example (context is just background):
380
+ context: "I found X and Y while investigating the issue. Here's what each does: ..."
381
+ questions: [{type: "question", title: "Preference", question: "Which approach do you prefer?", suggestions: ["X", "Y"]}]
382
+
383
+ The user sees the context field as explanatory text, then sees each question rendered as a separate UI element.
384
+ DO NOT duplicate questions in the context - they will appear twice to the user.
385
+
386
+ Question types:
387
+ - "question": Single-select. User picks one option or provides their own answer.
388
+ - "multiselect": Multi-select. User can pick multiple options.
389
+
390
+ Tips:
391
+ - If you recommend an option, make it first and add "(Recommended)" suffix
392
+ - Keep titles short (max 12 chars) for clean display
393
+ - Group related questions in a single ask event (1-4 questions)
394
+ - The user has NO access to your conversation history - include all relevant context`,
395
+ inputSchema: askSchema,
396
+ execute: async (input: AskInput) => {
397
+ return await executeAsk(input, context);
398
+ },
399
+ });
400
+
401
+ Object.defineProperty(aiTool, "getHumanReadableContent", {
402
+ value: ({ title, questions }: AskInput) => {
403
+ const questionSummary = questions.map(q => q.title).join(", ");
404
+ return `Asking: "${title}" [${questionSummary}]`;
405
+ },
406
+ enumerable: false,
407
+ configurable: true,
408
+ });
409
+
410
+ return aiTool as AISdkTool;
411
+ }
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Change Model Tool - Dynamic model selection for meta model agents
3
+ *
4
+ * Allows agents using a meta model configuration to switch between
5
+ * variants on-the-fly during a conversation.
6
+ */
7
+
8
+ import type { ConversationToolContext } from "@/tools/types";
9
+ import type { AISdkTool } from "@/tools/types";
10
+ import { config as configService } from "@/services/ConfigService";
11
+ import { isMetaModelConfiguration, type MetaModelConfiguration } from "@/services/config/types";
12
+ import { tool } from "ai";
13
+ import { z } from "zod";
14
+
15
+ const changeModelSchema = z.object({
16
+ variant: z
17
+ .string()
18
+ .describe("The name of the variant to switch to (e.g., 'fast', 'deep', 'standard')"),
19
+ });
20
+
21
+ type ChangeModelInput = z.infer<typeof changeModelSchema>;
22
+
23
+ interface ChangeModelOutput {
24
+ success: boolean;
25
+ message: string;
26
+ previousVariant?: string;
27
+ newVariant: string;
28
+ modelConfig?: string;
29
+ }
30
+
31
+ /**
32
+ * Get the meta model configuration for an agent if available
33
+ */
34
+ function getAgentMetaModelConfig(agentLlmConfig?: string): MetaModelConfiguration | undefined {
35
+ try {
36
+ const rawConfig = configService.getRawLLMConfig(agentLlmConfig);
37
+ if (isMetaModelConfiguration(rawConfig)) {
38
+ return rawConfig;
39
+ }
40
+ } catch {
41
+ // Config not available or not a meta model
42
+ }
43
+ return undefined;
44
+ }
45
+
46
+ async function executeChangeModel(
47
+ input: ChangeModelInput,
48
+ context: ConversationToolContext
49
+ ): Promise<ChangeModelOutput> {
50
+ const { variant } = input;
51
+ const conversation = context.getConversation();
52
+ const agentPubkey = context.agent.pubkey;
53
+
54
+ // Get the meta model configuration for this agent
55
+ const metaConfig = getAgentMetaModelConfig(context.agent.llmConfig);
56
+
57
+ if (!metaConfig) {
58
+ return {
59
+ success: false,
60
+ message: "This agent is not using a meta model configuration. Model switching is not available.",
61
+ newVariant: variant,
62
+ };
63
+ }
64
+
65
+ // Validate the variant exists
66
+ if (!metaConfig.variants[variant]) {
67
+ const availableVariants = Object.keys(metaConfig.variants);
68
+ return {
69
+ success: false,
70
+ message: `Unknown variant "${variant}". Available variants: ${availableVariants.join(", ")}`,
71
+ newVariant: variant,
72
+ };
73
+ }
74
+
75
+ // Get previous variant (if any)
76
+ const previousVariant = conversation.getMetaModelVariantOverride(agentPubkey);
77
+
78
+ // Set the new variant override
79
+ conversation.setMetaModelVariantOverride(agentPubkey, variant);
80
+
81
+ // Get info about the new variant
82
+ const variantConfig = metaConfig.variants[variant];
83
+ const modelConfig = variantConfig.model;
84
+
85
+ return {
86
+ success: true,
87
+ message: `Switched to "${variant}" variant. The new model is now active and will be used starting from the next step in this run.`,
88
+ previousVariant: previousVariant || metaConfig.default,
89
+ newVariant: variant,
90
+ modelConfig,
91
+ };
92
+ }
93
+
94
+ /**
95
+ * Create the change_model tool for agents using meta model configurations.
96
+ * This tool is automatically injected when an agent is configured with a meta model.
97
+ */
98
+ export function createChangeModelTool(context: ConversationToolContext): AISdkTool {
99
+ // Get the meta model config to build the description dynamically
100
+ const metaConfig = getAgentMetaModelConfig(context.agent.llmConfig);
101
+
102
+ // Build variant descriptions for the tool
103
+ let variantDescriptions = "";
104
+ if (metaConfig) {
105
+ const variants = Object.entries(metaConfig.variants)
106
+ .map(([name, v]) => {
107
+ const desc = v.description ? `: ${v.description}` : "";
108
+ const isDefault = name === metaConfig.default ? " [default]" : "";
109
+ return ` - ${name}${desc}${isDefault}`;
110
+ })
111
+ .join("\n");
112
+ variantDescriptions = `\n\nAvailable variants:\n${variants}`;
113
+ }
114
+
115
+ const aiTool = tool({
116
+ description:
117
+ "Switch to a different model variant for the rest of this conversation. " +
118
+ `Use this when you determine a different capability level is needed for the current task.${variantDescriptions}`,
119
+ inputSchema: changeModelSchema,
120
+ execute: async (input: ChangeModelInput) => {
121
+ return await executeChangeModel(input, context);
122
+ },
123
+ });
124
+
125
+ Object.defineProperty(aiTool, "getHumanReadableContent", {
126
+ value: ({ variant }: ChangeModelInput) => {
127
+ return `Switching to model variant: ${variant}`;
128
+ },
129
+ enumerable: false,
130
+ configurable: true,
131
+ });
132
+
133
+ // Mark as having side effects (changes conversation state)
134
+ Object.defineProperty(aiTool, "hasSideEffects", {
135
+ value: true,
136
+ enumerable: false,
137
+ configurable: true,
138
+ });
139
+
140
+ return aiTool as AISdkTool;
141
+ }