Merge branch 'voideditor:main' into mcp

This commit is contained in:
Joaquin Coromina 2025-05-14 11:05:51 -04:00 committed by GitHub
commit c119286571
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 162 additions and 95 deletions

46
package-lock.json generated
View file

@ -299,13 +299,14 @@
"dev": true
},
"node_modules/@azure/core-auth": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz",
"integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==",
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz",
"integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@azure/core-util": "^1.1.0",
"@azure/core-util": "^1.11.0",
"tslib": "^2.6.2"
},
"engines": {
@ -448,18 +449,18 @@
}
},
"node_modules/@azure/core-rest-pipeline": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.0.tgz",
"integrity": "sha512-CeuTvsXxCUmEuxH5g/aceuSl6w2EugvNHKAtKKVdiX915EjJJxAwfzNNWZreNnbxHZ2fi0zaM6wwS23x2JVqSQ==",
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.20.0.tgz",
"integrity": "sha512-ASoP8uqZBS3H/8N8at/XwFr6vYrRP3syTK0EUjDXQy0Y1/AUS+QeIRThKmTNJO2RggvBBxaXDPM7YoIwDGeA0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@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-util": "^1.9.0",
"@azure/core-util": "^1.11.0",
"@azure/logger": "^1.0.0",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.0",
"@typespec/ts-http-runtime": "^0.2.2",
"tslib": "^2.6.2"
},
"engines": {
@ -479,12 +480,14 @@
}
},
"node_modules/@azure/core-util": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz",
"integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==",
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.12.0.tgz",
"integrity": "sha512-13IyjTQgABPARvG90+N2dXpC+hwp466XCdQXPCRlbWHgd3SJd5Q1VvaBGv6k1BIa4MQm6hAF1UBU1m8QUxV8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@azure/abort-controller": "^2.0.0",
"@typespec/ts-http-runtime": "^0.2.2",
"tslib": "^2.6.2"
},
"engines": {
@ -4257,6 +4260,21 @@
"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": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@vscode/deviceid/-/deviceid-0.1.1.tgz",

View file

@ -1,8 +1,8 @@
{
"nameShort": "Void",
"nameLong": "Void",
"voidVersion": "1.3.7",
"voidRelease": "0031",
"voidVersion": "1.3.9",
"voidRelease": "0033",
"applicationName": "void",
"dataFolderName": ".void-editor",
"win32MutexName": "voideditor",

View file

@ -418,6 +418,7 @@ const prepareOpenAIOrAnthropicMessages = ({
else {
// 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')) {
currMsg.content = currMsg.content.filter(c => !(c.type === 'text' && !c.text)) as any
continue
}
if (nextMsg?.role === 'tool') continue

View file

@ -8,6 +8,8 @@ import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase
import { IExtensionTransferService } from './extensionTransferService.js';
import { os } from '../common/helpers/systemInfo.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
export class MiscWorkbenchContribs extends Disposable implements IWorkbenchContribution {
@ -31,6 +33,16 @@ export class MiscWorkbenchContribs extends Disposable implements IWorkbenchContr
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'))
})
}
}

View file

@ -2605,7 +2605,7 @@ const CommandBarInChat = () => {
// !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) => {
const basename = getBasename(uri.fsPath)
@ -2862,6 +2862,7 @@ export const SidebarChat = () => {
textAreaRef: textAreaRef,
scrollToBottom: () => scrollToBottom(scrollContainerRef),
})
}, [chatThreadsState, threadId, textAreaRef, scrollContainerRef, isResolved])

View file

