Skip to content

Commit 18cfb8c

Browse files
committed
refactor: migrate to Azure OpenAI v1 API
1 parent 968110e commit 18cfb8c

File tree

3 files changed

+37
-33
lines changed

3 files changed

+37
-33
lines changed

infra/main.bicep

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@ param environmentName string
1111
// Run `az functionapp list-flexconsumption-locations --output table` to get the latest list
1212
@allowed([
1313
'northeurope'
14-
'southeastasia'
15-
'eastasia'
14+
'uksouth'
15+
'swedencentral'
16+
'eastus'
1617
'eastus2'
1718
'southcentralus'
18-
'australiaeast'
19-
'eastus'
2019
'westus2'
21-
'uksouth'
22-
'eastus2euap'
2320
'westus3'
24-
'swedencentral'
21+
'eastasia'
22+
'southeastasia'
23+
'australiaeast'
2524
])
2625
param location string
2726

@@ -38,7 +37,9 @@ param blobContainerName string = 'blobs'
3837
'australiaeast'
3938
'canadaeast'
4039
'eastus'
40+
'westus2'
4141
'eastus2'
42+
'westus3'
4243
'francecentral'
4344
'japaneast'
4445
'northcentralus'
@@ -53,15 +54,14 @@ param blobContainerName string = 'blobs'
5354
}
5455
})
5556
param aiServicesLocation string // Set in main.parameters.json
56-
param openAiApiVersion string // Set in main.parameters.json
5757
param defaultModelName string // Set in main.parameters.json
5858
param defaultModelVersion string // Set in main.parameters.json
5959
param defaultModelCapacity int // Set in main.parameters.json
6060

