|
|
@@ -1,13 +1,12 @@
|
|
|
import React, { memo, useMemo, useRef, useState } from "react"
|
|
|
import { useWindowSize } from "react-use"
|
|
|
-import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
|
|
import prettyBytes from "pretty-bytes"
|
|
|
import { useTranslation } from "react-i18next"
|
|
|
|
|
|
import { vscode } from "@/utils/vscode"
|
|
|
import { formatLargeNumber } from "@/utils/format"
|
|
|
import { calculateTokenDistribution, getMaxTokensForModel } from "@/utils/model-utils"
|
|
|
-import { Button } from "@/components/ui"
|
|
|
+import { Button, Badge } from "@/components/ui"
|
|
|
|
|
|
import { ClineMessage } from "../../../../src/shared/ExtensionMessage"
|
|
|
import { mentionRegexGlobal } from "../../../../src/shared/context-mentions"
|
|
|
@@ -17,6 +16,7 @@ import { useExtensionState } from "../../context/ExtensionStateContext"
|
|
|
import Thumbnails from "../common/Thumbnails"
|
|
|
import { normalizeApiConfiguration } from "../settings/ApiOptions"
|
|
|
import { DeleteTaskDialog } from "../history/DeleteTaskDialog"
|
|
|
+import { cn } from "@/lib/utils"
|
|
|
|
|
|
interface TaskHeaderProps {
|
|
|
task: ClineMessage
|
|
|
@@ -55,10 +55,15 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|
|
const shouldShowPromptCacheInfo = doesModelSupportPromptCache && apiConfiguration?.apiProvider !== "openrouter"
|
|
|
|
|
|
return (
|
|
|
- <div className="py-[10px] px-[13px]">
|
|
|
+ <div className="py-2 px-3">
|
|
|
<div
|
|
|
- className={`rounded p-[10px] flex flex-col gap-[6px] relative z-1 outline hover:outline-vscode-badge-foreground hover:text-vscode-badge-foreground transition-color duration-500 ${!!isTaskExpanded ? "outline-vscode-badge-foreground text-vscode-badge-foreground" : "outline-vscode-badge-foreground/80 text-vscode-badge-foreground/80"}`}>
|
|
|
- <div className="flex justify-between items-center">
|
|
|
+ className={cn(
|
|
|
+ "rounded-xs p-2.5 flex flex-col gap-1.5 relative z-1 border",
|
|
|
+ !!isTaskExpanded
|
|
|
+ ? "border-vscode-panel-border text-vscode-foreground"
|
|
|
+ : "border-vscode-panel-border/80 text-vscode-foreground/80",
|
|
|
+ )}>
|
|
|
+ <div className="flex justify-between items-center gap-2">
|
|
|
<div
|
|
|
className="flex items-center cursor-pointer -ml-0.5 select-none grow min-w-0"
|
|
|
onClick={() => setIsTaskExpanded(!isTaskExpanded)}>
|
|
|
@@ -73,14 +78,14 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|
|
{!isTaskExpanded && <span className="ml-1">{highlightMentions(task.text, false)}</span>}
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <VSCodeButton
|
|
|
- appearance="icon"
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="icon"
|
|
|
onClick={onClose}
|
|
|
- className="ml-1.5 shrink-0 text-vscode-badge-foreground"
|
|
|
- title={t("chat:task.closeAndStart")}>
|
|
|
- <span className="codicon codicon-close"></span>
|
|
|
- </VSCodeButton>
|
|
|
+ title={t("chat:task.closeAndStart")}
|
|
|
+ className="shrink-0 w-5 h-5">
|
|
|
+ <span className="codicon codicon-close" />
|
|
|
+ </Button>
|
|
|
</div>
|
|
|
{/* Collapsed state: Track context and cost if we have any */}
|
|
|
{!isTaskExpanded && contextWindow > 0 && (
|
|
|
@@ -90,11 +95,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|
|
contextTokens={contextTokens || 0}
|
|
|
maxTokens={getMaxTokensForModel(selectedModelInfo, apiConfiguration)}
|
|
|
/>
|
|
|
- {!!totalCost && (
|
|
|
- <div className="ml-2.5 bg-vscode-editor-foreground text-vscode-editor-background py-0.5 px-1 rounded-full text-[11px] font-medium inline-block shrink-0">
|
|
|
- ${totalCost?.toFixed(2)}
|
|
|
- </div>
|
|
|
- )}
|
|
|
+ {!!totalCost && <Badge>${totalCost.toFixed(2)}</Badge>}
|
|
|
</div>
|
|
|
)}
|
|
|
{/* Expanded state: Show task text and images */}
|
|
|
@@ -271,7 +272,7 @@ const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: Cont
|
|
|
<div className="flex-1 relative">
|
|
|
{/* Invisible overlay for hover area */}
|
|
|
<div
|
|
|
- className="absolute w-full cursor-pointer h-4 -top-[7px] z-5"
|
|
|
+ className="absolute w-full h-4 -top-[7px] z-5"
|
|
|
title={t("chat:tokenProgress.availableSpace", { amount: formatLargeNumber(availableSize) })}
|
|
|
data-testid="context-available-space"
|
|
|
/>
|
|
|
@@ -282,7 +283,7 @@ const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: Cont
|
|
|
<div className="relative h-full" style={{ width: `${currentPercent}%` }}>
|
|
|
{/* Invisible overlay for current tokens section */}
|
|
|
<div
|
|
|
- className="absolute cursor-pointer h-4 -top-[7px] w-full z-6"
|
|
|
+ className="absolute h-4 -top-[7px] w-full z-6"
|
|
|
title={t("chat:tokenProgress.tokensUsed", {
|
|
|
used: formatLargeNumber(safeContextTokens),
|
|
|
total: formatLargeNumber(safeContextWindow),
|
|
|
@@ -297,7 +298,7 @@ const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: Cont
|
|
|
<div className="relative h-full" style={{ width: `${reservedPercent}%` }}>
|
|
|
{/* Invisible overlay for reserved section */}
|
|
|
<div
|
|
|
- className="absolute cursor-pointer h-4 -top-[7px] w-full z-6"
|
|
|
+ className="absolute h-4 -top-[7px] w-full z-6"
|
|
|
title={t("chat:tokenProgress.reservedForResponse", {
|
|
|
amount: formatLargeNumber(reservedForOutput),
|
|
|
})}
|
|
|
@@ -312,7 +313,7 @@ const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: Cont
|
|
|
<div className="relative h-full" style={{ width: `${availablePercent}%` }}>
|
|
|
{/* Invisible overlay for available space */}
|
|
|
<div
|
|
|
- className="absolute cursor-pointer h-4 -top-[7px] w-full z-6"
|
|
|
+ className="absolute h-4 -top-[7px] w-full z-6"
|
|
|
title={t("chat:tokenProgress.availableSpace", {
|
|
|
amount: formatLargeNumber(availableSize),
|
|
|
})}
|