mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(web): show Codex reasoning effort in SessionHeader (#1016)
Surface the same reasoning label already shown in the composer StatusBar in the top SessionHeader for codex/opencode sessions. Also show an explicit Fast badge only when serviceTier is fast (#1004-aligned). Closes #1015 (header display portion). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import type { AgentState, CodexCollaborationMode, PermissionMode } from '@/types
|
||||
import type { ConversationStatus } from '@/realtime/types'
|
||||
import type { ThreadGoal } from '@/types/api'
|
||||
import { getContextBudgetTokens } from '@/chat/modelConfig'
|
||||
import { formatCodexReasoningLabel, shouldShowCodexReasoningLabel } from '@/lib/codexStatusLabels'
|
||||
import { isFastServiceTier } from './codexFastMode'
|
||||
import { useTranslation } from '@/lib/use-translation'
|
||||
|
||||
@@ -124,12 +125,6 @@ function formatTokenCount(value: number): string {
|
||||
return String(value)
|
||||
}
|
||||
|
||||
function formatCodexReasoningLabel(effort?: string | null): string {
|
||||
const normalized = effort?.trim().toLowerCase()
|
||||
if (!normalized || normalized === 'default') return 'reasoning default'
|
||||
return `reasoning ${normalized}`
|
||||
}
|
||||
|
||||
function isCodexFastMode(model?: string | null, effort?: string | null): boolean {
|
||||
const normalizedEffort = effort?.trim().toLowerCase()
|
||||
if (normalizedEffort === 'none' || normalizedEffort === 'minimal' || normalizedEffort === 'low') {
|
||||
@@ -212,7 +207,7 @@ export function StatusBar(props: {
|
||||
const collaborationModeLabel = displayCollaborationMode
|
||||
? getCodexCollaborationModeLabel(displayCollaborationMode)
|
||||
: null
|
||||
const codexReasoningLabel = (props.agentFlavor === 'codex' || props.agentFlavor === 'opencode')
|
||||
const codexReasoningLabel = shouldShowCodexReasoningLabel(props.agentFlavor)
|
||||
? formatCodexReasoningLabel(props.modelReasoningEffort)
|
||||
: null
|
||||
// Prefer the explicit service tier (the real Fast-mode toggle) when set;
|
||||
|
||||
@@ -8,9 +8,11 @@ import { SessionExportDialog } from '@/components/SessionExportDialog'
|
||||
import { RenameSessionDialog } from '@/components/RenameSessionDialog'
|
||||
import { ConfirmDialog } from '@/components/ui/ConfirmDialog'
|
||||
import { formatReopenError } from '@/lib/reopenError'
|
||||
import { formatCodexReasoningLabel, shouldShowCodexReasoningLabel } from '@/lib/codexStatusLabels'
|
||||
import { getSessionModelLabel } from '@/lib/sessionModelLabel'
|
||||
import { useTranslation } from '@/lib/use-translation'
|
||||
import { AgentFlavorIcon } from '@/components/AgentFlavorIcon'
|
||||
import { isFastServiceTier } from '@/components/AssistantChat/codexFastMode'
|
||||
|
||||
function getSessionTitle(session: Session): string {
|
||||
if (session.metadata?.name) {
|
||||
@@ -111,6 +113,12 @@ export function SessionHeader(props: {
|
||||
const title = useMemo(() => getSessionTitle(session), [session])
|
||||
const worktreeBranch = session.metadata?.worktree?.branch
|
||||
const modelLabel = getSessionModelLabel(session)
|
||||
const agentFlavor = session.metadata?.flavor ?? null
|
||||
const reasoningLabel = shouldShowCodexReasoningLabel(agentFlavor)
|
||||
? formatCodexReasoningLabel(session.modelReasoningEffort)
|
||||
: null
|
||||
// Match expected Fast badge semantics (#1004): only explicit service tier, no effort/model heuristics.
|
||||
const showFastBadge = agentFlavor === 'codex' && isFastServiceTier(session.serviceTier)
|
||||
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
const [menuAnchorPoint, setMenuAnchorPoint] = useState<{ x: number; y: number }>({ x: 0, y: 0 })
|
||||
@@ -198,6 +206,16 @@ export function SessionHeader(props: {
|
||||
{t(modelLabel.key)}: {modelLabel.value}
|
||||
</span>
|
||||
) : null}
|
||||
{reasoningLabel ? (
|
||||
<span data-testid="session-header-reasoning">
|
||||
{reasoningLabel}
|
||||
</span>
|
||||
) : null}
|
||||
{showFastBadge ? (
|
||||
<span data-testid="session-header-fast" className="text-[#34C759]">
|
||||
fast
|
||||
</span>
|
||||
) : null}
|
||||
{worktreeBranch ? (
|
||||
<span>{t('session.item.worktree')}: {worktreeBranch}</span>
|
||||
) : null}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { formatCodexReasoningLabel, shouldShowCodexReasoningLabel } from './codexStatusLabels'
|
||||
|
||||
describe('codexStatusLabels', () => {
|
||||
it('formats unset and default effort as reasoning default', () => {
|
||||
expect(formatCodexReasoningLabel(null)).toBe('reasoning default')
|
||||
expect(formatCodexReasoningLabel(undefined)).toBe('reasoning default')
|
||||
expect(formatCodexReasoningLabel('default')).toBe('reasoning default')
|
||||
expect(formatCodexReasoningLabel(' DEFAULT ')).toBe('reasoning default')
|
||||
})
|
||||
|
||||
it('formats selected efforts', () => {
|
||||
expect(formatCodexReasoningLabel('xhigh')).toBe('reasoning xhigh')
|
||||
expect(formatCodexReasoningLabel('Ultra')).toBe('reasoning ultra')
|
||||
})
|
||||
|
||||
it('only shows the label for codex and opencode', () => {
|
||||
expect(shouldShowCodexReasoningLabel('codex')).toBe(true)
|
||||
expect(shouldShowCodexReasoningLabel('opencode')).toBe(true)
|
||||
expect(shouldShowCodexReasoningLabel('claude')).toBe(false)
|
||||
expect(shouldShowCodexReasoningLabel(null)).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
/** Labels shared by SessionHeader and composer StatusBar for Codex/OpenCode. */
|
||||
|
||||
export function formatCodexReasoningLabel(effort?: string | null): string {
|
||||
const normalized = effort?.trim().toLowerCase()
|
||||
if (!normalized || normalized === 'default') return 'reasoning default'
|
||||
return `reasoning ${normalized}`
|
||||
}
|
||||
|
||||
export function shouldShowCodexReasoningLabel(agentFlavor: string | null | undefined): boolean {
|
||||
return agentFlavor === 'codex' || agentFlavor === 'opencode'
|
||||
}
|
||||
Reference in New Issue
Block a user