Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion shared/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ const SIDEBAR_LOCAL_KEYS = [
'width',
'collapsed',
] as const
const AGENT_CHAT_LOCAL_KEYS = [
'showThinking',
'showTools',
'showTimecodes',
] as const

export type ThemeMode = (typeof THEME_VALUES)[number]
export type TerminalTheme = (typeof TERMINAL_THEME_VALUES)[number]
Expand Down Expand Up @@ -180,6 +185,11 @@ export type LocalSettings = {
width: number
collapsed: boolean
}
agentChat: {
showThinking: boolean
showTools: boolean
showTimecodes: boolean
}
notifications: {
soundEnabled: boolean
}
Expand All @@ -201,7 +211,7 @@ export type ResolvedSettings = {
codingCli: ServerSettings['codingCli']
panes: ServerSettings['panes'] & LocalSettings['panes']
editor: ServerSettings['editor']
agentChat: ServerSettings['agentChat']
agentChat: ServerSettings['agentChat'] & LocalSettings['agentChat']
extensions: ServerSettings['extensions']
network: ServerSettings['network']
}
Expand Down Expand Up @@ -465,6 +475,22 @@ function normalizeExtractedLocalSeed(patch: Record<string, unknown>): LocalSetti
}
}

if (isRecord(patch.agentChat)) {
const agentChat: LocalSettingsPatch['agentChat'] = {}
if (typeof patch.agentChat.showThinking === 'boolean') {
agentChat.showThinking = patch.agentChat.showThinking as boolean
}
if (typeof patch.agentChat.showTools === 'boolean') {
agentChat.showTools = patch.agentChat.showTools as boolean
}
if (typeof patch.agentChat.showTimecodes === 'boolean') {
agentChat.showTimecodes = patch.agentChat.showTimecodes as boolean
}
if (Object.keys(agentChat).length > 0) {
normalized.agentChat = agentChat
}
}

if (isRecord(patch.notifications)) {
const notifications: LocalSettingsPatch['notifications'] = {}
if (typeof patch.notifications.soundEnabled === 'boolean') {
Expand Down Expand Up @@ -695,6 +721,11 @@ export const defaultLocalSettings: LocalSettings = {
width: 288,
collapsed: false,
},
agentChat: {
showThinking: false,
showTools: false,
showTimecodes: false,
},
notifications: {
soundEnabled: true,
},
Expand Down Expand Up @@ -978,6 +1009,7 @@ export function resolveLocalSettings(patch?: LocalSettingsPatch): LocalSettings
sortMode: normalizeLocalSortMode(patch?.sidebar?.sortMode),
worktreeGrouping: normalizeWorktreeGrouping(patch?.sidebar?.worktreeGrouping),
},
agentChat: mergeDefined(defaultLocalSettings.agentChat, patch?.agentChat),
notifications: mergeDefined(defaultLocalSettings.notifications, patch?.notifications),
}
}
Expand Down Expand Up @@ -1018,6 +1050,14 @@ export function mergeLocalSettings(base: LocalSettingsPatch | undefined, patch:
next.sidebar = sidebar as LocalSettingsPatch['sidebar']
}

const agentChat = mergeDefined(
(base?.agentChat || {}) as Record<string, unknown>,
patch.agentChat as Record<string, unknown> | undefined,
)
if (Object.keys(agentChat).length > 0) {
next.agentChat = agentChat as LocalSettingsPatch['agentChat']
}

const notifications = mergeDefined(
(base?.notifications || {}) as Record<string, unknown>,
patch.notifications as Record<string, unknown> | undefined,
Expand Down Expand Up @@ -1062,6 +1102,7 @@ export function composeResolvedSettings(server: ServerSettings, local: LocalSett
...server.agentChat,
defaultPlugins: [...server.agentChat.defaultPlugins],
providers: mergeRecordOfObjects(server.agentChat.providers),
...local.agentChat,
},
extensions: {
disabled: [...server.extensions.disabled],
Expand Down Expand Up @@ -1097,6 +1138,9 @@ export function extractLegacyLocalSettingsSeed(
}
maybeAssignNested(patch, 'sidebar', sidebarPatch)
}
if (isRecord(raw.agentChat)) {
maybeAssignNested(patch, 'agentChat', pickKeys(raw.agentChat, AGENT_CHAT_LOCAL_KEYS))
}
if (isRecord(raw.notifications)) {
maybeAssignNested(patch, 'notifications', pickKeys(raw.notifications, ['soundEnabled']))
}
Expand Down Expand Up @@ -1140,5 +1184,14 @@ export function stripLocalSettings(
}
}

