mirror of
https://github.com/cline/cline.git
synced 2026-09-11 05:47:07 +08:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cdee1d0f0 | ||
|
|
ab4f7a2703 | ||
|
|
737a433903 | ||
|
|
680c57d951 | ||
|
|
778587b049 | ||
|
|
c1e4b08a09 |
+55
-13
@@ -22,7 +22,7 @@ import { listFiles } from "../services/glob/list-files"
|
||||
import { regexSearchFiles } from "../services/ripgrep"
|
||||
import { parseSourceCodeForDefinitionsTopLevel } from "../services/tree-sitter"
|
||||
import { ApiConfiguration } from "../shared/api"
|
||||
import { findLast, findLastIndex } from "../shared/array"
|
||||
import { findLast, findLastIndex, parsePartialArrayString } from "../shared/array"
|
||||
import { AutoApprovalSettings } from "../shared/AutoApprovalSettings"
|
||||
import { BrowserSettings } from "../shared/BrowserSettings"
|
||||
import { ChatSettings } from "../shared/ChatSettings"
|
||||
@@ -35,8 +35,10 @@ import {
|
||||
ClineApiReqCancelReason,
|
||||
ClineApiReqInfo,
|
||||
ClineAsk,
|
||||
ClineAskQuestion,
|
||||
ClineAskUseMcpServer,
|
||||
ClineMessage,
|
||||
ClinePlanModeResponse,
|
||||
ClineSay,
|
||||
ClineSayBrowserAction,
|
||||
ClineSayTool,
|
||||
@@ -2720,9 +2722,14 @@ export class Cline {
|
||||
}
|
||||
case "ask_followup_question": {
|
||||
const question: string | undefined = block.params.question
|
||||
const optionsRaw: string | undefined = block.params.options
|
||||
const sharedMessage = {
|
||||
question: removeClosingTag("question", question),
|
||||
options: parsePartialArrayString(removeClosingTag("options", optionsRaw)),
|
||||
} satisfies ClineAskQuestion
|
||||
try {
|
||||
if (block.partial) {
|
||||
await this.ask("followup", removeClosingTag("question", question), block.partial).catch(() => {})
|
||||
await this.ask("followup", JSON.stringify(sharedMessage), block.partial).catch(() => {})
|
||||
break
|
||||
} else {
|
||||
if (!question) {
|
||||
@@ -2740,8 +2747,25 @@ export class Cline {
|
||||
})
|
||||
}
|
||||
|
||||
const { text, images } = await this.ask("followup", question, false)
|
||||
await this.say("user_feedback", text ?? "", images)
|
||||
const { text, images } = await this.ask("followup", JSON.stringify(sharedMessage), false)
|
||||
|
||||
// Check if options contains the text response
|
||||
if (optionsRaw && text && parsePartialArrayString(optionsRaw).includes(text)) {
|
||||
// Valid option selected, don't show user message in UI
|
||||
// Update last followup message with selected option
|
||||
const lastFollowupMessage = findLast(this.clineMessages, (m) => m.ask === "followup")
|
||||
if (lastFollowupMessage) {
|
||||
lastFollowupMessage.text = JSON.stringify({
|
||||
...sharedMessage,
|
||||
selected: text,
|
||||
} satisfies ClineAskQuestion)
|
||||
await this.saveClineMessages()
|
||||
}
|
||||
} else {
|
||||
// Option not selected, send user feedback
|
||||
await this.say("user_feedback", text ?? "", images)
|
||||
}
|
||||
|
||||
pushToolResult(formatResponse.toolResult(`<answer>\n${text}\n</answer>`, images))
|
||||
|
||||
break
|
||||
@@ -2754,11 +2778,14 @@ export class Cline {
|
||||
}
|
||||
case "plan_mode_response": {
|
||||
const response: string | undefined = block.params.response
|
||||
const optionsRaw: string | undefined = block.params.options
|
||||
const sharedMessage = {
|
||||
response: removeClosingTag("response", response),
|
||||
options: parsePartialArrayString(removeClosingTag("options", optionsRaw)),
|
||||
} satisfies ClinePlanModeResponse
|
||||
try {
|
||||
if (block.partial) {
|
||||
await this.ask("plan_mode_response", removeClosingTag("response", response), block.partial).catch(
|
||||
() => {},
|
||||
)
|
||||
await this.ask("plan_mode_response", JSON.stringify(sharedMessage), block.partial).catch(() => {})
|
||||
break
|
||||
} else {
|
||||
if (!response) {
|
||||
@@ -2777,7 +2804,7 @@ export class Cline {
|
||||
// }
|
||||
|
||||
this.isAwaitingPlanResponse = true
|
||||
let { text, images } = await this.ask("plan_mode_response", response, false)
|
||||
let { text, images } = await this.ask("plan_mode_response", JSON.stringify(sharedMessage), false)
|
||||
this.isAwaitingPlanResponse = false
|
||||
|
||||
// webview invoke sendMessage will send this marker in order to put webview into the proper state (responding to an ask) and as a flag to extension that the user switched to ACT mode.
|
||||
@@ -2785,6 +2812,25 @@ export class Cline {
|
||||
text = ""
|
||||
}
|
||||
|
||||
// Check if options contains the text response
|
||||
if (optionsRaw && text && parsePartialArrayString(optionsRaw).includes(text)) {
|
||||
// Valid option selected, don't show user message in UI
|
||||
// Update last followup message with selected option
|
||||
const lastPlanMessage = findLast(this.clineMessages, (m) => m.ask === "plan_mode_response")
|
||||
if (lastPlanMessage) {
|
||||
lastPlanMessage.text = JSON.stringify({
|
||||
...sharedMessage,
|
||||
selected: text,
|
||||
} satisfies ClinePlanModeResponse)
|
||||
await this.saveClineMessages()
|
||||
}
|
||||
} else {
|
||||
// Option not selected, send user feedback
|
||||
if (text || images?.length) {
|
||||
await this.say("user_feedback", text ?? "", images)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.didRespondToPlanAskBySwitchingMode) {
|
||||
pushToolResult(
|
||||
formatResponse.toolResult(
|
||||
@@ -2800,10 +2846,6 @@ export class Cline {
|
||||
pushToolResult(formatResponse.toolResult(`<user_message>\n${text}\n</user_message>`, images))
|
||||
}
|
||||
|
||||
if (text || images?.length) {
|
||||
await this.say("user_feedback", text ?? "", images)
|
||||
}
|
||||
|
||||
//
|
||||
break
|
||||
}
|
||||
@@ -3563,7 +3605,7 @@ export class Cline {
|
||||
details +=
|
||||
"\nIn this mode you should focus on information gathering, asking questions, and architecting a solution. Once you have a plan, use the plan_mode_response tool to engage in a conversational back and forth with the user. Do not use the plan_mode_response tool until you've gathered all the information you need e.g. with read_file or ask_followup_question."
|
||||
details +=
|
||||
'\n(Remember: If it seems the user wants you to use tools only available in Act Mode, you should ask the user to "toggle to Act mode" (use those words) - they will have to manually do this themselves with the Plan/Act toggle button below. You do not have the ability to switch to Act Mode yourself, and must wait for the user to do it themselves once they are satisfied with the plan.)'
|
||||
'\n(Remember: If it seems the user wants you to use tools only available in Act Mode, you should ask the user to "toggle to Act mode" (use those words) - they will have to manually do this themselves with the Plan/Act toggle button below. You do not have the ability to switch to Act Mode yourself, and must wait for the user to do it themselves once they are satisfied with the plan. You also cannot present an option to toggle to Act mode, as this will be something you need to direct the user to do manually themselves.)'
|
||||
} else {
|
||||
details += "\nACT MODE"
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ export const toolParamNames = [
|
||||
"arguments",
|
||||
"uri",
|
||||
"question",
|
||||
"options",
|
||||
"response",
|
||||
"result",
|
||||
] as const
|
||||
@@ -58,64 +59,3 @@ export interface ToolUse {
|
||||
params: Partial<Record<ToolParamName, string>>
|
||||
partial: boolean
|
||||
}
|
||||
|
||||
export interface ExecuteCommandToolUse extends ToolUse {
|
||||
name: "execute_command"
|
||||
// Pick<Record<ToolParamName, string>, "command"> makes "command" required, but Partial<> makes it optional
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "command" | "requires_approval">>
|
||||
}
|
||||
|
||||
export interface ReadFileToolUse extends ToolUse {
|
||||
name: "read_file"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path">>
|
||||
}
|
||||
|
||||
export interface WriteToFileToolUse extends ToolUse {
|
||||
name: "write_to_file"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path" | "content">>
|
||||
}
|
||||
|
||||
export interface ReplaceInFileToolUse extends ToolUse {
|
||||
name: "replace_in_file"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path" | "diff">>
|
||||
}
|
||||
|
||||
export interface SearchFilesToolUse extends ToolUse {
|
||||
name: "search_files"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path" | "regex" | "file_pattern">>
|
||||
}
|
||||
|
||||
export interface ListFilesToolUse extends ToolUse {
|
||||
name: "list_files"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path" | "recursive">>
|
||||
}
|
||||
|
||||
export interface ListCodeDefinitionNamesToolUse extends ToolUse {
|
||||
name: "list_code_definition_names"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "path">>
|
||||
}
|
||||
|
||||
export interface BrowserActionToolUse extends ToolUse {
|
||||
name: "browser_action"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "action" | "url" | "coordinate" | "text">>
|
||||
}
|
||||
|
||||
export interface UseMcpToolToolUse extends ToolUse {
|
||||
name: "use_mcp_tool"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "tool_name" | "arguments">>
|
||||
}
|
||||
|
||||
export interface AccessMcpResourceToolUse extends ToolUse {
|
||||
name: "access_mcp_resource"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "uri">>
|
||||
}
|
||||
|
||||
export interface AskFollowupQuestionToolUse extends ToolUse {
|
||||
name: "ask_followup_question"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "question">>
|
||||
}
|
||||
|
||||
export interface AttemptCompletionToolUse extends ToolUse {
|
||||
name: "attempt_completion"
|
||||
params: Partial<Pick<Record<ToolParamName, string>, "result" | "command">>
|
||||
}
|
||||
|
||||
@@ -216,9 +216,13 @@ Usage:
|
||||
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
|
||||
Parameters:
|
||||
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
|
||||
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually.
|
||||
Usage:
|
||||
<ask_followup_question>
|
||||
<question>Your question here</question>
|
||||
<options>
|
||||
Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]
|
||||
</options>
|
||||
</ask_followup_question>
|
||||
|
||||
## attempt_completion
|
||||
@@ -239,9 +243,13 @@ Your final result description here
|
||||
Description: Respond to the user's inquiry in an effort to plan a solution to the user's task. This tool should be used when you need to provide a response to a question or statement from the user about how you plan to accomplish the task. This tool is only available in PLAN MODE. The environment_details will specify the current mode, if it is not PLAN MODE then you should not use this tool. Depending on the user's message, you may ask questions to get clarification about the user's request, architect a solution to the task, and to brainstorm ideas with the user. For example, if the user's task is to create a website, you may start by asking some clarifying questions, then present a detailed plan for how you will accomplish the task given the context, and perhaps engage in a back and forth to finalize the details before the user switches you to ACT MODE to implement the solution.
|
||||
Parameters:
|
||||
- response: (required) The response to provide to the user. Do not try to use tools in this parameter, this is simply a chat response.
|
||||
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible choice or path forward in the planning process. This can help guide the discussion and make it easier for the user to provide input on key decisions. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. Do NOT present an option to toggle to Act mode, as this will be something you need to direct the user to do manually themselves.
|
||||
Usage:
|
||||
<plan_mode_response>
|
||||
<response>Your response here</response>
|
||||
<options>
|
||||
Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]
|
||||
</options>
|
||||
</plan_mode_response>
|
||||
|
||||
# Tool Use Examples
|
||||
@@ -813,7 +821,7 @@ You have access to two tools for working with files: **write_to_file** and **rep
|
||||
|
||||
## Important Considerations
|
||||
|
||||
- Using write_to_file requires providing the file’s complete final content.
|
||||
- Using write_to_file requires providing the file's complete final content.
|
||||
- If you only need to make small changes to an existing file, consider using replace_in_file instead to avoid unnecessarily rewriting the entire file.
|
||||
- While write_to_file should not be your default choice, don't hesitate to use it when the situation truly calls for it.
|
||||
|
||||
@@ -826,12 +834,12 @@ You have access to two tools for working with files: **write_to_file** and **rep
|
||||
## When to Use
|
||||
|
||||
- Small, localized changes like updating a few lines, function implementations, changing variable names, modifying a section of text, etc.
|
||||
- Targeted improvements where only specific portions of the file’s content needs to be altered.
|
||||
- Targeted improvements where only specific portions of the file's content needs to be altered.
|
||||
- Especially useful for long files where much of the file will remain unchanged.
|
||||
|
||||
## Advantages
|
||||
|
||||
- More efficient for minor edits, since you don’t need to supply the entire file content.
|
||||
- More efficient for minor edits, since you don't need to supply the entire file content.
|
||||
- Reduces the chance of errors that can occur when overwriting large files.
|
||||
|
||||
# Choosing the Appropriate Tool
|
||||
|
||||
@@ -572,6 +572,13 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
await this.togglePlanActModeWithChatSettings(message.chatSettings, message.chatContent)
|
||||
}
|
||||
break
|
||||
case "optionsResponse":
|
||||
await this.postMessageToWebview({
|
||||
type: "invoke",
|
||||
invoke: "sendMessage",
|
||||
text: message.text,
|
||||
})
|
||||
break
|
||||
// case "relaunchChromeDebugMode":
|
||||
// if (this.cline) {
|
||||
// this.cline.browserSession.relaunchChromeDebugMode()
|
||||
|
||||
@@ -199,6 +199,18 @@ export interface ClineAskUseMcpServer {
|
||||
uri?: string
|
||||
}
|
||||
|
||||
export interface ClinePlanModeResponse {
|
||||
response: string
|
||||
options?: string[]
|
||||
selected?: string
|
||||
}
|
||||
|
||||
export interface ClineAskQuestion {
|
||||
question: string
|
||||
options?: string[]
|
||||
selected?: string
|
||||
}
|
||||
|
||||
export interface ClineApiReqInfo {
|
||||
request?: string
|
||||
tokensIn?: number
|
||||
|
||||
@@ -61,6 +61,7 @@ export interface WebviewMessage {
|
||||
| "invoke"
|
||||
| "updateSettings"
|
||||
| "clearAllTaskHistory"
|
||||
| "optionsResponse"
|
||||
// | "relaunchChromeDebugMode"
|
||||
text?: string
|
||||
disabled?: boolean
|
||||
|
||||
@@ -20,3 +20,37 @@ export function findLast<T>(array: Array<T>, predicate: (value: T, index: number
|
||||
const index = findLastIndex(array, predicate)
|
||||
return index === -1 ? undefined : array[index]
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a partial or complete stringified array into an actual array.
|
||||
* Handles both complete JSON strings and incomplete array strings.
|
||||
* Splits on the specific tokens: [" ", " "]
|
||||
* @param arrayString A string representation of an array, which may be incomplete
|
||||
* @returns Array of strings parsed from the input
|
||||
*/
|
||||
export function parsePartialArrayString(arrayString: string): string[] {
|
||||
try {
|
||||
// Try parsing as complete JSON first
|
||||
return JSON.parse(arrayString)
|
||||
} catch {
|
||||
// If JSON parsing fails, handle as partial string
|
||||
const trimmed = arrayString.trim()
|
||||
if (!trimmed.startsWith('["')) {
|
||||
return []
|
||||
}
|
||||
|
||||
// Remove leading ["
|
||||
let content = trimmed.slice(2)
|
||||
// Remove trailing "] if it exists
|
||||
content = content.replace(/"]$/, "")
|
||||
if (!content) {
|
||||
return []
|
||||
}
|
||||
|
||||
// Split on ", " token and handle the parts
|
||||
return content
|
||||
.split('", "')
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import { useEvent, useSize } from "react-use"
|
||||
import styled from "styled-components"
|
||||
import {
|
||||
ClineApiReqInfo,
|
||||
ClineAskQuestion,
|
||||
ClineAskUseMcpServer,
|
||||
ClineMessage,
|
||||
ClinePlanModeResponse,
|
||||
ClineSayTool,
|
||||
COMPLETION_RESULT_CHANGES_FLAG,
|
||||
ExtensionMessage,
|
||||
@@ -15,6 +17,7 @@ import { COMMAND_OUTPUT_STRING, COMMAND_REQ_APP_STRING } from "../../../../src/s
|
||||
import { useExtensionState } from "../../context/ExtensionStateContext"
|
||||
import { findMatchingResourceOrTemplate, getMcpServerDisplayName } from "../../utils/mcp"
|
||||
import { vscode } from "../../utils/vscode"
|
||||
import { CheckmarkControl } from "../common/CheckmarkControl"
|
||||
import { CheckpointControls, CheckpointOverlay } from "../common/CheckpointControls"
|
||||
import CodeAccordian, { cleanPathPrefix } from "../common/CodeAccordian"
|
||||
import CodeBlock, { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock"
|
||||
@@ -23,10 +26,9 @@ import SuccessButton from "../common/SuccessButton"
|
||||
import Thumbnails from "../common/Thumbnails"
|
||||
import McpResourceRow from "../mcp/McpResourceRow"
|
||||
import McpToolRow from "../mcp/McpToolRow"
|
||||
import { highlightMentions } from "./TaskHeader"
|
||||
import CreditLimitError from "./CreditLimitError"
|
||||
import { CheckmarkControl } from "../common/CheckmarkControl"
|
||||
import McpResponseDisplay from "../mcp/McpResponseDisplay"
|
||||
import { OptionsButtons } from "./OptionsButtons"
|
||||
import { highlightMentions } from "./TaskHeader"
|
||||
|
||||
const ChatRowContainer = styled.div`
|
||||
padding: 10px 6px 10px 15px;
|
||||
@@ -1198,6 +1200,19 @@ export const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifi
|
||||
return null // Don't render anything when we get a completion_result ask without text
|
||||
}
|
||||
case "followup":
|
||||
let question: string | undefined
|
||||
let options: string[] | undefined
|
||||
let selected: string | undefined
|
||||
try {
|
||||
const parsedMessage = JSON.parse(message.text || "{}") as ClineAskQuestion
|
||||
question = parsedMessage.question
|
||||
options = parsedMessage.options
|
||||
selected = parsedMessage.selected
|
||||
} catch (e) {
|
||||
// legacy messages would pass question directly
|
||||
question = message.text
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{title && (
|
||||
@@ -1207,16 +1222,39 @@ export const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifi
|
||||
</div>
|
||||
)}
|
||||
<div style={{ paddingTop: 10 }}>
|
||||
<Markdown markdown={message.text} />
|
||||
<Markdown markdown={question} />
|
||||
<OptionsButtons
|
||||
options={options}
|
||||
selected={selected}
|
||||
isActive={isLast && lastModifiedMessage?.ask === "followup"}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
case "plan_mode_response":
|
||||
case "plan_mode_response": {
|
||||
let response: string | undefined
|
||||
let options: string[] | undefined
|
||||
let selected: string | undefined
|
||||
try {
|
||||
const parsedMessage = JSON.parse(message.text || "{}") as ClinePlanModeResponse
|
||||
response = parsedMessage.response
|
||||
options = parsedMessage.options
|
||||
selected = parsedMessage.selected
|
||||
} catch (e) {
|
||||
// legacy messages would pass response directly
|
||||
response = message.text
|
||||
}
|
||||
return (
|
||||
<div style={{}}>
|
||||
<Markdown markdown={message.text} />
|
||||
<Markdown markdown={response} />
|
||||
<OptionsButtons
|
||||
options={options}
|
||||
selected={selected}
|
||||
isActive={isLast && lastModifiedMessage?.ask === "plan_mode_response"}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import styled from "styled-components"
|
||||
import { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock"
|
||||
import { vscode } from "../../utils/vscode"
|
||||
|
||||
const OptionButton = styled.button<{ isSelected?: boolean; isNotSelectable?: boolean }>`
|
||||
padding: 8px 12px;
|
||||
background: ${(props) => (props.isSelected ? "var(--vscode-focusBorder)" : CODE_BLOCK_BG_COLOR)};
|
||||
color: ${(props) => (props.isSelected ? "white" : "var(--vscode-input-foreground)")};
|
||||
border: 1px solid var(--vscode-editorGroup-border);
|
||||
border-radius: 2px;
|
||||
cursor: ${(props) => (props.isNotSelectable ? "default" : "pointer")};
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
|
||||
${(props) =>
|
||||
!props.isNotSelectable &&
|
||||
`
|
||||
&:hover {
|
||||
background: var(--vscode-focusBorder);
|
||||
color: white;
|
||||
}
|
||||
`}
|
||||
`
|
||||
|
||||
export const OptionsButtons = ({
|
||||
options,
|
||||
selected,
|
||||
isActive,
|
||||
}: {
|
||||
options?: string[]
|
||||
selected?: string
|
||||
isActive?: boolean
|
||||
}) => {
|
||||
if (!options?.length) return null
|
||||
|
||||
const hasSelected = selected !== undefined && options.includes(selected)
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "8px",
|
||||
paddingTop: 15,
|
||||
// marginTop: "22px",
|
||||
}}>
|
||||
{/* <div style={{ color: "var(--vscode-descriptionForeground)", fontSize: "11px", textTransform: "uppercase" }}>
|
||||
SELECT ONE:
|
||||
</div> */}
|
||||
{options.map((option, index) => (
|
||||
<OptionButton
|
||||
key={index}
|
||||
isSelected={option === selected}
|
||||
isNotSelectable={hasSelected || !isActive}
|
||||
onClick={() => {
|
||||
if (hasSelected || !isActive) {
|
||||
return
|
||||
}
|
||||
vscode.postMessage({
|
||||
type: "optionsResponse",
|
||||
text: option,
|
||||
})
|
||||
}}>
|
||||
{option}
|
||||
</OptionButton>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -34,7 +34,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
onClose,
|
||||
}) => {
|
||||
const { apiConfiguration, currentTaskItem, checkpointTrackerErrorMessage } = useExtensionState()
|
||||
const [isTaskExpanded, setIsTaskExpanded] = useState(true)
|
||||
const [isTaskExpanded, setIsTaskExpanded] = useState(false)
|
||||
const [isTextExpanded, setIsTextExpanded] = useState(false)
|
||||
const [showSeeMore, setShowSeeMore] = useState(false)
|
||||
const textContainerRef = useRef<HTMLDivElement>(null)
|
||||
@@ -386,49 +386,52 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{shouldShowPromptCacheInfo && (cacheReads !== undefined || cacheWrites !== undefined) && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "4px",
|
||||
flexWrap: "wrap",
|
||||
}}>
|
||||
<span style={{ fontWeight: "bold" }}>Cache:</span>
|
||||
<span
|
||||
{shouldShowPromptCacheInfo &&
|
||||
(cacheReads !== undefined ||
|
||||
cacheWrites !== undefined ||
|
||||
apiConfiguration?.apiProvider === "anthropic") && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "3px",
|
||||
gap: "4px",
|
||||
flexWrap: "wrap",
|
||||
}}>
|
||||
<i
|
||||
className="codicon codicon-database"
|
||||
<span style={{ fontWeight: "bold" }}>Cache:</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
fontWeight: "bold",
|
||||
marginBottom: "-1px",
|
||||
}}
|
||||
/>
|
||||
+{formatLargeNumber(cacheWrites || 0)}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "3px",
|
||||
}}>
|
||||
<i
|
||||
className="codicon codicon-arrow-right"
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "3px",
|
||||
}}>
|
||||
<i
|
||||
className="codicon codicon-database"
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
fontWeight: "bold",
|
||||
marginBottom: "-1px",
|
||||
}}
|
||||
/>
|
||||
+{formatLargeNumber(cacheWrites || 0)}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
fontWeight: "bold",
|
||||
marginBottom: 0,
|
||||
}}
|
||||
/>
|
||||
{formatLargeNumber(cacheReads || 0)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "3px",
|
||||
}}>
|
||||
<i
|
||||
className="codicon codicon-arrow-right"
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
fontWeight: "bold",
|
||||
marginBottom: 0,
|
||||
}}
|
||||
/>
|
||||
{formatLargeNumber(cacheReads || 0)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ContextWindowComponent}
|
||||
{isCostAvailable && (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user