@@ -69,6 +69,8 @@ export type PromptRef = {
6969 submit ( ) : void
7070}
7171
72+ type SubmitTrigger = "enter" | "tab"
73+
7274
7375function resolveHoldKeyNames ( bindings : Keybind . Info [ ] | undefined ) : Set < string > {
7476 const names = new Set < string > ( )
@@ -99,26 +101,9 @@ export function Prompt(props: PromptProps) {
99101 const safeLayoutWidth = createMemo ( ( ) => Math . max ( 0 , layoutWidth ( ) ) )
100102 const borderFill = createMemo ( ( ) => "─" . repeat ( safeLayoutWidth ( ) ) )
101103 const status = createMemo ( ( ) => sync . data . session_status ?. [ props . sessionID ?? "" ] ?? { type : "idle" } )
102- // Extended type to include new fields until SDK is regenerated
103- type StreamHealthExtended = {
104- isStalled : boolean
105- isThinking ?: boolean
106- timeSinceLastEventMs : number
107- timeSinceContentMs ?: number
108- eventsReceived : number
109- stallWarnings : number
110- phase ?: "starting" | "thinking" | "tool_calling" | "generating"
111- charsReceived ?: number
112- estimatedTokens ?: number
113- requestCount ?: number
114- embeddingConfig ?: {
115- model : string
116- maxContext : number
117- }
118- }
119- const streamHealth = createMemo ( ( ) : StreamHealthExtended | undefined => {
104+ const streamHealth = createMemo ( ( ) => {
120105 const s = status ( )
121- return s . type === "busy" ? ( s . streamHealth as StreamHealthExtended | undefined ) : undefined
106+ return s . type === "busy" ? s . streamHealth : undefined
122107 } )
123108 // Session for token counter
124109 const session = createMemo ( ( ) => props . sessionID ? sync . session . get ( props . sessionID ) : undefined )
@@ -674,7 +659,7 @@ export function Prompt(props: PromptProps) {
674659 insertDictationText ( transcript )
675660 setDictationState ( "idle" )
676661 if ( config . autoSubmit ) {
677- setTimeout ( ( ) => submit ( ) , 0 )
662+ setTimeout ( ( ) => submit ( "enter" ) , 0 )
678663 }
679664 } catch ( error ) {
680665 toast . show ( {
@@ -1227,7 +1212,7 @@ export function Prompt(props: PromptProps) {
12271212 setStore ( "extmarkToPartIndex" , new Map ( ) )
12281213 } ,
12291214 submit ( ) {
1230- submit ( )
1215+ submit ( "enter" )
12311216 } ,
12321217 }
12331218
@@ -1392,7 +1377,7 @@ export function Prompt(props: PromptProps) {
13921377 } ,
13931378 ] )
13941379
1395- async function submit ( ) {
1380+ async function submit ( trigger : SubmitTrigger = "enter" ) {
13961381 if ( props . disabled ) return
13971382 if ( autocomplete ?. visible ) return
13981383 if ( ! store . prompt . input ) return
@@ -1477,9 +1462,13 @@ export function Prompt(props: PromptProps) {
14771462 // Capture mode before it gets reset
14781463 const currentMode = store . mode
14791464 const variant = local . model . variant . current ( )
1465+ const sessionStatus = status ( )
1466+ const activeTurnID = sessionStatus . type === "busy" ? sessionStatus . activeTurnID : undefined
14801467 const busyDecision = decideBusySubmit ( {
1481- sessionIsBusy : status ( ) . type !== "idle" ,
1468+ sessionIsBusy : sessionStatus . type !== "idle" ,
14821469 hasSessionID : Boolean ( props . sessionID ) ,
1470+ hasActiveTurn : Boolean ( activeTurnID ) ,
1471+ trigger,
14831472 } )
14841473
14851474 // Tool permissions based on mode
@@ -1617,9 +1606,41 @@ export function Prompt(props: PromptProps) {
16171606 ] ,
16181607 } satisfies Parameters < typeof sdk . client . session . prompt > [ 0 ]
16191608
1609+ const queuePrompt = async ( ) => {
1610+ try {
1611+ await sdk . client . session . prompt (
1612+ {
1613+ ...promptPayload ,
1614+ noReply : true ,
1615+ } ,
1616+ { throwOnError : true } ,
1617+ )
1618+ toast . show ( {
1619+ message : "Message queued." ,
1620+ variant : "info" ,
1621+ duration : 2000 ,
1622+ } )
1623+ } catch ( error ) {
1624+ restoreInput ( )
1625+ toast . show ( {
1626+ message : `Failed to queue message: ${ formatSubmitError ( error ) } ` ,
1627+ variant : "error" ,
1628+ duration : 7000 ,
1629+ } )
1630+ }
1631+ }
1632+
16201633 if ( busyDecision . submit === "steer" ) {
1634+ if ( ! activeTurnID ) {
1635+ await queuePrompt ( )
1636+ return
1637+ }
16211638 try {
1622- await sdk . client . session . steer ( promptPayload , { throwOnError : true } )
1639+ const steerPayload = {
1640+ ...promptPayload ,
1641+ expectedTurnID : activeTurnID ,
1642+ } satisfies Parameters < typeof sdk . client . session . steer > [ 0 ]
1643+ await sdk . client . session . steer ( steerPayload , { throwOnError : true } )
16231644 toast . show ( {
16241645 message : "Steering message sent." ,
16251646 variant : "info" ,
@@ -1636,6 +1657,11 @@ export function Prompt(props: PromptProps) {
16361657 return
16371658 }
16381659
1660+ if ( busyDecision . submit === "queue" ) {
1661+ await queuePrompt ( )
1662+ return
1663+ }
1664+
16391665 try {
16401666 await sdk . client . session . prompt ( promptPayload , { throwOnError : true } )
16411667 } catch ( error ) {
@@ -2054,6 +2080,20 @@ export function Prompt(props: PromptProps) {
20542080 }
20552081 if ( store . mode === "normal" ) autocomplete . onKeyDown ( e )
20562082 if ( ! autocomplete . visible ) {
2083+ if (
2084+ e . name === "tab" &&
2085+ ! e . ctrl &&
2086+ ! e . meta &&
2087+ ! e . shift &&
2088+ ! keybind . leader &&
2089+ store . mode !== "shell" &&
2090+ ! input . plainText . trimStart ( ) . startsWith ( "!" )
2091+ ) {
2092+ e . preventDefault ( )
2093+ await submit ( "tab" )
2094+ return
2095+ }
2096+
20572097 if (
20582098 ( keybind . match ( "history_previous" , e ) && input . cursorOffset === 0 ) ||
20592099 ( keybind . match ( "history_next" , e ) && input . cursorOffset === input . plainText . length )
@@ -2078,7 +2118,7 @@ export function Prompt(props: PromptProps) {
20782118 input . cursorOffset = input . plainText . length
20792119 }
20802120 } }
2081- onSubmit = { submit }
2121+ onSubmit = { ( ) => submit ( "enter" ) }
20822122 onPaste = { async ( event : PasteEvent ) => {
20832123 if ( props . disabled ) {
20842124 event . preventDefault ( )
0 commit comments