if (isRecord(raw.agentChat)) {
const strippedAgentChat = omitKeys(raw.agentChat, AGENT_CHAT_LOCAL_KEYS)
if (Object.keys(strippedAgentChat).length > 0) {
next.agentChat = strippedAgentChat
} else {
delete next.agentChat
}
}

return next
}
6 changes: 5 additions & 1 deletion src/components/agent-chat/AgentChatSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import type { AgentChatPaneContent } from '@/store/paneTypes'
import type { AgentChatProviderConfig } from '@/lib/agent-chat-types'
import { formatModelDisplayName } from '../../../shared/format-model-name'

type SettingsFields = Pick<AgentChatPaneContent, 'model' | 'permissionMode' | 'effort' | 'showThinking' | 'showTools' | 'showTimecodes'>
type SettingsFields = Pick<AgentChatPaneContent, 'model' | 'permissionMode' | 'effort'> & {
showThinking?: boolean
showTools?: boolean
showTimecodes?: boolean
}

interface AgentChatSettingsProps {
model: string
Expand Down
83 changes: 51 additions & 32 deletions src/components/agent-chat/AgentChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { getAgentChatProviderConfig } from '@/lib/agent-chat-utils'
import { isValidClaudeSessionId } from '@/lib/claude-session-id'
import { getInstalledPerfAuditBridge } from '@/lib/perf-audit-bridge'
import { saveServerSettingsPatch } from '@/store/settingsThunks'
import { updateSettingsLocal } from '@/store/settingsSlice'
import type { Tab } from '@/store/types'
import {
buildAgentChatPersistedIdentityUpdate,
Expand Down Expand Up @@ -64,9 +65,10 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
const defaultModel = providerConfig?.defaultModel ?? 'claude-opus-4-6'
const defaultPermissionMode = providerConfig?.defaultPermissionMode ?? 'bypassPermissions'
const defaultEffort = providerConfig?.defaultEffort ?? 'high'
const defaultShowThinking = providerConfig?.defaultShowThinking ?? true
const defaultShowTools = providerConfig?.defaultShowTools ?? true
const defaultShowTimecodes = providerConfig?.defaultShowTimecodes ?? false
const localSettings = useAppSelector((state) => state.settings.settings)
const defaultShowThinking = localSettings.agentChat.showThinking
const defaultShowTools = localSettings.agentChat.showTools
const defaultShowTimecodes = localSettings.agentChat.showTimecodes
const providerLabel = providerConfig?.label ?? 'Agent Chat'
const createSentRef = useRef(false)
const attachSentRef = useRef(false)
Expand Down Expand Up @@ -543,11 +545,28 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
}, [])

