@shareai-lab/kode 1.0.69 → 1.0.71

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 (253) hide show
  1. package/README.md +205 -72
  2. package/README.zh-CN.md +246 -0
  3. package/cli.js +62 -0
  4. package/package.json +45 -25
  5. package/scripts/postinstall.js +56 -0
  6. package/src/ProjectOnboarding.tsx +180 -0
  7. package/src/Tool.ts +53 -0
  8. package/src/commands/approvedTools.ts +53 -0
  9. package/src/commands/bug.tsx +20 -0
  10. package/src/commands/clear.ts +43 -0
  11. package/src/commands/compact.ts +120 -0
  12. package/src/commands/config.tsx +19 -0
  13. package/src/commands/cost.ts +18 -0
  14. package/src/commands/ctx_viz.ts +209 -0
  15. package/src/commands/doctor.ts +24 -0
  16. package/src/commands/help.tsx +19 -0
  17. package/src/commands/init.ts +37 -0
  18. package/src/commands/listen.ts +42 -0
  19. package/src/commands/login.tsx +51 -0
  20. package/src/commands/logout.tsx +40 -0
  21. package/src/commands/mcp.ts +41 -0
  22. package/src/commands/model.tsx +40 -0
  23. package/src/commands/modelstatus.tsx +20 -0
  24. package/src/commands/onboarding.tsx +34 -0
  25. package/src/commands/pr_comments.ts +59 -0
  26. package/src/commands/refreshCommands.ts +54 -0
  27. package/src/commands/release-notes.ts +34 -0
  28. package/src/commands/resume.tsx +30 -0
  29. package/src/commands/review.ts +49 -0
  30. package/src/commands/terminalSetup.ts +221 -0
  31. package/src/commands.ts +136 -0
  32. package/src/components/ApproveApiKey.tsx +93 -0
  33. package/src/components/AsciiLogo.tsx +13 -0
  34. package/src/components/AutoUpdater.tsx +148 -0
  35. package/src/components/Bug.tsx +367 -0
  36. package/src/components/Config.tsx +289 -0
  37. package/src/components/ConsoleOAuthFlow.tsx +326 -0
  38. package/src/components/Cost.tsx +23 -0
  39. package/src/components/CostThresholdDialog.tsx +46 -0
  40. package/src/components/CustomSelect/option-map.ts +42 -0
  41. package/src/components/CustomSelect/select-option.tsx +52 -0
  42. package/src/components/CustomSelect/select.tsx +143 -0
  43. package/src/components/CustomSelect/use-select-state.ts +414 -0
  44. package/src/components/CustomSelect/use-select.ts +35 -0
  45. package/src/components/FallbackToolUseRejectedMessage.tsx +15 -0
  46. package/src/components/FileEditToolUpdatedMessage.tsx +66 -0
  47. package/src/components/Help.tsx +215 -0
  48. package/src/components/HighlightedCode.tsx +33 -0
  49. package/src/components/InvalidConfigDialog.tsx +113 -0
  50. package/src/components/Link.tsx +32 -0
  51. package/src/components/LogSelector.tsx +86 -0
  52. package/src/components/Logo.tsx +145 -0
  53. package/src/components/MCPServerApprovalDialog.tsx +100 -0
  54. package/src/components/MCPServerDialogCopy.tsx +25 -0
  55. package/src/components/MCPServerMultiselectDialog.tsx +109 -0
  56. package/src/components/Message.tsx +219 -0
  57. package/src/components/MessageResponse.tsx +15 -0
  58. package/src/components/MessageSelector.tsx +211 -0
  59. package/src/components/ModeIndicator.tsx +88 -0
  60. package/src/components/ModelConfig.tsx +301 -0
  61. package/src/components/ModelListManager.tsx +223 -0
  62. package/src/components/ModelSelector.tsx +3208 -0
  63. package/src/components/ModelStatusDisplay.tsx +228 -0
  64. package/src/components/Onboarding.tsx +274 -0
  65. package/src/components/PressEnterToContinue.tsx +11 -0
  66. package/src/components/PromptInput.tsx +710 -0
  67. package/src/components/SentryErrorBoundary.ts +33 -0
  68. package/src/components/Spinner.tsx +129 -0
  69. package/src/components/StructuredDiff.tsx +184 -0
  70. package/src/components/TextInput.tsx +246 -0
  71. package/src/components/TokenWarning.tsx +31 -0
  72. package/src/components/ToolUseLoader.tsx +40 -0
  73. package/src/components/TrustDialog.tsx +106 -0
  74. package/src/components/binary-feedback/BinaryFeedback.tsx +63 -0
  75. package/src/components/binary-feedback/BinaryFeedbackOption.tsx +111 -0
  76. package/src/components/binary-feedback/BinaryFeedbackView.tsx +172 -0
  77. package/src/components/binary-feedback/utils.ts +220 -0
  78. package/src/components/messages/AssistantBashOutputMessage.tsx +22 -0
  79. package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +45 -0
  80. package/src/components/messages/AssistantRedactedThinkingMessage.tsx +19 -0
  81. package/src/components/messages/AssistantTextMessage.tsx +144 -0
  82. package/src/components/messages/AssistantThinkingMessage.tsx +40 -0
  83. package/src/components/messages/AssistantToolUseMessage.tsx +123 -0
  84. package/src/components/messages/UserBashInputMessage.tsx +28 -0
  85. package/src/components/messages/UserCommandMessage.tsx +30 -0
  86. package/src/components/messages/UserKodingInputMessage.tsx +28 -0
  87. package/src/components/messages/UserPromptMessage.tsx +35 -0
  88. package/src/components/messages/UserTextMessage.tsx +39 -0
  89. package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +12 -0
  90. package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +36 -0
  91. package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +31 -0
  92. package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +57 -0
  93. package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +35 -0
  94. package/src/components/messages/UserToolResultMessage/utils.tsx +56 -0
  95. package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +121 -0
  96. package/src/components/permissions/FallbackPermissionRequest.tsx +155 -0
  97. package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +182 -0
  98. package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +75 -0
  99. package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +164 -0
  100. package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +81 -0
  101. package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +242 -0
  102. package/src/components/permissions/PermissionRequest.tsx +103 -0
  103. package/src/components/permissions/PermissionRequestTitle.tsx +69 -0
  104. package/src/components/permissions/hooks.ts +44 -0
  105. package/src/components/permissions/toolUseOptions.ts +59 -0
  106. package/src/components/permissions/utils.ts +23 -0
  107. package/src/constants/betas.ts +5 -0
  108. package/src/constants/claude-asterisk-ascii-art.tsx +238 -0
  109. package/src/constants/figures.ts +4 -0
  110. package/src/constants/keys.ts +3 -0
  111. package/src/constants/macros.ts +6 -0
  112. package/src/constants/models.ts +935 -0
  113. package/src/constants/oauth.ts +18 -0
  114. package/src/constants/product.ts +17 -0
  115. package/src/constants/prompts.ts +177 -0
  116. package/src/constants/releaseNotes.ts +7 -0
  117. package/src/context/PermissionContext.tsx +149 -0
  118. package/src/context.ts +278 -0
  119. package/src/cost-tracker.ts +84 -0
  120. package/src/entrypoints/cli.tsx +1498 -0
  121. package/src/entrypoints/mcp.ts +176 -0
  122. package/src/history.ts +25 -0
  123. package/src/hooks/useApiKeyVerification.ts +59 -0
  124. package/src/hooks/useArrowKeyHistory.ts +55 -0
  125. package/src/hooks/useCanUseTool.ts +138 -0
  126. package/src/hooks/useCancelRequest.ts +39 -0
  127. package/src/hooks/useDoublePress.ts +42 -0
  128. package/src/hooks/useExitOnCtrlCD.ts +31 -0
  129. package/src/hooks/useInterval.ts +25 -0
  130. package/src/hooks/useLogMessages.ts +16 -0
  131. package/src/hooks/useLogStartupTime.ts +12 -0
  132. package/src/hooks/useNotifyAfterTimeout.ts +65 -0
  133. package/src/hooks/usePermissionRequestLogging.ts +44 -0
  134. package/src/hooks/useSlashCommandTypeahead.ts +137 -0
  135. package/src/hooks/useTerminalSize.ts +49 -0
  136. package/src/hooks/useTextInput.ts +315 -0
  137. package/src/messages.ts +37 -0
  138. package/src/permissions.ts +268 -0
  139. package/src/query.ts +704 -0
  140. package/src/screens/ConfigureNpmPrefix.tsx +197 -0
  141. package/src/screens/Doctor.tsx +219 -0
  142. package/src/screens/LogList.tsx +68 -0
  143. package/src/screens/REPL.tsx +792 -0
  144. package/src/screens/ResumeConversation.tsx +68 -0
  145. package/src/services/browserMocks.ts +66 -0
  146. package/src/services/claude.ts +1947 -0
  147. package/src/services/customCommands.ts +683 -0
  148. package/src/services/fileFreshness.ts +377 -0
  149. package/src/services/mcpClient.ts +564 -0
  150. package/src/services/mcpServerApproval.tsx +50 -0
  151. package/src/services/notifier.ts +40 -0
  152. package/src/services/oauth.ts +357 -0
  153. package/src/services/openai.ts +796 -0
  154. package/src/services/sentry.ts +3 -0
  155. package/src/services/statsig.ts +171 -0
  156. package/src/services/statsigStorage.ts +86 -0
  157. package/src/services/systemReminder.ts +406 -0
  158. package/src/services/vcr.ts +161 -0
  159. package/src/tools/ArchitectTool/ArchitectTool.tsx +122 -0
  160. package/src/tools/ArchitectTool/prompt.ts +15 -0
  161. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +505 -0
  162. package/src/tools/BashTool/BashTool.tsx +270 -0
  163. package/src/tools/BashTool/BashToolResultMessage.tsx +38 -0
  164. package/src/tools/BashTool/OutputLine.tsx +48 -0
  165. package/src/tools/BashTool/prompt.ts +174 -0
  166. package/src/tools/BashTool/utils.ts +56 -0
  167. package/src/tools/FileEditTool/FileEditTool.tsx +316 -0
  168. package/src/tools/FileEditTool/prompt.ts +51 -0
  169. package/src/tools/FileEditTool/utils.ts +58 -0
  170. package/src/tools/FileReadTool/FileReadTool.tsx +371 -0
  171. package/src/tools/FileReadTool/prompt.ts +7 -0
  172. package/src/tools/FileWriteTool/FileWriteTool.tsx +297 -0
  173. package/src/tools/FileWriteTool/prompt.ts +10 -0
  174. package/src/tools/GlobTool/GlobTool.tsx +119 -0
  175. package/src/tools/GlobTool/prompt.ts +8 -0
  176. package/src/tools/GrepTool/GrepTool.tsx +147 -0
  177. package/src/tools/GrepTool/prompt.ts +11 -0
  178. package/src/tools/MCPTool/MCPTool.tsx +106 -0
  179. package/src/tools/MCPTool/prompt.ts +3 -0
  180. package/src/tools/MemoryReadTool/MemoryReadTool.tsx +127 -0
  181. package/src/tools/MemoryReadTool/prompt.ts +3 -0
  182. package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +89 -0
  183. package/src/tools/MemoryWriteTool/prompt.ts +3 -0
  184. package/src/tools/MultiEditTool/MultiEditTool.tsx +366 -0
  185. package/src/tools/MultiEditTool/prompt.ts +45 -0
  186. package/src/tools/NotebookEditTool/NotebookEditTool.tsx +298 -0
  187. package/src/tools/NotebookEditTool/prompt.ts +3 -0
  188. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +266 -0
  189. package/src/tools/NotebookReadTool/prompt.ts +3 -0
  190. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +93 -0
  191. package/src/tools/StickerRequestTool/prompt.ts +19 -0
  192. package/src/tools/TaskTool/TaskTool.tsx +382 -0
  193. package/src/tools/TaskTool/constants.ts +1 -0
  194. package/src/tools/TaskTool/prompt.ts +56 -0
  195. package/src/tools/ThinkTool/ThinkTool.tsx +56 -0
  196. package/src/tools/ThinkTool/prompt.ts +12 -0
  197. package/src/tools/TodoWriteTool/TodoWriteTool.tsx +289 -0
  198. package/src/tools/TodoWriteTool/prompt.ts +63 -0
  199. package/src/tools/lsTool/lsTool.tsx +269 -0
  200. package/src/tools/lsTool/prompt.ts +2 -0
  201. package/src/tools.ts +63 -0
  202. package/src/types/PermissionMode.ts +120 -0
  203. package/src/types/RequestContext.ts +72 -0
  204. package/src/utils/Cursor.ts +436 -0
  205. package/src/utils/PersistentShell.ts +373 -0
  206. package/src/utils/agentStorage.ts +97 -0
  207. package/src/utils/array.ts +3 -0
  208. package/src/utils/ask.tsx +98 -0
  209. package/src/utils/auth.ts +13 -0
  210. package/src/utils/autoCompactCore.ts +223 -0
  211. package/src/utils/autoUpdater.ts +318 -0
  212. package/src/utils/betas.ts +20 -0
  213. package/src/utils/browser.ts +14 -0
  214. package/src/utils/cleanup.ts +72 -0
  215. package/src/utils/commands.ts +261 -0
  216. package/src/utils/config.ts +771 -0
  217. package/src/utils/conversationRecovery.ts +54 -0
  218. package/src/utils/debugLogger.ts +1123 -0
  219. package/src/utils/diff.ts +42 -0
  220. package/src/utils/env.ts +57 -0
  221. package/src/utils/errors.ts +21 -0
  222. package/src/utils/exampleCommands.ts +108 -0
  223. package/src/utils/execFileNoThrow.ts +51 -0
  224. package/src/utils/expertChatStorage.ts +136 -0
  225. package/src/utils/file.ts +402 -0
  226. package/src/utils/fileRecoveryCore.ts +71 -0
  227. package/src/utils/format.tsx +44 -0
  228. package/src/utils/generators.ts +62 -0
  229. package/src/utils/git.ts +92 -0
  230. package/src/utils/globalLogger.ts +77 -0
  231. package/src/utils/http.ts +10 -0
  232. package/src/utils/imagePaste.ts +38 -0
  233. package/src/utils/json.ts +13 -0
  234. package/src/utils/log.ts +382 -0
  235. package/src/utils/markdown.ts +213 -0
  236. package/src/utils/messageContextManager.ts +289 -0
  237. package/src/utils/messages.tsx +938 -0
  238. package/src/utils/model.ts +836 -0
  239. package/src/utils/permissions/filesystem.ts +118 -0
  240. package/src/utils/ripgrep.ts +167 -0
  241. package/src/utils/sessionState.ts +49 -0
  242. package/src/utils/state.ts +25 -0
  243. package/src/utils/style.ts +29 -0
  244. package/src/utils/terminal.ts +49 -0
  245. package/src/utils/theme.ts +122 -0
  246. package/src/utils/thinking.ts +144 -0
  247. package/src/utils/todoStorage.ts +431 -0
  248. package/src/utils/tokens.ts +43 -0
  249. package/src/utils/toolExecutionController.ts +163 -0
  250. package/src/utils/unaryLogging.ts +26 -0
  251. package/src/utils/user.ts +37 -0
  252. package/src/utils/validate.ts +165 -0
  253. package/cli.mjs +0 -1803
