@within-7/minto 0.3.10 → 0.4.0

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 (306) hide show
  1. package/dist/Tool.js.map +2 -2
  2. package/dist/commands/agents/AgentsCommand.js +2 -2
  3. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  4. package/dist/commands/ctx_viz.js +1 -1
  5. package/dist/commands/effort.js +87 -0
  6. package/dist/commands/effort.js.map +7 -0
  7. package/dist/commands/export.js +19 -9
  8. package/dist/commands/export.js.map +2 -2
  9. package/dist/commands/ide.js +18 -0
  10. package/dist/commands/ide.js.map +7 -0
  11. package/dist/commands/mcp-interactive.js +14 -8
  12. package/dist/commands/mcp-interactive.js.map +2 -2
  13. package/dist/commands/memory.js +168 -0
  14. package/dist/commands/memory.js.map +7 -0
  15. package/dist/commands/model.js +45 -2
  16. package/dist/commands/model.js.map +2 -2
  17. package/dist/commands/outputStyle.js +64 -0
  18. package/dist/commands/outputStyle.js.map +7 -0
  19. package/dist/commands/plugin/utils.js +33 -1
  20. package/dist/commands/plugin/utils.js.map +2 -2
  21. package/dist/commands/plugin.js +10 -1
  22. package/dist/commands/plugin.js.map +2 -2
  23. package/dist/commands/refreshCommands.js +2 -0
  24. package/dist/commands/refreshCommands.js.map +2 -2
  25. package/dist/commands/review.js +51 -0
  26. package/dist/commands/review.js.map +7 -0
  27. package/dist/commands/terminalSetup.js +6 -0
  28. package/dist/commands/terminalSetup.js.map +2 -2
  29. package/dist/commands/undo.js +8 -0
  30. package/dist/commands/undo.js.map +2 -2
  31. package/dist/commands/vim.js +22 -0
  32. package/dist/commands/vim.js.map +7 -0
  33. package/dist/commands.js +12 -0
  34. package/dist/commands.js.map +2 -2
  35. package/dist/components/HighlightedCode.js +1 -0
  36. package/dist/components/HighlightedCode.js.map +2 -2
  37. package/dist/components/ModelSelector/ModelSelector.js +250 -143
  38. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  39. package/dist/components/PromptInput.js +21 -6
  40. package/dist/components/PromptInput.js.map +2 -2
  41. package/dist/components/PulseLabel.js +44 -0
  42. package/dist/components/PulseLabel.js.map +7 -0
  43. package/dist/components/RequestStatusIndicator.js +1 -1
  44. package/dist/components/RequestStatusIndicator.js.map +1 -1
  45. package/dist/components/Spinner.js +12 -42
  46. package/dist/components/Spinner.js.map +3 -3
  47. package/dist/components/StartupStatus.js +57 -0
  48. package/dist/components/StartupStatus.js.map +7 -0
  49. package/dist/components/SubagentBlock.js +43 -6
  50. package/dist/components/SubagentBlock.js.map +2 -2
  51. package/dist/components/TabbedListView/TabBar.js +13 -8
  52. package/dist/components/TabbedListView/TabBar.js.map +2 -2
  53. package/dist/components/TabbedListView/TabbedListView.js +1 -1
  54. package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
  55. package/dist/components/TodoPanel.js +1 -1
  56. package/dist/components/TodoPanel.js.map +1 -1
  57. package/dist/components/ToolUseLoader.js +5 -0
  58. package/dist/components/ToolUseLoader.js.map +2 -2
  59. package/dist/components/TrustDialog.js +0 -2
  60. package/dist/components/TrustDialog.js.map +2 -2
  61. package/dist/components/messages/TaskInModuleView.js +1 -1
  62. package/dist/components/messages/TaskInModuleView.js.map +2 -2
  63. package/dist/components/messages/TaskToolMessage.js +1 -1
  64. package/dist/components/messages/TaskToolMessage.js.map +2 -2
  65. package/dist/components/messages/UserPromptMessage.js +6 -1
  66. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  67. package/dist/constants/modelCapabilities.js +103 -18
  68. package/dist/constants/modelCapabilities.js.map +2 -2
  69. package/dist/constants/product.js +2 -0
  70. package/dist/constants/product.js.map +2 -2
  71. package/dist/constants/prompts/agentPrompt.js +30 -0
  72. package/dist/constants/prompts/agentPrompt.js.map +7 -0
  73. package/dist/constants/prompts/codeConventions.js +27 -0
  74. package/dist/constants/prompts/codeConventions.js.map +7 -0
  75. package/dist/constants/prompts/doingTasks.js +15 -0
  76. package/dist/constants/prompts/doingTasks.js.map +7 -0
  77. package/dist/constants/prompts/envInfo.js +17 -0
  78. package/dist/constants/prompts/envInfo.js.map +7 -0
  79. package/dist/constants/prompts/executingWithCare.js +17 -0
  80. package/dist/constants/prompts/executingWithCare.js.map +7 -0
  81. package/dist/constants/prompts/identity.js +10 -0
  82. package/dist/constants/prompts/identity.js.map +7 -0
  83. package/dist/constants/prompts/index.js +78 -0
  84. package/dist/constants/prompts/index.js.map +7 -0
  85. package/dist/constants/prompts/taskManagement.js +60 -0
  86. package/dist/constants/prompts/taskManagement.js.map +7 -0
  87. package/dist/constants/prompts/toneAndStyle.js +62 -0
  88. package/dist/constants/prompts/toneAndStyle.js.map +7 -0
  89. package/dist/constants/prompts/toolUsagePolicy.js +38 -0
  90. package/dist/constants/prompts/toolUsagePolicy.js.map +7 -0
  91. package/dist/constants/prompts.js +5 -176
  92. package/dist/constants/prompts.js.map +2 -2
  93. package/dist/constants/providerRegistry.js +235 -0
  94. package/dist/constants/providerRegistry.js.map +7 -0
  95. package/dist/constants/providers.js +35 -0
  96. package/dist/constants/providers.js.map +7 -0
  97. package/dist/context/PermissionContext.js +0 -1
  98. package/dist/context/PermissionContext.js.map +2 -2
  99. package/dist/context.js +87 -31
  100. package/dist/context.js.map +2 -2
  101. package/dist/core/backupHook.js +2 -2
  102. package/dist/core/backupHook.js.map +2 -2
  103. package/dist/core/config/defaults.js +4 -1
  104. package/dist/core/config/defaults.js.map +2 -2
  105. package/dist/core/config/schema.js +7 -1
  106. package/dist/core/config/schema.js.map +2 -2
  107. package/dist/core/costTracker.js +18 -0
  108. package/dist/core/costTracker.js.map +2 -2
  109. package/dist/core/index.js +0 -1
  110. package/dist/core/index.js.map +2 -2
  111. package/dist/core/tokenStatsManager.js +22 -4
  112. package/dist/core/tokenStatsManager.js.map +2 -2
  113. package/dist/entrypoints/cli.js +65 -84
  114. package/dist/entrypoints/cli.js.map +2 -2
  115. package/dist/hooks/useAgentTokenStats.js +1 -1
  116. package/dist/hooks/useAgentTokenStats.js.map +2 -2
  117. package/dist/hooks/useAgentTranscripts.js +2 -1
  118. package/dist/hooks/useAgentTranscripts.js.map +2 -2
  119. package/dist/hooks/useBackgroundShells.js +29 -0
  120. package/dist/hooks/useBackgroundShells.js.map +7 -0
  121. package/dist/hooks/useCanUseTool.js +1 -1
  122. package/dist/hooks/useCanUseTool.js.map +2 -2
  123. package/dist/hooks/useDeferredLoading.js +64 -0
  124. package/dist/hooks/useDeferredLoading.js.map +7 -0
  125. package/dist/hooks/useHookStatus.js +1 -1
  126. package/dist/hooks/useHookStatus.js.map +2 -2
  127. package/dist/hooks/useSessionTracking.js +55 -0
  128. package/dist/hooks/useSessionTracking.js.map +7 -0
  129. package/dist/hooks/useTerminalSize.js +21 -0
  130. package/dist/hooks/useTerminalSize.js.map +2 -2
  131. package/dist/hooks/useTextInput.js +1 -0
  132. package/dist/hooks/useTextInput.js.map +2 -2
  133. package/dist/hooks/useUnifiedCompletion.js +3 -2
  134. package/dist/hooks/useUnifiedCompletion.js.map +2 -2
  135. package/dist/i18n/locales/en.js +8 -9
  136. package/dist/i18n/locales/en.js.map +2 -2
  137. package/dist/i18n/locales/zh-CN.js +8 -9
  138. package/dist/i18n/locales/zh-CN.js.map +2 -2
  139. package/dist/i18n/types.js.map +1 -1
  140. package/dist/messages.js +41 -17
  141. package/dist/messages.js.map +2 -2
  142. package/dist/permissions.js +94 -1
  143. package/dist/permissions.js.map +2 -2
  144. package/dist/query.js +27 -19
  145. package/dist/query.js.map +2 -2
  146. package/dist/screens/REPL.js +83 -74
  147. package/dist/screens/REPL.js.map +2 -2
  148. package/dist/services/adapters/responsesAPI.js +6 -0
  149. package/dist/services/adapters/responsesAPI.js.map +2 -2
  150. package/dist/services/agentTeams/index.js +35 -0
  151. package/dist/services/agentTeams/index.js.map +7 -0
  152. package/dist/services/agentTeams/mailbox.js +114 -0
  153. package/dist/services/agentTeams/mailbox.js.map +7 -0
  154. package/dist/services/agentTeams/teamManager.js +149 -0
  155. package/dist/services/agentTeams/teamManager.js.map +7 -0
  156. package/dist/services/agentTeams/teamTaskStore.js +114 -0
  157. package/dist/services/agentTeams/teamTaskStore.js.map +7 -0
  158. package/dist/services/agentTeams/teammateSpawner.js +80 -0
  159. package/dist/services/agentTeams/teammateSpawner.js.map +7 -0
  160. package/dist/services/checkpointManager.js +16 -3
  161. package/dist/services/checkpointManager.js.map +2 -2
  162. package/dist/services/claude.js +19 -1728
  163. package/dist/services/claude.js.map +3 -3
  164. package/dist/services/gpt5ConnectionTest.js +4 -2
  165. package/dist/services/gpt5ConnectionTest.js.map +2 -2
  166. package/dist/services/hookExecutor.js +411 -127
  167. package/dist/services/hookExecutor.js.map +2 -2
  168. package/dist/services/llm/anthropicProvider.js +807 -0
  169. package/dist/services/llm/anthropicProvider.js.map +7 -0
  170. package/dist/services/llm/dispatch.js +218 -0
  171. package/dist/services/llm/dispatch.js.map +7 -0
  172. package/dist/services/llm/index.js +44 -0
  173. package/dist/services/llm/index.js.map +7 -0
  174. package/dist/services/llm/mintoContext.js +69 -0
  175. package/dist/services/llm/mintoContext.js.map +7 -0
  176. package/dist/services/llm/openaiProvider.js +622 -0
  177. package/dist/services/llm/openaiProvider.js.map +7 -0
  178. package/dist/services/llm/types.js +157 -0
  179. package/dist/services/llm/types.js.map +7 -0
  180. package/dist/services/mcpClient.js +183 -33
  181. package/dist/services/mcpClient.js.map +2 -2
  182. package/dist/services/notifier.js +14 -0
  183. package/dist/services/notifier.js.map +2 -2
  184. package/dist/services/oauth.js +4 -2
  185. package/dist/services/oauth.js.map +2 -2
  186. package/dist/services/openai.js +66 -56
  187. package/dist/services/openai.js.map +3 -3
  188. package/dist/services/outputStyles.js +102 -21
  189. package/dist/services/outputStyles.js.map +2 -2
  190. package/dist/services/plugins/skillMarketplace.js +4 -1
  191. package/dist/services/plugins/skillMarketplace.js.map +2 -2
  192. package/dist/services/sentry.js +1 -1
  193. package/dist/services/sentry.js.map +2 -2
  194. package/dist/services/sessionMemory.js +16 -3
  195. package/dist/services/sessionMemory.js.map +2 -2
  196. package/dist/services/systemReminder.js +350 -3
  197. package/dist/services/systemReminder.js.map +2 -2
  198. package/dist/services/taskStore.js +19 -0
  199. package/dist/services/taskStore.js.map +2 -2
  200. package/dist/tools/ArchitectTool/ArchitectTool.js.map +1 -1
  201. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +1 -1
  202. package/dist/tools/BashOutputTool/BashOutputTool.js.map +1 -1
  203. package/dist/tools/BashTool/BashTool.js +28 -0
  204. package/dist/tools/BashTool/BashTool.js.map +2 -2
  205. package/dist/tools/FileEditTool/FileEditTool.js +1 -1
  206. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  207. package/dist/tools/FileReadTool/FileReadTool.js +14 -0
  208. package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
  209. package/dist/tools/FileWriteTool/FileWriteTool.js +3 -1
  210. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  211. package/dist/tools/GlobTool/GlobTool.js.map +1 -1
  212. package/dist/tools/GrepTool/GrepTool.js.map +1 -1
  213. package/dist/tools/KillShellTool/KillShellTool.js.map +1 -1
  214. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
  215. package/dist/tools/LspTool/LspTool.js +11 -2
  216. package/dist/tools/LspTool/LspTool.js.map +2 -2
  217. package/dist/tools/MCPTool/MCPTool.js.map +1 -1
  218. package/dist/tools/MemoryReadTool/MemoryReadTool.js +2 -1
  219. package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +2 -2
  220. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +2 -1
  221. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +2 -2
  222. package/dist/tools/MultiEditTool/MultiEditTool.js.map +1 -1
  223. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +1 -1
  224. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +1 -1
  225. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +8 -2
  226. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
  227. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +2 -0
  228. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
  229. package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js.map +1 -1
  230. package/dist/tools/SlashCommandTool/SlashCommandTool.js +174 -18
  231. package/dist/tools/SlashCommandTool/SlashCommandTool.js.map +3 -3
  232. package/dist/tools/TaskCreateTool/TaskCreateTool.js.map +1 -1
  233. package/dist/tools/TaskGetTool/TaskGetTool.js.map +1 -1
  234. package/dist/tools/TaskListTool/TaskListTool.js.map +1 -1
  235. package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +1 -1
  236. package/dist/tools/TaskStopTool/TaskStopTool.js.map +1 -1
  237. package/dist/tools/TaskTool/TaskTool.js +75 -5
  238. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  239. package/dist/tools/TaskTool/prompt.js +12 -6
  240. package/dist/tools/TaskTool/prompt.js.map +2 -2
  241. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +1 -1
  242. package/dist/tools/ThinkTool/ThinkTool.js.map +1 -1
  243. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +1 -1
  244. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +1 -1
  245. package/dist/tools/WebSearchTool/WebSearchTool.js.map +1 -1
  246. package/dist/tools/WebSearchTool/searchProviders.js +2 -1
  247. package/dist/tools/WebSearchTool/searchProviders.js.map +2 -2
  248. package/dist/tools/lsTool/lsTool.js.map +2 -2
  249. package/dist/tools/lsTool/prompt.js.map +1 -1
  250. package/dist/tools.js +14 -3
  251. package/dist/tools.js.map +2 -2
  252. package/dist/types/PermissionMode.js +21 -1
  253. package/dist/types/PermissionMode.js.map +2 -2
  254. package/dist/types/agentTeams.js +1 -0
  255. package/dist/types/agentTeams.js.map +7 -0
  256. package/dist/types/hooks.js +8 -2
  257. package/dist/types/hooks.js.map +2 -2
  258. package/dist/types/plugin.js +1 -1
  259. package/dist/types/plugin.js.map +2 -2
  260. package/dist/utils/agentLoader.js +25 -3
  261. package/dist/utils/agentLoader.js.map +2 -2
  262. package/dist/utils/animationManager.js +1 -1
  263. package/dist/utils/animationManager.js.map +2 -2
  264. package/dist/utils/ask.js +1 -1
  265. package/dist/utils/async.js +5 -1
  266. package/dist/utils/async.js.map +2 -2
  267. package/dist/utils/autoCompactCore.js +60 -0
  268. package/dist/utils/autoCompactCore.js.map +2 -2
  269. package/dist/utils/config.js +26 -128
  270. package/dist/utils/config.js.map +2 -2
  271. package/dist/utils/configSchema.js +227 -0
  272. package/dist/utils/configSchema.js.map +7 -0
  273. package/dist/utils/debugLogger.js.map +2 -2
  274. package/dist/utils/env.js +4 -3
  275. package/dist/utils/env.js.map +2 -2
  276. package/dist/utils/envConfig.js +34 -0
  277. package/dist/utils/envConfig.js.map +3 -3
  278. package/dist/utils/gpt5.js +146 -0
  279. package/dist/utils/gpt5.js.map +7 -0
  280. package/dist/utils/hookManager.js +374 -140
  281. package/dist/utils/hookManager.js.map +2 -2
  282. package/dist/utils/markdown.js +47 -0
  283. package/dist/utils/markdown.js.map +2 -2
  284. package/dist/utils/memoizeWithTTL.js +25 -0
  285. package/dist/utils/memoizeWithTTL.js.map +7 -0
  286. package/dist/utils/model.js +34 -9
  287. package/dist/utils/model.js.map +2 -2
  288. package/dist/utils/pluginInstaller.js +34 -5
  289. package/dist/utils/pluginInstaller.js.map +2 -2
  290. package/dist/utils/pluginLoader.js +201 -32
  291. package/dist/utils/pluginLoader.js.map +2 -2
  292. package/dist/utils/safeFetch.js +45 -0
  293. package/dist/utils/safeFetch.js.map +7 -0
  294. package/dist/utils/skillLoader.js +59 -6
  295. package/dist/utils/skillLoader.js.map +2 -2
  296. package/dist/utils/streamingState.js +52 -0
  297. package/dist/utils/streamingState.js.map +7 -0
  298. package/dist/utils/style.js +6 -3
  299. package/dist/utils/style.js.map +2 -2
  300. package/dist/utils/teamConfig.js +9 -3
  301. package/dist/utils/teamConfig.js.map +2 -2
  302. package/dist/utils/toolRiskClassification.js +0 -6
  303. package/dist/utils/toolRiskClassification.js.map +2 -2
  304. package/dist/version.js +2 -2
  305. package/dist/version.js.map +1 -1
  306. package/package.json +2 -1
