diff --git a/web-app/public/images/model-provider/azure.svg b/web-app/public/images/model-provider/azure.svg
new file mode 100644
index 000000000..4c86f9e25
--- /dev/null
+++ b/web-app/public/images/model-provider/azure.svg
@@ -0,0 +1,23 @@
+
diff --git a/web-app/src/consts/providers.ts b/web-app/src/consts/providers.ts
index 9f40177bb..328ba3a9a 100644
--- a/web-app/src/consts/providers.ts
+++ b/web-app/src/consts/providers.ts
@@ -59,6 +59,40 @@ export const predefinedProviders = [
],
models: [],
},
+ {
+ active: true,
+ api_key: '',
+ base_url: 'https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1',
+ explore_models_url: 'https://oai.azure.com/deployments',
+ provider: 'azure',
+ settings: [
+ {
+ key: 'api-key',
+ title: 'API Key',
+ description:
+ 'The Azure OpenAI API uses API keys for authentication. Visit your [Azure OpenAI Studio](https://oai.azure.com/) to retrieve the API key from your resource.',
+ controller_type: 'input',
+ controller_props: {
+ placeholder: 'Insert API Key',
+ value: '',
+ type: 'password',
+ input_actions: ['unobscure', 'copy'],
+ },
+ },
+ {
+ key: 'base-url',
+ title: 'Base URL',
+ description:
+ 'Your Azure OpenAI resource endpoint. See the [Azure OpenAI documentation](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/latest) for more information.',
+ controller_type: 'input',
+ controller_props: {
+ placeholder: 'https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1',
+ value: 'https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1',
+ },
+ },
+ ],
+ models: [],
+ },
{
active: true,
api_key: '',
diff --git a/web-app/src/containers/dialogs/AddModel.tsx b/web-app/src/containers/dialogs/AddModel.tsx
index a8f51f36d..2b87fb222 100644
--- a/web-app/src/containers/dialogs/AddModel.tsx
+++ b/web-app/src/containers/dialogs/AddModel.tsx
@@ -51,15 +51,15 @@ export const DialogAddModel = ({ provider, trigger }: DialogAddModelProps) => {
(
providerModels[
provider.provider as unknown as keyof typeof providerModels
- ].supportsToolCalls as unknown as string[]
- ).includes(modelId)
+ ]?.supportsToolCalls as unknown as string[]
+ )?.includes(modelId)
? ModelCapabilities.TOOLS
: undefined,
(
providerModels[
provider.provider as unknown as keyof typeof providerModels
- ].supportsImages as unknown as string[]
- ).includes(modelId)
+ ]?.supportsImages as unknown as string[]
+ )?.includes(modelId)
? ModelCapabilities.VISION
: undefined,
].filter(Boolean) as string[],
diff --git a/web-app/src/lib/utils.ts b/web-app/src/lib/utils.ts
index 0d3fa8f61..60a055720 100644
--- a/web-app/src/lib/utils.ts
+++ b/web-app/src/lib/utils.ts
@@ -28,6 +28,8 @@ export function getProviderLogo(provider: string) {
return '/images/model-provider/gemini.svg'
case 'openai':
return '/images/model-provider/openai.svg'
+ case 'azure':
+ return '/images/model-provider/azure.svg'
default:
return undefined
}
@@ -161,5 +163,5 @@ export function formatDuration(startTime: number, endTime?: number): string {
}
export function sanitizeModelId(modelId: string): string {
- return modelId.replace(/[^a-zA-Z0-9/_\-.]/g, '').replace(/\./g, "_")
+ return modelId.replace(/[^a-zA-Z0-9/_\-.]/g, '').replace(/\./g, '_')
}
diff --git a/web-app/src/services/providers/tauri.ts b/web-app/src/services/providers/tauri.ts
index 8e546987f..50f1217da 100644
--- a/web-app/src/services/providers/tauri.ts
+++ b/web-app/src/services/providers/tauri.ts
@@ -35,15 +35,15 @@ export class TauriProvidersService extends DefaultProvidersService {
(
providerModels[
provider.provider as unknown as keyof typeof providerModels
- ].supportsToolCalls as unknown as string[]
- ).includes(model)
+ ]?.supportsToolCalls as unknown as string[]
+ )?.includes(model)
? ModelCapabilities.TOOLS
: undefined,
(
providerModels[
provider.provider as unknown as keyof typeof providerModels
- ].supportsImages as unknown as string[]
- ).includes(model)
+ ]?.supportsImages as unknown as string[]
+ )?.includes(model)
? ModelCapabilities.VISION
: undefined,
].filter(Boolean) as string[]
diff --git a/web-app/src/services/providers/web.ts b/web-app/src/services/providers/web.ts
index 5ad426a11..6a7865be8 100644
--- a/web-app/src/services/providers/web.ts
+++ b/web-app/src/services/providers/web.ts
@@ -93,8 +93,8 @@ export class WebProvidersService implements ProvidersService {
(
providerModels[
provider.provider as unknown as keyof typeof providerModels
- ].supportsToolCalls as unknown as string[]
- ).includes(model)
+ ]?.supportsToolCalls as unknown as string[]
+ )?.includes(model)
? ModelCapabilities.TOOLS
: undefined,
].filter(Boolean) as string[]
@@ -163,7 +163,9 @@ export class WebProvidersService implements ProvidersService {
// Handle different response formats that providers might use
if (data.data && Array.isArray(data.data)) {
// OpenAI format: { data: [{ id: "model-id" }, ...] }
- return data.data.map((model: { id: string }) => model.id).filter(Boolean)
+ return data.data
+ .map((model: { id: string }) => model.id)
+ .filter(Boolean)
} else if (Array.isArray(data)) {
// Direct array format: ["model-id1", "model-id2", ...]
return data
@@ -189,11 +191,15 @@ export class WebProvidersService implements ProvidersService {
'Authentication failed',
'Access forbidden',
'Models endpoint not found',
- 'Failed to fetch models from'
+ 'Failed to fetch models from',
]
- if (error instanceof Error &&
- structuredErrorPrefixes.some(prefix => (error as Error).message.startsWith(prefix))) {
+ if (
+ error instanceof Error &&
+ structuredErrorPrefixes.some((prefix) =>
+ (error as Error).message.startsWith(prefix)
+ )
+ ) {
throw new Error(error.message)
}
@@ -211,7 +217,10 @@ export class WebProvidersService implements ProvidersService {
}
}
- async updateSettings(providerName: string, settings: ProviderSetting[]): Promise {
+ async updateSettings(
+ providerName: string,
+ settings: ProviderSetting[]
+ ): Promise {
await ExtensionManager.getInstance()
.getEngine(providerName)
?.updateSettings(
@@ -233,4 +242,4 @@ export class WebProvidersService implements ProvidersService {
// Web implementation uses regular fetch
return fetch
}
-}
\ No newline at end of file
+}