@@ -32,7 +32,9 @@ import { useNavigate, useParams } from "@solidjs/router"
3232import { useSync } from "@/context/sync"
3333import { useComments } from "@/context/comments"
3434import { FileIcon } from "@opencode-ai/ui/file-icon"
35+ import { MorphChevron } from "@opencode-ai/ui/morph-chevron"
3536import { Button } from "@opencode-ai/ui/button"
37+ import { CycleLabel } from "@opencode-ai/ui/cycle-label"
3638import { Icon } from "@opencode-ai/ui/icon"
3739import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
3840import type { IconName } from "@opencode-ai/ui/icons/provider"
@@ -42,6 +44,7 @@ import { Select } from "@opencode-ai/ui/select"
4244import { getDirectory , getFilename , getFilenameTruncated } from "@opencode-ai/util/path"
4345import { useDialog } from "@opencode-ai/ui/context/dialog"
4446import { ImagePreview } from "@opencode-ai/ui/image-preview"
47+ import { ReasoningIcon } from "@opencode-ai/ui/reasoning-icon"
4548import { ModelSelectorPopover } from "@/components/dialog-select-model"
4649import { DialogSelectModelUnpaid } from "@/components/dialog-select-model-unpaid"
4750import { useProviders } from "@/hooks/use-providers"
@@ -922,7 +925,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
922925 . abort ( {
923926 sessionID,
924927 } )
925- . catch ( ( ) => { } )
928+ . catch ( ( ) => { } )
926929 }
927930
928931 const addToHistory = ( prompt : Prompt , mode : "normal" | "shell" ) => {
@@ -1348,18 +1351,18 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
13481351
13491352 const contextParts : Array <
13501353 | {
1351- id : string
1352- type : "text"
1353- text : string
1354- synthetic ?: boolean
1355- }
1354+ id : string
1355+ type : "text"
1356+ text : string
1357+ synthetic ?: boolean
1358+ }
13561359 | {
1357- id : string
1358- type : "file"
1359- mime : string
1360- url : string
1361- filename ?: string
1362- }
1360+ id : string
1361+ type : "file"
1362+ mime : string
1363+ url : string
1364+ filename ?: string
1365+ }
13631366 > = [ ]
13641367
13651368 const commentNote = ( path : string , selection : FileSelection | undefined , comment : string ) => {
@@ -1431,13 +1434,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
14311434
14321435 const optimisticParts = requestParts . map ( ( part ) => ( {
14331436 ...part ,
1434- sessionID : session . id ,
1437+ sessionID : session ? .id || '' ,
14351438 messageID,
14361439 } ) ) as unknown as Part [ ]
14371440
14381441 const optimisticMessage : Message = {
14391442 id : messageID ,
1440- sessionID : session . id ,
1443+ sessionID : session ? .id || '' ,
14411444 role : "user" ,
14421445 time : { created : Date . now ( ) } ,
14431446 agent,
@@ -1448,9 +1451,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
14481451 if ( sessionDirectory === projectDirectory ) {
14491452 sync . set (
14501453 produce ( ( draft ) => {
1451- const messages = draft . message [ session . id ]
1454+ const messages = draft . message [ session ? .id || '' ]
14521455 if ( ! messages ) {
1453- draft . message [ session . id ] = [ optimisticMessage ]
1456+ draft . message [ session ? .id || '' ] = [ optimisticMessage ]
14541457 } else {
14551458 const result = Binary . search ( messages , messageID , ( m ) => m . id )
14561459 messages . splice ( result . index , 0 , optimisticMessage )
@@ -1466,9 +1469,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
14661469
14671470 globalSync . child ( sessionDirectory ) [ 1 ] (
14681471 produce ( ( draft ) => {
1469- const messages = draft . message [ session . id ]
1472+ const messages = draft . message [ session ? .id || '' ]
14701473 if ( ! messages ) {
1471- draft . message [ session . id ] = [ optimisticMessage ]
1474+ draft . message [ session ? .id || '' ] = [ optimisticMessage ]
14721475 } else {
14731476 const result = Binary . search ( messages , messageID , ( m ) => m . id )
14741477 messages . splice ( result . index , 0 , optimisticMessage )
@@ -1485,7 +1488,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
14851488 if ( sessionDirectory === projectDirectory ) {
14861489 sync . set (
14871490 produce ( ( draft ) => {
1488- const messages = draft . message [ session . id ]
1491+ const messages = draft . message [ session ? .id || '' ]
14891492 if ( messages ) {
14901493 const result = Binary . search ( messages , messageID , ( m ) => m . id )
14911494 if ( result . found ) messages . splice ( result . index , 1 )
@@ -1498,7 +1501,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
14981501
14991502 globalSync . child ( sessionDirectory ) [ 1 ] (
15001503 produce ( ( draft ) => {
1501- const messages = draft . message [ session . id ]
1504+ const messages = draft . message [ session ? .id || '' ]
15021505 if ( messages ) {
15031506 const result = Binary . search ( messages , messageID , ( m ) => m . id )
15041507 if ( result . found ) messages . splice ( result . index , 1 )
@@ -1519,15 +1522,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
15191522 const worktree = WorktreeState . get ( sessionDirectory )
15201523 if ( ! worktree || worktree . status !== "pending" ) return true
15211524
1522- if ( sessionDirectory === projectDirectory ) {
1523- sync . set ( "session_status" , session . id , { type : "busy" } )
1525+ if ( sessionDirectory === projectDirectory && session ?. id ) {
1526+ sync . set ( "session_status" , session ? .id , { type : "busy" } )
15241527 }
15251528
15261529 const controller = new AbortController ( )
15271530
15281531 const cleanup = ( ) => {
1529- if ( sessionDirectory === projectDirectory ) {
1530- sync . set ( "session_status" , session . id , { type : "idle" } )
1532+ if ( sessionDirectory === projectDirectory && session ?. id ) {
1533+ sync . set ( "session_status" , session ? .id , { type : "idle" } )
15311534 }
15321535 removeOptimisticMessage ( )
15331536 for ( const item of commentItems ) {
@@ -1544,7 +1547,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
15441547 restoreInput ( )
15451548 }
15461549
1547- pending . set ( session . id , { abort : controller , cleanup } )
1550+ pending . set ( session ? .id || '' , { abort : controller , cleanup } )
15481551
15491552 const abort = new Promise < Awaited < ReturnType < typeof WorktreeState . wait > > > ( ( resolve ) => {
15501553 if ( controller . signal . aborted ) {
@@ -1572,7 +1575,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
15721575 if ( timer . id === undefined ) return
15731576 clearTimeout ( timer . id )
15741577 } )
1575- pending . delete ( session . id )
1578+ pending . delete ( session ? .id || '' )
15761579 if ( controller . signal . aborted ) return false
15771580 if ( result . status === "failed" ) throw new Error ( result . message )
15781581 return true
@@ -1582,7 +1585,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
15821585 const ok = await waitForWorktree ( )
15831586 if ( ! ok ) return
15841587 await client . session . prompt ( {
1585- sessionID : session . id ,
1588+ sessionID : session ? .id || '' ,
15861589 agent,
15871590 model,
15881591 messageID,
@@ -1592,9 +1595,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
15921595 }
15931596
15941597 void send ( ) . catch ( ( err ) => {
1595- pending . delete ( session . id )
1596- if ( sessionDirectory === projectDirectory ) {
1597- sync . set ( "session_status" , session . id , { type : "idle" } )
1598+ pending . delete ( session ? .id || '' )
1599+ if ( sessionDirectory === projectDirectory && session ?. id ) {
1600+ sync . set ( "session_status" , session ? .id , { type : "idle" } )
15981601 }
15991602 showToast ( {
16001603 title : language . t ( "prompt.toast.promptSendFailed.title" ) ,
@@ -1616,6 +1619,24 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
16161619 } )
16171620 }
16181621
1622+ const currrentModelVariant = createMemo ( ( ) => {
1623+ const modelVariant = local . model . variant . current ( ) ?? ''
1624+ return modelVariant === 'xhigh' ? 'xHigh' : ( modelVariant . length > 0 ? modelVariant [ 0 ] . toUpperCase ( ) + modelVariant . slice ( 1 ) : 'Default' )
1625+ } )
1626+
1627+ const reasoningPercentage = createMemo ( ( ) => {
1628+ const variants = local . model . variant . list ( )
1629+ const current = local . model . variant . current ( )
1630+ const totalEntries = variants . length + 1
1631+
1632+ if ( totalEntries <= 2 || current === 'Default' ) {
1633+ return 0
1634+ }
1635+
1636+ const currentIndex = current ? variants . indexOf ( current ) + 1 : 0
1637+ return ( ( currentIndex + 1 ) / totalEntries ) * 100
1638+ } , [ local . model . variant ] )
1639+
16191640 return (
16201641 < div class = "relative size-full _max-h-[320px] flex flex-col gap-3" >
16211642 < Show when = { store . popover } >
@@ -1668,7 +1689,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
16681689 </ >
16691690 }
16701691 >
1671- < Icon name = "brain" size = "small " class = "text-icon-info-active shrink-0" />
1692+ < Icon name = "brain" size = "normal " class = "text-icon-info-active shrink-0" />
16721693 < span class = "text-14-regular text-text-strong whitespace-nowrap" >
16731694 @{ ( item as { type : "agent" ; name : string } ) . name }
16741695 </ span >
@@ -1891,7 +1912,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
18911912 </ Show >
18921913 </ div >
18931914 < div class = "relative p-3 flex items-center justify-between" >
1894- < div class = "flex items-center justify-start gap-0.5 " >
1915+ < div class = "flex items-center justify-start gap-1 " >
18951916 < Switch >
18961917 < Match when = { store . mode === "shell" } >
18971918 < div class = "flex items-center gap-2 px-2 h-6" >
@@ -1922,12 +1943,12 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
19221943 title = { language . t ( "command.model.choose" ) }
19231944 keybind = { command . keybind ( "model.choose" ) }
19241945 >
1925- < Button as = "div" variant = "ghost" onClick = { ( ) => dialog . show ( ( ) => < DialogSelectModelUnpaid /> ) } >
1946+ < Button as = "div" variant = "ghost" onClick = { ( ) => dialog . render ( < DialogSelectModelUnpaid /> , "select-model" ) } >
19261947 < Show when = { local . model . current ( ) ?. provider ?. id } >
19271948 < ProviderIcon id = { local . model . current ( ) ! . provider . id as IconName } class = "size-4 shrink-0" />
19281949 </ Show >
19291950 { local . model . current ( ) ?. name ?? language . t ( "dialog.model.select.title" ) }
1930- < Icon name = "chevron-down" size = "small" />
1951+ < MorphChevron expanded = { dialog . isActive ( "select-model" ) } />
19311952 </ Button >
19321953 </ TooltipKeybind >
19331954 }
@@ -1938,11 +1959,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
19381959 keybind = { command . keybind ( "model.choose" ) }
19391960 >
19401961 < ModelSelectorPopover triggerAs = { Button } triggerProps = { { variant : "ghost" } } >
1941- < Show when = { local . model . current ( ) ?. provider ?. id } >
1942- < ProviderIcon id = { local . model . current ( ) ! . provider . id as IconName } class = "size-4 shrink-0" />
1943- </ Show >
1944- { local . model . current ( ) ?. name ?? language . t ( "dialog.model.select.title" ) }
1945- < Icon name = "chevron-down" size = "small" />
1962+ { ( open ) => (
1963+ < >
1964+ < Show when = { local . model . current ( ) ?. provider ?. id } >
1965+ < ProviderIcon id = { local . model . current ( ) ! . provider . id as IconName } class = "size-4 shrink-0" />
1966+ </ Show >
1967+ { local . model . current ( ) ?. name ?? language . t ( "dialog.model.select.title" ) }
1968+ < MorphChevron expanded = { open } class = "text-text-weak" />
1969+ </ >
1970+ ) }
19461971 </ ModelSelectorPopover >
19471972 </ TooltipKeybind >
19481973 </ Show >
@@ -1954,10 +1979,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
19541979 >
19551980 < Button
19561981 variant = "ghost"
1957- class = "text-text-base _hidden group-hover/prompt-input:inline-block capitalize text-12-regular"
1982+ class = "text-text-strong text-12-regular"
19581983 onClick = { ( ) => local . model . variant . cycle ( ) }
19591984 >
1960- { local . model . variant . current ( ) ?? language . t ( "common.default" ) }
1985+ < Show when = { local . model . variant . list ( ) . length > 1 } >
1986+ < ReasoningIcon percentage = { reasoningPercentage ( ) } size = { 16 } strokeWidth = { 1.25 } />
1987+ </ Show >
1988+ < CycleLabel value = { currrentModelVariant ( ) } />
19611989 </ Button >
19621990 </ TooltipKeybind >
19631991 </ Show >
@@ -1971,7 +1999,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
19711999 variant = "ghost"
19722000 onClick = { ( ) => permission . toggleAutoAccept ( params . id ! , sdk . directory ) }
19732001 classList = { {
1974- "_hidden group-hover/prompt-input:flex size-6 items-center justify-center" : true ,
2002+ "_hidden group-hover/prompt-input:flex items-center justify-center" : true ,
19752003 "text-text-base" : ! permission . isAutoAccepting ( params . id ! , sdk . directory ) ,
19762004 "hover:bg-surface-success-base" : permission . isAutoAccepting ( params . id ! , sdk . directory ) ,
19772005 } }
@@ -1993,7 +2021,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
19932021 </ Match >
19942022 </ Switch >
19952023 </ div >
1996- < div class = "flex items-center gap-3 absolute right-3 bottom-3" >
2024+ < div class = "flex items-center gap-2 absolute right-3 bottom-3" >
19972025 < input
19982026 ref = { fileInputRef }
19992027 type = "file"
@@ -2016,7 +2044,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
20162044 onClick = { ( ) => fileInputRef . click ( ) }
20172045 aria-label = { language . t ( "prompt.action.attachFile" ) }
20182046 >
2019- < Icon name = "photo" class = "size-4.5" />
2047+ < Icon name = "photo" class = "size-4.5 text-icon-base " />
20202048 </ Button >
20212049 </ Tooltip >
20222050 </ Show >
@@ -2035,7 +2063,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
20352063 < Match when = { true } >
20362064 < div class = "flex items-center gap-2" >
20372065 < span > { language . t ( "prompt.action.send" ) } </ span >
2038- < Icon name = "enter" size = "small " class = "text-icon-base" />
2066+ < Icon name = "enter" size = "normal " class = "text-icon-base" />
20392067 </ div >
20402068 </ Match >
20412069 </ Switch >
@@ -2046,7 +2074,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
20462074 disabled = { ! prompt . dirty ( ) && ! working ( ) }
20472075 icon = { working ( ) ? "stop" : "arrow-up" }
20482076 variant = "primary"
2049- class = "h-6 w-4. 5"
2077+ class = "h-6 w-5"
20502078 aria-label = { working ( ) ? language . t ( "prompt.action.stop" ) : language . t ( "prompt.action.send" ) }
20512079 />
20522080 </ Tooltip >
0 commit comments