const handleSettingsChange = useCallback((changes: Record<string, unknown>) => {
dispatch(updatePaneContent({
tabId,
paneId,
content: { ...paneContentRef.current, ...changes },
}))
const paneChanges: Partial<AgentChatPaneContent> = {}
const localChanges: Record<string, unknown> = {}

for (const [key, value] of Object.entries(changes)) {
if (key === 'showThinking' || key === 'showTools' || key === 'showTimecodes') {
localChanges[key] = value
} else {
(paneChanges as Record<string, unknown>)[key] = value
}
}

if (Object.keys(paneChanges).length > 0) {
dispatch(updatePaneContent({
tabId,
paneId,
content: { ...paneContentRef.current, ...paneChanges },
}))
}

if (Object.keys(localChanges).length > 0) {
dispatch(updateSettingsLocal({ agentChat: localChanges }))
}

const pc = paneContentRef.current

Expand Down Expand Up @@ -703,9 +722,9 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
model={paneContent.model ?? defaultModel}
permissionMode={paneContent.permissionMode ?? defaultPermissionMode}
effort={paneContent.effort ?? defaultEffort}
showThinking={paneContent.showThinking ?? defaultShowThinking}
showTools={paneContent.showTools ?? defaultShowTools}
showTimecodes={paneContent.showTimecodes ?? defaultShowTimecodes}
showThinking={defaultShowThinking}
showTools={defaultShowTools}
showTimecodes={defaultShowTimecodes}
sessionStarted={sessionStarted}
defaultOpen={shouldShowSettings}
modelOptions={availableModels.length > 0 ? availableModels : undefined}
Expand Down Expand Up @@ -765,9 +784,9 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
content={turn.message.content}
timestamp={turn.message.timestamp}
model={turn.message.model}
showThinking={paneContent.showThinking ?? defaultShowThinking}
showTools={paneContent.showTools ?? defaultShowTools}
showTimecodes={paneContent.showTimecodes ?? defaultShowTimecodes}
showThinking={defaultShowThinking}
showTools={defaultShowTools}
showTimecodes={defaultShowTimecodes}
/>
)
}
Expand All @@ -785,9 +804,9 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
turnId: item.turnId,
}))
}}
showThinking={paneContent.showThinking ?? defaultShowThinking}
showTools={paneContent.showTools ?? defaultShowTools}
showTimecodes={paneContent.showTimecodes ?? defaultShowTimecodes}
showThinking={defaultShowThinking}
showTools={defaultShowTools}
showTimecodes={defaultShowTimecodes}
/>
)
})}
Expand All @@ -805,9 +824,9 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
key={`turn-${i}`}
userMessage={item.user}
assistantMessage={item.assistant}
showThinking={paneContent.showThinking ?? defaultShowThinking}
showTools={paneContent.showTools ?? defaultShowTools}
showTimecodes={paneContent.showTimecodes ?? defaultShowTimecodes}
showThinking={defaultShowThinking}
showTools={defaultShowTools}
showTimecodes={defaultShowTimecodes}
/>
)
}
Expand All @@ -817,19 +836,19 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
speaker={item.user.role}
content={item.user.content}
timestamp={item.user.timestamp}
showThinking={paneContent.showThinking ?? defaultShowThinking}
showTools={paneContent.showTools ?? defaultShowTools}
showTimecodes={paneContent.showTimecodes ?? defaultShowTimecodes}
showThinking={defaultShowThinking}
showTools={defaultShowTools}
showTimecodes={defaultShowTimecodes}
/>
<MessageBubble
speaker={item.assistant.role}
content={item.assistant.content}
timestamp={item.assistant.timestamp}
model={item.assistant.model}
isLastMessage={isLast}
showThinking={paneContent.showThinking ?? defaultShowThinking}
showTools={paneContent.showTools ?? defaultShowTools}
showTimecodes={paneContent.showTimecodes ?? defaultShowTimecodes}
showThinking={defaultShowThinking}
showTools={defaultShowTools}
showTimecodes={defaultShowTimecodes}
/>
</React.Fragment>
)
Expand All @@ -843,9 +862,9 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
timestamp={item.message.timestamp}
model={item.message.model}
isLastMessage={isLast}
showThinking={paneContent.showThinking ?? defaultShowThinking}
showTools={paneContent.showTools ?? defaultShowTools}
showTimecodes={paneContent.showTimecodes ?? defaultShowTimecodes}
showThinking={defaultShowThinking}
showTools={defaultShowTools}
showTimecodes={defaultShowTimecodes}
/>
)
})
Expand All @@ -855,9 +874,9 @@ export default function AgentChatView({ tabId, paneId, paneContent, hidden }: Ag
<MessageBubble
speaker="assistant"
content={streamingContent}
showThinking={paneContent.showThinking ?? defaultShowThinking}
showTools={paneContent.showTools ?? defaultShowTools}
showTimecodes={paneContent.showTimecodes ?? defaultShowTimecodes}
showThinking={defaultShowThinking}
showTools={defaultShowTools}
showTimecodes={defaultShowTimecodes}
/>
)}

