From db95bdedb5f69f829957dad1cfaf30f579a27374 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Mon, 3 Nov 2025 12:34:21 +0200 Subject: [PATCH 01/21] Add support for Azure Foundry models using responses api --- .../byok/vscode-node/azureProvider.ts | 180 ++++++++++++++++-- .../byok/vscode-node/customOAIProvider.ts | 4 +- .../codeBlocks/node/codeBlockProcessor.ts | 39 ++-- .../common/configurationService.ts | 2 +- 4 files changed, 186 insertions(+), 39 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 673e8ca845..e0a7db025e 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -4,15 +4,27 @@ *--------------------------------------------------------------------------------------------*/ import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService'; +import { IChatModelInformation, ModelSupportedEndpoint } from '../../../platform/endpoint/common/endpointProvider'; import { ILogService } from '../../../platform/log/common/logService'; import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService'; import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; +import { BYOKModelCapabilities } from '../common/byokProvider'; import { IBYOKStorageService } from './byokStorageService'; import { CustomOAIBYOKModelProvider, hasExplicitApiPath } from './customOAIProvider'; -export function resolveAzureUrl(modelId: string, url: string): string { +export interface AzureUrlOptions { + deploymentType?: 'completions' | 'responses'; + deploymentName?: string; + apiVersion?: string; +} + +export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrlOptions, logService?: ILogService): string { + logService?.info(`[Azure Debug] resolveAzureUrl called - modelId: ${modelId}, url: ${url}`); + logService?.info(`[Azure Debug] options: ${JSON.stringify(options, null, 2)}`); + // The fully resolved url was already passed in if (hasExplicitApiPath(url)) { + logService?.info(`[Azure Debug] URL has explicit API path, returning as-is: ${url}`); return url; } @@ -25,15 +37,50 @@ export function resolveAzureUrl(modelId: string, url: string): string { url = url.slice(0, -3); } - // Default to chat completions for base URLs - const defaultApiPath = '/chat/completions'; + // Check if deployment type is specified + // If no deployment name is provided, use modelId as fallback + const deploymentName = options?.deploymentName || modelId; + const deploymentType = options?.deploymentType || 'completions'; + const apiVersion = options?.apiVersion || '2025-01-01-preview'; + + logService?.info(`[Azure Debug] Resolved values - deploymentName: ${deploymentName}, deploymentType: ${deploymentType}, apiVersion: ${apiVersion}`); + + // Determine if this is an Azure OpenAI endpoint (requires deployment name in path) + const isAzureOpenAIEndpointv1 = url.includes('models.ai.azure.com') || url.includes('inference.ml.azure.com'); + const isAzureOpenAIEndpoint = url.includes('openai.azure.com') || url.includes('cognitiveservices.azure.com'); + + logService?.info(`[Azure Debug] Endpoint detection - v1: ${isAzureOpenAIEndpointv1}, standard: ${isAzureOpenAIEndpoint}`); - if (url.includes('models.ai.azure.com') || url.includes('inference.ml.azure.com')) { - return `${url}/v1${defaultApiPath}`; - } else if (url.includes('openai.azure.com')) { - return `${url}/openai/deployments/${modelId}${defaultApiPath}?api-version=2025-01-01-preview`; + if (deploymentType === 'responses') { + // Handle Responses API + // Deployment name is passed in the request body as 'model' parameter, not in URL + let resolvedUrl: string; + if (isAzureOpenAIEndpointv1) { + resolvedUrl = `${url}/v1/responses?api-version=${apiVersion}`; + } else if (isAzureOpenAIEndpoint) { + resolvedUrl = `${url}/openai/responses?api-version=${apiVersion}`; + } else { + throw new Error(`Unrecognized Azure deployment URL for Responses API: ${url}`); + } + logService?.info(`[Azure Debug] Responses API URL resolved to: ${resolvedUrl}`); + logService?.info(`[Azure Debug] NOTE: Deployment name '${deploymentName}' will be sent in request body as 'model' field`); + return resolvedUrl; + } else if (deploymentType === 'completions') { + // Handle Chat Completions API (default) + const defaultApiPath = '/chat/completions'; + let resolvedUrl: string; + + if (isAzureOpenAIEndpointv1) { + resolvedUrl = `${url}/v1${defaultApiPath}`; + } else if (isAzureOpenAIEndpoint) { + resolvedUrl = `${url}/openai/deployments/${deploymentName}${defaultApiPath}?api-version=${apiVersion}`; + } else { + throw new Error(`Unrecognized Azure deployment URL: ${url}`); + } + logService?.info(`[Azure Debug] Completions API URL resolved to: ${resolvedUrl}`); + return resolvedUrl; } else { - throw new Error(`Unrecognized Azure deployment URL: ${url}`); + throw new Error(`Invalid deployment type specified for model ${modelId}: ${deploymentType}`); } } @@ -41,21 +88,26 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { static override readonly providerName = 'Azure'; constructor( - byokStorageService: IBYOKStorageService, - @IConfigurationService configurationService: IConfigurationService, - @ILogService logService: ILogService, - @IInstantiationService instantiationService: IInstantiationService, - @IExperimentationService experimentationService: IExperimentationService + _byokStorageService: IBYOKStorageService, + @IConfigurationService _configurationService: IConfigurationService, + @ILogService _logService: ILogService, + @IInstantiationService _instantiationService: IInstantiationService, + @IExperimentationService _experimentationService: IExperimentationService ) { super( - byokStorageService, - configurationService, - logService, - instantiationService, - experimentationService + _byokStorageService, + _configurationService, + _logService, + _instantiationService, + _experimentationService ); // Override the instance properties this.providerName = AzureBYOKModelProvider.providerName; + + // Bind methods to ensure proper context + this.resolveUrl = this.resolveUrl.bind(this); + this.getModelInfo = this.getModelInfo.bind(this); + this.getConfigKey = this.getConfigKey.bind(this); } protected override getConfigKey() { @@ -63,6 +115,96 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { } protected override resolveUrl(modelId: string, url: string): string { - return resolveAzureUrl(modelId, url); + this._logService?.info(`[Azure Debug] resolveUrl called for modelId: ${modelId}`); + try { + // Get model config to access deployment options + const modelConfig = this._configurationService?.getConfig(this.getConfigKey()) as Record | undefined; + + const config = modelConfig?.[modelId]; + this._logService?.info(`[Azure Debug] Model config for ${modelId}: ${JSON.stringify(config, null, 2)}`); + + const options: AzureUrlOptions | undefined = config ? { + deploymentType: config.deploymentType, + deploymentName: config.deploymentName, + apiVersion: config.apiVersion + } : undefined; + + const resolvedUrl = resolveAzureUrl(modelId, url, options, this._logService); + this._logService?.info(`[Azure Debug] Final resolved URL: ${resolvedUrl}`); + return resolvedUrl; + } catch (error) { + this._logService?.error(`AzureBYOKModelProvider: Error resolving URL for model ${modelId}:`, error); + // Fallback to basic URL resolution + return resolveAzureUrl(modelId, url, undefined, this._logService); + } + } + + protected override async getModelInfo(modelId: string, apiKey: string | undefined, modelCapabilities?: BYOKModelCapabilities): Promise { + this._logService?.info(`[Azure Debug] getModelInfo called for modelId: ${modelId}`); + this._logService?.info(`[Azure Debug] Initial modelCapabilities: ${JSON.stringify(modelCapabilities, null, 2)}`); + try { + // Get model config to check deployment type and deployment name + const configKey = this.getConfigKey(); + this._logService?.info(`[Azure Debug] Config key: ${configKey}`); + + const modelConfig = this._configurationService?.getConfig(configKey); + this._logService?.info(`[Azure Debug] Raw modelConfig type: ${typeof modelConfig}, value: ${JSON.stringify(modelConfig, null, 2)}`); + + // Safely access the model-specific config + let config: { deploymentType?: 'completions' | 'responses'; deploymentName?: string } | undefined; + if (modelConfig && typeof modelConfig === 'object' && modelId in modelConfig) { + config = (modelConfig as Record)[modelId]; + } + + this._logService?.info(`[Azure Debug] Model config for ${modelId}: ${JSON.stringify(config, null, 2)}`); + + const deploymentType = config?.deploymentType || 'completions'; + // If no deployment name is provided, use modelId as fallback + const deploymentName = config?.deploymentName || modelId; + + this._logService?.info(`[Azure Debug] Deployment info - type: ${deploymentType}, name: ${deploymentName}`); + + // For Azure Responses API, the 'model' field in the request body must be the deployment name + // We override the modelCapabilities.name to be the deployment name so it gets used correctly + let updatedCapabilities = modelCapabilities; + if (deploymentType === 'responses' && modelCapabilities) { + updatedCapabilities = { + ...modelCapabilities, + name: deploymentName + }; + this._logService?.info(`[Azure Debug] RESPONSES API: Overriding model name from '${modelCapabilities.name}' to '${deploymentName}'`); + this._logService?.info(`[Azure Debug] Updated capabilities: ${JSON.stringify(updatedCapabilities, null, 2)}`); + } else { + this._logService?.info(`[Azure Debug] COMPLETIONS API: Using capabilities as-is (deployment name in URL)`); + } + + const modelInfo = await super.getModelInfo(modelId, apiKey, updatedCapabilities); + + // Always set modelInfo.id to deployment name for Azure deployments + modelInfo.id = deploymentName; + + // Set supported endpoints based on deployment type + if (deploymentType === 'responses') { + modelInfo.supported_endpoints = [ModelSupportedEndpoint.Responses]; + this._logService?.info(`[Azure Debug] Set supported_endpoints to: [Responses]`); + } else { + // For completions API, only support chat completions + modelInfo.supported_endpoints = [ModelSupportedEndpoint.ChatCompletions]; + this._logService?.info(`[Azure Debug] Set supported_endpoints to: [ChatCompletions]`); + } + this._logService?.info(`[Azure Debug] Set modelInfo.id to deployment name: '${deploymentName}'`); + this._logService?.info(`[Azure Debug] Final modelInfo.id: ${modelInfo.id}`); + this._logService?.info(`[Azure Debug] Final modelInfo.supported_endpoints: ${JSON.stringify(modelInfo.supported_endpoints)}`); + + return modelInfo; + } catch (error) { + this._logService?.error(`AzureBYOKModelProvider: Error getting model info for ${modelId}:`, error); + throw error; + } } } diff --git a/src/extension/byok/vscode-node/customOAIProvider.ts b/src/extension/byok/vscode-node/customOAIProvider.ts index 825226dd4c..bc75d0fc6d 100644 --- a/src/extension/byok/vscode-node/customOAIProvider.ts +++ b/src/extension/byok/vscode-node/customOAIProvider.ts @@ -86,8 +86,8 @@ export class CustomOAIBYOKModelProvider implements BYOKModelProvider }> { - const modelConfig = this._configurationService.getConfig(this.getConfigKey()) as Record }>; + private getUserModelConfig(): Record; deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string }> { + const modelConfig = this._configurationService.getConfig(this.getConfigKey()) as Record; deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string }>; return modelConfig; } diff --git a/src/extension/codeBlocks/node/codeBlockProcessor.ts b/src/extension/codeBlocks/node/codeBlockProcessor.ts index a7788366ae..c5671f5fd8 100644 --- a/src/extension/codeBlocks/node/codeBlockProcessor.ts +++ b/src/extension/codeBlocks/node/codeBlockProcessor.ts @@ -102,26 +102,31 @@ export class CodeBlockTrackingChatResponseStream implements ChatResponseStream { return new CodeBlocksMetadata(this._codeBlocks); } - private forward(fc: CallableFunction) { - return (...args: any[]) => { + private forward(methodName: K): ChatResponseStream[K] { + const method = this._wrapped[methodName]; + if (typeof method !== 'function') { + // Return a no-op function for missing methods + return ((() => { }) as any); + } + return ((...args: any[]) => { this._codeBlockProcessor.flush(); - return fc(...args); - }; + return (method as Function).apply(this._wrapped, args); + }) as any; } - button = this.forward(this._wrapped.button.bind(this._wrapped)); - filetree = this.forward(this._wrapped.filetree.bind(this._wrapped)); - progress = this._wrapped.progress.bind(this._wrapped); - reference = this.forward(this._wrapped.reference.bind(this._wrapped)); - textEdit = this.forward(this._wrapped.textEdit.bind(this._wrapped)); - notebookEdit = this.forward(this._wrapped.notebookEdit.bind(this._wrapped)); - confirmation = this.forward(this._wrapped.confirmation.bind(this._wrapped)); - warning = this.forward(this._wrapped.warning.bind(this._wrapped)); - reference2 = this.forward(this._wrapped.reference2.bind(this._wrapped)); - codeCitation = this.forward(this._wrapped.codeCitation.bind(this._wrapped)); - anchor = this.forward(this._wrapped.anchor.bind(this._wrapped)); - externalEdit = this.forward(this._wrapped.externalEdit.bind(this._wrapped)); - prepareToolInvocation = this.forward(this._wrapped.prepareToolInvocation.bind(this._wrapped)); + button = this.forward('button'); + filetree = this.forward('filetree'); + progress = this.forward('progress'); + reference = this.forward('reference'); + textEdit = this.forward('textEdit'); + notebookEdit = this.forward('notebookEdit'); + confirmation = this.forward('confirmation'); + warning = this.forward('warning'); + reference2 = this.forward('reference2'); + codeCitation = this.forward('codeCitation'); + anchor = this.forward('anchor'); + externalEdit = this.forward('externalEdit'); + prepareToolInvocation = this.forward('prepareToolInvocation'); } diff --git a/src/platform/configuration/common/configurationService.ts b/src/platform/configuration/common/configurationService.ts index c45571f14b..2ca0159139 100644 --- a/src/platform/configuration/common/configurationService.ts +++ b/src/platform/configuration/common/configurationService.ts @@ -811,7 +811,7 @@ export namespace ConfigKey { export const CurrentEditorAgentContext = defineSetting('chat.agent.currentEditorContext.enabled', true); /** BYOK */ export const OllamaEndpoint = defineSetting('chat.byok.ollamaEndpoint', 'http://localhost:11434'); - export const AzureModels = defineSetting>('chat.azureModels', {}); + export const AzureModels = defineSetting>('chat.azureModels', {}); export const CustomOAIModels = defineSetting }>>('chat.customOAIModels', {}); export const AutoFixDiagnostics = defineExpSetting('chat.agent.autoFix', true); export const NotebookFollowCellExecution = defineSetting('chat.notebook.followCellExecution.enabled', false); From e59cf3cbabed415612042747acfe5bc2e933b000 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Mon, 3 Nov 2025 12:56:19 +0200 Subject: [PATCH 02/21] Add support for Azure Foundry models using temperature --- package.json | 28 +++++++++++++++---- src/extension/byok/common/byokProvider.ts | 4 +++ src/extension/byok/node/openAIEndpoint.ts | 6 ++++ .../byok/vscode-node/azureProvider.ts | 9 +++++- .../byok/vscode-node/customOAIProvider.ts | 13 ++++++--- .../endpoint/common/endpointProvider.ts | 1 + 6 files changed, 50 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 4f4a722f27..d2be7301cf 100644 --- a/package.json +++ b/package.json @@ -3035,13 +3035,17 @@ "type": "string", "description": "URL endpoint for the Azure model" }, - "toolCalling": { - "type": "boolean", - "description": "Whether the model supports tool calling" + "deploymentName": { + "type": "string", + "description": "Azure deployment name for the model" }, - "vision": { - "type": "boolean", - "description": "Whether the model supports vision capabilities" + "deploymentType": { + "type": "string", + "description": "Type of Azure deployment" + }, + "apiVersion": { + "type": "string", + "description": "Azure OpenAI API version to use" }, "maxInputTokens": { "type": "number", @@ -3051,11 +3055,23 @@ "type": "number", "description": "Maximum number of output tokens supported by the model" }, + "toolCalling": { + "type": "boolean", + "description": "Whether the model supports tool calling" + }, + "vision": { + "type": "boolean", + "description": "Whether the model supports vision capabilities" + }, "thinking": { "type": "boolean", "default": false, "description": "Whether the model supports thinking capabilities" }, + "temperature": { + "type": "number", + "description": "Temperature parameter for model responses (typically 0.0 to 2.0)" + }, "requestHeaders": { "type": "object", "description": "Additional HTTP headers to include with requests to this model. These reserved headers are not allowed and ignored if present: forbidden request headers (https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header), forwarding headers ('forwarded', 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto'), and others ('api-key', 'authorization', 'content-type', 'openai-intent', 'x-github-api-version', 'x-initiator', 'x-interaction-id', 'x-interaction-type', 'x-onbehalf-extension-id', 'x-request-id', 'x-vscode-user-agent-library-version'). Pattern-based forbidden headers ('proxy-*', 'sec-*', 'x-http-method*' with forbidden methods) are also blocked.", diff --git a/src/extension/byok/common/byokProvider.ts b/src/extension/byok/common/byokProvider.ts index b4c1bd4928..8d23d3c1f1 100644 --- a/src/extension/byok/common/byokProvider.ts +++ b/src/extension/byok/common/byokProvider.ts @@ -55,6 +55,7 @@ export interface BYOKModelCapabilities { toolCalling: boolean; vision: boolean; thinking?: boolean; + temperature?: number; editTools?: EndpointEditToolName[]; requestHeaders?: Record; } @@ -153,6 +154,9 @@ export function resolveModelInfo(modelId: string, providerName: string, knownMod if (knownModelInfo?.requestHeaders && Object.keys(knownModelInfo.requestHeaders).length > 0) { modelInfo.requestHeaders = { ...knownModelInfo.requestHeaders }; } + if (knownModelInfo?.temperature !== undefined) { + modelInfo.temperature = knownModelInfo.temperature; + } return modelInfo; } diff --git a/src/extension/byok/node/openAIEndpoint.ts b/src/extension/byok/node/openAIEndpoint.ts index 63fd236ccb..a8e0182c73 100644 --- a/src/extension/byok/node/openAIEndpoint.ts +++ b/src/extension/byok/node/openAIEndpoint.ts @@ -113,6 +113,7 @@ export class OpenAIEndpoint extends ChatEndpoint { private static readonly _maxCustomHeaderCount = 20; private readonly _customHeaders: Record; + private readonly _temperature: number | undefined; constructor( _modelMetadata: IChatModelInformation, protected readonly _apiKey: string, @@ -144,6 +145,7 @@ export class OpenAIEndpoint extends ChatEndpoint { logService ); this._customHeaders = this._sanitizeCustomHeaders(_modelMetadata.requestHeaders); + this._temperature = _modelMetadata.temperature; } private _sanitizeCustomHeaders(headers: Readonly> | undefined): Record { @@ -294,6 +296,10 @@ export class OpenAIEndpoint extends ChatEndpoint { body['max_completion_tokens'] = body.max_tokens; delete body.max_tokens; } + // Apply temperature from config if specified (and not a thinking model) + if (this._temperature !== undefined && !this.modelMetadata.capabilities.supports.thinking) { + body.temperature = this._temperature; + } // Removing max tokens defaults to the maximum which is what we want for BYOK delete body.max_tokens; if (!this.useResponsesApi && body.stream) { diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index e0a7db025e..439b89961a 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -122,6 +122,7 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string; + temperature?: number; url: string; }> | undefined; @@ -156,7 +157,7 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { this._logService?.info(`[Azure Debug] Raw modelConfig type: ${typeof modelConfig}, value: ${JSON.stringify(modelConfig, null, 2)}`); // Safely access the model-specific config - let config: { deploymentType?: 'completions' | 'responses'; deploymentName?: string } | undefined; + let config: { deploymentType?: 'completions' | 'responses'; deploymentName?: string; temperature?: number } | undefined; if (modelConfig && typeof modelConfig === 'object' && modelId in modelConfig) { config = (modelConfig as Record)[modelId]; } @@ -188,6 +189,12 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { // Always set modelInfo.id to deployment name for Azure deployments modelInfo.id = deploymentName; + // Set temperature from config if specified + if (config?.temperature !== undefined) { + modelInfo.temperature = config.temperature; + this._logService?.info(`[Azure Debug] Set temperature from config: ${config.temperature}`); + } + // Set supported endpoints based on deployment type if (deploymentType === 'responses') { modelInfo.supported_endpoints = [ModelSupportedEndpoint.Responses]; diff --git a/src/extension/byok/vscode-node/customOAIProvider.ts b/src/extension/byok/vscode-node/customOAIProvider.ts index bc75d0fc6d..bdc2a36a37 100644 --- a/src/extension/byok/vscode-node/customOAIProvider.ts +++ b/src/extension/byok/vscode-node/customOAIProvider.ts @@ -48,6 +48,7 @@ interface CustomOAIModelInfo extends LanguageModelChatInformation { url: string; thinking: boolean; requestHeaders?: Record; + temperature?: number; } export class CustomOAIBYOKModelProvider implements BYOKModelProvider { @@ -86,8 +87,8 @@ export class CustomOAIBYOKModelProvider implements BYOKModelProvider; deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string }> { - const modelConfig = this._configurationService.getConfig(this.getConfigKey()) as Record; deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string }>; + private getUserModelConfig(): Record; deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string; temperature?: number }> { + const modelConfig = this._configurationService.getConfig(this.getConfigKey()) as Record; deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string; temperature?: number }>; return modelConfig; } @@ -113,7 +114,8 @@ export class CustomOAIBYOKModelProvider implements BYOKModelProvider>; + temperature?: number; }; export function isChatModelInformation(model: IModelAPIResponse): model is IChatModelInformation { From cab7654d7bfb97df1b59cc32ce97e41599f923ff Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Mon, 3 Nov 2025 12:59:25 +0200 Subject: [PATCH 03/21] Add settings instructions for Azure Foundry models improvements --- .../azure-provider-settings.instructions.md | 273 ++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 .github/instructions/azure-provider-settings.instructions.md diff --git a/.github/instructions/azure-provider-settings.instructions.md b/.github/instructions/azure-provider-settings.instructions.md new file mode 100644 index 0000000000..afd840a021 --- /dev/null +++ b/.github/instructions/azure-provider-settings.instructions.md @@ -0,0 +1,273 @@ +--- +applyTo: '**/byok/**' +description: Azure provider settings format and configuration guidelines +--- + +# Azure Provider Settings Configuration + +Guidelines for configuring Azure OpenAI models in the BYOK (Bring Your Own Key) system using the `chat.azureModels` VS Code setting. + +## Settings Format + +The `chat.azureModels` setting accepts a record of model configurations where each key is a unique model identifier and the value is a model configuration object. + +### Model Configuration Schema + +```typescript +{ + "chat.azureModels": { + "[modelId]": { + "name": string, // Display name for the model + "url": string, // Azure endpoint URL (base URL without API path) + "deploymentType": "completions" | "responses", // API type (default: "completions") + "deploymentName": string, // Azure deployment name (optional, defaults to modelId) + "apiVersion": string, // Azure API version (optional, default: "2025-01-01-preview") + "temperature": number, // Temperature setting (optional, 0.0-2.0) + "toolCalling": boolean, // Whether model supports function/tool calling + "vision": boolean, // Whether model supports vision/image inputs + "maxInputTokens": number, // Maximum input context window size + "maxOutputTokens": number, // Maximum output tokens per response + "requiresAPIKey": boolean, // Whether model requires API key (optional, default: true) + "thinking": boolean // Whether model supports thinking/reasoning tokens (optional) + } + } +} +``` + +## URL Resolution Behavior + +### Base URL Format +The `url` field should contain the **base Azure endpoint URL** without the API path: + +```json +// ✅ Correct - base URL only +"url": "https://my-resource.openai.azure.com" +"url": "https://my-resource.models.ai.azure.com" + +// ❌ Wrong - includes API path +"url": "https://my-resource.openai.azure.com/openai/deployments/gpt-4/chat/completions" +``` + +### Deployment Types + +#### 1. Chat Completions API (`deploymentType: "completions"`) +**Default deployment type.** Uses the standard Azure OpenAI Chat Completions endpoint. + +- **URL Pattern**: Deployment name is included in the URL path +- **Azure OpenAI endpoints** (`openai.azure.com`): + - Resolved URL: `{url}/openai/deployments/{deploymentName}/chat/completions?api-version={apiVersion}` +- **Azure AI endpoints** (`models.ai.azure.com`, `inference.ml.azure.com`): + - Resolved URL: `{url}/v1/chat/completions` + +**Example Configuration:** +```json +{ + "chat.azureModels": { + "gpt-4-turbo": { + "name": "GPT-4 Turbo", + "url": "https://my-resource.openai.azure.com", + "deploymentType": "completions", + "deploymentName": "gpt-4-turbo-deployment", + "apiVersion": "2024-08-01-preview", + "toolCalling": true, + "vision": false, + "maxInputTokens": 128000, + "maxOutputTokens": 4096 + } + } +} +``` + +#### 2. Responses API (`deploymentType: "responses"`) +Uses the Azure OpenAI Responses API for streaming responses with structured outputs. + +- **URL Pattern**: Deployment name is sent in the request body, NOT in URL +- **Azure OpenAI endpoints** (`openai.azure.com`): + - Resolved URL: `{url}/openai/responses?api-version={apiVersion}` +- **Azure AI endpoints** (`models.ai.azure.com`, `inference.ml.azure.com`): + - Resolved URL: `{url}/v1/responses?api-version={apiVersion}` +- **Model Field**: The `deploymentName` is passed as the `model` field in the request body + +**Example Configuration:** +```json +{ + "chat.azureModels": { + "o1-preview": { + "name": "OpenAI o1-preview", + "url": "https://my-resource.openai.azure.com", + "deploymentType": "responses", + "deploymentName": "o1-preview-deployment", + "apiVersion": "2025-01-01-preview", + "toolCalling": false, + "vision": true, + "thinking": true, + "maxInputTokens": 128000, + "maxOutputTokens": 32768 + } + } +} +``` + +### Deployment Name Behavior + +- **If `deploymentName` is provided**: Uses the specified deployment name +- **If `deploymentName` is omitted**: Falls back to using `modelId` as the deployment name +- **For Completions API**: Deployment name is included in the URL path +- **For Responses API**: Deployment name is sent as the `model` field in the request body + +## Complete Configuration Examples + +### Example 1: Azure OpenAI - Chat Completions +```json +{ + "chat.azureModels": { + "gpt-4": { + "name": "GPT-4", + "url": "https://my-eastus-resource.openai.azure.com", + "deploymentType": "completions", + "deploymentName": "gpt-4-prod", + "apiVersion": "2024-08-01-preview", + "temperature": 0.7, + "toolCalling": true, + "vision": false, + "maxInputTokens": 8192, + "maxOutputTokens": 4096, + "requiresAPIKey": true + } + } +} +``` + +### Example 2: Azure AI - Responses API with Reasoning +```json +{ + "chat.azureModels": { + "o1": { + "name": "OpenAI o1", + "url": "https://my-resource.models.ai.azure.com", + "deploymentType": "responses", + "deploymentName": "o1-deployment", + "apiVersion": "2025-01-01-preview", + "toolCalling": false, + "vision": true, + "thinking": true, + "maxInputTokens": 200000, + "maxOutputTokens": 100000, + "requiresAPIKey": true + } + } +} +``` + +### Example 3: Multiple Models +```json +{ + "chat.azureModels": { + "gpt-35-turbo": { + "name": "GPT-3.5 Turbo", + "url": "https://my-resource.openai.azure.com", + "deploymentType": "completions", + "deploymentName": "gpt-35-turbo-16k", + "toolCalling": true, + "vision": false, + "maxInputTokens": 16384, + "maxOutputTokens": 4096 + }, + "gpt-4-vision": { + "name": "GPT-4 Vision", + "url": "https://my-resource.openai.azure.com", + "deploymentType": "completions", + "deploymentName": "gpt-4-vision-preview", + "toolCalling": true, + "vision": true, + "maxInputTokens": 128000, + "maxOutputTokens": 4096 + }, + "o1-preview": { + "name": "OpenAI o1 Preview", + "url": "https://my-resource.openai.azure.com", + "deploymentType": "responses", + "deploymentName": "o1-preview", + "toolCalling": false, + "vision": true, + "thinking": true, + "maxInputTokens": 128000, + "maxOutputTokens": 32768 + } + } +} +``` + +## Implementation Details + +### URL Resolution Logic (`resolveAzureUrl`) + +The `resolveAzureUrl` function in `azureProvider.ts` handles URL construction: + +1. **Strips trailing slashes and `/v1` suffixes** from base URLs +2. **Detects endpoint type** based on URL patterns: + - Azure AI: `models.ai.azure.com`, `inference.ml.azure.com` + - Azure OpenAI: `openai.azure.com`, `cognitiveservices.azure.com` +3. **Applies deployment-specific URL patterns** based on `deploymentType` +4. **Uses defaults** if optional fields are omitted: + - `deploymentType`: `"completions"` + - `deploymentName`: Falls back to `modelId` + - `apiVersion`: `"2025-01-01-preview"` + +### Model Info Resolution (`getModelInfo`) + +The `getModelInfo` method in `AzureBYOKModelProvider`: + +1. **Retrieves deployment configuration** from settings +2. **For Responses API**: Overrides the model name to use `deploymentName` (sent in request body) +3. **For Completions API**: Uses `deploymentName` in URL path +4. **Sets `modelInfo.id`** to the deployment name for proper API routing +5. **Configures `supported_endpoints`**: + - Responses API: `[ModelSupportedEndpoint.Responses]` + - Completions API: `[ModelSupportedEndpoint.ChatCompletions]` +6. **Applies temperature** from configuration if specified + +### API Key Management + +- API keys are stored securely using VS Code's secrets storage +- Keys are stored per-model using the pattern: `copilot-byok-Azure-{modelId}-api-key` +- The `requiresAPIKey` field controls whether authentication is required (default: `true`) +- Users configure API keys through the UI or via commands + +## Best Practices + +1. **Use explicit deployment names**: Always specify `deploymentName` to avoid confusion with model IDs +2. **Match API versions**: Use the API version that matches your Azure deployment capabilities +3. **Set accurate token limits**: Configure `maxInputTokens` and `maxOutputTokens` based on your deployment +4. **Enable appropriate capabilities**: Set `toolCalling`, `vision`, and `thinking` flags based on model support +5. **Test endpoint URLs**: Verify base URLs are correct and accessible before adding models +6. **Group related models**: Use descriptive model IDs for easy identification in the UI +7. **Document custom configurations**: Add comments in settings.json to explain non-standard configurations + +## Troubleshooting + +### Common Issues + +**Issue**: Model not appearing in selection +- **Check**: Verify `requiresAPIKey` is set correctly and API key is configured +- **Check**: Ensure all required fields are present in configuration + +**Issue**: 404 errors when using model +- **Check**: Verify `deploymentName` matches your Azure deployment +- **Check**: Ensure `url` points to the correct Azure resource +- **Check**: Confirm `apiVersion` is supported by your deployment + +**Issue**: Unsupported endpoint errors +- **Check**: Verify `deploymentType` matches your deployment's API type +- **Check**: For reasoning models (o1), use `deploymentType: "responses"` + +**Issue**: Model name mismatches in API calls +- **For Responses API**: Ensure `deploymentName` is set (it's sent as the model name) +- **For Completions API**: Deployment name is in URL, not request body + +## Related Files + +- Implementation: `src/extension/byok/vscode-node/azureProvider.ts` +- Base provider: `src/extension/byok/vscode-node/customOAIProvider.ts` +- Configuration: `src/platform/configuration/common/configurationService.ts` +- Storage: `src/extension/byok/vscode-node/byokStorageService.ts` From 7b4ed96edb829579e23aef343b2ed4904e8ec5fe Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Mon, 3 Nov 2025 14:31:41 +0200 Subject: [PATCH 04/21] Removed debug logs from azure provider --- .../byok/vscode-node/azureProvider.ts | 35 ++----------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 439b89961a..d2653617c8 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -115,7 +115,6 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { } protected override resolveUrl(modelId: string, url: string): string { - this._logService?.info(`[Azure Debug] resolveUrl called for modelId: ${modelId}`); try { // Get model config to access deployment options const modelConfig = this._configurationService?.getConfig(this.getConfigKey()) as Record | undefined; const config = modelConfig?.[modelId]; - this._logService?.info(`[Azure Debug] Model config for ${modelId}: ${JSON.stringify(config, null, 2)}`); const options: AzureUrlOptions | undefined = config ? { deploymentType: config.deploymentType, @@ -136,25 +134,19 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { } : undefined; const resolvedUrl = resolveAzureUrl(modelId, url, options, this._logService); - this._logService?.info(`[Azure Debug] Final resolved URL: ${resolvedUrl}`); return resolvedUrl; } catch (error) { - this._logService?.error(`AzureBYOKModelProvider: Error resolving URL for model ${modelId}:`, error); // Fallback to basic URL resolution return resolveAzureUrl(modelId, url, undefined, this._logService); } } protected override async getModelInfo(modelId: string, apiKey: string | undefined, modelCapabilities?: BYOKModelCapabilities): Promise { - this._logService?.info(`[Azure Debug] getModelInfo called for modelId: ${modelId}`); - this._logService?.info(`[Azure Debug] Initial modelCapabilities: ${JSON.stringify(modelCapabilities, null, 2)}`); try { // Get model config to check deployment type and deployment name const configKey = this.getConfigKey(); - this._logService?.info(`[Azure Debug] Config key: ${configKey}`); const modelConfig = this._configurationService?.getConfig(configKey); - this._logService?.info(`[Azure Debug] Raw modelConfig type: ${typeof modelConfig}, value: ${JSON.stringify(modelConfig, null, 2)}`); // Safely access the model-specific config let config: { deploymentType?: 'completions' | 'responses'; deploymentName?: string; temperature?: number } | undefined; @@ -162,29 +154,11 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { config = (modelConfig as Record)[modelId]; } - this._logService?.info(`[Azure Debug] Model config for ${modelId}: ${JSON.stringify(config, null, 2)}`); - const deploymentType = config?.deploymentType || 'completions'; // If no deployment name is provided, use modelId as fallback const deploymentName = config?.deploymentName || modelId; - this._logService?.info(`[Azure Debug] Deployment info - type: ${deploymentType}, name: ${deploymentName}`); - - // For Azure Responses API, the 'model' field in the request body must be the deployment name - // We override the modelCapabilities.name to be the deployment name so it gets used correctly - let updatedCapabilities = modelCapabilities; - if (deploymentType === 'responses' && modelCapabilities) { - updatedCapabilities = { - ...modelCapabilities, - name: deploymentName - }; - this._logService?.info(`[Azure Debug] RESPONSES API: Overriding model name from '${modelCapabilities.name}' to '${deploymentName}'`); - this._logService?.info(`[Azure Debug] Updated capabilities: ${JSON.stringify(updatedCapabilities, null, 2)}`); - } else { - this._logService?.info(`[Azure Debug] COMPLETIONS API: Using capabilities as-is (deployment name in URL)`); - } - - const modelInfo = await super.getModelInfo(modelId, apiKey, updatedCapabilities); + const modelInfo = await super.getModelInfo(modelId, apiKey, modelCapabilities); // Always set modelInfo.id to deployment name for Azure deployments modelInfo.id = deploymentName; @@ -192,21 +166,16 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { // Set temperature from config if specified if (config?.temperature !== undefined) { modelInfo.temperature = config.temperature; - this._logService?.info(`[Azure Debug] Set temperature from config: ${config.temperature}`); + this._logService?.info(`[Warning] Set temperature from config: ${config.temperature}`); } // Set supported endpoints based on deployment type if (deploymentType === 'responses') { modelInfo.supported_endpoints = [ModelSupportedEndpoint.Responses]; - this._logService?.info(`[Azure Debug] Set supported_endpoints to: [Responses]`); } else { // For completions API, only support chat completions modelInfo.supported_endpoints = [ModelSupportedEndpoint.ChatCompletions]; - this._logService?.info(`[Azure Debug] Set supported_endpoints to: [ChatCompletions]`); } - this._logService?.info(`[Azure Debug] Set modelInfo.id to deployment name: '${deploymentName}'`); - this._logService?.info(`[Azure Debug] Final modelInfo.id: ${modelInfo.id}`); - this._logService?.info(`[Azure Debug] Final modelInfo.supported_endpoints: ${JSON.stringify(modelInfo.supported_endpoints)}`); return modelInfo; } catch (error) { From a1428db36fc10a21bb9923baa0ef6666a82c2061 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Mon, 3 Nov 2025 14:40:36 +0200 Subject: [PATCH 05/21] Fixed Copilot reviewe suggestions --- src/extension/byok/node/openAIEndpoint.ts | 17 +++++++++++------ src/extension/byok/vscode-node/azureProvider.ts | 11 +---------- .../codeBlocks/node/codeBlockProcessor.ts | 2 +- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/extension/byok/node/openAIEndpoint.ts b/src/extension/byok/node/openAIEndpoint.ts index a8e0182c73..53d18e3140 100644 --- a/src/extension/byok/node/openAIEndpoint.ts +++ b/src/extension/byok/node/openAIEndpoint.ts @@ -291,17 +291,22 @@ export class OpenAIEndpoint extends ChatEndpoint { } if (body) { + // Apply temperature from config if specified (before thinking model checks) + if (this._temperature !== undefined) { + body.temperature = this._temperature; + } + if (this.modelMetadata.capabilities.supports.thinking) { + // Thinking models don't support temperature parameter delete body.temperature; + // Thinking models use max_completion_tokens instead of max_tokens body['max_completion_tokens'] = body.max_tokens; delete body.max_tokens; + } else { + // For non-thinking models, removing max_tokens defaults to the maximum which is what we want for BYOK + delete body.max_tokens; } - // Apply temperature from config if specified (and not a thinking model) - if (this._temperature !== undefined && !this.modelMetadata.capabilities.supports.thinking) { - body.temperature = this._temperature; - } - // Removing max tokens defaults to the maximum which is what we want for BYOK - delete body.max_tokens; + if (!this.useResponsesApi && body.stream) { body['stream_options'] = { 'include_usage': true }; } diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index d2653617c8..7d74bf819a 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -19,12 +19,9 @@ export interface AzureUrlOptions { } export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrlOptions, logService?: ILogService): string { - logService?.info(`[Azure Debug] resolveAzureUrl called - modelId: ${modelId}, url: ${url}`); - logService?.info(`[Azure Debug] options: ${JSON.stringify(options, null, 2)}`); // The fully resolved url was already passed in if (hasExplicitApiPath(url)) { - logService?.info(`[Azure Debug] URL has explicit API path, returning as-is: ${url}`); return url; } @@ -43,14 +40,10 @@ export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrl const deploymentType = options?.deploymentType || 'completions'; const apiVersion = options?.apiVersion || '2025-01-01-preview'; - logService?.info(`[Azure Debug] Resolved values - deploymentName: ${deploymentName}, deploymentType: ${deploymentType}, apiVersion: ${apiVersion}`); - // Determine if this is an Azure OpenAI endpoint (requires deployment name in path) const isAzureOpenAIEndpointv1 = url.includes('models.ai.azure.com') || url.includes('inference.ml.azure.com'); const isAzureOpenAIEndpoint = url.includes('openai.azure.com') || url.includes('cognitiveservices.azure.com'); - logService?.info(`[Azure Debug] Endpoint detection - v1: ${isAzureOpenAIEndpointv1}, standard: ${isAzureOpenAIEndpoint}`); - if (deploymentType === 'responses') { // Handle Responses API // Deployment name is passed in the request body as 'model' parameter, not in URL @@ -62,8 +55,7 @@ export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrl } else { throw new Error(`Unrecognized Azure deployment URL for Responses API: ${url}`); } - logService?.info(`[Azure Debug] Responses API URL resolved to: ${resolvedUrl}`); - logService?.info(`[Azure Debug] NOTE: Deployment name '${deploymentName}' will be sent in request body as 'model' field`); + return resolvedUrl; } else if (deploymentType === 'completions') { // Handle Chat Completions API (default) @@ -77,7 +69,6 @@ export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrl } else { throw new Error(`Unrecognized Azure deployment URL: ${url}`); } - logService?.info(`[Azure Debug] Completions API URL resolved to: ${resolvedUrl}`); return resolvedUrl; } else { throw new Error(`Invalid deployment type specified for model ${modelId}: ${deploymentType}`); diff --git a/src/extension/codeBlocks/node/codeBlockProcessor.ts b/src/extension/codeBlocks/node/codeBlockProcessor.ts index c5671f5fd8..63c25c0246 100644 --- a/src/extension/codeBlocks/node/codeBlockProcessor.ts +++ b/src/extension/codeBlocks/node/codeBlockProcessor.ts @@ -106,7 +106,7 @@ export class CodeBlockTrackingChatResponseStream implements ChatResponseStream { const method = this._wrapped[methodName]; if (typeof method !== 'function') { // Return a no-op function for missing methods - return ((() => { }) as any); + return (() => { }) as any; } return ((...args: any[]) => { this._codeBlockProcessor.flush(); From edaa621ee37e33349edd7ee9a599f6d4b58d692a Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Mon, 3 Nov 2025 15:19:52 +0200 Subject: [PATCH 06/21] Fixed Copilot reviewe suggestions --- src/extension/byok/vscode-node/azureProvider.ts | 13 ++++++------- .../configuration/common/configurationService.ts | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 7d74bf819a..784fbe0704 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -13,9 +13,9 @@ import { IBYOKStorageService } from './byokStorageService'; import { CustomOAIBYOKModelProvider, hasExplicitApiPath } from './customOAIProvider'; export interface AzureUrlOptions { - deploymentType?: 'completions' | 'responses'; - deploymentName?: string; - apiVersion?: string; + deploymentType: 'completions' | 'responses'; + deploymentName: string; + apiVersion: string; } export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrlOptions, logService?: ILogService): string { @@ -119,9 +119,9 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { const config = modelConfig?.[modelId]; const options: AzureUrlOptions | undefined = config ? { - deploymentType: config.deploymentType, - deploymentName: config.deploymentName, - apiVersion: config.apiVersion + deploymentType: config.deploymentType || 'completions', + deploymentName: config.deploymentName || modelId, + apiVersion: config.apiVersion || '2025-01-01-preview' } : undefined; const resolvedUrl = resolveAzureUrl(modelId, url, options, this._logService); @@ -157,7 +157,6 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { // Set temperature from config if specified if (config?.temperature !== undefined) { modelInfo.temperature = config.temperature; - this._logService?.info(`[Warning] Set temperature from config: ${config.temperature}`); } // Set supported endpoints based on deployment type diff --git a/src/platform/configuration/common/configurationService.ts b/src/platform/configuration/common/configurationService.ts index 2ca0159139..99bff89936 100644 --- a/src/platform/configuration/common/configurationService.ts +++ b/src/platform/configuration/common/configurationService.ts @@ -812,7 +812,7 @@ export namespace ConfigKey { /** BYOK */ export const OllamaEndpoint = defineSetting('chat.byok.ollamaEndpoint', 'http://localhost:11434'); export const AzureModels = defineSetting>('chat.azureModels', {}); - export const CustomOAIModels = defineSetting }>>('chat.customOAIModels', {}); + export const CustomOAIModels = defineSetting }>>('chat.customOAIModels', {}); export const AutoFixDiagnostics = defineExpSetting('chat.agent.autoFix', true); export const NotebookFollowCellExecution = defineSetting('chat.notebook.followCellExecution.enabled', false); export const UseAlternativeNESNotebookFormat = defineExpSetting('chat.notebook.enhancedNextEditSuggestions.enabled', false); From a0f891f2670d6f0dc3ae39b2f046143cc617b0e8 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Mon, 3 Nov 2025 16:06:07 +0200 Subject: [PATCH 07/21] Fixed Copilot reviews suggestions --- package.json | 4 +++- .../byok/vscode-node/azureProvider.ts | 20 ++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index d2be7301cf..22e17f467d 100644 --- a/package.json +++ b/package.json @@ -3070,7 +3070,9 @@ }, "temperature": { "type": "number", - "description": "Temperature parameter for model responses (typically 0.0 to 2.0)" + "description": "Temperature parameter for model responses (typically 0.0 to 2.0)", + "minimum": 0, + "maximum": 2 }, "requestHeaders": { "type": "object", diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 784fbe0704..f338cb5ed7 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -18,6 +18,14 @@ export interface AzureUrlOptions { apiVersion: string; } +interface AzureModelConfig { + deploymentType?: 'completions' | 'responses'; + deploymentName?: string; + apiVersion?: string; + temperature?: number; + url: string; +} + export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrlOptions, logService?: ILogService): string { // The fully resolved url was already passed in @@ -108,13 +116,7 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { protected override resolveUrl(modelId: string, url: string): string { try { // Get model config to access deployment options - const modelConfig = this._configurationService?.getConfig(this.getConfigKey()) as Record | undefined; + const modelConfig = this._configurationService?.getConfig(this.getConfigKey()) as Record | undefined; const config = modelConfig?.[modelId]; @@ -140,9 +142,9 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { const modelConfig = this._configurationService?.getConfig(configKey); // Safely access the model-specific config - let config: { deploymentType?: 'completions' | 'responses'; deploymentName?: string; temperature?: number } | undefined; + let config: AzureModelConfig | undefined; if (modelConfig && typeof modelConfig === 'object' && modelId in modelConfig) { - config = (modelConfig as Record)[modelId]; + config = (modelConfig as Record)[modelId]; } const deploymentType = config?.deploymentType || 'completions'; From a4227d36fe876c672125e115399d0053ff0db4e8 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 10:54:33 +0200 Subject: [PATCH 08/21] Fixed Copilot reviews suggestions --- src/extension/byok/vscode-node/azureProvider.ts | 2 +- src/extension/codeBlocks/node/codeBlockProcessor.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index f338cb5ed7..97b0d59d87 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -129,7 +129,7 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { const resolvedUrl = resolveAzureUrl(modelId, url, options, this._logService); return resolvedUrl; } catch (error) { - // Fallback to basic URL resolution + this._logService?.error(`AzureBYOKModelProvider: Error resolving URL for model ${modelId}, falling back to basic resolution:`, error); return resolveAzureUrl(modelId, url, undefined, this._logService); } } diff --git a/src/extension/codeBlocks/node/codeBlockProcessor.ts b/src/extension/codeBlocks/node/codeBlockProcessor.ts index 63c25c0246..7e52e585c5 100644 --- a/src/extension/codeBlocks/node/codeBlockProcessor.ts +++ b/src/extension/codeBlocks/node/codeBlockProcessor.ts @@ -9,6 +9,7 @@ import { createFilepathRegexp, mdCodeBlockLangToLanguageId } from '../../../util import { CharCode } from '../../../util/vs/base/common/charCode'; import { isFalsyOrWhitespace, splitLinesIncludeSeparators } from '../../../util/vs/base/common/strings'; +import { ILogService } from '../../../platform/log/common/logService'; import { IPromptPathRepresentationService } from '../../../platform/prompts/common/promptPathRepresentationService'; import { ChatResponseCodeblockUriPart, ChatResponseMarkdownPart, ChatResponseMarkdownWithVulnerabilitiesPart, MarkdownString } from '../../../vscodeTypes'; import { CodeBlock } from '../../prompt/common/conversation'; @@ -38,6 +39,7 @@ export class CodeBlockTrackingChatResponseStream implements ChatResponseStream { private readonly _wrapped: ChatResponseStream, codeblocksRepresentEdits: boolean | undefined, @IPromptPathRepresentationService _promptPathRepresentationService: IPromptPathRepresentationService, + @ILogService private readonly _logService: ILogService, ) { let uriReportedForIndex = -1; this._codeBlockProcessor = new CodeBlockProcessor( @@ -105,7 +107,7 @@ export class CodeBlockTrackingChatResponseStream implements ChatResponseStream { private forward(methodName: K): ChatResponseStream[K] { const method = this._wrapped[methodName]; if (typeof method !== 'function') { - // Return a no-op function for missing methods + this._logService.warn(`[CodeBlockTrackingChatResponseStream] Method '${String(methodName)}' does not exist on the wrapped ChatResponseStream.`); return (() => { }) as any; } return ((...args: any[]) => { From 73eda6534e856085bf7f7f3d998d2f0730afc3c6 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 11:11:52 +0200 Subject: [PATCH 09/21] Fixed Copilot reviews suggestions --- src/extension/byok/vscode-node/azureProvider.ts | 5 ----- src/extension/codeBlocks/node/codeBlockProcessor.ts | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 97b0d59d87..5f78731445 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -102,11 +102,6 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { ); // Override the instance properties this.providerName = AzureBYOKModelProvider.providerName; - - // Bind methods to ensure proper context - this.resolveUrl = this.resolveUrl.bind(this); - this.getModelInfo = this.getModelInfo.bind(this); - this.getConfigKey = this.getConfigKey.bind(this); } protected override getConfigKey() { diff --git a/src/extension/codeBlocks/node/codeBlockProcessor.ts b/src/extension/codeBlocks/node/codeBlockProcessor.ts index 7e52e585c5..b6419f948a 100644 --- a/src/extension/codeBlocks/node/codeBlockProcessor.ts +++ b/src/extension/codeBlocks/node/codeBlockProcessor.ts @@ -108,7 +108,7 @@ export class CodeBlockTrackingChatResponseStream implements ChatResponseStream { const method = this._wrapped[methodName]; if (typeof method !== 'function') { this._logService.warn(`[CodeBlockTrackingChatResponseStream] Method '${String(methodName)}' does not exist on the wrapped ChatResponseStream.`); - return (() => { }) as any; + return (() => undefined) as any; } return ((...args: any[]) => { this._codeBlockProcessor.flush(); From fa45fb2462e20131615dc9b3767678714b59f1a3 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 11:32:35 +0200 Subject: [PATCH 10/21] Fixed Copilot reviews suggestions --- .../byok/vscode-node/azureProvider.ts | 6 ++--- .../byok/vscode-node/customOAIProvider.ts | 23 ++++++++++++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 5f78731445..671eb8c428 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -26,7 +26,7 @@ interface AzureModelConfig { url: string; } -export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrlOptions, logService?: ILogService): string { +export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrlOptions): string { // The fully resolved url was already passed in if (hasExplicitApiPath(url)) { @@ -121,11 +121,11 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { apiVersion: config.apiVersion || '2025-01-01-preview' } : undefined; - const resolvedUrl = resolveAzureUrl(modelId, url, options, this._logService); + const resolvedUrl = resolveAzureUrl(modelId, url, options); return resolvedUrl; } catch (error) { this._logService?.error(`AzureBYOKModelProvider: Error resolving URL for model ${modelId}, falling back to basic resolution:`, error); - return resolveAzureUrl(modelId, url, undefined, this._logService); + return resolveAzureUrl(modelId, url, undefined); } } diff --git a/src/extension/byok/vscode-node/customOAIProvider.ts b/src/extension/byok/vscode-node/customOAIProvider.ts index bdc2a36a37..feb5284d92 100644 --- a/src/extension/byok/vscode-node/customOAIProvider.ts +++ b/src/extension/byok/vscode-node/customOAIProvider.ts @@ -44,10 +44,27 @@ export function hasExplicitApiPath(url: string): boolean { return url.includes('/responses') || url.includes('/chat/completions'); } +interface UserModelConfig { + requestHeaders?: Record; + name: string; + url: string; + deploymentType?: 'completions' | 'responses'; + deploymentName?: string; + apiVersion?: string; + maxInputTokens: number; + maxOutputTokens: number; + requiresAPIKey: boolean; + toolCalling: boolean; + editTools?: EndpointEditToolName[]; + vision: boolean; + thinking?: boolean; + temperature?: number; +} + interface CustomOAIModelInfo extends LanguageModelChatInformation { + requestHeaders?: Record; url: string; thinking: boolean; - requestHeaders?: Record; temperature?: number; } @@ -87,8 +104,8 @@ export class CustomOAIBYOKModelProvider implements BYOKModelProvider; deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string; temperature?: number }> { - const modelConfig = this._configurationService.getConfig(this.getConfigKey()) as Record; deploymentType?: 'completions' | 'responses'; deploymentName?: string; apiVersion?: string; temperature?: number }>; + private getUserModelConfig(): Record { + const modelConfig = this._configurationService.getConfig(this.getConfigKey()) as Record; return modelConfig; } From cc11c74d7e82bfcc9228eacf1ade397ce052ac85 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 11:59:51 +0200 Subject: [PATCH 11/21] Fixed Copilot reviews suggestions --- .../byok/vscode-node/azureProvider.ts | 2 +- .../byok/vscode-node/customOAIProvider.ts | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 671eb8c428..71a6fdfed2 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -148,7 +148,7 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { const modelInfo = await super.getModelInfo(modelId, apiKey, modelCapabilities); - // Always set modelInfo.id to deployment name for Azure deployments + // Set modelInfo.id to deployment name (or modelId if no deployment name configured) modelInfo.id = deploymentName; // Set temperature from config if specified diff --git a/src/extension/byok/vscode-node/customOAIProvider.ts b/src/extension/byok/vscode-node/customOAIProvider.ts index feb5284d92..7ac98615b7 100644 --- a/src/extension/byok/vscode-node/customOAIProvider.ts +++ b/src/extension/byok/vscode-node/customOAIProvider.ts @@ -45,7 +45,6 @@ export function hasExplicitApiPath(url: string): boolean { } interface UserModelConfig { - requestHeaders?: Record; name: string; url: string; deploymentType?: 'completions' | 'responses'; @@ -59,13 +58,14 @@ interface UserModelConfig { vision: boolean; thinking?: boolean; temperature?: number; + requestHeaders?: Record; } interface CustomOAIModelInfo extends LanguageModelChatInformation { - requestHeaders?: Record; url: string; thinking: boolean; temperature?: number; + requestHeaders?: Record; } export class CustomOAIBYOKModelProvider implements BYOKModelProvider { @@ -125,14 +125,14 @@ export class CustomOAIBYOKModelProvider implements BYOKModelProvider Date: Tue, 4 Nov 2025 12:04:20 +0200 Subject: [PATCH 12/21] Fixed Copilot reviews suggestions --- src/extension/byok/node/openAIEndpoint.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/extension/byok/node/openAIEndpoint.ts b/src/extension/byok/node/openAIEndpoint.ts index 53d18e3140..da70c75734 100644 --- a/src/extension/byok/node/openAIEndpoint.ts +++ b/src/extension/byok/node/openAIEndpoint.ts @@ -301,12 +301,12 @@ export class OpenAIEndpoint extends ChatEndpoint { delete body.temperature; // Thinking models use max_completion_tokens instead of max_tokens body['max_completion_tokens'] = body.max_tokens; - delete body.max_tokens; - } else { - // For non-thinking models, removing max_tokens defaults to the maximum which is what we want for BYOK - delete body.max_tokens; } + // For thinking models, replace max_tokens with max_completion_tokens + // For non-thinking models, removing max_tokens defaults to the maximum which is what we want for BYOK + delete body.max_tokens; + if (!this.useResponsesApi && body.stream) { body['stream_options'] = { 'include_usage': true }; } From 13b4b3f29968a7e13ce8e8d8e53764f557c86c4e Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 12:07:48 +0200 Subject: [PATCH 13/21] Fixed Copilot reviews suggestions --- src/extension/codeBlocks/node/codeBlockProcessor.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/extension/codeBlocks/node/codeBlockProcessor.ts b/src/extension/codeBlocks/node/codeBlockProcessor.ts index b6419f948a..724d5fba10 100644 --- a/src/extension/codeBlocks/node/codeBlockProcessor.ts +++ b/src/extension/codeBlocks/node/codeBlockProcessor.ts @@ -108,12 +108,14 @@ export class CodeBlockTrackingChatResponseStream implements ChatResponseStream { const method = this._wrapped[methodName]; if (typeof method !== 'function') { this._logService.warn(`[CodeBlockTrackingChatResponseStream] Method '${String(methodName)}' does not exist on the wrapped ChatResponseStream.`); - return (() => undefined) as any; + // Return a typed no-op function that matches the expected signature + return ((() => undefined) as unknown as ChatResponseStream[K]); } - return ((...args: any[]) => { + // Preserve the function signature by casting to the specific method type + return ((...args: Parameters any>>) => { this._codeBlockProcessor.flush(); return (method as Function).apply(this._wrapped, args); - }) as any; + }) as ChatResponseStream[K]; } button = this.forward('button'); From b4c9a5e7276bd7e15bbf2190e09d8156b8fd028c Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 12:23:10 +0200 Subject: [PATCH 14/21] Fixed Copilot reviews suggestions --- package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package.json b/package.json index 22e17f467d..cb84ed3476 100644 --- a/package.json +++ b/package.json @@ -3150,6 +3150,12 @@ "default": false, "description": "Whether the model supports thinking capabilities" }, + "temperature": { + "type": "number", + "description": "Temperature parameter for model responses (typically 0.0 to 2.0)", + "minimum": 0, + "maximum": 2 + }, "requestHeaders": { "type": "object", "description": "Additional HTTP headers to include with requests to this model. These reserved headers are not allowed and ignored if present: forbidden request headers (https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header), forwarding headers ('forwarded', 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto'), and others ('api-key', 'authorization', 'content-type', 'openai-intent', 'x-github-api-version', 'x-initiator', 'x-interaction-id', 'x-interaction-type', 'x-onbehalf-extension-id', 'x-request-id', 'x-vscode-user-agent-library-version'). Pattern-based forbidden headers ('proxy-*', 'sec-*', 'x-http-method*' with forbidden methods) are also blocked.", From 9ef329607f468350f07fc39333eb668a239722a9 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 13:21:55 +0200 Subject: [PATCH 15/21] Fixed Copilot reviews suggestions --- .../byok/vscode-node/azureProvider.ts | 114 ++++++++---------- 1 file changed, 48 insertions(+), 66 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 71a6fdfed2..c12ffce820 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -19,14 +19,21 @@ export interface AzureUrlOptions { } interface AzureModelConfig { - deploymentType?: 'completions' | 'responses'; - deploymentName?: string; - apiVersion?: string; + deploymentType: 'completions' | 'responses'; + deploymentName: string; + apiVersion: string; temperature?: number; - url: string; } -export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrlOptions): string { +function createAzureUrlOptions(modelId: string, config?: Partial): AzureUrlOptions { + return { + deploymentType: config?.deploymentType ?? 'completions', + deploymentName: config?.deploymentName ?? modelId, + apiVersion: config?.apiVersion ?? '2025-01-01-preview' + }; +} + +export function resolveAzureUrl(modelId: string, url: string, options: AzureUrlOptions): string { // The fully resolved url was already passed in if (hasExplicitApiPath(url)) { @@ -42,11 +49,7 @@ export function resolveAzureUrl(modelId: string, url: string, options?: AzureUrl url = url.slice(0, -3); } - // Check if deployment type is specified - // If no deployment name is provided, use modelId as fallback - const deploymentName = options?.deploymentName || modelId; - const deploymentType = options?.deploymentType || 'completions'; - const apiVersion = options?.apiVersion || '2025-01-01-preview'; + const { deploymentName, deploymentType, apiVersion } = options; // Determine if this is an Azure OpenAI endpoint (requires deployment name in path) const isAzureOpenAIEndpointv1 = url.includes('models.ai.azure.com') || url.includes('inference.ml.azure.com'); @@ -109,65 +112,44 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { } protected override resolveUrl(modelId: string, url: string): string { - try { - // Get model config to access deployment options - const modelConfig = this._configurationService?.getConfig(this.getConfigKey()) as Record | undefined; - - const config = modelConfig?.[modelId]; - - const options: AzureUrlOptions | undefined = config ? { - deploymentType: config.deploymentType || 'completions', - deploymentName: config.deploymentName || modelId, - apiVersion: config.apiVersion || '2025-01-01-preview' - } : undefined; - - const resolvedUrl = resolveAzureUrl(modelId, url, options); - return resolvedUrl; - } catch (error) { - this._logService?.error(`AzureBYOKModelProvider: Error resolving URL for model ${modelId}, falling back to basic resolution:`, error); - return resolveAzureUrl(modelId, url, undefined); - } + // Get model config to access deployment options + const modelConfig = this._configurationService?.getConfig(this.getConfigKey()) as Record | undefined; + const config = modelConfig?.[modelId]; + const options = createAzureUrlOptions(modelId, config); + return resolveAzureUrl(modelId, url, options); } protected override async getModelInfo(modelId: string, apiKey: string | undefined, modelCapabilities?: BYOKModelCapabilities): Promise { - try { - // Get model config to check deployment type and deployment name - const configKey = this.getConfigKey(); - - const modelConfig = this._configurationService?.getConfig(configKey); - - // Safely access the model-specific config - let config: AzureModelConfig | undefined; - if (modelConfig && typeof modelConfig === 'object' && modelId in modelConfig) { - config = (modelConfig as Record)[modelId]; - } - - const deploymentType = config?.deploymentType || 'completions'; - // If no deployment name is provided, use modelId as fallback - const deploymentName = config?.deploymentName || modelId; - - const modelInfo = await super.getModelInfo(modelId, apiKey, modelCapabilities); - - // Set modelInfo.id to deployment name (or modelId if no deployment name configured) - modelInfo.id = deploymentName; - - // Set temperature from config if specified - if (config?.temperature !== undefined) { - modelInfo.temperature = config.temperature; - } - - // Set supported endpoints based on deployment type - if (deploymentType === 'responses') { - modelInfo.supported_endpoints = [ModelSupportedEndpoint.Responses]; - } else { - // For completions API, only support chat completions - modelInfo.supported_endpoints = [ModelSupportedEndpoint.ChatCompletions]; - } - - return modelInfo; - } catch (error) { - this._logService?.error(`AzureBYOKModelProvider: Error getting model info for ${modelId}:`, error); - throw error; + // Get model config to check deployment type and deployment name + const configKey = this.getConfigKey(); + + const modelConfig = this._configurationService?.getConfig(configKey); + + // Safely access the model-specific config + let config: AzureModelConfig | undefined; + if (modelConfig && typeof modelConfig === 'object' && modelId in modelConfig) { + config = (modelConfig as Record)[modelId]; } + + const options = createAzureUrlOptions(modelId, config); + const modelInfo = await super.getModelInfo(modelId, apiKey, modelCapabilities); + + // Set modelInfo.id to deployment name (or modelId if no deployment name configured) + modelInfo.id = options.deploymentName; + + // Set temperature from config if specified + if (config?.temperature !== undefined) { + modelInfo.temperature = config.temperature; + } + + // Set supported endpoints based on deployment type + if (options.deploymentType === 'responses') { + modelInfo.supported_endpoints = [ModelSupportedEndpoint.Responses]; + } else { + // For completions API, only support chat completions + modelInfo.supported_endpoints = [ModelSupportedEndpoint.ChatCompletions]; + } + + return modelInfo; } } From 325f4757ba5e97607eff621c89aaab2688042328 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 13:31:41 +0200 Subject: [PATCH 16/21] Fixed Copilot reviews suggestions --- src/extension/byok/vscode-node/azureProvider.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index c12ffce820..c612ef620a 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -122,8 +122,7 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { protected override async getModelInfo(modelId: string, apiKey: string | undefined, modelCapabilities?: BYOKModelCapabilities): Promise { // Get model config to check deployment type and deployment name const configKey = this.getConfigKey(); - - const modelConfig = this._configurationService?.getConfig(configKey); + const modelConfig = this._configurationService.getConfig(configKey); // Safely access the model-specific config let config: AzureModelConfig | undefined; From ce56e2799b845a6dfdc07efc717cb126062ae737 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Tue, 4 Nov 2025 14:07:12 +0200 Subject: [PATCH 17/21] Fixed Copilot reviews suggestions --- src/extension/byok/node/openAIEndpoint.ts | 7 ++++--- src/extension/byok/vscode-node/azureProvider.ts | 3 ++- .../codeBlocks/node/codeBlockProcessor.ts | 14 +++++++++----- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/extension/byok/node/openAIEndpoint.ts b/src/extension/byok/node/openAIEndpoint.ts index da70c75734..e2d47064e0 100644 --- a/src/extension/byok/node/openAIEndpoint.ts +++ b/src/extension/byok/node/openAIEndpoint.ts @@ -300,11 +300,12 @@ export class OpenAIEndpoint extends ChatEndpoint { // Thinking models don't support temperature parameter delete body.temperature; // Thinking models use max_completion_tokens instead of max_tokens - body['max_completion_tokens'] = body.max_tokens; + if (typeof body.max_tokens !== 'undefined') { + body['max_completion_tokens'] = body.max_tokens; + } } - // For thinking models, replace max_tokens with max_completion_tokens - // For non-thinking models, removing max_tokens defaults to the maximum which is what we want for BYOK + // Removing max_tokens defaults to the maximum which is what we want for BYOK delete body.max_tokens; if (!this.useResponsesApi && body.stream) { diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index c612ef620a..463e5dd4b6 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -133,7 +133,8 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { const options = createAzureUrlOptions(modelId, config); const modelInfo = await super.getModelInfo(modelId, apiKey, modelCapabilities); - // Set modelInfo.id to deployment name (or modelId if no deployment name configured) + // IMPORTANT: Override modelInfo.id with the deployment name (handled above). + // This is required because Azure OpenAI uses the deployment name for API routing. modelInfo.id = options.deploymentName; // Set temperature from config if specified diff --git a/src/extension/codeBlocks/node/codeBlockProcessor.ts b/src/extension/codeBlocks/node/codeBlockProcessor.ts index 724d5fba10..c23f7ef92f 100644 --- a/src/extension/codeBlocks/node/codeBlockProcessor.ts +++ b/src/extension/codeBlocks/node/codeBlockProcessor.ts @@ -108,14 +108,18 @@ export class CodeBlockTrackingChatResponseStream implements ChatResponseStream { const method = this._wrapped[methodName]; if (typeof method !== 'function') { this._logService.warn(`[CodeBlockTrackingChatResponseStream] Method '${String(methodName)}' does not exist on the wrapped ChatResponseStream.`); - // Return a typed no-op function that matches the expected signature - return ((() => undefined) as unknown as ChatResponseStream[K]); + // Create a proper no-op function that matches the method signature + const noOp = (..._args: any[]): any => { + return undefined; + }; + return noOp as ChatResponseStream[K]; } - // Preserve the function signature by casting to the specific method type - return ((...args: Parameters any>>) => { + // Preserve the function signature without double casting + const boundMethod = (...args: any[]) => { this._codeBlockProcessor.flush(); return (method as Function).apply(this._wrapped, args); - }) as ChatResponseStream[K]; + }; + return boundMethod as ChatResponseStream[K]; } button = this.forward('button'); From 5f433070cfdf2dec060bb4399cdacbf678f73516 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Fri, 7 Nov 2025 10:41:29 +0200 Subject: [PATCH 18/21] Fixed Copilot reviews suggestions --- .../azure-provider-settings.instructions.md | 108 +++--------------- package.json | 24 ++-- src/extension/byok/node/openAIEndpoint.ts | 10 +- .../byok/vscode-node/azureProvider.ts | 2 +- 4 files changed, 34 insertions(+), 110 deletions(-) diff --git a/.github/instructions/azure-provider-settings.instructions.md b/.github/instructions/azure-provider-settings.instructions.md index afd840a021..e4fb9c666a 100644 --- a/.github/instructions/azure-provider-settings.instructions.md +++ b/.github/instructions/azure-provider-settings.instructions.md @@ -22,13 +22,12 @@ The `chat.azureModels` setting accepts a record of model configurations where ea "deploymentType": "completions" | "responses", // API type (default: "completions") "deploymentName": string, // Azure deployment name (optional, defaults to modelId) "apiVersion": string, // Azure API version (optional, default: "2025-01-01-preview") - "temperature": number, // Temperature setting (optional, 0.0-2.0) - "toolCalling": boolean, // Whether model supports function/tool calling - "vision": boolean, // Whether model supports vision/image inputs "maxInputTokens": number, // Maximum input context window size "maxOutputTokens": number, // Maximum output tokens per response - "requiresAPIKey": boolean, // Whether model requires API key (optional, default: true) + "toolCalling": boolean, // Whether model supports function/tool calling + "temperature": number, // Temperature setting (optional, 0.0-2.0) "thinking": boolean // Whether model supports thinking/reasoning tokens (optional) + "vision": boolean, // Whether model supports vision/image inputs (optional) } } } @@ -69,10 +68,12 @@ The `url` field should contain the **base Azure endpoint URL** without the API p "deploymentType": "completions", "deploymentName": "gpt-4-turbo-deployment", "apiVersion": "2024-08-01-preview", - "toolCalling": true, - "vision": false, "maxInputTokens": 128000, - "maxOutputTokens": 4096 + "maxOutputTokens": 4096, + "toolCalling": true, + "temperature": 0.7, + "thinking": false, + "vision": false } } } @@ -98,11 +99,12 @@ Uses the Azure OpenAI Responses API for streaming responses with structured outp "deploymentType": "responses", "deploymentName": "o1-preview-deployment", "apiVersion": "2025-01-01-preview", + "maxInputTokens": 128000, + "maxOutputTokens": 32768, "toolCalling": false, - "vision": true, + "temperature": 1.0, "thinking": true, - "maxInputTokens": 128000, - "maxOutputTokens": 32768 + "vision": true } } } @@ -115,89 +117,6 @@ Uses the Azure OpenAI Responses API for streaming responses with structured outp - **For Completions API**: Deployment name is included in the URL path - **For Responses API**: Deployment name is sent as the `model` field in the request body -## Complete Configuration Examples - -### Example 1: Azure OpenAI - Chat Completions -```json -{ - "chat.azureModels": { - "gpt-4": { - "name": "GPT-4", - "url": "https://my-eastus-resource.openai.azure.com", - "deploymentType": "completions", - "deploymentName": "gpt-4-prod", - "apiVersion": "2024-08-01-preview", - "temperature": 0.7, - "toolCalling": true, - "vision": false, - "maxInputTokens": 8192, - "maxOutputTokens": 4096, - "requiresAPIKey": true - } - } -} -``` - -### Example 2: Azure AI - Responses API with Reasoning -```json -{ - "chat.azureModels": { - "o1": { - "name": "OpenAI o1", - "url": "https://my-resource.models.ai.azure.com", - "deploymentType": "responses", - "deploymentName": "o1-deployment", - "apiVersion": "2025-01-01-preview", - "toolCalling": false, - "vision": true, - "thinking": true, - "maxInputTokens": 200000, - "maxOutputTokens": 100000, - "requiresAPIKey": true - } - } -} -``` - -### Example 3: Multiple Models -```json -{ - "chat.azureModels": { - "gpt-35-turbo": { - "name": "GPT-3.5 Turbo", - "url": "https://my-resource.openai.azure.com", - "deploymentType": "completions", - "deploymentName": "gpt-35-turbo-16k", - "toolCalling": true, - "vision": false, - "maxInputTokens": 16384, - "maxOutputTokens": 4096 - }, - "gpt-4-vision": { - "name": "GPT-4 Vision", - "url": "https://my-resource.openai.azure.com", - "deploymentType": "completions", - "deploymentName": "gpt-4-vision-preview", - "toolCalling": true, - "vision": true, - "maxInputTokens": 128000, - "maxOutputTokens": 4096 - }, - "o1-preview": { - "name": "OpenAI o1 Preview", - "url": "https://my-resource.openai.azure.com", - "deploymentType": "responses", - "deploymentName": "o1-preview", - "toolCalling": false, - "vision": true, - "thinking": true, - "maxInputTokens": 128000, - "maxOutputTokens": 32768 - } - } -} -``` - ## Implementation Details ### URL Resolution Logic (`resolveAzureUrl`) @@ -239,7 +158,7 @@ The `getModelInfo` method in `AzureBYOKModelProvider`: 1. **Use explicit deployment names**: Always specify `deploymentName` to avoid confusion with model IDs 2. **Match API versions**: Use the API version that matches your Azure deployment capabilities 3. **Set accurate token limits**: Configure `maxInputTokens` and `maxOutputTokens` based on your deployment -4. **Enable appropriate capabilities**: Set `toolCalling`, `vision`, and `thinking` flags based on model support +4. **Enable appropriate capabilities**: Set `toolCalling`, `thinking` and `vision`, flags based on model support 5. **Test endpoint URLs**: Verify base URLs are correct and accessible before adding models 6. **Group related models**: Use descriptive model IDs for easy identification in the UI 7. **Document custom configurations**: Add comments in settings.json to explain non-standard configurations @@ -249,7 +168,6 @@ The `getModelInfo` method in `AzureBYOKModelProvider`: ### Common Issues **Issue**: Model not appearing in selection -- **Check**: Verify `requiresAPIKey` is set correctly and API key is configured - **Check**: Ensure all required fields are present in configuration **Issue**: 404 errors when using model diff --git a/package.json b/package.json index cb84ed3476..fb2b6692f1 100644 --- a/package.json +++ b/package.json @@ -3059,20 +3059,20 @@ "type": "boolean", "description": "Whether the model supports tool calling" }, - "vision": { - "type": "boolean", - "description": "Whether the model supports vision capabilities" + "temperature": { + "type": "number", + "description": "Temperature parameter for model responses (typically 0.0 to 2.0)", + "minimum": 0, + "maximum": 2 }, "thinking": { "type": "boolean", "default": false, "description": "Whether the model supports thinking capabilities" }, - "temperature": { - "type": "number", - "description": "Temperature parameter for model responses (typically 0.0 to 2.0)", - "minimum": 0, - "maximum": 2 + "vision": { + "type": "boolean", + "description": "Whether the model supports vision capabilities" }, "requestHeaders": { "type": "object", @@ -3085,10 +3085,12 @@ "required": [ "name", "url", - "toolCalling", - "vision", + "deploymentName", + "deploymentType", "maxInputTokens", - "maxOutputTokens" + "maxOutputTokens", + "toolCalling", + "vision" ], "additionalProperties": false }, diff --git a/src/extension/byok/node/openAIEndpoint.ts b/src/extension/byok/node/openAIEndpoint.ts index e2d47064e0..42b34572ea 100644 --- a/src/extension/byok/node/openAIEndpoint.ts +++ b/src/extension/byok/node/openAIEndpoint.ts @@ -302,11 +302,15 @@ export class OpenAIEndpoint extends ChatEndpoint { // Thinking models use max_completion_tokens instead of max_tokens if (typeof body.max_tokens !== 'undefined') { body['max_completion_tokens'] = body.max_tokens; + delete body.max_tokens; + } + } + else { + if (typeof body.max_tokens !== 'undefined') { + body['max_completion_tokens'] = body.max_tokens; + delete body.max_tokens; } } - - // Removing max_tokens defaults to the maximum which is what we want for BYOK - delete body.max_tokens; if (!this.useResponsesApi && body.stream) { body['stream_options'] = { 'include_usage': true }; diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 463e5dd4b6..52074255c1 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -133,7 +133,7 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { const options = createAzureUrlOptions(modelId, config); const modelInfo = await super.getModelInfo(modelId, apiKey, modelCapabilities); - // IMPORTANT: Override modelInfo.id with the deployment name (handled above). + // Override modelInfo.id with the deployment name (deployment name is also handled). // This is required because Azure OpenAI uses the deployment name for API routing. modelInfo.id = options.deploymentName; From 3307f20ba882264ede966ee417ac4c42cebef837 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Fri, 7 Nov 2025 10:57:57 +0200 Subject: [PATCH 19/21] Fixed Copilot reviews suggestions --- .../instructions/azure-provider-settings.instructions.md | 6 +++--- package.json | 2 -- src/extension/byok/node/openAIEndpoint.ts | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/instructions/azure-provider-settings.instructions.md b/.github/instructions/azure-provider-settings.instructions.md index e4fb9c666a..b28de48162 100644 --- a/.github/instructions/azure-provider-settings.instructions.md +++ b/.github/instructions/azure-provider-settings.instructions.md @@ -19,14 +19,14 @@ The `chat.azureModels` setting accepts a record of model configurations where ea "[modelId]": { "name": string, // Display name for the model "url": string, // Azure endpoint URL (base URL without API path) - "deploymentType": "completions" | "responses", // API type (default: "completions") + "deploymentType": "completions" | "responses", // API type (optional, defaults to "completions") "deploymentName": string, // Azure deployment name (optional, defaults to modelId) "apiVersion": string, // Azure API version (optional, default: "2025-01-01-preview") "maxInputTokens": number, // Maximum input context window size "maxOutputTokens": number, // Maximum output tokens per response "toolCalling": boolean, // Whether model supports function/tool calling "temperature": number, // Temperature setting (optional, 0.0-2.0) - "thinking": boolean // Whether model supports thinking/reasoning tokens (optional) + "thinking": boolean, // Whether model supports thinking/reasoning tokens (optional) "vision": boolean, // Whether model supports vision/image inputs (optional) } } @@ -158,7 +158,7 @@ The `getModelInfo` method in `AzureBYOKModelProvider`: 1. **Use explicit deployment names**: Always specify `deploymentName` to avoid confusion with model IDs 2. **Match API versions**: Use the API version that matches your Azure deployment capabilities 3. **Set accurate token limits**: Configure `maxInputTokens` and `maxOutputTokens` based on your deployment -4. **Enable appropriate capabilities**: Set `toolCalling`, `thinking` and `vision`, flags based on model support +4. **Enable appropriate capabilities**: Set `toolCalling`, `thinking` and `vision` flags based on model support 5. **Test endpoint URLs**: Verify base URLs are correct and accessible before adding models 6. **Group related models**: Use descriptive model IDs for easy identification in the UI 7. **Document custom configurations**: Add comments in settings.json to explain non-standard configurations diff --git a/package.json b/package.json index fb2b6692f1..f35e2320c9 100644 --- a/package.json +++ b/package.json @@ -3085,8 +3085,6 @@ "required": [ "name", "url", - "deploymentName", - "deploymentType", "maxInputTokens", "maxOutputTokens", "toolCalling", diff --git a/src/extension/byok/node/openAIEndpoint.ts b/src/extension/byok/node/openAIEndpoint.ts index 42b34572ea..0e89f2eb17 100644 --- a/src/extension/byok/node/openAIEndpoint.ts +++ b/src/extension/byok/node/openAIEndpoint.ts @@ -307,7 +307,6 @@ export class OpenAIEndpoint extends ChatEndpoint { } else { if (typeof body.max_tokens !== 'undefined') { - body['max_completion_tokens'] = body.max_tokens; delete body.max_tokens; } } From c37f2c962893b8bc7e4360408bbbc0c2fe23660f Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Fri, 7 Nov 2025 11:34:29 +0200 Subject: [PATCH 20/21] Fixed Copilot reviews suggestions --- .../azure-provider-settings.instructions.md | 12 ++++++----- package.json | 6 +++++- src/extension/byok/node/openAIEndpoint.ts | 1 + .../byok/vscode-node/azureProvider.ts | 20 +++++++++++-------- .../byok/vscode-node/customOAIProvider.ts | 7 ++----- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/.github/instructions/azure-provider-settings.instructions.md b/.github/instructions/azure-provider-settings.instructions.md index b28de48162..13bf2165af 100644 --- a/.github/instructions/azure-provider-settings.instructions.md +++ b/.github/instructions/azure-provider-settings.instructions.md @@ -19,15 +19,17 @@ The `chat.azureModels` setting accepts a record of model configurations where ea "[modelId]": { "name": string, // Display name for the model "url": string, // Azure endpoint URL (base URL without API path) - "deploymentType": "completions" | "responses", // API type (optional, defaults to "completions") - "deploymentName": string, // Azure deployment name (optional, defaults to modelId) - "apiVersion": string, // Azure API version (optional, default: "2025-01-01-preview") + "deploymentType"?: "completions" | "responses", // API type (optional, defaults to "completions") + "deploymentName"?: string, // Azure deployment name (optional, defaults to modelId) + "apiVersion"?: string, // Azure API version (optional, default: "2025-01-01-preview") "maxInputTokens": number, // Maximum input context window size "maxOutputTokens": number, // Maximum output tokens per response "toolCalling": boolean, // Whether model supports function/tool calling - "temperature": number, // Temperature setting (optional, 0.0-2.0) - "thinking": boolean, // Whether model supports thinking/reasoning tokens (optional) + "temperature"?: number, // Temperature setting (optional, 0.0-2.0) + "thinking"?: boolean, // Whether model supports thinking/reasoning tokens (optional) "vision": boolean, // Whether model supports vision/image inputs (optional) + "requestHeaders"?: Record, // Custom HTTP headers for requests (optional) + "requiresAPIKey"?: boolean, // Whether model requires API key (optional, default: true) } } } diff --git a/package.json b/package.json index f35e2320c9..7d0bb66d7b 100644 --- a/package.json +++ b/package.json @@ -3040,7 +3040,11 @@ "description": "Azure deployment name for the model" }, "deploymentType": { - "type": "string", + "enum": [ + "completions", + "responses" + ], + "default": "completions", "description": "Type of Azure deployment" }, "apiVersion": { diff --git a/src/extension/byok/node/openAIEndpoint.ts b/src/extension/byok/node/openAIEndpoint.ts index 0e89f2eb17..af26953ac8 100644 --- a/src/extension/byok/node/openAIEndpoint.ts +++ b/src/extension/byok/node/openAIEndpoint.ts @@ -306,6 +306,7 @@ export class OpenAIEndpoint extends ChatEndpoint { } } else { + // Non thinking models does not use max_tokens if (typeof body.max_tokens !== 'undefined') { delete body.max_tokens; } diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index 52074255c1..b7649c3b35 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -19,10 +19,19 @@ export interface AzureUrlOptions { } interface AzureModelConfig { - deploymentType: 'completions' | 'responses'; - deploymentName: string; - apiVersion: string; + name: string; + url: string; + deploymentType?: 'completions' | 'responses'; + deploymentName?: string; + apiVersion?: string; + maxInputTokens: number; + maxOutputTokens: number; + toolCalling: boolean; + thinking?: boolean; + vision: boolean; temperature?: number; + requiresAPIKey?: boolean; + requestHeaders?: Record; } function createAzureUrlOptions(modelId: string, config?: Partial): AzureUrlOptions { @@ -137,11 +146,6 @@ export class AzureBYOKModelProvider extends CustomOAIBYOKModelProvider { // This is required because Azure OpenAI uses the deployment name for API routing. modelInfo.id = options.deploymentName; - // Set temperature from config if specified - if (config?.temperature !== undefined) { - modelInfo.temperature = config.temperature; - } - // Set supported endpoints based on deployment type if (options.deploymentType === 'responses') { modelInfo.supported_endpoints = [ModelSupportedEndpoint.Responses]; diff --git a/src/extension/byok/vscode-node/customOAIProvider.ts b/src/extension/byok/vscode-node/customOAIProvider.ts index 7ac98615b7..e75b4adec1 100644 --- a/src/extension/byok/vscode-node/customOAIProvider.ts +++ b/src/extension/byok/vscode-node/customOAIProvider.ts @@ -47,17 +47,14 @@ export function hasExplicitApiPath(url: string): boolean { interface UserModelConfig { name: string; url: string; - deploymentType?: 'completions' | 'responses'; - deploymentName?: string; - apiVersion?: string; maxInputTokens: number; maxOutputTokens: number; requiresAPIKey: boolean; toolCalling: boolean; editTools?: EndpointEditToolName[]; - vision: boolean; - thinking?: boolean; temperature?: number; + thinking?: boolean; + vision: boolean; requestHeaders?: Record; } From 760a99a58eff9c83473a553b77646b9c4fbff788 Mon Sep 17 00:00:00 2001 From: koureasstavros Date: Fri, 7 Nov 2025 12:01:49 +0200 Subject: [PATCH 21/21] Fixed Copilot reviews suggestions --- .../azure-provider-settings.instructions.md | 21 ++++--- package.json | 61 +++++++++++-------- src/extension/byok/node/openAIEndpoint.ts | 2 +- .../byok/vscode-node/azureProvider.ts | 7 ++- .../byok/vscode-node/customOAIProvider.ts | 10 +-- 5 files changed, 56 insertions(+), 45 deletions(-) diff --git a/.github/instructions/azure-provider-settings.instructions.md b/.github/instructions/azure-provider-settings.instructions.md index 13bf2165af..3262d889c5 100644 --- a/.github/instructions/azure-provider-settings.instructions.md +++ b/.github/instructions/azure-provider-settings.instructions.md @@ -17,19 +17,20 @@ The `chat.azureModels` setting accepts a record of model configurations where ea { "chat.azureModels": { "[modelId]": { - "name": string, // Display name for the model - "url": string, // Azure endpoint URL (base URL without API path) + "name": string, // Display name for the model + "url": string, // Azure endpoint URL (base URL without API path) "deploymentType"?: "completions" | "responses", // API type (optional, defaults to "completions") "deploymentName"?: string, // Azure deployment name (optional, defaults to modelId) "apiVersion"?: string, // Azure API version (optional, default: "2025-01-01-preview") - "maxInputTokens": number, // Maximum input context window size - "maxOutputTokens": number, // Maximum output tokens per response - "toolCalling": boolean, // Whether model supports function/tool calling - "temperature"?: number, // Temperature setting (optional, 0.0-2.0) - "thinking"?: boolean, // Whether model supports thinking/reasoning tokens (optional) - "vision": boolean, // Whether model supports vision/image inputs (optional) - "requestHeaders"?: Record, // Custom HTTP headers for requests (optional) - "requiresAPIKey"?: boolean, // Whether model requires API key (optional, default: true) + "maxInputTokens": number, // Maximum input context window size + "maxOutputTokens": number, // Maximum output tokens per response + "toolCalling"?: boolean, // Whether model supports function/tool calling (optional, default: false) + "editTools"?: string[], // List of supported edit tools (optional, default: []) + "temperature"?: number, // Temperature setting (optional, 0.0-2.0, default: 1.0) + "thinking"?: boolean, // Whether model supports thinking/reasoning tokens (optional, default: false) + "vision"?: boolean, // Whether model supports vision/image inputs (optional, default: false) + "requestHeaders"?: Record, // Custom HTTP headers for requests (optional, default: null) + "requiresAPIKey"?: boolean, // Whether model requires API key (optional, default: true) } } } diff --git a/package.json b/package.json index 7d0bb66d7b..b916d5df52 100644 --- a/package.json +++ b/package.json @@ -3063,6 +3063,19 @@ "type": "boolean", "description": "Whether the model supports tool calling" }, + "editTools": { + "type": "array", + "description": "List of edit tools supported by the model. If this is not configured, the editor will try multiple edit tools and pick the best one.\n\n- 'find-replace': Find and replace text in a document.\n- 'multi-find-replace': Find and replace text in a document.\n- 'apply-patch': A file-oriented diff format used by some OpenAI models\n- 'code-rewrite': A general but slower editing tool that allows the model to rewrite and code snippet and provide only the replacement to the editor.", + "items": { + "type": "string", + "enum": [ + "find-replace", + "multi-find-replace", + "apply-patch", + "code-rewrite" + ] + } + }, "temperature": { "type": "number", "description": "Temperature parameter for model responses (typically 0.0 to 2.0)", @@ -3090,9 +3103,7 @@ "name", "url", "maxInputTokens", - "maxOutputTokens", - "toolCalling", - "vision" + "maxOutputTokens" ], "additionalProperties": false }, @@ -3119,23 +3130,6 @@ "type": "boolean", "description": "Whether the model supports tool calling" }, - "vision": { - "type": "boolean", - "description": "Whether the model supports vision capabilities" - }, - "maxInputTokens": { - "type": "number", - "description": "Maximum number of input tokens supported by the model" - }, - "maxOutputTokens": { - "type": "number", - "description": "Maximum number of output tokens supported by the model" - }, - "requiresAPIKey": { - "type": "boolean", - "description": "Whether the model requires an API key for authentication", - "default": true - }, "editTools": { "type": "array", "description": "List of edit tools supported by the model. If this is not configured, the editor will try multiple edit tools and pick the best one.\n\n- 'find-replace': Find and replace text in a document.\n- 'multi-find-replace': Find and replace text in a document.\n- 'apply-patch': A file-oriented diff format used by some OpenAI models\n- 'code-rewrite': A general but slower editing tool that allows the model to rewrite and code snippet and provide only the replacement to the editor.", @@ -3149,16 +3143,28 @@ ] } }, + "temperature": { + "type": "number", + "description": "Temperature parameter for model responses (typically 0.0 to 2.0)", + "minimum": 0, + "maximum": 2 + }, "thinking": { "type": "boolean", "default": false, "description": "Whether the model supports thinking capabilities" }, - "temperature": { + "vision": { + "type": "boolean", + "description": "Whether the model supports vision capabilities" + }, + "maxInputTokens": { "type": "number", - "description": "Temperature parameter for model responses (typically 0.0 to 2.0)", - "minimum": 0, - "maximum": 2 + "description": "Maximum number of input tokens supported by the model" + }, + "maxOutputTokens": { + "type": "number", + "description": "Maximum number of output tokens supported by the model" }, "requestHeaders": { "type": "object", @@ -3166,13 +3172,16 @@ "additionalProperties": { "type": "string" } + }, + "requiresAPIKey": { + "type": "boolean", + "description": "Whether the model requires an API key for authentication", + "default": true } }, "required": [ "name", "url", - "toolCalling", - "vision", "maxInputTokens", "maxOutputTokens", "requiresAPIKey" diff --git a/src/extension/byok/node/openAIEndpoint.ts b/src/extension/byok/node/openAIEndpoint.ts index af26953ac8..7a146de833 100644 --- a/src/extension/byok/node/openAIEndpoint.ts +++ b/src/extension/byok/node/openAIEndpoint.ts @@ -306,7 +306,7 @@ export class OpenAIEndpoint extends ChatEndpoint { } } else { - // Non thinking models does not use max_tokens + // For non-thinking models, removing max_tokens defaults to the maximum allowed value, which is what we want for BYOK if (typeof body.max_tokens !== 'undefined') { delete body.max_tokens; } diff --git a/src/extension/byok/vscode-node/azureProvider.ts b/src/extension/byok/vscode-node/azureProvider.ts index b7649c3b35..0e6b084c07 100644 --- a/src/extension/byok/vscode-node/azureProvider.ts +++ b/src/extension/byok/vscode-node/azureProvider.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService'; -import { IChatModelInformation, ModelSupportedEndpoint } from '../../../platform/endpoint/common/endpointProvider'; +import { EndpointEditToolName, IChatModelInformation, ModelSupportedEndpoint } from '../../../platform/endpoint/common/endpointProvider'; import { ILogService } from '../../../platform/log/common/logService'; import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService'; import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; @@ -26,9 +26,10 @@ interface AzureModelConfig { apiVersion?: string; maxInputTokens: number; maxOutputTokens: number; - toolCalling: boolean; + toolCalling?: boolean; + editTools?: EndpointEditToolName[]; thinking?: boolean; - vision: boolean; + vision?: boolean; temperature?: number; requiresAPIKey?: boolean; requestHeaders?: Record; diff --git a/src/extension/byok/vscode-node/customOAIProvider.ts b/src/extension/byok/vscode-node/customOAIProvider.ts index e75b4adec1..3e2e5876a7 100644 --- a/src/extension/byok/vscode-node/customOAIProvider.ts +++ b/src/extension/byok/vscode-node/customOAIProvider.ts @@ -49,13 +49,13 @@ interface UserModelConfig { url: string; maxInputTokens: number; maxOutputTokens: number; - requiresAPIKey: boolean; - toolCalling: boolean; + toolCalling?: boolean; editTools?: EndpointEditToolName[]; temperature?: number; thinking?: boolean; - vision: boolean; + vision?: boolean; requestHeaders?: Record; + requiresAPIKey: boolean; } interface CustomOAIModelInfo extends LanguageModelChatInformation { @@ -124,9 +124,9 @@ export class CustomOAIBYOKModelProvider implements BYOKModelProvider