Skip to content

Commit 060a6ee

Browse files
committed
cli: FAST / MAX toggle (shift + tab or click)
1 parent e81e8bf commit 060a6ee

File tree

5 files changed

+95
-9
lines changed

5 files changed

+95
-9
lines changed

cli/src/chat.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useRenderer } from '@opentui/react'
22
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
33
import { useShallow } from 'zustand/react/shallow'
44

5+
import { AgentModeToggle } from './components/agent-mode-toggle'
56
import { MultilineInput } from './components/multiline-input'
67
import { Separator } from './components/separator'
78
import { StatusIndicator, useHasStatus } from './components/status-indicator'
@@ -104,6 +105,8 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
104105
setActiveSubagents,
105106
isChainInProgress,
106107
setIsChainInProgress,
108+
agentMode,
109+
toggleAgentMode,
107110
} = useChatStore(
108111
useShallow((store) => ({
109112
inputValue: store.inputValue,
@@ -126,6 +129,8 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
126129
setActiveSubagents: store.setActiveSubagents,
127130
isChainInProgress: store.isChainInProgress,
128131
setIsChainInProgress: store.setIsChainInProgress,
132+
agentMode: store.agentMode,
133+
toggleAgentMode: store.toggleAgentMode,
129134
})),
130135
)
131136

@@ -397,7 +402,9 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
397402
)
398403

399404
const sendMessageRef =
400-
useRef<(content: string, onComplete?: () => void) => Promise<void>>()
405+
useRef<
406+
(content: string, params: { agentMode: 'FAST' | 'MAX' }) => Promise<void>
407+
>()
401408

402409
const {
403410
queuedMessages,
@@ -411,7 +418,8 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
411418
setCanProcessQueue,
412419
setIsStreaming,
413420
} = useMessageQueue(
414-
(content: string) => sendMessageRef.current?.(content) ?? Promise.resolve(),
421+
(content: string) =>
422+
sendMessageRef.current?.(content, { agentMode }) ?? Promise.resolve(),
415423
isChainInProgressRef,
416424
activeAgentStreamsRef,
417425
)
@@ -444,14 +452,14 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
444452
const timeout = setTimeout(() => {
445453
logger.info({ prompt: initialPrompt }, 'Auto-submitting initial prompt')
446454
if (sendMessageRef.current) {
447-
sendMessageRef.current(initialPrompt)
455+
sendMessageRef.current(initialPrompt, { agentMode })
448456
}
449457
}, 100)
450458

451459
return () => clearTimeout(timeout)
452460
}
453461
return undefined
454-
}, [initialPrompt])
462+
}, [initialPrompt, agentMode])
455463

456464
const hasStatus = useHasStatus(isWaitingForResponse, clipboardMessage)
457465

@@ -473,7 +481,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
473481
return
474482
}
475483

476-
sendMessage(trimmed)
484+
sendMessage(trimmed, { agentMode })
477485

478486
setTimeout(() => {
479487
scrollToLatest()
@@ -500,6 +508,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
500508
setCollapsedAgents,
501509
navigateUp,
502510
navigateDown,
511+
toggleAgentMode,
503512
})
504513

