Compare commits

..

2 Commits

Author SHA1 Message Date
Haileyesus
d638a8982c fix: do not show model description in chat view 2026-06-05 21:28:08 +03:00
Simos Mikelatos
f238050b85 feat(chat): open cost modal from token usage 2026-06-05 17:33:22 +00:00
5 changed files with 38 additions and 10 deletions

View File

@@ -311,7 +311,7 @@ export function useChatComposerState({
}, [addMessage]);
const executeCommand = useCallback(
async (command: SlashCommand, rawInput?: string) => {
async (command: SlashCommand, rawInput?: string, options?: { preserveInput?: boolean }) => {
if (!command || !selectedProject) {
return;
}
@@ -368,8 +368,10 @@ export function useChatComposerState({
const result = (await response.json()) as CommandExecutionResult;
if (result.type === 'builtin') {
handleBuiltInCommand(result);
setInput('');
inputValueRef.current = '';
if (!options?.preserveInput) {
setInput('');
inputValueRef.current = '';
}
} else if (result.type === 'custom') {
await handleCustomCommand(result);
}
@@ -400,6 +402,19 @@ export function useChatComposerState({
],
);
const showCostModal = useCallback(() => {
executeCommand(
{
name: '/cost',
description: 'Display token usage information',
namespace: 'builtin',
metadata: { type: 'builtin' },
} as SlashCommand,
'/cost',
{ preserveInput: true },
);
}, [executeCommand]);
const {
slashCommands,
slashCommandsCount,
@@ -1049,5 +1064,6 @@ export function useChatComposerState({
isInputFocused,
commandModalPayload,
closeCommandModal,
showCostModal,
};
}

View File

@@ -178,6 +178,7 @@ function ChatInterface({
isInputFocused: _isInputFocused,
commandModalPayload,
closeCommandModal,
showCostModal,
} = useChatComposerState({
selectedProject,
selectedSession,
@@ -368,6 +369,7 @@ function ChatInterface({
permissionMode={permissionMode}
onModeSwitch={cyclePermissionMode}
tokenBudget={tokenBudget}
onShowTokenUsage={showCostModal}
slashCommandsCount={slashCommandsCount}
onToggleCommandMenu={handleToggleCommandMenu}
hasInput={Boolean(input.trim())}

View File

@@ -58,6 +58,7 @@ interface ChatComposerProps {
permissionMode: PermissionMode | string;
onModeSwitch: () => void;
tokenBudget: Record<string, unknown> | null;
onShowTokenUsage: () => void;
slashCommandsCount: number;
onToggleCommandMenu: () => void;
hasInput: boolean;
@@ -111,6 +112,7 @@ export default function ChatComposer({
permissionMode,
onModeSwitch,
tokenBudget,
onShowTokenUsage,
slashCommandsCount,
onToggleCommandMenu,
hasInput,
@@ -353,7 +355,7 @@ export default function ChatComposer({
</div>
</button>
<TokenUsageSummary usage={tokenBudget} />
<TokenUsageSummary usage={tokenBudget} onClick={onShowTokenUsage} />
<PromptInputButton
tooltip={{ content: t('input.showAllCommands') }}

View File

@@ -277,11 +277,15 @@ export default function ProviderSelectionEmptyState({
>
<div className="min-w-0 flex-1">
<div className="truncate">{model.label}</div>
{model.description && (
{/*
// * Temporarly commented out because the description of models from claude
// * was a bit inconsistent. Will return it back when it becomes more consistent.
*/}
{/* {model.description && (
<div className="truncate text-xs text-muted-foreground">
{model.description}
</div>
)}
)} */}
</div>
{isSelected && (
<Check className="ml-auto h-4 w-4 shrink-0 text-primary" />

View File

@@ -2,6 +2,7 @@ import { ActivityIcon } from 'lucide-react';
type TokenUsageSummaryProps = {
usage: Record<string, unknown> | null;
onClick?: () => void;
};
const formatTokenCount = (value: number) => {
@@ -29,7 +30,7 @@ const readUsageNumber = (value: unknown) => {
return Number.isFinite(parsed) ? parsed : 0;
};
export default function TokenUsageSummary({ usage }: TokenUsageSummaryProps) {
export default function TokenUsageSummary({ usage, onClick }: TokenUsageSummaryProps) {
const breakdown =
usage?.breakdown && typeof usage.breakdown === 'object'
? usage.breakdown as Record<string, unknown>
@@ -39,15 +40,18 @@ export default function TokenUsageSummary({ usage }: TokenUsageSummaryProps) {
const usedTokens = readUsageNumber(usage?.used) || inputTokens + outputTokens;
return (
<div
className="inline-flex h-9 items-center gap-1.5 rounded-lg border border-border/70 bg-background/70 px-2 text-xs text-muted-foreground shadow-sm transition-colors hover:border-primary/25 hover:text-foreground sm:gap-2 sm:px-2.5"
<button
type="button"
onClick={onClick}
className="inline-flex h-9 items-center gap-1.5 rounded-lg border border-border/70 bg-background/70 px-2 text-xs text-muted-foreground shadow-sm transition-colors hover:border-primary/25 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 sm:gap-2 sm:px-2.5"
title={`${usedTokens.toLocaleString()} tokens used`}
aria-label="Show token usage"
>
<span className="grid h-5 w-5 place-items-center rounded-md bg-primary/10 text-primary">
<ActivityIcon className="h-3.5 w-3.5" />
</span>
<span className="font-medium text-foreground">{formatTokenCount(usedTokens)}</span>
<span className="hidden text-muted-foreground/70 sm:inline">tokens</span>
</div>
</button>
);
}