@@ -0,0 +1,382 @@
1
+ import { TextBlock } from '@anthropic-ai/sdk/resources/index.mjs'
2
+ import chalk from 'chalk'
3
+ import { last, memoize } from 'lodash-es'
4
+ import { EOL } from 'os'
5
+ import * as React from 'react'
6
+ import { Box, Text } from 'ink'
7
+ import { z } from 'zod'
8
+ import { Tool, ValidationResult } from '../../Tool'
9
+ import { FallbackToolUseRejectedMessage } from '../../components/FallbackToolUseRejectedMessage'
10
+ import { getAgentPrompt } from '../../constants/prompts'
11
+ import { getContext } from '../../context'
12
+ import { hasPermissionsToUseTool } from '../../permissions'
13
+ import { AssistantMessage, Message as MessageType, query } from '../../query'
14
+ import { formatDuration, formatNumber } from '../../utils/format'
15
+ import {
16
+ getMessagesPath,
17
+ getNextAvailableLogSidechainNumber,
18
+ overwriteLog,
19
+ } from '../../utils/log.js'
20
+ import { applyMarkdown } from '../../utils/markdown'
21
+ import {
22
+ createAssistantMessage,
23
+ createUserMessage,
24
+ getLastAssistantMessageId,
25
+ INTERRUPT_MESSAGE,
26
+ normalizeMessages,
27
+ } from '../../utils/messages.js'
28
+ import { getModelManager } from '../../utils/model'
29
+ import { getMaxThinkingTokens } from '../../utils/thinking'
30
+ import { getTheme } from '../../utils/theme'
31
+ import { generateAgentId } from '../../utils/agentStorage'
32
+ import { debug as debugLogger } from '../../utils/debugLogger'
33
+ import { getTaskTools, getPrompt } from './prompt'
34
+ import { TOOL_NAME } from './constants'
35
+
36
+ const inputSchema = z.object({
37
+ description: z
38
+ .string()
39
+ .describe('A short (3-5 word) description of the task'),
40
+ prompt: z.string().describe('The task for the agent to perform'),
41
+ model_name: z
42
+ .string()
43
+ .optional()
44
+ .describe(
45
+ 'Optional: Specific model name to use for this task. If not provided, uses the default task model pointer.',
46
+ ),
47
+ })
48
+
49
+ export const TaskTool = {
50
+ async prompt({ safeMode }) {
51
+ return await getPrompt(safeMode)
52
+ },
53
+ name: TOOL_NAME,
54
+ async description() {
55
+ const modelManager = getModelManager()
56
+ const availableModels = modelManager.getAllAvailableModelNames()
57
+ const currentTaskModel =
58
+ modelManager.getModelName('task') || '<Not configured>'
59
+
60
+ if (availableModels.length === 0) {
61
+ return `Launch a new agent to handle complex, multi-step tasks autonomously.
62
+
63
+ ⚠️ No models configured. Use /model to configure models first.
64
+
65
+ Usage: Provide detailed task description for autonomous execution. The agent will return results in a single response.`
66
+ }
67
+
68
+ return `Launch a new agent to handle complex, multi-step tasks autonomously.
69
+
70
+ Available models: ${availableModels.join(', ')}
71
+
72
+ When to specify a model_name:
73
+ - Specify model_name for tasks requiring specific model capabilities
74
+ - If not provided, uses current task default: '${currentTaskModel}'
75
+ - Use reasoning models for complex analysis
76
+ - Use quick models for simple operations
77
+
78
+ The model_name parameter accepts actual model names (like 'claude-3-5-sonnet-20241022', 'gpt-4', etc.)
79
+
80
+ Usage: Provide detailed task description for autonomous execution. The agent will return results in a single response.`
81
+ },
82
+ inputSchema,
83
+
84
+ // 🔧 ULTRA FIX: Complete revert to original AgentTool pattern
85
+ async *call(
86
+ { description, prompt, model_name },
87
+ {
88
+ abortController,
89
+ options: { safeMode = false, forkNumber, messageLogName, verbose },
90
+ readFileTimestamps,
91
+ },
92
+ ) {
93
+ const startTime = Date.now()
94
+ const messages: MessageType[] = [createUserMessage(prompt)]
95
+ const tools = await getTaskTools(safeMode)
96
+
97
+ // We yield an initial message immediately so the UI
98
+ // doesn't move around when messages start streaming back.
99
+ yield {
100
+ type: 'progress',
101
+ content: createAssistantMessage(chalk.dim('Initializing…')),
102
+ normalizedMessages: normalizeMessages(messages),
103
+ tools,
104
+ }
105
+
106
+ const [taskPrompt, context, maxThinkingTokens] = await Promise.all([
107
+ getAgentPrompt(),
108
+ getContext(),
109
+ getMaxThinkingTokens(messages),
110
+ ])
111
+
112
+ // Simple model resolution - match original AgentTool pattern
113
+ const modelToUse = model_name || 'task'
114
+
115
+ // Inject model context to prevent self-referential expert consultations
116
+ taskPrompt.push(`\nIMPORTANT: You are currently running as ${modelToUse}. You do not need to consult ${modelToUse} via AskExpertModel since you ARE ${modelToUse}. Complete tasks directly using your capabilities.`)
117
+
118
+ let toolUseCount = 0
119
+
120
+ const getSidechainNumber = memoize(() =>
121
+ getNextAvailableLogSidechainNumber(messageLogName, forkNumber),
122
+ )
123
+
124
+ // Generate unique Task ID for this task execution
125
+ const taskId = generateAgentId()
126
+
127
+ // 🔧 ULTRA SIMPLIFIED: Exact original AgentTool pattern
128
+ for await (const message of query(
129
+ messages,
130
+ taskPrompt,
131
+ context,
132
+ hasPermissionsToUseTool,
133
+ {
134
+ abortController,
135
+ options: {
136
+ safeMode,
137
+ forkNumber,
138
+ messageLogName,
139
+ tools,
140
+ commands: [],
141
+ verbose,
142
+ maxThinkingTokens,
143
+ model: modelToUse,
144
+ },
145
+ messageId: getLastAssistantMessageId(messages),
146
+ agentId: taskId,
147
+ readFileTimestamps,
148
+ },
149
+ )) {
150
+ messages.push(message)
151
+
152
+ overwriteLog(
153
+ getMessagesPath(messageLogName, forkNumber, getSidechainNumber()),
154
+ messages.filter(_ => _.type !== 'progress'),
155
+ )
156
+
157
+ if (message.type !== 'assistant') {
158
+ continue
159
+ }
160
+
161
+ const normalizedMessages = normalizeMessages(messages)
162
+ for (const content of message.message.content) {
163
+ if (content.type !== 'tool_use') {
164
+ continue
165
+ }
166
+
167
+ toolUseCount++
168
+ yield {
169
+ type: 'progress',
170
+ content: normalizedMessages.find(
171
+ _ =>
172
+ _.type === 'assistant' &&
173
+ _.message.content[0]?.type === 'tool_use' &&
174
+ _.message.content[0].id === content.id,
175
+ ) as AssistantMessage,
176
+ normalizedMessages,
177
+ tools,
178
+ }
179
+ }
180
+ }
181
+
182
+ const normalizedMessages = normalizeMessages(messages)
183
+ const lastMessage = last(messages)
184
+ if (lastMessage?.type !== 'assistant') {
185
+ throw new Error('Last message was not an assistant message')
186
+ }
187
+
188
+ // 🔧 CRITICAL FIX: Match original AgentTool interrupt handling pattern exactly
189
+ if (
190
+ lastMessage.message.content.some(
191
+ _ => _.type === 'text' && _.text === INTERRUPT_MESSAGE,
192
+ )
193
+ ) {
194
+ yield {
195
+ type: 'progress',
196
+ content: lastMessage,
197
+ normalizedMessages,
198
+ tools,
199
+ }
200
+ } else {
201
+ const result = [
202
+ toolUseCount === 1 ? '1 tool use' : `${toolUseCount} tool uses`,
203
+ formatNumber(
204
+ (lastMessage.message.usage.cache_creation_input_tokens ?? 0) +
205
+ (lastMessage.message.usage.cache_read_input_tokens ?? 0) +
206
+ lastMessage.message.usage.input_tokens +
207
+ lastMessage.message.usage.output_tokens,
208
+ ) + ' tokens',
209
+ formatDuration(Date.now() - startTime),
210
+ ]
211
+ yield {
212
+ type: 'progress',
213
+ content: createAssistantMessage(`Done (${result.join(' · ')})`),
214
+ normalizedMessages,
215
+ tools,
216
+ }
217
+ }
218
+
219
+ // Output is an AssistantMessage, but since TaskTool is a tool, it needs
220
+ // to serialize its response to UserMessage-compatible content.
221
+ const data = lastMessage.message.content.filter(_ => _.type === 'text')
222
+ yield {
223
+ type: 'result',
224
+ data,
225
+ normalizedMessages,
226
+ resultForAssistant: this.renderResultForAssistant(data),
227
+ tools,
228
+ }
229
+ },
230
+
231
+ isReadOnly() {
232
+ return true // for now...
233
+ },
234
+ isConcurrencySafe() {
235
+ return true // Task tool supports concurrent execution in official implementation
236
+ },
237
+ async validateInput(input, context) {
238
+ if (!input.description || typeof input.description !== 'string') {
239
+ return {
240
+ result: false,
241
+ message: 'Description is required and must be a string',
242
+ }
243
+ }
244
+ if (!input.prompt || typeof input.prompt !== 'string') {
245
+ return {
246
+ result: false,
247
+ message: 'Prompt is required and must be a string',
248
+ }
249
+ }
250
+
251
+ // Model validation - similar to Edit tool error handling
252
+ if (input.model_name) {
253
+ const modelManager = getModelManager()
254
+ const availableModels = modelManager.getAllAvailableModelNames()
255
+
256
+ if (!availableModels.includes(input.model_name)) {
257
+ return {
258
+ result: false,
259
+ message: `Model '${input.model_name}' does not exist. Available models: ${availableModels.join(', ')}`,
260
+ meta: {
261
+ model_name: input.model_name,
262
+ availableModels,
263
+ },
264
+ }
265
+ }
266
+ }
267
+
268
+ return { result: true }
269
+ },
270
+ async isEnabled() {
271
+ return true
272
+ },
273
+ userFacingName() {
274
+ return 'Task'
275
+ },
276
+ needsPermissions() {
277
+ return false
278
+ },
279
+ renderResultForAssistant(data) {
280
+ return data
281
+ },
282
+ renderToolUseMessage({ description, prompt, model_name }, { verbose }) {
283
+ if (!description || !prompt) return null
284
+
285
+ const modelManager = getModelManager()
286
+ const defaultTaskModel = modelManager.getModelName('task')
287
+ const actualModel = model_name || defaultTaskModel
288
+ const promptPreview =
289
+ prompt.length > 80 ? prompt.substring(0, 80) + '...' : prompt
290
+
291
+ if (verbose) {
292
+ const theme = getTheme()
293
+ return (
294
+ <Box flexDirection="column">
295
+ <Text bold color={theme.text}>
296
+ 🚀 Task ({actualModel}): {description}
297
+ </Text>
298
+ <Box
299
+ marginTop={1}
300
+ paddingLeft={2}
301
+ borderLeftStyle="single"
302
+ borderLeftColor={theme.border}
303
+ >
304
+ <Text color={theme.secondaryText}>{promptPreview}</Text>
305
+ </Box>
306
+ </Box>
307
+ )
308
+ }
309
+
310
+ return `Task (${actualModel}): ${description}`
311
+ },
312
+ renderToolUseRejectedMessage() {
313
+ return <FallbackToolUseRejectedMessage />
314
+ },
315
+ renderToolResultMessage(content, { verbose }) {
316
+ const theme = getTheme()
317
+
318
+ if (Array.isArray(content)) {
319
+ const textBlocks = content.filter(block => block.type === 'text')
320
+ const totalLength = textBlocks.reduce(
321
+ (sum, block) => sum + block.text.length,
322
+ 0,
323
+ )
324
+ // 🔧 CRITICAL FIX: Use exact match for interrupt detection, not .includes()
325
+ const isInterrupted = content.some(
326
+ block =>
327
+ block.type === 'text' && block.text === INTERRUPT_MESSAGE,
328
+ )
329
+
330
+ if (isInterrupted) {
331
+ // 🔧 CRITICAL FIX: Match original system interrupt rendering exactly
332
+ return (
333
+ <Box flexDirection="row">
334
+ <Text>&nbsp;&nbsp;⎿ &nbsp;</Text>
335
+ <Text color={theme.error}>Interrupted by user</Text>
336
+ </Box>
337
+ )
338
+ }
339
+
340
+ return (
341
+ <Box flexDirection="column">
342
+ <Box justifyContent="space-between" width="100%">
343
+ <Box flexDirection="row">
344
+ <Text>&nbsp;&nbsp;⎿ &nbsp;</Text>
345
+ <Text>Task completed</Text>
346
+ {textBlocks.length > 0 && (
347
+ <Text color={theme.secondaryText}>
348
+ {' '}
349
+ ({totalLength} characters)
350
+ </Text>
351
+ )}
352
+ </Box>
353
+ </Box>
354
+ {verbose && textBlocks.length > 0 && (
355
+ <Box
356
+ marginTop={1}
357
+ paddingLeft={4}
358
+ borderLeftStyle="single"
359
+ borderLeftColor={theme.border}
360
+ >
361
+ <Text color={theme.secondaryText}>
362
+ {textBlocks
363
+ .slice(0, 2)
364
+ .map(block => block.text)
365
+ .join('\n')
366
+ .substring(0, 200)}
367
+ {totalLength > 200 ? '...' : ''}
368
+ </Text>
369
+ </Box>
370
+ )}
371
+ </Box>
372
+ )
373
+ }
374
+
375
+ return (
376
+ <Box flexDirection="row">
377
+ <Text>&nbsp;&nbsp;⎿ &nbsp;</Text>
378
+ <Text color={theme.secondaryText}>Task completed</Text>
379
+ </Box>
380
+ )
381
+ },
382
+ } satisfies Tool<typeof inputSchema, TextBlock[]>
@@ -0,0 +1 @@
1
+ export const TOOL_NAME = 'Task'
@@ -0,0 +1,56 @@
1
+ import { type Tool } from '../../Tool'
2
+ import { getTools, getReadOnlyTools } from '../../tools'
3
+ import { TaskTool } from './TaskTool'
4
+ import { BashTool } from '../BashTool/BashTool'
5
+ import { FileWriteTool } from '../FileWriteTool/FileWriteTool'
6
+ import { FileEditTool } from '../FileEditTool/FileEditTool'
7
+ import { NotebookEditTool } from '../NotebookEditTool/NotebookEditTool'
8
+ import { GlobTool } from '../GlobTool/GlobTool'
9
+ import { FileReadTool } from '../FileReadTool/FileReadTool'
10
+ import { getModelManager } from '../../utils/model'
11
+
12
+ export async function getTaskTools(safeMode: boolean): Promise<Tool[]> {
13
+ // No recursive tasks, yet..
14
+ return (await (!safeMode ? getTools() : getReadOnlyTools())).filter(
15
+ _ => _.name !== TaskTool.name,
16
+ )
17
+ }
18
+
19
+ export async function getPrompt(safeMode: boolean): Promise<string> {
20
+ const tools = await getTaskTools(safeMode)
21
+ const toolNames = tools.map(_ => _.name).join(', ')
22
+
23
+ // Add dynamic model information for Task tool prompts
24
+ const modelManager = getModelManager()
25
+ const availableModels = modelManager.getAllAvailableModelNames()
26
+ const currentTaskModel =
27
+ modelManager.getModelName('task') || '<Not configured>'
28
+
29
+ const modelInfo =
30
+ availableModels.length > 0
31
+ ? `
32
+
33
+ Available models for Task tool: ${availableModels.join(', ')}
34
+ Default task model: ${currentTaskModel}
35
+ Specify model_name parameter to use a specific model for the task.`
36
+ : ''
37
+
38
+ return `Launch a new agent that has access to the following tools: ${toolNames}. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries, use the Task tool to perform the search for you.${modelInfo}
39
+
40
+ When to use the Task tool:
41
+ - If you are searching for a keyword like "config" or "logger", or for questions like "which file does X?", the Task tool is strongly recommended
42
+
43
+ When NOT to use the Task tool:
44
+ - If you want to read a specific file path, use the ${FileReadTool.name} or ${GlobTool.name} tool instead of the Task tool, to find the match more quickly
45
+ - If you are searching for a specific class definition like "class Foo", use the ${GlobTool.name} tool instead, to find the match more quickly
46
+ - If you are searching for code within a specific file or set of 2-3 files, use the Read tool instead of the Task tool, to find the match more quickly
47
+ - Writing code and running bash commands (use other tools for that)
48
+ - Other tasks that are not related to searching for a keyword or file
49
+
50
+ Usage notes:
51
+ 1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
52
+ 2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
53
+ 3. Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.
54
+ 4. The agent's outputs should generally be trusted
55
+ 5. Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent`
56
+ }
@@ -0,0 +1,56 @@
1
+ import { z } from 'zod'
2
+ import React from 'react'
3
+ import { Text } from 'ink'
4
+ import { Tool } from '../../Tool'
5
+ import { DESCRIPTION, PROMPT } from './prompt'
6
+ import { getTheme } from '../../utils/theme'
7
+ import { MessageResponse } from '../../components/MessageResponse'
8
+ import { checkGate, logEvent } from '../../services/statsig'
9
+ import { USE_BEDROCK, USE_VERTEX } from '../../utils/model'
10
+
11
+ const thinkToolSchema = z.object({
12
+ thought: z.string().describe('Your thoughts.'),
13
+ })
14
+
15
+ export const ThinkTool = {
16
+ name: 'Think',
17
+ userFacingName: () => 'Think',
18
+ description: async () => DESCRIPTION,
19
+ inputSchema: thinkToolSchema,
20
+ isEnabled: async () =>
21
+ Boolean(process.env.THINK_TOOL) && (await checkGate('tengu_think_tool')),
22
+ isReadOnly: () => true,
23
+ isConcurrencySafe: () => true, // ThinkTool is read-only, safe for concurrent execution
24
+ needsPermissions: () => false,
25
+ prompt: async () => PROMPT,
26
+
27
+ async *call(input, { messageId }) {
28
+ logEvent('tengu_thinking', {
29
+ messageId,
30
+ thoughtLength: input.thought.length.toString(),
31
+ method: 'tool',
32
+ provider: USE_BEDROCK ? 'bedrock' : USE_VERTEX ? 'vertex' : '1p',
33
+ })
34
+
35
+ yield {
36
+ type: 'result',
37
+ resultForAssistant: 'Your thought has been logged.',
38
+ data: { thought: input.thought },
39
+ }
40
+ },
41
+
42
+ // This is never called -- it's special-cased in AssistantToolUseMessage
43
+ renderToolUseMessage(input) {
44
+ return input.thought
45
+ },
46
+
47
+ renderToolUseRejectedMessage() {
48
+ return (
49
+ <MessageResponse>
50
+ <Text color={getTheme().error}>Thought cancelled</Text>
51
+ </MessageResponse>
52
+ )
53
+ },
54
+
55
+ renderResultForAssistant: () => 'Your thought has been logged.',
56
+ } satisfies Tool<typeof thinkToolSchema>
@@ -0,0 +1,12 @@
1
+ export const DESCRIPTION =
2
+ 'This is a no-op tool that logs a thought. It is inspired by the tau-bench think tool.'
3
+ export const PROMPT = `Use the tool to think about something. It will not obtain new information or make any changes to the repository, but just log the thought. Use it when complex reasoning or brainstorming is needed.
4
+
5
+ Common use cases:
6
+ 1. When exploring a repository and discovering the source of a bug, call this tool to brainstorm several unique ways of fixing the bug, and assess which change(s) are likely to be simplest and most effective
7
+ 2. After receiving test results, use this tool to brainstorm ways to fix failing tests
8
+ 3. When planning a complex refactoring, use this tool to outline different approaches and their tradeoffs
9
+ 4. When designing a new feature, use this tool to think through architecture decisions and implementation details
10
+ 5. When debugging a complex issue, use this tool to organize your thoughts and hypotheses
11
+
12
+ The tool simply logs your thought process for better transparency and does not execute any code or make changes.`