chore: update '@folo-services/ai-tools' version to 0.2.65 and enhance TokenUsagePill component

- Bumped the version of '@folo-services/ai-tools' to 0.2.65 in pnpm-lock.yaml and pnpm-workspace.yaml.
- Refactored the TokenUsagePill component to improve structure and added localization support for token usage information.
- Introduced new model info and provider info sections for better user clarity.

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei 2025-11-20 20:00:40 +08:00
parent f364f4b0f0
commit 0099f30a03
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
8 changed files with 185 additions and 100 deletions

View File

@ -129,16 +129,14 @@ export const AIChatMessage: React.FC<AIChatMessageProps> = React.memo(
<span>Copy</span>
</button>
{message.metadata && (
<TokenUsagePill metadata={message.metadata}>
<button
type="button"
className="absolute right-0 flex items-center gap-1 rounded-md px-2 py-1 text-xs text-text-secondary transition-colors hover:bg-fill-tertiary"
>
<i className="i-mgc-information-cute-re size-3" />
</button>
</TokenUsagePill>
)}
<TokenUsagePill metadata={originalMessage.metadata}>
<button
type="button"
className="absolute right-0 flex items-center gap-1 rounded-md px-2 py-1 text-xs text-text-secondary transition-colors hover:bg-fill-tertiary"
>
<i className="i-mgc-information-cute-re size-3" />
</button>
</TokenUsagePill>
</div>
)}
<div className="h-6" />

View File