@@ -1,1732 +1,23 @@
1
- import "@anthropic-ai/sdk/shims/node";
2
- import Anthropic, { APIConnectionError, APIError } from "@anthropic-ai/sdk";
3
- import { AnthropicBedrock } from "@anthropic-ai/bedrock-sdk";
4
- import { AnthropicVertex } from "@anthropic-ai/vertex-sdk";
5
- import chalk from "chalk";
6
- import { randomUUID } from "crypto";
7
- import "dotenv/config";
8
- import { addToTotalCost } from "../cost-tracker.js";
9
- import { recordTokenUsage } from "../core/tokenStatsManager.js";
10
- import models from "../constants/models.js";
11
- import { getToolDescriptionAsync } from "../Tool.js";
12
1
  import {
13
- getAnthropicApiKey,
14
- getOrCreateUserID,
15
- getGlobalConfig
16
- } from "../utils/config.js";
17
- import { getProjectDocs } from "../context.js";
18
- import { logError, SESSION_ID } from "../utils/log.js";
19
- import { abortableDelay } from "../utils/async.js";
20
- import { USER_AGENT } from "../utils/http.js";
21
- import {
22
- createAssistantAPIErrorMessage,
23
- normalizeContentFromAPI
24
- } from "../utils/messages.js";
25
- import { withVCR } from "./vcr.js";
26
- import {
27
- debug as debugLogger,
28
- markPhase,
29
- getCurrentRequest,
30
- logLLMInteraction,
31
- logSystemPromptConstruction,
32
- logErrorWithDiagnosis
33
- } from "../utils/debugLogger.js";
34
- import { getModelManager } from "../utils/model.js";
35
- import { zodToJsonSchema } from "zod-to-json-schema";
36
- import { ModelAdapterFactory } from "./modelAdapterFactory.js";
37
- import { responseStateManager, getConversationId } from "./responseStateManager.js";
38
- import { USE_BEDROCK, USE_VERTEX } from "../utils/model.js";
39
- import { getCLISyspromptPrefix } from "../constants/prompts.js";
40
- import { getVertexRegionForModel } from "../utils/model.js";
41
- import { nanoid } from "nanoid";
42
- import {
43
- getCompletionWithProfile,
44
- getGPT5CompletionWithProfile
45
- } from "./openai.js";
46
- import { getReasoningEffort } from "../utils/thinking.js";
47
- import { generateSystemReminders } from "./systemReminder.js";
48
- import { addRetryEventToTranscript } from "../utils/agentTranscripts.js";
49
- import { setStreamingState, getStreamingState } from "../components/Spinner.js";
50
- function isGPT5Model(modelName) {
51
- return modelName.startsWith("gpt-5");
52
- }
53
- class MintoContextManager {
54
- static instance;
55
- projectDocsCache = "";
56
- cacheInitialized = false;
57
- initPromise = null;
58
- constructor() {
59
- }
60
- static getInstance() {
61
- if (!MintoContextManager.instance) {
62
- MintoContextManager.instance = new MintoContextManager();
63
- }
64
- return MintoContextManager.instance;
65
- }
66
- async initialize() {
67
- if (this.cacheInitialized) return;
68
- if (this.initPromise) {
69
- return this.initPromise;
70
- }
71
- this.initPromise = this.loadProjectDocs();
72
- await this.initPromise;
73
- }
74
- async loadProjectDocs() {
75
- try {
76
- const projectDocs = await getProjectDocs();
77
- this.projectDocsCache = projectDocs || "";
78
- this.cacheInitialized = true;
79
- if (process.env.NODE_ENV === "development") {
80
- debugLogger.info("MINTO_CONTEXT_LOADED", {
81
- characters: this.projectDocsCache.length
82
- });
83
- }
84
- } catch (error) {
85
- debugLogger.warn("MINTO_CONTEXT_LOAD_FAILED", { error: String(error) });
86
- this.projectDocsCache = "";
87
- this.cacheInitialized = true;
88
- }
89
- }
90
- getMintoContext() {
91
- if (!this.cacheInitialized) {
92
- this.initialize().catch((error) => {
93
- debugLogger.warn("MINTO_CONTEXT_INIT_FAILED", { error: String(error) });
94
- });
95
- return "";
96
- }
97
- return this.projectDocsCache;
98
- }
99
- async refreshCache() {
100
- this.cacheInitialized = false;
101
- this.initPromise = null;
102
- await this.initialize();
103
- }
104
- }
105
- const mintoContextManager = MintoContextManager.getInstance();
106
- mintoContextManager.initialize().catch((error) => {
107
- debugLogger.warn("MINTO_CONTEXT_MODULE_INIT_FAILED", { error: String(error) });
108
- });
109
- const generateMintoContext = () => {
110
- return mintoContextManager.getMintoContext();
111
- };
112
- const refreshMintoContext = async () => {
113
- await mintoContextManager.refreshCache();
114
- };
115
- const API_ERROR_MESSAGE_PREFIX = "API Error";
116
- const PROMPT_TOO_LONG_ERROR_MESSAGE = "Prompt is too long";
117
- const CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE = "Credit balance is too low";
118
- const INVALID_API_KEY_ERROR_MESSAGE = "Invalid API key \xB7 Please run /login";
119
- const NO_CONTENT_MESSAGE = "(no content)";
120
- const PROMPT_CACHING_ENABLED = !process.env.DISABLE_PROMPT_CACHING;
121
- const SONNET_COST_PER_MILLION_INPUT_TOKENS = 3;
122
- const SONNET_COST_PER_MILLION_OUTPUT_TOKENS = 15;
123
- const SONNET_COST_PER_MILLION_PROMPT_CACHE_WRITE_TOKENS = 3.75;
124
- const SONNET_COST_PER_MILLION_PROMPT_CACHE_READ_TOKENS = 0.3;
125
- const MAIN_QUERY_TEMPERATURE = 1;
126
- function getMetadata() {
127
- return {
128
- user_id: `${getOrCreateUserID()}_${SESSION_ID}`
129
- };
130
- }
131
- const MAX_RETRIES = process.env.USER_TYPE === "SWE_BENCH" ? 100 : 10;
132
- const BASE_DELAY_MS = 500;
133
- function getRetryDelay(attempt, retryAfterHeader) {
134
- if (retryAfterHeader) {
135
- const seconds = parseInt(retryAfterHeader, 10);
136
- if (!isNaN(seconds)) {
137
- return seconds * 1e3;
138
- }
139
- }
140
- return Math.min(BASE_DELAY_MS * Math.pow(2, attempt - 1), 32e3);
141
- }
142
- function shouldRetry(error) {
143
- if (error.message?.includes('"type":"overloaded_error"')) {
144
- return process.env.USER_TYPE === "SWE_BENCH";
145
- }
146
- const shouldRetryHeader = error.headers?.["x-should-retry"];
147
- if (shouldRetryHeader === "true") return true;
148
- if (shouldRetryHeader === "false") return false;
149
- if (error instanceof APIConnectionError) {
150
- return true;
151
- }
152
- if (!error.status) return false;
153
- if (error.status === 408) return true;
154
- if (error.status === 409) return true;
155
- if (error.status === 429) return true;
156
- if (error.status && error.status >= 500) return true;
157
- return false;
158
- }
159
- async function withRetry(operation, options = {}) {
160
- const maxRetries = options.maxRetries ?? MAX_RETRIES;
161
- let lastError;
162
- for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
163
- try {
164
- return await operation(attempt);
165
- } catch (error) {
166
- lastError = error;
167
- if (attempt > maxRetries || !(error instanceof APIError) || !shouldRetry(error)) {
168
- throw error;
169
- }
170
- if (options.signal?.aborted) {
171
- throw new Error("Request cancelled by user");
172
- }
173
- const retryAfter = error.headers?.["retry-after"] ?? null;
174
- const delayMs = getRetryDelay(attempt, retryAfter);
175
- setStreamingState({
176
- phase: "retrying",
177
- retryCount: attempt,
178
- maxRetries,
179
- errorName: error.name
180
- });
181
- debugLogger.flow("API_RETRY_ATTEMPT", {
182
- attempt,
183
- maxRetries,
184
- errorName: error.name,
185
- errorMessage: error.message,
186
- delayMs
187
- });
188
- if (options.onRetry) {
189
- options.onRetry({
190
- attempt,
191
- maxRetries,
192
- error,
193
- delayMs
194
- });
195
- } else {
196
- console.log(
197
- ` \u23BF ${chalk.red(`API ${error.name} (${error.message}) \xB7 Retrying in ${Math.round(delayMs / 1e3)} seconds\u2026 (attempt ${attempt}/${maxRetries})`)}`
198
- );
199
- }
200
- try {
201
- await abortableDelay(delayMs, options.signal);
202
- } catch (delayError) {
203
- if (delayError.message === "Request was aborted") {
204
- throw new Error("Request cancelled by user");
205
- }
206
- throw delayError;
207
- }
208
- }
209
- }
210
- throw lastError;
211
- }
212
- async function fetchAnthropicModels(baseURL, apiKey) {
213
- try {
214
- const modelsURL = baseURL ? `${baseURL.replace(/\/+$/, "")}/v1/models` : "https://api.anthropic.com/v1/models";
215
- const response = await fetch(modelsURL, {
216
- method: "GET",
217
- headers: {
218
- "x-api-key": apiKey,
219
- "anthropic-version": "2023-06-01",
220
- "User-Agent": USER_AGENT
221
- }
222
- });
223
- if (!response.ok) {
224
- if (response.status === 401) {
225
- throw new Error(
226
- "Invalid API key. Please check your Anthropic API key and try again."
227
- );
228
- } else if (response.status === 403) {
229
- throw new Error(
230
- "API key does not have permission to access models. Please check your API key permissions."
231
- );
232
- } else if (response.status === 429) {
233
- throw new Error(
234
- "Too many requests. Please wait a moment and try again."
235
- );
236
- } else if (response.status >= 500) {
237
- throw new Error(
238
- "Anthropic service is temporarily unavailable. Please try again later."
239
- );
240
- } else {
241
- throw new Error(
242
- `Unable to connect to Anthropic API (${response.status}). Please check your internet connection and API key.`
243
- );
244
- }
245
- }
246
- const data = await response.json();
247
- return data.data || [];
248
- } catch (error) {
249
- if (error instanceof Error && error.message.includes("API key") || error instanceof Error && error.message.includes("Anthropic")) {
250
- throw error;
251
- }
252
- logError(error);
253
- throw new Error(
254
- "Unable to connect to Anthropic API. Please check your internet connection and try again."
255
- );
256
- }
257
- }
258
- async function verifyApiKey(apiKey, baseURL, provider) {
259
- if (!apiKey) {
260
- return false;
261
- }
262
- if (provider && provider !== "anthropic") {
263
- try {
264
- const headers = {
265
- Authorization: `Bearer ${apiKey}`,
266
- "Content-Type": "application/json"
267
- };
268
- if (!baseURL) {
269
- debugLogger.warn("API_VERIFY", {
270
- error: "No baseURL provided for non-Anthropic provider"
271
- });
272
- return false;
273
- }
274
- const modelsURL = `${baseURL.replace(/\/+$/, "")}/models`;
275
- const response = await fetch(modelsURL, {
276
- method: "GET",
277
- headers
278
- });
279
- return response.ok;
280
- } catch (error) {
281
- debugLogger.warn("API_VERIFY", {
282
- error: "non-Anthropic provider verification failed",
283
- details: String(error)
284
- });
285
- return false;
286
- }
287
- }
288
- const clientConfig = {
289
- apiKey,
290
- dangerouslyAllowBrowser: true,
291
- maxRetries: 3,
292
- defaultHeaders: {
293
- "User-Agent": USER_AGENT
294
- }
295
- };
296
- if (baseURL && (provider === "anthropic" || provider === "bigdream" || provider === "opendev")) {
297
- clientConfig.baseURL = baseURL;
298
- }
299
- const anthropic = new Anthropic(clientConfig);
300
- try {
301
- await withRetry(
302
- async () => {
303
- const model = "claude-sonnet-4-20250514";
304
- const messages = [{ role: "user", content: "test" }];
305
- await anthropic.messages.create({
306
- model,
307
- max_tokens: 1e3,
308
- // Simple test token limit for API verification
309
- messages,
310
- temperature: 0,
311
- metadata: getMetadata()
312
- });
313
- return true;
314
- },
315
- { maxRetries: 2 }
316
- // Use fewer retries for API key verification
317
- );
318
- return true;
319
- } catch (error) {
320
- logError(error);
321
- if (error instanceof Error && error.message.includes(
322
- '{"type":"error","error":{"type":"authentication_error","message":"invalid x-api-key"}}'
323
- )) {
324
- return false;
325
- }
326
- throw error;
327
- }
328
- }
329
- function convertAnthropicMessagesToOpenAIMessages(messages) {
330
- const openaiMessages = [];
331
- const toolResults = {};
332
- for (const message of messages) {
333
- let contentBlocks = [];
334
- if (typeof message.message.content === "string") {
335
- contentBlocks = [
336
- {
337
- type: "text",
338
- text: message.message.content
339
- }
340
- ];
341
- } else if (!Array.isArray(message.message.content)) {
342
- contentBlocks = [message.message.content];
343
- } else {
344
- contentBlocks = message.message.content;
345
- }
346
- for (const block of contentBlocks) {
347
- if (block.type === "text") {
348
- openaiMessages.push({
349
- role: message.message.role,
350
- content: block.text
351
- });
352
- } else if (block.type === "tool_use") {
353
- openaiMessages.push({
354
- role: "assistant",
355
- content: void 0,
356
- tool_calls: [
357
- {
358
- type: "function",
359
- function: {
360
- name: block.name,
361
- arguments: JSON.stringify(block.input)
362
- },
363
- id: block.id
364
- }
365
- ]
366
- });
367
- } else if (block.type === "tool_result") {
368
- let toolContent = block.content;
369
- if (typeof toolContent !== "string") {
370
- toolContent = JSON.stringify(toolContent);
371
- }
372
- toolResults[block.tool_use_id] = {
373
- role: "tool",
374
- content: toolContent,
375
- tool_call_id: block.tool_use_id
376
- };
377
- }
378
- }
379
- }
380
- const finalMessages = [];
381
- for (const message of openaiMessages) {
382
- finalMessages.push(message);
383
- if ("tool_calls" in message && message.tool_calls) {
384
- for (const toolCall of message.tool_calls) {
385
- if (toolResults[toolCall.id]) {
386
- finalMessages.push(toolResults[toolCall.id]);
387
- }
388
- }
389
- }
390
- }
391
- return finalMessages;
392
- }
393
- function messageReducer(previous, item) {
394
- const reduce = (acc, delta) => {
395
- acc = { ...acc };
396
- for (const [key, value] of Object.entries(delta)) {
397
- if (acc[key] === void 0 || acc[key] === null) {
398
- acc[key] = value;
399
- if (Array.isArray(acc[key])) {
400
- for (const arr of acc[key]) {
401
- delete arr.index;
402
- }
403
- }
404
- } else if (typeof acc[key] === "string" && typeof value === "string") {
405
- acc[key] += value;
406
- } else if (typeof acc[key] === "number" && typeof value === "number") {
407
- acc[key] = value;
408
- } else if (Array.isArray(acc[key]) && Array.isArray(value)) {
409
- const accArray = acc[key];
410
- for (let i = 0; i < value.length; i++) {
411
- const { index, ...chunkTool } = value[i];
412
- if (index - accArray.length > 1) {
413
- throw new Error(
414
- `Error: An array has an empty value when tool_calls are constructed. tool_calls: ${accArray}; tool: ${value}`
415
- );
416
- }
417
- accArray[index] = reduce(accArray[index], chunkTool);
418
- }
419
- } else if (typeof acc[key] === "object" && typeof value === "object") {
420
- acc[key] = reduce(acc[key], value);
421
- }
422
- }
423
- return acc;
424
- };
425
- const choice = item.choices?.[0];
426
- if (!choice) {
427
- return previous;
428
- }
429
- return reduce(previous, choice.delta);
430
- }
431
- async function handleMessageStream(stream, signal) {
432
- const streamStartTime = Date.now();
433
- let ttftMs;
434
- let chunkCount = 0;
435
- let errorCount = 0;
436
- debugLogger.api("OPENAI_STREAM_START", {
437
- streamStartTime: String(streamStartTime)
438
- });
439
- let message = {};
440
- let id, model, created, object, usage;
441
- try {
442
- for await (const chunk of stream) {
443
- if (signal?.aborted) {
444
- debugLogger.flow("OPENAI_STREAM_ABORTED", {
445
- chunkCount,
446
- timestamp: Date.now()
447
- });
448
- throw new Error("Request was cancelled");
449
- }
450
- chunkCount++;
451
- try {
452
- if (!id) {
453
- id = chunk.id;
454
- debugLogger.api("OPENAI_STREAM_ID_RECEIVED", {
455
- id,
456
- chunkNumber: String(chunkCount)
457
- });
458
- }
459
- if (!model) {
460
- model = chunk.model;
461
- debugLogger.api("OPENAI_STREAM_MODEL_RECEIVED", {
462
- model,
463
- chunkNumber: String(chunkCount)
464
- });
465
- }
466
- if (!created) {
467
- created = chunk.created;
468
- }
469
- if (!object) {
470
- object = chunk.object;
471
- }
472
- if (!usage && chunk.usage) {
473
- usage = chunk.usage;
474
- setStreamingState({
475
- inputTokens: chunk.usage.prompt_tokens,
476
- outputTokens: chunk.usage.completion_tokens
477
- });
478
- }
479
- message = messageReducer(message, chunk);
480
- if (chunk?.choices?.[0]?.delta?.content) {
481
- if (!ttftMs) {
482
- ttftMs = Date.now() - streamStartTime;
483
- debugLogger.api("OPENAI_STREAM_FIRST_TOKEN", {
484
- ttftMs: String(ttftMs),
485
- chunkNumber: String(chunkCount)
486
- });
487
- }
488
- }
489
- } catch (chunkError) {
490
- errorCount++;
491
- debugLogger.error("OPENAI_STREAM_CHUNK_ERROR", {
492
- chunkNumber: String(chunkCount),
493
- errorMessage: chunkError instanceof Error ? chunkError.message : String(chunkError),
494
- errorType: chunkError instanceof Error ? chunkError.constructor.name : typeof chunkError
495
- });
496
- }
497
- }
498
- debugLogger.api("OPENAI_STREAM_COMPLETE", {
499
- totalChunks: String(chunkCount),
500
- errorCount: String(errorCount),
501
- totalDuration: String(Date.now() - streamStartTime),
502
- ttftMs: String(ttftMs || 0),
503
- finalMessageId: id || "undefined"
504
- });
505
- } catch (streamError) {
506
- debugLogger.error("OPENAI_STREAM_FATAL_ERROR", {
507
- totalChunks: String(chunkCount),
508
- errorCount: String(errorCount),
509
- errorMessage: streamError instanceof Error ? streamError.message : String(streamError),
510
- errorType: streamError instanceof Error ? streamError.constructor.name : typeof streamError
511
- });
512
- throw streamError;
513
- }
514
- return {
515
- id,
516
- created,
517
- model,
518
- object,
519
- choices: [
520
- {
521
- index: 0,
522
- message,
523
- finish_reason: "stop",
524
- logprobs: void 0
525
- }
526
- ],
527
- usage
528
- };
529
- }
530
- function convertOpenAIResponseToAnthropic(response, _tools) {
531
- let contentBlocks = [];
532
- const message = response.choices?.[0]?.message;
533
- if (!message) {
534
- return {
535
- role: "assistant",
536
- content: [],
537
- stop_reason: response.choices?.[0]?.finish_reason,
538
- type: "message",
539
- usage: response.usage
540
- };
541
- }
542
- if (message?.tool_calls) {
543
- for (const toolCall of message.tool_calls) {
544
- const tool = toolCall.function;
545
- const toolName = tool?.name;
546
- let toolArgs = {};
547
- let parseError = null;
548
- try {
549
- toolArgs = tool?.arguments ? JSON.parse(tool.arguments) : {};
550
- } catch (e) {
551
- parseError = e instanceof Error ? e.message : String(e);
552
- debugLogger.warn("TOOL_ARGUMENTS_PARSE_ERROR", {
553
- toolName,
554
- rawArguments: tool?.arguments?.substring(0, 200),
555
- // Limit log size
556
- errorMessage: parseError
557
- });
558
- }
559
- if (parseError && Object.keys(toolArgs).length === 0) {
560
- debugLogger.error("TOOL_CALL_EMPTY_ARGUMENTS", {
561
- toolName,
562
- parseError,
563
- suggestion: "Model may have sent malformed JSON. The tool call will likely fail validation."
564
- });
565
- }
566
- contentBlocks.push({
567
- type: "tool_use",
568
- input: toolArgs,
569
- name: toolName,
570
- id: toolCall.id?.length > 0 ? toolCall.id : nanoid()
571
- });
572
- }
573
- }
574
- if (message.reasoning) {
575
- contentBlocks.push({
576
- type: "thinking",
577
- thinking: message.reasoning,
578
- signature: ""
579
- });
580
- }
581
- if (message.reasoning_content) {
582
- contentBlocks.push({
583
- type: "thinking",
584
- thinking: message.reasoning_content,
585
- signature: ""
586
- });
587
- }
588
- if (message.content) {
589
- contentBlocks.push({
590
- type: "text",
591
- text: message?.content,
592
- citations: []
593
- });
594
- }
595
- const finalMessage = {
596
- role: "assistant",
597
- content: contentBlocks,
598
- stop_reason: response.choices?.[0]?.finish_reason,
599
- type: "message",
600
- usage: response.usage
601
- };
602
- return finalMessage;
603
- }
604
- let anthropicClient = null;
605
- function getAnthropicClient(model) {
606
- const config = getGlobalConfig();
607
- const provider = config.primaryProvider;
608
- if (anthropicClient && provider) {
609
- anthropicClient = null;
610
- }
611
- if (anthropicClient) {
612
- return anthropicClient;
613
- }
614
- const region = getVertexRegionForModel(model);
615
- const defaultHeaders = {
616
- "x-app": "cli",
617
- "User-Agent": USER_AGENT
618
- };
619
- if (process.env.ANTHROPIC_AUTH_TOKEN) {
620
- defaultHeaders["Authorization"] = `Bearer ${process.env.ANTHROPIC_AUTH_TOKEN}`;
621
- }
622
- const ARGS = {
623
- defaultHeaders,
624
- maxRetries: 0,
625
- // Disabled auto-retry in favor of manual implementation
626
- timeout: parseInt(process.env.API_TIMEOUT_MS || String(60 * 1e3), 10)
627
- };
628
- if (USE_BEDROCK) {
629
- const client = new AnthropicBedrock(ARGS);
630
- anthropicClient = client;
631
- return client;
632
- }
633
- if (USE_VERTEX) {
634
- const vertexArgs = {
635
- ...ARGS,
636
- region: region || process.env.CLOUD_ML_REGION || "us-east5"
637
- };
638
- const client = new AnthropicVertex(vertexArgs);
639
- anthropicClient = client;
640
- return client;
641
- }
642
- const modelManager = getModelManager();
643
- const modelProfile = modelManager.getModel("main");
644
- let apiKey;
645
- let baseURL;
646
- if (modelProfile) {
647
- apiKey = modelProfile.apiKey || "";
648
- baseURL = modelProfile.baseURL;
649
- } else {
650
- apiKey = getAnthropicApiKey();
651
- baseURL = void 0;
652
- }
653
- if (process.env.USER_TYPE === "ant" && !apiKey && provider === "anthropic") {
654
- console.error(
655
- chalk.red(
656
- "[ANT-ONLY] Please set the ANTHROPIC_API_KEY environment variable to use the CLI. To create a new key, go to https://console.anthropic.com/settings/keys."
657
- )
658
- );
659
- }
660
- const clientConfig = {
661
- apiKey,
662
- dangerouslyAllowBrowser: true,
663
- ...ARGS,
664
- ...baseURL && { baseURL }
665
- // Use baseURL directly, SDK will handle API versioning
666
- };
667
- anthropicClient = new Anthropic(clientConfig);
668
- return anthropicClient;
669
- }
670
- function resetAnthropicClient() {
671
- anthropicClient = null;
672
- }
673
- function applyCacheControlWithLimits(systemBlocks, messageParams) {
674
- if (!PROMPT_CACHING_ENABLED) {
675
- return { systemBlocks, messageParams };
676
- }
677
- const maxCacheBlocks = 4;
678
- let usedCacheBlocks = 0;
679
- const processedSystemBlocks = systemBlocks.map((block, _index) => {
680
- if (usedCacheBlocks < maxCacheBlocks && block.text.length > 1e3) {
681
- usedCacheBlocks++;
682
- return {
683
- ...block,
684
- cache_control: { type: "ephemeral" }
685
- };
686
- }
687
- const { cache_control, ...blockWithoutCache } = block;
688
- return blockWithoutCache;
689
- });
690
- const processedMessageParams = messageParams.map((message, messageIndex) => {
691
- if (Array.isArray(message.content)) {
692
- const processedContent = message.content.map(
693
- (contentBlock, blockIndex) => {
694
- const shouldCache = usedCacheBlocks < maxCacheBlocks && contentBlock.type === "text" && typeof contentBlock.text === "string" && // Long documents (over 2000 characters)
695
- (contentBlock.text.length > 2e3 || // Last content block of the last message (may be important context)
696
- messageIndex === messageParams.length - 1 && blockIndex === message.content.length - 1 && contentBlock.text.length > 500);
697
- if (shouldCache) {
698
- usedCacheBlocks++;
699
- return {
700
- ...contentBlock,
701
- cache_control: { type: "ephemeral" }
702
- };
703
- }
704
- const { cache_control, ...blockWithoutCache } = contentBlock;
705
- return blockWithoutCache;
706
- }
707
- );
708
- return {
709
- ...message,
710
- content: processedContent
711
- };
712
- }
713
- return message;
714
- });
715
- return {
716
- systemBlocks: processedSystemBlocks,
717
- messageParams: processedMessageParams
718
- };
719
- }
720
- function userMessageToMessageParam(message, addCache = false) {
721
- if (addCache) {
722
- if (typeof message.message.content === "string") {
723
- return {
724
- role: "user",
725
- content: [
726
- {
727
- type: "text",
728
- text: message.message.content
729
- }
730
- ]
731
- };
732
- } else {
733
- return {
734
- role: "user",
735
- content: message.message.content.map((_) => ({ ..._ }))
736
- };
737
- }
738
- }
739
- return {
740
- role: "user",
741
- content: message.message.content
742
- };
743
- }
744
- function assistantMessageToMessageParam(message, addCache = false) {
745
- if (addCache) {
746
- if (typeof message.message.content === "string") {
747
- return {
748
- role: "assistant",
749
- content: [
750
- {
751
- type: "text",
752
- text: message.message.content
753
- }
754
- ]
755
- };
756
- } else {
757
- return {
758
- role: "assistant",
759
- content: message.message.content.map((_) => ({ ..._ }))
760
- };
761
- }
762
- }
763
- return {
764
- role: "assistant",
765
- content: message.message.content
766
- };
767
- }
768
- function splitSysPromptPrefix(systemPrompt) {
769
- const systemPromptFirstBlock = systemPrompt[0] || "";
770
- const systemPromptRest = systemPrompt.slice(1);
771
- return [systemPromptFirstBlock, systemPromptRest.join("\n")].filter(Boolean);
772
- }
773
- async function queryLLM(messages, systemPrompt, maxThinkingTokens, tools, signal, options) {
774
- const modelManager = getModelManager();
775
- const modelResolution = modelManager.resolveModelWithInfo(options.model);
776
- if (!modelResolution.success || !modelResolution.profile) {
777
- throw new Error(
778
- modelResolution.error || `Failed to resolve model: ${options.model}`
779
- );
780
- }
781
- const modelProfile = modelResolution.profile;
782
- const resolvedModel = modelProfile.modelName;
783
- const toolUseContext = options.toolUseContext;
784
- if (toolUseContext && !toolUseContext.responseState) {
785
- const conversationId = getConversationId(
786
- toolUseContext.agentId,
787
- toolUseContext.messageId
788
- );
789
- const previousResponseId = responseStateManager.getPreviousResponseId(conversationId);
790
- toolUseContext.responseState = {
791
- previousResponseId,
792
- conversationId
793
- };
794
- }
795
- debugLogger.api("MODEL_RESOLVED", {
796
- inputParam: options.model,
797
- resolvedModelName: resolvedModel,
798
- provider: modelProfile.provider,
799
- isPointer: ["main", "task", "reasoning", "quick"].includes(options.model),
800
- hasResponseState: !!toolUseContext?.responseState,
801
- conversationId: toolUseContext?.responseState?.conversationId,
802
- requestId: getCurrentRequest()?.id
803
- });
804
- const currentRequest = getCurrentRequest();
805
- debugLogger.api("LLM_REQUEST_START", {
806
- messageCount: messages.length,
807
- systemPromptLength: systemPrompt.join(" ").length,
808
- toolCount: tools.length,
809
- model: resolvedModel,
810
- originalModelParam: options.model,
811
- requestId: getCurrentRequest()?.id
812
- });
813
- markPhase("LLM_CALL");
814
- try {
815
- const result = await withVCR(
816
- messages,
817
- () => queryLLMWithPromptCaching(
818
- messages,
819
- systemPrompt,
820
- maxThinkingTokens,
821
- tools,
822
- signal,
823
- { ...options, model: resolvedModel, modelProfile, toolUseContext }
824
- // Pass resolved ModelProfile and toolUseContext
825
- )
826
- );
827
- debugLogger.api("LLM_REQUEST_SUCCESS", {
828
- costUSD: result.costUSD,
829
- durationMs: result.durationMs,
830
- responseLength: result.message.content?.length || 0,
831
- requestId: getCurrentRequest()?.id
832
- });
833
- if (toolUseContext?.responseState?.conversationId && result.responseId) {
834
- responseStateManager.setPreviousResponseId(
835
- toolUseContext.responseState.conversationId,
836
- result.responseId
837
- );
838
- debugLogger.api("RESPONSE_STATE_UPDATED", {
839
- conversationId: toolUseContext.responseState.conversationId,
840
- responseId: result.responseId,
841
- requestId: getCurrentRequest()?.id
842
- });
843
- }
844
- return result;
845
- } catch (error) {
846
- logErrorWithDiagnosis(
847
- error,
848
- {
849
- messageCount: messages.length,
850
- systemPromptLength: systemPrompt.join(" ").length,
851
- model: options.model,
852
- toolCount: tools.length,
853
- phase: "LLM_CALL"
854
- },
855
- currentRequest?.id
856
- );
857
- throw error;
858
- }
859
- }
860
- function formatSystemPromptWithContext(systemPrompt, context, agentId, skipContextReminders = false) {
861
- const enhancedPrompt = [...systemPrompt];
862
- let reminders = "";
863
- const modelManager = getModelManager();
864
- const modelProfile = modelManager.getModel("main");
865
- if (modelProfile && isGPT5Model(modelProfile.modelName)) {
866
- const persistencePrompts = [
867
- "\n# Agent Persistence for Long-Running Coding Tasks",
868
- "You are working on a coding project that may involve multiple steps and iterations. Please maintain context and continuity throughout the session:",
869
- "- Remember architectural decisions and design patterns established earlier",
870
- "- Keep track of file modifications and their relationships",
871
- "- Maintain awareness of the overall project structure and goals",
872
- "- Reference previous implementations when making related changes",
873
- "- Ensure consistency with existing code style and conventions",
874
- "- Build incrementally on previous work rather than starting from scratch"
875
- ];
876
- enhancedPrompt.push(...persistencePrompts);
877
- }
878
- const hasContext = Object.entries(context).length > 0;
879
- if (hasContext) {
880
- if (!skipContextReminders) {
881
- const mintoContext = generateMintoContext();
882
- if (mintoContext) {
883
- enhancedPrompt.push("\n---\n# \u9879\u76EE\u4E0A\u4E0B\u6587\n");
884
- enhancedPrompt.push(mintoContext);
885
- enhancedPrompt.push("\n---\n");
886
- }
887
- }
888
- const reminderMessages = generateSystemReminders(hasContext, agentId);
889
- if (reminderMessages.length > 0) {
890
- reminders = reminderMessages.map((r) => r.content).join("\n") + "\n";
891
- }
892
- enhancedPrompt.push(
893
- `
894
- As you answer the user's questions, you can use the following context:
895
- `
896
- );
897
- const filteredContext = Object.fromEntries(
898
- Object.entries(context).filter(
899
- ([key]) => key !== "projectDocs" && key !== "userDocs"
900
- )
901
- );
902
- enhancedPrompt.push(
903
- ...Object.entries(filteredContext).map(
904
- ([key, value]) => `<context name="${key}">${value}</context>`
905
- )
906
- );
907
- }
908
- return { systemPrompt: enhancedPrompt, reminders };
909
- }
910
- async function queryLLMWithPromptCaching(messages, systemPrompt, maxThinkingTokens, tools, signal, options) {
911
- const config = getGlobalConfig();
912
- const modelManager = getModelManager();
913
- const toolUseContext = options.toolUseContext;
914
- const modelProfile = options.modelProfile || modelManager.getModel("main");
915
- let provider;
916
- if (modelProfile) {
917
- provider = modelProfile.provider || config.primaryProvider || "anthropic";
918
- } else {
919
- provider = config.primaryProvider || "anthropic";
920
- }
921
- if (provider === "anthropic" || provider === "bigdream" || provider === "opendev") {
922
- return queryAnthropicNative(
923
- messages,
924
- systemPrompt,
925
- maxThinkingTokens,
926
- tools,
927
- signal,
928
- { ...options, modelProfile, toolUseContext }
929
- );
930
- }
931
- return queryOpenAI(messages, systemPrompt, maxThinkingTokens, tools, signal, {
932
- ...options,
933
- modelProfile,
934
- toolUseContext
935
- });
936
- }
937
- async function queryAnthropicNative(messages, systemPrompt, maxThinkingTokens, tools, signal, options) {
938
- const config = getGlobalConfig();
939
- const modelManager = getModelManager();
940
- const toolUseContext = options?.toolUseContext;
941
- const modelProfile = options?.modelProfile || modelManager.getModel("main");
942
- let anthropic;
943
- let model;
944
- let provider;
945
- debugLogger.api("MODEL_CONFIG_ANTHROPIC", {
946
- modelProfileFound: !!modelProfile,
947
- modelProfileId: modelProfile?.modelName,
948
- modelProfileName: modelProfile?.name,
949
- modelProfileModelName: modelProfile?.modelName,
950
- modelProfileProvider: modelProfile?.provider,
951
- modelProfileBaseURL: modelProfile?.baseURL,
952
- modelProfileApiKeyExists: !!modelProfile?.apiKey,
953
- optionsModel: options?.model,
954
- requestId: getCurrentRequest()?.id
955
- });
956
- if (modelProfile) {
957
- model = modelProfile.modelName;
958
- provider = modelProfile.provider || config.primaryProvider || "anthropic";
959
- if (modelProfile.provider === "anthropic" || modelProfile.provider === "bigdream" || modelProfile.provider === "opendev") {
960
- const clientConfig = {
961
- apiKey: modelProfile.apiKey,
962
- dangerouslyAllowBrowser: true,
963
- maxRetries: 0,
964
- timeout: parseInt(process.env.API_TIMEOUT_MS || String(60 * 1e3), 10),
965
- defaultHeaders: {
966
- "x-app": "cli",
967
- "User-Agent": USER_AGENT
968
- }
969
- };
970
- if (modelProfile.baseURL) {
971
- clientConfig.baseURL = modelProfile.baseURL;
972
- }
973
- anthropic = new Anthropic(clientConfig);
974
- } else {
975
- anthropic = getAnthropicClient(model);
976
- }
977
- } else {
978
- const errorDetails = {
979
- modelProfileExists: !!modelProfile,
980
- modelProfileModelName: modelProfile?.modelName,
981
- requestedModel: options?.model,
982
- requestId: getCurrentRequest()?.id
983
- };
984
- debugLogger.error("ANTHROPIC_FALLBACK_ERROR", errorDetails);
985
- throw new Error(
986
- `No valid ModelProfile available for Anthropic provider. Please configure model through /model command. Debug: ${JSON.stringify(errorDetails)}`
987
- );
988
- }
989
- if (options?.prependCLISysprompt) {
990
- const [firstSyspromptBlock] = splitSysPromptPrefix(systemPrompt);
991
- systemPrompt = [getCLISyspromptPrefix(), ...systemPrompt];
992
- }
993
- const system = splitSysPromptPrefix(systemPrompt).map(
994
- (_) => ({
995
- text: _,
996
- type: "text"
997
- })
998
- );
999
- const toolSchemas = await Promise.all(
1000
- tools.map(
1001
- async (tool) => ({
1002
- name: tool.name,
1003
- // Use getToolDescriptionAsync for consistent async access
1004
- description: await getToolDescriptionAsync(tool),
1005
- input_schema: "inputJSONSchema" in tool && tool.inputJSONSchema ? tool.inputJSONSchema : zodToJsonSchema(tool.inputSchema)
1006
- })
1007
- )
1008
- );
1009
- const anthropicMessages = addCacheBreakpoints(messages);
1010
- const { systemBlocks: processedSystem, messageParams: processedMessages } = applyCacheControlWithLimits(system, anthropicMessages);
1011
- const startIncludingRetries = Date.now();
1012
- logSystemPromptConstruction({
1013
- basePrompt: systemPrompt.join("\n"),
1014
- mintoContext: generateMintoContext() || "",
1015
- reminders: [],
1016
- // 这里可以从 generateSystemReminders 获取
1017
- finalPrompt: systemPrompt.join("\n")
1018
- });
1019
- let start = Date.now();
1020
- let attemptNumber = 0;
1021
- let response;
1022
- try {
1023
- response = await withRetry(
1024
- async (attempt) => {
1025
- attemptNumber = attempt;
1026
- start = Date.now();
1027
- const params = {
1028
- model,
1029
- max_tokens: getMaxTokensFromProfile(modelProfile),
1030
- messages: processedMessages,
1031
- system: processedSystem,
1032
- tools: toolSchemas.length > 0 ? toolSchemas : void 0,
1033
- tool_choice: toolSchemas.length > 0 ? { type: "auto" } : void 0
1034
- };
1035
- if (maxThinkingTokens > 0) {
1036
- ;
1037
- params.extra_headers = {
1038
- "anthropic-beta": "max-tokens-3-5-sonnet-2024-07-15"
1039
- };
1040
- params.thinking = { max_tokens: maxThinkingTokens };
1041
- }
1042
- debugLogger.api("ANTHROPIC_API_CALL_START_STREAMING", {
1043
- endpoint: modelProfile?.baseURL || "DEFAULT_ANTHROPIC",
1044
- model,
1045
- provider,
1046
- apiKeyConfigured: !!modelProfile?.apiKey,
1047
- apiKeyPrefix: modelProfile?.apiKey ? modelProfile.apiKey.substring(0, 8) : null,
1048
- maxTokens: params.max_tokens,
1049
- temperature: MAIN_QUERY_TEMPERATURE,
1050
- params,
1051
- messageCount: params.messages?.length || 0,
1052
- streamMode: true,
1053
- toolsCount: toolSchemas.length,
1054
- thinkingTokens: maxThinkingTokens,
1055
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1056
- modelProfileId: modelProfile?.modelName,
1057
- modelProfileName: modelProfile?.name
1058
- });
1059
- if (config.stream) {
1060
- const stream = await anthropic.beta.messages.create(
1061
- {
1062
- ...params,
1063
- stream: true
1064
- },
1065
- {
1066
- signal
1067
- // ← CRITICAL: Connect the AbortSignal to API call
1068
- }
1069
- );
1070
- let finalResponse = null;
1071
- let messageStartEvent = null;
1072
- const contentBlocks = [];
1073
- const inputJSONBuffers = /* @__PURE__ */ new Map();
1074
- let usage = null;
1075
- let stopReason = null;
1076
- let stopSequence = null;
1077
- for await (const event of stream) {
1078
- if (signal.aborted) {
1079
- debugLogger.flow("STREAM_ABORTED", {
1080
- eventType: event.type,
1081
- timestamp: Date.now()
1082
- });
1083
- throw new Error("Request was cancelled");
1084
- }
1085
- switch (event.type) {
1086
- case "message_start":
1087
- messageStartEvent = event;
1088
- finalResponse = {
1089
- ...event.message,
1090
- content: []
1091
- // Will be populated from content blocks
1092
- };
1093
- setStreamingState({
1094
- inputTokens: event.message.usage?.input_tokens,
1095
- receivedChars: 0
1096
- // Reset for new request
1097
- });
1098
- break;
1099
- case "content_block_start":
1100
- contentBlocks[event.index] = { ...event.content_block };
1101
- if (event.content_block.type === "tool_use") {
1102
- inputJSONBuffers.set(event.index, "");
1103
- }
1104
- if (event.content_block.type === "thinking") {
1105
- const thinkingStartTime = Date.now();
1106
- setStreamingState({
1107
- phase: "deep_thinking",
1108
- tokenCount: 0,
1109
- thinkingMaxTokens: maxThinkingTokens,
1110
- thinkingStartTime
1111
- // NEW: Record start time for duration tracking
1112
- });
1113
- debugLogger.flow("THINKING_BLOCK_START", {
1114
- index: event.index,
1115
- maxTokens: maxThinkingTokens,
1116
- startTime: thinkingStartTime
1117
- });
1118
- }
1119
- break;
1120
- case "content_block_delta":
1121
- const blockIndex = event.index;
1122
- if (!contentBlocks[blockIndex]) {
1123
- contentBlocks[blockIndex] = {
1124
- type: event.delta.type === "text_delta" ? "text" : "tool_use",
1125
- text: event.delta.type === "text_delta" ? "" : void 0
1126
- };
1127
- if (event.delta.type === "input_json_delta") {
1128
- inputJSONBuffers.set(blockIndex, "");
1129
- }
1130
- }
1131
- if (event.delta.type === "text_delta") {
1132
- contentBlocks[blockIndex].text += event.delta.text;
1133
- const currentState = getStreamingState();
1134
- setStreamingState({
1135
- receivedChars: (currentState.receivedChars || 0) + event.delta.text.length
1136
- });
1137
- } else if (event.delta.type === "input_json_delta") {
1138
- const currentBuffer = inputJSONBuffers.get(blockIndex) || "";
1139
- inputJSONBuffers.set(
1140
- blockIndex,
1141
- currentBuffer + event.delta.partial_json
1142
- );
1143
- } else if (event.delta.type === "thinking_delta") {
1144
- const currentThinking = contentBlocks[blockIndex].thinking || "";
1145
- const updatedThinking = currentThinking + (event.delta.thinking || "");
1146
- contentBlocks[blockIndex] = {
1147
- ...contentBlocks[blockIndex],
1148
- thinking: updatedThinking
1149
- };
1150
- setStreamingState({
1151
- phase: "deep_thinking",
1152
- tokenCount: updatedThinking.length,
1153
- thinkingMaxTokens: maxThinkingTokens
1154
- });
1155
- debugLogger.trace("THINKING_DELTA", {
1156
- index: blockIndex,
1157
- tokenCount: updatedThinking.length
1158
- });
1159
- }
1160
- break;
1161
- case "message_delta":
1162
- if (event.delta.stop_reason)
1163
- stopReason = event.delta.stop_reason;
1164
- if (event.delta.stop_sequence)
1165
- stopSequence = event.delta.stop_sequence;
1166
- if (event.usage) {
1167
- usage = { ...usage, ...event.usage };
1168
- setStreamingState({
1169
- outputTokens: event.usage.output_tokens
1170
- });
1171
- }
1172
- break;
1173
- case "content_block_stop":
1174
- const stopIndex = event.index;
1175
- const block = contentBlocks[stopIndex];
1176
- if (block?.type === "thinking") {
1177
- const streamState2 = getStreamingState();
1178
- const thinkingDurationMs = streamState2.thinkingStartTime ? Date.now() - streamState2.thinkingStartTime : 0;
1179
- setStreamingState({
1180
- phase: "generating",
1181
- thinkingDurationMs
1182
- // NEW: Store duration for display
1183
- });
1184
- debugLogger.flow("THINKING_BLOCK_COMPLETE", {
1185
- index: stopIndex,
1186
- finalTokenCount: block.thinking?.length || 0,
1187
- durationMs: thinkingDurationMs
1188
- });
1189
- }
1190
- if (block?.type === "tool_use" && inputJSONBuffers.has(stopIndex)) {
1191
- const jsonStr = inputJSONBuffers.get(stopIndex);
1192
- if (jsonStr) {
1193
- try {
1194
- block.input = JSON.parse(jsonStr);
1195
- } catch (error) {
1196
- const errorMsg = error instanceof Error ? error.message : String(error);
1197
- debugLogger.error("JSON_PARSE_ERROR", {
1198
- blockIndex: stopIndex,
1199
- jsonStr: jsonStr.length > 500 ? jsonStr.slice(0, 500) + "..." : jsonStr,
1200
- error: errorMsg
1201
- });
1202
- block.input = {
1203
- __parse_error__: true,
1204
- __error_message__: `JSON parse failed: ${errorMsg}`,
1205
- __raw_json_preview__: jsonStr.length > 200 ? jsonStr.slice(0, 200) + "..." : jsonStr
1206
- };
1207
- }
1208
- inputJSONBuffers.delete(stopIndex);
1209
- }
1210
- }
1211
- break;
1212
- case "message_stop":
1213
- inputJSONBuffers.clear();
1214
- break;
1215
- }
1216
- if (event.type === "message_stop") {
1217
- break;
1218
- }
1219
- }
1220
- if (!finalResponse || !messageStartEvent) {
1221
- throw new Error("Stream ended without proper message structure");
1222
- }
1223
- finalResponse = {
1224
- ...messageStartEvent.message,
1225
- content: contentBlocks.filter(Boolean),
1226
- stop_reason: stopReason,
1227
- stop_sequence: stopSequence,
1228
- usage: {
1229
- ...messageStartEvent.message.usage,
1230
- ...usage
1231
- }
1232
- };
1233
- return finalResponse;
1234
- } else {
1235
- debugLogger.api("ANTHROPIC_API_CALL_START_NON_STREAMING", {
1236
- endpoint: modelProfile?.baseURL || "DEFAULT_ANTHROPIC",
1237
- model,
1238
- provider,
1239
- apiKeyConfigured: !!modelProfile?.apiKey,
1240
- apiKeyPrefix: modelProfile?.apiKey ? modelProfile.apiKey.substring(0, 8) : null,
1241
- maxTokens: params.max_tokens,
1242
- temperature: MAIN_QUERY_TEMPERATURE,
1243
- messageCount: params.messages?.length || 0,
1244
- streamMode: false,
1245
- toolsCount: toolSchemas.length,
1246
- thinkingTokens: maxThinkingTokens,
1247
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1248
- modelProfileId: modelProfile?.modelName,
1249
- modelProfileName: modelProfile?.name
1250
- });
1251
- return await anthropic.beta.messages.create(params, {
1252
- signal
1253
- // ← CRITICAL: Connect the AbortSignal to API call
1254
- });
1255
- }
1256
- },
1257
- {
1258
- signal,
1259
- // Pass retry events to agent transcript for UI display
1260
- onRetry: toolUseContext?.agentId ? ({ attempt, maxRetries, error, delayMs }) => {
1261
- addRetryEventToTranscript(toolUseContext.agentId, {
1262
- attempt,
1263
- maxRetries,
1264
- errorMessage: error.message,
1265
- delayMs
1266
- });
1267
- } : void 0
1268
- }
1269
- );
1270
- debugLogger.api("ANTHROPIC_API_CALL_SUCCESS", {
1271
- content: response.content
1272
- });
1273
- const ttftMs = start - Date.now();
1274
- const durationMs = Date.now() - startIncludingRetries;
1275
- const content = response.content.map((block) => {
1276
- if (block.type === "text") {
1277
- return {
1278
- type: "text",
1279
- text: block.text
1280
- };
1281
- } else if (block.type === "tool_use") {
1282
- return {
1283
- type: "tool_use",
1284
- id: block.id,
1285
- name: block.name,
1286
- input: block.input
1287
- };
1288
- }
1289
- return block;
1290
- });
1291
- const thinkingBlocks = content.filter(
1292
- (block) => block.type === "thinking"
1293
- );
1294
- const streamState = getStreamingState();
1295
- const thinkingMetadata = thinkingBlocks.length > 0 ? {
1296
- charCount: thinkingBlocks.reduce(
1297
- (sum, b) => sum + (b.thinking?.length || 0),
1298
- 0
1299
- ),
1300
- durationMs: streamState.thinkingDurationMs || 0,
1301
- startTime: streamState.thinkingStartTime || Date.now(),
1302
- isComplete: true
1303
- } : void 0;
1304
- const assistantMessage = {
1305
- message: {
1306
- id: response.id,
1307
- content,
1308
- model: response.model,
1309
- role: "assistant",
1310
- stop_reason: response.stop_reason,
1311
- stop_sequence: response.stop_sequence,
1312
- type: "message",
1313
- usage: response.usage
1314
- },
1315
- type: "assistant",
1316
- uuid: nanoid(),
1317
- durationMs,
1318
- costUSD: 0,
1319
- // Will be calculated below
1320
- thinkingMetadata
1321
- };
1322
- const systemMessages = system.map((block) => ({
1323
- role: "system",
1324
- content: block.text
1325
- }));
1326
- logLLMInteraction({
1327
- systemPrompt: systemPrompt.join("\n"),
1328
- messages: [...systemMessages, ...anthropicMessages],
1329
- response,
1330
- usage: response.usage ? {
1331
- inputTokens: response.usage.input_tokens,
1332
- outputTokens: response.usage.output_tokens
1333
- } : void 0,
1334
- timing: {
1335
- start,
1336
- end: Date.now()
1337
- },
1338
- apiFormat: "anthropic"
1339
- });
1340
- const inputTokens = response.usage.input_tokens;
1341
- const outputTokens = response.usage.output_tokens;
1342
- const cacheCreationInputTokens = response.usage.cache_creation_input_tokens ?? 0;
1343
- const cacheReadInputTokens = response.usage.cache_read_input_tokens ?? 0;
1344
- const costUSD = inputTokens / 1e6 * getModelInputTokenCostUSD(model) + outputTokens / 1e6 * getModelOutputTokenCostUSD(model) + cacheCreationInputTokens / 1e6 * getModelInputTokenCostUSD(model) + cacheReadInputTokens / 1e6 * (getModelInputTokenCostUSD(model) * 0.1);
1345
- assistantMessage.costUSD = costUSD;
1346
- addToTotalCost(costUSD, durationMs);
1347
- recordTokenUsage(
1348
- {
1349
- inputTokens,
1350
- outputTokens,
1351
- cacheCreationTokens: cacheCreationInputTokens,
1352
- cacheReadTokens: cacheReadInputTokens
1353
- },
1354
- costUSD,
1355
- model,
1356
- toolUseContext ? {
1357
- agentId: toolUseContext.agentId,
1358
- toolUseId: toolUseContext.toolUseId,
1359
- model
1360
- } : void 0
1361
- );
1362
- return assistantMessage;
1363
- } catch (error) {
1364
- return getAssistantMessageFromError(error);
1365
- }
1366
- }
1367
- function getAssistantMessageFromError(error) {
1368
- if (error instanceof Error && error.message.includes("prompt is too long")) {
1369
- return createAssistantAPIErrorMessage(PROMPT_TOO_LONG_ERROR_MESSAGE);
1370
- }
1371
- if (error instanceof Error && error.message.includes("Your credit balance is too low")) {
1372
- return createAssistantAPIErrorMessage(CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE);
1373
- }
1374
- if (error instanceof Error && error.message.toLowerCase().includes("x-api-key")) {
1375
- return createAssistantAPIErrorMessage(INVALID_API_KEY_ERROR_MESSAGE);
1376
- }
1377
- if (error instanceof Error) {
1378
- if (process.env.NODE_ENV === "development") {
1379
- debugLogger.error("ANTHROPIC_API_ERROR", {
1380
- message: error.message,
1381
- stack: error.stack
1382
- });
1383
- }
1384
- return createAssistantAPIErrorMessage(
1385
- `${API_ERROR_MESSAGE_PREFIX}: ${error.message}`
1386
- );
1387
- }
1388
- return createAssistantAPIErrorMessage(API_ERROR_MESSAGE_PREFIX);
1389
- }
1390
- function addCacheBreakpoints(messages) {
1391
- return messages.map((msg, index) => {
1392
- return msg.type === "user" ? userMessageToMessageParam(msg, index > messages.length - 3) : assistantMessageToMessageParam(msg, index > messages.length - 3);
1393
- });
1394
- }
1395
- async function queryOpenAI(messages, systemPrompt, maxThinkingTokens, tools, signal, options) {
1396
- const config = getGlobalConfig();
1397
- const modelManager = getModelManager();
1398
- const toolUseContext = options?.toolUseContext;
1399
- const modelProfile = options?.modelProfile || modelManager.getModel("main");
1400
- let model;
1401
- const currentRequest = getCurrentRequest();
1402
- debugLogger.api("MODEL_CONFIG_OPENAI", {
1403
- modelProfileFound: !!modelProfile,
1404
- modelProfileId: modelProfile?.modelName,
1405
- modelProfileName: modelProfile?.name,
1406
- modelProfileModelName: modelProfile?.modelName,
1407
- modelProfileProvider: modelProfile?.provider,
1408
- modelProfileBaseURL: modelProfile?.baseURL,
1409
- modelProfileApiKeyExists: !!modelProfile?.apiKey,
1410
- optionsModel: options?.model,
1411
- requestId: getCurrentRequest()?.id
1412
- });
1413
- if (modelProfile) {
1414
- model = modelProfile.modelName;
1415
- } else {
1416
- model = options?.model || modelProfile?.modelName || "";
1417
- }
1418
- if (options?.prependCLISysprompt) {
1419
- const [firstSyspromptBlock] = splitSysPromptPrefix(systemPrompt);
1420
- systemPrompt = [getCLISyspromptPrefix() + systemPrompt];
1421
- }
1422
- const system = splitSysPromptPrefix(systemPrompt).map(
1423
- (_) => ({
1424
- ...PROMPT_CACHING_ENABLED ? { cache_control: { type: "ephemeral" } } : {},
1425
- text: _,
1426
- type: "text"
1427
- })
1428
- );
1429
- const toolSchemas = await Promise.all(
1430
- tools.map(
1431
- async (_) => ({
1432
- type: "function",
1433
- function: {
1434
- name: _.name,
1435
- description: await _.prompt({
1436
- safeMode: options?.safeMode
1437
- }),
1438
- // Use tool's JSON schema directly if provided, otherwise convert Zod schema
1439
- parameters: "inputJSONSchema" in _ && _.inputJSONSchema ? _.inputJSONSchema : zodToJsonSchema(_.inputSchema)
1440
- }
1441
- })
1442
- )
1443
- );
1444
- const openaiSystem = system.map(
1445
- (s) => ({
1446
- role: "system",
1447
- content: s.text
1448
- })
1449
- );
1450
- const openaiMessages = convertAnthropicMessagesToOpenAIMessages(messages);
1451
- const startIncludingRetries = Date.now();
1452
- logSystemPromptConstruction({
1453
- basePrompt: systemPrompt.join("\n"),
1454
- mintoContext: generateMintoContext() || "",
1455
- reminders: [],
1456
- // 这里可以从 generateSystemReminders 获取
1457
- finalPrompt: systemPrompt.join("\n")
1458
- });
1459
- let start = Date.now();
1460
- let attemptNumber = 0;
1461
- let response;
1462
- try {
1463
- response = await withRetry(
1464
- async (attempt) => {
1465
- attemptNumber = attempt;
1466
- start = Date.now();
1467
- const maxTokens = getMaxTokensFromProfile(modelProfile);
1468
- const isGPT5 = isGPT5Model(model);
1469
- const opts = {
1470
- model,
1471
- ...isGPT5 ? { max_completion_tokens: maxTokens } : { max_tokens: maxTokens },
1472
- messages: [...openaiSystem, ...openaiMessages],
1473
- temperature: isGPT5 ? 1 : MAIN_QUERY_TEMPERATURE
1474
- };
1475
- if (config.stream) {
1476
- ;
1477
- opts.stream = true;
1478
- opts.stream_options = {
1479
- include_usage: true
1480
- };
1481
- }
1482
- if (toolSchemas.length > 0) {
1483
- opts.tools = toolSchemas;
1484
- opts.tool_choice = "auto";
1485
- }
1486
- const reasoningEffort = await getReasoningEffort(modelProfile, messages);
1487
- if (reasoningEffort) {
1488
- opts.reasoning_effort = reasoningEffort;
1489
- }
1490
- if (modelProfile && modelProfile.modelName) {
1491
- debugLogger.api("USING_MODEL_PROFILE_PATH", {
1492
- modelProfileName: modelProfile.modelName,
1493
- modelName: modelProfile.modelName,
1494
- provider: modelProfile.provider,
1495
- baseURL: modelProfile.baseURL,
1496
- apiKeyExists: !!modelProfile.apiKey,
1497
- requestId: getCurrentRequest()?.id
1498
- });
1499
- const USE_NEW_ADAPTER_SYSTEM = process.env.USE_NEW_ADAPTERS !== "false";
1500
- if (USE_NEW_ADAPTER_SYSTEM) {
1501
- const adapter = ModelAdapterFactory.createAdapter(modelProfile);
1502
- const unifiedParams = {
1503
- messages: openaiMessages,
1504
- systemPrompt: openaiSystem.map((s) => s.content),
1505
- tools,
1506
- maxTokens: getMaxTokensFromProfile(modelProfile),
1507
- stream: config.stream,
1508
- reasoningEffort,
1509
- temperature: isGPT5Model(model) ? 1 : MAIN_QUERY_TEMPERATURE,
1510
- previousResponseId: toolUseContext?.responseState?.previousResponseId,
1511
- verbosity: "high"
1512
- // High verbosity for coding tasks
1513
- };
1514
- const request = adapter.createRequest(unifiedParams);
1515
- if (ModelAdapterFactory.shouldUseResponsesAPI(modelProfile)) {
1516
- const { callGPT5ResponsesAPI } = await import("./openai.js");
1517
- const response2 = await callGPT5ResponsesAPI(
1518
- modelProfile,
1519
- request,
1520
- signal
1521
- );
1522
- const unifiedResponse = adapter.parseResponse(response2);
1523
- const apiMessage = {
1524
- role: "assistant",
1525
- content: unifiedResponse.content,
1526
- tool_calls: unifiedResponse.toolCalls,
1527
- usage: {
1528
- prompt_tokens: unifiedResponse.usage.promptTokens,
1529
- completion_tokens: unifiedResponse.usage.completionTokens
1530
- }
1531
- };
1532
- const assistantMsg = {
1533
- type: "assistant",
1534
- message: apiMessage,
1535
- costUSD: 0,
1536
- // Will be calculated later
1537
- durationMs: Date.now() - start,
1538
- uuid: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1539
- responseId: unifiedResponse.responseId
1540
- // For state management
1541
- };
1542
- return assistantMsg;
1543
- } else {
1544
- const s = await getCompletionWithProfile(
1545
- modelProfile,
1546
- request,
1547
- 0,
1548
- 10,
1549
- signal
1550
- );
1551
- let finalResponse;
1552
- if (config.stream) {
1553
- finalResponse = await handleMessageStream(
1554
- s,
1555
- signal
1556
- );
1557
- } else {
1558
- finalResponse = s;
1559
- }
1560
- const r = convertOpenAIResponseToAnthropic(finalResponse, tools);
1561
- return r;
1562
- }
1563
- } else {
1564
- const completionFunction = isGPT5Model(modelProfile.modelName) ? getGPT5CompletionWithProfile : getCompletionWithProfile;
1565
- const s = await completionFunction(
1566
- modelProfile,
1567
- opts,
1568
- 0,
1569
- 10,
1570
- signal
1571
- );
1572
- let finalResponse;
1573
- if (opts.stream) {
1574
- finalResponse = await handleMessageStream(
1575
- s,
1576
- signal
1577
- );
1578
- } else {
1579
- finalResponse = s;
1580
- }
1581
- const r = convertOpenAIResponseToAnthropic(finalResponse, tools);
1582
- return r;
1583
- }
1584
- } else {
1585
- debugLogger.api("USING_LEGACY_PATH", {
1586
- modelProfileExists: !!modelProfile,
1587
- modelProfileId: modelProfile?.modelName,
1588
- modelNameExists: !!modelProfile?.modelName,
1589
- fallbackModel: "main",
1590
- actualModel: model,
1591
- requestId: getCurrentRequest()?.id
1592
- });
1593
- const errorDetails = {
1594
- modelProfileExists: !!modelProfile,
1595
- modelProfileId: modelProfile?.modelName,
1596
- modelNameExists: !!modelProfile?.modelName,
1597
- requestedModel: model,
1598
- requestId: getCurrentRequest()?.id
1599
- };
1600
- debugLogger.error("NO_VALID_MODEL_PROFILE", errorDetails);
1601
- throw new Error(
1602
- `No valid ModelProfile available for model: ${model}. Please configure model through /model command. Debug: ${JSON.stringify(errorDetails)}`
1603
- );
1604
- }
1605
- },
1606
- {
1607
- signal,
1608
- // Pass retry events to agent transcript for UI display
1609
- onRetry: toolUseContext?.agentId ? ({ attempt, maxRetries, error, delayMs }) => {
1610
- addRetryEventToTranscript(toolUseContext.agentId, {
1611
- attempt,
1612
- maxRetries,
1613
- errorMessage: error.message,
1614
- delayMs
1615
- });
1616
- } : void 0
1617
- }
1618
- );
1619
- } catch (error) {
1620
- logError(error);
1621
- return getAssistantMessageFromError(error);
1622
- }
1623
- const durationMs = Date.now() - start;
1624
- const durationMsIncludingRetries = Date.now() - startIncludingRetries;
1625
- const inputTokens = response.usage?.prompt_tokens ?? 0;
1626
- const outputTokens = response.usage?.completion_tokens ?? 0;
1627
- const cacheReadInputTokens = response.usage?.prompt_token_details?.cached_tokens ?? 0;
1628
- const cacheCreationInputTokens = response.usage?.prompt_token_details?.cached_tokens ?? 0;
1629
- const costUSD = inputTokens / 1e6 * SONNET_COST_PER_MILLION_INPUT_TOKENS + outputTokens / 1e6 * SONNET_COST_PER_MILLION_OUTPUT_TOKENS + cacheReadInputTokens / 1e6 * SONNET_COST_PER_MILLION_PROMPT_CACHE_READ_TOKENS + cacheCreationInputTokens / 1e6 * SONNET_COST_PER_MILLION_PROMPT_CACHE_WRITE_TOKENS;
1630
- addToTotalCost(costUSD, durationMsIncludingRetries);
1631
- recordTokenUsage(
1632
- {
1633
- inputTokens,
1634
- outputTokens,
1635
- cacheCreationTokens: cacheCreationInputTokens,
1636
- cacheReadTokens: cacheReadInputTokens
1637
- },
1638
- costUSD,
1639
- model,
1640
- toolUseContext ? {
1641
- agentId: toolUseContext.agentId,
1642
- toolUseId: toolUseContext.toolUseId,
1643
- model
1644
- } : void 0
1645
- );
1646
- logLLMInteraction({
1647
- systemPrompt: systemPrompt.join("\n"),
1648
- messages: [...openaiSystem, ...openaiMessages],
1649
- response,
1650
- usage: {
1651
- inputTokens,
1652
- outputTokens
1653
- },
1654
- timing: {
1655
- start,
1656
- end: Date.now()
1657
- },
1658
- apiFormat: "openai"
1659
- });
1660
- return {
1661
- message: {
1662
- ...response,
1663
- content: normalizeContentFromAPI(response.content),
1664
- usage: {
1665
- input_tokens: inputTokens,
1666
- output_tokens: outputTokens,
1667
- cache_read_input_tokens: cacheReadInputTokens,
1668
- cache_creation_input_tokens: 0
1669
- }
1670
- },
1671
- costUSD,
1672
- durationMs,
1673
- type: "assistant",
1674
- uuid: randomUUID()
1675
- };
1676
- }
1677
- function getMaxTokensFromProfile(modelProfile) {
1678
- return modelProfile?.maxTokens || 8e3;
1679
- }
1680
- function getModelInputTokenCostUSD(model) {
1681
- for (const providerModels of Object.values(models)) {
1682
- const modelInfo = providerModels.find((m) => m.model === model);
1683
- if (modelInfo) {
1684
- return modelInfo.input_cost_per_token || 0;
1685
- }
1686
- }
1687
- return 3e-6;
1688
- }
1689
- function getModelOutputTokenCostUSD(model) {
1690
- for (const providerModels of Object.values(models)) {
1691
- const modelInfo = providerModels.find((m) => m.model === model);
1692
- if (modelInfo) {
1693
- return modelInfo.output_cost_per_token || 0;
1694
- }
1695
- }
1696
- return 15e-6;
1697
- }
1698
- async function queryModel(modelPointer, messages, systemPrompt = [], signal) {
1699
- return queryLLM(
1700
- messages,
1701
- systemPrompt,
1702
- 0,
1703
- // maxThinkingTokens
1704
- [],
1705
- // tools
1706
- signal || new AbortController().signal,
1707
- {
1708
- safeMode: false,
1709
- model: modelPointer,
1710
- prependCLISysprompt: true
1711
- }
1712
- );
1713
- }
1714
- async function queryQuick({
1715
- systemPrompt = [],
1716
- userPrompt,
1717
- assistantPrompt,
1718
- enablePromptCaching = false,
1719
- signal
1720
- }) {
1721
- const messages = [
1722
- {
1723
- message: { role: "user", content: userPrompt },
1724
- type: "user",
1725
- uuid: randomUUID()
1726
- }
1727
- ];
1728
- return queryModel("quick", messages, systemPrompt, signal);
1729
- }
2
+ API_ERROR_MESSAGE_PREFIX,
3
+ PROMPT_TOO_LONG_ERROR_MESSAGE,
4
+ CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE,
5
+ INVALID_API_KEY_ERROR_MESSAGE,
6
+ NO_CONTENT_MESSAGE,
7
+ MAIN_QUERY_TEMPERATURE,
8
+ generateMintoContext,
9
+ refreshMintoContext,
10
+ fetchAnthropicModels,
11
+ verifyApiKey,
12
+ getAnthropicClient,
13
+ resetAnthropicClient,
14
+ userMessageToMessageParam,
15
+ assistantMessageToMessageParam,
16
+ queryLLM,
17
+ formatSystemPromptWithContext,
18
+ queryModel,
19
+ queryQuick
20
+ } from "./llm/index.js";
1730
21
  export {
1731
22
  API_ERROR_MESSAGE_PREFIX,
1732
23
  CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE,