@shareai-lab/kode 1.1.13 → 1.1.16

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 (288) hide show
  1. package/dist/entrypoints/cli.js +2 -1
  2. package/dist/entrypoints/cli.js.map +2 -2
  3. package/dist/index.js +5 -26
  4. package/dist/package.json +4 -1
  5. package/package.json +9 -104
  6. package/dist/test/testAdapters.js +0 -88
  7. package/dist/test/testAdapters.js.map +0 -1
  8. package/src/ProjectOnboarding.tsx +0 -198
  9. package/src/Tool.ts +0 -83
  10. package/src/commands/agents.tsx +0 -3416
  11. package/src/commands/approvedTools.ts +0 -53
  12. package/src/commands/bug.tsx +0 -20
  13. package/src/commands/clear.ts +0 -43
  14. package/src/commands/compact.ts +0 -120
  15. package/src/commands/config.tsx +0 -19
  16. package/src/commands/cost.ts +0 -18
  17. package/src/commands/ctx_viz.ts +0 -209
  18. package/src/commands/doctor.ts +0 -24
  19. package/src/commands/help.tsx +0 -19
  20. package/src/commands/init.ts +0 -37
  21. package/src/commands/listen.ts +0 -42
  22. package/src/commands/login.tsx +0 -51
  23. package/src/commands/logout.tsx +0 -40
  24. package/src/commands/mcp.ts +0 -41
  25. package/src/commands/model.tsx +0 -40
  26. package/src/commands/modelstatus.tsx +0 -20
  27. package/src/commands/onboarding.tsx +0 -34
  28. package/src/commands/pr_comments.ts +0 -59
  29. package/src/commands/refreshCommands.ts +0 -54
  30. package/src/commands/release-notes.ts +0 -34
  31. package/src/commands/resume.tsx +0 -31
  32. package/src/commands/review.ts +0 -49
  33. package/src/commands/terminalSetup.ts +0 -221
  34. package/src/commands.ts +0 -139
  35. package/src/components/ApproveApiKey.tsx +0 -93
  36. package/src/components/AsciiLogo.tsx +0 -13
  37. package/src/components/AutoUpdater.tsx +0 -148
  38. package/src/components/Bug.tsx +0 -367
  39. package/src/components/Config.tsx +0 -293
  40. package/src/components/ConsoleOAuthFlow.tsx +0 -327
  41. package/src/components/Cost.tsx +0 -23
  42. package/src/components/CostThresholdDialog.tsx +0 -46
  43. package/src/components/CustomSelect/option-map.ts +0 -42
  44. package/src/components/CustomSelect/select-option.tsx +0 -78
  45. package/src/components/CustomSelect/select.tsx +0 -152
  46. package/src/components/CustomSelect/theme.ts +0 -45
  47. package/src/components/CustomSelect/use-select-state.ts +0 -414
  48. package/src/components/CustomSelect/use-select.ts +0 -35
  49. package/src/components/FallbackToolUseRejectedMessage.tsx +0 -15
  50. package/src/components/FileEditToolUpdatedMessage.tsx +0 -66
  51. package/src/components/Help.tsx +0 -215
  52. package/src/components/HighlightedCode.tsx +0 -33
  53. package/src/components/InvalidConfigDialog.tsx +0 -113
  54. package/src/components/Link.tsx +0 -32
  55. package/src/components/LogSelector.tsx +0 -86
  56. package/src/components/Logo.tsx +0 -170
  57. package/src/components/MCPServerApprovalDialog.tsx +0 -100
  58. package/src/components/MCPServerDialogCopy.tsx +0 -25
  59. package/src/components/MCPServerMultiselectDialog.tsx +0 -109
  60. package/src/components/Message.tsx +0 -221
  61. package/src/components/MessageResponse.tsx +0 -15
  62. package/src/components/MessageSelector.tsx +0 -211
  63. package/src/components/ModeIndicator.tsx +0 -88
  64. package/src/components/ModelConfig.tsx +0 -301
  65. package/src/components/ModelListManager.tsx +0 -227
  66. package/src/components/ModelSelector.tsx +0 -3387
  67. package/src/components/ModelStatusDisplay.tsx +0 -230
  68. package/src/components/Onboarding.tsx +0 -274
  69. package/src/components/PressEnterToContinue.tsx +0 -11
  70. package/src/components/PromptInput.tsx +0 -760
  71. package/src/components/SentryErrorBoundary.ts +0 -39
  72. package/src/components/Spinner.tsx +0 -129
  73. package/src/components/StickerRequestForm.tsx +0 -16
  74. package/src/components/StructuredDiff.tsx +0 -191
  75. package/src/components/TextInput.tsx +0 -259
  76. package/src/components/TodoItem.tsx +0 -47
  77. package/src/components/TokenWarning.tsx +0 -31
  78. package/src/components/ToolUseLoader.tsx +0 -40
  79. package/src/components/TrustDialog.tsx +0 -106
  80. package/src/components/binary-feedback/BinaryFeedback.tsx +0 -63
  81. package/src/components/binary-feedback/BinaryFeedbackOption.tsx +0 -111
  82. package/src/components/binary-feedback/BinaryFeedbackView.tsx +0 -172
  83. package/src/components/binary-feedback/utils.ts +0 -220
  84. package/src/components/messages/AssistantBashOutputMessage.tsx +0 -22
  85. package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +0 -49
  86. package/src/components/messages/AssistantRedactedThinkingMessage.tsx +0 -19
  87. package/src/components/messages/AssistantTextMessage.tsx +0 -144
  88. package/src/components/messages/AssistantThinkingMessage.tsx +0 -40
  89. package/src/components/messages/AssistantToolUseMessage.tsx +0 -132
  90. package/src/components/messages/TaskProgressMessage.tsx +0 -32
  91. package/src/components/messages/TaskToolMessage.tsx +0 -58
  92. package/src/components/messages/UserBashInputMessage.tsx +0 -28
  93. package/src/components/messages/UserCommandMessage.tsx +0 -30
  94. package/src/components/messages/UserKodingInputMessage.tsx +0 -28
  95. package/src/components/messages/UserPromptMessage.tsx +0 -35
  96. package/src/components/messages/UserTextMessage.tsx +0 -39
  97. package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +0 -12
  98. package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +0 -36
  99. package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +0 -31
  100. package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +0 -57
  101. package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +0 -35
  102. package/src/components/messages/UserToolResultMessage/utils.tsx +0 -56
  103. package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +0 -121
  104. package/src/components/permissions/FallbackPermissionRequest.tsx +0 -153
  105. package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +0 -182
  106. package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +0 -77
  107. package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +0 -164
  108. package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +0 -83
  109. package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +0 -240
  110. package/src/components/permissions/PermissionRequest.tsx +0 -101
  111. package/src/components/permissions/PermissionRequestTitle.tsx +0 -69
  112. package/src/components/permissions/hooks.ts +0 -44
  113. package/src/components/permissions/toolUseOptions.ts +0 -59
  114. package/src/components/permissions/utils.ts +0 -23
  115. package/src/constants/betas.ts +0 -5
  116. package/src/constants/claude-asterisk-ascii-art.tsx +0 -238
  117. package/src/constants/figures.ts +0 -4
  118. package/src/constants/keys.ts +0 -3
  119. package/src/constants/macros.ts +0 -11
  120. package/src/constants/modelCapabilities.ts +0 -179
  121. package/src/constants/models.ts +0 -1025
  122. package/src/constants/oauth.ts +0 -18
  123. package/src/constants/product.ts +0 -17
  124. package/src/constants/prompts.ts +0 -168
  125. package/src/constants/releaseNotes.ts +0 -7
  126. package/src/context/PermissionContext.tsx +0 -149
  127. package/src/context.ts +0 -278
  128. package/src/cost-tracker.ts +0 -84
  129. package/src/entrypoints/cli.tsx +0 -1561
  130. package/src/entrypoints/mcp.ts +0 -175
  131. package/src/history.ts +0 -25
  132. package/src/hooks/useApiKeyVerification.ts +0 -59
  133. package/src/hooks/useArrowKeyHistory.ts +0 -55
  134. package/src/hooks/useCanUseTool.ts +0 -138
  135. package/src/hooks/useCancelRequest.ts +0 -39
  136. package/src/hooks/useDoublePress.ts +0 -41
  137. package/src/hooks/useExitOnCtrlCD.ts +0 -31
  138. package/src/hooks/useInterval.ts +0 -25
  139. package/src/hooks/useLogMessages.ts +0 -16
  140. package/src/hooks/useLogStartupTime.ts +0 -12
  141. package/src/hooks/useNotifyAfterTimeout.ts +0 -65
  142. package/src/hooks/usePermissionRequestLogging.ts +0 -44
  143. package/src/hooks/useTerminalSize.ts +0 -49
  144. package/src/hooks/useTextInput.ts +0 -317
  145. package/src/hooks/useUnifiedCompletion.ts +0 -1405
  146. package/src/index.ts +0 -34
  147. package/src/messages.ts +0 -38
  148. package/src/permissions.ts +0 -268
  149. package/src/query.ts +0 -720
  150. package/src/screens/ConfigureNpmPrefix.tsx +0 -197
  151. package/src/screens/Doctor.tsx +0 -219
  152. package/src/screens/LogList.tsx +0 -68
  153. package/src/screens/REPL.tsx +0 -813
  154. package/src/screens/ResumeConversation.tsx +0 -68
  155. package/src/services/adapters/base.ts +0 -38
  156. package/src/services/adapters/chatCompletions.ts +0 -90
  157. package/src/services/adapters/responsesAPI.ts +0 -170
  158. package/src/services/browserMocks.ts +0 -66
  159. package/src/services/claude.ts +0 -2197
  160. package/src/services/customCommands.ts +0 -704
  161. package/src/services/fileFreshness.ts +0 -377
  162. package/src/services/gpt5ConnectionTest.ts +0 -340
  163. package/src/services/mcpClient.ts +0 -564
  164. package/src/services/mcpServerApproval.tsx +0 -50
  165. package/src/services/mentionProcessor.ts +0 -273
  166. package/src/services/modelAdapterFactory.ts +0 -69
  167. package/src/services/notifier.ts +0 -40
  168. package/src/services/oauth.ts +0 -357
  169. package/src/services/openai.ts +0 -1359
  170. package/src/services/responseStateManager.ts +0 -90
  171. package/src/services/sentry.ts +0 -3
  172. package/src/services/statsig.ts +0 -172
  173. package/src/services/statsigStorage.ts +0 -86
  174. package/src/services/systemReminder.ts +0 -507
  175. package/src/services/vcr.ts +0 -161
  176. package/src/test/testAdapters.ts +0 -96
  177. package/src/tools/ArchitectTool/ArchitectTool.tsx +0 -135
  178. package/src/tools/ArchitectTool/prompt.ts +0 -15
  179. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +0 -576
  180. package/src/tools/BashTool/BashTool.tsx +0 -243
  181. package/src/tools/BashTool/BashToolResultMessage.tsx +0 -38
  182. package/src/tools/BashTool/OutputLine.tsx +0 -49
  183. package/src/tools/BashTool/prompt.ts +0 -174
  184. package/src/tools/BashTool/utils.ts +0 -56
  185. package/src/tools/FileEditTool/FileEditTool.tsx +0 -319
  186. package/src/tools/FileEditTool/prompt.ts +0 -51
  187. package/src/tools/FileEditTool/utils.ts +0 -58
  188. package/src/tools/FileReadTool/FileReadTool.tsx +0 -404
  189. package/src/tools/FileReadTool/prompt.ts +0 -7
  190. package/src/tools/FileWriteTool/FileWriteTool.tsx +0 -301
  191. package/src/tools/FileWriteTool/prompt.ts +0 -10
  192. package/src/tools/GlobTool/GlobTool.tsx +0 -119
  193. package/src/tools/GlobTool/prompt.ts +0 -8
  194. package/src/tools/GrepTool/GrepTool.tsx +0 -147
  195. package/src/tools/GrepTool/prompt.ts +0 -11
  196. package/src/tools/MCPTool/MCPTool.tsx +0 -107
  197. package/src/tools/MCPTool/prompt.ts +0 -3
  198. package/src/tools/MemoryReadTool/MemoryReadTool.tsx +0 -127
  199. package/src/tools/MemoryReadTool/prompt.ts +0 -3
  200. package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +0 -89
  201. package/src/tools/MemoryWriteTool/prompt.ts +0 -3
  202. package/src/tools/MultiEditTool/MultiEditTool.tsx +0 -388
  203. package/src/tools/MultiEditTool/prompt.ts +0 -45
  204. package/src/tools/NotebookEditTool/NotebookEditTool.tsx +0 -298
  205. package/src/tools/NotebookEditTool/prompt.ts +0 -3
  206. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +0 -258
  207. package/src/tools/NotebookReadTool/prompt.ts +0 -3
  208. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +0 -107
  209. package/src/tools/StickerRequestTool/prompt.ts +0 -19
  210. package/src/tools/TaskTool/TaskTool.tsx +0 -438
  211. package/src/tools/TaskTool/constants.ts +0 -1
  212. package/src/tools/TaskTool/prompt.ts +0 -92
  213. package/src/tools/ThinkTool/ThinkTool.tsx +0 -54
  214. package/src/tools/ThinkTool/prompt.ts +0 -12
  215. package/src/tools/TodoWriteTool/TodoWriteTool.tsx +0 -313
  216. package/src/tools/TodoWriteTool/prompt.ts +0 -63
  217. package/src/tools/URLFetcherTool/URLFetcherTool.tsx +0 -178
  218. package/src/tools/URLFetcherTool/cache.ts +0 -55
  219. package/src/tools/URLFetcherTool/htmlToMarkdown.ts +0 -55
  220. package/src/tools/URLFetcherTool/prompt.ts +0 -17
  221. package/src/tools/WebSearchTool/WebSearchTool.tsx +0 -103
  222. package/src/tools/WebSearchTool/prompt.ts +0 -13
  223. package/src/tools/WebSearchTool/searchProviders.ts +0 -66
  224. package/src/tools/lsTool/lsTool.tsx +0 -272
  225. package/src/tools/lsTool/prompt.ts +0 -2
  226. package/src/tools.ts +0 -67
  227. package/src/types/PermissionMode.ts +0 -120
  228. package/src/types/RequestContext.ts +0 -72
  229. package/src/types/common.d.ts +0 -2
  230. package/src/types/conversation.ts +0 -51
  231. package/src/types/logs.ts +0 -58
  232. package/src/types/modelCapabilities.ts +0 -64
  233. package/src/types/notebook.ts +0 -87
  234. package/src/utils/Cursor.ts +0 -436
  235. package/src/utils/PersistentShell.ts +0 -552
  236. package/src/utils/advancedFuzzyMatcher.ts +0 -290
  237. package/src/utils/agentLoader.ts +0 -278
  238. package/src/utils/agentStorage.ts +0 -97
  239. package/src/utils/array.ts +0 -3
  240. package/src/utils/ask.tsx +0 -99
  241. package/src/utils/auth.ts +0 -13
  242. package/src/utils/autoCompactCore.ts +0 -223
  243. package/src/utils/autoUpdater.ts +0 -458
  244. package/src/utils/betas.ts +0 -20
  245. package/src/utils/browser.ts +0 -14
  246. package/src/utils/cleanup.ts +0 -72
  247. package/src/utils/commands.ts +0 -261
  248. package/src/utils/commonUnixCommands.ts +0 -161
  249. package/src/utils/config.ts +0 -945
  250. package/src/utils/conversationRecovery.ts +0 -55
  251. package/src/utils/debugLogger.ts +0 -1235
  252. package/src/utils/diff.ts +0 -42
  253. package/src/utils/env.ts +0 -57
  254. package/src/utils/errors.ts +0 -21
  255. package/src/utils/exampleCommands.ts +0 -109
  256. package/src/utils/execFileNoThrow.ts +0 -51
  257. package/src/utils/expertChatStorage.ts +0 -136
  258. package/src/utils/file.ts +0 -405
  259. package/src/utils/fileRecoveryCore.ts +0 -71
  260. package/src/utils/format.tsx +0 -44
  261. package/src/utils/fuzzyMatcher.ts +0 -328
  262. package/src/utils/generators.ts +0 -62
  263. package/src/utils/git.ts +0 -92
  264. package/src/utils/globalLogger.ts +0 -77
  265. package/src/utils/http.ts +0 -10
  266. package/src/utils/imagePaste.ts +0 -38
  267. package/src/utils/json.ts +0 -13
  268. package/src/utils/log.ts +0 -382
  269. package/src/utils/markdown.ts +0 -213
  270. package/src/utils/messageContextManager.ts +0 -294
  271. package/src/utils/messages.tsx +0 -945
  272. package/src/utils/model.ts +0 -914
  273. package/src/utils/permissions/filesystem.ts +0 -127
  274. package/src/utils/responseState.ts +0 -23
  275. package/src/utils/ripgrep.ts +0 -167
  276. package/src/utils/secureFile.ts +0 -564
  277. package/src/utils/sessionState.ts +0 -49
  278. package/src/utils/state.ts +0 -25
  279. package/src/utils/style.ts +0 -29
  280. package/src/utils/terminal.ts +0 -50
  281. package/src/utils/theme.ts +0 -127
  282. package/src/utils/thinking.ts +0 -144
  283. package/src/utils/todoStorage.ts +0 -431
  284. package/src/utils/tokens.ts +0 -43
  285. package/src/utils/toolExecutionController.ts +0 -163
  286. package/src/utils/unaryLogging.ts +0 -26
  287. package/src/utils/user.ts +0 -37
  288. package/src/utils/validate.ts +0 -165