@ -17,7 +17,7 @@ import { os } from '../../../../common/helpers/systemInfo.js'
import { IconLoading } from '../sidebar-tsx/SidebarChat.js'
import { ToolApprovalType, toolApprovalTypes } from '../../../../common/toolsServiceTypes.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';
const ButtonLeftTextRightOption = ({ text, leftButton }: { text: string, leftButton?: React.ReactNode }) => {
@ -185,6 +185,11 @@ const ConfirmButton = ({ children, onConfirm, className }: { children: React.Rea
};
// ---------------- 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.
const SimpleModelSettingsDialog = ({
isOpen,
@ -208,39 +213,26 @@ const SimpleModelSettingsDialog = ({
const currentOverrides = settingsState.overridesOfModel?.[providerName]?.[modelName] ?? undefined;
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
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 [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 textAreaRef = useRef<HTMLTextAreaElement | null>(null)
// reset when dialog toggles
useEffect(() => {
if (!isOpen) return;
const cur = settingsState.overridesOfModel?.[providerName]?.[modelName];
setOverrideEnabled(!!cur);
// If there are overrides, show them; otherwise use default values
setJsonText(cur ? JSON.stringify(cur, null, 2) : placeholder);
setErrorMsg(null);
}, [isOpen, providerName, modelName, settingsState.overridesOfModel, placeholder]);
const onSave = async () => {
// if disabled override, reset overrides
if (!overrideEnabled) {
await settingsStateService.setOverridesOfModel(providerName, modelName, undefined);
@ -251,9 +243,10 @@ const SimpleModelSettingsDialog = ({
// enabled overrides
// parse json
let parsedInput: Record<string, unknown>
if (jsonText.trim()) {
if (textAreaRef.current?.value) {
try {
parsedInput = JSON.parse(jsonText);
parsedInput = JSON.parse(textAreaRef.current.value);
} catch (e) {
setErrorMsg('Invalid JSON');
return;
@ -265,10 +258,10 @@ const SimpleModelSettingsDialog = ({
// only keep allowed keys
const cleaned: Partial<ModelOverrides> = {};
for (const k of allowedKeys) {
for (const k of modelOverrideKeys) {
if (!(k in parsedInput)) continue
const isEmpty = parsedInput[k] === '' || parsedInput[k] === null || parsedInput[k] === undefined;
if (!isEmpty && (k in partialDefaults)) {
if (!isEmpty) {
cleaned[k] = parsedInput[k] as any;
}
}
@ -333,10 +326,11 @@ const SimpleModelSettingsDialog = ({
</div>}
<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' : ''}`}
value={overrideEnabled ? jsonText : placeholder}
defaultValue={overrideEnabled && currentOverrides ? JSON.stringify(currentOverrides, null, 2) : placeholder}
placeholder={placeholder}
onChange={overrideEnabled ? (e) => setJsonText(e.target.value) : undefined}
readOnly={!overrideEnabled}
/>
{errorMsg && (

View file

@ -84,8 +84,8 @@ export const defaultModelsOfProvider = {
'claude-3-opus-latest',
],
xAI: [ // https://docs.x.ai/docs/models?cluster=us-east-1
'grok-2-latest',
'grok-3-latest',
'grok-2',
'grok-3',
],
gemini: [ // https://ai.google.dev/gemini-api/docs/models/gemini
'gemini-2.5-pro-exp-03-25',
@ -188,14 +188,20 @@ export type VoidStaticModelInfo = { // not stateful
// if you change the above type, remember to update the Settings link
export type ModelOverrides = Pick<VoidStaticModelInfo,
| 'contextWindow'
| 'reservedOutputTokenSpace'
| 'specialToolFormat'
| 'supportsSystemMessage'
| 'supportsFIM'
| 'reasoningCapabilities'
| 'additionalOpenAIPayload'
export const modelOverrideKeys = [
'contextWindow',
'reservedOutputTokenSpace',
'supportsSystemMessage',
'specialToolFormat',
'supportsFIM',
'reasoningCapabilities',
'additionalOpenAIPayload'
] as const
export type ModelOverrides = Pick<
VoidStaticModelInfo,
(typeof modelOverrideKeys)[number]
>
@ -386,7 +392,8 @@ const extensiveModelOptionsFallback: VoidStaticProviderInfo['modelOptionsFallbac
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('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') && lower.includes('v2')) return toFallback(openSourceModelOptions_assumingOAICompat, 'deepseekCoderV2')
@ -630,6 +637,16 @@ const openAIModelOptions = { // https://platform.openai.com/docs/pricing
} 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 = {
modelOptions: openAIModelOptions,
modelOptionsFallback: (modelName) => {
@ -642,17 +659,7 @@ const openAISettings: VoidStaticProviderInfo = {
return null
},
providerReasoningIOSettings: {
input: {
// 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
}
},
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
},
}
@ -667,6 +674,7 @@ const xAIModelOptions = {
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
specialToolFormat: 'openai-style',
reasoningCapabilities: false,
},
'grok-3': {
@ -676,6 +684,7 @@ const xAIModelOptions = {
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
specialToolFormat: 'openai-style',
reasoningCapabilities: false,
},
'grok-3-fast': {
@ -685,6 +694,7 @@ const xAIModelOptions = {
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
specialToolFormat: 'openai-style',
reasoningCapabilities: false,
},
// only mini supports thinking
@ -695,6 +705,7 @@ const xAIModelOptions = {
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
specialToolFormat: 'openai-style',
reasoningCapabilities: { supportsReasoning: true, canTurnOffReasoning: false, canIOReasoning: false, reasoningSlider: { type: 'effort_slider', values: ['low', 'high'], default: 'low' } },
},
'grok-3-mini-fast': {
@ -704,6 +715,7 @@ const xAIModelOptions = {
downloadable: false,
supportsFIM: false,
supportsSystemMessage: 'system-role',
specialToolFormat: 'openai-style',
reasoningCapabilities: { supportsReasoning: true, canTurnOffReasoning: false, canIOReasoning: false, reasoningSlider: { type: 'effort_slider', values: ['low', 'high'], default: 'low' } },
},
} as const satisfies { [s: string]: VoidStaticModelInfo }
@ -714,11 +726,15 @@ const xAISettings: VoidStaticProviderInfo = {
const lower = modelName.toLowerCase()
let fallbackName: keyof typeof xAIModelOptions | null = null
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] }
return null
},
// same implementation as openai
providerReasoningIOSettings: openAISettings.providerReasoningIOSettings,
providerReasoningIOSettings: {
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
},
}
@ -837,7 +853,7 @@ const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing
const geminiSettings: VoidStaticProviderInfo = {
modelOptions: geminiModelOptions,
modelOptionsFallback: (modelName) => { return null }
modelOptionsFallback: (modelName) => { return null },
}
@ -863,11 +879,12 @@ const deepseekModelOptions = {
const deepseekSettings: VoidStaticProviderInfo = {
modelOptions: deepseekModelOptions,
modelOptionsFallback: (modelName) => { return null },
providerReasoningIOSettings: {
// reasoning: OAICompat + response.choices[0].delta.reasoning_content // https://api-docs.deepseek.com/guides/reasoning_model
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
output: { nameOfFieldInDelta: 'reasoning_content' },
},
modelOptionsFallback: (modelName) => { return null }
}
@ -925,6 +942,9 @@ const mistralModelOptions = { // https://mistral.ai/products/la-plateforme#prici
const mistralSettings: VoidStaticProviderInfo = {
modelOptions: mistralModelOptions,
modelOptionsFallback: (modelName) => { return null },
providerReasoningIOSettings: {
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
},
}
@ -968,11 +988,13 @@ const groqModelOptions = { // https://console.groq.com/docs/models, https://groq
},
} as const satisfies { [s: string]: VoidStaticModelInfo }
const groqSettings: VoidStaticProviderInfo = {
modelOptions: groqModelOptions,
modelOptionsFallback: (modelName) => { return null },
providerReasoningIOSettings: {
// Must be set to either parsed or hidden when using tool calling https://console.groq.com/docs/reasoning
input: {
includeInPayload: (reasoningInfo) => {
if (!reasoningInfo?.isReasoningEnabled) return null
if (reasoningInfo.type === 'budget_slider_value') {
return { reasoning_format: 'parsed' }
}
@ -980,9 +1002,7 @@ const groqSettings: VoidStaticProviderInfo = {
}
},
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 }
},
}
@ -991,7 +1011,10 @@ const googleVertexModelOptions = {
} as const satisfies Record<string, VoidStaticModelInfo>
const googleVertexSettings: VoidStaticProviderInfo = {
modelOptions: googleVertexModelOptions,
modelOptionsFallback: (modelName) => { return null }
modelOptionsFallback: (modelName) => { return null },
providerReasoningIOSettings: {
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
},
}
// ---------------- MICROSOFT AZURE ----------------
@ -999,7 +1022,10 @@ const microsoftAzureModelOptions = {
} as const satisfies Record<string, VoidStaticModelInfo>
const microsoftAzureSettings: VoidStaticProviderInfo = {
modelOptions: microsoftAzureModelOptions,
modelOptionsFallback: (modelName) => { return null }
modelOptionsFallback: (modelName) => { return null },
providerReasoningIOSettings: {
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
},
}
@ -1075,35 +1101,50 @@ export const ollamaRecommendedModels = ['qwen2.5-coder:1.5b', 'llama3.1', 'qwq',
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' } }),
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 = {
providerReasoningIOSettings: { output: { needsManualParse: true }, },
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' }, contextWindow: 4_096 }),
modelOptions: {}, // TODO
modelOptions: {},
providerReasoningIOSettings: {
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
output: { needsManualParse: true },
},
}
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' } }),
modelOptions: ollamaModelOptions,
providerReasoningIOSettings: {
// reasoning: we need to filter out reasoning <think> tags manually
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
output: { needsManualParse: true },
},
}
const openaiCompatible: VoidStaticProviderInfo = {
// reasoning: we have no idea what endpoint they used, so we can't consistently parse out reasoning
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName),
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
providerReasoningIOSettings: { output: { nameOfFieldInDelta: 'reasoning_content' } },
modelOptionsFallback: (modelName) => extensiveModelOptionsFallback(modelName, { downloadable: { sizeGb: 'not-known' } }),
modelOptions: {}, // TODO
modelOptions: {},
providerReasoningIOSettings: {
input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
output: { nameOfFieldInDelta: 'reasoning_content' },
},
}
@ -1228,8 +1269,18 @@ const openRouterModelOptions_assumingOpenAICompat = {
} as const satisfies { [s: string]: VoidStaticModelInfo }
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: {
// reasoning: OAICompat + response.choices[0].delta.reasoning : payload should have {include_reasoning: true} https://openrouter.ai/announcements/reasoning-tokens-for-thinking-models
input: {
// https://openrouter.ai/docs/use-cases/reasoning-tokens
includeInPayload: (reasoningInfo) => {
@ -1253,16 +1304,6 @@ const openRouterSettings: VoidStaticProviderInfo = {
},
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
},
}

View file

@ -7,7 +7,7 @@
/* eslint-disable */
import Anthropic from '@anthropic-ai/sdk';
import { Ollama } from 'ollama';
import OpenAI, { ClientOptions } from 'openai';
import OpenAI, { ClientOptions, AzureOpenAI } from 'openai';
import { MistralCore } from '@mistralai/mistralai/core.js';
import { fimComplete } from '@mistralai/mistralai/funcs/fimComplete.js';
import { Tool as GeminiTool, FunctionDeclaration, GoogleGenAI, ThinkingConfig, Schema, Type } from '@google/genai';
@ -114,9 +114,9 @@ const newOpenAICompatibleSDK = async ({ settingsOfProvider, providerName, includ
}
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://github.com/openai/openai-node?tab=readme-ov-file#microsoft-azure-openai
const thisConfig = settingsOfProvider[providerName]
const baseURL = `https://${thisConfig.project}.services.ai.azure.com/api/models/chat/completions?api-version=${thisConfig.azureApiVersion}`
return new OpenAI({ baseURL: baseURL, apiKey: thisConfig.apiKey, ...commonPayloadOpts })
return new AzureOpenAI({ apiKey: thisConfig.apiKey, apiVersion: thisConfig.azureApiVersion, project: thisConfig.project, ...commonPayloadOpts })
}
else if (providerName === 'deepseek') {