@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.
- package/README.md +205 -72
- package/README.zh-CN.md +246 -0
- package/cli.js +62 -0
- package/package.json +45 -25
- package/scripts/postinstall.js +56 -0
- package/src/ProjectOnboarding.tsx +180 -0
- package/src/Tool.ts +53 -0
- package/src/commands/approvedTools.ts +53 -0
- package/src/commands/bug.tsx +20 -0
- package/src/commands/clear.ts +43 -0
- package/src/commands/compact.ts +120 -0
- package/src/commands/config.tsx +19 -0
- package/src/commands/cost.ts +18 -0
- package/src/commands/ctx_viz.ts +209 -0
- package/src/commands/doctor.ts +24 -0
- package/src/commands/help.tsx +19 -0
- package/src/commands/init.ts +37 -0
- package/src/commands/listen.ts +42 -0
- package/src/commands/login.tsx +51 -0
- package/src/commands/logout.tsx +40 -0
- package/src/commands/mcp.ts +41 -0
- package/src/commands/model.tsx +40 -0
- package/src/commands/modelstatus.tsx +20 -0
- package/src/commands/onboarding.tsx +34 -0
- package/src/commands/pr_comments.ts +59 -0
- package/src/commands/refreshCommands.ts +54 -0
- package/src/commands/release-notes.ts +34 -0
- package/src/commands/resume.tsx +30 -0
- package/src/commands/review.ts +49 -0
- package/src/commands/terminalSetup.ts +221 -0
- package/src/commands.ts +136 -0
- package/src/components/ApproveApiKey.tsx +93 -0
- package/src/components/AsciiLogo.tsx +13 -0
- package/src/components/AutoUpdater.tsx +148 -0
- package/src/components/Bug.tsx +367 -0
- package/src/components/Config.tsx +289 -0
- package/src/components/ConsoleOAuthFlow.tsx +326 -0
- package/src/components/Cost.tsx +23 -0
- package/src/components/CostThresholdDialog.tsx +46 -0
- package/src/components/CustomSelect/option-map.ts +42 -0
- package/src/components/CustomSelect/select-option.tsx +52 -0
- package/src/components/CustomSelect/select.tsx +143 -0
- package/src/components/CustomSelect/use-select-state.ts +414 -0
- package/src/components/CustomSelect/use-select.ts +35 -0
- package/src/components/FallbackToolUseRejectedMessage.tsx +15 -0
- package/src/components/FileEditToolUpdatedMessage.tsx +66 -0
- package/src/components/Help.tsx +215 -0
- package/src/components/HighlightedCode.tsx +33 -0
- package/src/components/InvalidConfigDialog.tsx +113 -0
- package/src/components/Link.tsx +32 -0
- package/src/components/LogSelector.tsx +86 -0
- package/src/components/Logo.tsx +145 -0
- package/src/components/MCPServerApprovalDialog.tsx +100 -0
- package/src/components/MCPServerDialogCopy.tsx +25 -0
- package/src/components/MCPServerMultiselectDialog.tsx +109 -0
- package/src/components/Message.tsx +219 -0
- package/src/components/MessageResponse.tsx +15 -0
- package/src/components/MessageSelector.tsx +211 -0
- package/src/components/ModeIndicator.tsx +88 -0
- package/src/components/ModelConfig.tsx +301 -0
- package/src/components/ModelListManager.tsx +223 -0
- package/src/components/ModelSelector.tsx +3208 -0
- package/src/components/ModelStatusDisplay.tsx +228 -0
- package/src/components/Onboarding.tsx +274 -0
- package/src/components/PressEnterToContinue.tsx +11 -0
- package/src/components/PromptInput.tsx +710 -0
- package/src/components/SentryErrorBoundary.ts +33 -0
- package/src/components/Spinner.tsx +129 -0
- package/src/components/StructuredDiff.tsx +184 -0
- package/src/components/TextInput.tsx +246 -0
- package/src/components/TokenWarning.tsx +31 -0
- package/src/components/ToolUseLoader.tsx +40 -0
- package/src/components/TrustDialog.tsx +106 -0
- package/src/components/binary-feedback/BinaryFeedback.tsx +63 -0
- package/src/components/binary-feedback/BinaryFeedbackOption.tsx +111 -0
- package/src/components/binary-feedback/BinaryFeedbackView.tsx +172 -0
- package/src/components/binary-feedback/utils.ts +220 -0
- package/src/components/messages/AssistantBashOutputMessage.tsx +22 -0
- package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +45 -0
- package/src/components/messages/AssistantRedactedThinkingMessage.tsx +19 -0
- package/src/components/messages/AssistantTextMessage.tsx +144 -0
- package/src/components/messages/AssistantThinkingMessage.tsx +40 -0
- package/src/components/messages/AssistantToolUseMessage.tsx +123 -0
- package/src/components/messages/UserBashInputMessage.tsx +28 -0
- package/src/components/messages/UserCommandMessage.tsx +30 -0
- package/src/components/messages/UserKodingInputMessage.tsx +28 -0
- package/src/components/messages/UserPromptMessage.tsx +35 -0
- package/src/components/messages/UserTextMessage.tsx +39 -0
- package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +12 -0
- package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +36 -0
- package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +31 -0
- package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +57 -0
- package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +35 -0
- package/src/components/messages/UserToolResultMessage/utils.tsx +56 -0
- package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +121 -0
- package/src/components/permissions/FallbackPermissionRequest.tsx +155 -0
- package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +182 -0
- package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +75 -0
- package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +164 -0
- package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +81 -0
- package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +242 -0
- package/src/components/permissions/PermissionRequest.tsx +103 -0
- package/src/components/permissions/PermissionRequestTitle.tsx +69 -0
- package/src/components/permissions/hooks.ts +44 -0
- package/src/components/permissions/toolUseOptions.ts +59 -0
- package/src/components/permissions/utils.ts +23 -0
- package/src/constants/betas.ts +5 -0
- package/src/constants/claude-asterisk-ascii-art.tsx +238 -0
- package/src/constants/figures.ts +4 -0
- package/src/constants/keys.ts +3 -0
- package/src/constants/macros.ts +6 -0
- package/src/constants/models.ts +935 -0
- package/src/constants/oauth.ts +18 -0
- package/src/constants/product.ts +17 -0
- package/src/constants/prompts.ts +177 -0
- package/src/constants/releaseNotes.ts +7 -0
- package/src/context/PermissionContext.tsx +149 -0
- package/src/context.ts +278 -0
- package/src/cost-tracker.ts +84 -0
- package/src/entrypoints/cli.tsx +1498 -0
- package/src/entrypoints/mcp.ts +176 -0
- package/src/history.ts +25 -0
- package/src/hooks/useApiKeyVerification.ts +59 -0
- package/src/hooks/useArrowKeyHistory.ts +55 -0
- package/src/hooks/useCanUseTool.ts +138 -0
- package/src/hooks/useCancelRequest.ts +39 -0
- package/src/hooks/useDoublePress.ts +42 -0
- package/src/hooks/useExitOnCtrlCD.ts +31 -0
- package/src/hooks/useInterval.ts +25 -0
- package/src/hooks/useLogMessages.ts +16 -0
- package/src/hooks/useLogStartupTime.ts +12 -0
- package/src/hooks/useNotifyAfterTimeout.ts +65 -0
- package/src/hooks/usePermissionRequestLogging.ts +44 -0
- package/src/hooks/useSlashCommandTypeahead.ts +137 -0
- package/src/hooks/useTerminalSize.ts +49 -0
- package/src/hooks/useTextInput.ts +315 -0
- package/src/messages.ts +37 -0
- package/src/permissions.ts +268 -0
- package/src/query.ts +704 -0
- package/src/screens/ConfigureNpmPrefix.tsx +197 -0
- package/src/screens/Doctor.tsx +219 -0
- package/src/screens/LogList.tsx +68 -0
- package/src/screens/REPL.tsx +792 -0
- package/src/screens/ResumeConversation.tsx +68 -0
- package/src/services/browserMocks.ts +66 -0
- package/src/services/claude.ts +1947 -0
- package/src/services/customCommands.ts +683 -0
- package/src/services/fileFreshness.ts +377 -0
- package/src/services/mcpClient.ts +564 -0
- package/src/services/mcpServerApproval.tsx +50 -0
- package/src/services/notifier.ts +40 -0
- package/src/services/oauth.ts +357 -0
- package/src/services/openai.ts +796 -0
- package/src/services/sentry.ts +3 -0
- package/src/services/statsig.ts +171 -0
- package/src/services/statsigStorage.ts +86 -0
- package/src/services/systemReminder.ts +406 -0
- package/src/services/vcr.ts +161 -0
- package/src/tools/ArchitectTool/ArchitectTool.tsx +122 -0
- package/src/tools/ArchitectTool/prompt.ts +15 -0
- package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +505 -0
- package/src/tools/BashTool/BashTool.tsx +270 -0
- package/src/tools/BashTool/BashToolResultMessage.tsx +38 -0
- package/src/tools/BashTool/OutputLine.tsx +48 -0
- package/src/tools/BashTool/prompt.ts +174 -0
- package/src/tools/BashTool/utils.ts +56 -0
- package/src/tools/FileEditTool/FileEditTool.tsx +316 -0
- package/src/tools/FileEditTool/prompt.ts +51 -0
- package/src/tools/FileEditTool/utils.ts +58 -0
- package/src/tools/FileReadTool/FileReadTool.tsx +371 -0
- package/src/tools/FileReadTool/prompt.ts +7 -0
- package/src/tools/FileWriteTool/FileWriteTool.tsx +297 -0
- package/src/tools/FileWriteTool/prompt.ts +10 -0
- package/src/tools/GlobTool/GlobTool.tsx +119 -0
- package/src/tools/GlobTool/prompt.ts +8 -0
- package/src/tools/GrepTool/GrepTool.tsx +147 -0
- package/src/tools/GrepTool/prompt.ts +11 -0
- package/src/tools/MCPTool/MCPTool.tsx +106 -0
- package/src/tools/MCPTool/prompt.ts +3 -0
- package/src/tools/MemoryReadTool/MemoryReadTool.tsx +127 -0
- package/src/tools/MemoryReadTool/prompt.ts +3 -0
- package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +89 -0
- package/src/tools/MemoryWriteTool/prompt.ts +3 -0
- package/src/tools/MultiEditTool/MultiEditTool.tsx +366 -0
- package/src/tools/MultiEditTool/prompt.ts +45 -0
- package/src/tools/NotebookEditTool/NotebookEditTool.tsx +298 -0
- package/src/tools/NotebookEditTool/prompt.ts +3 -0
- package/src/tools/NotebookReadTool/NotebookReadTool.tsx +266 -0
- package/src/tools/NotebookReadTool/prompt.ts +3 -0
- package/src/tools/StickerRequestTool/StickerRequestTool.tsx +93 -0
- package/src/tools/StickerRequestTool/prompt.ts +19 -0
- package/src/tools/TaskTool/TaskTool.tsx +382 -0
- package/src/tools/TaskTool/constants.ts +1 -0
- package/src/tools/TaskTool/prompt.ts +56 -0
- package/src/tools/ThinkTool/ThinkTool.tsx +56 -0
- package/src/tools/ThinkTool/prompt.ts +12 -0
- package/src/tools/TodoWriteTool/TodoWriteTool.tsx +289 -0
- package/src/tools/TodoWriteTool/prompt.ts +63 -0
- package/src/tools/lsTool/lsTool.tsx +269 -0
- package/src/tools/lsTool/prompt.ts +2 -0
- package/src/tools.ts +63 -0
- package/src/types/PermissionMode.ts +120 -0
- package/src/types/RequestContext.ts +72 -0
- package/src/utils/Cursor.ts +436 -0
- package/src/utils/PersistentShell.ts +373 -0
- package/src/utils/agentStorage.ts +97 -0
- package/src/utils/array.ts +3 -0
- package/src/utils/ask.tsx +98 -0
- package/src/utils/auth.ts +13 -0
- package/src/utils/autoCompactCore.ts +223 -0
- package/src/utils/autoUpdater.ts +318 -0
- package/src/utils/betas.ts +20 -0
- package/src/utils/browser.ts +14 -0
- package/src/utils/cleanup.ts +72 -0
- package/src/utils/commands.ts +261 -0
- package/src/utils/config.ts +771 -0
- package/src/utils/conversationRecovery.ts +54 -0
- package/src/utils/debugLogger.ts +1123 -0
- package/src/utils/diff.ts +42 -0
- package/src/utils/env.ts +57 -0
- package/src/utils/errors.ts +21 -0
- package/src/utils/exampleCommands.ts +108 -0
- package/src/utils/execFileNoThrow.ts +51 -0
- package/src/utils/expertChatStorage.ts +136 -0
- package/src/utils/file.ts +402 -0
- package/src/utils/fileRecoveryCore.ts +71 -0
- package/src/utils/format.tsx +44 -0
- package/src/utils/generators.ts +62 -0
- package/src/utils/git.ts +92 -0
- package/src/utils/globalLogger.ts +77 -0
- package/src/utils/http.ts +10 -0
- package/src/utils/imagePaste.ts +38 -0
- package/src/utils/json.ts +13 -0
- package/src/utils/log.ts +382 -0
- package/src/utils/markdown.ts +213 -0
- package/src/utils/messageContextManager.ts +289 -0
- package/src/utils/messages.tsx +938 -0
- package/src/utils/model.ts +836 -0
- package/src/utils/permissions/filesystem.ts +118 -0
- package/src/utils/ripgrep.ts +167 -0
- package/src/utils/sessionState.ts +49 -0
- package/src/utils/state.ts +25 -0
- package/src/utils/style.ts +29 -0
- package/src/utils/terminal.ts +49 -0
- package/src/utils/theme.ts +122 -0
- package/src/utils/thinking.ts +144 -0
- package/src/utils/todoStorage.ts +431 -0
- package/src/utils/tokens.ts +43 -0
- package/src/utils/toolExecutionController.ts +163 -0
- package/src/utils/unaryLogging.ts +26 -0
- package/src/utils/user.ts +37 -0
- package/src/utils/validate.ts +165 -0
- 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> ⎿ </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> ⎿ </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> ⎿ </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.`
|