mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
feat: add model-aware context budget calculation for status bar warnings
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
import type { ModelMode } from '@/types/api'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context windows vary by model/provider and may change over time.
|
||||||
|
*
|
||||||
|
* The UI only needs this to compute a conservative "context remaining" warning.
|
||||||
|
* We intentionally keep a headroom budget to avoid false confidence near the limit
|
||||||
|
* (system prompts, tool overhead, and other hidden tokens can consume extra space).
|
||||||
|
*
|
||||||
|
* If/when the server provides an explicit per-session context limit, prefer that
|
||||||
|
* and use this only as a fallback.
|
||||||
|
*/
|
||||||
|
const CONTEXT_HEADROOM_TOKENS = 10_000
|
||||||
|
|
||||||
|
const MODEL_CONTEXT_WINDOWS: Record<NonNullable<ModelMode>, number> = {
|
||||||
|
// Claude Code modes used in this app; currently treated as ~200k context.
|
||||||
|
default: 200_000,
|
||||||
|
sonnet: 200_000,
|
||||||
|
opus: 200_000
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getContextBudgetTokens(modelMode: ModelMode): number | null {
|
||||||
|
const mode: NonNullable<ModelMode> = modelMode ?? 'default'
|
||||||
|
const windowTokens = MODEL_CONTEXT_WINDOWS[mode]
|
||||||
|
if (!windowTokens) return null
|
||||||
|
return Math.max(1, windowTokens - CONTEXT_HEADROOM_TOKENS)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -401,6 +401,7 @@ export function HappyComposer(props: {
|
|||||||
thinking={thinking}
|
thinking={thinking}
|
||||||
agentState={agentState}
|
agentState={agentState}
|
||||||
contextSize={contextSize}
|
contextSize={contextSize}
|
||||||
|
modelMode={modelMode}
|
||||||
permissionMode={permissionMode}
|
permissionMode={permissionMode}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import type { AgentState, PermissionMode } from '@/types/api'
|
import type { AgentState, ModelMode, PermissionMode } from '@/types/api'
|
||||||
|
import { getContextBudgetTokens } from '@/chat/modelConfig'
|
||||||
|
|
||||||
const PERMISSION_MODE_LABELS: Record<string, string> = {
|
const PERMISSION_MODE_LABELS: Record<string, string> = {
|
||||||
default: 'Default',
|
default: 'Default',
|
||||||
@@ -8,9 +9,6 @@ const PERMISSION_MODE_LABELS: Record<string, string> = {
|
|||||||
bypassPermissions: 'Bypass All'
|
bypassPermissions: 'Bypass All'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Max context size for percentage calculation
|
|
||||||
const MAX_CONTEXT_SIZE = 190000
|
|
||||||
|
|
||||||
// Vibing messages for thinking state
|
// Vibing messages for thinking state
|
||||||
const VIBING_MESSAGES = [
|
const VIBING_MESSAGES = [
|
||||||
"Accomplishing", "Actioning", "Actualizing", "Baking", "Booping", "Brewing",
|
"Accomplishing", "Actioning", "Actualizing", "Baking", "Booping", "Brewing",
|
||||||
@@ -73,9 +71,9 @@ function getConnectionStatus(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContextWarning(contextSize: number): { text: string; color: string } | null {
|
function getContextWarning(contextSize: number, maxContextSize: number): { text: string; color: string } | null {
|
||||||
const percentageUsed = (contextSize / MAX_CONTEXT_SIZE) * 100
|
const percentageUsed = (contextSize / maxContextSize) * 100
|
||||||
const percentageRemaining = 100 - percentageUsed
|
const percentageRemaining = Math.max(0, 100 - percentageUsed)
|
||||||
|
|
||||||
if (percentageRemaining <= 5) {
|
if (percentageRemaining <= 5) {
|
||||||
return { text: `${Math.round(percentageRemaining)}% left`, color: 'text-red-500' }
|
return { text: `${Math.round(percentageRemaining)}% left`, color: 'text-red-500' }
|
||||||
@@ -91,6 +89,7 @@ export function StatusBar(props: {
|
|||||||
thinking: boolean
|
thinking: boolean
|
||||||
agentState: AgentState | null | undefined
|
agentState: AgentState | null | undefined
|
||||||
contextSize?: number
|
contextSize?: number
|
||||||
|
modelMode?: ModelMode
|
||||||
permissionMode?: PermissionMode
|
permissionMode?: PermissionMode
|
||||||
}) {
|
}) {
|
||||||
const connectionStatus = useMemo(
|
const connectionStatus = useMemo(
|
||||||
@@ -99,8 +98,13 @@ export function StatusBar(props: {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const contextWarning = useMemo(
|
const contextWarning = useMemo(
|
||||||
() => props.contextSize !== undefined ? getContextWarning(props.contextSize) : null,
|
() => {
|
||||||
[props.contextSize]
|
if (props.contextSize === undefined) return null
|
||||||
|
const maxContextSize = getContextBudgetTokens(props.modelMode)
|
||||||
|
if (!maxContextSize) return null
|
||||||
|
return getContextWarning(props.contextSize, maxContextSize)
|
||||||
|
},
|
||||||
|
[props.contextSize, props.modelMode]
|
||||||
)
|
)
|
||||||
|
|
||||||
const permissionMode = props.permissionMode
|
const permissionMode = props.permissionMode
|
||||||
@@ -136,4 +140,3 @@ export function StatusBar(props: {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user