Add support for claude 1M context. close #291

This commit is contained in:
weishu
2026-03-16 08:51:40 +08:00
parent fedc8e79eb
commit ce5edc42e1
12 changed files with 103 additions and 11 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ See `src/router.tsx` for route definitions.
- Message thread with infinite scroll.
- Composer for sending messages.
- Permission mode toggle (default/acceptEdits/bypassPermissions/plan).
- Model selection (default/sonnet/opus).
- Model selection (default/sonnet/sonnet[1m]/opus/opus[1m]).
- Session abort and mode switch controls.
- Context size display.
+16
View File
@@ -0,0 +1,16 @@
import { describe, expect, it } from 'vitest'
import { getContextBudgetTokens } from './modelConfig'
describe('getContextBudgetTokens', () => {
it('uses the existing 200k budget for default Claude modes', () => {
expect(getContextBudgetTokens(undefined)).toBe(190_000)
expect(getContextBudgetTokens('default')).toBe(190_000)
expect(getContextBudgetTokens('sonnet')).toBe(190_000)
expect(getContextBudgetTokens('opus')).toBe(190_000)
})
it('uses the 1m budget for Claude 1m modes', () => {
expect(getContextBudgetTokens('sonnet[1m]')).toBe(990_000)
expect(getContextBudgetTokens('opus[1m]')).toBe(990_000)
})
})
+4 -2
View File
@@ -13,10 +13,12 @@ import type { ModelMode } from '@/types/api'
const CONTEXT_HEADROOM_TOKENS = 10_000
const MODEL_CONTEXT_WINDOWS: Record<ModelMode, number> = {
// Claude Code modes used in this app; currently treated as ~200k context.
// Claude Code modes used in this app. 1M variants get the larger budget.
default: 200_000,
sonnet: 200_000,
opus: 200_000
'sonnet[1m]': 1_000_000,
opus: 200_000,
'opus[1m]': 1_000_000
}
export function getContextBudgetTokens(modelMode: ModelMode | undefined): number | null {
@@ -0,0 +1,21 @@
import { getModelModeLabel, MODEL_MODES } from '@hapi/protocol'
import { describe, expect, it } from 'vitest'
import { MODEL_OPTIONS } from './types'
describe('Claude model options', () => {
it('includes 1m model options in the expected order', () => {
expect(MODEL_OPTIONS.claude).toEqual([
{ value: 'auto', label: 'Auto' },
{ value: 'opus', label: 'Opus' },
{ value: 'opus[1m]', label: 'Opus 1M' },
{ value: 'sonnet', label: 'Sonnet' },
{ value: 'sonnet[1m]', label: 'Sonnet 1M' },
])
})
it('exposes friendly labels for session model modes', () => {
expect(MODEL_MODES).toEqual(['default', 'sonnet', 'sonnet[1m]', 'opus', 'opus[1m]'])
expect(getModelModeLabel('sonnet[1m]')).toBe('Sonnet 1M')
expect(getModelModeLabel('opus[1m]')).toBe('Opus 1M')
})
})
+2
View File
@@ -5,7 +5,9 @@ export const MODEL_OPTIONS: Record<AgentType, { value: string; label: string }[]
claude: [
{ value: 'auto', label: 'Auto' },
{ value: 'opus', label: 'Opus' },
{ value: 'opus[1m]', label: 'Opus 1M' },
{ value: 'sonnet', label: 'Sonnet' },
{ value: 'sonnet[1m]', label: 'Sonnet 1M' },
],
codex: [
{ value: 'auto', label: 'Auto' },
+3 -1
View File
@@ -1,3 +1,4 @@
import { getModelModeLabel } from '@hapi/protocol'
import { useId, useMemo, useRef, useState } from 'react'
import type { Session } from '@/types/api'
import type { ApiClient } from '@/api/client'
@@ -70,6 +71,7 @@ export function SessionHeader(props: {
const { session, api, onSessionDeleted } = props
const title = useMemo(() => getSessionTitle(session), [session])
const worktreeBranch = session.metadata?.worktree?.branch
const modelModeLabel = getModelModeLabel(session.modelMode ?? 'default')
const [menuOpen, setMenuOpen] = useState(false)
const [menuAnchorPoint, setMenuAnchorPoint] = useState<{ x: number; y: number }>({ x: 0, y: 0 })
@@ -139,7 +141,7 @@ export function SessionHeader(props: {
{session.metadata?.flavor?.trim() || 'unknown'}
</span>
<span>
{t('session.item.modelMode')}: {session.modelMode || 'default'}
{t('session.item.modelMode')}: {modelModeLabel}
</span>
{worktreeBranch ? (
<span>{t('session.item.worktree')}: {worktreeBranch}</span>
+3 -1
View File
@@ -1,3 +1,4 @@
import { getModelModeLabel } from '@hapi/protocol'
import { useEffect, useMemo, useState } from 'react'
import type { SessionSummary } from '@/types/api'
import type { ApiClient } from '@/api/client'
@@ -198,6 +199,7 @@ function SessionItem(props: {
})
const sessionName = getSessionTitle(s)
const modelModeLabel = getModelModeLabel(s.modelMode ?? 'default')
const statusDotClass = s.active
? (s.thinking ? 'bg-[#007AFF]' : 'bg-[var(--app-badge-success-text)]')
: 'bg-[var(--app-hint)]'
@@ -259,7 +261,7 @@ function SessionItem(props: {
</span>
{getAgentLabel(s)}
</span>
<span>{t('session.item.modelMode')}: {s.modelMode || 'default'}</span>
<span>{t('session.item.modelMode')}: {modelModeLabel}</span>
{s.metadata?.worktree?.branch ? (
<span>{t('session.item.worktree')}: {s.metadata.worktree.branch}</span>
) : null}