mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
Merge branch 'main' into void-settings-sidebar
This commit is contained in:
commit
23bb28f3c0
17 changed files with 588 additions and 187 deletions
46
package-lock.json
generated
46
package-lock.json
generated
|
|
@ -299,13 +299,14 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@azure/core-auth": {
|
"node_modules/@azure/core-auth": {
|
||||||
"version": "1.7.2",
|
"version": "1.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz",
|
||||||
"integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==",
|
"integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/abort-controller": "^2.0.0",
|
"@azure/abort-controller": "^2.0.0",
|
||||||
"@azure/core-util": "^1.1.0",
|
"@azure/core-util": "^1.11.0",
|
||||||
"tslib": "^2.6.2"
|
"tslib": "^2.6.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -448,18 +449,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@azure/core-rest-pipeline": {
|
"node_modules/@azure/core-rest-pipeline": {
|
||||||
"version": "1.16.0",
|
"version": "1.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.20.0.tgz",
|
||||||
"integrity": "sha512-CeuTvsXxCUmEuxH5g/aceuSl6w2EugvNHKAtKKVdiX915EjJJxAwfzNNWZreNnbxHZ2fi0zaM6wwS23x2JVqSQ==",
|
"integrity": "sha512-ASoP8uqZBS3H/8N8at/XwFr6vYrRP3syTK0EUjDXQy0Y1/AUS+QeIRThKmTNJO2RggvBBxaXDPM7YoIwDGeA0g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/abort-controller": "^2.0.0",
|
"@azure/abort-controller": "^2.0.0",
|
||||||
"@azure/core-auth": "^1.4.0",
|
"@azure/core-auth": "^1.8.0",
|
||||||
"@azure/core-tracing": "^1.0.1",
|
"@azure/core-tracing": "^1.0.1",
|
||||||
"@azure/core-util": "^1.9.0",
|
"@azure/core-util": "^1.11.0",
|
||||||
"@azure/logger": "^1.0.0",
|
"@azure/logger": "^1.0.0",
|
||||||
"http-proxy-agent": "^7.0.0",
|
"@typespec/ts-http-runtime": "^0.2.2",
|
||||||
"https-proxy-agent": "^7.0.0",
|
|
||||||
"tslib": "^2.6.2"
|
"tslib": "^2.6.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -479,12 +480,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@azure/core-util": {
|
"node_modules/@azure/core-util": {
|
||||||
"version": "1.9.0",
|
"version": "1.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.12.0.tgz",
|
||||||
"integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==",
|
"integrity": "sha512-13IyjTQgABPARvG90+N2dXpC+hwp466XCdQXPCRlbWHgd3SJd5Q1VvaBGv6k1BIa4MQm6hAF1UBU1m8QUxV8sQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/abort-controller": "^2.0.0",
|
"@azure/abort-controller": "^2.0.0",
|
||||||
|
"@typespec/ts-http-runtime": "^0.2.2",
|
||||||
"tslib": "^2.6.2"
|
"tslib": "^2.6.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -4257,6 +4260,21 @@
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@typespec/ts-http-runtime": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-Gz/Sm64+Sq/vklJu1tt9t+4R2lvnud8NbTD/ZfpZtMiUX7YeVpCA8j6NSW8ptwcoLL+NmYANwqP8DV0q/bwl2w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"http-proxy-agent": "^7.0.0",
|
||||||
|
"https-proxy-agent": "^7.0.0",
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vscode/deviceid": {
|
"node_modules/@vscode/deviceid": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vscode/deviceid/-/deviceid-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@vscode/deviceid/-/deviceid-0.1.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"nameShort": "Void",
|
"nameShort": "Void",
|
||||||
"nameLong": "Void",
|
"nameLong": "Void",
|
||||||
"voidVersion": "1.3.6",
|
"voidVersion": "1.3.10",
|
||||||
"voidRelease": "0030",
|
"voidRelease": "0034",
|
||||||
"applicationName": "void",
|
"applicationName": "void",
|
||||||
"dataFolderName": ".void-editor",
|
"dataFolderName": ".void-editor",
|
||||||
"win32MutexName": "voideditor",
|
"win32MutexName": "voideditor",
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,7 @@ const prepareOpenAIOrAnthropicMessages = ({
|
||||||
else {
|
else {
|
||||||
// allowed to be empty if has a tool in it or following it
|
// allowed to be empty if has a tool in it or following it
|
||||||
if (currMsg.content.find(c => c.type === 'tool_result' || c.type === 'tool_use')) {
|
if (currMsg.content.find(c => c.type === 'tool_result' || c.type === 'tool_use')) {
|
||||||
|
currMsg.content = currMsg.content.filter(c => !(c.type === 'text' && !c.text)) as any
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (nextMsg?.role === 'tool') continue
|
if (nextMsg?.role === 'tool') continue
|
||||||
|
|
|
||||||
78
src/vs/workbench/contrib/void/browser/fileService.ts
Normal file
78
src/vs/workbench/contrib/void/browser/fileService.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { localize2 } from '../../../../nls.js';
|
||||||
|
import { URI } from '../../../../base/common/uri.js';
|
||||||
|
import { Action2, registerAction2, MenuId } from '../../../../platform/actions/common/actions.js';
|
||||||
|
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
|
||||||
|
import { INotificationService } from '../../../../platform/notification/common/notification.js';
|
||||||
|
import { IFileService } from '../../../../platform/files/common/files.js';
|
||||||
|
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
|
||||||
|
import { IDirectoryStrService } from '../common/directoryStrService.js';
|
||||||
|
import { messageOfSelection } from '../common/prompt/prompts.js';
|
||||||
|
import { IVoidModelService } from '../common/voidModelService.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class FilePromptActionService extends Action2 {
|
||||||
|
private static readonly VOID_COPY_FILE_PROMPT_ID = 'void.copyfileprompt'
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: FilePromptActionService.VOID_COPY_FILE_PROMPT_ID,
|
||||||
|
title: localize2('voidCopyPrompt', 'Void: Copy Prompt'),
|
||||||
|
menu: [{
|
||||||
|
id: MenuId.ExplorerContext,
|
||||||
|
group: '8_void',
|
||||||
|
order: 1,
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(accessor: ServicesAccessor, uri: URI): Promise<void> {
|
||||||
|
try {
|
||||||
|
const fileService = accessor.get(IFileService);
|
||||||
|
const clipboardService = accessor.get(IClipboardService)
|
||||||
|
const directoryStrService = accessor.get(IDirectoryStrService)
|
||||||
|
const voidModelService = accessor.get(IVoidModelService)
|
||||||
|
|
||||||
|
const stat = await fileService.stat(uri)
|
||||||
|
|
||||||
|
const folderOpts = {
|
||||||
|
maxChildren: 1000,
|
||||||
|
maxCharsPerFile: 2_000_000,
|
||||||
|
} as const
|
||||||
|
|
||||||
|
let m: string = 'No contents detected'
|
||||||
|
if (stat.isFile) {
|
||||||
|
m = await messageOfSelection({
|
||||||
|
type: 'File',
|
||||||
|
uri,
|
||||||
|
language: (await voidModelService.getModelSafe(uri)).model?.getLanguageId() || '',
|
||||||
|
state: { wasAddedAsCurrentFile: false, },
|
||||||
|
}, {
|
||||||
|
folderOpts,
|
||||||
|
directoryStrService,
|
||||||
|
fileService,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat.isDirectory) {
|
||||||
|
m = await messageOfSelection({
|
||||||
|
type: 'Folder',
|
||||||
|
uri,
|
||||||
|
}, {
|
||||||
|
folderOpts,
|
||||||
|
fileService,
|
||||||
|
directoryStrService,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await clipboardService.writeText(m)
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
const notificationService = accessor.get(INotificationService)
|
||||||
|
notificationService.error(error + '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
registerAction2(FilePromptActionService)
|
||||||
|
|
@ -8,6 +8,8 @@ import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase
|
||||||
import { IExtensionTransferService } from './extensionTransferService.js';
|
import { IExtensionTransferService } from './extensionTransferService.js';
|
||||||
import { os } from '../common/helpers/systemInfo.js';
|
import { os } from '../common/helpers/systemInfo.js';
|
||||||
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
|
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
|
||||||
|
import { timeout } from '../../../../base/common/async.js';
|
||||||
|
import { getActiveWindow } from '../../../../base/browser/dom.js';
|
||||||
|
|
||||||
// Onboarding contribution that mounts the component at startup
|
// Onboarding contribution that mounts the component at startup
|
||||||
export class MiscWorkbenchContribs extends Disposable implements IWorkbenchContribution {
|
export class MiscWorkbenchContribs extends Disposable implements IWorkbenchContribution {
|
||||||
|
|
@ -31,6 +33,16 @@ export class MiscWorkbenchContribs extends Disposable implements IWorkbenchContr
|
||||||
this.extensionTransferService.deleteBlacklistExtensions(os)
|
this.extensionTransferService.deleteBlacklistExtensions(os)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// after some time, trigger a resize event for the blank screen error
|
||||||
|
timeout(5_000).then(() => {
|
||||||
|
// Get the active window reference for multi-window support
|
||||||
|
const targetWindow = getActiveWindow();
|
||||||
|
// Trigger a window resize event to ensure proper layout calculations
|
||||||
|
targetWindow.dispatchEvent(new Event('resize'))
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import { roundRangeToLines } from './sidebarActions.js';
|
||||||
import { VOID_CTRL_K_ACTION_ID } from './actionIDs.js';
|
import { VOID_CTRL_K_ACTION_ID } from './actionIDs.js';
|
||||||
import { localize2 } from '../../../../nls.js';
|
import { localize2 } from '../../../../nls.js';
|
||||||
import { IMetricsService } from '../common/metricsService.js';
|
import { IMetricsService } from '../common/metricsService.js';
|
||||||
|
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
|
||||||
|
|
||||||
export type QuickEditPropsType = {
|
export type QuickEditPropsType = {
|
||||||
diffareaid: number,
|
diffareaid: number,
|
||||||
|
|
@ -42,6 +42,7 @@ registerAction2(class extends Action2 {
|
||||||
keybinding: {
|
keybinding: {
|
||||||
primary: KeyMod.CtrlCmd | KeyCode.KeyK,
|
primary: KeyMod.CtrlCmd | KeyCode.KeyK,
|
||||||
weight: KeybindingWeight.VoidExtension,
|
weight: KeybindingWeight.VoidExtension,
|
||||||
|
when: ContextKeyExpr.deserialize('editorFocus && !terminalFocus'),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,17 +239,94 @@ export const StatusIndicatorForApplyButton = ({ applyBoxId, uri }: { applyBoxId:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const ApplyButtonsHTML = ({
|
const terminalLanguages = new Set([
|
||||||
|
'bash',
|
||||||
|
'shellscript',
|
||||||
|
'shell',
|
||||||
|
'powershell',
|
||||||
|
'bat',
|
||||||
|
'zsh',
|
||||||
|
'sh',
|
||||||
|
'fish',
|
||||||
|
'nushell',
|
||||||
|
'ksh',
|
||||||
|
'xonsh',
|
||||||
|
'elvish',
|
||||||
|
])
|
||||||
|
|
||||||
|
const ApplyButtonsForTerminal = ({
|
||||||
codeStr,
|
codeStr,
|
||||||
applyBoxId,
|
applyBoxId,
|
||||||
uri,
|
uri,
|
||||||
|
language,
|
||||||
}: {
|
}: {
|
||||||
codeStr: string,
|
codeStr: string,
|
||||||
applyBoxId: string,
|
applyBoxId: string,
|
||||||
} & ({
|
language?: string,
|
||||||
uri: URI | 'current';
|
uri: URI | 'current';
|
||||||
})
|
}) => {
|
||||||
) => {
|
const accessor = useAccessor()
|
||||||
|
const metricsService = accessor.get('IMetricsService')
|
||||||
|
const terminalToolService = accessor.get('ITerminalToolService')
|
||||||
|
|
||||||
|
const settingsState = useSettingsState()
|
||||||
|
|
||||||
|
const [isShellRunning, setIsShellRunning] = useState<boolean>(false)
|
||||||
|
const interruptToolRef = useRef<(() => void) | null>(null)
|
||||||
|
const isDisabled = isShellRunning
|
||||||
|
|
||||||
|
const onClickSubmit = useCallback(async () => {
|
||||||
|
if (isShellRunning) return
|
||||||
|
try {
|
||||||
|
setIsShellRunning(true)
|
||||||
|
const terminalId = await terminalToolService.createPersistentTerminal({ cwd: null })
|
||||||
|
const { interrupt } = await terminalToolService.runCommand(
|
||||||
|
codeStr,
|
||||||
|
{ type: 'persistent', persistentTerminalId: terminalId }
|
||||||
|
);
|
||||||
|
interruptToolRef.current = interrupt
|
||||||
|
metricsService.capture('Execute Shell', { length: codeStr.length })
|
||||||
|
} catch (e) {
|
||||||
|
setIsShellRunning(false)
|
||||||
|
console.error('Failed to execute in terminal:', e)
|
||||||
|
}
|
||||||
|
}, [codeStr, uri, applyBoxId, metricsService, terminalToolService, isShellRunning])
|
||||||
|
|
||||||
|
if (isShellRunning) {
|
||||||
|
return (
|
||||||
|
<IconShell1
|
||||||
|
Icon={X}
|
||||||
|
onClick={() => {
|
||||||
|
interruptToolRef.current?.();
|
||||||
|
setIsShellRunning(false);
|
||||||
|
}}
|
||||||
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Stop' })}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isDisabled) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <IconShell1
|
||||||
|
Icon={Play}
|
||||||
|
onClick={onClickSubmit}
|
||||||
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Apply' })}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const ApplyButtonsForEdit = ({
|
||||||
|
codeStr,
|
||||||
|
applyBoxId,
|
||||||
|
uri,
|
||||||
|
language,
|
||||||
|
}: {
|
||||||
|
codeStr: string,
|
||||||
|
applyBoxId: string,
|
||||||
|
language?: string,
|
||||||
|
uri: URI | 'current';
|
||||||
|
}) => {
|
||||||
const accessor = useAccessor()
|
const accessor = useAccessor()
|
||||||
const editCodeService = accessor.get('IEditCodeService')
|
const editCodeService = accessor.get('IEditCodeService')
|
||||||
const metricsService = accessor.get('IMetricsService')
|
const metricsService = accessor.get('IMetricsService')
|
||||||
|
|
@ -260,7 +337,6 @@ export const ApplyButtonsHTML = ({
|
||||||
|
|
||||||
const { currStreamStateRef, setApplying } = useApplyStreamState({ applyBoxId })
|
const { currStreamStateRef, setApplying } = useApplyStreamState({ applyBoxId })
|
||||||
|
|
||||||
|
|
||||||
const onClickSubmit = useCallback(async () => {
|
const onClickSubmit = useCallback(async () => {
|
||||||
if (currStreamStateRef.current === 'streaming') return
|
if (currStreamStateRef.current === 'streaming') return
|
||||||
|
|
||||||
|
|
@ -287,7 +363,7 @@ export const ApplyButtonsHTML = ({
|
||||||
})
|
})
|
||||||
metricsService.capture('Apply Code', { length: codeStr.length }) // capture the length only
|
metricsService.capture('Apply Code', { length: codeStr.length }) // capture the length only
|
||||||
|
|
||||||
}, [setApplying, currStreamStateRef, editCodeService, codeStr, uri, applyBoxId, metricsService])
|
}, [setApplying, currStreamStateRef, editCodeService, codeStr, uri, applyBoxId, metricsService, notificationService])
|
||||||
|
|
||||||
|
|
||||||
const onClickStop = useCallback(() => {
|
const onClickStop = useCallback(() => {
|
||||||
|
|
@ -309,9 +385,7 @@ export const ApplyButtonsHTML = ({
|
||||||
if (uri) editCodeService.acceptOrRejectAllDiffAreas({ uri: uri, behavior: 'reject', removeCtrlKs: false })
|
if (uri) editCodeService.acceptOrRejectAllDiffAreas({ uri: uri, behavior: 'reject', removeCtrlKs: false })
|
||||||
}, [uri, applyBoxId, editCodeService])
|
}, [uri, applyBoxId, editCodeService])
|
||||||
|
|
||||||
|
|
||||||
const currStreamState = currStreamStateRef.current
|
const currStreamState = currStreamStateRef.current
|
||||||
|
|
||||||
if (currStreamState === 'streaming') {
|
if (currStreamState === 'streaming') {
|
||||||
return <IconShell1
|
return <IconShell1
|
||||||
Icon={Square}
|
Icon={Square}
|
||||||
|
|
@ -319,12 +393,9 @@ export const ApplyButtonsHTML = ({
|
||||||
{...tooltipPropsForApplyBlock({ tooltipName: 'Stop' })}
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Stop' })}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDisabled) {
|
if (isDisabled) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (currStreamState === 'idle-no-changes') {
|
if (currStreamState === 'idle-no-changes') {
|
||||||
return <IconShell1
|
return <IconShell1
|
||||||
Icon={Play}
|
Icon={Play}
|
||||||
|
|
@ -332,7 +403,6 @@ export const ApplyButtonsHTML = ({
|
||||||
{...tooltipPropsForApplyBlock({ tooltipName: 'Apply' })}
|
{...tooltipPropsForApplyBlock({ tooltipName: 'Apply' })}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currStreamState === 'idle-has-changes') {
|
if (currStreamState === 'idle-has-changes') {
|
||||||
return <Fragment>
|
return <Fragment>
|
||||||
<IconShell1
|
<IconShell1
|
||||||
|
|
@ -353,6 +423,27 @@ export const ApplyButtonsHTML = ({
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const ApplyButtonsHTML = (params: {
|
||||||
|
codeStr: string,
|
||||||
|
applyBoxId: string,
|
||||||
|
language?: string,
|
||||||
|
uri: URI | 'current';
|
||||||
|
}) => {
|
||||||
|
const { language } = params
|
||||||
|
const isShellLanguage = !!language && terminalLanguages.has(language)
|
||||||
|
|
||||||
|
if (isShellLanguage) {
|
||||||
|
return <ApplyButtonsForTerminal {...params} />
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return <ApplyButtonsForEdit {...params} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const EditToolAcceptRejectButtonsHTML = ({
|
export const EditToolAcceptRejectButtonsHTML = ({
|
||||||
codeStr,
|
codeStr,
|
||||||
applyBoxId,
|
applyBoxId,
|
||||||
|
|
@ -456,7 +547,7 @@ export const BlockCodeApplyWrapper = ({
|
||||||
<div className={`${canApply ? '' : 'hidden'} flex items-center gap-1`}>
|
<div className={`${canApply ? '' : 'hidden'} flex items-center gap-1`}>
|
||||||
<JumpToFileButton uri={uri} />
|
<JumpToFileButton uri={uri} />
|
||||||
{currStreamState === 'idle-no-changes' && <CopyButton codeStr={codeStr} toolTipName='Copy' />}
|
{currStreamState === 'idle-no-changes' && <CopyButton codeStr={codeStr} toolTipName='Copy' />}
|
||||||
<ApplyButtonsHTML uri={uri} applyBoxId={applyBoxId} codeStr={codeStr} />
|
<ApplyButtonsHTML uri={uri} applyBoxId={applyBoxId} codeStr={codeStr} language={language} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2605,7 +2605,7 @@ const CommandBarInChat = () => {
|
||||||
|
|
||||||
|
|
||||||
// !select-text cursor-auto
|
// !select-text cursor-auto
|
||||||
const fileDetailsContent = <div className="px-2 gap-1 w-full">
|
const fileDetailsContent = <div className="px-2 gap-1 w-full overflow-y-auto">
|
||||||
{sortedCommandBarURIs.map((uri, i) => {
|
{sortedCommandBarURIs.map((uri, i) => {
|
||||||
const basename = getBasename(uri.fsPath)
|
const basename = getBasename(uri.fsPath)
|
||||||
|
|
||||||
|
|
@ -2862,6 +2862,7 @@ export const SidebarChat = () => {
|
||||||
textAreaRef: textAreaRef,
|
textAreaRef: textAreaRef,
|
||||||
scrollToBottom: () => scrollToBottom(scrollContainerRef),
|
scrollToBottom: () => scrollToBottom(scrollContainerRef),
|
||||||
})
|
})
|
||||||
|
|
||||||
}, [chatThreadsState, threadId, textAreaRef, scrollContainerRef, isResolved])
|
}, [chatThreadsState, threadId, textAreaRef, scrollContainerRef, isResolved])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import { os } from '../../../../common/helpers/systemInfo.js'
|
||||||
import { IconLoading } from '../sidebar-tsx/SidebarChat.js'
|
import { IconLoading } from '../sidebar-tsx/SidebarChat.js'
|
||||||
import { ToolApprovalType, toolApprovalTypes } from '../../../../common/toolsServiceTypes.js'
|
import { ToolApprovalType, toolApprovalTypes } from '../../../../common/toolsServiceTypes.js'
|
||||||
import Severity from '../../../../../../../base/common/severity.js'
|
import Severity from '../../../../../../../base/common/severity.js'
|
||||||
import { getModelCapabilities, ModelOverrides } from '../../../../common/modelCapabilities.js';
|
import { getModelCapabilities, modelOverrideKeys, ModelOverrides } from '../../../../common/modelCapabilities.js';
|
||||||
import { TransferEditorType, TransferFilesInfo } from '../../../extensionTransferTypes.js';
|
import { TransferEditorType, TransferFilesInfo } from '../../../extensionTransferTypes.js';
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
// Sidebar navigation helpers
|
// Sidebar navigation helpers
|
||||||
|
|
@ -195,6 +195,11 @@ const ConfirmButton = ({ children, onConfirm, className }: { children: React.Rea
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------- Simplified Model Settings Dialog ------------------
|
// ---------------- Simplified Model Settings Dialog ------------------
|
||||||
|
|
||||||
|
// keys of ModelOverrides we allow the user to override
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// This new dialog replaces the verbose UI with a single JSON override box.
|
// This new dialog replaces the verbose UI with a single JSON override box.
|
||||||
const SimpleModelSettingsDialog = ({
|
const SimpleModelSettingsDialog = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
|
|
@ -218,39 +223,26 @@ const SimpleModelSettingsDialog = ({
|
||||||
const currentOverrides = settingsState.overridesOfModel?.[providerName]?.[modelName] ?? undefined;
|
const currentOverrides = settingsState.overridesOfModel?.[providerName]?.[modelName] ?? undefined;
|
||||||
const { recognizedModelName, isUnrecognizedModel } = defaultModelCapabilities
|
const { recognizedModelName, isUnrecognizedModel } = defaultModelCapabilities
|
||||||
|
|
||||||
// keys of ModelOverrides we allow the user to override
|
|
||||||
const allowedKeys: (string & (keyof ModelOverrides))[] = [
|
|
||||||
'contextWindow',
|
|
||||||
'reservedOutputTokenSpace',
|
|
||||||
'supportsSystemMessage',
|
|
||||||
'specialToolFormat',
|
|
||||||
'supportsFIM',
|
|
||||||
'reasoningCapabilities',
|
|
||||||
];
|
|
||||||
|
|
||||||
// Create the placeholder with the default values for allowed keys
|
// Create the placeholder with the default values for allowed keys
|
||||||
const partialDefaults: Partial<ModelOverrides> = {};
|
const partialDefaults: Partial<ModelOverrides> = {};
|
||||||
for (const k of allowedKeys) { if (defaultModelCapabilities[k]) partialDefaults[k] = defaultModelCapabilities[k] as any; }
|
for (const k of modelOverrideKeys) { if (defaultModelCapabilities[k]) partialDefaults[k] = defaultModelCapabilities[k] as any; }
|
||||||
const placeholder = JSON.stringify(partialDefaults, null, 2);
|
const placeholder = JSON.stringify(partialDefaults, null, 2);
|
||||||
|
|
||||||
const [overrideEnabled, setOverrideEnabled] = useState<boolean>(() => !!currentOverrides);
|
const [overrideEnabled, setOverrideEnabled] = useState<boolean>(() => !!currentOverrides);
|
||||||
const [jsonText, setJsonText] = useState<string>(() => currentOverrides ? JSON.stringify(currentOverrides, null, 2) : placeholder);
|
|
||||||
|
|
||||||
const [readOnlyHeight, setReadOnlyHeight] = useState<number | undefined>(undefined);
|
|
||||||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const textAreaRef = useRef<HTMLTextAreaElement | null>(null)
|
||||||
|
|
||||||
// reset when dialog toggles
|
// reset when dialog toggles
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isOpen) return;
|
if (!isOpen) return;
|
||||||
const cur = settingsState.overridesOfModel?.[providerName]?.[modelName];
|
const cur = settingsState.overridesOfModel?.[providerName]?.[modelName];
|
||||||
setOverrideEnabled(!!cur);
|
setOverrideEnabled(!!cur);
|
||||||
// If there are overrides, show them; otherwise use default values
|
|
||||||
setJsonText(cur ? JSON.stringify(cur, null, 2) : placeholder);
|
|
||||||
setErrorMsg(null);
|
setErrorMsg(null);
|
||||||
}, [isOpen, providerName, modelName, settingsState.overridesOfModel, placeholder]);
|
}, [isOpen, providerName, modelName, settingsState.overridesOfModel, placeholder]);
|
||||||
|
|
||||||
const onSave = async () => {
|
const onSave = async () => {
|
||||||
|
|
||||||
// if disabled override, reset overrides
|
// if disabled override, reset overrides
|
||||||
if (!overrideEnabled) {
|
if (!overrideEnabled) {
|
||||||
await settingsStateService.setOverridesOfModel(providerName, modelName, undefined);
|
await settingsStateService.setOverridesOfModel(providerName, modelName, undefined);
|
||||||
|
|
@ -261,9 +253,10 @@ const SimpleModelSettingsDialog = ({
|
||||||
// enabled overrides
|
// enabled overrides
|
||||||
// parse json
|
// parse json
|
||||||
let parsedInput: Record<string, unknown>
|
let parsedInput: Record<string, unknown>
|
||||||
if (jsonText.trim()) {
|
|
||||||
|
if (textAreaRef.current?.value) {
|
||||||
try {
|
try {
|
||||||
parsedInput = JSON.parse(jsonText);
|
parsedInput = JSON.parse(textAreaRef.current.value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setErrorMsg('Invalid JSON');
|
setErrorMsg('Invalid JSON');
|
||||||
return;
|
return;
|
||||||
|
|
@ -275,10 +268,10 @@ const SimpleModelSettingsDialog = ({
|
||||||
|
|
||||||
// only keep allowed keys
|
// only keep allowed keys
|
||||||
const cleaned: Partial<ModelOverrides> = {};
|
const cleaned: Partial<ModelOverrides> = {};
|
||||||
for (const k of allowedKeys) {
|
for (const k of modelOverrideKeys) {
|
||||||
if (!(k in parsedInput)) continue
|
if (!(k in parsedInput)) continue
|
||||||
const isEmpty = parsedInput[k] === '' || parsedInput[k] === null || parsedInput[k] === undefined;
|
const isEmpty = parsedInput[k] === '' || parsedInput[k] === null || parsedInput[k] === undefined;
|
||||||
if (!isEmpty && (k in partialDefaults)) {
|
if (!isEmpty) {
|
||||||
cleaned[k] = parsedInput[k] as any;
|
cleaned[k] = parsedInput[k] as any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +279,7 @@ const SimpleModelSettingsDialog = ({
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const sourcecodeOverridesLink = `https://github.com/voideditor/void/blob/d33b5ff9a32a748a22ac99e543a9eedd2e600062/src/vs/workbench/contrib/void/common/modelCapabilities.ts#L146-L170`
|
const sourcecodeOverridesLink = `https://github.com/voideditor/void/blob/2e5ecb291d33afbe4565921664fb7e183189c1c5/src/vs/workbench/contrib/void/common/modelCapabilities.ts#L146-L172`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div // Backdrop
|
<div // Backdrop
|
||||||
|
|
@ -343,10 +336,11 @@ const SimpleModelSettingsDialog = ({
|
||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
|
key={overrideEnabled + ''}
|
||||||
|
ref={textAreaRef}
|
||||||
className={`w-full min-h-[200px] p-2 rounded-sm border border-void-border-2 bg-void-bg-2 resize-none font-mono text-sm ${!overrideEnabled ? 'text-void-fg-3' : ''}`}
|
className={`w-full min-h-[200px] p-2 rounded-sm border border-void-border-2 bg-void-bg-2 resize-none font-mono text-sm ${!overrideEnabled ? 'text-void-fg-3' : ''}`}
|
||||||
value={overrideEnabled ? jsonText : placeholder}
|
defaultValue={overrideEnabled && currentOverrides ? JSON.stringify(currentOverrides, null, 2) : placeholder}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onChange={overrideEnabled ? (e) => setJsonText(e.target.value) : undefined}
|
|
||||||
readOnly={!overrideEnabled}
|
readOnly={!overrideEnabled}
|
||||||
/>
|
/>
|
||||||
{errorMsg && (
|
{errorMsg && (
|
||||||
|
|
|
||||||
|
|
@ -89,10 +89,7 @@ registerAction2(class extends Action2 {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async run(accessor: ServicesAccessor): Promise<void> {
|
async run(accessor: ServicesAccessor): Promise<void> {
|
||||||
|
// Get services
|
||||||
|
|
||||||
// Get the views service to check if the sidebar is open
|
|
||||||
// const viewsService = accessor.get(IViewsService)
|
|
||||||
const commandService = accessor.get(ICommandService)
|
const commandService = accessor.get(ICommandService)
|
||||||
const viewsService = accessor.get(IViewsService)
|
const viewsService = accessor.get(IViewsService)
|
||||||
const metricsService = accessor.get(IMetricsService)
|
const metricsService = accessor.get(IMetricsService)
|
||||||
|
|
@ -101,31 +98,28 @@ registerAction2(class extends Action2 {
|
||||||
|
|
||||||
metricsService.capture('Ctrl+L', {})
|
metricsService.capture('Ctrl+L', {})
|
||||||
|
|
||||||
|
// capture selection and model before opening the chat panel
|
||||||
|
const editor = editorService.getActiveCodeEditor()
|
||||||
|
const model = editor?.getModel()
|
||||||
|
if (!model) return
|
||||||
|
|
||||||
|
const selectionRange = roundRangeToLines(editor?.getSelection(), { emptySelectionBehavior: 'null' })
|
||||||
|
|
||||||
|
// open panel
|
||||||
const wasAlreadyOpen = viewsService.isViewContainerVisible(VOID_VIEW_CONTAINER_ID)
|
const wasAlreadyOpen = viewsService.isViewContainerVisible(VOID_VIEW_CONTAINER_ID)
|
||||||
if (!wasAlreadyOpen) {
|
if (!wasAlreadyOpen) {
|
||||||
await commandService.executeCommand(VOID_OPEN_SIDEBAR_ACTION_ID)
|
await commandService.executeCommand(VOID_OPEN_SIDEBAR_ACTION_ID)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add selection to chat
|
||||||
// if was already open
|
|
||||||
|
|
||||||
const model = accessor.get(ICodeEditorService).getActiveCodeEditor()?.getModel()
|
|
||||||
if (!model) return
|
|
||||||
|
|
||||||
const editor = editorService.getActiveCodeEditor()
|
|
||||||
const selectionRange = roundRangeToLines(editor?.getSelection(), { emptySelectionBehavior: 'null' })
|
|
||||||
|
|
||||||
// if has no selection, close + return
|
|
||||||
// if (!selectionRange) {
|
|
||||||
// viewsService.closeViewContainer(VOID_VIEW_CONTAINER_ID);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// add line selection
|
// add line selection
|
||||||
if (selectionRange) {
|
if (selectionRange) {
|
||||||
editor?.setSelection({ startLineNumber: selectionRange.startLineNumber, endLineNumber: selectionRange.endLineNumber, startColumn: 1, endColumn: Number.MAX_SAFE_INTEGER })
|
editor?.setSelection({
|
||||||
|
startLineNumber: selectionRange.startLineNumber,
|
||||||
|
endLineNumber: selectionRange.endLineNumber,
|
||||||
|
startColumn: 1,
|
||||||
|
endColumn: Number.MAX_SAFE_INTEGER
|
||||||
|
})
|
||||||
chatThreadService.addNewStagingSelection({
|
chatThreadService.addNewStagingSelection({
|
||||||
type: 'CodeSelection',
|
type: 'CodeSelection',
|
||||||
uri: model.uri,
|
uri: model.uri,
|
||||||
|
|
@ -142,12 +136,9 @@ registerAction2(class extends Action2 {
|
||||||
language: model.getLanguageId(),
|
language: model.getLanguageId(),
|
||||||
state: { wasAddedAsCurrentFile: false },
|
state: { wasAddedAsCurrentFile: false },
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await chatThreadService.focusCurrentChat()
|
await chatThreadService.focusCurrentChat()
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,12 @@ export interface ITerminalToolService {
|
||||||
readonly _serviceBrand: undefined;
|
readonly _serviceBrand: undefined;
|
||||||
|
|
||||||
listPersistentTerminalIds(): string[];
|
listPersistentTerminalIds(): string[];
|
||||||
runCommand(command: string, opts: { type: 'persistent', persistentTerminalId: string } | { type: 'ephemeral', cwd: string | null, terminalId: string }): Promise<{ interrupt: () => void; resPromise: Promise<{ result: string, resolveReason: TerminalResolveReason }> }>;
|
runCommand(command: string, opts:
|
||||||
|
| { type: 'persistent', persistentTerminalId: string }
|
||||||
|
| { type: 'temporary', cwd: string | null, terminalId: string }
|
||||||
|
// | { type: 'apply', terminalId: string }
|
||||||
|
): Promise<{ interrupt: () => void; resPromise: Promise<{ result: string, resolveReason: TerminalResolveReason }> }>;
|
||||||
|
|
||||||
focusPersistentTerminal(terminalId: string): Promise<void>
|
focusPersistentTerminal(terminalId: string): Promise<void>
|
||||||
persistentTerminalExists(terminalId: string): boolean
|
persistentTerminalExists(terminalId: string): boolean
|
||||||
|
|
||||||
|
|
@ -277,6 +282,8 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ
|
||||||
terminal.dispose()
|
terminal.dispose()
|
||||||
if (!isPersistent)
|
if (!isPersistent)
|
||||||
delete this.temporaryTerminalInstanceOfId[params.terminalId]
|
delete this.temporaryTerminalInstanceOfId[params.terminalId]
|
||||||
|
else
|
||||||
|
delete this.persistentTerminalInstanceOfId[params.persistentTerminalId]
|
||||||
}
|
}
|
||||||
|
|
||||||
const waitForResult = async () => {
|
const waitForResult = async () => {
|
||||||
|
|
|
||||||
|
|
@ -430,7 +430,7 @@ export class ToolsService implements IToolsService {
|
||||||
},
|
},
|
||||||
// ---
|
// ---
|
||||||
run_command: async ({ command, cwd, terminalId }) => {
|
run_command: async ({ command, cwd, terminalId }) => {
|
||||||
const { resPromise, interrupt } = await this.terminalToolService.runCommand(command, { type: 'ephemeral', cwd, terminalId })
|
const { resPromise, interrupt } = await this.terminalToolService.runCommand(command, { type: 'temporary', cwd, terminalId })
|
||||||
return { result: resPromise, interruptTool: interrupt }
|
return { result: resPromise, interruptTool: interrupt }
|
||||||
},
|
},
|
||||||
run_persistent_command: async ({ command, persistentTerminalId }) => {
|
run_persistent_command: async ({ command, persistentTerminalId }) => {
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,9 @@ import './voidOnboardingService.js'
|
||||||
// register misc service
|
// register misc service
|
||||||
import './miscWokrbenchContrib.js'
|
import './miscWokrbenchContrib.js'
|
||||||
|
|
||||||
|
// register file service (for explorer context menu)
|
||||||
|
import './fileService.js'
|
||||||
|
|
||||||
// ---------- common (unclear if these actually need to be imported, because they're already imported wherever they're used) ----------
|
// ---------- common (unclear if these actually need to be imported, because they're already imported wherever they're used) ----------
|
||||||
|
|
||||||
// llmMessage
|
// llmMessage
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import Severity from '../../../../base/common/severity.js';
|
||||||
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
|
import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';
|
||||||
import { localize2 } from '../../../../nls.js';
|
import { localize2 } from '../../../../nls.js';
|
||||||
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
|
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
|
||||||
import { INotificationActions, INotificationService } from '../../../../platform/notification/common/notification.js';
|
import { INotificationActions, INotificationHandle, INotificationService } from '../../../../platform/notification/common/notification.js';
|
||||||
import { IMetricsService } from '../common/metricsService.js';
|
import { IMetricsService } from '../common/metricsService.js';
|
||||||
import { IVoidUpdateService } from '../common/voidUpdateService.js';
|
import { IVoidUpdateService } from '../common/voidUpdateService.js';
|
||||||
import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js';
|
import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js';
|
||||||
|
|
@ -20,7 +20,7 @@ import { IAction } from '../../../../base/common/actions.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const notifyUpdate = (res: VoidCheckUpdateRespose & { message: string }, notifService: INotificationService, updateService: IUpdateService) => {
|
const notifyUpdate = (res: VoidCheckUpdateRespose & { message: string }, notifService: INotificationService, updateService: IUpdateService): INotificationHandle => {
|
||||||
const message = res?.message || 'This is a very old version of Void, please download the latest version! [Void Editor](https://voideditor.com/download-beta)!'
|
const message = res?.message || 'This is a very old version of Void, please download the latest version! [Void Editor](https://voideditor.com/download-beta)!'
|
||||||
|
|
||||||
let actions: INotificationActions | undefined
|
let actions: INotificationActions | undefined
|
||||||
|
|
@ -119,18 +119,21 @@ const notifyUpdate = (res: VoidCheckUpdateRespose & { message: string }, notifSe
|
||||||
progress: actions ? { worked: 0, total: 100 } : undefined,
|
progress: actions ? { worked: 0, total: 100 } : undefined,
|
||||||
actions: actions,
|
actions: actions,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return notifController
|
||||||
// const d = notifController.onDidClose(() => {
|
// const d = notifController.onDidClose(() => {
|
||||||
// notifyYesUpdate(notifService, res)
|
// notifyYesUpdate(notifService, res)
|
||||||
// d.dispose()
|
// d.dispose()
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
const notifyErrChecking = (notifService: INotificationService) => {
|
const notifyErrChecking = (notifService: INotificationService): INotificationHandle => {
|
||||||
const message = `Void Error: There was an error checking for updates. If this persists, please get in touch or reinstall Void [here](https://voideditor.com/download-beta)!`
|
const message = `Void Error: There was an error checking for updates. If this persists, please get in touch or reinstall Void [here](https://voideditor.com/download-beta)!`
|
||||||
notifService.notify({
|
const notifController = notifService.notify({
|
||||||
severity: Severity.Info,
|
severity: Severity.Info,
|
||||||
message: message,
|
message: message,
|
||||||
sticky: true,
|
sticky: true,
|
||||||
})
|
})
|
||||||
|
return notifController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -140,30 +143,35 @@ const performVoidCheck = async (
|
||||||
voidUpdateService: IVoidUpdateService,
|
voidUpdateService: IVoidUpdateService,
|
||||||
metricsService: IMetricsService,
|
metricsService: IMetricsService,
|
||||||
updateService: IUpdateService,
|
updateService: IUpdateService,
|
||||||
) => {
|
): Promise<INotificationHandle | null> => {
|
||||||
|
|
||||||
const metricsTag = explicit ? 'Manual' : 'Auto'
|
const metricsTag = explicit ? 'Manual' : 'Auto'
|
||||||
|
|
||||||
metricsService.capture(`Void Update ${metricsTag}: Checking...`, {})
|
metricsService.capture(`Void Update ${metricsTag}: Checking...`, {})
|
||||||
const res = await voidUpdateService.check(explicit)
|
const res = await voidUpdateService.check(explicit)
|
||||||
if (!res) {
|
if (!res) {
|
||||||
notifyErrChecking(notifService);
|
const notifController = notifyErrChecking(notifService);
|
||||||
metricsService.capture(`Void Update ${metricsTag}: Error`, { res })
|
metricsService.capture(`Void Update ${metricsTag}: Error`, { res })
|
||||||
|
return notifController
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (res.message) {
|
if (res.message) {
|
||||||
notifyUpdate(res, notifService, updateService)
|
const notifController = notifyUpdate(res, notifService, updateService)
|
||||||
metricsService.capture(`Void Update ${metricsTag}: Yes`, { res })
|
metricsService.capture(`Void Update ${metricsTag}: Yes`, { res })
|
||||||
|
return notifController
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
metricsService.capture(`Void Update ${metricsTag}: No`, { res })
|
metricsService.capture(`Void Update ${metricsTag}: No`, { res })
|
||||||
return
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Action
|
// Action
|
||||||
|
let lastNotifController: INotificationHandle | null = null
|
||||||
|
|
||||||
|
|
||||||
registerAction2(class extends Action2 {
|
registerAction2(class extends Action2 {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
|
|
@ -177,7 +185,15 @@ registerAction2(class extends Action2 {
|
||||||
const notifService = accessor.get(INotificationService)
|
const notifService = accessor.get(INotificationService)
|
||||||
const metricsService = accessor.get(IMetricsService)
|
const metricsService = accessor.get(IMetricsService)
|
||||||
const updateService = accessor.get(IUpdateService)
|
const updateService = accessor.get(IUpdateService)
|
||||||
performVoidCheck(true, notifService, voidUpdateService, metricsService, updateService)
|
|
||||||
|
const currNotifController = lastNotifController
|
||||||
|
|
||||||
|
const newController = await performVoidCheck(true, notifService, voidUpdateService, metricsService, updateService)
|
||||||
|
|
||||||
|
if (newController) {
|
||||||
|
currNotifController?.close()
|
||||||
|
lastNotifController = newController
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,14 +78,16 @@ export const defaultModelsOfProvider = {
|
||||||
// 'gpt-4o-mini',
|
// 'gpt-4o-mini',
|
||||||
],
|
],
|
||||||
anthropic: [ // https://docs.anthropic.com/en/docs/about-claude/models
|
anthropic: [ // https://docs.anthropic.com/en/docs/about-claude/models
|
||||||
|
'claude-opus-4-0',
|
||||||
|
'claude-sonnet-4-0',
|
||||||
'claude-3-7-sonnet-latest',
|
'claude-3-7-sonnet-latest',
|
||||||
'claude-3-5-sonnet-latest',
|
'claude-3-5-sonnet-latest',
|
||||||
'claude-3-5-haiku-latest',
|
'claude-3-5-haiku-latest',
|
||||||
'claude-3-opus-latest',
|
'claude-3-opus-latest',
|
||||||
],
|
],
|
||||||
xAI: [ // https://docs.x.ai/docs/models?cluster=us-east-1
|
xAI: [ // https://docs.x.ai/docs/models?cluster=us-east-1
|
||||||
'grok-2-latest',
|
'grok-2',
|
||||||
'grok-3-latest',
|
'grok-3',
|
||||||
],
|
],
|
||||||
gemini: [ // https://ai.google.dev/gemini-api/docs/models/gemini
|
gemini: [ // https://ai.google.dev/gemini-api/docs/models/gemini
|
||||||
'gemini-2.5-pro-exp-03-25',
|
'gemini-2.5-pro-exp-03-25',
|
||||||
|
|
@ -106,11 +108,14 @@ export const defaultModelsOfProvider = {
|
||||||
|
|
||||||
openRouter: [ // https://openrouter.ai/models
|
openRouter: [ // https://openrouter.ai/models
|
||||||
// 'anthropic/claude-3.7-sonnet:thinking',
|
// 'anthropic/claude-3.7-sonnet:thinking',
|
||||||
|
'anthropic/claude-opus-4',
|
||||||
|
'anthropic/claude-sonnet-4',
|
||||||
'qwen/qwen3-235b-a22b',
|
'qwen/qwen3-235b-a22b',
|
||||||
'anthropic/claude-3.7-sonnet',
|
'anthropic/claude-3.7-sonnet',
|
||||||
'anthropic/claude-3.5-sonnet',
|
'anthropic/claude-3.5-sonnet',
|
||||||
'deepseek/deepseek-r1',
|
'deepseek/deepseek-r1',
|
||||||
'deepseek/deepseek-r1-zero:free',
|
'deepseek/deepseek-r1-zero:free',
|
||||||
|
'mistralai/devstral-small:free'
|
||||||
// 'openrouter/quasar-alpha',
|
// 'openrouter/quasar-alpha',
|
||||||
// 'google/gemini-2.5-pro-preview-03-25',
|
// 'google/gemini-2.5-pro-preview-03-25',
|
||||||
// 'mistralai/codestral-2501',
|
// 'mistralai/codestral-2501',
|
||||||
|
|
@ -128,6 +133,7 @@ export const defaultModelsOfProvider = {
|
||||||
],
|
],
|
||||||
mistral: [ // https://docs.mistral.ai/getting-started/models/models_overview/
|
mistral: [ // https://docs.mistral.ai/getting-started/models/models_overview/
|
||||||
'codestral-latest',
|
'codestral-latest',
|
||||||
|
'devstral-small-latest',
|
||||||
'mistral-large-latest',
|
'mistral-large-latest',
|
||||||
'mistral-medium-latest',
|
'mistral-medium-latest',
|
||||||
'ministral-3b-latest',
|
'ministral-3b-latest',
|
||||||
|
|
@ -154,6 +160,8 @@ export type VoidStaticModelInfo = { // not stateful
|
||||||
specialToolFormat?: 'openai-style' | 'anthropic-style' | 'gemini-style', // typically you should use 'openai-style'. null means "can't call tools by default", and asks the LLM to output XML in agent mode
|
specialToolFormat?: 'openai-style' | 'anthropic-style' | 'gemini-style', // typically you should use 'openai-style'. null means "can't call tools by default", and asks the LLM to output XML in agent mode
|
||||||
supportsFIM: boolean; // whether the model was specifically designed for autocomplete or "FIM" ("fill-in-middle" format)
|
supportsFIM: boolean; // whether the model was specifically designed for autocomplete or "FIM" ("fill-in-middle" format)
|
||||||
|
|
||||||
|
additionalOpenAIPayload?: { [key: string]: string } // additional payload in the message body for requests that are openai-compatible (ollama, vllm, openai, openrouter, etc)
|
||||||
|
|
||||||
// reasoning options
|
// reasoning options
|
||||||
reasoningCapabilities: false | {
|
reasoningCapabilities: false | {
|
||||||
readonly supportsReasoning: true; // for clarity, this must be true if anything below is specified
|
readonly supportsReasoning: true; // for clarity, this must be true if anything below is specified
|
||||||
|
|
@ -186,8 +194,20 @@ export type VoidStaticModelInfo = { // not stateful
|
||||||
// if you change the above type, remember to update the Settings link
|
// if you change the above type, remember to update the Settings link
|
||||||
|
|
||||||
|
|
||||||
export type ModelOverrides = Pick<VoidStaticModelInfo,
|
|
||||||
'contextWindow' | 'reservedOutputTokenSpace' | 'specialToolFormat' | 'supportsSystemMessage' | 'supportsFIM' | 'reasoningCapabilities'
|
export const modelOverrideKeys = [
|
||||||
|
'contextWindow',
|
||||||
|
'reservedOutputTokenSpace',
|
||||||
|
'supportsSystemMessage',
|
||||||
|
'specialToolFormat',
|
||||||
|
'supportsFIM',
|
||||||
|
'reasoningCapabilities',
|
||||||
|
'additionalOpenAIPayload'
|
||||||
|
] as const
|
||||||
|
|
||||||
|
export type ModelOverrides = Pick<
|
||||||
|
VoidStaticModelInfo,
|
||||||
|
(typeof modelOverrideKeys)[number]
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -249,6 +269,12 @@ const openSourceModelOptions_assumingOAICompat = {
|
||||||
reasoningCapabilities: false,
|
reasoningCapabilities: false,
|
||||||
contextWindow: 32_000, reservedOutputTokenSpace: 4_096,
|
contextWindow: 32_000, reservedOutputTokenSpace: 4_096,
|
||||||
},
|
},
|
||||||
|
'devstral': {
|
||||||
|
supportsFIM: false,
|
||||||
|
supportsSystemMessage: 'system-role',
|
||||||
|
reasoningCapabilities: false,
|
||||||
|
contextWindow: 131_000, reservedOutputTokenSpace: 8_192,
|
||||||
|
},
|
||||||
'openhands-lm-32b': { // https://www.all-hands.dev/blog/introducing-openhands-lm-32b----a-strong-open-coding-agent-model
|
'openhands-lm-32b': { // https://www.all-hands.dev/blog/introducing-openhands-lm-32b----a-strong-open-coding-agent-model
|
||||||
supportsFIM: false,
|
supportsFIM: false,
|
||||||
supportsSystemMessage: 'system-role',
|
supportsSystemMessage: 'system-role',
|
||||||
|
|
@ -363,22 +389,28 @@ const extensiveModelOptionsFallback: VoidStaticProviderInfo['modelOptionsFallbac
|
||||||
: VoidStaticModelInfo & { modelName: string, recognizedModelName: string } => {
|
: VoidStaticModelInfo & { modelName: string, recognizedModelName: string } => {
|
||||||
|
|
||||||
const opts = obj[recognizedModelName]
|
const opts = obj[recognizedModelName]
|
||||||
|
const supportsSystemMessage = opts.supportsSystemMessage === 'separated'
|
||||||
|
? 'system-role'
|
||||||
|
: opts.supportsSystemMessage
|
||||||
|
|
||||||
return {
|
return {
|
||||||
recognizedModelName,
|
recognizedModelName,
|
||||||
modelName,
|
modelName,
|
||||||
...opts,
|
...opts,
|
||||||
supportsSystemMessage: opts.supportsSystemMessage ? 'system-role' : false,
|
supportsSystemMessage: supportsSystemMessage,
|
||||||
cost: { input: 0, output: 0 },
|
cost: { input: 0, output: 0 },
|
||||||
downloadable: false,
|
downloadable: false,
|
||||||
...fallbackKnownValues
|
...fallbackKnownValues
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lower.includes('gemini') && (lower.includes('2.5') || lower.includes('2-5'))) return toFallback(geminiModelOptions, 'gemini-2.5-pro-exp-03-25')
|
if (lower.includes('gemini') && (lower.includes('2.5') || lower.includes('2-5'))) return toFallback(geminiModelOptions, 'gemini-2.5-pro-exp-03-25')
|
||||||
|
|
||||||
if (lower.includes('claude-3-5') || lower.includes('claude-3.5')) return toFallback(anthropicModelOptions, 'claude-3-5-sonnet-20241022')
|
if (lower.includes('claude-3-5') || lower.includes('claude-3.5')) return toFallback(anthropicModelOptions, 'claude-3-5-sonnet-20241022')
|
||||||
if (lower.includes('claude')) return toFallback(anthropicModelOptions, 'claude-3-7-sonnet-20250219')
|
if (lower.includes('claude')) return toFallback(anthropicModelOptions, 'claude-3-7-sonnet-20250219')
|
||||||
|
|
||||||
if (lower.includes('grok')) return toFallback(xAIModelOptions, 'grok-2')
|
if (lower.includes('grok2') || lower.includes('grok2')) return toFallback(xAIModelOptions, 'grok-2')
|
||||||
|
if (lower.includes('grok')) return toFallback(xAIModelOptions, 'grok-3')
|
||||||
|
|
||||||
if (lower.includes('deepseek-r1') || lower.includes('deepseek-reasoner')) return toFallback(openSourceModelOptions_assumingOAICompat, 'deepseekR1')
|
if (lower.includes('deepseek-r1') || lower.includes('deepseek-reasoner')) return toFallback(openSourceModelOptions_assumingOAICompat, 'deepseekR1')
|
||||||
if (lower.includes('deepseek') && lower.includes('v2')) return toFallback(openSourceModelOptions_assumingOAICompat, 'deepseekCoderV2')
|
if (lower.includes('deepseek') && lower.includes('v2')) return toFallback(openSourceModelOptions_assumingOAICompat, 'deepseekCoderV2')
|
||||||
|
|
@ -398,6 +430,7 @@ const extensiveModelOptionsFallback: VoidStaticProviderInfo['modelOptionsFallbac
|
||||||
if (lower.includes('qwq')) { return toFallback(openSourceModelOptions_assumingOAICompat, 'qwq') }
|
if (lower.includes('qwq')) { return toFallback(openSourceModelOptions_assumingOAICompat, 'qwq') }
|
||||||
if (lower.includes('phi4')) return toFallback(openSourceModelOptions_assumingOAICompat, 'phi4')
|
if (lower.includes('phi4')) return toFallback(openSourceModelOptions_assumingOAICompat, 'phi4')
|
||||||
if (lower.includes('codestral')) return toFallback(openSourceModelOptions_assumingOAICompat, 'codestral')
|
if (lower.includes('codestral')) return toFallback(openSourceModelOptions_assumingOAICompat, 'codestral')
|
||||||
|
if (lower.includes('devstral')) return toFallback(openSourceModelOptions_assumingOAICompat, 'devstral')
|
||||||
|
|
||||||
if (lower.includes('gemma')) return toFallback(openSourceModelOptions_assumingOAICompat, 'gemma')
|
if (lower.includes('gemma')) return toFallback(openSourceModelOptions_assumingOAICompat, 'gemma')
|
||||||
|
|
||||||
|
|
@ -450,6 +483,40 @@ const anthropicModelOptions = {
|
||||||
reasoningSlider: { type: 'budget_slider', min: 1024, max: 8192, default: 1024 }, // they recommend batching if max > 32_000. we cap at 8192 because above is typically not necessary (often even buggy)
|
reasoningSlider: { type: 'budget_slider', min: 1024, max: 8192, default: 1024 }, // they recommend batching if max > 32_000. we cap at 8192 because above is typically not necessary (often even buggy)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
'claude-opus-4-20250514': {
|
||||||
|
contextWindow: 200_000,
|
||||||
|
reservedOutputTokenSpace: 8_192,
|
||||||
|
cost: { input: 15.00, cache_read: 1.50, cache_write: 18.75, output: 30.00 },
|
||||||
|
downloadable: false,
|
||||||
|
supportsFIM: false,
|
||||||
|
specialToolFormat: 'anthropic-style',
|
||||||
|
supportsSystemMessage: 'separated',
|
||||||
|
reasoningCapabilities: {
|
||||||
|
supportsReasoning: true,
|
||||||
|
canTurnOffReasoning: true,
|
||||||
|
canIOReasoning: true,
|
||||||
|
reasoningReservedOutputTokenSpace: 8192, // can bump it to 128_000 with beta mode output-128k-2025-02-19
|
||||||
|
reasoningSlider: { type: 'budget_slider', min: 1024, max: 8192, default: 1024 }, // they recommend batching if max > 32_000. we cap at 8192 because above is typically not necessary (often even buggy)
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
'claude-sonnet-4-20250514': {
|
||||||
|
contextWindow: 200_000,
|
||||||
|
reservedOutputTokenSpace: 8_192,
|
||||||
|
cost: { input: 3.00, cache_read: 0.30, cache_write: 3.75, output: 6.00 },
|
||||||
|
downloadable: false,
|
||||||
|
supportsFIM: false,
|
||||||
|
specialToolFormat: 'anthropic-style',
|
||||||
|
supportsSystemMessage: 'separated',
|
||||||
|
reasoningCapabilities: {
|
||||||
|
supportsReasoning: true,
|
||||||
|
canTurnOffReasoning: true,
|
||||||
|
canIOReasoning: true,
|
||||||
|
reasoningReservedOutputTokenSpace: 8192, // can bump it to 128_000 with beta mode output-128k-2025-02-19
|
||||||
|
reasoningSlider: { type: 'budget_slider', min: 1024, max: 8192, default: 1024 }, // they recommend batching if max > 32_000. we cap at 8192 because above is typically not necessary (often even buggy)
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
'claude-3-5-sonnet-20241022': {
|
'claude-3-5-sonnet-20241022': {
|
||||||
contextWindow: 200_000,
|
contextWindow: 200_000,
|
||||||
|
|
@ -509,6 +576,10 @@ const anthropicSettings: VoidStaticProviderInfo = {
|
||||||
modelOptionsFallback: (modelName) => {
|
modelOptionsFallback: (modelName) => {
|
||||||
const lower = modelName.toLowerCase()
|
const lower = modelName.toLowerCase()
|
||||||
let fallbackName: keyof typeof anthropicModelOptions | null = null
|
let fallbackName: keyof typeof anthropicModelOptions | null = null
|
||||||
|
if (lower.includes('claude-4-opus') || lower.includes('claude-opus-4')) fallbackName = 'claude-opus-4-20250514'
|
||||||
|
if (lower.includes('claude-4-sonnet') || lower.includes('claude-sonnet-4')) fallbackName = 'claude-sonnet-4-20250514'
|
||||||
|
|
||||||
|
|
||||||
if (lower.includes('claude-3-7-sonnet')) fallbackName = 'claude-3-7-sonnet-20250219'
|
if (lower.includes('claude-3-7-sonnet')) fallbackName = 'claude-3-7-sonnet-20250219'
|
||||||
if (lower.includes('claude-3-5-sonnet')) fallbackName = 'claude-3-5-sonnet-20241022'
|
if (lower.includes('claude-3-5-sonnet')) fallbackName = 'claude-3-5-sonnet-20241022'
|
||||||
if (lower.includes('claude-3-5-haiku')) fallbackName = 'claude-3-5-haiku-20241022'
|
if (lower.includes('claude-3-5-haiku')) fallbackName = 'claude-3-5-haiku-20241022'
|
||||||
|
|
@ -622,6 +693,16 @@ const openAIModelOptions = { // https://platform.openai.com/docs/pricing
|
||||||
} as const satisfies { [s: string]: VoidStaticModelInfo }
|
} as const satisfies { [s: string]: VoidStaticModelInfo }
|
||||||
|
|
||||||
|
|
||||||
|
// https://platform.openai.com/docs/guides/reasoning?api-mode=chat
|
||||||
|
const openAICompatIncludeInPayloadReasoning = (reasoningInfo: SendableReasoningInfo) => {
|
||||||
|
if (!reasoningInfo?.isReasoningEnabled) return null
|
||||||
|
if (reasoningInfo.type === 'effort_slider_value') {
|
||||||
|
return { reasoning_effort: reasoningInfo.reasoningEffort }
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const openAISettings: VoidStaticProviderInfo = {
|
const openAISettings: VoidStaticProviderInfo = {
|
||||||
modelOptions: openAIModelOptions,
|
modelOptions: openAIModelOptions,
|
||||||
modelOptionsFallback: (modelName) => {
|
modelOptionsFallback: (modelName) => {
|
||||||
|
|
@ -634,17 +715,7 @@ const openAISettings: VoidStaticProviderInfo = {
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
providerReasoningIOSettings: {
|
providerReasoningIOSettings: {
|
||||||
input: {
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
// https://platform.openai.com/docs/guides/reasoning?api-mode=chat
|
|
||||||
includeInPayload: (reasoningInfo) => {
|
|
||||||
if (!reasoningInfo?.isReasoningEnabled) return null
|
|
||||||
|
|
||||||
if (reasoningInfo.type === 'effort_slider_value') {
|
|
||||||
return { reasoning_effort: reasoningInfo.reasoningEffort }
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -659,6 +730,7 @@ const xAIModelOptions = {
|
||||||
downloadable: false,
|
downloadable: false,
|
||||||
supportsFIM: false,
|
supportsFIM: false,
|
||||||
supportsSystemMessage: 'system-role',
|
supportsSystemMessage: 'system-role',
|
||||||
|
specialToolFormat: 'openai-style',
|
||||||
reasoningCapabilities: false,
|
reasoningCapabilities: false,
|
||||||
},
|
},
|
||||||
'grok-3': {
|
'grok-3': {
|
||||||
|
|
@ -668,6 +740,7 @@ const xAIModelOptions = {
|
||||||
downloadable: false,
|
downloadable: false,
|
||||||
supportsFIM: false,
|
supportsFIM: false,
|
||||||
supportsSystemMessage: 'system-role',
|
supportsSystemMessage: 'system-role',
|
||||||
|
specialToolFormat: 'openai-style',
|
||||||
reasoningCapabilities: false,
|
reasoningCapabilities: false,
|
||||||
},
|
},
|
||||||
'grok-3-fast': {
|
'grok-3-fast': {
|
||||||
|
|
@ -677,6 +750,7 @@ const xAIModelOptions = {
|
||||||
downloadable: false,
|
downloadable: false,
|
||||||
supportsFIM: false,
|
supportsFIM: false,
|
||||||
supportsSystemMessage: 'system-role',
|
supportsSystemMessage: 'system-role',
|
||||||
|
specialToolFormat: 'openai-style',
|
||||||
reasoningCapabilities: false,
|
reasoningCapabilities: false,
|
||||||
},
|
},
|
||||||
// only mini supports thinking
|
// only mini supports thinking
|
||||||
|
|
@ -687,6 +761,7 @@ const xAIModelOptions = {
|
||||||
downloadable: false,
|
downloadable: false,
|
||||||
supportsFIM: false,
|
supportsFIM: false,
|
||||||
supportsSystemMessage: 'system-role',
|
supportsSystemMessage: 'system-role',
|
||||||
|
specialToolFormat: 'openai-style',
|
||||||
reasoningCapabilities: { supportsReasoning: true, canTurnOffReasoning: false, canIOReasoning: false, reasoningSlider: { type: 'effort_slider', values: ['low', 'high'], default: 'low' } },
|
reasoningCapabilities: { supportsReasoning: true, canTurnOffReasoning: false, canIOReasoning: false, reasoningSlider: { type: 'effort_slider', values: ['low', 'high'], default: 'low' } },
|
||||||
},
|
},
|
||||||
'grok-3-mini-fast': {
|
'grok-3-mini-fast': {
|
||||||
|
|
@ -696,6 +771,7 @@ const xAIModelOptions = {
|
||||||
downloadable: false,
|
downloadable: false,
|
||||||
supportsFIM: false,
|
supportsFIM: false,
|
||||||
supportsSystemMessage: 'system-role',
|
supportsSystemMessage: 'system-role',
|
||||||
|
specialToolFormat: 'openai-style',
|
||||||
reasoningCapabilities: { supportsReasoning: true, canTurnOffReasoning: false, canIOReasoning: false, reasoningSlider: { type: 'effort_slider', values: ['low', 'high'], default: 'low' } },
|
reasoningCapabilities: { supportsReasoning: true, canTurnOffReasoning: false, canIOReasoning: false, reasoningSlider: { type: 'effort_slider', values: ['low', 'high'], default: 'low' } },
|
||||||
},
|
},
|
||||||
} as const satisfies { [s: string]: VoidStaticModelInfo }
|
} as const satisfies { [s: string]: VoidStaticModelInfo }
|
||||||
|
|
@ -706,11 +782,15 @@ const xAISettings: VoidStaticProviderInfo = {
|
||||||
const lower = modelName.toLowerCase()
|
const lower = modelName.toLowerCase()
|
||||||
let fallbackName: keyof typeof xAIModelOptions | null = null
|
let fallbackName: keyof typeof xAIModelOptions | null = null
|
||||||
if (lower.includes('grok-2')) fallbackName = 'grok-2'
|
if (lower.includes('grok-2')) fallbackName = 'grok-2'
|
||||||
|
if (lower.includes('grok-3')) fallbackName = 'grok-3'
|
||||||
|
if (lower.includes('grok')) fallbackName = 'grok-3'
|
||||||
if (fallbackName) return { modelName: fallbackName, recognizedModelName: fallbackName, ...xAIModelOptions[fallbackName] }
|
if (fallbackName) return { modelName: fallbackName, recognizedModelName: fallbackName, ...xAIModelOptions[fallbackName] }
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
// same implementation as openai
|
// same implementation as openai
|
||||||
providerReasoningIOSettings: openAISettings.providerReasoningIOSettings,
|
providerReasoningIOSettings: {
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -783,13 +863,7 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
|
||||||
supportsFIM: false,
|
supportsFIM: false,
|
||||||
supportsSystemMessage: 'separated',
|
supportsSystemMessage: 'separated',
|
||||||
specialToolFormat: 'gemini-style',
|
specialToolFormat: 'gemini-style',
|
||||||
reasoningCapabilities: { // thinking: experimental as of 5-10-25
|
reasoningCapabilities: false,
|
||||||
supportsReasoning: true,
|
|
||||||
canTurnOffReasoning: true,
|
|
||||||
canIOReasoning: false,
|
|
||||||
reasoningSlider: { type: 'budget_slider', min: 1024, max: 8192, default: 1024 }, // max is really 24576
|
|
||||||
reasoningReservedOutputTokenSpace: 8192,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'gemini-2.0-flash-lite-preview-02-05': {
|
'gemini-2.0-flash-lite-preview-02-05': {
|
||||||
contextWindow: 1_048_576,
|
contextWindow: 1_048_576,
|
||||||
|
|
@ -835,7 +909,7 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
|
||||||
|
|
||||||
const geminiSettings: VoidStaticProviderInfo = {
|
const geminiSettings: VoidStaticProviderInfo = {
|
||||||
modelOptions: geminiModelOptions,
|
modelOptions: geminiModelOptions,
|
||||||
modelOptionsFallback: (modelName) => { return null }
|
modelOptionsFallback: (modelName) => { return null },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -861,11 +935,12 @@ const deepseekModelOptions = {
|
||||||
|
|
||||||
const deepseekSettings: VoidStaticProviderInfo = {
|
const deepseekSettings: VoidStaticProviderInfo = {
|
||||||
modelOptions: deepseekModelOptions,
|
modelOptions: deepseekModelOptions,
|
||||||
|
modelOptionsFallback: (modelName) => { return null },
|
||||||
providerReasoningIOSettings: {
|
providerReasoningIOSettings: {
|
||||||
// reasoning: OAICompat + response.choices[0].delta.reasoning_content // https://api-docs.deepseek.com/guides/reasoning_model
|
// reasoning: OAICompat + response.choices[0].delta.reasoning_content // https://api-docs.deepseek.com/guides/reasoning_model
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
output: { nameOfFieldInDelta: 'reasoning_content' },
|
output: { nameOfFieldInDelta: 'reasoning_content' },
|
||||||
},
|
},
|
||||||
modelOptionsFallback: (modelName) => { return null }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -900,6 +975,17 @@ const mistralModelOptions = { // https://mistral.ai/products/la-plateforme#prici
|
||||||
supportsSystemMessage: 'system-role',
|
supportsSystemMessage: 'system-role',
|
||||||
reasoningCapabilities: false,
|
reasoningCapabilities: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'devstral-small-latest': { //https://openrouter.ai/mistralai/devstral-small:free
|
||||||
|
contextWindow: 131_000,
|
||||||
|
reservedOutputTokenSpace: 8_192,
|
||||||
|
cost: { input: 0, output: 0 },
|
||||||
|
supportsFIM: false,
|
||||||
|
downloadable: { sizeGb: 14 }, //https://ollama.com/library/devstral
|
||||||
|
supportsSystemMessage: 'system-role',
|
||||||
|
reasoningCapabilities: false,
|
||||||
|
},
|
||||||
|
|
||||||
'ministral-8b-latest': { // ollama 'mistral'
|
'ministral-8b-latest': { // ollama 'mistral'
|
||||||
contextWindow: 131_000,
|
contextWindow: 131_000,
|
||||||
reservedOutputTokenSpace: 4_096,
|
reservedOutputTokenSpace: 4_096,
|
||||||
|
|
@ -923,6 +1009,9 @@ const mistralModelOptions = { // https://mistral.ai/products/la-plateforme#prici
|
||||||
const mistralSettings: VoidStaticProviderInfo = {
|
const mistralSettings: VoidStaticProviderInfo = {
|
||||||
modelOptions: mistralModelOptions,
|
modelOptions: mistralModelOptions,
|
||||||
modelOptionsFallback: (modelName) => { return null },
|
modelOptionsFallback: (modelName) => { return null },
|
||||||
|
providerReasoningIOSettings: {
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -966,11 +1055,13 @@ const groqModelOptions = { // https://console.groq.com/docs/models, https://groq
|
||||||
},
|
},
|
||||||
} as const satisfies { [s: string]: VoidStaticModelInfo }
|
} as const satisfies { [s: string]: VoidStaticModelInfo }
|
||||||
const groqSettings: VoidStaticProviderInfo = {
|
const groqSettings: VoidStaticProviderInfo = {
|
||||||
|
modelOptions: groqModelOptions,
|
||||||
|
modelOptionsFallback: (modelName) => { return null },
|
||||||
providerReasoningIOSettings: {
|
providerReasoningIOSettings: {
|
||||||
|
// Must be set to either parsed or hidden when using tool calling https://console.groq.com/docs/reasoning
|
||||||
input: {
|
input: {
|
||||||
includeInPayload: (reasoningInfo) => {
|
includeInPayload: (reasoningInfo) => {
|
||||||
if (!reasoningInfo?.isReasoningEnabled) return null
|
if (!reasoningInfo?.isReasoningEnabled) return null
|
||||||
|
|
||||||
if (reasoningInfo.type === 'budget_slider_value') {
|
if (reasoningInfo.type === 'budget_slider_value') {
|
||||||
return { reasoning_format: 'parsed' }
|
return { reasoning_format: 'parsed' }
|
||||||
}
|
}
|
||||||
|
|
@ -978,9 +1069,7 @@ const groqSettings: VoidStaticProviderInfo = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
output: { nameOfFieldInDelta: 'reasoning' },
|
output: { nameOfFieldInDelta: 'reasoning' },
|
||||||
}, // Must be set to either parsed or hidden when using tool calling https://console.groq.com/docs/reasoning
|
},
|
||||||
modelOptions: groqModelOptions,
|
|
||||||
modelOptionsFallback: (modelName) => { return null }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -989,7 +1078,10 @@ const googleVertexModelOptions = {
|
||||||
} as const satisfies Record<string, VoidStaticModelInfo>
|
} as const satisfies Record<string, VoidStaticModelInfo>
|
||||||
const googleVertexSettings: VoidStaticProviderInfo = {
|
const googleVertexSettings: VoidStaticProviderInfo = {
|
||||||
modelOptions: googleVertexModelOptions,
|
modelOptions: googleVertexModelOptions,
|
||||||
modelOptionsFallback: (modelName) => { return null }
|
modelOptionsFallback: (modelName) => { return null },
|
||||||
|
providerReasoningIOSettings: {
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- MICROSOFT AZURE ----------------
|
// ---------------- MICROSOFT AZURE ----------------
|
||||||
|
|
@ -997,7 +1089,10 @@ const microsoftAzureModelOptions = {
|
||||||
} as const satisfies Record<string, VoidStaticModelInfo>
|
} as const satisfies Record<string, VoidStaticModelInfo>
|
||||||
const microsoftAzureSettings: VoidStaticProviderInfo = {
|
const microsoftAzureSettings: VoidStaticProviderInfo = {
|
||||||
modelOptions: microsoftAzureModelOptions,
|
modelOptions: microsoftAzureModelOptions,
|
||||||
modelOptionsFallback: (modelName) => { return null }
|
modelOptionsFallback: (modelName) => { return null },
|
||||||
|
providerReasoningIOSettings: {
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1066,42 +1161,66 @@ const ollamaModelOptions = {
|
||||||
supportsSystemMessage: 'system-role',
|
supportsSystemMessage: 'system-role',
|
||||||
reasoningCapabilities: { supportsReasoning: true, canIOReasoning: false, canTurnOffReasoning: false, openSourceThinkTags: ['<think>', '</think>'] },
|
reasoningCapabilities: { supportsReasoning: true, canIOReasoning: false, canTurnOffReasoning: false, openSourceThinkTags: ['<think>', '</think>'] },
|
||||||
},
|
},
|
||||||
|
'devstral:latest': {
|
||||||
|
contextWindow: 131_000,
|
||||||
|
reservedOutputTokenSpace: 8_192,
|
||||||
|
cost: { input: 0, output: 0 },
|
||||||
|
downloadable: { sizeGb: 14 },
|
||||||
|
supportsFIM: false,
|
||||||
|
supportsSystemMessage: 'system-role',
|
||||||
|
reasoningCapabilities: false,
|
||||||
|
},
|
||||||
|
|
||||||
} as const satisfies Record<string, VoidStaticModelInfo>
|
} as const satisfies Record<string, VoidStaticModelInfo>
|
||||||
|
|
||||||
export const ollamaRecommendedModels = ['qwen2.5-coder:1.5b', 'llama3.1', 'qwq', 'deepseek-r1'] as const satisfies (keyof typeof ollamaModelOptions)[]
|
export const ollamaRecommendedModels = ['qwen2.5-coder:1.5b', 'llama3.1', 'qwq', 'deepseek-r1', 'devstral:latest'] as const satisfies (keyof typeof ollamaModelOptions)[]
|
||||||
|
|
||||||
|
|
||||||
const vLLMSettings: VoidStaticProviderInfo = {
|
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) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
|
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
|
||||||
modelOptions: {}, // TODO
|
modelOptions: {},
|
||||||
|
providerReasoningIOSettings: {
|
||||||
|
// reasoning: OAICompat + response.choices[0].delta.reasoning_content // https://docs.vllm.ai/en/stable/features/reasoning_outputs.html#streaming-chat-completions
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
output: { nameOfFieldInDelta: 'reasoning_content' },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const lmStudioSettings: VoidStaticProviderInfo = {
|
const lmStudioSettings: VoidStaticProviderInfo = {
|
||||||
providerReasoningIOSettings: { output: { needsManualParse: true }, },
|
|
||||||
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' }, contextWindow: 4_096 }),
|
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' }, contextWindow: 4_096 }),
|
||||||
modelOptions: {}, // TODO
|
modelOptions: {},
|
||||||
|
providerReasoningIOSettings: {
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
output: { needsManualParse: true },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const ollamaSettings: VoidStaticProviderInfo = {
|
const ollamaSettings: VoidStaticProviderInfo = {
|
||||||
// reasoning: we need to filter out reasoning <think> tags manually
|
|
||||||
providerReasoningIOSettings: { output: { needsManualParse: true }, },
|
|
||||||
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
|
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
|
||||||
modelOptions: ollamaModelOptions,
|
modelOptions: ollamaModelOptions,
|
||||||
|
providerReasoningIOSettings: {
|
||||||
|
// reasoning: we need to filter out reasoning <think> tags manually
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
output: { needsManualParse: true },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const openaiCompatible: VoidStaticProviderInfo = {
|
const openaiCompatible: VoidStaticProviderInfo = {
|
||||||
// reasoning: we have no idea what endpoint they used, so we can't consistently parse out reasoning
|
|
||||||
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName),
|
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName),
|
||||||
modelOptions: {},
|
modelOptions: {},
|
||||||
|
providerReasoningIOSettings: {
|
||||||
|
// reasoning: we have no idea what endpoint they used, so we can't consistently parse out reasoning
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const liteLLMSettings: VoidStaticProviderInfo = { // https://docs.litellm.ai/docs/reasoning_content
|
const liteLLMSettings: VoidStaticProviderInfo = { // https://docs.litellm.ai/docs/reasoning_content
|
||||||
providerReasoningIOSettings: { output: { nameOfFieldInDelta: 'reasoning_content' } },
|
|
||||||
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
|
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
|
||||||
modelOptions: {}, // TODO
|
modelOptions: {},
|
||||||
|
providerReasoningIOSettings: {
|
||||||
|
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
|
||||||
|
output: { nameOfFieldInDelta: 'reasoning_content' },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1168,6 +1287,24 @@ const openRouterModelOptions_assumingOpenAICompat = {
|
||||||
cost: { input: 0.8, output: 2.4 },
|
cost: { input: 0.8, output: 2.4 },
|
||||||
downloadable: false,
|
downloadable: false,
|
||||||
},
|
},
|
||||||
|
'anthropic/claude-opus-4': {
|
||||||
|
contextWindow: 200_000,
|
||||||
|
reservedOutputTokenSpace: null,
|
||||||
|
cost: { input: 15.00, output: 75.00 },
|
||||||
|
downloadable: false,
|
||||||
|
supportsFIM: false,
|
||||||
|
supportsSystemMessage: 'system-role',
|
||||||
|
reasoningCapabilities: false,
|
||||||
|
},
|
||||||
|
'anthropic/claude-sonnet-4': {
|
||||||
|
contextWindow: 200_000,
|
||||||
|
reservedOutputTokenSpace: null,
|
||||||
|
cost: { input: 15.00, output: 75.00 },
|
||||||
|
downloadable: false,
|
||||||
|
supportsFIM: false,
|
||||||
|
supportsSystemMessage: 'system-role',
|
||||||
|
reasoningCapabilities: false,
|
||||||
|
},
|
||||||
'anthropic/claude-3.7-sonnet:thinking': {
|
'anthropic/claude-3.7-sonnet:thinking': {
|
||||||
contextWindow: 200_000,
|
contextWindow: 200_000,
|
||||||
reservedOutputTokenSpace: null,
|
reservedOutputTokenSpace: null,
|
||||||
|
|
@ -1209,6 +1346,14 @@ const openRouterModelOptions_assumingOpenAICompat = {
|
||||||
downloadable: false,
|
downloadable: false,
|
||||||
reasoningCapabilities: false,
|
reasoningCapabilities: false,
|
||||||
},
|
},
|
||||||
|
'mistralai/devstral-small:free': {
|
||||||
|
...openSourceModelOptions_assumingOAICompat.devstral,
|
||||||
|
contextWindow: 130_000,
|
||||||
|
reservedOutputTokenSpace: null,
|
||||||
|
cost: { input: 0, output: 0 },
|
||||||
|
downloadable: false,
|
||||||
|
reasoningCapabilities: false,
|
||||||
|
},
|
||||||
'qwen/qwen-2.5-coder-32b-instruct': {
|
'qwen/qwen-2.5-coder-32b-instruct': {
|
||||||
...openSourceModelOptions_assumingOAICompat['qwen2.5coder'],
|
...openSourceModelOptions_assumingOAICompat['qwen2.5coder'],
|
||||||
contextWindow: 33_000,
|
contextWindow: 33_000,
|
||||||
|
|
@ -1226,8 +1371,18 @@ const openRouterModelOptions_assumingOpenAICompat = {
|
||||||
} as const satisfies { [s: string]: VoidStaticModelInfo }
|
} as const satisfies { [s: string]: VoidStaticModelInfo }
|
||||||
|
|
||||||
const openRouterSettings: VoidStaticProviderInfo = {
|
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
|
modelOptions: openRouterModelOptions_assumingOpenAICompat,
|
||||||
|
// TODO!!! send a query to openrouter to get the price, etc.
|
||||||
|
modelOptionsFallback: (modelName) => {
|
||||||
|
const res = extensiveModelOptionsFallback(modelName)
|
||||||
|
// openRouter does not support gemini-style, use openai-style instead
|
||||||
|
if (res?.specialToolFormat === 'gemini-style') {
|
||||||
|
res.specialToolFormat = 'openai-style'
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
providerReasoningIOSettings: {
|
providerReasoningIOSettings: {
|
||||||
|
// reasoning: OAICompat + response.choices[0].delta.reasoning : payload should have {include_reasoning: true} https://openrouter.ai/announcements/reasoning-tokens-for-thinking-models
|
||||||
input: {
|
input: {
|
||||||
// https://openrouter.ai/docs/use-cases/reasoning-tokens
|
// https://openrouter.ai/docs/use-cases/reasoning-tokens
|
||||||
includeInPayload: (reasoningInfo) => {
|
includeInPayload: (reasoningInfo) => {
|
||||||
|
|
@ -1251,16 +1406,6 @@ const openRouterSettings: VoidStaticProviderInfo = {
|
||||||
},
|
},
|
||||||
output: { nameOfFieldInDelta: 'reasoning' },
|
output: { nameOfFieldInDelta: 'reasoning' },
|
||||||
},
|
},
|
||||||
modelOptions: openRouterModelOptions_assumingOpenAICompat,
|
|
||||||
// TODO!!! send a query to openrouter to get the price, etc.
|
|
||||||
modelOptionsFallback: (modelName) => {
|
|
||||||
const res = extensiveModelOptionsFallback(modelName)
|
|
||||||
// openRouter does not support gemini-style, use openai-style instead
|
|
||||||
if (res?.specialToolFormat === 'gemini-style') {
|
|
||||||
res.specialToolFormat = 'openai-style'
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -481,7 +481,6 @@ ${directoryStr}
|
||||||
details.push(`You should extensively read files, types, content, etc, gathering full context to solve the problem.`)
|
details.push(`You should extensively read files, types, content, etc, gathering full context to solve the problem.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
details.push(`If you write any code blocks to the user (wrapped in triple backticks), please use this format:
|
details.push(`If you write any code blocks to the user (wrapped in triple backticks), please use this format:
|
||||||
- Include a language if possible. Terminal should have the language 'shell'.
|
- Include a language if possible. Terminal should have the language 'shell'.
|
||||||
- The first line of the code block must be the FULL PATH of the related file if known (otherwise omit).
|
- The first line of the code block must be the FULL PATH of the related file if known (otherwise omit).
|
||||||
|
|
@ -529,7 +528,9 @@ ${details.map((d, i) => `${i + 1}. ${d}`).join('\n\n')}`)
|
||||||
// chat_systemMessage({ chatMode, workspaceFolders: [], openedURIs: [], activeURI: 'pee', persistentTerminalIDs: [], directoryStr: 'lol', }))
|
// chat_systemMessage({ chatMode, workspaceFolders: [], openedURIs: [], activeURI: 'pee', persistentTerminalIDs: [], directoryStr: 'lol', }))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const readFile = async (fileService: IFileService, uri: URI, fileSizeLimit: number): Promise<{
|
export const DEFAULT_FILE_SIZE_LIMIT = 2_000_000
|
||||||
|
|
||||||
|
export const readFile = async (fileService: IFileService, uri: URI, fileSizeLimit: number): Promise<{
|
||||||
val: string,
|
val: string,
|
||||||
truncated: boolean,
|
truncated: boolean,
|
||||||
fullFileLen: number,
|
fullFileLen: number,
|
||||||
|
|
@ -553,46 +554,70 @@ const readFile = async (fileService: IFileService, uri: URI, fileSizeLimit: numb
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const messageOfSelection = async (
|
||||||
|
s: StagingSelectionItem,
|
||||||
|
opts: {
|
||||||
|
directoryStrService: IDirectoryStrService,
|
||||||
|
fileService: IFileService,
|
||||||
|
folderOpts: {
|
||||||
|
maxChildren: number,
|
||||||
|
maxCharsPerFile: number,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
const lineNumAddition = (range: [number, number]) => ` (lines ${range[0]}:${range[1]})`
|
||||||
|
|
||||||
|
if (s.type === 'File' || s.type === 'CodeSelection') {
|
||||||
|
const { val } = await readFile(opts.fileService, s.uri, DEFAULT_FILE_SIZE_LIMIT)
|
||||||
|
const lineNumAdd = s.type === 'CodeSelection' ? lineNumAddition(s.range) : ''
|
||||||
|
const content = val === null ? 'null' : `${tripleTick[0]}${s.language}\n${val}\n${tripleTick[1]}`
|
||||||
|
const str = `${s.uri.fsPath}${lineNumAdd}:\n${content}`
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
else if (s.type === 'Folder') {
|
||||||
|
const dirStr: string = await opts.directoryStrService.getDirectoryStrTool(s.uri)
|
||||||
|
const folderStructure = `${s.uri.fsPath} folder structure:${tripleTick[0]}\n${dirStr}\n${tripleTick[1]}`
|
||||||
|
|
||||||
|
const uris = await opts.directoryStrService.getAllURIsInDirectory(s.uri, { maxResults: opts.folderOpts.maxChildren })
|
||||||
|
const strOfFiles = await Promise.all(uris.map(async uri => {
|
||||||
|
const { val, truncated } = await readFile(opts.fileService, uri, opts.folderOpts.maxCharsPerFile)
|
||||||
|
const truncationStr = truncated ? `\n... file truncated ...` : ''
|
||||||
|
const content = val === null ? 'null' : `${tripleTick[0]}\n${val}${truncationStr}\n${tripleTick[1]}`
|
||||||
|
const str = `${uri.fsPath}:\n${content}`
|
||||||
|
return str
|
||||||
|
}))
|
||||||
|
const contentStr = [folderStructure, ...strOfFiles].join('\n\n')
|
||||||
|
return contentStr
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const chat_userMessageContent = async (
|
||||||
export const chat_userMessageContent = async (instructions: string, currSelns: StagingSelectionItem[] | null,
|
instructions: string,
|
||||||
opts: { directoryStrService: IDirectoryStrService, fileService: IFileService }
|
currSelns: StagingSelectionItem[] | null,
|
||||||
|
opts: {
|
||||||
|
directoryStrService: IDirectoryStrService,
|
||||||
|
fileService: IFileService
|
||||||
|
},
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
const lineNumAddition = (range: [number, number]) => ` (lines ${range[0]}:${range[1]})`
|
const selnsStrs = await Promise.all(
|
||||||
let selnsStrs: string[] = []
|
(currSelns ?? []).map(async (s) =>
|
||||||
selnsStrs = await Promise.all(currSelns?.map(async (s) => {
|
messageOfSelection(s, {
|
||||||
|
...opts,
|
||||||
|
folderOpts: { maxChildren: 100, maxCharsPerFile: 100_000, }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if (s.type === 'File' || s.type === 'CodeSelection') {
|
|
||||||
const { val } = await readFile(opts.fileService, s.uri, 2_000_000)
|
|
||||||
const lineNumAdd = s.type === 'CodeSelection' ? lineNumAddition(s.range) : ''
|
|
||||||
const content = val === null ? 'null' : `${tripleTick[0]}${s.language}\n${val}\n${tripleTick[1]}`
|
|
||||||
const str = `${s.uri.fsPath}${lineNumAdd}:\n${content}`
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
else if (s.type === 'Folder') {
|
|
||||||
const dirStr: string = await opts.directoryStrService.getDirectoryStrTool(s.uri)
|
|
||||||
const folderStructure = `${s.uri.fsPath} folder structure:${tripleTick[0]}\n${dirStr}\n${tripleTick[1]}`
|
|
||||||
|
|
||||||
const uris = await opts.directoryStrService.getAllURIsInDirectory(s.uri, { maxResults: 100 })
|
|
||||||
const strOfFiles = await Promise.all(uris.map(async uri => {
|
|
||||||
const { val, truncated } = await readFile(opts.fileService, uri, 100_000)
|
|
||||||
const truncationStr = truncated ? `\n... file truncated ...` : ''
|
|
||||||
const content = val === null ? 'null' : `${tripleTick[0]}\n${val}${truncationStr}\n${tripleTick[1]}`
|
|
||||||
const str = `${uri.fsPath}:\n${content}`
|
|
||||||
return str
|
|
||||||
}))
|
|
||||||
const contentStr = [folderStructure, ...strOfFiles].join('\n\n')
|
|
||||||
return contentStr
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return ''
|
|
||||||
}) ?? [])
|
|
||||||
|
|
||||||
const selnsStr = selnsStrs.join('\n') ?? ''
|
|
||||||
let str = ''
|
let str = ''
|
||||||
str += `${instructions}`
|
str += `${instructions}`
|
||||||
|
|
||||||
|
const selnsStr = selnsStrs.join('\n\n') ?? ''
|
||||||
if (selnsStr) str += `\n---\nSELECTIONS\n${selnsStr}`
|
if (selnsStr) str += `\n---\nSELECTIONS\n${selnsStr}`
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import Anthropic from '@anthropic-ai/sdk';
|
import Anthropic from '@anthropic-ai/sdk';
|
||||||
import { Ollama } from 'ollama';
|
import { Ollama } from 'ollama';
|
||||||
import OpenAI, { ClientOptions } from 'openai';
|
import OpenAI, { ClientOptions, AzureOpenAI } from 'openai';
|
||||||
import { MistralCore } from '@mistralai/mistralai/core.js';
|
import { MistralCore } from '@mistralai/mistralai/core.js';
|
||||||
import { fimComplete } from '@mistralai/mistralai/funcs/fimComplete.js';
|
import { fimComplete } from '@mistralai/mistralai/funcs/fimComplete.js';
|
||||||
import { Tool as GeminiTool, FunctionDeclaration, GoogleGenAI, ThinkingConfig, Schema, Type } from '@google/genai';
|
import { Tool as GeminiTool, FunctionDeclaration, GoogleGenAI, ThinkingConfig, Schema, Type } from '@google/genai';
|
||||||
|
|
@ -114,9 +114,12 @@ const newOpenAICompatibleSDK = async ({ settingsOfProvider, providerName, includ
|
||||||
}
|
}
|
||||||
else if (providerName === 'microsoftAzure') {
|
else if (providerName === 'microsoftAzure') {
|
||||||
// https://learn.microsoft.com/en-us/rest/api/aifoundry/model-inference/get-chat-completions/get-chat-completions?view=rest-aifoundry-model-inference-2024-05-01-preview&tabs=HTTP
|
// https://learn.microsoft.com/en-us/rest/api/aifoundry/model-inference/get-chat-completions/get-chat-completions?view=rest-aifoundry-model-inference-2024-05-01-preview&tabs=HTTP
|
||||||
|
// https://github.com/openai/openai-node?tab=readme-ov-file#microsoft-azure-openai
|
||||||
const thisConfig = settingsOfProvider[providerName]
|
const thisConfig = settingsOfProvider[providerName]
|
||||||
const baseURL = `https://${thisConfig.project}.services.ai.azure.com/api/models/chat/completions??api-version=${thisConfig.azureApiVersion}`
|
const endpoint = `https://${thisConfig.project}.openai.azure.com/`;
|
||||||
return new OpenAI({ baseURL: baseURL, apiKey: thisConfig.apiKey, ...commonPayloadOpts })
|
const apiVersion = thisConfig.azureApiVersion ?? '2024-04-01-preview';
|
||||||
|
const options = { endpoint, apiKey: thisConfig.apiKey, apiVersion };
|
||||||
|
return new AzureOpenAI({ ...options, ...commonPayloadOpts });
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (providerName === 'deepseek') {
|
else if (providerName === 'deepseek') {
|
||||||
|
|
@ -147,7 +150,12 @@ const newOpenAICompatibleSDK = async ({ settingsOfProvider, providerName, includ
|
||||||
|
|
||||||
const _sendOpenAICompatibleFIM = async ({ messages: { prefix, suffix, stopTokens }, onFinalMessage, onError, settingsOfProvider, modelName: modelName_, _setAborter, providerName, overridesOfModel }: SendFIMParams_Internal) => {
|
const _sendOpenAICompatibleFIM = async ({ messages: { prefix, suffix, stopTokens }, onFinalMessage, onError, settingsOfProvider, modelName: modelName_, _setAborter, providerName, overridesOfModel }: SendFIMParams_Internal) => {
|
||||||
|
|
||||||
const { modelName, supportsFIM } = getModelCapabilities(providerName, modelName_, overridesOfModel)
|
const {
|
||||||
|
modelName,
|
||||||
|
supportsFIM,
|
||||||
|
additionalOpenAIPayload,
|
||||||
|
} = getModelCapabilities(providerName, modelName_, overridesOfModel)
|
||||||
|
|
||||||
if (!supportsFIM) {
|
if (!supportsFIM) {
|
||||||
if (modelName === modelName_)
|
if (modelName === modelName_)
|
||||||
onError({ message: `Model ${modelName} does not support FIM.`, fullError: null })
|
onError({ message: `Model ${modelName} does not support FIM.`, fullError: null })
|
||||||
|
|
@ -156,7 +164,7 @@ const _sendOpenAICompatibleFIM = async ({ messages: { prefix, suffix, stopTokens
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const openai = await newOpenAICompatibleSDK({ providerName, settingsOfProvider })
|
const openai = await newOpenAICompatibleSDK({ providerName, settingsOfProvider, includeInPayload: additionalOpenAIPayload })
|
||||||
openai.completions
|
openai.completions
|
||||||
.create({
|
.create({
|
||||||
model: modelName,
|
model: modelName,
|
||||||
|
|
@ -236,6 +244,7 @@ const _sendOpenAICompatibleChat = async ({ messages, onText, onFinalMessage, onE
|
||||||
modelName,
|
modelName,
|
||||||
specialToolFormat,
|
specialToolFormat,
|
||||||
reasoningCapabilities,
|
reasoningCapabilities,
|
||||||
|
additionalOpenAIPayload,
|
||||||
} = getModelCapabilities(providerName, modelName_, overridesOfModel)
|
} = getModelCapabilities(providerName, modelName_, overridesOfModel)
|
||||||
|
|
||||||
const { providerReasoningIOSettings } = getProviderCapabilities(providerName)
|
const { providerReasoningIOSettings } = getProviderCapabilities(providerName)
|
||||||
|
|
@ -243,7 +252,11 @@ const _sendOpenAICompatibleChat = async ({ messages, onText, onFinalMessage, onE
|
||||||
// reasoning
|
// reasoning
|
||||||
const { canIOReasoning, openSourceThinkTags } = reasoningCapabilities || {}
|
const { canIOReasoning, openSourceThinkTags } = reasoningCapabilities || {}
|
||||||
const reasoningInfo = getSendableReasoningInfo('Chat', providerName, modelName_, modelSelectionOptions, overridesOfModel) // user's modelName_ here
|
const reasoningInfo = getSendableReasoningInfo('Chat', providerName, modelName_, modelSelectionOptions, overridesOfModel) // user's modelName_ here
|
||||||
const includeInPayload = providerReasoningIOSettings?.input?.includeInPayload?.(reasoningInfo) || {}
|
|
||||||
|
const includeInPayload = {
|
||||||
|
...providerReasoningIOSettings?.input?.includeInPayload?.(reasoningInfo),
|
||||||
|
...additionalOpenAIPayload
|
||||||
|
}
|
||||||
|
|
||||||
// tools
|
// tools
|
||||||
const potentialTools = chatMode !== null ? openAITools(chatMode) : null
|
const potentialTools = chatMode !== null ? openAITools(chatMode) : null
|
||||||
|
|
@ -253,11 +266,16 @@ const _sendOpenAICompatibleChat = async ({ messages, onText, onFinalMessage, onE
|
||||||
|
|
||||||
// instance
|
// instance
|
||||||
const openai: OpenAI = await newOpenAICompatibleSDK({ providerName, settingsOfProvider, includeInPayload })
|
const openai: OpenAI = await newOpenAICompatibleSDK({ providerName, settingsOfProvider, includeInPayload })
|
||||||
|
if (providerName === 'microsoftAzure') {
|
||||||
|
// Required to select the model
|
||||||
|
(openai as AzureOpenAI).deploymentName = modelName;
|
||||||
|
}
|
||||||
const options: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
|
const options: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
|
||||||
model: modelName,
|
model: modelName,
|
||||||
messages: messages as any,
|
messages: messages as any,
|
||||||
stream: true,
|
stream: true,
|
||||||
...nativeToolsObj,
|
...nativeToolsObj,
|
||||||
|
...additionalOpenAIPayload
|
||||||
// max_completion_tokens: maxTokens,
|
// max_completion_tokens: maxTokens,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue