@jonab/azure-ai-sdk 0.5.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/adapters/anthropic-adapter.d.ts +172 -0
- package/dist/adapters/anthropic-adapter.d.ts.map +1 -0
- package/dist/adapters/anthropic-adapter.js +394 -0
- package/dist/adapters/anthropic-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +15 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +85 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/openai-adapter.d.ts +180 -0
- package/dist/adapters/openai-adapter.d.ts.map +1 -0
- package/dist/adapters/openai-adapter.js +363 -0
- package/dist/adapters/openai-adapter.js.map +1 -0
- package/dist/adapters/openai-legacy-adapter.d.ts +70 -0
- package/dist/adapters/openai-legacy-adapter.d.ts.map +1 -0
- package/dist/adapters/openai-legacy-adapter.js +38 -0
- package/dist/adapters/openai-legacy-adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +109 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/azure-foundry-chat-language-model.d.ts +37 -0
- package/dist/azure-foundry-chat-language-model.d.ts.map +1 -0
- package/dist/azure-foundry-chat-language-model.js +119 -0
- package/dist/azure-foundry-chat-language-model.js.map +1 -0
- package/dist/azure-foundry-chat-options.d.ts +34 -0
- package/dist/azure-foundry-chat-options.d.ts.map +1 -0
- package/dist/azure-foundry-chat-options.js +2 -0
- package/dist/azure-foundry-chat-options.js.map +1 -0
- package/dist/azure-foundry-error.d.ts +12 -0
- package/dist/azure-foundry-error.d.ts.map +1 -0
- package/dist/azure-foundry-error.js +15 -0
- package/dist/azure-foundry-error.js.map +1 -0
- package/dist/azure-foundry-provider.d.ts +239 -0
- package/dist/azure-foundry-provider.d.ts.map +1 -0
- package/dist/azure-foundry-provider.js +263 -0
- package/dist/azure-foundry-provider.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { LanguageModelV3, ProviderV3 } from '@ai-sdk/provider';
|
|
2
|
+
import { FetchFunction } from '@ai-sdk/provider-utils';
|
|
3
|
+
import type { TokenCredential } from '@azure/identity';
|
|
4
|
+
import { AzureFoundryChatModelId, AzureFoundryChatSettings } from './azure-foundry-chat-options.js';
|
|
5
|
+
export interface AzureFoundryProviderSettings {
|
|
6
|
+
/**
|
|
7
|
+
* Azure resource base URL. Two formats are supported:
|
|
8
|
+
*
|
|
9
|
+
* Azure OpenAI / Cognitive Services (cognitiveservices.azure.com):
|
|
10
|
+
* https://<resource>.cognitiveservices.azure.com
|
|
11
|
+
* → calls /openai/deployments/{model}/chat/completions?api-version=...
|
|
12
|
+
*
|
|
13
|
+
* AI Foundry inference (services.ai.azure.com):
|
|
14
|
+
* https://<project>.services.ai.azure.com/models
|
|
15
|
+
* → calls /chat/completions with model in the request body
|
|
16
|
+
*
|
|
17
|
+
* Can also be provided via the AZURE_AI_FOUNDRY_ENDPOINT environment variable.
|
|
18
|
+
*
|
|
19
|
+
* Alternatively, provide `resourceName` (and optionally `projectId`) to have
|
|
20
|
+
* the endpoint constructed automatically.
|
|
21
|
+
*/
|
|
22
|
+
endpoint?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Azure AI Foundry resource name (the subdomain portion of the hostname).
|
|
25
|
+
*
|
|
26
|
+
* Constructs: https://{resourceName}.services.ai.azure.com/models
|
|
27
|
+
*
|
|
28
|
+
* `projectId` may be provided alongside this for configuration purposes but
|
|
29
|
+
* does not change the URL — the `/models` endpoint serves all deployed models.
|
|
30
|
+
*
|
|
31
|
+
* Takes precedence over `endpoint` when both are set.
|
|
32
|
+
* Can also be provided via the AZURE_FOUNDRY_RESOURCE environment variable.
|
|
33
|
+
*/
|
|
34
|
+
resourceName?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Azure AI Foundry project name.
|
|
37
|
+
* Accepted as a configuration convenience but does not affect the URL —
|
|
38
|
+
* the provider always uses the resource-level `/models` inference endpoint,
|
|
39
|
+
* which works for all deployed models regardless of project scoping.
|
|
40
|
+
* Can also be provided via the AZURE_FOUNDRY_PROJECT environment variable.
|
|
41
|
+
*/
|
|
42
|
+
projectId?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Controls how the chat completions URL is constructed.
|
|
45
|
+
*
|
|
46
|
+
* - `'auto'` (default) — infer from the hostname:
|
|
47
|
+
* `cognitiveservices.azure.com` → `'cognitive-services'`
|
|
48
|
+
* all others → `'foundry'`
|
|
49
|
+
* - `'cognitive-services'` — Azure OpenAI deployment-path style:
|
|
50
|
+
* `{endpoint}/openai/deployments/{model}/chat/completions?api-version=...`
|
|
51
|
+
* Model is placed in the URL path; `api-version` query param is appended.
|
|
52
|
+
* - `'foundry'` — AI Foundry inference style:
|
|
53
|
+
* `{endpoint}/chat/completions` (model sent in request body)
|
|
54
|
+
*
|
|
55
|
+
* Set this explicitly when routing through a gateway (e.g. APIM) whose
|
|
56
|
+
* hostname does not contain `cognitiveservices.azure.com` but whose backend
|
|
57
|
+
* expects the deployment-path URL format.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* // APIM gateway fronting an Azure OpenAI backend
|
|
62
|
+
* createAzureFoundry({
|
|
63
|
+
* endpoint: 'https://my-org.azure-api.net',
|
|
64
|
+
* endpointStyle: 'cognitive-services',
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
endpointStyle?: 'auto' | 'cognitive-services' | 'foundry';
|
|
69
|
+
/**
|
|
70
|
+
* API version query parameter appended to every request.
|
|
71
|
+
* Only relevant for the `'cognitive-services'` endpoint style.
|
|
72
|
+
* Defaults to '2024-10-21'.
|
|
73
|
+
*/
|
|
74
|
+
apiVersion?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Azure token credential to use for authentication.
|
|
77
|
+
* Defaults to DefaultAzureCredential which supports:
|
|
78
|
+
* - Environment variables (AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET)
|
|
79
|
+
* - Workload identity (Kubernetes)
|
|
80
|
+
* - Managed identity (Azure-hosted compute)
|
|
81
|
+
* - Azure CLI (`az login`)
|
|
82
|
+
* - Azure PowerShell
|
|
83
|
+
* - Visual Studio Code
|
|
84
|
+
*/
|
|
85
|
+
credential?: TokenCredential;
|
|
86
|
+
/**
|
|
87
|
+
* OAuth2 scope to request when obtaining a bearer token.
|
|
88
|
+
*
|
|
89
|
+
* The default scope is inferred from the endpoint:
|
|
90
|
+
* - `*.services.ai.azure.com` → `'https://ai.azure.com/.default'`
|
|
91
|
+
* - all other endpoints → `'https://cognitiveservices.azure.com/.default'`
|
|
92
|
+
*
|
|
93
|
+
* When routing through Azure API Management (APIM), set this to the scope
|
|
94
|
+
* of the APIM's Entra app registration:
|
|
95
|
+
* `'api://<apim-app-client-id>/.default'`
|
|
96
|
+
*
|
|
97
|
+
* The APIM instance must be configured to validate JWT tokens from this
|
|
98
|
+
* audience and forward requests to the backend on behalf of the caller.
|
|
99
|
+
*/
|
|
100
|
+
scope?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Direct API key for Azure AI Foundry endpoints.
|
|
103
|
+
*
|
|
104
|
+
* When set, this value is used directly as the Bearer token and **Entra
|
|
105
|
+
* identity is bypassed entirely**. This is convenient for local testing or
|
|
106
|
+
* environments where `az login` is not available.
|
|
107
|
+
*
|
|
108
|
+
* For production workloads prefer leaving this unset and relying on
|
|
109
|
+
* `DefaultAzureCredential` (managed identity, workload identity, etc.).
|
|
110
|
+
*
|
|
111
|
+
* Can also be provided via the `AZURE_FOUNDRY_API_KEY` environment variable.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* // Quick local test without az login
|
|
116
|
+
* createAzureFoundry({
|
|
117
|
+
* resourceName: 'my-resource',
|
|
118
|
+
* projectId: 'my-project',
|
|
119
|
+
* apiKey: process.env.AZURE_FOUNDRY_API_KEY,
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
apiKey?: string;
|
|
124
|
+
/**
|
|
125
|
+
* APIM subscription key sent **alongside** the Entra bearer token.
|
|
126
|
+
*
|
|
127
|
+
* Use this when routing through Azure API Management that requires a
|
|
128
|
+
* subscription key in addition to a valid Entra JWT. The Entra bearer token
|
|
129
|
+
* is always obtained and sent; this key is forwarded as supplemental headers:
|
|
130
|
+
* - `Ocp-Apim-Subscription-Key`
|
|
131
|
+
* - `api-key`
|
|
132
|
+
*
|
|
133
|
+
* Values in `headers` take precedence if the same key appears in both.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* // APIM policy requires both an Entra token AND a subscription key
|
|
138
|
+
* createAzureFoundry({
|
|
139
|
+
* endpoint: 'https://my-org.azure-api.net',
|
|
140
|
+
* endpointStyle: 'cognitive-services',
|
|
141
|
+
* scope: 'api://<apim-app-client-id>/.default',
|
|
142
|
+
* subscriptionKey: process.env.APIM_SUBSCRIPTION_KEY,
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
subscriptionKey?: string;
|
|
147
|
+
/**
|
|
148
|
+
* Custom headers to include in every request.
|
|
149
|
+
* These take precedence over any headers set by `apiKey`.
|
|
150
|
+
*/
|
|
151
|
+
headers?: Record<string, string>;
|
|
152
|
+
/**
|
|
153
|
+
* Custom fetch implementation. Useful for testing / middleware.
|
|
154
|
+
*/
|
|
155
|
+
fetch?: FetchFunction;
|
|
156
|
+
generateId?: () => string;
|
|
157
|
+
/**
|
|
158
|
+
* Logger for diagnostic output. Defaults to `console`.
|
|
159
|
+
*
|
|
160
|
+
* Set to `null` to silence all SDK logging. You can also supply a custom
|
|
161
|
+
* object with `{ error, warn, info }` methods to route logs to your own
|
|
162
|
+
* logging infrastructure.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* // Silence logging
|
|
166
|
+
* createAzureFoundry({ ..., logger: null });
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* // Route to a custom logger
|
|
170
|
+
* createAzureFoundry({ ..., logger: myLogger });
|
|
171
|
+
*/
|
|
172
|
+
logger?: Pick<Console, 'error' | 'warn' | 'info'> | null;
|
|
173
|
+
/**
|
|
174
|
+
* Path to write debug log lines to. Defaults to
|
|
175
|
+
* `<os.tmpdir()>/azure-ai-sdk-debug.log` when not set.
|
|
176
|
+
* Can also be overridden via the `AZURE_AI_SDK_DEBUG_LOG` environment variable.
|
|
177
|
+
* The file is overwritten on each provider init (fresh log per run).
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* // In opencode.json options:
|
|
181
|
+
* { "debugLogFile": "/tmp/azure-ai-sdk-debug.log" }
|
|
182
|
+
*/
|
|
183
|
+
debugLogFile?: string;
|
|
184
|
+
}
|
|
185
|
+
export interface AzureFoundryProvider extends ProviderV3 {
|
|
186
|
+
/**
|
|
187
|
+
* Create a language model instance for the given deployment name.
|
|
188
|
+
*/
|
|
189
|
+
(modelId: AzureFoundryChatModelId, settings?: AzureFoundryChatSettings): LanguageModelV3;
|
|
190
|
+
/**
|
|
191
|
+
* Create a language model instance for the given deployment name.
|
|
192
|
+
*/
|
|
193
|
+
languageModel(modelId: AzureFoundryChatModelId, settings?: AzureFoundryChatSettings): LanguageModelV3;
|
|
194
|
+
/**
|
|
195
|
+
* Create a chat model instance for the given deployment name.
|
|
196
|
+
*/
|
|
197
|
+
chat(modelId: AzureFoundryChatModelId, settings?: AzureFoundryChatSettings): LanguageModelV3;
|
|
198
|
+
/**
|
|
199
|
+
* Same as {@link chat} — alias matching `@ai-sdk/openai-compatible` / OpenCode
|
|
200
|
+
* conventions (`chatModel`).
|
|
201
|
+
*/
|
|
202
|
+
chatModel?(modelId: AzureFoundryChatModelId, settings?: AzureFoundryChatSettings): LanguageModelV3;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Create an Azure AI Foundry provider instance.
|
|
206
|
+
*
|
|
207
|
+
* Authentication is handled via Azure Identity. The credential is resolved
|
|
208
|
+
* in the following order (when no `credential` is specified):
|
|
209
|
+
*
|
|
210
|
+
* 1. `AZURE_CLIENT_ID` / `AZURE_CLIENT_SECRET` / `AZURE_TENANT_ID` env vars
|
|
211
|
+
* 2. Workload identity (Kubernetes pods with federated credentials)
|
|
212
|
+
* 3. Managed identity (Azure-hosted compute)
|
|
213
|
+
* 4. Azure CLI (`az login`)
|
|
214
|
+
* 5. Azure PowerShell
|
|
215
|
+
* 6. VS Code account
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* import { createAzureFoundry } from '@nquandt/azure-ai-sdk';
|
|
220
|
+
* import { generateText } from 'ai';
|
|
221
|
+
*
|
|
222
|
+
* // Azure OpenAI / Cognitive Services endpoint:
|
|
223
|
+
* const foundry = createAzureFoundry({
|
|
224
|
+
* endpoint: 'https://my-resource.cognitiveservices.azure.com',
|
|
225
|
+
* });
|
|
226
|
+
*
|
|
227
|
+
* // AI Foundry inference endpoint:
|
|
228
|
+
* const foundry = createAzureFoundry({
|
|
229
|
+
* endpoint: 'https://my-project.services.ai.azure.com/models',
|
|
230
|
+
* });
|
|
231
|
+
*
|
|
232
|
+
* const { text } = await generateText({
|
|
233
|
+
* model: foundry('DeepSeek-R1'),
|
|
234
|
+
* prompt: 'Hello world',
|
|
235
|
+
* });
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
export declare function createAzureFoundry(options?: AzureFoundryProviderSettings): AzureFoundryProvider;
|
|
239
|
+
//# sourceMappingURL=azure-foundry-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azure-foundry-provider.d.ts","sourceRoot":"","sources":["../src/azure-foundry-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAoB,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,aAAa,EAAwB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAOvD,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,iCAAiC,CAAC;AAYzC,MAAM,WAAW,4BAA4B;IAC3C;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAAC;IAE1D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAE7B;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;IAE1B;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAEzD;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,MAAM,WAAW,oBAAqB,SAAQ,UAAU;IACtD;;OAEG;IACH,CACE,OAAO,EAAE,uBAAuB,EAChC,QAAQ,CAAC,EAAE,wBAAwB,GAClC,eAAe,CAAC;IAEnB;;OAEG;IACH,aAAa,CACX,OAAO,EAAE,uBAAuB,EAChC,QAAQ,CAAC,EAAE,wBAAwB,GAClC,eAAe,CAAC;IAEnB;;OAEG;IACH,IAAI,CACF,OAAO,EAAE,uBAAuB,EAChC,QAAQ,CAAC,EAAE,wBAAwB,GAClC,eAAe,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,CACR,OAAO,EAAE,uBAAuB,EAChC,QAAQ,CAAC,EAAE,wBAAwB,GAClC,eAAe,CAAC;CACpB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,4BAAiC,GACzC,oBAAoB,CA6OtB"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { NoSuchModelError } from '@ai-sdk/provider';
|
|
2
|
+
import { withoutTrailingSlash } from '@ai-sdk/provider-utils';
|
|
3
|
+
import { appendFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { dirname } from 'node:path';
|
|
6
|
+
import { AzureFoundryChatLanguageModel, } from './azure-foundry-chat-language-model.js';
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Scope used to obtain tokens for Azure AI Foundry / Azure ML endpoints
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const COGNITIVE_SERVICES_SCOPE = 'https://cognitiveservices.azure.com/.default';
|
|
11
|
+
const AI_FOUNDRY_SCOPE = 'https://ai.azure.com/.default';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Factory
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
/**
|
|
16
|
+
* Create an Azure AI Foundry provider instance.
|
|
17
|
+
*
|
|
18
|
+
* Authentication is handled via Azure Identity. The credential is resolved
|
|
19
|
+
* in the following order (when no `credential` is specified):
|
|
20
|
+
*
|
|
21
|
+
* 1. `AZURE_CLIENT_ID` / `AZURE_CLIENT_SECRET` / `AZURE_TENANT_ID` env vars
|
|
22
|
+
* 2. Workload identity (Kubernetes pods with federated credentials)
|
|
23
|
+
* 3. Managed identity (Azure-hosted compute)
|
|
24
|
+
* 4. Azure CLI (`az login`)
|
|
25
|
+
* 5. Azure PowerShell
|
|
26
|
+
* 6. VS Code account
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { createAzureFoundry } from '@nquandt/azure-ai-sdk';
|
|
31
|
+
* import { generateText } from 'ai';
|
|
32
|
+
*
|
|
33
|
+
* // Azure OpenAI / Cognitive Services endpoint:
|
|
34
|
+
* const foundry = createAzureFoundry({
|
|
35
|
+
* endpoint: 'https://my-resource.cognitiveservices.azure.com',
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* // AI Foundry inference endpoint:
|
|
39
|
+
* const foundry = createAzureFoundry({
|
|
40
|
+
* endpoint: 'https://my-project.services.ai.azure.com/models',
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* const { text } = await generateText({
|
|
44
|
+
* model: foundry('DeepSeek-R1'),
|
|
45
|
+
* prompt: 'Hello world',
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function createAzureFoundry(options = {}) {
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Debug file logger — always writes to a log file. The path can be
|
|
52
|
+
// overridden via the `debugLogFile` option or the AZURE_AI_SDK_DEBUG_LOG
|
|
53
|
+
// env var; it defaults to <tmpdir>/azure-ai-sdk-debug.log.
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
const debugFilePath = options.debugLogFile ??
|
|
56
|
+
(typeof process !== 'undefined' && process.env.AZURE_AI_SDK_DEBUG_LOG
|
|
57
|
+
? process.env.AZURE_AI_SDK_DEBUG_LOG
|
|
58
|
+
: `${tmpdir()}/azure-ai-sdk-debug.log`);
|
|
59
|
+
function debugLog(level, msg) {
|
|
60
|
+
try {
|
|
61
|
+
mkdirSync(dirname(debugFilePath), { recursive: true });
|
|
62
|
+
// Overwrite on the first call each process run, append thereafter.
|
|
63
|
+
if (debugLog.firstWrite) {
|
|
64
|
+
debugLog.firstWrite = false;
|
|
65
|
+
writeFileSync(debugFilePath, `[${new Date().toISOString()}] [${level}] ${msg}\n`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
appendFileSync(debugFilePath, `[${new Date().toISOString()}] [${level}] ${msg}\n`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// never let debug logging break the provider
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
debugLog.firstWrite = true;
|
|
76
|
+
debugLog('INFO', `createAzureFoundry called — options: ${JSON.stringify({
|
|
77
|
+
hasResourceName: !!options.resourceName,
|
|
78
|
+
hasEndpoint: !!options.endpoint,
|
|
79
|
+
hasApiKey: !!options.apiKey,
|
|
80
|
+
hasCredential: !!options.credential,
|
|
81
|
+
hasScope: !!options.scope,
|
|
82
|
+
endpointStyle: options.endpointStyle,
|
|
83
|
+
apiVersion: options.apiVersion,
|
|
84
|
+
})}`);
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// Endpoint resolution (priority order):
|
|
87
|
+
// 1. options.resourceName (+ options.projectId) — explicit code-level names
|
|
88
|
+
// 2. options.endpoint — explicit code-level URL
|
|
89
|
+
// 3. AZURE_FOUNDRY_RESOURCE env var (+ AZURE_FOUNDRY_PROJECT) — env-based names
|
|
90
|
+
// 4. AZURE_AI_FOUNDRY_ENDPOINT env var — env-based full URL
|
|
91
|
+
//
|
|
92
|
+
// Explicit code-level options always win over env vars so that unit tests
|
|
93
|
+
// which pass a specific endpoint are never overridden by a .env file.
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
const resolvedEndpoint = (() => {
|
|
96
|
+
if (options.resourceName) {
|
|
97
|
+
// projectId is accepted as a config convenience but does not change the URL.
|
|
98
|
+
// The /models endpoint is the known-working inference surface for all models.
|
|
99
|
+
return `https://${options.resourceName}.services.ai.azure.com/models`;
|
|
100
|
+
}
|
|
101
|
+
if (options.endpoint !== undefined)
|
|
102
|
+
return options.endpoint;
|
|
103
|
+
const envResource = typeof process !== 'undefined' ? process.env.AZURE_FOUNDRY_RESOURCE : undefined;
|
|
104
|
+
if (envResource) {
|
|
105
|
+
return `https://${envResource}.services.ai.azure.com/models`;
|
|
106
|
+
}
|
|
107
|
+
return typeof process !== 'undefined' ? process.env.AZURE_AI_FOUNDRY_ENDPOINT : undefined;
|
|
108
|
+
})();
|
|
109
|
+
const endpoint = withoutTrailingSlash(resolvedEndpoint) ?? '';
|
|
110
|
+
if (!endpoint) {
|
|
111
|
+
const err = '@nquandt/azure-ai-sdk: An Azure AI Foundry endpoint is required. ' +
|
|
112
|
+
'Provide it via `resourceName`/`projectId`, the `endpoint` option, or the AZURE_AI_FOUNDRY_ENDPOINT environment variable.';
|
|
113
|
+
debugLog('ERROR', err);
|
|
114
|
+
throw new Error(err);
|
|
115
|
+
}
|
|
116
|
+
debugLog('INFO', `endpoint resolved — url=${endpoint}`);
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
// API key resolution:
|
|
119
|
+
// - options.apiKey wins if provided
|
|
120
|
+
// - If options.credential is explicitly set, the caller wants Entra auth;
|
|
121
|
+
// do NOT fall back to AZURE_FOUNDRY_API_KEY env var.
|
|
122
|
+
// - Otherwise, read AZURE_FOUNDRY_API_KEY from env as a convenience for
|
|
123
|
+
// testing without az login.
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
const apiKey = options.apiKey ??
|
|
126
|
+
(options.credential
|
|
127
|
+
? undefined
|
|
128
|
+
: (typeof process !== 'undefined' ? process.env.AZURE_FOUNDRY_API_KEY : undefined));
|
|
129
|
+
// When an explicit API key is provided, use it directly as the Bearer token
|
|
130
|
+
// and skip Entra identity entirely. This is useful for local testing without
|
|
131
|
+
// requiring `az login`. For production, prefer credential-based auth.
|
|
132
|
+
// null explicitly disables logging; undefined falls back to console.
|
|
133
|
+
const logger = options.logger === null ? null : (options.logger ?? console);
|
|
134
|
+
const getHeaders = apiKey
|
|
135
|
+
? (() => {
|
|
136
|
+
debugLog('INFO', 'auth=apiKey (Entra bypassed)');
|
|
137
|
+
return async () => ({
|
|
138
|
+
Authorization: `Bearer ${apiKey}`,
|
|
139
|
+
...options.headers,
|
|
140
|
+
});
|
|
141
|
+
})()
|
|
142
|
+
: (() => {
|
|
143
|
+
// Lazily import @azure/identity only when Entra auth is actually needed.
|
|
144
|
+
// This avoids loading native Azure SDK modules in environments (e.g. bun)
|
|
145
|
+
// where they may not be available, when an apiKey is being used instead.
|
|
146
|
+
let getTokenFn;
|
|
147
|
+
const defaultScope = endpoint.includes('services.ai.azure.com')
|
|
148
|
+
? AI_FOUNDRY_SCOPE
|
|
149
|
+
: COGNITIVE_SERVICES_SCOPE;
|
|
150
|
+
const scope = options.scope ?? defaultScope;
|
|
151
|
+
const credentialType = options.credential
|
|
152
|
+
? options.credential.constructor?.name ?? 'custom'
|
|
153
|
+
: 'DefaultAzureCredential';
|
|
154
|
+
return async () => {
|
|
155
|
+
if (!getTokenFn) {
|
|
156
|
+
debugLog('INFO', `acquiring Entra token — scope=${scope} credentialType=${credentialType}`);
|
|
157
|
+
const { DefaultAzureCredential, getBearerTokenProvider } = await import('@azure/identity');
|
|
158
|
+
const credential = options.credential ?? new DefaultAzureCredential();
|
|
159
|
+
getTokenFn = getBearerTokenProvider(credential, scope);
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const token = await getTokenFn();
|
|
163
|
+
debugLog('INFO', 'Entra token acquired successfully');
|
|
164
|
+
return {
|
|
165
|
+
Authorization: `Bearer ${token}`,
|
|
166
|
+
// APIM subscription key — sent alongside the Entra token when set
|
|
167
|
+
...(options.subscriptionKey
|
|
168
|
+
? {
|
|
169
|
+
'Ocp-Apim-Subscription-Key': options.subscriptionKey,
|
|
170
|
+
'api-key': options.subscriptionKey,
|
|
171
|
+
}
|
|
172
|
+
: {}),
|
|
173
|
+
// Explicit headers always win — they are merged last
|
|
174
|
+
...options.headers,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
179
|
+
const msg = `[azure-ai-sdk] Failed to acquire Azure token — endpoint=${endpoint} scope=${scope} credentialType=${credentialType} cause=${cause}`;
|
|
180
|
+
debugLog('ERROR', msg);
|
|
181
|
+
logger?.error(msg);
|
|
182
|
+
throw new Error(msg, { cause: err instanceof Error ? err : undefined });
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
})();
|
|
186
|
+
// Resolve the endpoint style.
|
|
187
|
+
//
|
|
188
|
+
// 'auto' (default) — infer from hostname:
|
|
189
|
+
// cognitiveservices.azure.com → 'cognitive-services'
|
|
190
|
+
// anything else → 'foundry'
|
|
191
|
+
//
|
|
192
|
+
// Callers may override with an explicit 'endpointStyle' to handle gateways
|
|
193
|
+
// (e.g. APIM) whose hostname does not match the backend's hostname pattern.
|
|
194
|
+
//
|
|
195
|
+
const resolvedStyle = (() => {
|
|
196
|
+
const style = options.endpointStyle ?? 'auto';
|
|
197
|
+
if (style === 'cognitive-services')
|
|
198
|
+
return 'cognitive-services';
|
|
199
|
+
if (style === 'foundry')
|
|
200
|
+
return 'foundry';
|
|
201
|
+
// 'auto' — sniff hostname
|
|
202
|
+
return endpoint.includes('cognitiveservices.azure.com')
|
|
203
|
+
? 'cognitive-services'
|
|
204
|
+
: 'foundry';
|
|
205
|
+
})();
|
|
206
|
+
const isCognitiveServices = resolvedStyle === 'cognitive-services';
|
|
207
|
+
const apiVersion = options.apiVersion ?? '2024-10-21';
|
|
208
|
+
const buildUrl = (modelId, urlSuffix = '/chat/completions') => {
|
|
209
|
+
if (isCognitiveServices) {
|
|
210
|
+
// Strip a trailing `/openai` that callers may have included in the endpoint.
|
|
211
|
+
// We always append `/openai/deployments/...` ourselves, so including it in
|
|
212
|
+
// the endpoint would produce a doubled path segment:
|
|
213
|
+
// https://my-org.azure-api.net/openai/openai/deployments/... ← wrong
|
|
214
|
+
// https://my-org.azure-api.net/openai/deployments/... ← correct
|
|
215
|
+
const base = endpoint.replace(/\/openai\/?$/i, '');
|
|
216
|
+
// For non-standard paths (e.g. Anthropic's /anthropic/v1/messages)
|
|
217
|
+
// don't wrap in the OpenAI deployment path structure
|
|
218
|
+
if (urlSuffix !== '/chat/completions') {
|
|
219
|
+
return `${base}${urlSuffix}`;
|
|
220
|
+
}
|
|
221
|
+
return `${base}/openai/deployments/${encodeURIComponent(modelId)}/chat/completions?api-version=${apiVersion}`;
|
|
222
|
+
}
|
|
223
|
+
// Foundry inference: OpenAI-compatible chat lives under `.../models/chat/completions`.
|
|
224
|
+
// Anthropic (Claude) on the same host uses `.../anthropic/v1/messages` — there is no
|
|
225
|
+
// `/models` segment on that route (see Azure AI Foundry Anthropic integration).
|
|
226
|
+
if (urlSuffix !== '/chat/completions' && /\/models\/?$/i.test(endpoint)) {
|
|
227
|
+
const base = endpoint.replace(/\/models\/?$/i, '');
|
|
228
|
+
return `${base}${urlSuffix}`;
|
|
229
|
+
}
|
|
230
|
+
return `${endpoint}${urlSuffix}`;
|
|
231
|
+
};
|
|
232
|
+
const createChatModel = (modelId, settings = {}) => new AzureFoundryChatLanguageModel(modelId, settings, {
|
|
233
|
+
provider: 'azure-foundry.chat',
|
|
234
|
+
url: buildUrl,
|
|
235
|
+
modelInBody: !isCognitiveServices,
|
|
236
|
+
headers: getHeaders,
|
|
237
|
+
fetch: options.fetch,
|
|
238
|
+
generateId: options.generateId,
|
|
239
|
+
});
|
|
240
|
+
const provider = function (modelId, settings) {
|
|
241
|
+
if (new.target) {
|
|
242
|
+
throw new Error('The AzureFoundry model function cannot be called with the new keyword.');
|
|
243
|
+
}
|
|
244
|
+
return createChatModel(modelId, settings);
|
|
245
|
+
};
|
|
246
|
+
provider.specificationVersion = 'v3';
|
|
247
|
+
provider.languageModel = createChatModel;
|
|
248
|
+
provider.chat = createChatModel;
|
|
249
|
+
provider.chatModel = createChatModel;
|
|
250
|
+
const noEmbeddings = (modelId) => {
|
|
251
|
+
throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' });
|
|
252
|
+
};
|
|
253
|
+
provider.embeddingModel = noEmbeddings;
|
|
254
|
+
provider.textEmbeddingModel = noEmbeddings;
|
|
255
|
+
provider.imageModel = (modelId) => {
|
|
256
|
+
throw new NoSuchModelError({ modelId, modelType: 'imageModel' });
|
|
257
|
+
};
|
|
258
|
+
debugLog('INFO', `provider created — endpoint=${endpoint} style=${resolvedStyle}`);
|
|
259
|
+
return provider;
|
|
260
|
+
}
|
|
261
|
+
// Credential classes are no longer re-exported from this module.
|
|
262
|
+
// Import them directly from '@azure/identity' when needed.
|
|
263
|
+
//# sourceMappingURL=azure-foundry-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azure-foundry-provider.js","sourceRoot":"","sources":["../src/azure-foundry-provider.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createAzureFoundry } from './azure-foundry-provider.js';
|
|
2
|
+
export type { AzureFoundryProvider, AzureFoundryProviderSettings } from './azure-foundry-provider.js';
|
|
3
|
+
export type { AzureFoundryChatModelId, AzureFoundryChatSettings } from './azure-foundry-chat-options.js';
|
|
4
|
+
export { AzureFoundryChatLanguageModel } from './azure-foundry-chat-language-model.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,YAAY,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAMtG,YAAY,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAMzG,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// @nquandt/azure-ai-sdk
|
|
3
|
+
//
|
|
4
|
+
// Vercel AI SDK custom provider for Azure AI Foundry using Entra authentication.
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Primary entrypoint — everything a consumer needs is re-exported here.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// -- Provider factory --------------------------------------------------------
|
|
10
|
+
// `createAzureFoundry` is the main entrypoint. Call it with your endpoint
|
|
11
|
+
// (and optionally a credential) to get a provider instance:
|
|
12
|
+
//
|
|
13
|
+
// const foundry = createAzureFoundry({ endpoint: '...' });
|
|
14
|
+
// const model = foundry('DeepSeek-R1'); // LanguageModelV2
|
|
15
|
+
// const model = foundry.chat('DeepSeek-R1'); // same, explicit
|
|
16
|
+
// const model = foundry.languageModel('DeepSeek-R1'); // same, via ProviderV2
|
|
17
|
+
//
|
|
18
|
+
export { createAzureFoundry } from './azure-foundry-provider.js';
|
|
19
|
+
// -- Language model class ----------------------------------------------------
|
|
20
|
+
// Exposed for advanced use — e.g. constructing a model directly without the
|
|
21
|
+
// provider factory, or wrapping it in another abstraction.
|
|
22
|
+
//
|
|
23
|
+
export { AzureFoundryChatLanguageModel } from './azure-foundry-chat-language-model.js';
|
|
24
|
+
// -- Azure Identity credentials ----------------------------------------------
|
|
25
|
+
// Import credential classes directly from '@azure/identity' when needed:
|
|
26
|
+
//
|
|
27
|
+
// import { ManagedIdentityCredential } from '@azure/identity';
|
|
28
|
+
// const foundry = createAzureFoundry({
|
|
29
|
+
// endpoint: '...',
|
|
30
|
+
// credential: new ManagedIdentityCredential('<client-id>'),
|
|
31
|
+
// });
|
|
32
|
+
//
|
|
33
|
+
// They are NOT re-exported here so that '@azure/identity' is not loaded at
|
|
34
|
+
// module-import time when an apiKey is used instead of Entra credentials.
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,wBAAwB;AACxB,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAEhF,8EAA8E;AAC9E,wEAAwE;AACxE,8EAA8E;AAE9E,+EAA+E;AAC/E,0EAA0E;AAC1E,4DAA4D;AAC5D,EAAE;AACF,6DAA6D;AAC7D,6EAA6E;AAC7E,6EAA6E;AAC7E,kFAAkF;AAClF,EAAE;AACF,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AASjE,+EAA+E;AAC/E,4EAA4E;AAC5E,2DAA2D;AAC3D,EAAE;AACF,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAEvF,+EAA+E;AAC/E,yEAAyE;AACzE,EAAE;AACF,iEAAiE;AACjE,yCAAyC;AACzC,uBAAuB;AACvB,gEAAgE;AAChE,QAAQ;AACR,EAAE;AACF,2EAA2E;AAC3E,0EAA0E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jonab/azure-ai-sdk",
|
|
3
|
+
"version": "0.5.17",
|
|
4
|
+
"description": "Vercel AI SDK custom provider for Azure AI Foundry using Azure Entra identity authentication. Fork with streaming usage and model body fixes.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "jonab",
|
|
7
|
+
"homepage": "https://github.com/BitcoinSuisse/azure-ai-sdk",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/BitcoinSuisse/azure-ai-sdk.git",
|
|
11
|
+
"directory": ""
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/nquandt/azure-ai-sdk/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai",
|
|
18
|
+
"azure",
|
|
19
|
+
"azure-ai-foundry",
|
|
20
|
+
"vercel-ai-sdk",
|
|
21
|
+
"ai-sdk",
|
|
22
|
+
"custom-provider",
|
|
23
|
+
"llm"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc -p tsconfig.build.json",
|
|
40
|
+
"dev": "tsc -p tsconfig.build.json --watch",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"clean": "rm -rf dist",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"test:watch": "vitest"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"ai": ">=6.0.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@ai-sdk/provider": "^3.0.10",
|
|
51
|
+
"@ai-sdk/provider-utils": "^4.0.27",
|
|
52
|
+
"@azure/identity": "^4.13.1",
|
|
53
|
+
"zod": "^4.4.3"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^25.8.0",
|
|
57
|
+
"ai": "^6.0.183",
|
|
58
|
+
"tsx": "^4.22.0",
|
|
59
|
+
"typescript": "^6.0.3",
|
|
60
|
+
"vitest": "^4.1.6"
|
|
61
|
+
}
|
|
62
|
+
}
|