@ -8,6 +8,7 @@ import { isFreeRole } from "@follow/constants"
import { useUserRole } from "@follow/store/user/hooks"
import type { BizUIMetadata } from "@folo-services/ai-tools"
import * as React from "react"
import { useTranslation } from "react-i18next"
import { formatTokenCountString } from "~/modules/settings/tabs/ai/usage/utils"
@ -22,10 +23,51 @@ const formatDuration = (ms: number): string => {
return `${ms}ms`
}
export const TokenUsagePill: React.FC<TokenUsagePillProps> = ({ metadata, children }) => {
const userRole = useUserRole()
if (!metadata) return null
const isFreeUser = userRole ? isFreeRole(userRole) : false
interface ModelInfoSectionProps {
metadata: BizUIMetadata
}
const ModelInfoSection: React.FC<ModelInfoSectionProps> = ({ metadata }) => {
const { t } = useTranslation("ai")
const hasProviderInfo = metadata.provider != null || metadata.providerType != null
return (
<>
<div className="mb-2 flex flex-col gap-2">
<div className="text-xs text-text">{t("token_usage_pill.model_info")}</div>
<div className="font-mono text-xs text-text-secondary">
{metadata.modelUsed ?? t("token_usage_pill.unknown")}
</div>
</div>
{hasProviderInfo && (
<div className="mb-2 flex flex-col gap-2">
<div className="text-xs text-text">{t("token_usage_pill.provider_info")}</div>
<div className="font-mono text-xs text-text-secondary">
<span>{metadata.provider ?? t("token_usage_pill.unknown")}</span>
{metadata.providerType && (
<span className="ml-2 text-text-tertiary">
<span>(</span>
<span>
{metadata.providerType === "byok"
? t("token_usage_pill.byok")
: t("token_usage_pill.system")}
</span>
<span>)</span>
</span>
)}
</div>
</div>
)}
</>
)
}
interface FreeUserTokenUsageProps {
metadata: BizUIMetadata
}
const FreeUserTokenUsage: React.FC<FreeUserTokenUsageProps> = ({ metadata }) => {
const { t } = useTranslation("ai")
const summarizedTokens =
metadata.billedTokens ??
metadata.totalTokens ??
@ -33,76 +75,93 @@ export const TokenUsagePill: React.FC<TokenUsagePillProps> = ({ metadata, childr
metadata.contextTokens ??
null
return (
<>
<ModelInfoSection metadata={metadata} />
<div className="space-y-2 text-xs">
<div className="font-medium text-text">{t("token_usage_pill.credits_usage")}</div>
<div className="flex items-center justify-between gap-2 rounded-md border border-border px-3 py-2">
<span className="text-text-secondary">{t("token_usage_pill.credits")}:</span>
<span className="font-mono text-text">
{summarizedTokens != null ? formatTokenCountString(summarizedTokens) : "—"}
</span>
</div>
</div>
</>
)
}
interface NormalUserTokenUsageProps {
metadata: BizUIMetadata
}
const NormalUserTokenUsage: React.FC<NormalUserTokenUsageProps> = ({ metadata }) => {
const { t } = useTranslation("ai")
const hasBillingMultiplier =
metadata.billingMultiplier != null && metadata.billingMultiplier !== 1
const hasDuration = metadata.duration != null
return (
<>
<ModelInfoSection metadata={metadata} />
<div className="space-y-2 text-xs">
<div className="font-medium text-text">{t("token_usage_pill.credits_usage")}</div>
<div className="grid grid-cols-2 gap-x-4 gap-y-1">
{metadata.totalTokens != null && (
<div className="flex justify-between gap-2">
<span className="text-text-secondary">{t("token_usage_pill.total")}:</span>
<span className="font-mono text-text">
{formatTokenCountString(metadata.totalTokens)}
</span>
</div>
)}
{metadata.billedTokens != null && (
<div className="flex justify-between gap-2">
<span className="text-text-secondary">{t("token_usage_pill.billed")}:</span>
<span className="font-mono">{formatTokenCountString(metadata.billedTokens)}</span>
</div>
)}
</div>
{(hasDuration || hasBillingMultiplier) && (
<>
<hr className="border-fill-secondary" />
<div className="grid grid-cols-2 gap-x-4 gap-y-1">
{hasDuration && (
<div className="flex justify-between gap-2">
<span className="text-text-secondary">{t("token_usage_pill.duration")}:</span>
<span className="font-mono text-text">{formatDuration(metadata.duration!)}</span>
</div>
)}
{hasBillingMultiplier && (
<div className="flex justify-between gap-2">
<span className="text-text-secondary">{t("token_usage_pill.multiplier")}:</span>
<span className="font-mono text-text">{metadata.billingMultiplier!}×</span>
</div>
)}
</div>
</>
)}
</div>
</>
)
}
export const TokenUsagePill: React.FC<TokenUsagePillProps> = ({ metadata, children }) => {
const userRole = useUserRole()
if (!metadata) return null
const isFreeUser = userRole ? isFreeRole(userRole) : false
return (
<Tooltip>
<TooltipTrigger asChild>{children}</TooltipTrigger>
<TooltipPortal>
<TooltipContent side="top" className="p-2" align="center" sideOffset={8}>
<div className="mb-2 flex flex-col gap-2">
<div className="text-xs text-text">Model Info</div>
<div className="font-mono text-xs text-text-secondary">
{metadata.modelUsed ?? "Unknown"}
</div>
</div>
<div className="space-y-2 text-xs">
<div className="font-medium text-text">AI Credits Usage</div>
{isFreeUser ? (
<div className="flex items-center justify-between gap-2 rounded-md border border-border px-3 py-2">
<span className="text-text-secondary">Credits:</span>
<span className="font-mono text-text">
{summarizedTokens != null ? formatTokenCountString(summarizedTokens) : "—"}
</span>
</div>
) : (
<>
<div className="grid grid-cols-2 gap-x-4 gap-y-1">
{metadata.totalTokens != null && (
<div className="flex justify-between gap-2">
<span className="text-text-secondary">Total:</span>
<span className="font-mono text-text">
{formatTokenCountString(metadata.totalTokens)}
</span>
</div>
)}
{metadata.billedTokens != null && (
<div className="flex justify-between gap-2">
<span className="text-text-secondary">Billed:</span>
<span className="font-mono">
{formatTokenCountString(metadata.billedTokens)}
</span>
</div>
)}
</div>
{(hasDuration || hasBillingMultiplier) && (
<>
<hr className="border-fill-secondary" />
<div className="grid grid-cols-2 gap-x-4 gap-y-1">
{hasDuration && (
<div className="flex justify-between gap-2">
<span className="text-text-secondary">Duration:</span>
<span className="font-mono text-text">
{formatDuration(metadata.duration!)}
</span>
</div>
)}
{hasBillingMultiplier && (
<div className="flex justify-between gap-2">
<span className="text-text-secondary">Multiplier:</span>
<span className="font-mono text-text">
{metadata.billingMultiplier!}×
</span>
</div>
)}
</div>
</>
)}
</>
)}
</div>
{isFreeUser ? (
<FreeUserTokenUsage metadata={metadata} />
) : (
<NormalUserTokenUsage metadata={metadata} />
)}
</TooltipContent>
</TooltipPortal>
</Tooltip>

View File

@ -337,6 +337,17 @@
"token_usage.title": "AI Credits Usage",
"token_usage.tokens_remaining": "credits remaining",
"token_usage.tokens_used": "{{used}} / {{total}} credits used",
"token_usage_pill.billed": "Billed",
"token_usage_pill.byok": "BYOK",
"token_usage_pill.credits": "Credits",
"token_usage_pill.credits_usage": "AI Credits Usage",
"token_usage_pill.duration": "Duration",
"token_usage_pill.model_info": "Model Info",
"token_usage_pill.multiplier": "Multiplier",
"token_usage_pill.provider_info": "Provider Info",
"token_usage_pill.system": "System",
"token_usage_pill.total": "Total",
"token_usage_pill.unknown": "Unknown",
"usage_analysis.active_session": "Active Session",
"usage_analysis.current_usage": "Current Usage",
"usage_analysis.detailed_description": "Comprehensive overview of your AI usage patterns and insights",

View File

@ -283,6 +283,17 @@
"timeline_summary.generating": "タイムラインを要約しています...",
"timeline_summary.heading": "タイムラインに新しい内容はありますか",
"timeline_summary.options.include": "タイムライン要約でチャット",
"token_usage_pill.billed": "請求済み",
"token_usage_pill.byok": "BYOK",
"token_usage_pill.credits": "クレジット",
"token_usage_pill.credits_usage": "AI クレジット使用",
"token_usage_pill.duration": "持続時間",
"token_usage_pill.model_info": "モデル情報",
"token_usage_pill.multiplier": "倍数",
"token_usage_pill.provider_info": "プロバイダー情報",
"token_usage_pill.system": "システム",
"token_usage_pill.total": "合計",
"token_usage_pill.unknown": "不明",
"usage_analysis.active_session": "アクティブセッション",
"usage_analysis.current_usage": "現在の使用状況",
"usage_analysis.detailed_description": "AI使用パターンとインサイトの包括的概要",

View File

@ -330,6 +330,17 @@
"token_usage.title": "令牌使用情况",
"token_usage.tokens_remaining": "剩余令牌",
"token_usage.tokens_used": "已使用{{used}} / {{total}}令牌",
"token_usage_pill.billed": "计费",
"token_usage_pill.byok": "BYOK",
"token_usage_pill.credits": "额度",
"token_usage_pill.credits_usage": "AI 额度使用",
"token_usage_pill.duration": "持续时间",
"token_usage_pill.model_info": "模型信息",
"token_usage_pill.multiplier": "倍数",
"token_usage_pill.provider_info": "提供商信息",
"token_usage_pill.system": "系统",
"token_usage_pill.total": "总计",
"token_usage_pill.unknown": "未知",
"usage_analysis.active_session": "活跃会话",
"usage_analysis.current_usage": "当前使用情况",
"usage_analysis.detailed_description": "全面了解您的 AI 使用模式和洞察",

View File

@ -302,6 +302,17 @@
"token_usage.title": "令牌使用狀況",
"token_usage.tokens_remaining": "剩餘令牌",
"token_usage.tokens_used": "已使用 {{used}} / {{total}} 令牌",
"token_usage_pill.billed": "計費",
"token_usage_pill.byok": "BYOK",
"token_usage_pill.credits": "額度",
"token_usage_pill.credits_usage": "AI 額度使用",
"token_usage_pill.duration": "持續時間",
"token_usage_pill.model_info": "模型資訊",
"token_usage_pill.multiplier": "倍數",
"token_usage_pill.provider_info": "提供商資訊",
"token_usage_pill.system": "系統",
"token_usage_pill.total": "總計",
"token_usage_pill.unknown": "未知",
"usage_analysis.active_session": "活躍工作階段",
"usage_analysis.current_usage": "目前使用狀況",
"usage_analysis.detailed_description": "全面瞭解您的 AI 使用模式和洞察",

View File

@ -10,8 +10,8 @@ catalogs:
specifier: 0.3.92
version: 0.3.92
'@folo-services/ai-tools':
specifier: 0.2.63
version: 0.2.63
specifier: 0.2.65
version: 0.2.65
tailwindcss-uikit-colors:
specifier: 1.0.0
version: 1.0.0
@ -782,7 +782,7 @@ importers:
version: link:../../../../packages/internal/utils
'@folo-services/ai-tools':
specifier: 'catalog:'
version: 0.2.63(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
version: 0.2.65(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)
'@types/node':
specifier: 24.10.0
version: 24.10.0
@ -4516,8 +4516,8 @@ packages:
'@follow-app/client-sdk@0.3.92':
resolution: {integrity: sha512-lJNMXyt40vkGFSsLt83zCE/zDjh2numbgR4FgR5Qh8VCp5cExmy+LgYOgmi+q3N8jpWyHw/ipE3cX1k3SPP/mQ==}
'@folo-services/ai-tools@0.2.63':
resolution: {integrity: sha512-Iyyx97fL6nDUQtd9fl2MRaN1+95yPT3iVI9PbOMGJxH87WXRpfeAg0dwmGHGdGfyNyM78kh32AymKrdpV8looQ==}
'@folo-services/ai-tools@0.2.65':
resolution: {integrity: sha512-Z6sScc3Hl66Yr8vHRy/yzOoFPhqqhQi0M9xjlmXd+d+0U1PCCKLwNSF+5ORjFDt2PICyA8thE8HBwI/Rl9pWUg==}
'@folo-services/constants@0.1.53':
resolution: {integrity: sha512-zD6CCC8+Sjos7tdutH+cefv5K+s+7jhYSM/asKUBGDq0FgmpgHnl9apB5qldlH/6hHtFwf+9HxjBtcHcewsNzg==}
@ -21234,7 +21234,7 @@ snapshots:
- svelte
- vue
'@folo-services/ai-tools@0.2.63(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
'@folo-services/ai-tools@0.2.65(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)':
dependencies:
'@ai-sdk/openai': 2.0.63(zod@4.1.12)
'@folo-services/drizzle': 0.1.44(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)
@ -23796,7 +23796,7 @@ snapshots:
debug: 2.6.9
invariant: 2.2.4
metro: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5)
metro-config: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5)
metro-config: 0.82.4(bufferutil@4.0.9)
metro-core: 0.82.4
semver: 7.7.3
transitivePeerDependencies:
@ -31631,22 +31631,6 @@ snapshots:
- supports-color
- utf-8-validate
metro-config@0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5):
dependencies:
connect: 3.7.0
cosmiconfig: 5.2.1
flow-enums-runtime: 0.0.6
jest-validate: 29.7.0
metro: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5)
metro-cache: 0.82.4
metro-core: 0.82.4
metro-runtime: 0.82.4
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
optional: true
metro-core@0.82.4:
dependencies:
flow-enums-runtime: 0.0.6
@ -31832,7 +31816,7 @@ snapshots:
metro-babel-transformer: 0.82.4
metro-cache: 0.82.4
metro-cache-key: 0.82.4
metro-config: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5)
metro-config: 0.82.4(bufferutil@4.0.9)
metro-core: 0.82.4
metro-file-map: 0.82.4
metro-resolver: 0.82.4

View File

@ -9,7 +9,7 @@ packages:
catalog:
"@follow-app/client-sdk": 0.3.92
"@folo-services/ai-tools": 0.2.63
"@folo-services/ai-tools": 0.2.65
tailwindcss-uikit-colors: 1.0.0
typescript: 5.9.3