onboarding draft and lots of misc changes

This commit is contained in:
Mathew Pareles 2025-04-07 16:11:07 -07:00
parent 4b4dde71b3
commit 8e2e8c58c9
17 changed files with 1434 additions and 437 deletions

View file

@ -1599,7 +1599,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
const modelSelection = this._settingsService.state.modelSelectionOfFeature[featureName]
const modelSelectionOptions = modelSelection ? this._settingsService.state.optionsOfModelSelection[featureName][modelSelection.providerName]?.[modelSelection.modelName] : undefined
const N_RETRIES = 5
const N_RETRIES = 2
// allowed to throw errors - this is called inside a promise that handles everything
const runSearchReplace = async () => {

View file

@ -76,93 +76,108 @@
opacity: 80%;
}
/* styles for all containers used by void */
.void-scope {
background-color: var(--vscode-editor-background);
--scrollbar-vertical-width: 8px;
--scrollbar-horizontal-height: 6px;
}
/* Target both void-scope and all its descendants with scrollbars */
.void-scope,
.void-scope * {
scrollbar-width: thin !important;
scrollbar-color: var(--void-bg-1) var(--void-bg-3) !important; /* For Firefox */
}
.void-scope::-webkit-scrollbar,
.void-scope *::-webkit-scrollbar {
width: var(--scrollbar-vertical-width) !important;
height: var(--scrollbar-horizontal-height) !important;
background-color: var(--void-bg-3) !important;
}
.void-scope::-webkit-scrollbar-thumb,
.void-scope *::-webkit-scrollbar-thumb {
background-color: var(--void-bg-1) !important;
border-radius: 4px !important;
border: none !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
}
.void-scope::-webkit-scrollbar-thumb:hover,
.void-scope *::-webkit-scrollbar-thumb:hover {
background-color: var(--void-bg-1) !important;
filter: brightness(1.1) !important;
}
.void-scope::-webkit-scrollbar-thumb:active,
.void-scope *::-webkit-scrollbar-thumb:active {
background-color: var(--void-bg-1) !important;
filter: brightness(1.2) !important;
}
.void-scope::-webkit-scrollbar-track,
.void-scope *::-webkit-scrollbar-track {
background-color: var(--void-bg-3) !important;
border: none !important;
}
.void-scope::-webkit-scrollbar-corner,
.void-scope *::-webkit-scrollbar-corner {
background-color: var(--void-bg-3) !important;
}
/* Add void-scrollable-element styles to match */
.void-scrollable-element {
background-color: var(--vscode-editor-background);
--scrollbar-vertical-width: 14px;
--scrollbar-horizontal-height: 6px;
overflow: auto; /* Ensure scrollbars are shown when needed */
}
.void-scrollable-element,
.void-scrollable-element * {
scrollbar-width: thin !important; /* For Firefox */
scrollbar-color: var(--void-bg-1) var(--void-bg-3) !important; /* For Firefox */
}
.void-scrollable-element::-webkit-scrollbar,
.void-scrollable-element *::-webkit-scrollbar {
width: 14px !important;
height: 4px !important;
}
.void-scrollable-element::-webkit-scrollbar-track,
.void-scrollable-element *::-webkit-scrollbar-track {
background: transparent !important;
width: var(--scrollbar-vertical-width) !important;
height: var(--scrollbar-horizontal-height) !important;
background-color: var(--void-bg-3) !important;
}
.void-scrollable-element::-webkit-scrollbar-thumb,
.void-scrollable-element *::-webkit-scrollbar-thumb {
background-color: transparent !important;
border-radius: 0px !important;
background-color: var(--void-bg-1) !important;
border-radius: 4px !important;
border: none !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
}
.void-scrollable-element::-webkit-scrollbar-thumb:hover,
.void-scrollable-element *::-webkit-scrollbar-thumb:hover {
background-color: var(--vscode-scrollbarSlider-hoverBackground) !important;
background-color: var(--void-bg-1) !important;
filter: brightness(1.1) !important;
}
.void-scrollable-element::-webkit-scrollbar-thumb:active,
.void-scrollable-element *::-webkit-scrollbar-thumb:active {
background-color: var(--vscode-scrollbarSlider-activeBackground) !important;
background-color: var(--void-bg-1) !important;
filter: brightness(1.2) !important;
}
.void-scrollable-element::-webkit-scrollbar-track,
.void-scrollable-element *::-webkit-scrollbar-track {
background-color: var(--void-bg-3) !important;
border: none !important;
}
.void-scrollable-element::-webkit-scrollbar-corner,
.void-scrollable-element *::-webkit-scrollbar-corner {
background-color: transparent !important;
}
.void-scrollable-element.show-scrollbar-0::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-0 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 0%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-1::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-1 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 10%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-2::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-2 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 20%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-3::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-3 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 30%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-4::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-4 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 40%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-5::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-5 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 50%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-6::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-6 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 60%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-7::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-7 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 70%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-8::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-8 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 80%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-9::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-9 *::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--vscode-scrollbarSlider-background) 90%, transparent) !important;
}
.void-scrollable-element.show-scrollbar-10::-webkit-scrollbar-thumb,
.void-scrollable-element.show-scrollbar-10 *::-webkit-scrollbar-thumb {
background-color: var(--vscode-scrollbarSlider-background) !important;
background-color: var(--void-bg-3) !important;
}

View file