6161
// Location is not relevant here as it's only for the built-in api
6262
// which is not used here. Static Web App is a global service otherwise
6363
@description('Location for the Static Web App')
64-
@allowed(['westus2', 'centralus', 'eastus2', 'westeurope', 'eastasia', 'eastasiastage'])
64+
@allowed(['westus2', 'centralus', 'eastus2', 'westeurope', 'eastasia'])
6565
@metadata({
6666
azd: {
6767
type: 'location'
@@ -87,7 +87,7 @@ var burgerApiResourceName = '${abbrs.webSitesFunctions}burger-api-${resourceToke
8787
var burgerMcpResourceName = '${abbrs.webSitesFunctions}burger-mcp-${resourceToken}'
8888
var agentApiResourceName = '${abbrs.webSitesFunctions}agent-api-${resourceToken}'
8989
var storageAccountName = '${abbrs.storageStorageAccounts}${resourceToken}'
90-
var openAiUrl = 'https://${openAi.outputs.name}.openai.azure.com'
90+
var openAiUrl = 'https://${openAi.outputs.name}.openai.azure.com/openai/v1'
9191
var storageUrl = 'https://${storage.outputs.name}.blob.${environment().suffixes.storage}'
9292
var burgerApiUrl = 'https://${burgerApiFunction.outputs.defaultHostname}'
9393
var burgerMcpUrl = 'https://${burgerMcpFunction.outputs.defaultHostname}/mcp'
@@ -265,10 +265,8 @@ module agentApiFunctionSettings 'br/public:avm/res/web/site/config:0.1.0' = {
265265
appName: agentApiFunction.outputs.name
266266
properties: {
267267
AZURE_COSMOSDB_NOSQL_ENDPOINT: cosmosDb.outputs.endpoint
268-
AZURE_OPENAI_ENDPOINT: openAiUrl
269-
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: defaultModelName
270-
AZURE_OPENAI_INSTANCE_NAME: openAi.outputs.name
271-
AZURE_OPENAI_API_VERSION: openAiApiVersion
268+
AZURE_OPENAI_API_ENDPOINT: openAiUrl
269+
AZURE_OPENAI_MODEL: defaultModelName
272270
BURGER_MCP_ENDPOINT: burgerMcpUrl
273271
}
274272
storageAccountResourceId: storage.outputs.resourceId
@@ -444,7 +442,7 @@ module monitoring 'br/public:avm/ptn/azd/monitoring:0.2.1' = {
444442
}
445443
}
446444

447-
// TODO: migrate to Foundry
445+
// TODO: migrate to AI Foundry
448446
module openAi 'br/public:avm/res/cognitive-services/account:0.13.2' = {
449447
name: 'openai'
450448
scope: resourceGroup
@@ -625,9 +623,6 @@ output AZURE_STORAGE_CONTAINER_NAME string = blobContainerName
625623
output AZURE_COSMOSDB_NOSQL_ENDPOINT string = cosmosDb.outputs.endpoint
626624

627625
output AZURE_OPENAI_API_ENDPOINT string = openAiUrl
628-
output AZURE_OPENAI_API_INSTANCE_NAME string = openAi.outputs.name
629-
output AZURE_OPENAI_API_DEPLOYMENT_NAME string = defaultModelName
630-
output AZURE_OPENAI_API_VERSION string = openAiApiVersion
631626
output AZURE_OPENAI_MODEL string = defaultModelName
632627

633628
output GENAISCRIPT_DEFAULT_MODEL string = 'azure:${defaultModelName}'

packages/agent-api/scripts/update-local-settings.mjs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,8 @@ const settingsFilePath = path.join(__dirname, '../local.settings.json');
2727
console.log('Setting Azure AI service values...');
2828
settings = {
2929
...settings,
30-
AZURE_OPENAI_API_VERSION: process.env.AZURE_OPENAI_API_VERSION,
31-
AZURE_OPENAI_API_INSTANCE_NAME: process.env.AZURE_OPENAI_API_INSTANCE_NAME,
32-
AZURE_OPENAI_API_DEPLOYMENT_NAME: process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME,
3330
AZURE_OPENAI_API_ENDPOINT: process.env.AZURE_OPENAI_API_ENDPOINT,
31+
AZURE_OPENAI_MODEL: process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME,
3432
};
3533

3634
console.log('Setting Cosmos DB service values...');

packages/agent-api/src/functions/chats-post.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Readable } from 'node:stream';
22
import { randomUUID } from 'node:crypto';
33
import { HttpRequest, InvocationContext, HttpResponseInit, app } from '@azure/functions';
44
import { AIChatCompletionRequest, AIChatCompletionDelta } from '@microsoft/ai-chat-protocol';
5-
import { AzureChatOpenAI } from '@langchain/openai';
5+
import { ChatOpenAI } from '@langchain/openai';
66
import { AzureCosmsosDBNoSQLChatMessageHistory } from '@langchain/azure-cosmosdb';
77
import { createReactAgent } from "@langchain/langgraph/prebuilt";
88
import { AIMessage, HumanMessage } from '@langchain/core/messages';
@@ -40,7 +40,7 @@ Make sure the last question ends with ">>".
4040
- When using images in answers, use tables if you are showing multiple images in a list, to make the layout cleaner. Otherwise, try using a single image at the bottom of your answer.
4141
`;
4242

43-
const titleSystemPrompt = `Create a title for this chat session, based on the user question. The title should be less than 32 characters. Do NOT use double-quotes.`;
43+
const titleSystemPrompt = `Create a title for this chat session, based on the user question. The title should be less than 32 characters. Do NOT use double-quotes. The title should be concise, descriptive, and catchy. Respond with only the title, no other text.`;
4444

4545
export async function postChats(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
4646
const azureOpenAiEndpoint = process.env.AZURE_OPENAI_API_ENDPOINT;
@@ -83,14 +83,25 @@ export async function postChats(request: HttpRequest, context: InvocationContext
8383
};
8484
}
8585

86-
const credentials = getCredentials();
87-
const azureADTokenProvider = getAzureOpenAiTokenProvider();
88-
89-
const model = new AzureChatOpenAI({ azureADTokenProvider, streaming: true });
86+
const model = new ChatOpenAI({
87+
configuration: {
88+
baseURL: azureOpenAiEndpoint,
89+
async fetch(url, init = {}) {
90+
const token = await getAzureOpenAiTokenProvider()();
91+
const headers = new Headers(init.headers);
92+
headers.set('Authorization', `Bearer ${token}`);
93+
return fetch(url, { ...init, headers });
94+
},
95+
},
96+
modelName: process.env.AZURE_OPENAI_MODEL ?? 'gpt-5-mini',
97+
streaming: true,
98+
useResponsesApi: true,
99+
apiKey: 'not_used'
100+
});
90101
const chatHistory = new AzureCosmsosDBNoSQLChatMessageHistory({
91102
sessionId,
92103
userId,
93-
credentials,
104+
credentials: getCredentials(),
94105
containerName: 'history',
95106
databaseName: 'historyDB',
96107
});
@@ -156,8 +167,8 @@ export async function postChats(request: HttpRequest, context: InvocationContext
156167
['system', titleSystemPrompt],
157168
['human', question],
158169
]);
159-
context.log(`Title for session: ${response.content as string}`);
160-
chatHistory.setContext({ title: response.content });
170+
context.log(`Title for session: ${response.text}`);
171+
chatHistory.setContext({ title: response.text });
161172
}
162173

163174
return {
@@ -186,16 +197,16 @@ async function* createJsonStream(chunks: AsyncIterable<StreamEvent>, sessionId:
186197
const data = chunk.data;
187198
let responseChunk: AIChatCompletionDelta | undefined;
188199

189-
if (chunk.event === 'on_chain_end' && chunk.name === 'RunnableSequence') {
200+
if (chunk.event === 'on_chain_end' && chunk.name === 'RunnableSequence' && data.output?.content.length > 0) {
190201
// End of our agentic chain
191-
const content = data?.output?.content ?? '';
202+
const content = data?.output.content[0].text ?? '';
192203
await onComplete(content);
193204

194205
} else if (chunk.event === 'on_chat_model_stream' && data.chunk.content.length > 0) {
195206
// Streaming response from the LLM
196207
responseChunk = {
197208
delta: {
198-
content: data.chunk.content,
209+
content: data.chunk.content[0].text,
199210
role: 'assistant',
200211
},
201212
context: {

0 commit comments

Comments
 (0)