Compare commits

...

1 Commits

Author SHA1 Message Date
claude[bot]
59ee1e7baa fix: support Azure provider with reasoning models
- Add azure, openrouter, bedrock, and ollama to VALIDATED_PROVIDERS array
- Add Azure reasoning models (GPT-5, o1, o3, o3-mini, o4-mini) to supported-models.json
- Implement automatic API endpoint detection for Azure reasoning models
- Add dual endpoint support (chat/completions vs responses) in AzureProvider
- Add smart URL adjustment logic for different Azure configurations
- Maintain backward compatibility with existing Azure setups

Fixes #638

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Ralph Khreish <Crunchyman-ralph@users.noreply.github.com>
2025-10-14 08:00:46 +00:00
3 changed files with 113 additions and 3 deletions

View File

@@ -997,6 +997,67 @@
"allowed_roles": ["main", "fallback"], "allowed_roles": ["main", "fallback"],
"max_tokens": 16384, "max_tokens": 16384,
"supported": true "supported": true
},
{
"id": "gpt-5",
"swe_score": 0.749,
"cost_per_1m_tokens": {
"input": 5.0,
"output": 20.0
},
"allowed_roles": ["main", "fallback"],
"max_tokens": 100000,
"temperature": 1,
"supported": true,
"api_type": "responses"
},
{
"id": "o1",
"swe_score": 0.489,
"cost_per_1m_tokens": {
"input": 15.0,
"output": 60.0
},
"allowed_roles": ["main"],
"max_tokens": 100000,
"supported": true,
"api_type": "responses"
},
{
"id": "o3",
"swe_score": 0.5,
"cost_per_1m_tokens": {
"input": 2.0,
"output": 8.0
},
"allowed_roles": ["main", "fallback"],
"max_tokens": 100000,
"supported": true,
"api_type": "responses"
},
{
"id": "o3-mini",
"swe_score": 0.493,
"cost_per_1m_tokens": {
"input": 1.1,
"output": 4.4
},
"allowed_roles": ["main"],
"max_tokens": 100000,
"supported": true,
"api_type": "responses"
},
{
"id": "o4-mini",
"swe_score": 0.45,
"cost_per_1m_tokens": {
"input": 1.1,
"output": 4.4
},
"allowed_roles": ["main", "fallback"],
"max_tokens": 100000,
"supported": true,
"api_type": "responses"
} }
], ],
"bedrock": [ "bedrock": [

View File

@@ -5,6 +5,7 @@
import { createAzure } from '@ai-sdk/azure'; import { createAzure } from '@ai-sdk/azure';
import { BaseAIProvider } from './base-provider.js'; import { BaseAIProvider } from './base-provider.js';
import MODEL_MAP from '../../scripts/modules/supported-models.json' with { type: 'json' };
export class AzureProvider extends BaseAIProvider { export class AzureProvider extends BaseAIProvider {
constructor() { constructor() {
@@ -37,21 +38,65 @@ export class AzureProvider extends BaseAIProvider {
} }
} }
/**
* Determines if a model requires the responses API endpoint instead of chat/completions
* @param {string} modelId - The model ID to check
* @returns {boolean} True if the model needs the responses API
*/
isReasoningModel(modelId) {
const azureModels = MODEL_MAP.azure || [];
const modelDef = azureModels.find(m => m.id === modelId);
return modelDef?.api_type === 'responses';
}
/**
* Adjusts the base URL for reasoning models that need the responses endpoint
* @param {string} baseURL - Original base URL
* @param {string} modelId - Model ID
* @returns {string} Adjusted base URL
*/
adjustBaseURL(baseURL, modelId) {
if (!this.isReasoningModel(modelId)) {
return baseURL;
}
// Convert chat/completions URL to responses URL for reasoning models
if (baseURL.includes('/chat/completions')) {
return baseURL.replace('/chat/completions', '/responses');
}
// If baseURL ends with deployments/<model-name>, add responses endpoint
if (baseURL.includes('/deployments/')) {
return baseURL.replace(/\/deployments\/[^\/]+$/, '/responses');
}
// If baseURL is just the base, ensure it ends with /responses
if (!baseURL.endsWith('/responses')) {
return baseURL.replace(/\/$/, '') + '/responses';
}
return baseURL;
}
/** /**
* Creates and returns an Azure OpenAI client instance. * Creates and returns an Azure OpenAI client instance.
* @param {object} params - Parameters for client initialization * @param {object} params - Parameters for client initialization
* @param {string} params.apiKey - Azure OpenAI API key * @param {string} params.apiKey - Azure OpenAI API key
* @param {string} params.baseURL - Azure OpenAI endpoint URL (from .taskmasterconfig global.azureBaseURL or models.[role].baseURL) * @param {string} params.baseURL - Azure OpenAI endpoint URL (from .taskmasterconfig global.azureBaseURL or models.[role].baseURL)
* @param {string} params.modelId - Model ID (used to determine API endpoint)
* @returns {Function} Azure OpenAI client function * @returns {Function} Azure OpenAI client function
* @throws {Error} If required parameters are missing or initialization fails * @throws {Error} If required parameters are missing or initialization fails
*/ */
getClient(params) { getClient(params) {
try { try {
const { apiKey, baseURL } = params; const { apiKey, baseURL, modelId } = params;
// Adjust base URL for reasoning models
const adjustedBaseURL = this.adjustBaseURL(baseURL, modelId);
return createAzure({ return createAzure({
apiKey, apiKey,
baseURL baseURL: adjustedBaseURL
}); });
} catch (error) { } catch (error) {
this.handleError('client initialization', error); this.handleError('client initialization', error);

View File

@@ -11,7 +11,11 @@ export const VALIDATED_PROVIDERS = [
'perplexity', 'perplexity',
'xai', 'xai',
'groq', 'groq',
'mistral' 'mistral',
'azure',
'openrouter',
'bedrock',
'ollama'
]; ];
// Custom providers object for easy named access // Custom providers object for easy named access