Expand Down
4 changes: 2 additions & 2 deletions src/components/agent-chat/CollapsedTurn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ function CollapsedTurn({
message,
loading = false,
onExpand,
showThinking = true,
showTools = true,
showThinking = false,
showTools = false,
showTimecodes = false,
}: CollapsedTurnProps) {
const [expanded, setExpanded] = useState(false)
Expand Down
4 changes: 2 additions & 2 deletions src/components/agent-chat/MessageBubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ function MessageBubble({
content,
timestamp,
model,
showThinking = true,
showTools = true,
showThinking = false,
showTools = false,
showTimecodes = false,
isLastMessage = false,
}: MessageBubbleProps) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/agent-chat/ToolStrip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export interface ToolPair {
interface ToolStripProps {
pairs: ToolPair[]
isStreaming: boolean
/** When false, strip is locked to collapsed view (no expand chevron). Default true. */
/** When true, strip starts expanded. Default false. */
showTools?: boolean
}

function ToolStrip({ pairs, isStreaming, showTools = true }: ToolStripProps) {
function ToolStrip({ pairs, isStreaming, showTools = false }: ToolStripProps) {
const [stripExpanded, setStripExpanded] = useState(showTools)
useEffect(() => { setStripExpanded(showTools) }, [showTools])

Expand Down
27 changes: 27 additions & 0 deletions src/components/settings/WorkspaceSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,33 @@ export default function WorkspaceSettings({
</SettingsRow>
</SettingsSection>

<SettingsSection title="Agent chat" description="Display settings for agent chat panes">
<SettingsRow label="Show thinking">
<Toggle
checked={settings.agentChat?.showThinking ?? false}
onChange={(checked) => {
applyLocalSetting({ agentChat: { showThinking: checked } })
}}
/>
</SettingsRow>
<SettingsRow label="Show tools">
<Toggle
checked={settings.agentChat?.showTools ?? false}
onChange={(checked) => {
applyLocalSetting({ agentChat: { showTools: checked } })
}}
/>
</SettingsRow>
<SettingsRow label="Show timecodes &amp; model">
<Toggle
checked={settings.agentChat?.showTimecodes ?? false}
onChange={(checked) => {
applyLocalSetting({ agentChat: { showTimecodes: checked } })
}}
/>
</SettingsRow>
</SettingsSection>

<SettingsSection title="Editor" description="External editor for file opening">
<SettingsRow label="External editor" description="Which editor to use when opening files from the editor pane">
<select
Expand Down
4 changes: 0 additions & 4 deletions src/lib/agent-chat-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ export interface AgentChatProviderConfig {
defaultPermissionMode: string
/** Default effort level */
defaultEffort: 'low' | 'medium' | 'high' | 'max'
/** Default display settings */
defaultShowThinking: boolean
defaultShowTools: boolean
defaultShowTimecodes: boolean
/** Which settings are visible in the settings popover */
settingsVisibility: {
model: boolean
Expand Down
6 changes: 0 additions & 6 deletions src/lib/agent-chat-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ export const AGENT_CHAT_PROVIDER_CONFIGS: AgentChatProviderConfig[] = [
defaultModel: 'claude-opus-4-6',
defaultPermissionMode: 'bypassPermissions',
defaultEffort: 'high',
defaultShowThinking: true,
defaultShowTools: true,
defaultShowTimecodes: false,
settingsVisibility: {
model: true,
permissionMode: true,
Expand All @@ -38,9 +35,6 @@ export const AGENT_CHAT_PROVIDER_CONFIGS: AgentChatProviderConfig[] = [
defaultModel: 'claude-opus-4-6',
defaultPermissionMode: 'bypassPermissions',
defaultEffort: 'high',
defaultShowThinking: true,
defaultShowTools: true,
defaultShowTimecodes: false,
settingsVisibility: {
model: true,
permissionMode: true,
Expand Down
Loading
Loading