Skip to content

Commit

Permalink
add model selection + misc UI improvements (notably, change how model…
Browse files Browse the repository at this point in the history
… dropdown works)
  • Loading branch information
andrewpareles committed Jan 30, 2025
1 parent 27d0093 commit d9cf214
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 210 deletions.
60 changes: 60 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
},
"dependencies": {
"@anthropic-ai/sdk": "^0.32.1",
"@floating-ui/react": "^0.27.3",
"@google/generative-ai": "^0.21.0",
"@microsoft/1ds-core-js": "^3.2.13",
"@microsoft/1ds-post-js": "^3.2.13",
Expand Down
7 changes: 6 additions & 1 deletion src/vs/platform/void/common/voidSettingsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ let _computeModelOptions = (settingsOfProvider: SettingsOfProvider) => {
const defaultState = () => {
const d: VoidSettingsState = {
settingsOfProvider: deepClone(defaultSettingsOfProvider),
modelSelectionOfFeature: { 'Ctrl+L': null, 'Ctrl+K': null, 'Autocomplete': null },
modelSelectionOfFeature: { 'Ctrl+L': null, 'Ctrl+K': null, 'Autocomplete': null, 'FastApply': null },
globalSettings: deepClone(defaultGlobalSettings),
_modelOptions: _computeModelOptions(defaultSettingsOfProvider), // computed
}
Expand Down Expand Up @@ -137,6 +137,11 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
...defaultSettingsOfProvider.gemini.models.filter(m => /* if cant find the model in readS (yes this is O(n^2), very small) */ !readS.settingsOfProvider.gemini.models.find(m2 => m2.modelName === m.modelName))
]
}
},
modelSelectionOfFeature: {
// A HACK BECAUSE WE ADDED FastApply
...{ 'FastApply': null },
...readS.modelSelectionOfFeature,
}
}

Expand Down
20 changes: 14 additions & 6 deletions src/vs/platform/void/common/voidSettingsTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,14 +432,22 @@ export const modelSelectionsEqual = (m1: ModelSelection, m2: ModelSelection) =>
}

// this is a state
export type ModelSelectionOfFeature = {
'Ctrl+L': ModelSelection | null,
'Ctrl+K': ModelSelection | null,
'Autocomplete': ModelSelection | null,
}
export const featureNames = ['Ctrl+L', 'Ctrl+K', 'Autocomplete', 'FastApply'] as const
export type ModelSelectionOfFeature = Record<(typeof featureNames)[number], ModelSelection | null>
export type FeatureName = keyof ModelSelectionOfFeature
export const featureNames = ['Ctrl+L', 'Ctrl+K', 'Autocomplete'] as const

