kimi-code / apps /vscode /webview-ui /src /components /ThinkingButton.tsx
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
f59fbe2 verified
Raw
History Blame Contribute Delete
3.09 kB
import { IconBulb, IconCheck } from "@tabler/icons-react";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import type { ThinkingMode } from "shared/legacy-sdk";
interface ThinkingButtonProps {
mode: ThinkingMode;
effort: string;
efforts?: string[];
alwaysOn?: boolean;
disabled?: boolean;
/** When set, rendered as a muted wrapping note below the effort options
* (e.g. the mid-conversation switch cache-cost notice). */
cacheNote?: string;
onToggle: () => void;
onSelectEffort: (effort: string) => void;
}
function label(effort: string): string {
return effort.charAt(0).toUpperCase() + effort.slice(1);
}
export function ThinkingButton({ mode, effort, efforts = [], alwaysOn = false, disabled, cacheNote, onToggle, onSelectEffort }: ThinkingButtonProps) {
if (mode === "none") return null;
const active = effort !== "off" || alwaysOn;
const button = (
<button
type="button"
onClick={mode === "switch" && !disabled ? onToggle : undefined}
disabled={disabled || mode === "always"}
className={cn(
"flex items-center gap-0.5 justify-center h-6 min-w-6 px-1 rounded-md transition-all",
active ? "bg-blue-500/15 text-blue-500" : "bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground",
!disabled && mode !== "always" && "cursor-pointer hover:bg-blue-500/25",
(disabled || mode === "always") && "cursor-default",
)}
>
<IconBulb className="size-4" />
{mode === "effort" && <span className="text-[9px] font-medium leading-none">{label(effort)}</span>}
</button>
);
if (mode === "effort") {
const options = alwaysOn ? efforts : ["off", ...efforts];
return (
<DropdownMenu>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild disabled={disabled}>{button}</DropdownMenuTrigger>
</TooltipTrigger>
<TooltipContent>Thinking effort: {label(effort)}</TooltipContent>
</Tooltip>
<DropdownMenuContent align="start">
{options.map((option) => (
<DropdownMenuItem key={option} onClick={() => onSelectEffort(option)} className="text-xs gap-2">
<IconCheck className={cn("size-3", option !== effort && "opacity-0")} />
{label(option)}
</DropdownMenuItem>
))}
{cacheNote !== undefined && (
<div className="w-44 px-2 py-1.5 text-[10px] leading-snug whitespace-normal text-muted-foreground">
{cacheNote}
</div>
)}
</DropdownMenuContent>
</DropdownMenu>
);
}
const tooltip = mode === "always" ? "Thinking is always enabled for this model" : active ? "Thinking enabled" : "Enable thinking";
return (
<Tooltip>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent>{tooltip}</TooltipContent>
</Tooltip>
);
}