Cosmetic updates

This commit is contained in:
Saoud Rizwan 2024-09-10 16:25:38 -04:00
parent ade506d1f8
commit 3a4e8b8d96
7 changed files with 238 additions and 174 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -5,7 +5,7 @@
"version": "1.6.2", "version": "1.6.2",
"icon": "icons/icon.png", "icon": "icons/icon.png",
"galleryBanner": { "galleryBanner": {
"color": "#C1DCEA", "color": "#C7D1D9",
"theme": "light" "theme": "light"
}, },
"engines": { "engines": {

View File

@ -330,6 +330,9 @@ export class TerminalProcess extends EventEmitter<TerminalProcessEvents> {
data = lines.join("\n") data = lines.join("\n")
} }
// sometimes chunks have leading/trailing commas which we'll remove too
data = data.replace(/^,+|,+$/g, "")
// For non-immediately returning commands we want to show loading spinner right away but this wouldnt happen until it emits a line break, so as soon as we get any output we emit "" to let webview know to show spinner // For non-immediately returning commands we want to show loading spinner right away but this wouldnt happen until it emits a line break, so as soon as we get any output we emit "" to let webview know to show spinner
if (!didEmitEmptyLine && !this.fullOutput && data) { if (!didEmitEmptyLine && !this.fullOutput && data) {
this.emit("line", "") // empty line to indicate start of command output stream this.emit("line", "") // empty line to indicate start of command output stream

View File

@ -1,4 +1,4 @@
import { VSCodeBadge, VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react" import { VSCodeBadge, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
import deepEqual from "fast-deep-equal" import deepEqual from "fast-deep-equal"
import React, { memo, useMemo } from "react" import React, { memo, useMemo } from "react"
import ReactMarkdown from "react-markdown" import ReactMarkdown from "react-markdown"
@ -103,11 +103,11 @@ const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifiedMessa
<ProgressIndicator /> <ProgressIndicator />
), ),
cost != null ? ( cost != null ? (
<span style={{ color: normalColor, fontWeight: "bold" }}>API Request Complete</span> <span style={{ color: normalColor, fontWeight: "bold" }}>API Request</span>
) : apiRequestFailedMessage ? ( ) : apiRequestFailedMessage ? (
<span style={{ color: errorColor, fontWeight: "bold" }}>API Request Failed</span> <span style={{ color: errorColor, fontWeight: "bold" }}>API Request Failed</span>
) : ( ) : (
<span style={{ color: normalColor, fontWeight: "bold" }}>Making API Request...</span> <span style={{ color: normalColor, fontWeight: "bold" }}>API Request...</span>
), ),
] ]
case "followup": case "followup":
@ -299,15 +299,19 @@ const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifiedMessa
...headerStyle, ...headerStyle,
marginBottom: cost == null && apiRequestFailedMessage ? 10 : 0, marginBottom: cost == null && apiRequestFailedMessage ? 10 : 0,
justifyContent: "space-between", justifyContent: "space-between",
}}> cursor: "pointer",
userSelect: "none",
WebkitUserSelect: "none",
MozUserSelect: "none",
msUserSelect: "none",
}}
onClick={onToggleExpand}>
<div style={{ display: "flex", alignItems: "center", gap: "10px" }}> <div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
{icon} {icon}
{title} {title}
{cost != null && cost > 0 && <VSCodeBadge>${Number(cost)?.toFixed(4)}</VSCodeBadge>} {cost != null && cost > 0 && <VSCodeBadge>${Number(cost)?.toFixed(4)}</VSCodeBadge>}
</div> </div>
<VSCodeButton appearance="icon" aria-label="Toggle Details" onClick={onToggleExpand}> <span className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span>
<span className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span>
</VSCodeButton>
</div> </div>
{cost == null && apiRequestFailedMessage && ( {cost == null && apiRequestFailedMessage && (
<> <>
@ -391,24 +395,12 @@ const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifiedMessa
return ( return (
<div <div
style={{ style={{
backgroundColor: "var(--vscode-editor-inactiveSelectionBackground)", marginTop: -10,
borderRadius: "3px", width: "100%",
padding: "8px",
whiteSpace: "pre-line",
wordWrap: "break-word",
}}> }}>
<span
style={{
display: "block",
fontStyle: "italic",
marginBottom: "8px",
opacity: 0.8,
}}>
The user made the following changes:
</span>
<CodeAccordian <CodeAccordian
diff={tool.diff!} diff={tool.diff!}
path={tool.path!} isFeedback={true}
isExpanded={isExpanded} isExpanded={isExpanded}
onToggleExpand={onToggleExpand} onToggleExpand={onToggleExpand}
/> />
@ -627,7 +619,8 @@ const Markdown = memo(({ markdown }: { markdown?: string }) => {
// react-markdown lets us customize elements, so here we're using their example of replacing code blocks with SyntaxHighlighter. However when there are no language matches (` or ``` without a language specifier) then we default to a normal code element for inline code. Code blocks without a language specifier shouldn't be a common occurrence as we prompt Claude to always use a language specifier. // react-markdown lets us customize elements, so here we're using their example of replacing code blocks with SyntaxHighlighter. However when there are no language matches (` or ``` without a language specifier) then we default to a normal code element for inline code. Code blocks without a language specifier shouldn't be a common occurrence as we prompt Claude to always use a language specifier.
// when claude wraps text in thinking tags, he doesnt use line breaks so we need to insert those ourselves to render markdown correctly // when claude wraps text in thinking tags, he doesnt use line breaks so we need to insert those ourselves to render markdown correctly
const parsed = markdown?.replace(/<thinking>([\s\S]*?)<\/thinking>/g, (match, content) => { const parsed = markdown?.replace(/<thinking>([\s\S]*?)<\/thinking>/g, (match, content) => {
return `_<thinking>_\n\n${content}\n\n_</thinking>_` return content
// return `_<thinking>_\n\n${content}\n\n_</thinking>_`
}) })
return ( return (
<div style={{ wordBreak: "break-word", overflowWrap: "anywhere" }}> <div style={{ wordBreak: "break-word", overflowWrap: "anywhere" }}>
@ -704,6 +697,13 @@ const Markdown = memo(({ markdown }: { markdown?: string }) => {
whiteSpace: "pre-line", whiteSpace: "pre-line",
wordBreak: "break-word", wordBreak: "break-word",
overflowWrap: "anywhere", overflowWrap: "anywhere",
backgroundColor: "var(--vscode-textCodeBlock-background)",
color: "var(--vscode-textPreformat-foreground)",
fontFamily: "var(--vscode-editor-font-family)",
fontSize: "var(--vscode-editor-font-size)",
borderRadius: "3px",
border: "1px solid var(--vscode-textSeparator-foreground)",
// padding: "2px 4px",
}}> }}>
{children} {children}
</code> </code>

View File

@ -602,11 +602,12 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
// Since we have maxRows, when text is long enough it starts to overflow the bottom padding, appearing behind the thumbnails. To fix this, we use a transparent border to push the text up instead. (https://stackoverflow.com/questions/42631947/maintaining-a-padding-inside-of-text-area/52538410#52538410) // Since we have maxRows, when text is long enough it starts to overflow the bottom padding, appearing behind the thumbnails. To fix this, we use a transparent border to push the text up instead. (https://stackoverflow.com/questions/42631947/maintaining-a-padding-inside-of-text-area/52538410#52538410)
borderTop: "9px solid transparent", borderTop: "9px solid transparent",
borderBottom: `${thumbnailsHeight + 9}px solid transparent`, borderBottom: `${thumbnailsHeight + 9}px solid transparent`,
borderRight: "54px solid transparent", borderColor: "transparent",
borderLeft: "9px solid transparent", // borderRight: "54px solid transparent",
// borderLeft: "9px solid transparent", // NOTE: react-textarea-autosize doesn't calculate correct height when using borderLeft/borderRight so we need to use horizontal padding instead
// Instead of using boxShadow, we use a div with a border to better replicate the behavior when the textarea is focused // Instead of using boxShadow, we use a div with a border to better replicate the behavior when the textarea is focused
// boxShadow: "0px 0px 0px 1px var(--vscode-input-border)", // boxShadow: "0px 0px 0px 1px var(--vscode-input-border)",
padding: 0, padding: "0 50px 0 9px",
cursor: textAreaDisabled ? "not-allowed" : undefined, cursor: textAreaDisabled ? "not-allowed" : undefined,
flex: 1, flex: 1,
}} }}

View File

@ -7,6 +7,7 @@ interface CodeAccordianProps {
diff?: string diff?: string
language?: string | undefined language?: string | undefined
path?: string path?: string
isFeedback?: boolean
isExpanded: boolean isExpanded: boolean
onToggleExpand: () => void onToggleExpand: () => void
} }
@ -19,7 +20,7 @@ The replace method removes these matched characters, effectively trimming the st
*/ */
const removeLeadingNonAlphanumeric = (path: string): string => path.replace(/^[^a-zA-Z0-9]+/, "") const removeLeadingNonAlphanumeric = (path: string): string => path.replace(/^[^a-zA-Z0-9]+/, "")
const CodeAccordian = ({ code, diff, language, path, isExpanded, onToggleExpand }: CodeAccordianProps) => { const CodeAccordian = ({ code, diff, language, path, isFeedback, isExpanded, onToggleExpand }: CodeAccordianProps) => {
const inferredLanguage = useMemo( const inferredLanguage = useMemo(
() => code && (language ?? (path ? getLanguageFromPath(path) : undefined)), () => code && (language ?? (path ? getLanguageFromPath(path) : undefined)),
[path, language, code] [path, language, code]
@ -33,7 +34,7 @@ const CodeAccordian = ({ code, diff, language, path, isExpanded, onToggleExpand
overflow: "hidden", // This ensures the inner scrollable area doesn't overflow the rounded corners overflow: "hidden", // This ensures the inner scrollable area doesn't overflow the rounded corners
border: "1px solid var(--vscode-editorGroup-border)", border: "1px solid var(--vscode-editorGroup-border)",
}}> }}>
{path && ( {(path || isFeedback) && (
<div <div
style={{ style={{
color: "var(--vscode-descriptionForeground)", color: "var(--vscode-descriptionForeground)",
@ -42,25 +43,34 @@ const CodeAccordian = ({ code, diff, language, path, isExpanded, onToggleExpand
alignItems: "center", alignItems: "center",
padding: "6px 10px", padding: "6px 10px",
cursor: "pointer", cursor: "pointer",
userSelect: "none",
WebkitUserSelect: "none",
MozUserSelect: "none",
msUserSelect: "none",
}} }}
onClick={onToggleExpand}> onClick={onToggleExpand}>
<span <div style={{ display: "flex", alignItems: "center" }}>
style={{ {isFeedback && (
whiteSpace: "nowrap", <span className="codicon codicon-feedback" style={{ marginRight: "6px" }}></span>
overflow: "hidden", )}
textOverflow: "ellipsis", <span
marginRight: "8px", style={{
fontSize: "11px", whiteSpace: "nowrap",
// trick to get ellipsis at beginning of string overflow: "hidden",
direction: "rtl", textOverflow: "ellipsis",
textAlign: "left", marginRight: "8px",
}}> fontSize: "11px",
{removeLeadingNonAlphanumeric(path) + "\u200E"} // trick to get ellipsis at beginning of string
</span> direction: "rtl",
textAlign: "left",
}}>
{isFeedback ? "User Edits" : removeLeadingNonAlphanumeric(path ?? "") + "\u200E"}
</span>
</div>
<span className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span> <span className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span>
</div> </div>
)} )}
{(!path || isExpanded) && ( {(!(path || isFeedback) || isExpanded) && (
<div <div
//className="code-block-scrollable" this doesn't seem to be necessary anymore, on silicon macs it shows the native mac scrollbar instead of the vscode styled one //className="code-block-scrollable" this doesn't seem to be necessary anymore, on silicon macs it shows the native mac scrollbar instead of the vscode styled one
style={{ style={{

View File

@ -28,7 +28,8 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
onClose, onClose,
}) => { }) => {
const { apiConfiguration } = useExtensionState() const { apiConfiguration } = useExtensionState()
const [isExpanded, setIsExpanded] = useState(false) const [isTaskExpanded, setIsTaskExpanded] = useState(true)
const [isTextExpanded, setIsTextExpanded] = useState(false)
const [showSeeMore, setShowSeeMore] = useState(false) const [showSeeMore, setShowSeeMore] = useState(false)
const textContainerRef = useRef<HTMLDivElement>(null) const textContainerRef = useRef<HTMLDivElement>(null)
const textRef = useRef<HTMLDivElement>(null) const textRef = useRef<HTMLDivElement>(null)
@ -68,11 +69,11 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
const { height: windowHeight, width: windowWidth } = useWindowSize() const { height: windowHeight, width: windowWidth } = useWindowSize()
useEffect(() => { useEffect(() => {
if (isExpanded && textContainerRef.current) { if (isTextExpanded && textContainerRef.current) {
const maxHeight = windowHeight * (1 / 2) const maxHeight = windowHeight * (1 / 2)
textContainerRef.current.style.maxHeight = `${maxHeight}px` textContainerRef.current.style.maxHeight = `${maxHeight}px`
} }
}, [isExpanded, windowHeight]) }, [isTextExpanded, windowHeight])
useEffect(() => { useEffect(() => {
if (textRef.current && textContainerRef.current) { if (textRef.current && textContainerRef.current) {
@ -83,7 +84,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
const isOverflowing = textRef.current.scrollHeight > textContainerHeight const isOverflowing = textRef.current.scrollHeight > textContainerHeight
// necessary to show see more button again if user resizes window to expand and then back to collapse // necessary to show see more button again if user resizes window to expand and then back to collapse
if (!isOverflowing) { if (!isOverflowing) {
setIsExpanded(false) setIsTextExpanded(false)
} }
setShowSeeMore(isOverflowing) setShowSeeMore(isOverflowing)
} }
@ -96,10 +97,10 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
backgroundColor: "var(--vscode-badge-background)", backgroundColor: "var(--vscode-badge-background)",
color: "var(--vscode-badge-foreground)", color: "var(--vscode-badge-foreground)",
borderRadius: "3px", borderRadius: "3px",
padding: "12px", padding: "9px 10px 9px 14px",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: "8px", gap: 6,
position: "relative", position: "relative",
zIndex: 1, zIndex: 1,
}}> }}>
@ -109,144 +110,191 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
justifyContent: "space-between", justifyContent: "space-between",
alignItems: "center", alignItems: "center",
}}> }}>
<span style={{ fontWeight: "bold" }}>Task</span> <div
<VSCodeButton style={{
appearance="icon" display: "flex",
onClick={onClose} alignItems: "center",
style={{ marginTop: "-6px", marginRight: "-4px" }}> cursor: "pointer",
marginLeft: -2,
userSelect: "none",
WebkitUserSelect: "none",
MozUserSelect: "none",
msUserSelect: "none",
flexGrow: 1,
minWidth: 0, // This allows the div to shrink below its content size
}}
onClick={() => setIsTaskExpanded(!isTaskExpanded)}>
<div style={{ display: "flex", alignItems: "center", flexShrink: 0 }}>
<span className={`codicon codicon-chevron-${isTaskExpanded ? "down" : "right"}`}></span>
</div>
<div
style={{
marginLeft: 6,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
flexGrow: 1,
minWidth: 0, // This allows the div to shrink below its content size
}}>
<span style={{ fontWeight: "bold" }}>Task{!isTaskExpanded && ":"}</span>
{!isTaskExpanded && <span style={{ marginLeft: 4 }}>{task.text}</span>}
</div>
</div>
{!isTaskExpanded && (
<div
style={{
marginLeft: 10,
backgroundColor: "color-mix(in srgb, var(--vscode-badge-foreground) 70%, transparent)",
color: "var(--vscode-badge-background)",
padding: "2px 4px",
borderRadius: "500px",
fontSize: "11px",
fontWeight: 500,
display: "inline-block",
flexShrink: 0,
}}>
${totalCost?.toFixed(4)}
</div>
)}
<VSCodeButton appearance="icon" onClick={onClose} style={{ marginLeft: 10, flexShrink: 0 }}>
<span className="codicon codicon-close"></span> <span className="codicon codicon-close"></span>
</VSCodeButton> </VSCodeButton>
</div> </div>
<div {isTaskExpanded && (
ref={textContainerRef} <>
style={{
fontSize: "var(--vscode-font-size)",
overflowY: isExpanded ? "auto" : "hidden",
wordBreak: "break-word",
overflowWrap: "anywhere",
position: "relative",
}}>
<div
ref={textRef}
style={{
display: "-webkit-box",
WebkitLineClamp: isExpanded ? "unset" : 3,
WebkitBoxOrient: "vertical",
overflow: "hidden",
whiteSpace: "pre-wrap",
wordBreak: "break-word",
overflowWrap: "anywhere",
}}>
{task.text}
</div>
{!isExpanded && showSeeMore && (
<div <div
ref={textContainerRef}
style={{ style={{
position: "absolute", marginTop: -2,
right: 0, fontSize: "var(--vscode-font-size)",
bottom: 0, overflowY: isTextExpanded ? "auto" : "hidden",
display: "flex", wordBreak: "break-word",
alignItems: "center", overflowWrap: "anywhere",
position: "relative",
}}> }}>
<div <div
ref={textRef}
style={{ style={{
width: 30, display: "-webkit-box",
height: "1.2em", WebkitLineClamp: isTextExpanded ? "unset" : 3,
background: WebkitBoxOrient: "vertical",
"linear-gradient(to right, transparent, var(--vscode-badge-background))", overflow: "hidden",
}} whiteSpace: "pre-wrap",
/> wordBreak: "break-word",
overflowWrap: "anywhere",
}}>
{task.text}
</div>
{!isTextExpanded && showSeeMore && (
<div
style={{
position: "absolute",
right: 0,
bottom: 0,
display: "flex",
alignItems: "center",
}}>
<div
style={{
width: 30,
height: "1.2em",
background:
"linear-gradient(to right, transparent, var(--vscode-badge-background))",
}}
/>
<div
style={{
cursor: "pointer",
color: "var(--vscode-textLink-foreground)",
paddingRight: 0,
paddingLeft: 3,
backgroundColor: "var(--vscode-badge-background)",
}}
onClick={() => setIsTextExpanded(!isTextExpanded)}>
See more
</div>
</div>
)}
</div>
{isTextExpanded && showSeeMore && (
<div <div
style={{ style={{
cursor: "pointer", cursor: "pointer",
color: "var(--vscode-textLink-foreground)", color: "var(--vscode-textLink-foreground)",
paddingRight: 0, marginLeft: "auto",
paddingLeft: 3, textAlign: "right",
backgroundColor: "var(--vscode-badge-background)", paddingRight: 2,
}} }}
onClick={() => setIsExpanded(!isExpanded)}> onClick={() => setIsTextExpanded(!isTextExpanded)}>
See more See less
</div> </div>
</div>
)}
</div>
{isExpanded && showSeeMore && (
<div
style={{
cursor: "pointer",
color: "var(--vscode-textLink-foreground)",
marginLeft: "auto",
textAlign: "right",
paddingRight: 2,
}}
onClick={() => setIsExpanded(!isExpanded)}>
See less
</div>
)}
{task.images && task.images.length > 0 && <Thumbnails images={task.images} />}
<div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}>
<div style={{ display: "flex", alignItems: "center", gap: "4px", flexWrap: "wrap" }}>
<span style={{ fontWeight: "bold" }}>Tokens:</span>
<span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
<i
className="codicon codicon-arrow-up"
style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-2px" }}
/>
{tokensIn?.toLocaleString()}
</span>
<span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
<i
className="codicon codicon-arrow-down"
style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-2px" }}
/>
{tokensOut?.toLocaleString()}
</span>
</div>
{(apiConfiguration?.apiProvider === "openai" || apiConfiguration?.apiProvider === "ollama") && (
<ExportButton />
)} )}
</div> {task.images && task.images.length > 0 && <Thumbnails images={task.images} />}
<div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
{(doesModelSupportPromptCache || cacheReads !== undefined || cacheWrites !== undefined) && ( <div
<div style={{ display: "flex", alignItems: "center", gap: "4px", flexWrap: "wrap" }}> style={{
<span style={{ fontWeight: "bold" }}>Cache:</span> display: "flex",
<span style={{ display: "flex", alignItems: "center", gap: "3px" }}> justifyContent: "space-between",
<i alignItems: "center",
className="codicon codicon-database" }}>
style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-1px" }} <div style={{ display: "flex", alignItems: "center", gap: "4px", flexWrap: "wrap" }}>
/> <span style={{ fontWeight: "bold" }}>Tokens:</span>
+{(cacheWrites || 0)?.toLocaleString()} <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
</span> <i
<span style={{ display: "flex", alignItems: "center", gap: "3px" }}> className="codicon codicon-arrow-up"
<i style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-2px" }}
className="codicon codicon-arrow-right" />
style={{ fontSize: "12px", fontWeight: "bold", marginBottom: 0 }} {tokensIn?.toLocaleString()}
/> </span>
{(cacheReads || 0)?.toLocaleString()} <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
</span> <i
</div> className="codicon codicon-arrow-down"
)} style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-2px" }}
{apiConfiguration?.apiProvider !== "openai" && apiConfiguration?.apiProvider !== "ollama" && ( />
<div {tokensOut?.toLocaleString()}
style={{ </span>
display: "flex", </div>
justifyContent: "space-between", {(apiConfiguration?.apiProvider === "openai" ||
alignItems: "center", apiConfiguration?.apiProvider === "ollama") && <ExportButton />}
}}>
<div style={{ display: "flex", alignItems: "center", gap: "4px" }}>
<span style={{ fontWeight: "bold" }}>API Cost:</span>
<span>${totalCost?.toFixed(4)}</span>
</div> </div>
<ExportButton />
{(doesModelSupportPromptCache || cacheReads !== undefined || cacheWrites !== undefined) && (
<div style={{ display: "flex", alignItems: "center", gap: "4px", flexWrap: "wrap" }}>
<span style={{ fontWeight: "bold" }}>Cache:</span>
<span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
<i
className="codicon codicon-database"
style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-1px" }}
/>
+{(cacheWrites || 0)?.toLocaleString()}
</span>
<span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
<i
className="codicon codicon-arrow-right"
style={{ fontSize: "12px", fontWeight: "bold", marginBottom: 0 }}
/>
{(cacheReads || 0)?.toLocaleString()}
</span>
</div>
)}
{apiConfiguration?.apiProvider !== "openai" &&
apiConfiguration?.apiProvider !== "ollama" && (
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}>
<div style={{ display: "flex", alignItems: "center", gap: "4px" }}>
<span style={{ fontWeight: "bold" }}>API Cost:</span>
<span>${totalCost?.toFixed(4)}</span>
</div>
<ExportButton />
</div>
)}
</div> </div>
)} </>
</div> )}
</div> </div>
{/* {apiProvider === "kodu" && ( {/* {apiProvider === "kodu" && (
<div <div
@ -284,10 +332,12 @@ const ExportButton = () => (
<VSCodeButton <VSCodeButton
appearance="icon" appearance="icon"
onClick={() => vscode.postMessage({ type: "exportCurrentTask" })} onClick={() => vscode.postMessage({ type: "exportCurrentTask" })}
style={{ style={
marginBottom: "-2px", {
marginRight: "-2.5px", // marginBottom: "-2px",
}}> // marginRight: "-2.5px",
}
}>
<div style={{ fontSize: "10.5px", fontWeight: "bold", opacity: 0.6 }}>EXPORT</div> <div style={{ fontSize: "10.5px", fontWeight: "bold", opacity: 0.6 }}>EXPORT</div>
</VSCodeButton> </VSCodeButton>
) )