@@ -1,576 +0,0 @@
1
- import * as React from 'react'
2
- import { Box, Text } from 'ink'
3
- import { z } from 'zod'
4
- import { Tool, ValidationResult } from '../../Tool'
5
- import { FallbackToolUseRejectedMessage } from '../../components/FallbackToolUseRejectedMessage'
6
- import { getModelManager } from '../../utils/model'
7
- import { getTheme } from '../../utils/theme'
8
- import {
9
- createUserMessage,
10
- createAssistantMessage,
11
- INTERRUPT_MESSAGE,
12
- } from '../../utils/messages'
13
- import { logError } from '../../utils/log'
14
- import {
15
- createExpertChatSession,
16
- loadExpertChatSession,
17
- getSessionMessages,
18
- addMessageToSession,
19
- } from '../../utils/expertChatStorage'
20
- import { queryLLM } from '../../services/claude'
21
- import { debug as debugLogger } from '../../utils/debugLogger'
22
- import { applyMarkdown } from '../../utils/markdown'
23
-
24
- export const inputSchema = z.strictObject({
25
- question: z.string().describe(
26
- 'COMPLETE SELF-CONTAINED QUESTION: Must include full background context, relevant details, and a clear independent question. The expert model will receive ONLY this content with no access to previous conversation or external context. Structure as: 1) Background/Context 2) Specific situation/problem 3) Clear question. Ensure the expert can fully understand and respond without needing additional information.'
27
- ),
28
- expert_model: z
29
- .string()
30
- .describe(
31
- 'The expert model to use (e.g., gpt-5, claude-3-5-sonnet-20241022)',
32
- ),
33
- chat_session_id: z
34
- .string()
35
- .describe(
36
- 'Chat session ID: use "new" for new session or existing session ID',
37
- ),
38
- })
39
-
40
- type In = typeof inputSchema
41
- export type Out = {
42
- chatSessionId: string
43
- expertModelName: string
44
- expertAnswer: string
45
- }
46
-
47
- export const AskExpertModelTool = {
48
- name: 'AskExpertModel',
49
- async description() {
50
- return "Consult external AI models for expert opinions and analysis"
51
- },
52
- async prompt() {
53
- return `Ask a question to a specific external AI model for expert analysis.
54
-
55
- This tool allows you to consult different AI models for their unique perspectives and expertise.
56
-
57
- CRITICAL REQUIREMENT FOR QUESTION PARAMETER:
58
- The question MUST be completely self-contained and include:
59
- 1. FULL BACKGROUND CONTEXT - All relevant information the expert needs
60
- 2. SPECIFIC SITUATION - Clear description of the current scenario/problem
61
- 3. INDEPENDENT QUESTION - What exactly you want the expert to analyze/answer
62
-
63
- The expert model receives ONLY your question content with NO access to:
64
- - Previous conversation history (unless using existing session)
65
- - Current codebase or file context
66
- - User's current task or project details
67
-
68
- IMPORTANT: This tool is for asking questions to models, not for task execution.
69
- - Use when you need a specific model's opinion or analysis
70
- - Use when you want to compare different models' responses
71
- - Use the @ask-[model] format when available
72
-
73
- The expert_model parameter accepts:
74
- - OpenAI: gpt-4, gpt-5, o1-preview
75
- - Anthropic: claude-3-5-sonnet, claude-3-opus
76
- - Others: kimi, gemini-pro, mixtral
77
-
78
- Example of well-structured question:
79
- "Background: I'm working on a React TypeScript application with performance issues. The app renders a large list of 10,000 items using a simple map() function, causing UI freezing.
80
-
81
- Current situation: Users report 3-5 second delays when scrolling through the list. The component re-renders the entire list on every state change.
82
-
83
- Question: What are the most effective React optimization techniques for handling large lists, and how should I prioritize implementing virtualization vs memoization vs other approaches?"`
84
- },
85
- isReadOnly() {
86
- return true
87
- },
88
- isConcurrencySafe() {
89
- return true
90
- },
91
- inputSchema,
92
- userFacingName() {
93
- return 'AskExpertModel'
94
- },
95
- async isEnabled() {
96
- return true
97
- },
98
- needsPermissions(): boolean {
99
- return false
100
- },
101
- async validateInput({
102
- question,
103
- expert_model,
104
- chat_session_id,
105
- }, context?: any): Promise<ValidationResult> {
106
- if (!question.trim()) {
107
- return { result: false, message: 'Question cannot be empty' }
108
- }
109
-
110
-
111
- if (!expert_model.trim()) {
112
- return { result: false, message: 'Expert model must be specified' }
113
- }
114
-
115
- if (!chat_session_id.trim()) {
116
- return {
117
- result: false,
118
- message:
119
- 'Chat session ID must be specified (use "new" for new session)',
120
- }
121
- }
122
-
123
- // Check if trying to consult the same model we're currently running
124
- try {
125
- const modelManager = getModelManager()
126
-
127
- // Get current model based on context
128
- let currentModel: string
129
- if (context?.agentId && context?.options?.model) {
130
- // In subagent context (Task tool)
131
- currentModel = context.options.model
132
- } else {
133
- // In main agent context or after model switch
134
- currentModel = modelManager.getModelName('main') || ''
135
- }
136
-
137
- // Normalize model names for comparison
138
- const normalizedExpert = expert_model.toLowerCase().replace(/[^a-z0-9]/g, '')
139
- const normalizedCurrent = currentModel.toLowerCase().replace(/[^a-z0-9]/g, '')
140
-
141
- if (normalizedExpert === normalizedCurrent) {
142
- return {
143
- result: false,
144
- message: `You are already running as ${currentModel}. Consulting the same model would be redundant. Please choose a different model or handle the task directly.`
145
- }
146
- }
147
- } catch (e) {
148
- // If we can't determine current model, allow the request
149
- debugLogger.error('AskExpertModel', { message: 'Could not determine current model', error: e })
150
- }
151
-
152
- // Validate that the model exists and is available
153
- try {
154
- const modelManager = getModelManager()
155
- const modelResolution = modelManager.resolveModelWithInfo(expert_model)
156
-
157
- if (!modelResolution.success) {
158
- const availableModels = modelManager.getAllAvailableModelNames()
159
- if (availableModels.length > 0) {
160
- return {
161
- result: false,
162
- message: `Model '${expert_model}' is not configured. Available models: ${availableModels.join(', ')}. Check if any available model closely matches the user's request (e.g., 'kimi' matches 'kimi-k2-0711-preview'). If there's a strong match, auto retry using the correct model name. If no close match exists, inform the user that '${expert_model}' needs to be configured using /model command.`,
163
- }
164
- } else {
165
- return {
166
- result: false,
167
- message: `Model '${expert_model}' not found and no models are currently configured in the system. Inform the user that models need to be configured first using the /model command.`,
168
- }
169
- }
170
- }
171
- } catch (error) {
172
- console.error('Model validation error in AskExpertModelTool:', error)
173
- logError(error)
174
- return {
175
- result: false,
176
- message: `Failed to validate expert model '${expert_model}'. Please check your model configuration.`,
177
- }
178
- }
179
-
180
- return { result: true }
181
- },
182
-
183
- renderToolUseMessage(
184
- { question, expert_model, chat_session_id },
185
- { verbose },
186
- ) {
187
- if (!question || !expert_model) return null
188
- const isNewSession = chat_session_id === 'new'
189
- const sessionDisplay = isNewSession ? 'new session' : `session ${chat_session_id.substring(0, 5)}...`
190
- const theme = getTheme()
191
-
192
- if (verbose) {
193
- return (
194
- <Box flexDirection="column">
195
- <Text bold color="yellow">{expert_model}</Text>
196
- <Text color={theme.secondaryText}>{sessionDisplay}</Text>
197
- <Box marginTop={1}>
198
- <Text color={theme.text}>
199
- {question.length > 300 ? question.substring(0, 300) + '...' : question}
200
- </Text>
201
- </Box>
202
- </Box>
203
- )
204
- }
205
- return (
206
- <Box flexDirection="column">
207
- <Text bold color="yellow">{expert_model} </Text>
208
- <Text color={theme.secondaryText} dimColor>({sessionDisplay})</Text>
209
- </Box>
210
- )
211
- },
212
-
213
- renderToolResultMessage(content) {
214
- const verbose = true // Show more content
215
- const theme = getTheme()
216
-
217
- if (typeof content === 'object' && content && 'expertAnswer' in content) {
218
- const expertResult = content as Out
219
- const isError = expertResult.expertAnswer.startsWith('Error') || expertResult.expertAnswer.includes('failed')
220
- const isInterrupted = expertResult.chatSessionId === 'interrupted'
221
-
222
- if (isInterrupted) {
223
- return (
224
- <Box flexDirection="row">
225
- <Text color={theme.secondaryText}>Consultation interrupted</Text>
226
- </Box>
227
- )
228
- }
229
-
230
- const answerText = verbose
231
- ? expertResult.expertAnswer.trim()
232
- : expertResult.expertAnswer.length > 500
233
- ? expertResult.expertAnswer.substring(0, 500) + '...'
234
- : expertResult.expertAnswer.trim()
235
-
236
- if (isError) {
237
- return (
238
- <Box flexDirection="column">
239
- <Text color="red">{answerText}</Text>
240
- </Box>
241
- )
242
- }
243
-
244
- return (
245
- <Box flexDirection="column">
246
- <Text bold color={theme.text}>Response from {expertResult.expertModelName}:</Text>
247
- <Box marginTop={1}>
248
- <Text color={theme.text}>
249
- {applyMarkdown(answerText)}
250
- </Text>
251
- </Box>
252
- <Box marginTop={1}>
253
- <Text color={theme.secondaryText} dimColor>
254
- Session: {expertResult.chatSessionId.substring(0, 8)}
255
- </Text>
256
- </Box>
257
- </Box>
258
- )
259
- }
260
-
261
- return (
262
- <Box flexDirection="row">
263
- <Text color={theme.secondaryText}>Consultation completed</Text>
264
- </Box>
265
- )
266
- },
267
-
268
- renderResultForAssistant(output: Out): string {
269
- return `[Expert consultation completed]
270
- Expert Model: ${output.expertModelName}
271
- Session ID: ${output.chatSessionId}
272
- To continue this conversation with context preservation, use this Session ID in your next AskExpertModel call to maintain the full conversation history and context.
273
-
274
- ${output.expertAnswer}`
275
- },
276
-
277
- renderToolUseRejectedMessage() {
278
- return <FallbackToolUseRejectedMessage />
279
- },
280
-
281
- async *call(
282
- { question, expert_model, chat_session_id },
283
- { abortController, readFileTimestamps },
284
- ) {
285
- const expertModel = expert_model
286
-
287
- let sessionId: string
288
- let isInterrupted = false
289
-
290
- // Set up abort listener (following TaskTool pattern)
291
- const abortListener = () => {
292
- isInterrupted = true
293
- }
294
- abortController.signal.addEventListener('abort', abortListener)
295
-
296
- try {
297
- // Initial abort check
298
- if (abortController.signal.aborted) {
299
- return yield* this.handleInterrupt()
300
- }
301
- // Session management with error handling
302
- if (chat_session_id === 'new') {
303
- try {
304
- const session = createExpertChatSession(expertModel)
305
- sessionId = session.sessionId
306
- } catch (error) {
307
- console.error('Failed to create new expert chat session:', error)
308
- logError(error)
309
- throw new Error('Failed to create new chat session')
310
- }
311
- } else {
312
- sessionId = chat_session_id
313
- try {
314
- const session = loadExpertChatSession(sessionId)
315
- if (!session) {
316
- // Session doesn't exist, create new one
317
- const newSession = createExpertChatSession(expertModel)
318
- sessionId = newSession.sessionId
319
- }
320
- } catch (error) {
321
- console.error('Failed to load expert chat session:', error)
322
- logError(error)
323
- // Fallback: create new session
324
- try {
325
- const newSession = createExpertChatSession(expertModel)
326
- sessionId = newSession.sessionId
327
- } catch (createError) {
328
- console.error('Failed to create fallback expert chat session:', createError)
329
- logError(createError)
330
- throw new Error('Unable to create or load chat session')
331
- }
332
- }
333
- }
334
-
335
- // Check for cancellation before loading history
336
- if (isInterrupted || abortController.signal.aborted) {
337
- return yield* this.handleInterrupt()
338
- }
339
-
340
- // Load history and prepare messages with error handling
341
- let historyMessages: Array<{ role: string; content: string }>
342
- try {
343
- historyMessages = getSessionMessages(sessionId)
344
- } catch (error) {
345
- console.error('Failed to load session messages:', error)
346
- logError(error)
347
- historyMessages = [] // Fallback to empty history
348
- }
349
-
350
- const messages = [...historyMessages, { role: 'user', content: question }]
351
-
352
- let systemMessages
353
- try {
354
- systemMessages = messages.map(msg =>
355
- msg.role === 'user'
356
- ? createUserMessage(msg.content)
357
- : createAssistantMessage(msg.content),
358
- )
359
- } catch (error) {
360
- console.error('Failed to create system messages:', error)
361
- logError(error)
362
- throw new Error('Failed to prepare conversation messages')
363
- }
364
-
365
- // Check for cancellation before model call
366
- if (isInterrupted || abortController.signal.aborted) {
367
- return yield* this.handleInterrupt()
368
- }
369
-
370
- // Yield progress message to show we're connecting
371
- yield {
372
- type: 'progress',
373
- content: createAssistantMessage(
374
- `Connecting to ${expertModel}... (timeout: 5 minutes)`
375
- ),
376
- }
377
-
378
- // Call model with comprehensive error handling and timeout
379
- let response
380
- try {
381
- // Debug: Log the model we're trying to use (using global debug logger)
382
- const modelManager = getModelManager()
383
- const modelResolution = modelManager.resolveModelWithInfo(expertModel)
384
-
385
- debugLogger.api('EXPERT_MODEL_RESOLUTION', {
386
- requestedModel: expertModel,
387
- success: modelResolution.success,
388
- profileName: modelResolution.profile?.name,
389
- profileModelName: modelResolution.profile?.modelName,
390
- provider: modelResolution.profile?.provider,
391
- isActive: modelResolution.profile?.isActive,
392
- error: modelResolution.error,
393
- })
394
-
395
- // Create a timeout promise to prevent hanging
396
- const timeoutMs = 300000 // 300 seconds (5 minutes) timeout for external models
397
- const timeoutPromise = new Promise((_, reject) => {
398
- setTimeout(() => {
399
- reject(new Error(`Expert model query timed out after ${timeoutMs/1000}s`))
400
- }, timeoutMs)
401
- })
402
-
403
- // Race between the query and timeout
404
- response = await Promise.race([
405
- queryLLM(
406
- systemMessages,
407
- [], // no system prompt - let expert model use its default behavior
408
- 0, // no thinking tokens needed
409
- [], // no tools needed
410
- abortController.signal,
411
- {
412
- safeMode: false,
413
- model: expertModel,
414
- prependCLISysprompt: false, // KEY: avoid injecting CLI context
415
- },
416
- ),
417
- timeoutPromise
418
- ])
419
- } catch (error: any) {
420
- console.error('Expert model query failed:', error)
421
- logError(error)
422
-
423
- // Check for specific error types
424
- if (
425
- error.name === 'AbortError' ||
426
- abortController.signal?.aborted ||
427
- isInterrupted
428
- ) {
429
- return yield* this.handleInterrupt()
430
- }
431
-
432
- if (error.message?.includes('timed out')) {
433
- throw new Error(
434
- `Expert model '${expertModel}' timed out after 5 minutes.\n\n` +
435
- `Suggestions:\n` +
436
- ` - The model might be experiencing high load\n` +
437
- ` - Try a different model or retry later\n` +
438
- ` - Consider breaking down your question into smaller parts`,
439
- )
440
- }
441
-
442
- if (error.message?.includes('rate limit')) {
443
- throw new Error(
444
- `Rate limit exceeded for ${expertModel}.\n\n` +
445
- `Please wait a moment and try again, or use a different model.`,
446
- )
447
- }
448
-
449
- if (error.message?.includes('invalid api key')) {
450
- throw new Error(
451
- `Invalid API key for ${expertModel}.\n\n` +
452
- `Please check your model configuration with /model command.`,
453
- )
454
- }
455
-
456
- if (
457
- error.message?.includes('model not found') ||
458
- error.message?.includes('Failed to resolve model')
459
- ) {
460
- // Provide helpful model guidance in runtime errors too
461
- try {
462
- const modelManager = getModelManager()
463
- const availableModels = modelManager.getAllAvailableModelNames()
464
- if (availableModels.length > 0) {
465
- throw new Error(
466
- `Model '${expertModel}' is not configured. Available models: ${availableModels.join(', ')}. Check if any available model closely matches the user's request (e.g., 'kimi' matches 'kimi-k2-0711-preview'). If there's a strong match, auto retry using the correct model name. If no close match exists, inform the user that '${expertModel}' needs to be configured using /model command.`,
467
- )
468
- } else {
469
- throw new Error(
470
- `Model '${expertModel}' not found and no models are currently configured in the system. Inform the user that models need to be configured first using the /model command.`,
471
- )
472
- }
473
- } catch (modelError) {
474
- // If we can't get model list, fall back to simple error
475
- throw new Error(
476
- `Model '${expertModel}' not found. Please check model configuration or inform user about the issue.`,
477
- )
478
- }
479
- }
480
-
481
- // Generic fallback
482
- throw new Error(
483
- `Expert model query failed: ${error.message || 'Unknown error'}`,
484
- )
485
- }
486
-
487
- // Extract answer with error handling
488
- let expertAnswer: string
489
- try {
490
- if (!response?.message?.content) {
491
- throw new Error('No content in expert response')
492
- }
493
-
494
- expertAnswer = response.message.content
495
- .filter(block => block.type === 'text')
496
- .map(block => (block as any).text)
497
- .join('\n')
498
-
499
- if (!expertAnswer.trim()) {
500
- throw new Error('Expert response was empty')
501
- }
502
- } catch (error) {
503
- console.error('Failed to extract expert answer:', error)
504
- logError(error)
505
- throw new Error('Failed to process expert response')
506
- }
507
-
508
- // Save conversation with error handling
509
- try {
510
- addMessageToSession(sessionId, 'user', question)
511
- addMessageToSession(sessionId, 'assistant', expertAnswer)
512
- } catch (error) {
513
- console.error('Failed to save conversation to session:', error)
514
- logError(error)
515
- // Don't throw here - we got a valid response, saving is non-critical
516
- }
517
-
518
- const result: Out = {
519
- chatSessionId: sessionId,
520
- expertModelName: expertModel,
521
- expertAnswer: expertAnswer,
522
- }
523
-
524
- yield {
525
- type: 'result',
526
- data: result,
527
- resultForAssistant: this.renderResultForAssistant(result),
528
- }
529
- } catch (error: any) {
530
- // Check if error is due to cancellation
531
- if (
532
- error.name === 'AbortError' ||
533
- abortController.signal?.aborted ||
534
- isInterrupted
535
- ) {
536
- return yield* this.handleInterrupt()
537
- }
538
-
539
- console.error('AskExpertModelTool execution failed:', error)
540
- logError(error)
541
-
542
- // Ensure we have a valid sessionId for error response
543
- const errorSessionId = sessionId || 'error-session'
544
-
545
- const errorMessage =
546
- error.message || 'Expert consultation failed with unknown error'
547
- const result: Out = {
548
- chatSessionId: errorSessionId,
549
- expertModelName: expertModel,
550
- expertAnswer: `❌ ${errorMessage}`,
551
- }
552
-
553
- yield {
554
- type: 'result',
555
- data: result,
556
- resultForAssistant: this.renderResultForAssistant(result),
557
- }
558
- } finally {
559
- // Clean up event listener
560
- abortController.signal.removeEventListener('abort', abortListener)
561
- }
562
- },
563
-
564
- // Unified interrupt handling method (following TaskTool pattern)
565
- async *handleInterrupt() {
566
- yield {
567
- type: 'result',
568
- data: {
569
- chatSessionId: 'interrupted',
570
- expertModelName: 'cancelled',
571
- expertAnswer: INTERRUPT_MESSAGE,
572
- },
573
- resultForAssistant: INTERRUPT_MESSAGE,
574
- }
575
- },
576
- }