505514
const { tree: messageTree, topLevelMessages } = useMemo(
@@ -637,6 +646,11 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
637646
</text>
638647
</>
639648
)}
649+
<AgentModeToggle
650+
mode={agentMode}
651+
theme={theme}
652+
onToggle={toggleAgentMode}
653+
/>
640654
<Separator theme={theme} width={renderer.width} />
641655
{slashContext.active && slashSuggestionItems.length > 0 ? (
642656
<SuggestionMenu
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { ChatTheme } from '../utils/theme-system'
2+
3+
export const AgentModeToggle = ({
4+
mode,
5+
theme,
6+
onToggle,
7+
}: {
8+
mode: 'FAST' | 'MAX'
9+
theme: ChatTheme
10+
onToggle: () => void
11+
}) => {
12+
const isFast = mode === 'FAST'
13+
14+
const bgColor = isFast ? '#12852e' : '#ac1626'
15+
const textColor = '#ffffff'
16+
const label = isFast ? 'FAST' : '💪 MAX'
17+
18+
return (
19+
<box
20+
style={{
21+
flexDirection: 'row',
22+
alignSelf: 'flex-end',
23+
backgroundColor: bgColor,
24+
paddingLeft: isFast ? 2 : 1,
25+
paddingRight: isFast ? 2 : 1,
26+
}}
27+
onMouseDown={onToggle}
28+
>
29+
<text wrap={false}>
30+
<span fg={textColor}>{label}</span>
31+
</text>
32+
</box>
33+
)
34+
}

cli/src/hooks/use-keyboard-handlers.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ interface KeyboardHandlersConfig {
1414
setCollapsedAgents: React.Dispatch<React.SetStateAction<Set<string>>>
1515
navigateUp: () => void
1616
navigateDown: () => void
17+
toggleAgentMode: () => void
1718
}
1819

1920
export const useKeyboardHandlers = ({
@@ -27,6 +28,7 @@ export const useKeyboardHandlers = ({
2728
setCollapsedAgents,
2829
navigateUp,
2930
navigateDown,
31+
toggleAgentMode,
3032
}: KeyboardHandlersConfig) => {
3133
useKeyboard(
3234
useCallback(
@@ -150,4 +152,25 @@ export const useKeyboardHandlers = ({
150152
[navigateUp, navigateDown],
151153
),
152154
)
155+
156+
useKeyboard(
157+
useCallback(
158+
(key) => {
159+
const isShiftTab =
160+
key.shift && key.name === 'tab' && !key.ctrl && !key.meta
161+
162+
if (!isShiftTab) return
163+
164+
if (
165+
'preventDefault' in key &&
166+
typeof key.preventDefault === 'function'
167+
) {
168+
key.preventDefault()
169+
}
170+
171+
toggleAgentMode()
172+
},
173+
[toggleAgentMode],
174+
),
175+
)
153176
}

cli/src/hooks/use-send-message.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ interface UseSendMessageOptions {
107107
setIsStreaming: (streaming: boolean) => void
108108
setCanProcessQueue: (can: boolean) => void
109109
abortControllerRef: React.MutableRefObject<AbortController | null>
110-
agentMode: 'FAST' | 'MAX'
111110
}
112111

113112
export const useSendMessage = ({
@@ -127,7 +126,6 @@ export const useSendMessage = ({
127126
setIsStreaming,
128127
setCanProcessQueue,
129128
abortControllerRef,
130-
agentMode,
131129
}: UseSendMessageOptions) => {
132130
const previousRunStateRef = useRef<any>(null)
133131
const spawnAgentsMapRef = useRef<
@@ -253,7 +251,8 @@ export const useSendMessage = ({
253251
}, [flushPendingUpdates])
254252

255253
const sendMessage = useCallback(
256-
async (content: string) => {
254+
async (content: string, params: { agentMode: 'FAST' | 'MAX' }) => {
255+
const { agentMode } = params
257256
const timestamp = formatTimestamp()
258257
const userMessage: ChatMessage = {
259258
id: `user-${Date.now()}`,
@@ -557,8 +556,9 @@ export const useSendMessage = ({
557556
// Load local agent definitions from .agents directory
558557
const agentDefinitions = loadAgentDefinitions()
559558

559+
const agent = agentMode === 'FAST' ? 'base2-fast' : 'base2-max'
560560
const result = await client.run({
561-
agent: 'base',
561+
agent,
562562
prompt: content,
563563
previousRun: previousRunStateRef.current,
564564
signal: abortController.signal,

cli/src/state/chat-store.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export type ChatStoreState = {
1717
isChainInProgress: boolean
1818
slashSelectedIndex: number
1919
agentSelectedIndex: number
20+
agentMode: 'FAST' | 'MAX'
2021
}
2122

2223
type ChatStoreActions = {
@@ -30,6 +31,8 @@ type ChatStoreActions = {
3031
setIsChainInProgress: (active: boolean) => void
3132
setSlashSelectedIndex: (value: number | ((prev: number) => number)) => void
3233
setAgentSelectedIndex: (value: number | ((prev: number) => number)) => void
34+
setAgentMode: (mode: 'FAST' | 'MAX') => void
35+
toggleAgentMode: () => void
3336
reset: () => void
3437
}
3538

@@ -56,6 +59,7 @@ const initialState: ChatStoreState = {
5659
isChainInProgress: false,
5760
slashSelectedIndex: 0,
5861
agentSelectedIndex: 0,
62+
agentMode: 'FAST',
5963
}
6064

6165
export const useChatStore = create<ChatStore>()(immer((set) => ({
@@ -111,6 +115,16 @@ export const useChatStore = create<ChatStore>()(immer((set) => ({
111115
state.agentSelectedIndex = typeof value === 'function' ? value(state.agentSelectedIndex) : value
112116
}),
113117

118+
setAgentMode: (mode) =>
119+
set((state) => {
120+
state.agentMode = mode
121+
}),
122+
123+
toggleAgentMode: () =>
124+
set((state) => {
125+
state.agentMode = state.agentMode === 'FAST' ? 'MAX' : 'FAST'
126+
}),
127+
114128
reset: () =>
115129
set((state) => {
116130
state.messages = initialState.messages.slice()
@@ -123,5 +137,6 @@ export const useChatStore = create<ChatStore>()(immer((set) => ({
123137
state.isChainInProgress = initialState.isChainInProgress
124138
state.slashSelectedIndex = initialState.slashSelectedIndex
125139
state.agentSelectedIndex = initialState.agentSelectedIndex
140+
state.agentMode = initialState.agentMode
126141
}),
127142
})))

0 commit comments

Comments
 (0)