@@ -12,6 +12,7 @@ import { normalizeApiConfiguration } from "@/components/settings/ApiOptions"
1212import { validateSlashCommand } from "@/utils/slash-commands"
1313import TaskTimeline from "./TaskTimeline"
1414import { TaskServiceClient } from "@/services/grpc-client"
15+ import HeroTooltip from "@/components/common/HeroTooltip"
1516
1617interface TaskHeaderProps {
1718 task : ClineMessage
@@ -136,12 +137,12 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
136137 )
137138 } , [ apiConfiguration ?. apiProvider , apiConfiguration ?. openAiModelInfo ] )
138139
139- const shouldShowPromptCacheInfo =
140- doesModelSupportPromptCache && apiConfiguration ?. apiProvider !== "openrouter" && apiConfiguration ?. apiProvider !== "cline"
141-
142- const shouldShowPromptCacheInfoClineOR =
143- doesModelSupportPromptCache &&
144- ( apiConfiguration ?. apiProvider === "openrouter" || apiConfiguration ?. apiProvider === "cline" )
140+ const shouldShowPromptCacheInfo = ( ) => {
141+ return (
142+ doesModelSupportPromptCache &&
143+ ( ( cacheReads !== undefined && cacheReads > 0 ) || ( cacheWrites !== undefined && cacheWrites > 0 ) )
144+ )
145+ }
145146
146147 const ContextWindowComponent = (
147148 < >
@@ -152,18 +153,6 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
152153 flexDirection : windowWidth < 270 ? "column" : "row" ,
153154 gap : "4px" ,
154155 } } >
155- < div
156- style = { {
157- display : "flex" ,
158- alignItems : "center" ,
159- gap : "4px" ,
160- flexShrink : 0 , // Prevents shrinking
161- } } >
162- < span style = { { fontWeight : "bold" } } >
163- { /* {windowWidth > 280 && windowWidth < 310 ? "Context:" : "Context Window:"} */ }
164- Context Window:
165- </ span >
166- </ div >
167156 < div
168157 style = { {
169158 display : "flex" ,
@@ -172,32 +161,39 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
172161 flex : 1 ,
173162 whiteSpace : "nowrap" ,
174163 } } >
175- < span > { formatLargeNumber ( lastApiReqTotalTokens || 0 ) } </ span >
164+ < HeroTooltip content = "Current tokens used in this request" >
165+ < span className = "cursor-pointer" > { formatLargeNumber ( lastApiReqTotalTokens || 0 ) } </ span >
166+ </ HeroTooltip >
176167 < div
177168 style = { {
178169 display : "flex" ,
179170 alignItems : "center" ,
180171 gap : "3px" ,
181172 flex : 1 ,
182173 } } >
183- < div
184- style = { {
185- flex : 1 ,
186- height : "4px" ,
187- backgroundColor : "color-mix(in srgb, var(--vscode-badge-foreground) 20%, transparent)" ,
188- borderRadius : "2px" ,
189- overflow : "hidden" ,
190- } } >
174+ < HeroTooltip content = "Context window usage" >
191175 < div
192176 style = { {
193- width : ` ${ ( ( lastApiReqTotalTokens || 0 ) / contextWindow ) * 100 } %` ,
194- height : "100% " ,
195- backgroundColor : "var(--vscode-badge-foreground)" ,
177+ flex : 1 ,
178+ height : "4px " ,
179+ backgroundColor : "color-mix(in srgb, var(--vscode-badge-foreground) 20%, transparent )" ,
196180 borderRadius : "2px" ,
181+ overflow : "hidden" ,
197182 } }
198- />
199- </ div >
200- < span > { formatLargeNumber ( contextWindow ) } </ span >
183+ className = "cursor-pointer" >
184+ < div
185+ style = { {
186+ width : `${ ( ( lastApiReqTotalTokens || 0 ) / contextWindow ) * 100 } %` ,
187+ height : "100%" ,
188+ backgroundColor : "var(--vscode-badge-foreground)" ,
189+ borderRadius : "2px" ,
190+ } }
191+ />
192+ </ div >
193+ </ HeroTooltip >
194+ < HeroTooltip content = "Maximum context window size for this model" >
195+ < span className = "cursor-pointer" > { formatLargeNumber ( contextWindow ) } </ span >
196+ </ HeroTooltip >
201197 </ div >
202198 </ div >
203199 </ div >
@@ -263,7 +259,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
263259 { ! isTaskExpanded && < span style = { { marginLeft : 4 } } > { highlightText ( task . text , false ) } </ span > }
264260 </ div >
265261 </ div >
266- { ! isTaskExpanded && isCostAvailable && (
262+ { isCostAvailable && (
267263 < div
268264 style = { {
269265 marginLeft : 10 ,
@@ -299,7 +295,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
299295 ref = { textRef }
300296 style = { {
301297 display : "-webkit-box" ,
302- WebkitLineClamp : isTextExpanded ? "unset" : 3 ,
298+ WebkitLineClamp : isTextExpanded ? "unset" : 2 ,
303299 WebkitBoxOrient : "vertical" ,
304300 overflow : "hidden" ,
305301 whiteSpace : "pre-wrap" ,
@@ -352,18 +348,19 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
352348 </ div >
353349 ) }
354350 { task . images && task . images . length > 0 && < Thumbnails images = { task . images } /> }
351+
355352 < div
356353 style = { {
357354 display : "flex" ,
358355 flexDirection : "column" ,
359- gap : "4px " ,
356+ gap : "2px " ,
360357 } } >
361358 < div
362359 style = { {
363360 display : "flex" ,
364361 justifyContent : "space-between" ,
365362 alignItems : "center" ,
366- height : 17 ,
363+ flexWrap : "wrap" ,
367364 } } >
368365 < div
369366 style = { {
@@ -375,140 +372,93 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
375372 < div style = { { display : "flex" , alignItems : "center" } } >
376373 < span style = { { fontWeight : "bold" } } > Tokens:</ span >
377374 </ div >
378- < span
379- style = { {
380- display : "flex" ,
381- alignItems : "center" ,
382- gap : "3px" ,
383- } } >
384- < i
385- className = "codicon codicon-arrow-up"
386- style = { {
387- fontSize : "12px" ,
388- fontWeight : "bold" ,
389- marginBottom : "-2px" ,
390- } }
391- />
392- { formatLargeNumber ( tokensIn || 0 ) }
393- </ span >
394- < span
395- style = { {
396- display : "flex" ,
397- alignItems : "center" ,
398- gap : "3px" ,
399- } } >
400- < i
401- className = "codicon codicon-arrow-down"
402- style = { {
403- fontSize : "12px" ,
404- fontWeight : "bold" ,
405- marginBottom : "-2px" ,
406- } }
407- />
408- { formatLargeNumber ( tokensOut || 0 ) }
409- </ span >
410- </ div >
411- { ! isCostAvailable && (
412- < DeleteButton taskSize = { formatSize ( currentTaskItem ?. size ) } taskId = { currentTaskItem ?. id } />
413- ) }
414- </ div >
415-
416- < TaskTimeline messages = { clineMessages } />
417-
418- { shouldShowPromptCacheInfoClineOR && cacheReads !== undefined && (
419- < div
420- style = { {
421- display : "flex" ,
422- alignItems : "center" ,
423- gap : "4px" ,
424- flexWrap : "wrap" ,
425- } } >
426- < span style = { { fontWeight : "bold" } } > Cache:</ span >
427- < span
428- style = { {
429- display : "flex" ,
430- alignItems : "center" ,
431- gap : "3px" ,
432- } } >
433- < i
434- className = "codicon codicon-arrow-right"
435- style = { {
436- fontSize : "12px" ,
437- fontWeight : "bold" ,
438- marginBottom : 0 ,
439- } }
440- />
441- { formatLargeNumber ( cacheReads || 0 ) }
442- </ span >
443- </ div >
444- ) }
445- { shouldShowPromptCacheInfo &&
446- ( cacheReads !== undefined ||
447- cacheWrites !== undefined ||
448- apiConfiguration ?. apiProvider === "anthropic" ) && (
449- < div
450- style = { {
451- display : "flex" ,
452- alignItems : "center" ,
453- gap : "4px" ,
454- flexWrap : "wrap" ,
455- } } >
456- < span style = { { fontWeight : "bold" } } > Cache:</ span >
457- < span
458- style = { {
459- display : "flex" ,
460- alignItems : "center" ,
461- gap : "3px" ,
462- } } >
375+ < HeroTooltip content = "Prompt Tokens" >
376+ < span className = "flex items-center gap-[3px] cursor-pointer" >
463377 < i
464- className = "codicon codicon-database "
378+ className = "codicon codicon-arrow-up "
465379 style = { {
466380 fontSize : "12px" ,
467381 fontWeight : "bold" ,
468- marginBottom : "-1px " ,
382+ marginBottom : "-2px " ,
469383 } }
470384 />
471- + { formatLargeNumber ( cacheWrites || 0 ) }
385+ { formatLargeNumber ( tokensIn || 0 ) }
472386 </ span >
473- < span
474- style = { {
475- display : "flex" ,
476- alignItems : "center" ,
477- gap : "3px" ,
478- } } >
387+ </ HeroTooltip >
388+ < HeroTooltip content = "Completion Tokens" >
389+ < span className = "flex items-center gap-[3px] cursor-pointer" >
479390 < i
480- className = "codicon codicon-arrow-right "
391+ className = "codicon codicon-arrow-down "
481392 style = { {
482393 fontSize : "12px" ,
483394 fontWeight : "bold" ,
484- marginBottom : 0 ,
395+ marginBottom : "-2px" ,
485396 } }
486397 />
487- { formatLargeNumber ( cacheReads || 0 ) }
398+ { formatLargeNumber ( tokensOut || 0 ) }
488399 </ span >
489- </ div >
400+ </ HeroTooltip >
401+ </ div >
402+ { ! shouldShowPromptCacheInfo ( ) && (
403+ < DeleteButton taskSize = { formatSize ( currentTaskItem ?. size ) } taskId = { currentTaskItem ?. id } />
490404 ) }
491- { ContextWindowComponent }
492- { isCostAvailable && (
405+ </ div >
406+ { shouldShowPromptCacheInfo ( ) && (
493407 < div
494408 style = { {
495409 display : "flex" ,
496410 justifyContent : "space-between" ,
497411 alignItems : "center" ,
498- height : 17 ,
412+ flexWrap : "wrap" ,
499413 } } >
500414 < div
501415 style = { {
502416 display : "flex" ,
503417 alignItems : "center" ,
504418 gap : "4px" ,
419+ flexWrap : "wrap" ,
505420 } } >
506- < span style = { { fontWeight : "bold" } } > API Cost:</ span >
507- < span > ${ totalCost ?. toFixed ( 4 ) } </ span >
421+ < div style = { { display : "flex" , alignItems : "center" } } >
422+ < span style = { { fontWeight : "bold" } } > Cache:</ span >
423+ </ div >
424+ { cacheWrites !== undefined && cacheWrites > 0 && (
425+ < HeroTooltip content = "Tokens written to cache" >
426+ < span className = "flex items-center gap-[3px] cursor-pointer" >
427+ < i
428+ className = "codicon codicon-database"
429+ style = { {
430+ fontSize : "12px" ,
431+ fontWeight : "bold" ,
432+ marginBottom : "-1px" ,
433+ } }
434+ />
435+ +{ formatLargeNumber ( cacheWrites || 0 ) }
436+ </ span >
437+ </ HeroTooltip >
438+ ) }
439+ { cacheReads !== undefined && cacheReads > 0 && (
440+ < HeroTooltip content = "Tokens read from cache" >
441+ < span className = "flex items-center gap-[3px] cursor-pointer" >
442+ < i
443+ className = { "codicon codicon-arrow-right" }
444+ style = { {
445+ fontSize : "12px" ,
446+ fontWeight : "bold" ,
447+ marginBottom : 0 ,
448+ } }
449+ />
450+ { formatLargeNumber ( cacheReads || 0 ) }
451+ </ span >
452+ </ HeroTooltip >
453+ ) }
508454 </ div >
509455 < DeleteButton taskSize = { formatSize ( currentTaskItem ?. size ) } taskId = { currentTaskItem ?. id } />
510456 </ div >
511457 ) }
458+ < div className = "flex flex-col" >
459+ < TaskTimeline messages = { clineMessages } />
460+ { ContextWindowComponent }
461+ </ div >
512462 { checkpointTrackerErrorMessage && (
513463 < div
514464 style = { {
@@ -673,23 +623,25 @@ const DeleteButton: React.FC<{
673623 taskSize : string
674624 taskId ?: string
675625} > = ( { taskSize, taskId } ) => (
676- < VSCodeButton
677- appearance = "icon"
678- onClick = { ( ) => taskId && TaskServiceClient . deleteTasksWithIds ( { value : [ taskId ] } ) }
679- style = { { padding : "0px 0px" } } >
680- < div
681- style = { {
682- display : "flex" ,
683- alignItems : "center" ,
684- gap : "3px" ,
685- fontSize : "10px" ,
686- fontWeight : "bold" ,
687- opacity : 0.6 ,
688- } } >
689- < i className = { `codicon codicon-trash` } />
690- { taskSize }
691- </ div >
692- </ VSCodeButton >
626+ < HeroTooltip content = "Delete Task & Checkpoints" >
627+ < VSCodeButton
628+ appearance = "icon"
629+ onClick = { ( ) => taskId && TaskServiceClient . deleteTasksWithIds ( { value : [ taskId ] } ) }
630+ style = { { padding : "0px 0px" } } >
631+ < div
632+ style = { {
633+ display : "flex" ,
634+ alignItems : "center" ,
635+ gap : "3px" ,
636+ fontSize : "10px" ,
637+ fontWeight : "bold" ,
638+ opacity : 0.6 ,
639+ } } >
640+ < i className = { `codicon codicon-trash` } />
641+ { taskSize }
642+ </ div >
643+ </ VSCodeButton >
644+ </ HeroTooltip >
693645)
694646
695647// const ExportButton = () => (
0 commit comments