Files
orca/src/shared/native-chat-session-options.ts
T
Jinjing 546cc8237f Improve native chat ui (#9246)
* refactor(native-chat): extract option appliers and improve toggle UI

- Extract setOption apply logic to native-chat-session-option-apply.ts
- Add invokeAction method for toggle-only options without tracked baseline
- Replace checkbox UI with On/Off radio groups for boolean options
- Display option values only in pills (remove redundant label prefixes)
- Serialize concurrent applies so later dispatches win in order

* Remove focus-visible border from composer container

The container uses a steady hairline border (no focus/click flash), with focus-visible styling delegated to the inner textarea. The container is a layout wrapper, not a focus target.

* Prevent option commits on model switch during dispatch

When a user changes an option and the model switches before dispatch
completes, committing the stale option would overwrite state under
the new model. Guard by capturing the baseline option state before
dispatch and validating it hasn't changed post-dispatch.

* Use invokeAction for model option in NativeChatComposer test

Codex model is an agent picker mid-session, so setOption rejects.
Update test to use invokeAction to match the actual UI behavior.
2026-07-17 17:18:27 -07:00

64 lines
2.0 KiB
TypeScript

export type SessionOptionValue = string | boolean
export type SessionOptionSelectChoice = {
value: string
label: string
description?: string
}
export type SessionOptionValueSource = 'applied' | 'dispatched' | 'reported' | 'unknown'
/** Closed set of reasons an option is not settable in the current mode. A key
* (not free English) so the producer and the localized label stay in sync —
* an exhaustive switch turns any drift into a type error instead of leaking
* untranslated text. */
export type SessionOptionDisabledReason =
| 'available-after-session-start'
| 'set-when-session-starts'
export type SessionOptionDescriptor = {
id: string
label: string
description?: string
category?: 'model' | 'thought_level' | 'model_config' | 'mode'
kind:
| {
type: 'select'
currentValue?: string
choices: SessionOptionSelectChoice[]
}
| {
type: 'boolean'
currentValue?: boolean
}
valueSource: SessionOptionValueSource
settable: boolean
disabledReason?: SessionOptionDisabledReason
/** Why: picker-only and toggle-only PTY commands cannot be represented as
* a truthful radio/checkbox state, so the producer exposes an action row. */
action?: { type: 'agent-picker' | 'toggle-command' }
}
export type SessionOptionSetResult = {
snapshot: SessionOptionDescriptor[]
}
export type PersistedNativeChatSessionOptions = Partial<
Record<
string,
{
model?: string
valuesByModel?: Record<string, Record<string, SessionOptionValue>>
}
>
>
export type SessionOptionsSurface = {
getSnapshot(): SessionOptionDescriptor[]
/** Apply an absolute target; known flip-only options use their tracked baseline. */
setOption(id: string, value: SessionOptionValue): Promise<SessionOptionSetResult>
/** Invoke the value-less action exposed by the current descriptor. */
invokeAction(id: string): Promise<SessionOptionSetResult>
subscribe(listener: (snapshot: SessionOptionDescriptor[]) => void): () => void
}