@@ -23,6 +23,7 @@ import {
2323 selectFreebuffChatModel ,
2424 requestFreebuffChatAdmission ,
2525} from '../state/freebuff-chat-store'
26+ import { captureCliFunnel } from '../utils/cli-product-funnel'
2627import { isPlainEnterKey } from '../utils/terminal-enter-detection'
2728
2829export function FreebuffChatControls ( ) {
@@ -36,11 +37,25 @@ export function FreebuffChatControls() {
3637 const session = useFreebuffSessionStore ( ( s ) => s . session )
3738 const { clearQueue, queuePaused } = useChatRuntime ( )
3839 useEffect ( ( ) => {
39- if ( pickerOpen ) void refreshFreebuffSessionMetadata ( ) . catch ( ( ) => { } )
40+ if ( pickerOpen ) {
41+ captureCliFunnel ( 'model_picker' , 'shown' , { model : nextModel ?? model } )
42+ void refreshFreebuffSessionMetadata ( ) . catch ( ( ) => { } )
43+ }
4044 } , [ pickerOpen ] )
45+ useEffect ( ( ) => {
46+ if ( ! admission ) return
47+ const state =
48+ admission . phase === 'failed'
49+ ? 'failed'
50+ : admission . phase === 'starting'
51+ ? 'started'
52+ : 'shown'
53+ captureCliFunnel ( 'admission' , state , { model : admission . model } )
54+ } , [ admission ?. phase , admission ?. model ] )
4155
4256 const cancel = useCallback ( async ( ) => {
4357 if ( pickerOpen ) {
58+ captureCliFunnel ( 'model_picker' , 'cancelled' )
4459 useFreebuffChatStore . setState ( { pickerOpen : false } )
4560 return
4661 }
@@ -60,6 +75,7 @@ export function FreebuffChatControls() {
6075 return
6176 }
6277 }
78+ captureCliFunnel ( 'admission' , 'cancelled' , { model : current . model } )
6379 const queued = clearQueue ( )
6480 const chat = useChatStore . getState ( )
6581 const text = [ ...queued . map ( ( m ) => m . content ) , chat . inputValue ]
@@ -81,6 +97,11 @@ export function FreebuffChatControls() {
8197
8298 const confirm = useCallback ( ( ) => {
8399 if ( ! admission ) return
100+ if (
101+ session ?. status === 'takeover_prompt' ||
102+ [ 'confirm' , 'failed' ] . includes ( admission . phase )
103+ )
104+ captureCliFunnel ( 'admission' , 'clicked' , { model : admission . model } )
84105 if ( session ?. status === 'takeover_prompt' ) {
85106 void takeOverFreebuffSession ( )
86107 } else if ( admission . phase === 'confirm' ) {
@@ -117,8 +138,20 @@ export function FreebuffChatControls() {
117138 maxHeight = { Math . max ( 4 , Math . floor ( terminalHeight * 0.65 ) - 2 ) }
118139 selectedModelOverride = { nextModel ?? model }
119140 initialView = { pickerInitialView }
120- onSelectModel = { selectFreebuffChatModel }
121- onCancel = { ( ) => useFreebuffChatStore . setState ( { pickerOpen : false } ) }
141+ onSelectModel = { ( selected ) => {
142+ selectFreebuffChatModel ( selected )
143+ if ( ! useFreebuffChatStore . getState ( ) . pickerOpen )
144+ captureCliFunnel ( 'model_selection' , 'selected' , {
145+ model : selected ,
146+ previous_model : nextModel ?? model ,
147+ selection_kind :
148+ selected === ( nextModel ?? model ) ? 'reselected' : 'changed' ,
149+ } )
150+ } }
151+ onCancel = { ( ) => {
152+ captureCliFunnel ( 'model_picker' , 'cancelled' )
153+ useFreebuffChatStore . setState ( { pickerOpen : false } )
154+ } }
122155 />
123156 </ box >
124157 )
0 commit comments