@ -20,19 +20,16 @@ enum CopyButtonText {
type IconButtonProps = {
onClick: () => void;
Icon: LucideIcon
disabled?: boolean
className?: string
}
export const IconShell1 = ({ onClick, Icon, disabled, className }: IconButtonProps) => (
export const IconShell1 = ({ onClick, Icon, disabled, className, ...props }: IconButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>) => (
<button
disabled={disabled}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onClick?.();
onClick?.(e);
}}
className={`
size-[22px]
@ -44,6 +41,7 @@ export const IconShell1 = ({ onClick, Icon, disabled, className }: IconButtonPro
disabled:opacity-50 disabled:cursor-not-allowed
${className}
`}
{...props}
>
<Icon />
</button>
@ -163,10 +161,11 @@ export const useApplyButtonState = ({ applyBoxId, uri }: { applyBoxId: string, u
rerender(c => c + 1)
console.log('rerendering....')
}
}, [applyBoxId, applyBoxId, uri]))
}, [applyBoxId, uri]))
const currStreamState = getStreamState()
return {
getStreamState,
isDisabled,
@ -192,7 +191,8 @@ export const StatusIndicator = ({ color, title, className }: { color: 'green' |
);
};
export const StatusIndicatorHTML = ({ applyBoxId, uri }: { applyBoxId: string, uri: URI | 'current' }) => {
export const StatusIndicatorForApplyButton = ({ applyBoxId, uri }: { applyBoxId: string, uri: URI | 'current' }) => {
const { currStreamState } = useApplyButtonState({ applyBoxId, uri })
const color = (
@ -329,7 +329,7 @@ export const BlockCodeApplyWrapper = ({
{/* header */}
<div className=" select-none flex justify-between items-center py-1 px-2 border-b border-void-border-3 cursor-default">
<div className="flex items-center">
<StatusIndicatorHTML uri={uri} applyBoxId={applyBoxId} />
<StatusIndicatorForApplyButton uri={uri} applyBoxId={applyBoxId} />
<span className="text-[13px] font-light text-void-fg-3">
{name}
</span>

View file

@ -10,7 +10,6 @@ import { QuickEditPropsType } from '../../../quickEditActions.js';
import { ButtonStop, ButtonSubmit, IconX, VoidChatArea } from '../sidebar-tsx/SidebarChat.js';
import { VOID_CTRL_K_ACTION_ID } from '../../../actionIDs.js';
import { useRefState } from '../util/helpers.js';
import { useScrollbarStyles } from '../util/useScrollbarStyles.js';
import { isFeatureNameDisabled } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js';
export const QuickEditChat = ({
@ -89,8 +88,6 @@ export const QuickEditChat = ({
editCodeService.removeCtrlKZone({ diffareaid })
}, [editCodeService, diffareaid])
useScrollbarStyles(sizerRef)
const keybindingString = accessor.get('IKeybindingService').lookupKeybinding(VOID_CTRL_K_ACTION_ID)?.getLabel()
const chatAreaRef = useRef<HTMLDivElement | null>(null)

View file

@ -15,7 +15,6 @@ import { ErrorDisplay } from './ErrorDisplay.js';
import { BlockCode, TextAreaFns, VoidCustomDropdownBox, VoidInputBox2, VoidSlider, VoidSwitch } from '../util/inputs.js';
import { ModelDropdown, } from '../void-settings-tsx/ModelDropdown.js';
import { SidebarThreadSelector } from './SidebarThreadSelector.js';
import { useScrollbarStyles } from '../util/useScrollbarStyles.js';
import { VOID_CTRL_L_ACTION_ID } from '../../../actionIDs.js';
import { VOID_OPEN_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js';
import { ChatMode, FeatureName, isFeatureNameDisabled } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js';
@ -1027,6 +1026,7 @@ const SmallProseWrapper = ({ children }: { children: React.ReactNode }) => {
prose-blockquote:pl-2
prose-blockquote:my-2
prose-code:text-void-fg-3
prose-code:text-[12px]
prose-code:before:content-none
prose-code:after:content-none
@ -1294,7 +1294,7 @@ export const ToolChildrenWrapper = ({ children, className }: { children: React.R
</div>
}
export const CodeChildren = ({ children }: { children: React.ReactNode }) => {
return <div className='bg-void-bg-3 p-1 rounded-sm font-mono overflow-auto text-sm'>
return <div className='bg-void-bg-3 p-1 rounded-sm overflow-auto text-sm'>
<div className='!select-text cursor-auto'>
{children}
</div>
@ -1328,6 +1328,8 @@ const EditToolChildren = ({ uri, changeDescription }: { uri: URI, changeDescript
const EditToolHeaderButtons = ({ applyBoxId, uri, codeStr }: { applyBoxId: string, uri: URI, codeStr: string }) => {
const { currStreamState } = useApplyButtonState({ applyBoxId, uri })
return <div className='flex items-center gap-1'>
<StatusIndicatorForApplyButton applyBoxId={applyBoxId} uri={uri} />
<JumpToFileButton uri={uri} />
{currStreamState === 'idle-no-changes' && <CopyButton codeStr={codeStr} />}
@ -1767,18 +1769,18 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper<T>,
resolveReason.type === 'toofull' ? `\n(truncated)`
: null
componentParams.children = <ToolChildrenWrapper className='font-mono whitespace-pre text-nowrap overflow-auto text-sm'>
componentParams.children = <ToolChildrenWrapper className='whitespace-pre text-nowrap overflow-auto text-sm'>
<div className='!select-text cursor-auto'>
<div>
<span>{`Ran command: `}</span>
<span className="text-void-fg-1">{command}</span>
<span className="text-void-fg-1 font-sans">{`Ran command: `}</span>
<span className="font-mono">{command}</span>
</div>
<div>
<span>{resolveReason.type === 'bgtask' ? 'Result so far:\n' : null}</span>
<span>{`Result: `}</span>
<span className="text-void-fg-1">{terminalResult}</span>
<span className="text-void-fg-1">{additionalDetailsStr}</span>
<span className="text-void-fg-1 font-mono">{terminalResult}</span>
<span className="text-void-fg-1 font-mono">{additionalDetailsStr}</span>
</div>
</div>
</ToolChildrenWrapper>
@ -2150,7 +2152,7 @@ const CommandBarInChat = () => {
<svg
className="transition-transform duration-200 size-3.5"
style={{
transform: isFileDetailsOpened ? 'rotate(180deg)' : 'rotate(0deg)',
transform: isFileDetailsOpened ? 'rotate(0deg)' : 'rotate(180deg)',
transition: 'transform 0.2s cubic-bezier(0.25, 0.1, 0.25, 1)'
}}
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="18 15 12 9 6 15"></polyline>
@ -2254,8 +2256,6 @@ export const SidebarChat = () => {
const sidebarRef = useRef<HTMLDivElement>(null)
const scrollContainerRef = useRef<HTMLDivElement | null>(null)
useScrollbarStyles(sidebarRef)
const onSubmit = useCallback(async () => {
if (isDisabled) return

View file

@ -153,12 +153,13 @@ export const VoidInputBox2 = forwardRef<HTMLTextAreaElement, InputBox2Props>(fun
})
export const VoidSimpleInputBox = ({ value, onChangeValue, placeholder, className, disabled, passwordBlur, ...inputProps }: {
export const VoidSimpleInputBox = ({ value, onChangeValue, placeholder, className, disabled, passwordBlur, compact, ...inputProps }: {
value: string;
onChangeValue: (value: string) => void;
placeholder: string;
className?: string;
disabled?: boolean;
compact?: boolean;
passwordBlur?: boolean;
} & React.InputHTMLAttributes<HTMLInputElement>) => {
@ -168,7 +169,11 @@ export const VoidSimpleInputBox = ({ value, onChangeValue, placeholder, classNam
onChange={(e) => onChangeValue(e.target.value)}
placeholder={placeholder}
disabled={disabled}
className={`w-full resize-none text-void-fg-1 placeholder:text-void-fg-3 px-2 py-1 rounded-sm
// className='max-w-44 w-full border border-void-border-2 bg-void-bg-1 text-void-fg-3 text-root'
// className={`w-full resize-none text-void-fg-1 placeholder:text-void-fg-3 px-2 py-1 rounded-sm
className={`w-full resize-none bg-void-bg-1 text-void-fg-1 placeholder:text-void-fg-3 border border-void-border-2 focus:border-void-border-1
${compact ? 'py-1 px-2' : 'py-2 px-4 '}
rounded
${disabled ? 'opacity-50 cursor-not-allowed' : ''}
${className}`}
style={{
@ -954,9 +959,9 @@ export const BlockCode = ({ initValue, language, maxHeight, showScrollbars }: Bl
}
export const VoidButton = ({ children, disabled, onClick }: { children: React.ReactNode; disabled?: boolean; onClick: () => void }) => {
export const VoidButtonBgDarken = ({ children, disabled, onClick }: { children: React.ReactNode; disabled?: boolean; onClick: () => void }) => {
return <button disabled={disabled}
className='px-3 py-1 bg-black/10 dark:bg-white/10 rounded-sm overflow-hidden whitespace-nowrap'
className='px-3 py-1 bg-black/10 dark:bg-white/10 rounded-sm overflow-hidden whitespace-nowrap flex items-center justify-center'
onClick={onClick}
>{children}</button>
}

View file

@ -1,128 +1,130 @@
import { useEffect } from 'react';
// Get rid of this as it was causing lag
export const useScrollbarStyles = (containerRef: React.MutableRefObject<HTMLDivElement | null>) => {
useEffect(() => {
if (!containerRef.current) return;
// import { useEffect } from 'react';
// Create selector for specific overflow classes
const overflowSelector = [
'[class*="overflow-auto"]',
'[class*="overflow-x-auto"]',
'[class*="overflow-y-auto"]'
].join(',');
// export const useScrollbarStyles = (containerRef: React.RefObject<HTMLDivElement | null>) => {
// useEffect(() => {
// if (!containerRef.current) return;
// Function to initialize scrollbar styles for elements
const initializeScrollbarStyles = () => {
// Get all matching elements within the container, including the container itself
const scrollElements = [
...(containerRef.current?.matches(overflowSelector) ? [containerRef.current] : []),
...Array.from(containerRef.current?.querySelectorAll(overflowSelector) || [])
];
// // Create selector for specific overflow classes
// const overflowSelector = [
// '[class*="overflow-auto"]',
// '[class*="overflow-x-auto"]',
// '[class*="overflow-y-auto"]'
// ].join(',');
// Apply basic styling to all elements
scrollElements.forEach(element => {
element.classList.add('void-scrollable-element');
});
// // Function to initialize scrollbar styles for elements
// const initializeScrollbarStyles = () => {
// // Get all matching elements within the container, including the container itself
// const scrollElements = [
// ...(containerRef.current?.matches(overflowSelector) ? [containerRef.current] : []),
// ...Array.from(containerRef.current?.querySelectorAll(overflowSelector) || [])
// ];
// Only initialize fade effects for elements that haven't been initialized yet
scrollElements.forEach(element => {
if (!(element as any).__scrollbarCleanup) {
let fadeTimeout: NodeJS.Timeout | null = null;
let fadeInterval: NodeJS.Timeout | null = null;
// // Apply basic styling to all elements
// scrollElements.forEach(element => {
// element.classList.add('void-scrollable-element');
// });
const fadeIn = () => {
if (fadeInterval) clearInterval(fadeInterval);
// // Only initialize fade effects for elements that haven't been initialized yet
// scrollElements.forEach(element => {
// if (!(element as any).__scrollbarCleanup) {
// let fadeTimeout: NodeJS.Timeout | null = null;
// let fadeInterval: NodeJS.Timeout | null = null;
let step = 0;
fadeInterval = setInterval(() => {
if (step <= 10) {
element.classList.remove(`show-scrollbar-${step - 1}`);
element.classList.add(`show-scrollbar-${step}`);
step++;
} else {
clearInterval(fadeInterval!);
}
}, 10);
};
// const fadeIn = () => {
// if (fadeInterval) clearInterval(fadeInterval);
const fadeOut = () => {
if (fadeInterval) clearInterval(fadeInterval);
// let step = 0;
// fadeInterval = setInterval(() => {
// if (step <= 10) {
// element.classList.remove(`show-scrollbar-${step - 1}`);
// element.classList.add(`show-scrollbar-${step}`);
// step++;
// } else {
// clearInterval(fadeInterval!);
// }
// }, 10);
// };
let step = 10;
fadeInterval = setInterval(() => {
if (step >= 0) {
element.classList.remove(`show-scrollbar-${step + 1}`);
element.classList.add(`show-scrollbar-${step}`);
step--;
} else {
clearInterval(fadeInterval!);
}
}, 60);
};
// const fadeOut = () => {
// if (fadeInterval) clearInterval(fadeInterval);
const onMouseEnter = () => {
if (fadeTimeout) clearTimeout(fadeTimeout);
if (fadeInterval) clearInterval(fadeInterval);
fadeIn();
};
// let step = 10;
// fadeInterval = setInterval(() => {
// if (step >= 0) {
// element.classList.remove(`show-scrollbar-${step + 1}`);
// element.classList.add(`show-scrollbar-${step}`);
// step--;
// } else {
// clearInterval(fadeInterval!);
// }
// }, 60);
// };
const onMouseLeave = () => {
if (fadeTimeout) clearTimeout(fadeTimeout);
fadeTimeout = setTimeout(() => {
fadeOut();
}, 10);
};
// const onMouseEnter = () => {
// if (fadeTimeout) clearTimeout(fadeTimeout);
// if (fadeInterval) clearInterval(fadeInterval);
// fadeIn();
// };
element.addEventListener('mouseenter', onMouseEnter);
element.addEventListener('mouseleave', onMouseLeave);
// const onMouseLeave = () => {
// if (fadeTimeout) clearTimeout(fadeTimeout);
// fadeTimeout = setTimeout(() => {
// fadeOut();
// }, 10);
// };
// Store cleanup function
const cleanup = () => {
element.removeEventListener('mouseenter', onMouseEnter);
element.removeEventListener('mouseleave', onMouseLeave);
if (fadeTimeout) clearTimeout(fadeTimeout);
if (fadeInterval) clearInterval(fadeInterval);
element.classList.remove('void-scrollable-element');
// Remove any remaining show-scrollbar classes
for (let i = 0; i <= 10; i++) {
element.classList.remove(`show-scrollbar-${i}`);
}
};
// element.addEventListener('mouseenter', onMouseEnter);
// element.addEventListener('mouseleave', onMouseLeave);
// Store the cleanup function on the element for later use
(element as any).__scrollbarCleanup = cleanup;
}
});
};
// // Store cleanup function
// const cleanup = () => {
// element.removeEventListener('mouseenter', onMouseEnter);
// element.removeEventListener('mouseleave', onMouseLeave);
// if (fadeTimeout) clearTimeout(fadeTimeout);
// if (fadeInterval) clearInterval(fadeInterval);
// element.classList.remove('void-scrollable-element');
// // Remove any remaining show-scrollbar classes
// for (let i = 0; i <= 10; i++) {
// element.classList.remove(`show-scrollbar-${i}`);
// }
// };
// Initialize for the first time
initializeScrollbarStyles();
// // Store the cleanup function on the element for later use
// (element as any).__scrollbarCleanup = cleanup;
// }
// });
// };
// Set up mutation observer to do the same
const observer = new MutationObserver(() => {
initializeScrollbarStyles();
});
// // Initialize for the first time
// initializeScrollbarStyles();
// Start observing the container for child changes
observer.observe(containerRef.current, {
childList: true,
subtree: true
});
// // Set up mutation observer to do the same
// const observer = new MutationObserver(() => {
// initializeScrollbarStyles();
// });
return () => {
observer.disconnect();
// Your existing cleanup code...
if (containerRef.current) {
const scrollElements = [
...(containerRef.current.matches(overflowSelector) ? [containerRef.current] : []),
...Array.from(containerRef.current.querySelectorAll(overflowSelector))
];
scrollElements.forEach(element => {
if ((element as any).__scrollbarCleanup) {
(element as any).__scrollbarCleanup();
}
});
}
};
}, [containerRef]);
};
// // Start observing the container for child changes
// observer.observe(containerRef.current, {
// childList: true,
// subtree: true
// });
// return () => {
// observer.disconnect();
// // Your existing cleanup code...
// if (containerRef.current) {
// const scrollElements = [
// ...(containerRef.current.matches(overflowSelector) ? [containerRef.current] : []),
// ...Array.from(containerRef.current.querySelectorAll(overflowSelector))
// ];
// scrollElements.forEach(element => {
// if ((element as any).__scrollbarCleanup) {
// (element as any).__scrollbarCleanup();
// }
// });
// }
// };
// }, [containerRef]);
// };

View file

@ -309,7 +309,7 @@ const VoidCommandBar = ({ uri, editor }: VoidCommandBarProps) => {
</div>
</div>
return <div className={`flex flex-col items-center gap-y-2 mx-2 pointer-events-auto`}>
return <div className={`flex flex-col items-center gap-y-2 pointer-events-auto`}>
{showAcceptRejectAll && acceptRejectAllButtons}
{leftRightUpDownButtons}

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------*/
import { useAccessor, useIsDark, useSettingsState } from '../util/services.js';
import { useAccessor, useActiveURI, useIsDark, useSettingsState } from '../util/services.js';
import '../styles.css'
import { VOID_CTRL_K_ACTION_ID, VOID_CTRL_L_ACTION_ID } from '../../../actionIDs.js';
@ -65,6 +65,8 @@ const VoidSelectionHelper = ({ rerenderKey }: VoidSelectionHelperProps) => {
// }, [rerenderKey, reactRerenderCount, setReactRerenderKey, setClickState])
// if the user selected an option, close
if (clickState === 'clickedOption') {
return null
}

View file

@ -125,6 +125,10 @@ export class SelectionHelperContribution extends Disposable implements IEditorCo
return;
}
if (this._editor.getModel().uri.scheme !== 'file') {
return;
}
const selection = this._editor.getSelection();
if (!selection || selection.isEmpty()) {

View file

@ -6,6 +6,46 @@
import { FeatureName, ModelSelectionOptions, ProviderName } from './voidSettingsTypes.js';
export const defaultProviderSettings = {
anthropic: {
apiKey: '',
},
openAI: {
apiKey: '',
},
deepseek: {
apiKey: '',
},
ollama: {
endpoint: 'http://127.0.0.1:11434',
},
vLLM: {
endpoint: 'http://localhost:8000',
},
openRouter: {
apiKey: '',
},
openAICompatible: {
endpoint: '',
apiKey: '',
},
gemini: {
apiKey: '',
},
groq: {
apiKey: '',
},
xAI: {
apiKey: ''
},
} as const
export const defaultModelsOfProvider = {
openAI: [ // https://platform.openai.com/docs/models/gp
'o3-mini',
@ -68,20 +108,22 @@ export const defaultModelsOfProvider = {
type ModelOptions = {
export type VoidStaticModelInfo = { // not stateful
contextWindow: number; // input tokens
maxOutputTokens: number | null; // output tokens, defaults to 4092
cost: { // <-- UNUSED
cost: { // <-- UNUSED
input: number;
output: number;
cache_read?: number;
cache_write?: number;
}
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated';
supportsTools: false | 'anthropic-style' | 'openai-style';
downloadable: false | {
sizeGb: number | 'not-known'
}
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated'; // separated = anthropic where "system" is a special parameter
supportsTools: false | 'TODO-yes-but-we-handle-it-manually' | 'anthropic-style' | 'openai-style';
supportsFIM: boolean;
reasoningCapabilities: false | {
@ -109,18 +151,19 @@ type ProviderReasoningIOSettings = {
| { nameOfFieldInDelta?: undefined, needsManualParse?: true, };
}
type ProviderSettings = {
type VoidStaticProviderInfo = { // doesn't change (not stateful)
providerReasoningIOSettings?: ProviderReasoningIOSettings; // input/output settings around thinking (allowed to be empty) - only applied if the model supports reasoning output
modelOptions: { [key: string]: ModelOptions };
modelOptionsFallback: (modelName: string) => (ModelOptions & { modelName: string }) | null;
modelOptions: { [key: string]: VoidStaticModelInfo };
modelOptionsFallback: (modelName: string, fallbackKnownValues?: Partial<VoidStaticModelInfo>) => (VoidStaticModelInfo & { modelName: string }) | null;
}
const modelOptionsDefaults: ModelOptions = {
const modelOptionsDefaults: VoidStaticModelInfo = {
contextWindow: 32_000,
maxOutputTokens: 4_096,
cost: { input: 0, output: 0 },
downloadable: false,
supportsSystemMessage: false,
supportsTools: false,
supportsFIM: false,
@ -261,21 +304,24 @@ const openSourceModelOptions_assumingOAICompat = {
contextWindow: 128_000, maxOutputTokens: 8_192,
},
} as const satisfies { [s: string]: Omit<ModelOptions, 'cost'> }
} as const satisfies { [s: string]: Partial<VoidStaticModelInfo> }
const extensiveModelFallback: ProviderSettings['modelOptionsFallback'] = (modelName) => {
const extensiveModelFallback: VoidStaticProviderInfo['modelOptionsFallback'] = (modelName, fallbackKnownValues) => {
const lower = modelName.toLowerCase()
const toFallback = (opts: Omit<ModelOptions, 'cost'>): ModelOptions & { modelName: string } => {
const toFallback = (opts: Omit<VoidStaticModelInfo, 'cost' | 'downloadable'>): VoidStaticModelInfo & { modelName: string } => {
return {
modelName,
...opts,
supportsSystemMessage: opts.supportsSystemMessage ? 'system-role' : false,
cost: { input: 0, output: 0 },
downloadable: false,
...fallbackKnownValues
}
}
if (Object.keys(openSourceModelOptions_assumingOAICompat).map(k => k.toLowerCase()).includes(lower))
@ -332,6 +378,7 @@ const anthropicModelOptions = {
contextWindow: 200_000,
maxOutputTokens: 8_192,
cost: { input: 3.00, cache_read: 0.30, cache_write: 3.75, output: 15.00 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'separated',
supportsTools: 'anthropic-style',
@ -347,6 +394,7 @@ const anthropicModelOptions = {
contextWindow: 200_000,
maxOutputTokens: 8_192,
cost: { input: 3.00, cache_read: 0.30, cache_write: 3.75, output: 15.00 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'separated',
supportsTools: 'anthropic-style',
@ -356,6 +404,7 @@ const anthropicModelOptions = {
contextWindow: 200_000,
maxOutputTokens: 8_192,
cost: { input: 0.80, cache_read: 0.08, cache_write: 1.00, output: 4.00 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'separated',
supportsTools: 'anthropic-style',
@ -365,6 +414,7 @@ const anthropicModelOptions = {
contextWindow: 200_000,
maxOutputTokens: 4_096,
cost: { input: 15.00, cache_read: 1.50, cache_write: 18.75, output: 75.00 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'separated',
supportsTools: 'anthropic-style',
@ -372,15 +422,16 @@ const anthropicModelOptions = {
},
'claude-3-sonnet-20240229': { // no point of using this, but including this for people who put it in
contextWindow: 200_000, cost: { input: 3.00, output: 15.00 },
downloadable: false,
maxOutputTokens: 4_096,
supportsFIM: false,
supportsSystemMessage: 'separated',
supportsTools: 'anthropic-style',
reasoningCapabilities: false,
}
} as const satisfies { [s: string]: ModelOptions }
} as const satisfies { [s: string]: VoidStaticModelInfo }
const anthropicSettings: ProviderSettings = {
const anthropicSettings: VoidStaticProviderInfo = {
providerReasoningIOSettings: {
input: {
includeInPayload: (reasoningInfo) => {
@ -412,6 +463,7 @@ const openAIModelOptions = { // https://platform.openai.com/docs/pricing
contextWindow: 128_000,
maxOutputTokens: 100_000,
cost: { input: 15.00, cache_read: 7.50, output: 60.00, },
downloadable: false,
supportsFIM: false,
supportsTools: false,
supportsSystemMessage: 'developer-role',
@ -421,6 +473,7 @@ const openAIModelOptions = { // https://platform.openai.com/docs/pricing
contextWindow: 200_000,
maxOutputTokens: 100_000,
cost: { input: 1.10, cache_read: 0.55, output: 4.40, },
downloadable: false,
supportsFIM: false,
supportsTools: false,
supportsSystemMessage: 'developer-role',
@ -430,6 +483,7 @@ const openAIModelOptions = { // https://platform.openai.com/docs/pricing
contextWindow: 128_000,
maxOutputTokens: 16_384,
cost: { input: 2.50, cache_read: 1.25, output: 10.00, },
downloadable: false,
supportsFIM: false,
supportsTools: 'openai-style',
supportsSystemMessage: 'system-role',
@ -439,6 +493,7 @@ const openAIModelOptions = { // https://platform.openai.com/docs/pricing
contextWindow: 128_000,
maxOutputTokens: 65_536,
cost: { input: 1.10, cache_read: 0.55, output: 4.40, },
downloadable: false,
supportsFIM: false,
supportsTools: false,
supportsSystemMessage: false, // does not support any system
@ -448,15 +503,16 @@ const openAIModelOptions = { // https://platform.openai.com/docs/pricing
contextWindow: 128_000,
maxOutputTokens: 16_384,
cost: { input: 0.15, cache_read: 0.075, output: 0.60, },
downloadable: false,
supportsFIM: false,
supportsTools: 'openai-style',
supportsSystemMessage: 'system-role', // ??
reasoningCapabilities: false,
},
} as const satisfies { [s: string]: ModelOptions }
} as const satisfies { [s: string]: VoidStaticModelInfo }
const openAISettings: ProviderSettings = {
const openAISettings: VoidStaticProviderInfo = {
modelOptions: openAIModelOptions,
modelOptionsFallback: (modelName) => {
const lower = modelName.toLowerCase()
@ -475,14 +531,15 @@ const xAIModelOptions = {
contextWindow: 131_072,
maxOutputTokens: null, // 131_072,
cost: { input: 2.00, output: 10.00 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
reasoningCapabilities: false,
},
} as const satisfies { [s: string]: ModelOptions }
} as const satisfies { [s: string]: VoidStaticModelInfo }
const xAISettings: ProviderSettings = {
const xAISettings: VoidStaticProviderInfo = {
modelOptions: xAIModelOptions,
modelOptionsFallback: (modelName) => {
const lower = modelName.toLowerCase()
@ -500,6 +557,7 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
contextWindow: 1_048_576,
maxOutputTokens: 8_192,
cost: { input: 0, output: 0 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style', // we are assuming OpenAI SDK when calling gemini
@ -509,6 +567,7 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
contextWindow: 1_048_576,
maxOutputTokens: 8_192, // 8_192,
cost: { input: 0.10, output: 0.40 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style', // we are assuming OpenAI SDK when calling gemini
@ -518,6 +577,7 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
contextWindow: 1_048_576,
maxOutputTokens: 8_192, // 8_192,
cost: { input: 0.075, output: 0.30 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -527,6 +587,7 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
contextWindow: 1_048_576,
maxOutputTokens: 8_192, // 8_192,
cost: { input: 0.075, output: 0.30 }, // TODO!!! price doubles after 128K tokens, we are NOT encoding that info right now
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -536,6 +597,7 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
contextWindow: 2_097_152,
maxOutputTokens: 8_192,
cost: { input: 1.25, output: 5.00 }, // TODO!!! price doubles after 128K tokens, we are NOT encoding that info right now
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -545,14 +607,15 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
contextWindow: 1_048_576,
maxOutputTokens: 8_192,
cost: { input: 0.0375, output: 0.15 }, // TODO!!! price doubles after 128K tokens, we are NOT encoding that info right now
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
reasoningCapabilities: false,
},
} as const satisfies { [s: string]: ModelOptions }
} as const satisfies { [s: string]: VoidStaticModelInfo }
const geminiSettings: ProviderSettings = {
const geminiSettings: VoidStaticProviderInfo = {
modelOptions: geminiModelOptions,
modelOptionsFallback: (modelName) => { return null }
}
@ -566,17 +629,19 @@ const deepseekModelOptions = {
contextWindow: 64_000, // https://api-docs.deepseek.com/quick_start/pricing
maxOutputTokens: 8_000, // 8_000,
cost: { cache_read: .07, input: .27, output: 1.10, },
downloadable: false,
},
'deepseek-reasoner': {
...openSourceModelOptions_assumingOAICompat.deepseekCoderV2,
contextWindow: 64_000,
maxOutputTokens: 8_000, // 8_000,
cost: { cache_read: .14, input: .55, output: 2.19, },
downloadable: false,
},
} as const satisfies { [s: string]: ModelOptions }
} as const satisfies { [s: string]: VoidStaticModelInfo }
const deepseekSettings: ProviderSettings = {
const deepseekSettings: VoidStaticProviderInfo = {
modelOptions: deepseekModelOptions,
providerReasoningIOSettings: {
// reasoning: OAICompat + response.choices[0].delta.reasoning_content // https://api-docs.deepseek.com/guides/reasoning_model
@ -591,6 +656,7 @@ const groqModelOptions = { // https://console.groq.com/docs/models, https://groq
contextWindow: 128_000,
maxOutputTokens: 32_768, // 32_768,
cost: { input: 0.59, output: 0.79 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -600,6 +666,7 @@ const groqModelOptions = { // https://console.groq.com/docs/models, https://groq
contextWindow: 128_000,
maxOutputTokens: 8_192,
cost: { input: 0.05, output: 0.08 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -609,6 +676,7 @@ const groqModelOptions = { // https://console.groq.com/docs/models, https://groq
contextWindow: 128_000,
maxOutputTokens: null, // not specified?
cost: { input: 0.79, output: 0.79 },
downloadable: false,
supportsFIM: false, // unfortunately looks like no FIM support on groq
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -618,13 +686,14 @@ const groqModelOptions = { // https://console.groq.com/docs/models, https://groq
contextWindow: 128_000,
maxOutputTokens: null, // not specified?
cost: { input: 0.29, output: 0.39 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
reasoningCapabilities: { supportsReasoning: true, canIOReasoning: true, canTurnOffReasoning: false, openSourceThinkTags: ['<think>', '</think>'] }, // we're using reasoning_format:parsed so really don't need to know openSourceThinkTags
},
} as const satisfies { [s: string]: ModelOptions }
const groqSettings: ProviderSettings = {
} as const satisfies { [s: string]: VoidStaticModelInfo }
const groqSettings: VoidStaticProviderInfo = {
providerReasoningIOSettings: {
input: {
includeInPayload: (reasoningInfo) => {
@ -640,23 +709,71 @@ const groqSettings: ProviderSettings = {
modelOptionsFallback: (modelName) => { return null }
}
const ollamaModelOptions = {
'qwen2.5-coder:3b': {
contextWindow: 32_000,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: { sizeGb: 1.9 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: false,
reasoningCapabilities: false,
},
'qwen2.5-coder': {
contextWindow: 128_000,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: { sizeGb: 4.7 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: false,
reasoningCapabilities: false,
},
'qwq': {
contextWindow: 128_000,
maxOutputTokens: 32_000,
cost: { input: 0, output: 0 },
downloadable: { sizeGb: 20 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'TODO-yes-but-we-handle-it-manually',
reasoningCapabilities: { supportsReasoning: true, canIOReasoning: false, canTurnOffReasoning: false, openSourceThinkTags: ['<think>', '</think>'] },
},
'deepseek-r1': {
contextWindow: 128_000,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: { sizeGb: 4.7 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'TODO-yes-but-we-handle-it-manually',
reasoningCapabilities: { supportsReasoning: true, canIOReasoning: false, canTurnOffReasoning: false, openSourceThinkTags: ['<think>', '</think>'] },
},
} as const satisfies Record<string, VoidStaticModelInfo>
export const ollamaRecommendedModels = ['qwen2.5-coder:3b', 'qwq', 'deepseek-r1'] as const satisfies (keyof typeof ollamaModelOptions)[]
// ---------------- VLLM, OLLAMA, OPENAICOMPAT (self-hosted / local) ----------------
const vLLMSettings: ProviderSettings = {
const vLLMSettings: VoidStaticProviderInfo = {
// reasoning: OAICompat + response.choices[0].delta.reasoning_content // https://docs.vllm.ai/en/stable/features/reasoning_outputs.html#streaming-chat-completions
providerReasoningIOSettings: { output: { nameOfFieldInDelta: 'reasoning_content' }, },
modelOptionsFallback: (modelName) => extensiveModelFallback(modelName),
modelOptions: {},
modelOptionsFallback: (modelName) => extensiveModelFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
modelOptions: {}, // TODO
}
const ollamaSettings: ProviderSettings = {
const ollamaSettings: VoidStaticProviderInfo = {
// reasoning: we need to filter out reasoning <think> tags manually
providerReasoningIOSettings: { output: { needsManualParse: true }, },
modelOptionsFallback: (modelName) => extensiveModelFallback(modelName),
modelOptions: {},
modelOptionsFallback: (modelName) => extensiveModelFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
modelOptions: ollamaModelOptions,
}
const openaiCompatible: ProviderSettings = {
const openaiCompatible: VoidStaticProviderInfo = {
// reasoning: we have no idea what endpoint they used, so we can't consistently parse out reasoning
modelOptionsFallback: (modelName) => extensiveModelFallback(modelName),
modelOptions: {},
@ -669,6 +786,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
contextWindow: 128_000,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: false,
supportsFIM: false,
supportsTools: 'openai-style',
supportsSystemMessage: 'system-role',
@ -678,6 +796,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
contextWindow: 1_048_576,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: false,
supportsFIM: false,
supportsTools: 'openai-style',
supportsSystemMessage: 'system-role',
@ -687,6 +806,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
contextWindow: 1_048_576,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: false,
supportsFIM: false,
supportsTools: 'openai-style',
supportsSystemMessage: 'system-role',
@ -696,6 +816,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
contextWindow: 1_048_576,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: false,
supportsFIM: false,
supportsTools: 'openai-style',
supportsSystemMessage: 'system-role',
@ -706,11 +827,13 @@ const openRouterModelOptions_assumingOpenAICompat = {
contextWindow: 128_000,
maxOutputTokens: null,
cost: { input: 0.8, output: 2.4 },
downloadable: false,
},
'anthropic/claude-3.7-sonnet:thinking': {
contextWindow: 200_000,
maxOutputTokens: null,
cost: { input: 3.00, output: 15.00 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -726,6 +849,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
contextWindow: 200_000,
maxOutputTokens: null,
cost: { input: 3.00, output: 15.00 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -735,6 +859,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
contextWindow: 200_000,
maxOutputTokens: null,
cost: { input: 3.00, output: 15.00 },
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
@ -745,6 +870,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
contextWindow: 256_000,
maxOutputTokens: null,
cost: { input: 0.3, output: 0.9 },
downloadable: false,
supportsTools: 'openai-style',
reasoningCapabilities: false,
},
@ -754,6 +880,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
maxOutputTokens: null,
supportsTools: false, // openrouter qwen doesn't seem to support tools...?
cost: { input: 0.07, output: 0.16 },
downloadable: false,
},
'qwen/qwq-32b': {
...openSourceModelOptions_assumingOAICompat['qwq'],
@ -761,10 +888,11 @@ const openRouterModelOptions_assumingOpenAICompat = {
maxOutputTokens: null,
supportsTools: false, // openrouter qwen doesn't seem to support tools...?
cost: { input: 0.07, output: 0.16 },
downloadable: false,
}
} as const satisfies { [s: string]: ModelOptions }
} as const satisfies { [s: string]: VoidStaticModelInfo }
const openRouterSettings: ProviderSettings = {
const openRouterSettings: VoidStaticProviderInfo = {
// reasoning: OAICompat + response.choices[0].delta.reasoning : payload should have {include_reasoning: true} https://openrouter.ai/announcements/reasoning-tokens-for-thinking-models
providerReasoningIOSettings: {
input: {
@ -791,7 +919,7 @@ const openRouterSettings: ProviderSettings = {
// ---------------- model settings of everything above ----------------
const modelSettingsOfProvider: { [providerName in ProviderName]: ProviderSettings } = {
const modelSettingsOfProvider: { [providerName in ProviderName]: VoidStaticProviderInfo } = {
openAI: openAISettings,
anthropic: anthropicSettings,
xAI: xAISettings,
@ -817,8 +945,10 @@ const modelSettingsOfProvider: { [providerName in ProviderName]: ProviderSetting
// ---------------- exports ----------------
// returns the capabilities and the adjusted modelName if it was a fallback
export const getModelCapabilities = (providerName: ProviderName, modelName: string): ModelOptions & { modelName: string; isUnrecognizedModel: boolean } => {
export const getModelCapabilities = (providerName: ProviderName, modelName: string): VoidStaticModelInfo & { modelName: string; isUnrecognizedModel: boolean } => {
const lowercaseModelName = modelName.toLowerCase()
const { modelOptions, modelOptionsFallback } = modelSettingsOfProvider[providerName]
// search model options object directly first

View file

@ -85,6 +85,10 @@ export const voidTools = {
}
},
// pathname_search: {
// name: 'pathname_search',
// description: `Returns all pathnames that match a given \`find\`-style query over the entire workspace. ONLY searches file names. ONLY searches the current workspace. You should use this when looking for a file with a specific name or path. ${paginationHelper.desc}`,
search_pathnames_only: {
name: 'search_pathnames_only',
description: `Returns all pathnames that match a given query (searches ONLY file names). You should use this when looking for a file with a specific name or path. ${paginationHelper.desc}`,
@ -95,6 +99,8 @@ export const voidTools = {
},
},
search_files: {
name: 'search_files',
description: `Returns all pathnames that match a given \`grep\`-style query (searches ONLY file contents). The query can be any regex. This is often followed by the \`read_file\` tool to view the full file contents of results. ${paginationHelper.desc}`,

View file

@ -11,9 +11,9 @@ import { registerSingleton, InstantiationType } from '../../../../platform/insta
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { IMetricsService } from './metricsService.js';
import { getModelCapabilities } from './modelCapabilities.js';
import { defaultProviderSettings, getModelCapabilities } from './modelCapabilities.js';
import { VOID_SETTINGS_STORAGE_KEY } from './storageKeys.js';
import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, VoidModelInfo, GlobalSettings, GlobalSettingName, defaultGlobalSettings, defaultProviderSettings, ModelSelectionOptions, OptionsOfModelSelection, ChatMode } from './voidSettingsTypes.js';
import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, VoidStatefulModelInfo, GlobalSettings, GlobalSettingName, defaultGlobalSettings, ModelSelectionOptions, OptionsOfModelSelection, ChatMode } from './voidSettingsTypes.js';
// name is the name in the dropdown
@ -71,10 +71,10 @@ export interface IVoidSettingsService {
const _updatedModelsAfterDefaultModelsChange = (defaultModelNames: string[], options: { existingModels: VoidModelInfo[] }) => {
const _updatedModelsAfterDefaultModelsChange = (defaultModelNames: string[], options: { existingModels: VoidStatefulModelInfo[] }) => {
const { existingModels } = options
const existingModelsMap: Record<string, VoidModelInfo> = {}
const existingModelsMap: Record<string, VoidStatefulModelInfo> = {}
for (const existingModel of existingModels) {
existingModelsMap[existingModel.modelName] = existingModel
}
@ -363,7 +363,7 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
const modelIdx = models.findIndex(m => m.modelName === modelName)
if (modelIdx === -1) return
const newIsHidden = !models[modelIdx].isHidden
const newModels: VoidModelInfo[] = [
const newModels: VoidStatefulModelInfo[] = [
...models.slice(0, modelIdx),
{ ...models[modelIdx], isHidden: newIsHidden },
...models.slice(modelIdx + 1, Infinity)

View file

@ -4,49 +4,13 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
*--------------------------------------------------------------------------------------*/
import { defaultModelsOfProvider } from './modelCapabilities.js';
import { defaultModelsOfProvider, defaultProviderSettings } from './modelCapabilities.js';
import { VoidSettingsState } from './voidSettingsService.js'
type UnionOfKeys<T> = T extends T ? keyof T : never;
export const defaultProviderSettings = {
anthropic: {
apiKey: '',
},
openAI: {
apiKey: '',
},
deepseek: {
apiKey: '',
},
ollama: {
endpoint: 'http://127.0.0.1:11434',
},
vLLM: {
endpoint: 'http://localhost:8000',
},
openRouter: {
apiKey: '',
},
openAICompatible: {
endpoint: '',
apiKey: '',
},
gemini: {
apiKey: '',
},
groq: {
apiKey: '',
},
xAI: {
apiKey: ''
},
} as const
export type ProviderName = keyof typeof defaultProviderSettings
export const providerNames = Object.keys(defaultProviderSettings) as ProviderName[]
@ -64,7 +28,7 @@ export const customSettingNamesOfProvider = (providerName: ProviderName) => {
export type VoidModelInfo = { // <-- STATEFUL
export type VoidStatefulModelInfo = { // <-- STATEFUL
modelName: string,
isDefault: boolean, // whether or not it's a default for its provider
isHidden: boolean, // whether or not the user is hiding it (switched off)
@ -75,7 +39,7 @@ export type VoidModelInfo = { // <-- STATEFUL
type CommonProviderSettings = {
_didFillInProviderSettings: boolean | undefined, // undefined initially, computed when user types in all fields
models: VoidModelInfo[],
models: VoidStatefulModelInfo[],
}
export type SettingsAtProvider<providerName extends ProviderName> = CustomProviderSettings<providerName> & CommonProviderSettings
@ -227,7 +191,7 @@ const defaultCustomSettings: Record<CustomSettingName, undefined> = {
}
const modelInfoOfDefaultModelNames = (defaultModelNames: string[]): { models: VoidModelInfo[] } => {
const modelInfoOfDefaultModelNames = (defaultModelNames: string[]): { models: VoidStatefulModelInfo[] } => {
return {
models: defaultModelNames.map((modelName, i) => ({
modelName,
@ -334,6 +298,8 @@ export const displayInfoOfFeatureName = (featureName: FeatureName) => {
export const refreshableProviderNames = localProviderNames
export type RefreshableProviderName = typeof refreshableProviderNames[number]
// models that come with download buttons
export const hasDownloadButtonsOnModelsProviderNames = ['ollama'] as const satisfies ProviderName[]

View file

@ -372,7 +372,7 @@ const prepareMessages_tools_anthropic = ({ messages }: { messages: InternalLLMCh
type PrepareMessagesTools = PrepareMessagesToolsAnthropic | PrepareMessagesToolsOpenAI
const prepareMessages_tools = ({ messages, supportsTools }: { messages: InternalLLMChatMessage[], supportsTools: false | 'anthropic-style' | 'openai-style' }): { messages: PrepareMessagesTools } => {
const prepareMessages_tools = ({ messages, supportsTools }: { messages: InternalLLMChatMessage[], supportsTools: false | 'TODO-yes-but-we-handle-it-manually' | 'anthropic-style' | 'openai-style' }): { messages: PrepareMessagesTools } => {
if (!supportsTools) {
return { messages: messages }
}
@ -466,7 +466,7 @@ export const prepareMessages = ({
messages: LLMChatMessage[],
aiInstructions: string,
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated',
supportsTools: false | 'anthropic-style' | 'openai-style',
supportsTools: false | 'TODO-yes-but-we-handle-it-manually' | 'anthropic-style' | 'openai-style',
supportsAnthropicReasoningSignature: boolean,
contextWindow: number,
maxOutputTokens: number | null | undefined,

View file

@ -9,9 +9,9 @@ import OpenAI, { ClientOptions } from 'openai';
import { extractReasoningOnFinalMessage, extractReasoningOnTextWrapper } from '../../common/helpers/extractCodeFromResult.js';
import { LLMChatMessage, LLMFIMMessage, ModelListParams, OllamaModelResponse, OnError, OnFinalMessage, OnText } from '../../common/sendLLMMessageTypes.js';
import { defaultProviderSettings, displayInfoOfProviderName, ModelSelectionOptions, ProviderName, SettingsOfProvider } from '../../common/voidSettingsTypes.js';
import { displayInfoOfProviderName, ModelSelectionOptions, ProviderName, SettingsOfProvider } from '../../common/voidSettingsTypes.js';
import { prepareFIMMessage, prepareMessages } from './preprocessLLMMessages.js';
import { getSendableReasoningInfo, getModelCapabilities, getProviderCapabilities } from '../../common/modelCapabilities.js';
import { getSendableReasoningInfo, getModelCapabilities, getProviderCapabilities, defaultProviderSettings } from '../../common/modelCapabilities.js';
import { InternalToolInfo, ToolName, isAToolName } from '../../common/toolsServiceTypes.js';