export const displayInfoOfFeatureName = (featureName: FeatureName) => {
if (featureName === 'Autocomplete')
return 'Autocomplete'
else if (featureName === 'Ctrl+K')
return 'Quick Edit'
else if (featureName === 'Ctrl+L')
return 'Sidebar Chat'
else if (featureName === 'FastApply')
return 'Fast Apply'
else
throw new Error(`Feature Name ${featureName} not allowed`)
}



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ export const BlockCode = ({ buttonsOnHover, ...codeEditorProps }: { buttonsOnHov

return (
<>
<div className="relative group w-full overflow-hidden">
<div className="relative group w-full overflow-hidden my-4">
{buttonsOnHover === null ? null : (
<div className={`z-[1] absolute top-0 right-0 opacity-0 group-hover:opacity-100 duration-200 ${isSingleLine ? 'h-full flex items-center' : ''
}`}>
<div className={`z-[1] absolute top-0 right-0 opacity-0 group-hover:opacity-100 duration-200 ${isSingleLine ? 'h-full flex items-center' : ''}`}>
<div className={`flex space-x-1 ${isSingleLine ? 'pr-2' : 'p-2'}`}>
{buttonsOnHover}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,15 +436,15 @@ const ChatBubble_ = ({ isEditMode, isLoading, children, role }: { role: ChatMess
className={`
relative
${isEditMode ? 'px-2 w-full max-w-full'
: role === 'user' ? `px-2 self-end w-fit max-w-full`
: role === 'user' ? `px-2 self-end w-fit max-w-full whitespace-pre-wrap` // user words should be pre
: role === 'assistant' ? `px-2 self-start w-full max-w-full` : ''
}
`}
>
<div
// style chatbubble according to role
className={`
text-left space-y-2 rounded-lg
text-left rounded-lg
overflow-x-auto max-w-full
${role === 'user' ? 'p-2 bg-void-bg-1 text-void-fg-1' : 'px-2'}
`}
Expand Down Expand Up @@ -603,129 +603,129 @@ export const SidebarChat = () => {
)
}, [previousMessages])

return <div
ref={sidebarRef}
className={`w-full h-full`}

const threadSelector = <div ref={historyRef}
className={`w-full h-auto ${isHistoryOpen ? '' : 'hidden'} ring-2 ring-widget-shadow ring-inset z-10`}
>
{/* thread selector */}
<div ref={historyRef}
className={`w-full h-auto ${isHistoryOpen ? '' : 'hidden'} ring-2 ring-widget-shadow ring-inset z-10`}
>
<SidebarThreadSelector />
</div>
<SidebarThreadSelector />
</div>

{/* previous messages + current stream */}
<ScrollToBottomContainer
scrollContainerRef={scrollContainerRef}
className={`
w-full h-auto
flex flex-col
overflow-x-hidden
overflow-y-auto
gap-4
`}
style={{ maxHeight: sidebarDimensions.height - historyDimensions.height - formDimensions.height - 36 }} // the height of the previousMessages is determined by all other heights
>
{/* previous messages */}
{prevMessagesHTML}

{/* message stream */}
<ChatBubble chatMessage={{ role: 'assistant', content: messageSoFar ?? '', displayContent: messageSoFar || null }} isLoading={isStreaming} />
const messagesHTML = <ScrollToBottomContainer
scrollContainerRef={scrollContainerRef}
className={`
w-full h-auto
flex flex-col
overflow-x-hidden
overflow-y-auto
py-4
`}
style={{ maxHeight: sidebarDimensions.height - historyDimensions.height - formDimensions.height - 36 }} // the height of the previousMessages is determined by all other heights
>
{/* previous messages */}
{prevMessagesHTML}

{/* message stream */}
<ChatBubble chatMessage={{ role: 'assistant', content: messageSoFar ?? '', displayContent: messageSoFar || null }} isLoading={isStreaming} />

{/* error message */}
{latestError === undefined ? null :
<div className='px-2'>
<ErrorDisplay
message={latestError.message}
fullError={latestError.fullError}
onDismiss={() => { chatThreadsService.dismissStreamError(currentThread.id) }}
showDismiss={true}
/>

<WarningBox className='text-sm my-2 pl-4' onClick={() => { commandService.executeCommand(VOID_OPEN_SETTINGS_ACTION_ID) }} text='Open settings' />
</div>
}
{/* error message */}
{latestError === undefined ? null :
<div className='px-2'>
<ErrorDisplay
message={latestError.message}
fullError={latestError.fullError}
onDismiss={() => { chatThreadsService.dismissStreamError(currentThread.id) }}
showDismiss={true}
/>

</ScrollToBottomContainer>
<WarningBox className='text-sm my-2 pl-4' onClick={() => { commandService.executeCommand(VOID_OPEN_SETTINGS_ACTION_ID) }} text='Open settings' />
</div>
}
</ScrollToBottomContainer>


{/* input box */}
<div // this div is used to position the input box properly
className={`right-0 left-0 m-2 z-[999] overflow-hidden ${previousMessages.length > 0 ? 'absolute bottom-0' : ''}`}
const inputBox = <div // this div is used to position the input box properly
className={`right-0 left-0 m-2 z-[999] overflow-hidden ${previousMessages.length > 0 ? 'absolute bottom-0' : ''}`}
>
<div
ref={formRef}
className={`
flex flex-col gap-1 p-2 relative input text-left shrink-0
transition-all duration-200
rounded-md
bg-vscode-input-bg
max-h-[80vh] overflow-y-auto
border border-void-border-3 focus-within:border-void-border-1 hover:border-void-border-1
`}
onClick={(e) => {
textAreaRef.current?.focus()
}}
>
{/* top row */}
<>
{/* selections */}
<SelectedFiles type='staging' selections={selections || []} setSelections={chatThreadsService.setStaging.bind(chatThreadsService)} showProspectiveSelections={previousMessages.length === 0} />
</>

{/* middle row */}
<div>

{/* text input */}
<VoidInputBox2
className='min-h-[81px] p-1'
placeholder={`${keybindingString ? `${keybindingString} to select. ` : ''}Enter instructions...`}
onChangeText={useCallback((newStr: string) => { setInstructionsAreEmpty(!newStr) }, [setInstructionsAreEmpty])}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
onSubmit()
}
}}
ref={textAreaRef}
fnsRef={textAreaFnsRef}
multiline={true}
/>
</div>

{/* bottom row */}
<div
ref={formRef}
className={`
flex flex-col gap-1 p-2 relative input text-left shrink-0
transition-all duration-200
rounded-md
bg-vscode-input-bg
max-h-[80vh] overflow-y-auto
border border-void-border-3 focus-within:border-void-border-1 hover:border-void-border-1
`}
onClick={(e) => {
textAreaRef.current?.focus()
}}
className='flex flex-row justify-between items-end gap-1'
>
{/* top row */}
<>
{/* selections */}
<SelectedFiles type='staging' selections={selections || []} setSelections={chatThreadsService.setStaging.bind(chatThreadsService)} showProspectiveSelections={previousMessages.length === 0} />
</>

{/* middle row */}
<div>

{/* text input */}
<VoidInputBox2
className='min-h-[81px] p-1'
placeholder={`${keybindingString ? `${keybindingString} to select. ` : ''}Enter instructions...`}
onChangeText={useCallback((newStr: string) => { setInstructionsAreEmpty(!newStr) }, [setInstructionsAreEmpty])}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
onSubmit()
}
}}
ref={textAreaRef}
fnsRef={textAreaFnsRef}
multiline={true}
/>
{/* submit options */}
<div className='max-w-[150px]
@@[&_select]:!void-border-none
@@[&_select]:!void-outline-none
flex-grow
'
>
<ModelDropdown featureName='Ctrl+L' />
</div>

{/* bottom row */}
<div
className='flex flex-row justify-between items-end gap-1'
>
{/* submit options */}
<div className='max-w-[150px]
@@[&_select]:!void-border-none
@@[&_select]:!void-outline-none
flex-grow
'
>
<ModelDropdown featureName='Ctrl+L' />
</div>
{/* submit / stop button */}
{isStreaming ?
// stop button
<ButtonStop
onClick={onAbort}
/>
:
// submit button (up arrow)
<ButtonSubmit
onClick={onSubmit}
disabled={isDisabled}
/>
}
</div>
</div>
</div>

{/* submit / stop button */}
{isStreaming ?
// stop button
<ButtonStop
onClick={onAbort}
/>
:
// submit button (up arrow)
<ButtonSubmit
onClick={onSubmit}
disabled={isDisabled}
/>
}
</div>
return <div ref={sidebarRef} className={`w-full h-full`}>
{threadSelector}

{messagesHTML}

</div>
</div >
</div >
{inputBox}

</div>
}


Loading

0 comments on commit d9cf214

Please sign in to comment.