@shareai-lab/kode 1.1.14 → 1.1.16-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/cli.js +77 -82
  2. package/dist/entrypoints/cli.js +59 -38
  3. package/dist/entrypoints/cli.js.map +3 -3
  4. package/dist/index.js +5 -26
  5. package/dist/package.json +4 -1
  6. package/package.json +11 -104
  7. package/dist/test/testAdapters.js +0 -88
  8. package/dist/test/testAdapters.js.map +0 -1
  9. package/src/ProjectOnboarding.tsx +0 -198
  10. package/src/Tool.ts +0 -83
  11. package/src/commands/agents.tsx +0 -3416
  12. package/src/commands/approvedTools.ts +0 -53
  13. package/src/commands/bug.tsx +0 -20
  14. package/src/commands/clear.ts +0 -43
  15. package/src/commands/compact.ts +0 -120
  16. package/src/commands/config.tsx +0 -19
  17. package/src/commands/cost.ts +0 -18
  18. package/src/commands/ctx_viz.ts +0 -209
  19. package/src/commands/doctor.ts +0 -24
  20. package/src/commands/help.tsx +0 -19
  21. package/src/commands/init.ts +0 -37
  22. package/src/commands/listen.ts +0 -42
  23. package/src/commands/login.tsx +0 -51
  24. package/src/commands/logout.tsx +0 -40
  25. package/src/commands/mcp.ts +0 -41
  26. package/src/commands/model.tsx +0 -40
  27. package/src/commands/modelstatus.tsx +0 -20
  28. package/src/commands/onboarding.tsx +0 -34
  29. package/src/commands/pr_comments.ts +0 -59
  30. package/src/commands/refreshCommands.ts +0 -54
  31. package/src/commands/release-notes.ts +0 -34
  32. package/src/commands/resume.tsx +0 -31
  33. package/src/commands/review.ts +0 -49
  34. package/src/commands/terminalSetup.ts +0 -221
  35. package/src/commands.ts +0 -139
  36. package/src/components/ApproveApiKey.tsx +0 -93
  37. package/src/components/AsciiLogo.tsx +0 -13
  38. package/src/components/AutoUpdater.tsx +0 -148
  39. package/src/components/Bug.tsx +0 -367
  40. package/src/components/Config.tsx +0 -293
  41. package/src/components/ConsoleOAuthFlow.tsx +0 -327
  42. package/src/components/Cost.tsx +0 -23
  43. package/src/components/CostThresholdDialog.tsx +0 -46
  44. package/src/components/CustomSelect/option-map.ts +0 -42
  45. package/src/components/CustomSelect/select-option.tsx +0 -78
  46. package/src/components/CustomSelect/select.tsx +0 -152
  47. package/src/components/CustomSelect/theme.ts +0 -45
  48. package/src/components/CustomSelect/use-select-state.ts +0 -414
  49. package/src/components/CustomSelect/use-select.ts +0 -35
  50. package/src/components/FallbackToolUseRejectedMessage.tsx +0 -15
  51. package/src/components/FileEditToolUpdatedMessage.tsx +0 -66
  52. package/src/components/Help.tsx +0 -215
  53. package/src/components/HighlightedCode.tsx +0 -33
  54. package/src/components/InvalidConfigDialog.tsx +0 -113
  55. package/src/components/Link.tsx +0 -32
  56. package/src/components/LogSelector.tsx +0 -86
  57. package/src/components/Logo.tsx +0 -170
  58. package/src/components/MCPServerApprovalDialog.tsx +0 -100
  59. package/src/components/MCPServerDialogCopy.tsx +0 -25
  60. package/src/components/MCPServerMultiselectDialog.tsx +0 -109
  61. package/src/components/Message.tsx +0 -221
  62. package/src/components/MessageResponse.tsx +0 -15
  63. package/src/components/MessageSelector.tsx +0 -211
  64. package/src/components/ModeIndicator.tsx +0 -88
  65. package/src/components/ModelConfig.tsx +0 -301
  66. package/src/components/ModelListManager.tsx +0 -227
  67. package/src/components/ModelSelector.tsx +0 -3387
  68. package/src/components/ModelStatusDisplay.tsx +0 -230
  69. package/src/components/Onboarding.tsx +0 -274
  70. package/src/components/PressEnterToContinue.tsx +0 -11
  71. package/src/components/PromptInput.tsx +0 -760
  72. package/src/components/SentryErrorBoundary.ts +0 -39
  73. package/src/components/Spinner.tsx +0 -129
  74. package/src/components/StickerRequestForm.tsx +0 -16
  75. package/src/components/StructuredDiff.tsx +0 -191
  76. package/src/components/TextInput.tsx +0 -259
  77. package/src/components/TodoItem.tsx +0 -47
  78. package/src/components/TokenWarning.tsx +0 -31
  79. package/src/components/ToolUseLoader.tsx +0 -40
  80. package/src/components/TrustDialog.tsx +0 -106
  81. package/src/components/binary-feedback/BinaryFeedback.tsx +0 -63
  82. package/src/components/binary-feedback/BinaryFeedbackOption.tsx +0 -111
  83. package/src/components/binary-feedback/BinaryFeedbackView.tsx +0 -172
  84. package/src/components/binary-feedback/utils.ts +0 -220
  85. package/src/components/messages/AssistantBashOutputMessage.tsx +0 -22
  86. package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +0 -49
  87. package/src/components/messages/AssistantRedactedThinkingMessage.tsx +0 -19
  88. package/src/components/messages/AssistantTextMessage.tsx +0 -144
  89. package/src/components/messages/AssistantThinkingMessage.tsx +0 -40
  90. package/src/components/messages/AssistantToolUseMessage.tsx +0 -132
  91. package/src/components/messages/TaskProgressMessage.tsx +0 -32
  92. package/src/components/messages/TaskToolMessage.tsx +0 -58
  93. package/src/components/messages/UserBashInputMessage.tsx +0 -28
  94. package/src/components/messages/UserCommandMessage.tsx +0 -30
  95. package/src/components/messages/UserKodingInputMessage.tsx +0 -28
  96. package/src/components/messages/UserPromptMessage.tsx +0 -35
  97. package/src/components/messages/UserTextMessage.tsx +0 -39
  98. package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +0 -12
  99. package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +0 -36
  100. package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +0 -31
  101. package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +0 -57
  102. package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +0 -35
  103. package/src/components/messages/UserToolResultMessage/utils.tsx +0 -56
  104. package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +0 -121
  105. package/src/components/permissions/FallbackPermissionRequest.tsx +0 -153
  106. package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +0 -182
  107. package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +0 -77
  108. package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +0 -164
  109. package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +0 -83
  110. package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +0 -240
  111. package/src/components/permissions/PermissionRequest.tsx +0 -101
  112. package/src/components/permissions/PermissionRequestTitle.tsx +0 -69
  113. package/src/components/permissions/hooks.ts +0 -44
  114. package/src/components/permissions/toolUseOptions.ts +0 -59
  115. package/src/components/permissions/utils.ts +0 -23
  116. package/src/constants/betas.ts +0 -5
  117. package/src/constants/claude-asterisk-ascii-art.tsx +0 -238
  118. package/src/constants/figures.ts +0 -4
  119. package/src/constants/keys.ts +0 -3
  120. package/src/constants/macros.ts +0 -11
  121. package/src/constants/modelCapabilities.ts +0 -179
  122. package/src/constants/models.ts +0 -1025
  123. package/src/constants/oauth.ts +0 -18
  124. package/src/constants/product.ts +0 -17
  125. package/src/constants/prompts.ts +0 -168
  126. package/src/constants/releaseNotes.ts +0 -7
  127. package/src/context/PermissionContext.tsx +0 -149
  128. package/src/context.ts +0 -278
  129. package/src/cost-tracker.ts +0 -84
  130. package/src/entrypoints/cli.tsx +0 -1561
  131. package/src/entrypoints/mcp.ts +0 -175
  132. package/src/history.ts +0 -25
  133. package/src/hooks/useApiKeyVerification.ts +0 -59
  134. package/src/hooks/useArrowKeyHistory.ts +0 -55
  135. package/src/hooks/useCanUseTool.ts +0 -138
  136. package/src/hooks/useCancelRequest.ts +0 -39
  137. package/src/hooks/useDoublePress.ts +0 -41
  138. package/src/hooks/useExitOnCtrlCD.ts +0 -31
  139. package/src/hooks/useInterval.ts +0 -25
  140. package/src/hooks/useLogMessages.ts +0 -16
  141. package/src/hooks/useLogStartupTime.ts +0 -12
  142. package/src/hooks/useNotifyAfterTimeout.ts +0 -65
  143. package/src/hooks/usePermissionRequestLogging.ts +0 -44
  144. package/src/hooks/useTerminalSize.ts +0 -49
  145. package/src/hooks/useTextInput.ts +0 -317
  146. package/src/hooks/useUnifiedCompletion.ts +0 -1405
  147. package/src/index.ts +0 -34
  148. package/src/messages.ts +0 -38
  149. package/src/permissions.ts +0 -268
  150. package/src/query.ts +0 -720
  151. package/src/screens/ConfigureNpmPrefix.tsx +0 -197
  152. package/src/screens/Doctor.tsx +0 -219
  153. package/src/screens/LogList.tsx +0 -68
  154. package/src/screens/REPL.tsx +0 -813
  155. package/src/screens/ResumeConversation.tsx +0 -68
  156. package/src/services/adapters/base.ts +0 -38
  157. package/src/services/adapters/chatCompletions.ts +0 -90
  158. package/src/services/adapters/responsesAPI.ts +0 -170
  159. package/src/services/browserMocks.ts +0 -66
  160. package/src/services/claude.ts +0 -2197
  161. package/src/services/customCommands.ts +0 -704
  162. package/src/services/fileFreshness.ts +0 -377
  163. package/src/services/gpt5ConnectionTest.ts +0 -340
  164. package/src/services/mcpClient.ts +0 -564
  165. package/src/services/mcpServerApproval.tsx +0 -50
  166. package/src/services/mentionProcessor.ts +0 -273
  167. package/src/services/modelAdapterFactory.ts +0 -69
  168. package/src/services/notifier.ts +0 -40
  169. package/src/services/oauth.ts +0 -357
  170. package/src/services/openai.ts +0 -1359
  171. package/src/services/responseStateManager.ts +0 -90
  172. package/src/services/sentry.ts +0 -3
  173. package/src/services/statsig.ts +0 -172
  174. package/src/services/statsigStorage.ts +0 -86
  175. package/src/services/systemReminder.ts +0 -507
  176. package/src/services/vcr.ts +0 -161
  177. package/src/test/testAdapters.ts +0 -96
  178. package/src/tools/ArchitectTool/ArchitectTool.tsx +0 -135
  179. package/src/tools/ArchitectTool/prompt.ts +0 -15
  180. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +0 -576
  181. package/src/tools/BashTool/BashTool.tsx +0 -243
  182. package/src/tools/BashTool/BashToolResultMessage.tsx +0 -38
  183. package/src/tools/BashTool/OutputLine.tsx +0 -49
  184. package/src/tools/BashTool/prompt.ts +0 -174
  185. package/src/tools/BashTool/utils.ts +0 -56
  186. package/src/tools/FileEditTool/FileEditTool.tsx +0 -319
  187. package/src/tools/FileEditTool/prompt.ts +0 -51
  188. package/src/tools/FileEditTool/utils.ts +0 -58
  189. package/src/tools/FileReadTool/FileReadTool.tsx +0 -404
  190. package/src/tools/FileReadTool/prompt.ts +0 -7
  191. package/src/tools/FileWriteTool/FileWriteTool.tsx +0 -301
  192. package/src/tools/FileWriteTool/prompt.ts +0 -10
  193. package/src/tools/GlobTool/GlobTool.tsx +0 -119
  194. package/src/tools/GlobTool/prompt.ts +0 -8
  195. package/src/tools/GrepTool/GrepTool.tsx +0 -147
  196. package/src/tools/GrepTool/prompt.ts +0 -11
  197. package/src/tools/MCPTool/MCPTool.tsx +0 -107
  198. package/src/tools/MCPTool/prompt.ts +0 -3
  199. package/src/tools/MemoryReadTool/MemoryReadTool.tsx +0 -127
  200. package/src/tools/MemoryReadTool/prompt.ts +0 -3
  201. package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +0 -89
  202. package/src/tools/MemoryWriteTool/prompt.ts +0 -3
  203. package/src/tools/MultiEditTool/MultiEditTool.tsx +0 -388
  204. package/src/tools/MultiEditTool/prompt.ts +0 -45
  205. package/src/tools/NotebookEditTool/NotebookEditTool.tsx +0 -298
  206. package/src/tools/NotebookEditTool/prompt.ts +0 -3
  207. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +0 -258
  208. package/src/tools/NotebookReadTool/prompt.ts +0 -3
  209. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +0 -107
  210. package/src/tools/StickerRequestTool/prompt.ts +0 -19
  211. package/src/tools/TaskTool/TaskTool.tsx +0 -438
  212. package/src/tools/TaskTool/constants.ts +0 -1
  213. package/src/tools/TaskTool/prompt.ts +0 -92
  214. package/src/tools/ThinkTool/ThinkTool.tsx +0 -54
  215. package/src/tools/ThinkTool/prompt.ts +0 -12
  216. package/src/tools/TodoWriteTool/TodoWriteTool.tsx +0 -313
  217. package/src/tools/TodoWriteTool/prompt.ts +0 -63
  218. package/src/tools/URLFetcherTool/URLFetcherTool.tsx +0 -178
  219. package/src/tools/URLFetcherTool/cache.ts +0 -55
  220. package/src/tools/URLFetcherTool/htmlToMarkdown.ts +0 -55
  221. package/src/tools/URLFetcherTool/prompt.ts +0 -17
  222. package/src/tools/WebSearchTool/WebSearchTool.tsx +0 -103
  223. package/src/tools/WebSearchTool/prompt.ts +0 -13
  224. package/src/tools/WebSearchTool/searchProviders.ts +0 -66
  225. package/src/tools/lsTool/lsTool.tsx +0 -272
  226. package/src/tools/lsTool/prompt.ts +0 -2
  227. package/src/tools.ts +0 -67
  228. package/src/types/PermissionMode.ts +0 -120
  229. package/src/types/RequestContext.ts +0 -72
  230. package/src/types/common.d.ts +0 -2
  231. package/src/types/conversation.ts +0 -51
  232. package/src/types/logs.ts +0 -58
  233. package/src/types/modelCapabilities.ts +0 -64
  234. package/src/types/notebook.ts +0 -87
  235. package/src/utils/Cursor.ts +0 -436
  236. package/src/utils/PersistentShell.ts +0 -552
  237. package/src/utils/advancedFuzzyMatcher.ts +0 -290
  238. package/src/utils/agentLoader.ts +0 -278
  239. package/src/utils/agentStorage.ts +0 -97
  240. package/src/utils/array.ts +0 -3
  241. package/src/utils/ask.tsx +0 -99
  242. package/src/utils/auth.ts +0 -13
  243. package/src/utils/autoCompactCore.ts +0 -223
  244. package/src/utils/autoUpdater.ts +0 -458
  245. package/src/utils/betas.ts +0 -20
  246. package/src/utils/browser.ts +0 -14
  247. package/src/utils/cleanup.ts +0 -72
  248. package/src/utils/commands.ts +0 -261
  249. package/src/utils/commonUnixCommands.ts +0 -161
  250. package/src/utils/config.ts +0 -945
  251. package/src/utils/conversationRecovery.ts +0 -55
  252. package/src/utils/debugLogger.ts +0 -1235
  253. package/src/utils/diff.ts +0 -42
  254. package/src/utils/env.ts +0 -57
  255. package/src/utils/errors.ts +0 -21
  256. package/src/utils/exampleCommands.ts +0 -109
  257. package/src/utils/execFileNoThrow.ts +0 -51
  258. package/src/utils/expertChatStorage.ts +0 -136
  259. package/src/utils/file.ts +0 -405
  260. package/src/utils/fileRecoveryCore.ts +0 -71
  261. package/src/utils/format.tsx +0 -44
  262. package/src/utils/fuzzyMatcher.ts +0 -328
  263. package/src/utils/generators.ts +0 -62
  264. package/src/utils/git.ts +0 -92
  265. package/src/utils/globalLogger.ts +0 -77
  266. package/src/utils/http.ts +0 -10
  267. package/src/utils/imagePaste.ts +0 -38
  268. package/src/utils/json.ts +0 -13
  269. package/src/utils/log.ts +0 -382
  270. package/src/utils/markdown.ts +0 -213
  271. package/src/utils/messageContextManager.ts +0 -294
  272. package/src/utils/messages.tsx +0 -945
  273. package/src/utils/model.ts +0 -914
  274. package/src/utils/permissions/filesystem.ts +0 -127
  275. package/src/utils/responseState.ts +0 -23
  276. package/src/utils/ripgrep.ts +0 -167
  277. package/src/utils/secureFile.ts +0 -564
  278. package/src/utils/sessionState.ts +0 -49
  279. package/src/utils/state.ts +0 -25
  280. package/src/utils/style.ts +0 -29
  281. package/src/utils/terminal.ts +0 -50
  282. package/src/utils/theme.ts +0 -127
  283. package/src/utils/thinking.ts +0 -144
  284. package/src/utils/todoStorage.ts +0 -431
  285. package/src/utils/tokens.ts +0 -43
  286. package/src/utils/toolExecutionController.ts +0 -163
  287. package/src/utils/unaryLogging.ts +0 -26
  288. package/src/utils/user.ts +0 -37
  289. 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
- }