@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
@@ -16,6 +16,8 @@ import {
16
16
  validateGPT5Config
17
17
  } from "../../services/gpt5ConnectionTest.js";
18
18
  import { SEMANTIC_COLORS } from "../../constants/colors.js";
19
+ import { isOpenAICompatibleProvider } from "../../constants/providers.js";
20
+ import { getEffectiveCapabilities } from "../../constants/providerRegistry.js";
19
21
  import { t } from "../../i18n/index.js";
20
22
  import { SimpleSelector } from "../SimpleSelector/SimpleSelector.js";
21
23
  import { InfoPanel } from "../InfoPanel/InfoPanel.js";
@@ -26,32 +28,20 @@ import {
26
28
  MAX_TOKENS_OPTIONS,
27
29
  DEFAULT_MAX_TOKENS
28
30
  } from "./constants.js";
29
- function printModelConfig() {
30
- const config = getGlobalConfig();
31
- const modelProfiles = config.modelProfiles || [];
32
- const activeProfiles = modelProfiles.filter((p) => p.isActive);
33
- if (activeProfiles.length === 0) {
34
- return;
35
- }
36
- }
37
31
  function ModelSelector({
38
32
  onDone: onDoneProp,
39
33
  abortController,
40
34
  targetPointer,
41
35
  isOnboarding = false,
42
36
  onCancel,
43
- skipModelType = false
37
+ skipModelType = false,
38
+ editingModel
44
39
  }) {
45
40
  const config = getGlobalConfig();
46
- const onDone = () => {
47
- printModelConfig();
48
- onDoneProp();
49
- };
41
+ const onDone = onDoneProp;
50
42
  useExitOnCtrlCD(() => process.exit(0));
51
- const getInitialScreen = () => {
52
- return "provider";
53
- };
54
- const [screenStack, setScreenStack] = useState([getInitialScreen()]);
43
+ const isEditMode = !!editingModel;
44
+ const [screenStack, setScreenStack] = useState([isEditMode ? "testAndSave" : "provider"]);
55
45
  const currentScreen = screenStack[screenStack.length - 1];
56
46
  const navigateTo = (screen) => {
57
47
  setScreenStack((prev) => [...prev, screen]);
@@ -64,22 +54,26 @@ function ModelSelector({
64
54
  }
65
55
  };
66
56
  const [selectedProvider, setSelectedProvider] = useState(
67
- config.primaryProvider ?? "anthropic"
57
+ editingModel?.provider ?? config.primaryProvider ?? "anthropic"
68
58
  );
69
59
  const [anthropicProviderType, setAnthropicProviderType] = useState("official");
70
- const [selectedModel, setSelectedModel] = useState("");
71
- const [apiKey, setApiKey] = useState("");
60
+ const [selectedModel, setSelectedModel] = useState(
61
+ editingModel?.modelName ?? ""
62
+ );
63
+ const [apiKey, setApiKey] = useState(editingModel?.apiKey ?? "");
72
64
  const [maxTokens, setMaxTokens] = useState(
73
- config.maxTokens?.toString() || DEFAULT_MAX_TOKENS.toString()
65
+ editingModel?.maxTokens?.toString() ?? config.maxTokens?.toString() ?? DEFAULT_MAX_TOKENS.toString()
74
66
  );
75
67
  const [maxTokensMode, setMaxTokensMode] = useState(
76
68
  "preset"
77
69
  );
78
70
  const [selectedMaxTokensPreset, setSelectedMaxTokensPreset] = useState(config.maxTokens || DEFAULT_MAX_TOKENS);
79
- const [reasoningEffort, setReasoningEffort] = useState("medium");
80
- const [supportsReasoningEffort, setSupportsReasoningEffort] = useState(false);
71
+ const [reasoningEffort, setReasoningEffort] = useState(
72
+ editingModel?.reasoningEffort ?? "medium"
73
+ );
74
+ const [supportsReasoningEffort, setSupportsReasoningEffort] = useState(!!editingModel?.reasoningEffort);
81
75
  const [contextLength, setContextLength] = useState(
82
- DEFAULT_CONTEXT_LENGTH
76
+ editingModel?.contextLength ?? DEFAULT_CONTEXT_LENGTH
83
77
  );
84
78
  const [activeFieldIndex, setActiveFieldIndex] = useState(0);
85
79
  const [maxTokensCursorOffset, setMaxTokensCursorOffset] = useState(0);
@@ -89,12 +83,13 @@ function ModelSelector({
89
83
  const [modelSearchQuery, setModelSearchQuery] = useState("");
90
84
  const [modelSearchCursorOffset, setModelSearchCursorOffset] = useState(0);
91
85
  const [cursorOffset, setCursorOffset] = useState(0);
92
- const [apiKeyEdited, setApiKeyEdited] = useState(false);
86
+ const [apiKeyEdited, setApiKeyEdited] = useState(isEditMode);
93
87
  const [fetchRetryCount, setFetchRetryCount] = useState(0);
94
88
  const [isRetrying, setIsRetrying] = useState(false);
95
89
  const [isTestingConnection, setIsTestingConnection] = useState(false);
96
90
  const [connectionTestResult, setConnectionTestResult] = useState(null);
97
91
  const [validationError, setValidationError] = useState(null);
92
+ const [isManualModelEntry, setIsManualModelEntry] = useState(false);
98
93
  const [resourceName, setResourceName] = useState("");
99
94
  const [resourceNameCursorOffset, setResourceNameCursorOffset] = useState(0);
100
95
  const [customModelName, setCustomModelName] = useState("");
@@ -105,7 +100,9 @@ function ModelSelector({
105
100
  const [ollamaBaseUrlCursorOffset, setOllamaBaseUrlCursorOffset] = useState(0);
106
101
  const [customBaseUrl, setCustomBaseUrl] = useState("");
107
102
  const [customBaseUrlCursorOffset, setCustomBaseUrlCursorOffset] = useState(0);
108
- const [providerBaseUrl, setProviderBaseUrl] = useState("");
103
+ const [providerBaseUrl, setProviderBaseUrl] = useState(
104
+ editingModel?.baseURL ?? ""
105
+ );
109
106
  const [providerBaseUrlCursorOffset, setProviderBaseUrlCursorOffset] = useState(0);
110
107
  const reasoningEffortOptions = [
111
108
  { label: "Low - Faster responses, less thorough reasoning", value: "low" },
@@ -142,6 +139,11 @@ function ModelSelector({
142
139
  setContextLength(DEFAULT_CONTEXT_LENGTH);
143
140
  }
144
141
  }, [currentScreen, contextLength]);
142
+ useEffect(() => {
143
+ if (currentScreen === "testAndSave" && !isEditMode && !isTestingConnection && !connectionTestResult) {
144
+ handleConnectionTest();
145
+ }
146
+ }, [currentScreen]);
145
147
  const ourModelNames = new Set(
146
148
  (models[selectedProvider] || []).map(
147
149
  (model) => model.model
@@ -234,7 +236,8 @@ function ModelSelector({
234
236
  "anthropic-version": "2023-06-01",
235
237
  "Content-Type": "application/json",
236
238
  Authorization: `Bearer ${apiKey2}`
237
- }
239
+ },
240
+ signal: AbortSignal.timeout(3e4)
238
241
  });
239
242
  if (!response.ok) {
240
243
  if (response.status === 401) {
@@ -608,7 +611,8 @@ function ModelSelector({
608
611
  async function fetchGeminiModels() {
609
612
  try {
610
613
  const response = await fetch(
611
- `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`
614
+ `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`,
615
+ { signal: AbortSignal.timeout(3e4) }
612
616
  );
613
617
  if (!response.ok) {
614
618
  const errorData = await response.json();
@@ -636,7 +640,9 @@ function ModelSelector({
636
640
  }
637
641
  async function fetchOllamaModels() {
638
642
  try {
639
- const response = await fetch(`${ollamaBaseUrl}/models`);
643
+ const response = await fetch(`${ollamaBaseUrl}/models`, {
644
+ signal: AbortSignal.timeout(3e4)
645
+ });
640
646
  if (!response.ok) {
641
647
  throw new Error(`HTTP error ${response.status}: ${response.statusText}`);
642
648
  }
@@ -718,7 +724,8 @@ function ModelSelector({
718
724
  const showResp = await fetch(`${ollamaRoot}/api/show`, {
719
725
  method: "POST",
720
726
  headers: { "Content-Type": "application/json" },
721
- body: JSON.stringify({ name: m.model })
727
+ body: JSON.stringify({ name: m.model }),
728
+ signal: AbortSignal.timeout(3e4)
722
729
  });
723
730
  if (showResp.ok) {
724
731
  const showData = await showResp.json();
@@ -906,6 +913,10 @@ function ModelSelector({
906
913
  }
907
914
  function handleApiKeySubmit(key) {
908
915
  setApiKey(key);
916
+ if (isEditMode) {
917
+ goBack();
918
+ return;
919
+ }
909
920
  if (selectedProvider === "azure") {
910
921
  navigateTo("resourceName");
911
922
  return;
@@ -928,11 +939,20 @@ function ModelSelector({
928
939
  function handleCustomBaseUrlSubmit(url) {
929
940
  const cleanUrl = url.replace(/\/+$/, "");
930
941
  setCustomBaseUrl(cleanUrl);
942
+ setProviderBaseUrl(cleanUrl);
943
+ if (isEditMode) {
944
+ goBack();
945
+ return;
946
+ }
931
947
  navigateTo("apiKey");
932
948
  }
933
949
  function handleProviderBaseUrlSubmit(url) {
934
950
  const cleanUrl = url.replace(/\/+$/, "");
935
951
  setProviderBaseUrl(cleanUrl);
952
+ if (isEditMode) {
953
+ goBack();
954
+ return;
955
+ }
936
956
  if (selectedProvider === "ollama") {
937
957
  setOllamaBaseUrl(cleanUrl);
938
958
  setIsLoadingModels(true);
@@ -962,6 +982,7 @@ function ModelSelector({
962
982
  function handleCustomModelSubmit(model) {
963
983
  setCustomModelName(model);
964
984
  setSelectedModel(model);
985
+ setIsManualModelEntry(true);
965
986
  setSupportsReasoningEffort(false);
966
987
  setReasoningEffort(null);
967
988
  setMaxTokensMode("preset");
@@ -973,6 +994,7 @@ function ModelSelector({
973
994
  }
974
995
  function handleModelSelection(model) {
975
996
  setSelectedModel(model);
997
+ setIsManualModelEntry(false);
976
998
  const modelInfo = availableModels.find((m) => m.model === model);
977
999
  setSupportsReasoningEffort(modelInfo?.supports_reasoning_effort || false);
978
1000
  if (!modelInfo?.supports_reasoning_effort) {
@@ -1007,6 +1029,17 @@ function ModelSelector({
1007
1029
  setActiveFieldIndex(0);
1008
1030
  }
1009
1031
  const handleModelParamsSubmit = () => {
1032
+ if (isEditMode) {
1033
+ goBack();
1034
+ return;
1035
+ }
1036
+ if (!isManualModelEntry) {
1037
+ const modelInfo = availableModels.find((m) => m.model === selectedModel);
1038
+ if (modelInfo?.context_length || modelInfo?.max_input_tokens) {
1039
+ navigateTo("testAndSave");
1040
+ return;
1041
+ }
1042
+ }
1010
1043
  if (!CONTEXT_LENGTH_OPTIONS.find((opt) => opt.value === contextLength)) {
1011
1044
  setContextLength(DEFAULT_CONTEXT_LENGTH);
1012
1045
  }
@@ -1022,21 +1055,7 @@ function ModelSelector({
1022
1055
  } else if (selectedProvider === "custom-openai") {
1023
1056
  testBaseURL = customBaseUrl;
1024
1057
  }
1025
- const isOpenAICompatible = [
1026
- "minimax",
1027
- "kimi",
1028
- "deepseek",
1029
- "siliconflow",
1030
- "qwen",
1031
- "glm",
1032
- "baidu-qianfan",
1033
- "openai",
1034
- "mistral",
1035
- "xai",
1036
- "groq",
1037
- "custom-openai"
1038
- ].includes(selectedProvider);
1039
- if (isOpenAICompatible) {
1058
+ if (isOpenAICompatibleProvider(selectedProvider)) {
1040
1059
  const isGPT5 = selectedModel?.toLowerCase().includes("gpt-5");
1041
1060
  if (isGPT5) {
1042
1061
  const configValidation = validateGPT5Config({
@@ -1131,13 +1150,19 @@ function ModelSelector({
1131
1150
  temperature: 0,
1132
1151
  stream: false
1133
1152
  };
1134
- if (selectedModel && selectedModel.toLowerCase().includes("gpt-5")) {
1135
- if (testPayload.max_tokens) {
1136
- testPayload.max_completion_tokens = testPayload.max_tokens;
1153
+ if (selectedModel && selectedProvider) {
1154
+ const caps = getEffectiveCapabilities(selectedProvider, selectedModel);
1155
+ if (caps.maxTokensField !== "max_tokens" && testPayload.max_tokens) {
1156
+ testPayload[caps.maxTokensField] = testPayload.max_tokens;
1137
1157
  delete testPayload.max_tokens;
1138
1158
  }
1139
- if (testPayload.temperature !== void 0 && testPayload.temperature !== 1) {
1140
- testPayload.temperature = 1;
1159
+ if (caps.temperatureRange === "omit") {
1160
+ delete testPayload.temperature;
1161
+ } else if (typeof caps.temperatureRange === "object") {
1162
+ testPayload.temperature = Math.min(
1163
+ testPayload.temperature,
1164
+ caps.temperatureRange.max
1165
+ );
1141
1166
  }
1142
1167
  }
1143
1168
  const headers = {
@@ -1152,7 +1177,8 @@ function ModelSelector({
1152
1177
  const response = await fetch(testURL, {
1153
1178
  method: "POST",
1154
1179
  headers,
1155
- body: JSON.stringify(testPayload)
1180
+ body: JSON.stringify(testPayload),
1181
+ signal: AbortSignal.timeout(3e4)
1156
1182
  });
1157
1183
  if (response.ok) {
1158
1184
  const data = await response.json();
@@ -1226,7 +1252,8 @@ function ModelSelector({
1226
1252
  const response = await fetch(testURL, {
1227
1253
  method: "POST",
1228
1254
  headers,
1229
- body: JSON.stringify(testPayload)
1255
+ body: JSON.stringify(testPayload),
1256
+ signal: AbortSignal.timeout(3e4)
1230
1257
  });
1231
1258
  if (response.ok) {
1232
1259
  const data = await response.json();
@@ -1326,14 +1353,13 @@ function ModelSelector({
1326
1353
  async function handleConnectionTest() {
1327
1354
  const result = await testConnection();
1328
1355
  setConnectionTestResult(result);
1329
- if (result.success) {
1330
- setTimeout(() => {
1331
- navigateTo("confirmation");
1332
- }, 2e3);
1333
- }
1334
1356
  }
1335
1357
  const handleContextLengthSubmit = () => {
1336
- navigateTo("connectionTest");
1358
+ if (isEditMode) {
1359
+ goBack();
1360
+ return;
1361
+ }
1362
+ navigateTo("testAndSave");
1337
1363
  };
1338
1364
  async function saveConfiguration(provider, model) {
1339
1365
  let baseURL = providerBaseUrl || providers[provider]?.baseURL || "";
@@ -1380,6 +1406,24 @@ function ModelSelector({
1380
1406
  }
1381
1407
  async function handleConfirmation() {
1382
1408
  setValidationError(null);
1409
+ if (isEditMode && editingModel) {
1410
+ try {
1411
+ const modelManager = getModelManager();
1412
+ modelManager.updateModel(editingModel.modelName, {
1413
+ baseURL: providerBaseUrl || editingModel.baseURL,
1414
+ apiKey: apiKey || editingModel.apiKey,
1415
+ maxTokens: parseInt(maxTokens) || editingModel.maxTokens,
1416
+ contextLength: contextLength || editingModel.contextLength,
1417
+ reasoningEffort
1418
+ });
1419
+ onDone();
1420
+ } catch (error) {
1421
+ setValidationError(
1422
+ error instanceof Error ? error.message : "Failed to update model"
1423
+ );
1424
+ }
1425
+ return;
1426
+ }
1383
1427
  const modelId = await saveConfiguration(selectedProvider, selectedModel);
1384
1428
  if (!modelId) {
1385
1429
  return;
@@ -1401,6 +1445,11 @@ function ModelSelector({
1401
1445
  onDone();
1402
1446
  }
1403
1447
  } else {
1448
+ if (currentScreen === "testAndSave") {
1449
+ setConnectionTestResult(null);
1450
+ setIsTestingConnection(false);
1451
+ setValidationError(null);
1452
+ }
1404
1453
  const prevScreen = screenStack[screenStack.length - 2];
1405
1454
  if (prevScreen === "modelParams") {
1406
1455
  const formFields = getFormFieldsForModelParams();
@@ -1764,84 +1813,104 @@ function ModelSelector({
1764
1813
  }
1765
1814
  );
1766
1815
  }
1767
- if (currentScreen === "connectionTest") {
1816
+ if (currentScreen === "testAndSave") {
1768
1817
  const providerDisplayName = getProviderLabel(selectedProvider, 0).split(
1769
1818
  " ("
1770
1819
  )[0];
1771
- const testSections = [
1772
- {
1773
- title: t("modelSelector.connectionTestDesc"),
1774
- items: [
1775
- { label: "Provider", value: providerDisplayName },
1776
- { label: "Model", value: selectedModel },
1777
- ...connectionTestResult ? [
1778
- {
1779
- label: "Status",
1780
- value: connectionTestResult.message,
1781
- valueColor: connectionTestResult.success ? SEMANTIC_COLORS.success : SEMANTIC_COLORS.error
1782
- },
1783
- ...connectionTestResult.endpoint ? [
1784
- {
1785
- label: "Endpoint",
1786
- value: connectionTestResult.endpoint
1787
- }
1788
- ] : [],
1789
- ...connectionTestResult.details ? [
1790
- {
1791
- label: "Details",
1792
- value: connectionTestResult.details
1793
- }
1794
- ] : []
1795
- ] : []
1796
- ]
1820
+ const showsApiKey = selectedProvider !== "ollama";
1821
+ const contextLengthLabel = CONTEXT_LENGTH_OPTIONS.find((opt) => opt.value === contextLength)?.label || `${contextLength.toLocaleString()} tokens`;
1822
+ if (isEditMode) {
1823
+ const editItems = [];
1824
+ if (showsApiKey) {
1825
+ editItems.push({
1826
+ id: "__edit_apiKey__",
1827
+ label: "API Key",
1828
+ description: apiKey ? `****${apiKey.slice(-4)}` : "(not set)",
1829
+ category: t("modelSelector.testAndSaveDesc")
1830
+ });
1797
1831
  }
1798
- ];
1799
- const testActions = [];
1800
- if (!isTestingConnection && !connectionTestResult) {
1801
- testActions.push({
1802
- key: "return",
1803
- keyLabel: "Enter",
1804
- description: t("modelSelector.connectionTestStart"),
1805
- onPress: () => handleConnectionTest()
1832
+ if (selectedProvider === "custom-openai" || providerBaseUrl !== providers[selectedProvider]?.baseURL) {
1833
+ editItems.push({
1834
+ id: "__edit_baseUrl__",
1835
+ label: "Base URL",
1836
+ description: providerBaseUrl || customBaseUrl || "(not set)",
1837
+ category: t("modelSelector.testAndSaveDesc")
1838
+ });
1839
+ }
1840
+ editItems.push({
1841
+ id: "__edit_modelParams__",
1842
+ label: "Max Tokens",
1843
+ description: maxTokens,
1844
+ category: t("modelSelector.testAndSaveDesc")
1806
1845
  });
1807
- } else if (connectionTestResult && connectionTestResult.success) {
1808
- testActions.push({
1809
- key: "return",
1810
- keyLabel: "Enter",
1811
- description: t("modelSelector.continue"),
1812
- onPress: () => navigateTo("confirmation")
1846
+ editItems.push({
1847
+ id: "__edit_contextLength__",
1848
+ label: "Context Length",
1849
+ description: contextLengthLabel,
1850
+ category: t("modelSelector.testAndSaveDesc")
1813
1851
  });
1814
- } else if (connectionTestResult && !connectionTestResult.success) {
1815
- testActions.push({
1816
- key: "return",
1817
- keyLabel: "Enter",
1818
- description: t("modelSelector.connectionTestRetry"),
1819
- onPress: () => handleConnectionTest()
1852
+ if (connectionTestResult) {
1853
+ editItems.push({
1854
+ id: "__test_status__",
1855
+ label: "Connection",
1856
+ description: connectionTestResult.message,
1857
+ statusIcon: connectionTestResult.success ? "\u2713" : "\u2715",
1858
+ statusColor: connectionTestResult.success ? SEMANTIC_COLORS.success : SEMANTIC_COLORS.error,
1859
+ category: t("modelSelector.testAndSaveDesc")
1860
+ });
1861
+ }
1862
+ editItems.push({
1863
+ id: "__save__",
1864
+ label: t("modelSelector.confirmationSave"),
1865
+ category: t("commands.model.actionsCategory"),
1866
+ statusIcon: "\u2713",
1867
+ statusColor: SEMANTIC_COLORS.success
1820
1868
  });
1869
+ editItems.push({
1870
+ id: "__test__",
1871
+ label: t("modelSelector.connectionTestRetry"),
1872
+ category: t("commands.model.actionsCategory")
1873
+ });
1874
+ const editTitle = t("commands.model.editTitle").replace(
1875
+ "{model}",
1876
+ editingModel?.name ?? selectedModel
1877
+ );
1878
+ const editOverlay = isTestingConnection ? {
1879
+ type: "loading",
1880
+ message: t("modelSelector.autoTesting")
1881
+ } : validationError ? { type: "error", message: validationError } : null;
1882
+ return /* @__PURE__ */ React.createElement(
1883
+ SimpleSelector,
1884
+ {
1885
+ title: editTitle,
1886
+ items: editItems,
1887
+ groupByCategory: true,
1888
+ onSelect: (item) => {
1889
+ if (item.id === "__edit_apiKey__") {
1890
+ navigateTo("apiKey");
1891
+ } else if (item.id === "__edit_baseUrl__") {
1892
+ navigateTo("baseUrl");
1893
+ } else if (item.id === "__edit_modelParams__") {
1894
+ setActiveFieldIndex(0);
1895
+ navigateTo("modelParams");
1896
+ } else if (item.id === "__edit_contextLength__") {
1897
+ navigateTo("contextLength");
1898
+ } else if (item.id === "__save__") {
1899
+ handleConfirmation().catch((error) => {
1900
+ setValidationError(
1901
+ error instanceof Error ? error.message : "Unexpected error occurred"
1902
+ );
1903
+ });
1904
+ } else if (item.id === "__test__") {
1905
+ setConnectionTestResult(null);
1906
+ handleConnectionTest();
1907
+ }
1908
+ },
1909
+ onClose: handleBack,
1910
+ statusOverlay: editOverlay
1911
+ }
1912
+ );
1821
1913
  }
1822
- const testOverlay = isTestingConnection ? {
1823
- type: "loading",
1824
- message: t("modelSelector.connectionTestRunning")
1825
- } : connectionTestResult?.success ? {
1826
- type: "success",
1827
- message: t("modelSelector.connectionTestAutoProceeding")
1828
- } : null;
1829
- return /* @__PURE__ */ React.createElement(
1830
- InfoPanel,
1831
- {
1832
- title: `${t("modelSelector.connectionTestTitle")} \u2014 ${providerDisplayName}`,
1833
- sections: testSections,
1834
- actions: testActions,
1835
- onClose: handleBack,
1836
- statusOverlay: testOverlay
1837
- }
1838
- );
1839
- }
1840
- if (currentScreen === "confirmation") {
1841
- const providerDisplayName = getProviderLabel(selectedProvider, 0).split(
1842
- " ("
1843
- )[0];
1844
- const showsApiKey = selectedProvider !== "ollama";
1845
1914
  const configItems = [
1846
1915
  { label: "Provider", value: providerDisplayName },
1847
1916
  ...selectedProvider === "azure" ? [{ label: "Resource Name", value: resourceName }] : [],
@@ -1850,20 +1919,30 @@ function ModelSelector({
1850
1919
  { label: "Model", value: selectedModel },
1851
1920
  ...apiKey && showsApiKey ? [{ label: "API Key", value: `****${apiKey.slice(-4)}` }] : [],
1852
1921
  ...maxTokens ? [{ label: "Max Tokens", value: maxTokens }] : [],
1853
- {
1854
- label: "Context Length",
1855
- value: CONTEXT_LENGTH_OPTIONS.find((opt) => opt.value === contextLength)?.label || `${contextLength.toLocaleString()} tokens`
1856
- },
1922
+ { label: "Context Length", value: contextLengthLabel },
1857
1923
  ...supportsReasoningEffort ? [{ label: "Reasoning Effort", value: reasoningEffort }] : []
1858
1924
  ];
1859
- const confirmSections = [
1925
+ if (connectionTestResult) {
1926
+ configItems.push({
1927
+ label: "Connection",
1928
+ value: connectionTestResult.message,
1929
+ valueColor: connectionTestResult.success ? SEMANTIC_COLORS.success : SEMANTIC_COLORS.error
1930
+ });
1931
+ if (connectionTestResult.details && !connectionTestResult.success) {
1932
+ configItems.push({
1933
+ label: "Details",
1934
+ value: connectionTestResult.details
1935
+ });
1936
+ }
1937
+ }
1938
+ const testAndSaveSections = [
1860
1939
  {
1861
- title: t("modelSelector.confirmationDesc"),
1940
+ title: t("modelSelector.testAndSaveDesc"),
1862
1941
  items: configItems
1863
1942
  }
1864
1943
  ];
1865
1944
  if (validationError) {
1866
- confirmSections.unshift({
1945
+ testAndSaveSections.unshift({
1867
1946
  title: t("modelSelector.configError"),
1868
1947
  items: [
1869
1948
  {
@@ -1874,8 +1953,9 @@ function ModelSelector({
1874
1953
  ]
1875
1954
  });
1876
1955
  }
1877
- const confirmActions = [
1878
- {
1956
+ const testAndSaveActions = [];
1957
+ if (connectionTestResult?.success) {
1958
+ testAndSaveActions.push({
1879
1959
  key: "return",
1880
1960
  keyLabel: "Enter",
1881
1961
  description: t("modelSelector.confirmationSave"),
@@ -1886,15 +1966,42 @@ function ModelSelector({
1886
1966
  );
1887
1967
  });
1888
1968
  }
1889
- }
1890
- ];
1969
+ });
1970
+ } else if (connectionTestResult && !connectionTestResult.success) {
1971
+ testAndSaveActions.push({
1972
+ key: "return",
1973
+ keyLabel: "Enter",
1974
+ description: t("modelSelector.connectionTestRetry"),
1975
+ onPress: () => {
1976
+ setConnectionTestResult(null);
1977
+ handleConnectionTest();
1978
+ }
1979
+ });
1980
+ testAndSaveActions.push({
1981
+ key: "s",
1982
+ keyLabel: "s",
1983
+ description: t("modelSelector.saveAnyway"),
1984
+ onPress: () => {
1985
+ handleConfirmation().catch((error) => {
1986
+ setValidationError(
1987
+ error instanceof Error ? error.message : "Unexpected error occurred"
1988
+ );
1989
+ });
1990
+ }
1991
+ });
1992
+ }
1993
+ const testAndSaveOverlay = isTestingConnection ? {
1994
+ type: "loading",
1995
+ message: t("modelSelector.autoTesting")
1996
+ } : null;
1891
1997
  return /* @__PURE__ */ React.createElement(
1892
1998
  InfoPanel,
1893
1999
  {
1894
- title: t("modelSelector.confirmationTitle"),
1895
- sections: confirmSections,
1896
- actions: confirmActions,
1897
- onClose: handleBack
2000
+ title: t("modelSelector.testAndSaveTitle"),
2001
+ sections: testAndSaveSections,
2002
+ actions: testAndSaveActions,
2003
+ onClose: handleBack,
2004
+ statusOverlay: testAndSaveOverlay
1898
2005
  }
1899
2006
  );
1900
2007
  }