Add context window percentage and subscription model detection to session info
This commit is contained in:
@@ -5,28 +5,74 @@ import ToolCall from "./tool-call"
|
|||||||
import { sseManager } from "../lib/sse-manager"
|
import { sseManager } from "../lib/sse-manager"
|
||||||
import Kbd from "./kbd"
|
import Kbd from "./kbd"
|
||||||
import { preferences } from "../stores/preferences"
|
import { preferences } from "../stores/preferences"
|
||||||
|
import { providers } from "../stores/sessions"
|
||||||
|
|
||||||
// Calculate session tokens and cost from messagesInfo
|
// Calculate session tokens and cost from messagesInfo (matches TUI logic)
|
||||||
function calculateSessionInfo(messagesInfo?: Map<string, any>) {
|
function calculateSessionInfo(messagesInfo?: Map<string, any>, instanceId?: string) {
|
||||||
if (!messagesInfo) return { tokens: 0, cost: 0 }
|
if (!messagesInfo || messagesInfo.size === 0)
|
||||||
|
return { tokens: 0, cost: 0, contextWindow: 0, isSubscriptionModel: false }
|
||||||
|
|
||||||
let totalTokens = 0
|
let tokens = 0
|
||||||
let totalCost = 0
|
let cost = 0
|
||||||
|
let contextWindow = 0
|
||||||
|
let isSubscriptionModel = false
|
||||||
|
let modelID = ""
|
||||||
|
let providerID = ""
|
||||||
|
|
||||||
for (const [, info] of messagesInfo) {
|
// Go backwards through messages to find the last relevant assistant message (like TUI)
|
||||||
|
const messageArray = Array.from(messagesInfo.values()).reverse()
|
||||||
|
|
||||||
|
for (const info of messageArray) {
|
||||||
if (info.role === "assistant" && info.tokens) {
|
if (info.role === "assistant" && info.tokens) {
|
||||||
const tokens = info.tokens
|
const usage = info.tokens
|
||||||
totalTokens +=
|
|
||||||
(tokens.input || 0) +
|
if (usage.output > 0) {
|
||||||
(tokens.cache?.read || 0) +
|
if (info.summary) {
|
||||||
(tokens.cache?.write || 0) +
|
// If summary message, only count output tokens and stop (like TUI)
|
||||||
(tokens.output || 0) +
|
tokens = usage.output || 0
|
||||||
(tokens.reasoning || 0)
|
cost = info.cost || 0
|
||||||
totalCost += info.cost || 0
|
} else {
|
||||||
|
// Regular message - count all token types (like TUI)
|
||||||
|
tokens =
|
||||||
|
(usage.input || 0) +
|
||||||
|
(usage.cache?.read || 0) +
|
||||||
|
(usage.cache?.write || 0) +
|
||||||
|
(usage.output || 0) +
|
||||||
|
(usage.reasoning || 0)
|
||||||
|
cost = info.cost || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get model info for context window and subscription check
|
||||||
|
modelID = info.modelID || ""
|
||||||
|
providerID = info.providerID || ""
|
||||||
|
isSubscriptionModel = cost === 0
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { tokens: totalTokens, cost: totalCost }
|
// Try to get context window from providers
|
||||||
|
if (instanceId && modelID && providerID) {
|
||||||
|
const instanceProviders = providers().get(instanceId) || []
|
||||||
|
console.log("[calculateSessionInfo] instanceProviders:", instanceProviders)
|
||||||
|
console.log("[calculateSessionInfo] looking for providerID:", providerID, "modelID:", modelID)
|
||||||
|
const provider = instanceProviders.find((p) => p.id === providerID)
|
||||||
|
console.log("[calculateSessionInfo] found provider:", provider)
|
||||||
|
if (provider) {
|
||||||
|
const model = provider.models.find((m) => m.id === modelID)
|
||||||
|
console.log("[calculateSessionInfo] found model:", model)
|
||||||
|
if (model?.limit?.context) {
|
||||||
|
contextWindow = model.limit.context
|
||||||
|
}
|
||||||
|
// Check if it's a subscription model (cost is 0 for both input and output)
|
||||||
|
if (model?.cost?.input === 0 && model?.cost?.output === 0) {
|
||||||
|
isSubscriptionModel = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { tokens, cost, contextWindow, isSubscriptionModel }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format tokens like TUI (e.g., "110K", "1.2M")
|
// Format tokens like TUI (e.g., "110K", "1.2M")
|
||||||
@@ -39,11 +85,24 @@ function formatTokens(tokens: number): string {
|
|||||||
return tokens.toString()
|
return tokens.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format session info like TUI (e.g., "110K • $0.42")
|
// Format session info like TUI (e.g., "110K/73% ($0.42)" or "110K/73%")
|
||||||
function formatSessionInfo(tokens: number, cost: number): string {
|
function formatSessionInfo(tokens: number, cost: number, contextWindow: number, isSubscriptionModel: boolean): string {
|
||||||
const tokensStr = formatTokens(tokens)
|
const tokensStr = formatTokens(tokens)
|
||||||
const costStr = cost > 0 ? ` • $${cost.toFixed(2)}` : ""
|
|
||||||
return `${tokensStr}${costStr}`
|
// Calculate percentage if we have context window
|
||||||
|
if (contextWindow > 0) {
|
||||||
|
const percentage = Math.round((tokens / contextWindow) * 100)
|
||||||
|
if (isSubscriptionModel) {
|
||||||
|
return `${tokensStr}/${percentage}%`
|
||||||
|
}
|
||||||
|
return `${tokensStr}/${percentage}% ($${cost.toFixed(2)})`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback without context window
|
||||||
|
if (isSubscriptionModel) {
|
||||||
|
return tokensStr
|
||||||
|
}
|
||||||
|
return `${tokensStr} ($${cost.toFixed(2)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MessageStreamProps {
|
interface MessageStreamProps {
|
||||||
@@ -155,8 +214,16 @@ export default function MessageStream(props: MessageStreamProps) {
|
|||||||
<div class="flex items-center gap-2 text-sm font-medium text-gray-700">
|
<div class="flex items-center gap-2 text-sm font-medium text-gray-700">
|
||||||
<span>
|
<span>
|
||||||
{(() => {
|
{(() => {
|
||||||
const sessionInfo = calculateSessionInfo(props.messagesInfo)
|
const sessionInfo = calculateSessionInfo(props.messagesInfo, props.instanceId)
|
||||||
return formatSessionInfo(sessionInfo.tokens, sessionInfo.cost)
|
console.log("[MessageStream] sessionInfo:", sessionInfo)
|
||||||
|
const result = formatSessionInfo(
|
||||||
|
sessionInfo.tokens,
|
||||||
|
sessionInfo.cost,
|
||||||
|
sessionInfo.contextWindow,
|
||||||
|
sessionInfo.isSubscriptionModel,
|
||||||
|
)
|
||||||
|
console.log("[MessageStream] formatted result:", result)
|
||||||
|
return result
|
||||||
})()}
|
})()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -290,6 +290,8 @@ async function fetchProviders(instanceId: string): Promise<void> {
|
|||||||
id,
|
id,
|
||||||
name: model.name,
|
name: model.name,
|
||||||
providerId: provider.id,
|
providerId: provider.id,
|
||||||
|
limit: model.limit,
|
||||||
|
cost: model.cost,
|
||||||
})),
|
})),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
@@ -45,4 +45,11 @@ export interface Model {
|
|||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
providerId: string
|
providerId: string
|
||||||
|
limit?: {
|
||||||
|
context?: number
|
||||||
|
}
|
||||||
|
cost?: {
|
||||||
|
input?: number
|
||||||
|
output?: number
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user