mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
add new models, more info in prompt,
This commit is contained in:
parent
a2a9cdba60
commit
de703e82cb
6 changed files with 360 additions and 42 deletions
|
|
@ -29,9 +29,11 @@ import { shorten } from '../../../../base/common/labels.js';
|
|||
import { IVoidModelService } from '../common/voidModelService.js';
|
||||
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
||||
import { findLastIdx } from '../../../../base/common/arraysFind.js';
|
||||
import { findLast, findLastIdx } from '../../../../base/common/arraysFind.js';
|
||||
import { IEditCodeService } from './editCodeServiceInterface.js';
|
||||
import { VoidFileSnapshot } from '../common/editCodeServiceTypes.js';
|
||||
import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js';
|
||||
import { IModelService } from '../../../../editor/common/services/model.js';
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -241,7 +243,8 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IEditCodeService private readonly _editCodeService: IEditCodeService,
|
||||
// @IModelService private readonly _modelService: IModelService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
|
||||
) {
|
||||
super()
|
||||
|
|
@ -475,7 +478,10 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
|
||||
const callThisToolFirst: ToolRequestApproval<ToolName> = lastMessage
|
||||
|
||||
this._runChatAgent({ callThisToolFirst, prevSelns, currSelns, threadId, userMessageContent: instructions, ...this._currentModelSelectionProps() })
|
||||
this._wrapRunAgentToNotify(
|
||||
this._runChatAgent({ callThisToolFirst, prevSelns, currSelns, threadId, userMessageContent: instructions, ...this._currentModelSelectionProps() })
|
||||
, threadId
|
||||
)
|
||||
}
|
||||
rejectLatestToolRequest(threadId: string) {
|
||||
const thread = this.state.allThreads[threadId]
|
||||
|
|
@ -572,8 +578,12 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
|
||||
// system message
|
||||
const workspaceFolders = this._workspaceContextService.getWorkspace().folders.map(f => f.uri.fsPath)
|
||||
const terminalIds = this._terminalToolService.listTerminalIds()
|
||||
const systemMessage = chat_systemMessage(workspaceFolders, terminalIds, chatMode)
|
||||
|
||||
const openedURIs = this._modelService.getModels().filter(m => m.isAttachedToEditor()).map(m => m.uri.fsPath) || [];
|
||||
const activeURI = this._editorService.activeEditor?.resource?.fsPath;
|
||||
|
||||
const runningTerminalIds = this._terminalToolService.listTerminalIds()
|
||||
const systemMessage = chat_systemMessage({ workspaceFolders, openedURIs, activeURI, runningTerminalIds, chatMode })
|
||||
|
||||
// all messages so far in the chat history (including tools)
|
||||
const messages: LLMChatMessage[] = [
|
||||
|
|
@ -767,9 +777,11 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
// if awaiting user approval, keep isRunning true, else end isRunning
|
||||
this._setStreamState(threadId, { isRunning: isRunningWhenEnd }, 'merge')
|
||||
|
||||
// if successful, add checkpoint
|
||||
this._addUserCheckpoint({ threadId })
|
||||
|
||||
// capture number of messages sent
|
||||
this._metricsService.capture('Agent Loop Done', { nMessagesSent, chatMode })
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1039,6 +1051,43 @@ We only need to do it for files that were edited since `from`, ie files between
|
|||
}
|
||||
|
||||
|
||||
private _wrapRunAgentToNotify(p: Promise<void>, threadId: string) {
|
||||
const notify = (error: string | null) => {
|
||||
const thread = this.state.allThreads[threadId]
|
||||
if (!thread) return
|
||||
const userMsg = findLast(thread.messages, m => m.role === 'user')
|
||||
if (!userMsg) return
|
||||
if (userMsg.role !== 'user') return
|
||||
const messageContent = userMsg.displayContent.substring(0, 50)
|
||||
|
||||
this._notificationService.notify({
|
||||
severity: error ? Severity.Warning : Severity.Info,
|
||||
message: error ? `Error: ${error} ` : `Task Complete!\n${messageContent}...`,
|
||||
actions: {
|
||||
secondary: [{
|
||||
id: 'void.goToChat',
|
||||
enabled: true,
|
||||
label: `View`,
|
||||
tooltip: '',
|
||||
class: undefined,
|
||||
run: () => {
|
||||
this.switchToThread(threadId)
|
||||
// TODO!!! scroll to bottom
|
||||
}
|
||||
}]
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
p.then(() => {
|
||||
notify(null)
|
||||
|
||||
}).catch((e) => {
|
||||
notify(getErrorMessage(e))
|
||||
throw e
|
||||
})
|
||||
}
|
||||
|
||||
async addUserMessageAndStreamResponse({ userMessage, _chatSelections, threadId }: { userMessage: string, _chatSelections?: { prevSelns?: StagingSelectionItem[], currSelns?: StagingSelectionItem[], }, threadId: string }) {
|
||||
const thread = this.state.allThreads[threadId]
|
||||
if (!thread) return // should never happen
|
||||
|
|
@ -1058,10 +1107,10 @@ We only need to do it for files that were edited since `from`, ie files between
|
|||
const userHistoryElt: ChatMessage = { role: 'user', content: userMessageContent, displayContent: instructions, selections: currSelns, state: defaultMessageState }
|
||||
this._addMessageToThread(threadId, userHistoryElt)
|
||||
|
||||
this._runChatAgent({ prevSelns, currSelns, threadId, userMessageContent, ...this._currentModelSelectionProps(), })
|
||||
.then(() => {
|
||||
this._addUserCheckpoint({ threadId })
|
||||
})
|
||||
this._wrapRunAgentToNotify(
|
||||
this._runChatAgent({ prevSelns, currSelns, threadId, userMessageContent, ...this._currentModelSelectionProps(), }),
|
||||
threadId,
|
||||
)
|
||||
}
|
||||
|
||||
dismissStreamError(threadId: string): void {
|
||||
|
|
|
|||
222
src/vs/workbench/contrib/void/browser/directoryTreeService.ts
Normal file
222
src/vs/workbench/contrib/void/browser/directoryTreeService.ts
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*--------------------------------------------------------------------------------------
|
||||
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
|
||||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||
*--------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from '../../../../base/common/path.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { FilesFilter } from '../../files/browser/views/explorerViewer.js';
|
||||
import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||
import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
|
||||
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { IFileService } from '../../../../platform/files/common/files.js';
|
||||
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
|
||||
import { IExplorerService } from '../../files/browser/files.js';
|
||||
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||
import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';
|
||||
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
|
||||
|
||||
export interface IDirectoryTreeService {
|
||||
readonly _serviceBrand: undefined;
|
||||
getDirectoryTreeWithVSCodeIgnores(directoryPath: string): Promise<{ content: string, cutOff: boolean }>;
|
||||
}
|
||||
|
||||
export const IDirectoryTreeService = createDecorator<IDirectoryTreeService>('voidDirectoryTreeService');
|
||||
|
||||
class DirectoryTreeService extends Disposable implements IDirectoryTreeService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@IConfigurationService private readonly _configService: IConfigurationService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
|
||||
@IExplorerService private readonly explorerService: IExplorerService,
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a directory structure in a tree-like format, respecting gitignore patterns
|
||||
* @param directoryPath The path to the directory to print
|
||||
* @returns Object containing the formatted tree as a string and whether it was cut off
|
||||
*/
|
||||
public async getDirectoryTreeWithVSCodeIgnores(directoryPath: string): Promise<{ content: string, cutOff: boolean }> {
|
||||
// Create a files filter instance
|
||||
const filesFilter = new FilesFilter(
|
||||
this.workspaceContextService,
|
||||
this._configService,
|
||||
this.explorerService,
|
||||
this.editorService,
|
||||
this.uriIdentityService,
|
||||
this._fileService
|
||||
);
|
||||
|
||||
const isPathIgnored = this.createVSCodeIgnoreCheck(
|
||||
directoryPath,
|
||||
filesFilter,
|
||||
);
|
||||
|
||||
const MAX_CHARS = 20_000;
|
||||
const result = await this.printDirectoryTree(this._fileService, directoryPath, '', isPathIgnored, MAX_CHARS);
|
||||
|
||||
return {
|
||||
content: result.content,
|
||||
cutOff: result.cutOff
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a directory structure in a tree-like format, respecting gitignore patterns
|
||||
* @param fileService The file service to use
|
||||
* @param directoryPath The path to the directory to print
|
||||
* @param indent Optional indentation for nested calls
|
||||
* @param isPathIgnored Optional function to check if a path is ignored
|
||||
* @param maxChars Maximum number of characters before cutting off
|
||||
* @returns Object containing the formatted tree and cut-off status
|
||||
*/
|
||||
private async printDirectoryTree(
|
||||
fileService: IFileService,
|
||||
directoryPath: string,
|
||||
indent: string = '',
|
||||
isPathIgnored?: (path: string, isDirectory: boolean) => boolean,
|
||||
maxChars: number = Infinity
|
||||
): Promise<{ content: string, cutOff: boolean }> {
|
||||
let resolve: (result: { content: string, cutOff: boolean }) => void = () => undefined
|
||||
const p = new Promise<{ content: string, cutOff: boolean }>((res) => { resolve = res });
|
||||
|
||||
try {
|
||||
const directoryUri = URI.file(directoryPath);
|
||||
const stat = await fileService.resolve(directoryUri);
|
||||
if (!stat.isDirectory) {
|
||||
resolve({ content: '', cutOff: false });
|
||||
return p;
|
||||
}
|
||||
|
||||
// For root level only
|
||||
let result = '';
|
||||
let cutOff = false;
|
||||
|
||||
if (indent === '') {
|
||||
const baseName = path.basename(directoryPath);
|
||||
result += baseName + '\n';
|
||||
|
||||
if (result.length >= maxChars) {
|
||||
resolve({ content: result.substring(0, maxChars), cutOff: true });
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
// Separate directories and files
|
||||
const directories: string[] = [];
|
||||
const files: string[] = [];
|
||||
|
||||
for (const entry of stat.children || []) {
|
||||
const itemPath = entry.resource.fsPath;
|
||||
const isDirectory = entry.isDirectory;
|
||||
|
||||
// Skip ignored files/folders if isPathIgnored is provided
|
||||
if (isPathIgnored && isPathIgnored(itemPath, isDirectory)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isDirectory) {
|
||||
directories.push(entry.name);
|
||||
} else {
|
||||
files.push(entry.name);
|
||||
}
|
||||
}
|
||||
|
||||
// Process directories first, then files
|
||||
const sortedItems = [...directories.sort(), ...files.sort()];
|
||||
|
||||
// Process each visible item
|
||||
for (let i = 0; i < sortedItems.length; i++) {
|
||||
// Check if we've reached the character limit
|
||||
if (result.length >= maxChars) {
|
||||
cutOff = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const item = sortedItems[i];
|
||||
const isLast = i === sortedItems.length - 1;
|
||||
const itemPath = path.join(directoryPath, item);
|
||||
const isDirectory = directories.includes(item);
|
||||
|
||||
// Add the current item to the result
|
||||
const itemLine = `${indent}|--${item}\n`;
|
||||
|
||||
// Check if adding this line would exceed the limit
|
||||
if (result.length + itemLine.length > maxChars) {
|
||||
result += itemLine.substring(0, maxChars - result.length);
|
||||
cutOff = true;
|
||||
break;
|
||||
}
|
||||
|
||||
result += itemLine;
|
||||
|
||||
// Recursively process directories
|
||||
if (isDirectory) {
|
||||
// Next level indentation
|
||||
const childIndent = `${indent}${isLast ? ' ' : '| '}`;
|
||||
const childResult = await this.printDirectoryTree(
|
||||
fileService,
|
||||
itemPath,
|
||||
childIndent,
|
||||
isPathIgnored,
|
||||
maxChars - result.length
|
||||
);
|
||||
|
||||
result += childResult.content;
|
||||
|
||||
if (childResult.cutOff) {
|
||||
cutOff = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve({ content: result, cutOff });
|
||||
} catch (error) {
|
||||
const errorMessage = `Error: ${error.message}\n`;
|
||||
const cutOff = errorMessage.length > maxChars;
|
||||
resolve({
|
||||
content: cutOff ? errorMessage.substring(0, maxChars) : errorMessage,
|
||||
cutOff
|
||||
});
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that checks if a path should be ignored based on VS Code's FilesFilter
|
||||
* @param directoryPath Root directory path
|
||||
* @param filesFilter VS Code's FilesFilter instance
|
||||
* @param fileService VS Code's FileService instance
|
||||
* @param configService VS Code's ConfigurationService instance
|
||||
* @param filesConfigService VS Code's FilesConfigurationService instance
|
||||
* @returns A function that checks if a path is ignored
|
||||
*/
|
||||
private createVSCodeIgnoreCheck(
|
||||
directoryPath: string,
|
||||
filesFilter: FilesFilter,
|
||||
): (path: string, isDirectory: boolean) => boolean {
|
||||
// Create a workspace folder URI (root explorer item)
|
||||
const workspaceUri = URI.file(directoryPath);
|
||||
|
||||
return (itemPath: string, isDirectory: boolean): boolean => {
|
||||
try {
|
||||
const itemUri = URI.file(itemPath);
|
||||
|
||||
// Use FilesFilter.isIgnored to check if the item should be hidden based on VS Code's excludes
|
||||
return filesFilter.isIgnored(itemUri, workspaceUri, isDirectory);
|
||||
} catch (error) {
|
||||
console.error(`Error checking if path is ignored: ${itemPath}`, error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IDirectoryTreeService, DirectoryTreeService, InstantiationType.Delayed);
|
||||
|
|
@ -1390,7 +1390,10 @@ const toolNameToComponent: { [T in ToolName]: ToolComponent<T> } = {
|
|||
if (toolMessage.result.type === 'success') {
|
||||
const { value, params } = toolMessage.result
|
||||
componentParams.onClick = () => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }
|
||||
if (value.hasNextPage) componentParams.desc2 = `(AI can scroll for more)`
|
||||
if (value.hasNextPage && params.pageNumber === 1) // first page
|
||||
componentParams.desc2 = '(more content available)'
|
||||
else if (params.pageNumber >= 1) // subsequent pages
|
||||
componentParams.desc2 = `(part ${params.pageNumber})`
|
||||
}
|
||||
else {
|
||||
const { value, params } = toolMessage.result
|
||||
|
|
|
|||
|
|
@ -200,7 +200,11 @@ registerAction2(class extends Action2 {
|
|||
id: 'void.newChatAction',
|
||||
title: 'New Chat',
|
||||
icon: { id: 'add' },
|
||||
menu: [{ id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.equals('view', VOID_VIEW_ID), }]
|
||||
menu: [{ id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.equals('view', VOID_VIEW_ID), }],
|
||||
keybinding: {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyL,
|
||||
weight: KeybindingWeight.VoidExtension,
|
||||
},
|
||||
});
|
||||
}
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -25,11 +25,9 @@ export const defaultModelsOfProvider = {
|
|||
'grok-3-latest',
|
||||
],
|
||||
gemini: [ // https://ai.google.dev/gemini-api/docs/models/gemini
|
||||
'gemini-2.5-pro-exp-03-25',
|
||||
'gemini-2.0-flash',
|
||||
'gemini-1.5-flash',
|
||||
'gemini-1.5-pro',
|
||||
'gemini-1.5-flash-8b',
|
||||
'gemini-2.0-flash-thinking-exp',
|
||||
'gemini-2.0-flash-lite',
|
||||
],
|
||||
deepseek: [ // https://api-docs.deepseek.com/quick_start/pricing
|
||||
'deepseek-chat',
|
||||
|
|
@ -144,6 +142,19 @@ const openSourceModelOptions_assumingOAICompat = {
|
|||
supportsTools: 'openai-style',
|
||||
reasoningCapabilities: false,
|
||||
},
|
||||
'openhands-lm-32b': { // https://www.all-hands.dev/blog/introducing-openhands-lm-32b----a-strong-open-coding-agent-model
|
||||
supportsFIM: false,
|
||||
supportsSystemMessage: 'system-role',
|
||||
supportsTools: 'openai-style',
|
||||
reasoningCapabilities: false, // built on qwen 2.5 32B instruct
|
||||
},
|
||||
'phi4': {
|
||||
supportsFIM: false,
|
||||
supportsSystemMessage: 'system-role',
|
||||
supportsTools: false,
|
||||
reasoningCapabilities: false,
|
||||
},
|
||||
|
||||
// llama
|
||||
'llama3': {
|
||||
supportsFIM: false,
|
||||
|
|
@ -201,6 +212,9 @@ const openSourceModelOptions_assumingOAICompat = {
|
|||
|
||||
|
||||
const extensiveModelFallback: ProviderSettings['modelOptionsFallback'] = (modelName) => {
|
||||
|
||||
const lower = modelName.toLowerCase()
|
||||
|
||||
const toFallback = (opts: Omit<ModelOptions, 'cost'>): ModelOptions & { modelName: string } => {
|
||||
return {
|
||||
modelName,
|
||||
|
|
@ -209,15 +223,19 @@ const extensiveModelFallback: ProviderSettings['modelOptionsFallback'] = (modelN
|
|||
cost: { input: 0, output: 0 },
|
||||
}
|
||||
}
|
||||
if (modelName.includes('gpt-4o')) return toFallback(openAIModelOptions['gpt-4o'])
|
||||
if (modelName.includes('claude-3-5') || modelName.includes('claude-3.5')) return toFallback(anthropicModelOptions['claude-3-5-sonnet-20241022'])
|
||||
if (modelName.includes('claude')) return toFallback(anthropicModelOptions['claude-3-7-sonnet-20250219'])
|
||||
if (modelName.includes('grok')) return toFallback(xAIModelOptions['grok-2'])
|
||||
if (modelName.includes('deepseek-r1') || modelName.includes('deepseek-reasoner')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.deepseekR1, contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (modelName.includes('deepseek')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.deepseekCoderV2, contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (modelName.includes('llama3')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.llama3, contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (modelName.includes('qwen') && modelName.includes('2.5') && modelName.includes('coder')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['qwen2.5coder'], contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (modelName.includes('codestral')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.codestral, contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (lower.includes('gpt-4o')) return toFallback(openAIModelOptions['gpt-4o'])
|
||||
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('grok')) return toFallback(xAIModelOptions['grok-2'])
|
||||
if (lower.includes('deepseek-r1') || lower.includes('deepseek-reasoner')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.deepseekR1, contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (lower.includes('deepseek')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.deepseekCoderV2, contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (lower.includes('llama3')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.llama3, contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (lower.includes('qwen') && lower.includes('2.5') && lower.includes('coder')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['qwen2.5coder'], contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (lower.includes('codestral')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.codestral, contextWindow: 32_000, maxOutputTokens: 4_096, })
|
||||
if (lower.includes('qwq')) { return toFallback({ ...openSourceModelOptions_assumingOAICompat.qwq, contextWindow: 128_000, maxOutputTokens: 8_192, }) }
|
||||
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('phi4')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.phi4, contextWindow: 16_000, maxOutputTokens: 4_096, })
|
||||
if (lower.includes('openhands')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['openhands-lm-32b'], contextWindow: 128_000, maxOutputTokens: 4_096 }) // max output unclear
|
||||
if (/\bo1\b/.test(modelName) || /\bo3\b/.test(modelName)) return toFallback(openAIModelOptions['o1'])
|
||||
return toFallback(modelOptionsDefaults)
|
||||
}
|
||||
|
|
@ -294,12 +312,13 @@ const anthropicSettings: ProviderSettings = {
|
|||
},
|
||||
modelOptions: anthropicModelOptions,
|
||||
modelOptionsFallback: (modelName) => {
|
||||
const lower = modelName.toLowerCase()
|
||||
let fallbackName: keyof typeof anthropicModelOptions | null = null
|
||||
if (modelName.includes('claude-3-7-sonnet')) fallbackName = 'claude-3-7-sonnet-20250219'
|
||||
if (modelName.includes('claude-3-5-sonnet')) fallbackName = 'claude-3-5-sonnet-20241022'
|
||||
if (modelName.includes('claude-3-5-haiku')) fallbackName = 'claude-3-5-haiku-20241022'
|
||||
if (modelName.includes('claude-3-opus')) fallbackName = 'claude-3-opus-20240229'
|
||||
if (modelName.includes('claude-3-sonnet')) fallbackName = 'claude-3-sonnet-20240229'
|
||||
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-haiku')) fallbackName = 'claude-3-5-haiku-20241022'
|
||||
if (lower.includes('claude-3-opus')) fallbackName = 'claude-3-opus-20240229'
|
||||
if (lower.includes('claude-3-sonnet')) fallbackName = 'claude-3-sonnet-20240229'
|
||||
if (fallbackName) return { modelName: fallbackName, ...anthropicModelOptions[fallbackName] }
|
||||
return { modelName, ...modelOptionsDefaults, maxOutputTokens: 4_096 }
|
||||
},
|
||||
|
|
@ -359,10 +378,11 @@ const openAIModelOptions = { // https://platform.openai.com/docs/pricing
|
|||
const openAISettings: ProviderSettings = {
|
||||
modelOptions: openAIModelOptions,
|
||||
modelOptionsFallback: (modelName) => {
|
||||
const lower = modelName.toLowerCase()
|
||||
let fallbackName: keyof typeof openAIModelOptions | null = null
|
||||
if (modelName.includes('o1')) { fallbackName = 'o1' }
|
||||
if (modelName.includes('o3-mini')) { fallbackName = 'o3-mini' }
|
||||
if (modelName.includes('gpt-4o')) { fallbackName = 'gpt-4o' }
|
||||
if (lower.includes('o1')) { fallbackName = 'o1' }
|
||||
if (lower.includes('o3-mini')) { fallbackName = 'o3-mini' }
|
||||
if (lower.includes('gpt-4o')) { fallbackName = 'gpt-4o' }
|
||||
if (fallbackName) return { modelName: fallbackName, ...openAIModelOptions[fallbackName] }
|
||||
return null
|
||||
}
|
||||
|
|
@ -384,8 +404,9 @@ const xAIModelOptions = {
|
|||
const xAISettings: ProviderSettings = {
|
||||
modelOptions: xAIModelOptions,
|
||||
modelOptionsFallback: (modelName) => {
|
||||
const lower = modelName.toLowerCase()
|
||||
let fallbackName: keyof typeof xAIModelOptions | null = null
|
||||
if (modelName.includes('grok-2')) fallbackName = 'grok-2'
|
||||
if (lower.includes('grok-2')) fallbackName = 'grok-2'
|
||||
if (fallbackName) return { modelName: fallbackName, ...xAIModelOptions[fallbackName] }
|
||||
return null
|
||||
}
|
||||
|
|
@ -394,6 +415,15 @@ const xAISettings: ProviderSettings = {
|
|||
|
||||
// ---------------- GEMINI ----------------
|
||||
const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
|
||||
'gemini-2.5-pro-exp-03-25': {
|
||||
contextWindow: 1_048_576,
|
||||
maxOutputTokens: null, // 8_192,
|
||||
cost: { input: 0, output: 0 },
|
||||
supportsFIM: false,
|
||||
supportsSystemMessage: 'system-role',
|
||||
supportsTools: 'openai-style', // we are assuming OpenAI SDK when calling gemini
|
||||
reasoningCapabilities: false,
|
||||
},
|
||||
'gemini-2.0-flash': {
|
||||
contextWindow: 1_048_576,
|
||||
maxOutputTokens: null, // 8_192,
|
||||
|
|
@ -660,8 +690,10 @@ const modelSettingsOfProvider: { [providerName in ProviderName]: ProviderSetting
|
|||
ollama: ollamaSettings,
|
||||
openAICompatible: openaiCompatible,
|
||||
|
||||
// TODO!!!
|
||||
// googleVertex: {},
|
||||
// microsoftAzure: {},
|
||||
// openHands: {},
|
||||
} as const
|
||||
|
||||
|
||||
|
|
@ -669,8 +701,16 @@ const modelSettingsOfProvider: { [providerName in ProviderName]: ProviderSetting
|
|||
|
||||
// returns the capabilities and the adjusted modelName if it was a fallback
|
||||
export const getModelCapabilities = (providerName: ProviderName, modelName: string): ModelOptions & { modelName: string; isUnrecognizedModel: boolean } => {
|
||||
const lowercaseModelName = modelName.toLowerCase()
|
||||
const { modelOptions, modelOptionsFallback } = modelSettingsOfProvider[providerName]
|
||||
if (modelName in modelOptions) return { modelName, ...modelOptions[modelName], isUnrecognizedModel: false }
|
||||
|
||||
// search model options object directly first
|
||||
for (const modelName_ in modelOptions) {
|
||||
const lowercaseModelName_ = modelName_.toLowerCase()
|
||||
if (lowercaseModelName === lowercaseModelName_)
|
||||
return { modelName, ...modelOptions[modelName], isUnrecognizedModel: false }
|
||||
}
|
||||
|
||||
const result = modelOptionsFallback(modelName)
|
||||
if (result) return { ...result, isUnrecognizedModel: false }
|
||||
return { modelName, ...modelOptionsDefaults, isUnrecognizedModel: true }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||
*--------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
import { URI } from '../../../../../base/common/uri.js';
|
||||
import { os } from '../helpers/systemInfo.js';
|
||||
import { CodeSelection, FileSelection, StagingSelectionItem } from '../chatThreadServiceTypes.js';
|
||||
|
|
@ -12,7 +11,6 @@ import { IVoidModelService } from '../voidModelService.js';
|
|||
import { EndOfLinePreference } from '../../../../../editor/common/model.js';
|
||||
import { InternalToolInfo } from '../toolsServiceTypes.js';
|
||||
|
||||
|
||||
// this is just for ease of readability
|
||||
export const tripleTick = ['```', '```']
|
||||
|
||||
|
|
@ -148,7 +146,7 @@ Here's an example of a good description:\n${editToolDescription}.`
|
|||
|
||||
|
||||
|
||||
export const chat_systemMessage = (workspaces: string[], runningTerminalIds: string[], mode: ChatMode) => `\
|
||||
export const chat_systemMessage = ({ workspaceFolders, openedURIs, activeURI, runningTerminalIds, chatMode: mode }: { workspaceFolders: string[], openedURIs: string[], activeURI: string | undefined, runningTerminalIds: string[], chatMode: ChatMode }) => `\
|
||||
You are an expert coding ${mode === 'agent' ? 'agent' : 'assistant'} that runs in the Void code editor. Your job is \
|
||||
${mode === 'agent' ? `to help the user develop, run, deploy, and make changes to their codebase. You should ALWAYS bring user's task to completion to the fullest extent possible, calling tools to make all necessary changes.`
|
||||
: mode === 'gather' ? `to search and understand the user's codebase. You MUST use tools to read files and help the user understand the codebase, even if you were initially given files.`
|
||||
|
|
@ -159,10 +157,12 @@ Please assist the user with their query. The user's query is never invalid.
|
|||
${/* system info */''}
|
||||
The user's system information is as follows:
|
||||
- ${os}
|
||||
- Open workspace(s): ${workspaces.join(', ') || 'NO WORKSPACE OPEN'}
|
||||
${(mode === 'agent') && runningTerminalIds.length !== 0 ? `\
|
||||
- Existing terminal IDs: ${runningTerminalIds.join(', ')}
|
||||
`: '\n'}
|
||||
- Open workspace(s): ${workspaceFolders.join(', ') || 'NO WORKSPACE OPEN'}
|
||||
- Open tab(s): ${openedURIs.join(', ') || 'NO OPENED EDITORS'}
|
||||
- Active tab: ${activeURI}
|
||||
${(mode === 'agent') && runningTerminalIds.length !== 0 ? `
|
||||
- Existing terminal IDs: ${runningTerminalIds.join(', ')}` : ''}
|
||||
|
||||
${/* tool use */ mode === 'agent' || mode === 'gather' ? `\
|
||||
You will be given tools you can call.
|
||||
${mode === 'agent' ? `\
|
||||
|
|
|
|||
Loading…
Reference in a new issue