fix(desktop): refresh session model metadata on switch (#43977)
Co-authored-by: Omar Baradei <omar@kostudios.io>
This commit is contained in:
co-authored by
Omar Baradei
parent
d0e017bac8
commit
e372803554
@@ -64,6 +64,67 @@ interface QueuedStreamDeltas {
|
|||||||
reasoning: string
|
reasoning: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SessionRuntimeStatePatch = Partial<
|
||||||
|
Pick<
|
||||||
|
ClientSessionState,
|
||||||
|
| 'branch'
|
||||||
|
| 'cwd'
|
||||||
|
| 'fast'
|
||||||
|
| 'model'
|
||||||
|
| 'personality'
|
||||||
|
| 'provider'
|
||||||
|
| 'reasoningEffort'
|
||||||
|
| 'serviceTier'
|
||||||
|
| 'yolo'
|
||||||
|
>
|
||||||
|
>
|
||||||
|
|
||||||
|
function sessionInfoStatePatch(payload: GatewayEventPayload | undefined): SessionRuntimeStatePatch {
|
||||||
|
const patch: SessionRuntimeStatePatch = {}
|
||||||
|
|
||||||
|
if (typeof payload?.model === 'string') {
|
||||||
|
patch.model = payload.model || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof payload?.provider === 'string') {
|
||||||
|
patch.provider = payload.provider || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof payload?.cwd === 'string') {
|
||||||
|
patch.cwd = payload.cwd
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof payload?.branch === 'string') {
|
||||||
|
patch.branch = payload.branch
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof payload?.personality === 'string') {
|
||||||
|
patch.personality = normalizePersonalityValue(payload.personality)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof payload?.reasoning_effort === 'string') {
|
||||||
|
patch.reasoningEffort = payload.reasoning_effort
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof payload?.service_tier === 'string') {
|
||||||
|
patch.serviceTier = payload.service_tier
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof payload?.fast === 'boolean') {
|
||||||
|
patch.fast = payload.fast
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof payload?.yolo === 'boolean') {
|
||||||
|
patch.yolo = payload.yolo
|
||||||
|
}
|
||||||
|
|
||||||
|
return patch
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasSessionInfoStatePatch(patch: SessionRuntimeStatePatch): boolean {
|
||||||
|
return Object.keys(patch).length > 0
|
||||||
|
}
|
||||||
|
|
||||||
// Minimum gap between two assistant-text flushes during a stream. Was 16ms
|
// Minimum gap between two assistant-text flushes during a stream. Was 16ms
|
||||||
// (rAF only), which at typical LLM token rates of ~30-80 tok/sec meant every
|
// (rAF only), which at typical LLM token rates of ~30-80 tok/sec meant every
|
||||||
// token got its own React commit + Streamdown markdown re-parse, scaling
|
// token got its own React commit + Streamdown markdown re-parse, scaling
|
||||||
@@ -628,36 +689,27 @@ export function useMessageStream({
|
|||||||
// Apply session-scoped fields when the event targets the active
|
// Apply session-scoped fields when the event targets the active
|
||||||
// session, OR when it's a global broadcast and we have no session.
|
// session, OR when it's a global broadcast and we have no session.
|
||||||
const apply = explicitSid ? isActiveEvent : !activeSessionIdRef.current
|
const apply = explicitSid ? isActiveEvent : !activeSessionIdRef.current
|
||||||
|
const statePatch = sessionInfoStatePatch(payload)
|
||||||
|
const hasStatePatch = hasSessionInfoStatePatch(statePatch)
|
||||||
const modelChanged = typeof payload?.model === 'string'
|
const modelChanged = typeof payload?.model === 'string'
|
||||||
const providerChanged = typeof payload?.provider === 'string'
|
const providerChanged = typeof payload?.provider === 'string'
|
||||||
const runningChanged = typeof payload?.running === 'boolean'
|
const runningChanged = typeof payload?.running === 'boolean'
|
||||||
|
|
||||||
if (apply) {
|
if (apply) {
|
||||||
const runtimeInfo: Partial<
|
|
||||||
Pick<
|
|
||||||
ClientSessionState,
|
|
||||||
'branch' | 'cwd' | 'fast' | 'model' | 'provider' | 'reasoningEffort' | 'serviceTier' | 'yolo'
|
|
||||||
>
|
|
||||||
> = {}
|
|
||||||
|
|
||||||
if (modelChanged) {
|
if (modelChanged) {
|
||||||
setCurrentModel(payload!.model || '')
|
setCurrentModel(payload!.model || '')
|
||||||
runtimeInfo.model = payload!.model || ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (providerChanged) {
|
if (providerChanged) {
|
||||||
setCurrentProvider(payload!.provider || '')
|
setCurrentProvider(payload!.provider || '')
|
||||||
runtimeInfo.provider = payload!.provider || ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof payload?.cwd === 'string') {
|
if (typeof payload?.cwd === 'string') {
|
||||||
setCurrentCwd(payload.cwd)
|
setCurrentCwd(payload.cwd)
|
||||||
runtimeInfo.cwd = payload.cwd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof payload?.branch === 'string') {
|
if (typeof payload?.branch === 'string') {
|
||||||
setCurrentBranch(payload.branch)
|
setCurrentBranch(payload.branch)
|
||||||
runtimeInfo.branch = payload.branch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof payload?.personality === 'string') {
|
if (typeof payload?.personality === 'string') {
|
||||||
@@ -666,28 +718,31 @@ export function useMessageStream({
|
|||||||
|
|
||||||
if (typeof payload?.reasoning_effort === 'string') {
|
if (typeof payload?.reasoning_effort === 'string') {
|
||||||
setCurrentReasoningEffort(payload.reasoning_effort)
|
setCurrentReasoningEffort(payload.reasoning_effort)
|
||||||
runtimeInfo.reasoningEffort = payload.reasoning_effort
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof payload?.service_tier === 'string') {
|
if (typeof payload?.service_tier === 'string') {
|
||||||
setCurrentServiceTier(payload.service_tier)
|
setCurrentServiceTier(payload.service_tier)
|
||||||
runtimeInfo.serviceTier = payload.service_tier
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof payload?.fast === 'boolean') {
|
if (typeof payload?.fast === 'boolean') {
|
||||||
setCurrentFastMode(payload.fast)
|
setCurrentFastMode(payload.fast)
|
||||||
runtimeInfo.fast = payload.fast
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof payload?.yolo === 'boolean') {
|
if (typeof payload?.yolo === 'boolean') {
|
||||||
setYoloActive(payload.yolo)
|
setYoloActive(payload.yolo)
|
||||||
runtimeInfo.yolo = payload.yolo
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sessionId && Object.keys(runtimeInfo).length > 0) {
|
if (sessionId && hasStatePatch) {
|
||||||
updateSessionState(sessionId, state => ({ ...state, ...runtimeInfo }))
|
updateSessionState(sessionId, state => ({
|
||||||
}
|
...state,
|
||||||
|
...statePatch,
|
||||||
|
branch: statePatch.branch ?? state.branch,
|
||||||
|
cwd: statePatch.cwd ?? state.cwd
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apply) {
|
||||||
if (runningChanged && sessionId) {
|
if (runningChanged && sessionId) {
|
||||||
updateSessionState(sessionId, state => {
|
updateSessionState(sessionId, state => {
|
||||||
const busy = Boolean(payload!.running)
|
const busy = Boolean(payload!.running)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import {
|
|||||||
workspaceCwdForNewSession
|
workspaceCwdForNewSession
|
||||||
} from '@/store/session'
|
} from '@/store/session'
|
||||||
import { reportBackendContract } from '@/store/updates'
|
import { reportBackendContract } from '@/store/updates'
|
||||||
import type { SessionCreateResponse, SessionInfo, SessionResumeResponse, UsageStats } from '@/types/hermes'
|
import type { SessionCreateResponse, SessionInfo, SessionResumeResponse, SessionRuntimeInfo, UsageStats } from '@/types/hermes'
|
||||||
|
|
||||||
import { NEW_CHAT_ROUTE, sessionRoute, SETTINGS_ROUTE } from '../../routes'
|
import { NEW_CHAT_ROUTE, sessionRoute, SETTINGS_ROUTE } from '../../routes'
|
||||||
import type { ClientSessionState, SidebarNavItem } from '../../types'
|
import type { ClientSessionState, SidebarNavItem } from '../../types'
|
||||||
@@ -209,16 +209,27 @@ function patchSessionWorkspace(sessionId: string, cwd: string | undefined) {
|
|||||||
setSessions(prev => prev.map(session => (session.id === sessionId ? { ...session, cwd } : session)))
|
setSessions(prev => prev.map(session => (session.id === sessionId ? { ...session, cwd } : session)))
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyRuntimeInfo(info: SessionCreateResponse['info'] | undefined): Partial<
|
type SessionRuntimeStatePatch = Partial<
|
||||||
Pick<ClientSessionState, 'branch' | 'cwd' | 'fast' | 'model' | 'provider' | 'reasoningEffort' | 'serviceTier' | 'yolo'>
|
Pick<
|
||||||
> | null {
|
ClientSessionState,
|
||||||
|
| 'branch'
|
||||||
|
| 'cwd'
|
||||||
|
| 'fast'
|
||||||
|
| 'model'
|
||||||
|
| 'personality'
|
||||||
|
| 'provider'
|
||||||
|
| 'reasoningEffort'
|
||||||
|
| 'serviceTier'
|
||||||
|
| 'yolo'
|
||||||
|
>
|
||||||
|
>
|
||||||
|
|
||||||
|
function applyRuntimeInfo(info: SessionRuntimeInfo | undefined): SessionRuntimeStatePatch | null {
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const sessionState: Partial<
|
const sessionState: SessionRuntimeStatePatch = {}
|
||||||
Pick<ClientSessionState, 'branch' | 'cwd' | 'fast' | 'model' | 'provider' | 'reasoningEffort' | 'serviceTier' | 'yolo'>
|
|
||||||
> = {}
|
|
||||||
|
|
||||||
reportBackendContract(info.desktop_contract)
|
reportBackendContract(info.desktop_contract)
|
||||||
|
|
||||||
@@ -226,12 +237,12 @@ function applyRuntimeInfo(info: SessionCreateResponse['info'] | undefined): Part
|
|||||||
requestDesktopOnboarding(info.credential_warning)
|
requestDesktopOnboarding(info.credential_warning)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.model) {
|
if (typeof info.model === 'string') {
|
||||||
setCurrentModel(info.model)
|
setCurrentModel(info.model)
|
||||||
sessionState.model = info.model
|
sessionState.model = info.model
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.provider) {
|
if (typeof info.provider === 'string') {
|
||||||
setCurrentProvider(info.provider)
|
setCurrentProvider(info.provider)
|
||||||
sessionState.provider = info.provider
|
sessionState.provider = info.provider
|
||||||
}
|
}
|
||||||
@@ -247,7 +258,9 @@ function applyRuntimeInfo(info: SessionCreateResponse['info'] | undefined): Part
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof info.personality === 'string') {
|
if (typeof info.personality === 'string') {
|
||||||
setCurrentPersonality(normalizePersonalityValue(info.personality))
|
const personality = normalizePersonalityValue(info.personality)
|
||||||
|
setCurrentPersonality(personality)
|
||||||
|
sessionState.personality = personality
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof info.reasoning_effort === 'string') {
|
if (typeof info.reasoning_effort === 'string') {
|
||||||
@@ -277,6 +290,16 @@ function applyRuntimeInfo(info: SessionCreateResponse['info'] | undefined): Part
|
|||||||
return sessionState
|
return sessionState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyStoredSessionPreviewRuntimeInfo(stored: { model?: null | string } | undefined) {
|
||||||
|
setCurrentModel(stored?.model || '')
|
||||||
|
setCurrentProvider('')
|
||||||
|
setCurrentReasoningEffort('')
|
||||||
|
setCurrentServiceTier('')
|
||||||
|
setCurrentFastMode(false)
|
||||||
|
setYoloActive(false)
|
||||||
|
setCurrentPersonality('')
|
||||||
|
}
|
||||||
|
|
||||||
export function useSessionActions({
|
export function useSessionActions({
|
||||||
activeSessionId,
|
activeSessionId,
|
||||||
activeSessionIdRef,
|
activeSessionIdRef,
|
||||||
@@ -465,15 +488,28 @@ export function useSessionActions({
|
|||||||
const cachedState = cachedRuntimeId && sessionStateByRuntimeIdRef.current.get(cachedRuntimeId)
|
const cachedState = cachedRuntimeId && sessionStateByRuntimeIdRef.current.get(cachedRuntimeId)
|
||||||
|
|
||||||
if (cachedRuntimeId && cachedState) {
|
if (cachedRuntimeId && cachedState) {
|
||||||
|
const stored = $sessions.get().find(session => session.id === storedSessionId)
|
||||||
|
const cachedViewState =
|
||||||
|
!cachedState.model && stored?.model != null
|
||||||
|
? {
|
||||||
|
...cachedState,
|
||||||
|
model: stored.model || ''
|
||||||
|
}
|
||||||
|
: cachedState
|
||||||
|
|
||||||
|
if (cachedViewState !== cachedState) {
|
||||||
|
sessionStateByRuntimeIdRef.current.set(cachedRuntimeId, cachedViewState)
|
||||||
|
}
|
||||||
|
|
||||||
setFreshDraftReady(false)
|
setFreshDraftReady(false)
|
||||||
clearNotifications()
|
clearNotifications()
|
||||||
setSelectedStoredSessionId(storedSessionId)
|
setSelectedStoredSessionId(storedSessionId)
|
||||||
selectedStoredSessionIdRef.current = storedSessionId
|
selectedStoredSessionIdRef.current = storedSessionId
|
||||||
setActiveSessionId(cachedRuntimeId)
|
setActiveSessionId(cachedRuntimeId)
|
||||||
activeSessionIdRef.current = cachedRuntimeId
|
activeSessionIdRef.current = cachedRuntimeId
|
||||||
syncSessionStateToView(cachedRuntimeId, cachedState)
|
syncSessionStateToView(cachedRuntimeId, cachedViewState)
|
||||||
setCurrentCwd(cachedState.cwd)
|
setCurrentCwd(cachedViewState.cwd)
|
||||||
setCurrentBranch(cachedState.branch)
|
setCurrentBranch(cachedViewState.branch)
|
||||||
setSessionStartedAt(Date.now())
|
setSessionStartedAt(Date.now())
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -514,6 +550,7 @@ export function useSessionActions({
|
|||||||
selectedStoredSessionIdRef.current = storedSessionId
|
selectedStoredSessionIdRef.current = storedSessionId
|
||||||
setSessionStartedAt(Date.now())
|
setSessionStartedAt(Date.now())
|
||||||
const stored = $sessions.get().find(session => session.id === storedSessionId)
|
const stored = $sessions.get().find(session => session.id === storedSessionId)
|
||||||
|
applyStoredSessionPreviewRuntimeInfo(stored)
|
||||||
|
|
||||||
if (stored) {
|
if (stored) {
|
||||||
setCurrentUsage(current => ({
|
setCurrentUsage(current => ({
|
||||||
|
|||||||
@@ -2,7 +2,20 @@ import { act, cleanup, render } from '@testing-library/react'
|
|||||||
import type { MutableRefObject } from 'react'
|
import type { MutableRefObject } from 'react'
|
||||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
import { $turnStartedAt, setTurnStartedAt } from '@/store/session'
|
import {
|
||||||
|
$currentFastMode,
|
||||||
|
$currentModel,
|
||||||
|
$currentProvider,
|
||||||
|
$currentReasoningEffort,
|
||||||
|
$currentServiceTier,
|
||||||
|
$turnStartedAt,
|
||||||
|
setCurrentFastMode,
|
||||||
|
setCurrentModel,
|
||||||
|
setCurrentProvider,
|
||||||
|
setCurrentReasoningEffort,
|
||||||
|
setCurrentServiceTier,
|
||||||
|
setTurnStartedAt
|
||||||
|
} from '@/store/session'
|
||||||
|
|
||||||
import { useSessionStateCache } from './use-session-state-cache'
|
import { useSessionStateCache } from './use-session-state-cache'
|
||||||
|
|
||||||
@@ -46,12 +59,22 @@ describe('useSessionStateCache — per-session turn timer', () => {
|
|||||||
return null as unknown as number
|
return null as unknown as number
|
||||||
})
|
})
|
||||||
setTurnStartedAt(null)
|
setTurnStartedAt(null)
|
||||||
|
setCurrentModel('')
|
||||||
|
setCurrentProvider('')
|
||||||
|
setCurrentReasoningEffort('')
|
||||||
|
setCurrentServiceTier('')
|
||||||
|
setCurrentFastMode(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cleanup()
|
cleanup()
|
||||||
vi.restoreAllMocks()
|
vi.restoreAllMocks()
|
||||||
setTurnStartedAt(null)
|
setTurnStartedAt(null)
|
||||||
|
setCurrentModel('')
|
||||||
|
setCurrentProvider('')
|
||||||
|
setCurrentReasoningEffort('')
|
||||||
|
setCurrentServiceTier('')
|
||||||
|
setCurrentFastMode(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("keeps a background session's running turn clock and never mirrors it to the view", () => {
|
it("keeps a background session's running turn clock and never mirrors it to the view", () => {
|
||||||
@@ -115,4 +138,78 @@ describe('useSessionStateCache — per-session turn timer', () => {
|
|||||||
})
|
})
|
||||||
expect($turnStartedAt.get()).toBeNull()
|
expect($turnStartedAt.get()).toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('mirrors the focused session model metadata when switching from a cached session', () => {
|
||||||
|
let cache!: Cache
|
||||||
|
const { rerender } = render(
|
||||||
|
<Harness activeSessionId="fg-runtime" onReady={c => (cache = c)} selectedStoredSessionId="fg-stored" />
|
||||||
|
)
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
cache.updateSessionState(
|
||||||
|
'bg-runtime',
|
||||||
|
state => ({
|
||||||
|
...state,
|
||||||
|
fast: true,
|
||||||
|
model: 'anthropic/claude-opus-4.8',
|
||||||
|
provider: 'anthropic',
|
||||||
|
reasoningEffort: 'high',
|
||||||
|
serviceTier: 'priority'
|
||||||
|
}),
|
||||||
|
'bg-stored'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Background metadata is cached but must not bleed into the visible statusbar.
|
||||||
|
expect($currentModel.get()).toBe('')
|
||||||
|
expect($currentReasoningEffort.get()).toBe('')
|
||||||
|
expect($currentFastMode.get()).toBe(false)
|
||||||
|
|
||||||
|
rerender(<Harness activeSessionId="bg-runtime" onReady={c => (cache = c)} selectedStoredSessionId="bg-stored" />)
|
||||||
|
|
||||||
|
const bgState = cache.sessionStateByRuntimeIdRef.current.get('bg-runtime')
|
||||||
|
expect(bgState).toBeTruthy()
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
cache.syncSessionStateToView('bg-runtime', bgState!)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect($currentModel.get()).toBe('anthropic/claude-opus-4.8')
|
||||||
|
expect($currentProvider.get()).toBe('anthropic')
|
||||||
|
expect($currentReasoningEffort.get()).toBe('high')
|
||||||
|
expect($currentServiceTier.get()).toBe('priority')
|
||||||
|
expect($currentFastMode.get()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clears stale model metadata when the newly focused session has no cached value', () => {
|
||||||
|
setCurrentModel('previous-model')
|
||||||
|
setCurrentProvider('previous-provider')
|
||||||
|
setCurrentReasoningEffort('high')
|
||||||
|
setCurrentServiceTier('priority')
|
||||||
|
setCurrentFastMode(true)
|
||||||
|
|
||||||
|
let cache!: Cache
|
||||||
|
const { rerender } = render(
|
||||||
|
<Harness activeSessionId="fg-runtime" onReady={c => (cache = c)} selectedStoredSessionId="fg-stored" />
|
||||||
|
)
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
cache.updateSessionState('bg-runtime', state => ({ ...state }), 'bg-stored')
|
||||||
|
})
|
||||||
|
|
||||||
|
rerender(<Harness activeSessionId="bg-runtime" onReady={c => (cache = c)} selectedStoredSessionId="bg-stored" />)
|
||||||
|
|
||||||
|
const bgState = cache.sessionStateByRuntimeIdRef.current.get('bg-runtime')
|
||||||
|
expect(bgState).toBeTruthy()
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
cache.syncSessionStateToView('bg-runtime', bgState!)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect($currentModel.get()).toBe('')
|
||||||
|
expect($currentProvider.get()).toBe('')
|
||||||
|
expect($currentReasoningEffort.get()).toBe('')
|
||||||
|
expect($currentServiceTier.get()).toBe('')
|
||||||
|
expect($currentFastMode.get()).toBe(false)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
noteSessionActivity,
|
noteSessionActivity,
|
||||||
setCurrentFastMode,
|
setCurrentFastMode,
|
||||||
setCurrentModel,
|
setCurrentModel,
|
||||||
|
setCurrentPersonality,
|
||||||
setCurrentProvider,
|
setCurrentProvider,
|
||||||
setCurrentReasoningEffort,
|
setCurrentReasoningEffort,
|
||||||
setCurrentServiceTier,
|
setCurrentServiceTier,
|
||||||
@@ -53,6 +54,16 @@ interface SessionStateCacheOptions {
|
|||||||
setMessages: (messages: ChatMessage[]) => void
|
setMessages: (messages: ChatMessage[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncRuntimeMetadataToView(state: ClientSessionState) {
|
||||||
|
setCurrentModel(state.model ?? '')
|
||||||
|
setCurrentProvider(state.provider ?? '')
|
||||||
|
setCurrentReasoningEffort(state.reasoningEffort ?? '')
|
||||||
|
setCurrentServiceTier(state.serviceTier ?? '')
|
||||||
|
setCurrentFastMode(state.fast ?? false)
|
||||||
|
setYoloActive(state.yolo ?? false)
|
||||||
|
setCurrentPersonality(state.personality ?? '')
|
||||||
|
}
|
||||||
|
|
||||||
export function useSessionStateCache({
|
export function useSessionStateCache({
|
||||||
activeSessionId,
|
activeSessionId,
|
||||||
busyRef,
|
busyRef,
|
||||||
@@ -137,12 +148,7 @@ export function useSessionStateCache({
|
|||||||
setMessages(nextMessages)
|
setMessages(nextMessages)
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentModel(pending.state.model)
|
syncRuntimeMetadataToView(pending.state)
|
||||||
setCurrentProvider(pending.state.provider)
|
|
||||||
setCurrentReasoningEffort(pending.state.reasoningEffort)
|
|
||||||
setCurrentServiceTier(pending.state.serviceTier)
|
|
||||||
setCurrentFastMode(pending.state.fast)
|
|
||||||
setYoloActive(pending.state.yolo)
|
|
||||||
setBusy(pending.state.busy)
|
setBusy(pending.state.busy)
|
||||||
setMutableRef(busyRef, pending.state.busy)
|
setMutableRef(busyRef, pending.state.busy)
|
||||||
setAwaitingResponse(pending.state.awaitingResponse)
|
setAwaitingResponse(pending.state.awaitingResponse)
|
||||||
@@ -167,6 +173,7 @@ export function useSessionStateCache({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncRuntimeMetadataToView(state)
|
||||||
pendingViewStateRef.current = { sessionId, state }
|
pendingViewStateRef.current = { sessionId, state }
|
||||||
|
|
||||||
// Terminal / attention transitions (turn finished, error, or the agent is
|
// Terminal / attention transitions (turn finished, error, or the agent is
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ export interface ClientSessionState {
|
|||||||
serviceTier: string
|
serviceTier: string
|
||||||
fast: boolean
|
fast: boolean
|
||||||
yolo: boolean
|
yolo: boolean
|
||||||
|
personality: string
|
||||||
busy: boolean
|
busy: boolean
|
||||||
awaitingResponse: boolean
|
awaitingResponse: boolean
|
||||||
streamId: string | null
|
streamId: string | null
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export function createClientSessionState(
|
|||||||
serviceTier: '',
|
serviceTier: '',
|
||||||
fast: false,
|
fast: false,
|
||||||
yolo: false,
|
yolo: false,
|
||||||
|
personality: '',
|
||||||
busy: false,
|
busy: false,
|
||||||
awaitingResponse: false,
|
awaitingResponse: false,
|
||||||
streamId: null,
|
streamId: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user