From a074b9c1db86a6fad13522f0950e3a9c2de85619 Mon Sep 17 00:00:00 2001 From: Abdul-Microsoft Date: Fri, 13 Jun 2025 16:50:45 +0530 Subject: [PATCH 01/14] FDP changes --- infra/main.bicep | 447 ++++++++++++++++++++++++------------------ infra/main.bicepparam | 6 +- 2 files changed, 258 insertions(+), 195 deletions(-) diff --git a/infra/main.bicep b/infra/main.bicep index b0552b5cc..37c56a591 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -147,30 +147,30 @@ param aiFoundryAiServicesConfiguration aiServicesConfigurationType = { modelCapacity: 140 } -@description('Optional. The configuration to apply for the AI Foundry Storage Account resource.') -param aiFoundryStorageAccountConfiguration storageAccountType = { - enabled: true - name: replace('sthub${solutionPrefix}', '-', '') - location: azureOpenAILocation - tags: tags - sku: 'Standard_ZRS' - subnetResourceId: null //Default value set on module configuration -} - -@description('Optional. The configuration to apply for the AI Foundry AI Hub resource.') -param aiFoundryAiHubConfiguration aiHubType = { - enabled: true - name: 'aih-${solutionPrefix}' - location: azureOpenAILocation - sku: 'Basic' - tags: tags - subnetResourceId: null //Default value set on module configuration -} +// @description('Optional. The configuration to apply for the AI Foundry Storage Account resource.') +// param aiFoundryStorageAccountConfiguration storageAccountType = { +// enabled: true +// name: replace('sthub${solutionPrefix}', '-', '') +// location: azureOpenAILocation +// tags: tags +// sku: 'Standard_ZRS' +// subnetResourceId: null //Default value set on module configuration +// } + +// @description('Optional. The configuration to apply for the AI Foundry AI Hub resource.') +// param aiFoundryAiHubConfiguration aiHubType = { +// enabled: true +// name: 'aih-${solutionPrefix}' +// location: azureOpenAILocation +// sku: 'Basic' +// tags: tags +// subnetResourceId: null //Default value set on module configuration +// } @description('Optional. The configuration to apply for the AI Foundry AI Project resource.') param aiFoundryAiProjectConfiguration aiProjectConfigurationType = { enabled: true - name: 'aihb-${solutionPrefix}' + name: 'aifp-${solutionPrefix}' location: azureOpenAILocation sku: 'Basic' tags: tags @@ -754,7 +754,7 @@ var aiFoundryAiServicesModelDeployment = { raiPolicyName: 'Microsoft.Default' } -module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.10.2' = if (aiFoundryAIservicesEnabled) { +module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.11.0' = if (aiFoundryAIservicesEnabled) { name: take('avm.res.cognitive-services.account.${aiFoundryAiServicesResourceName}', 64) params: { name: aiFoundryAiServicesResourceName @@ -769,6 +769,10 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.10.2' apiProperties: { //staticsEnabled: false } + allowProjectManagement: true + managedIdentities: { + systemAssigned: true + } //publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' //publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' publicNetworkAccess: 'Enabled' //TODO: connection via private endpoint is not working from containers network. Change this when fixed @@ -798,6 +802,11 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.10.2' principalType: 'ServicePrincipal' roleDefinitionIdOrName: 'Cognitive Services OpenAI User' } + { + principalId: containerApp.outputs.?systemAssignedMIPrincipalId! + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' + } ] deployments: aiFoundryAiServicesConfiguration.?deployments ?? [ { @@ -819,168 +828,214 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.10.2' // AI Foundry: storage account // WAF best practices for Azure Blob Storage: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-blob-storage -var storageAccountPrivateDnsZones = { - 'privatelink.blob.${environment().suffixes.storage}': 'blob' - 'privatelink.file.${environment().suffixes.storage}': 'file' +// var storageAccountPrivateDnsZones = { +// 'privatelink.blob.${environment().suffixes.storage}': 'blob' +// 'privatelink.file.${environment().suffixes.storage}': 'file' +// } + +// module privateDnsZonesAiFoundryStorageAccount 'br/public:avm/res/network/private-dns-zone:0.3.1' = [ +// for zone in objectKeys(storageAccountPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryStorageAccountEnabled) { +// name: take( +// 'avm.res.network.private-dns-zone.storage-account.${uniqueString(aiFoundryStorageAccountResourceName,zone)}.${solutionPrefix}', +// 64 +// ) +// params: { +// name: zone +// tags: tags +// enableTelemetry: enableTelemetry +// virtualNetworkLinks: [ +// { +// name: 'vnetlink-${split(zone, '.')[1]}' +// virtualNetworkResourceId: virtualNetwork.outputs.resourceId +// } +// ] +// } +// } +// ] +// var aiFoundryStorageAccountEnabled = aiFoundryStorageAccountConfiguration.?enabled ?? true +// var aiFoundryStorageAccountResourceName = aiFoundryStorageAccountConfiguration.?name ?? replace( +// 'sthub${solutionPrefix}', +// '-', +// '' +// ) + +// module aiFoundryStorageAccount 'br/public:avm/res/storage/storage-account:0.18.2' = if (aiFoundryStorageAccountEnabled) { +// name: take('avm.res.storage.storage-account.${aiFoundryStorageAccountResourceName}', 64) +// dependsOn: [ +// privateDnsZonesAiFoundryStorageAccount +// ] +// params: { +// name: aiFoundryStorageAccountResourceName +// location: aiFoundryStorageAccountConfiguration.?location ?? azureOpenAILocation +// tags: aiFoundryStorageAccountConfiguration.?tags ?? tags +// enableTelemetry: enableTelemetry +// diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] +// skuName: aiFoundryStorageAccountConfiguration.?sku ?? 'Standard_ZRS' +// allowSharedKeyAccess: false +// networkAcls: { +// bypass: 'AzureServices' +// defaultAction: 'Allow' +// } +// blobServices: { +// deleteRetentionPolicyEnabled: false +// containerDeleteRetentionPolicyDays: 7 +// containerDeleteRetentionPolicyEnabled: false +// diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] +// } +// publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' +// allowBlobPublicAccess: false +// privateEndpoints: virtualNetworkEnabled +// ? map(items(storageAccountPrivateDnsZones), zone => { +// name: 'pep-${zone.value}-${aiFoundryStorageAccountResourceName}' +// customNetworkInterfaceName: 'nic-${zone.value}-${aiFoundryStorageAccountResourceName}' +// service: zone.value +// subnetResourceId: aiFoundryStorageAccountConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] ?? '' +// privateDnsZoneResourceIds: [resourceId('Microsoft.Network/privateDnsZones', zone.key)] +// }) +// : null +// roleAssignments: [ +// { +// principalId: userAssignedIdentity.outputs.principalId +// roleDefinitionIdOrName: 'Storage Blob Data Contributor' +// } +// ] +// } +// } + +// AI Foundry: AI Hub +// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai +// var mlTargetSubResource = 'amlworkspace' +// var mlPrivateDnsZones = { +// 'privatelink.api.azureml.ms': mlTargetSubResource +// 'privatelink.notebooks.azure.net': mlTargetSubResource +// } +// module privateDnsZonesAiFoundryWorkspaceHub 'br/public:avm/res/network/private-dns-zone:0.3.1' = [ +// for zone in objectKeys(mlPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryAiHubEnabled) { +// name: take('avm.res.network.private-dns-zone.ai-hub.${uniqueString(aiFoundryAiHubName,zone)}.${solutionPrefix}', 64) +// params: { +// name: zone +// enableTelemetry: enableTelemetry +// tags: tags +// virtualNetworkLinks: [ +// { +// name: 'vnetlink-${split(zone, '.')[1]}' +// virtualNetworkResourceId: virtualNetwork.outputs.resourceId +// } +// ] +// } +// } +// ] +// var aiFoundryAiHubEnabled = aiFoundryAiHubConfiguration.?enabled ?? true +// var aiFoundryAiHubName = aiFoundryAiHubConfiguration.?name ?? 'aih-${solutionPrefix}' +// module aiFoundryAiHub 'modules/ai-hub.bicep' = if (aiFoundryAiHubEnabled) { +// name: take('module.ai-hub.${aiFoundryAiHubName}', 64) +// dependsOn: [ +// privateDnsZonesAiFoundryWorkspaceHub +// ] +// params: { +// name: aiFoundryAiHubName +// location: aiFoundryAiHubConfiguration.?location ?? azureOpenAILocation +// tags: aiFoundryAiHubConfiguration.?tags ?? tags +// sku: aiFoundryAiHubConfiguration.?sku ?? 'Basic' +// aiFoundryAiServicesName: aiFoundryAiServices.outputs.name +// applicationInsightsResourceId: applicationInsights.outputs.resourceId +// enableTelemetry: enableTelemetry +// logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceId +// storageAccountResourceId: aiFoundryStorageAccount.outputs.resourceId +// virtualNetworkEnabled: virtualNetworkEnabled +// privateEndpoints: virtualNetworkEnabled +// ? [ +// { +// name: 'pep-${aiFoundryAiHubName}' +// customNetworkInterfaceName: 'nic-${aiFoundryAiHubName}' +// service: mlTargetSubResource +// subnetResourceId: virtualNetworkEnabled +// ? aiFoundryAiHubConfiguration.?subnetResourceId ?? virtualNetwork.?outputs.?subnetResourceIds[0] +// : null +// privateDnsZoneGroup: { +// privateDnsZoneGroupConfigs: map(objectKeys(mlPrivateDnsZones), zone => { +// name: replace(zone, '.', '-') +// privateDnsZoneResourceId: resourceId('Microsoft.Network/privateDnsZones', zone) +// }) +// } +// } +// ] +// : [] +// } +// } + +// AI Foundry: AI Project +// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai +// var aiFoundryAiProjectEnabled = aiFoundryAiProjectConfiguration.?enabled ?? true +var aiFoundryAiProjectName = aiFoundryAiProjectConfiguration.?name ?? 'aifp-${solutionPrefix}' + +// module aiFoundryAiProject 'br/public:avm/res/machine-learning-services/workspace:0.12.0' = if (aiFoundryAiProjectEnabled) { +// name: take('avm.res.machine-learning-services.workspace.${aiFoundryAiProjectName}', 64) +// params: { +// name: aiFoundryAiProjectName +// location: aiFoundryAiProjectConfiguration.?location ?? azureOpenAILocation +// tags: aiFoundryAiProjectConfiguration.?tags ?? tags +// enableTelemetry: enableTelemetry +// diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] +// sku: aiFoundryAiProjectConfiguration.?sku ?? 'Basic' +// kind: 'Project' +// hubResourceId: aiFoundryAiHub.outputs.resourceId +// roleAssignments: [ +// { +// principalId: containerApp.outputs.?systemAssignedMIPrincipalId! +// // Assigning the role with the role name instead of the role ID freezes the deployment at this point +// roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' //'Azure AI Developer' +// } +// ] +// } +// } + +resource aiServices 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = { + name: aiFoundryAiServicesResourceName } -module privateDnsZonesAiFoundryStorageAccount 'br/public:avm/res/network/private-dns-zone:0.3.1' = [ - for zone in objectKeys(storageAccountPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryStorageAccountEnabled) { - name: take( - 'avm.res.network.private-dns-zone.storage-account.${uniqueString(aiFoundryStorageAccountResourceName,zone)}.${solutionPrefix}', - 64 - ) - params: { - name: zone - tags: tags - enableTelemetry: enableTelemetry - virtualNetworkLinks: [ - { - name: 'vnetlink-${split(zone, '.')[1]}' - virtualNetworkResourceId: virtualNetwork.outputs.resourceId - } - ] - } +var aiProjectDescription = 'AI Foundry Project' + +resource aiFoundryProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' = { + parent: aiServices + name: aiFoundryAiProjectName + location: aiFoundryAiProjectConfiguration.?location ?? azureOpenAILocation + identity: { + type: 'SystemAssigned' } -] -var aiFoundryStorageAccountEnabled = aiFoundryStorageAccountConfiguration.?enabled ?? true -var aiFoundryStorageAccountResourceName = aiFoundryStorageAccountConfiguration.?name ?? replace( - 'sthub${solutionPrefix}', - '-', - '' -) - -module aiFoundryStorageAccount 'br/public:avm/res/storage/storage-account:0.18.2' = if (aiFoundryStorageAccountEnabled) { - name: take('avm.res.storage.storage-account.${aiFoundryStorageAccountResourceName}', 64) - dependsOn: [ - privateDnsZonesAiFoundryStorageAccount - ] - params: { - name: aiFoundryStorageAccountResourceName - location: aiFoundryStorageAccountConfiguration.?location ?? azureOpenAILocation - tags: aiFoundryStorageAccountConfiguration.?tags ?? tags - enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - skuName: aiFoundryStorageAccountConfiguration.?sku ?? 'Standard_ZRS' - allowSharedKeyAccess: false - networkAcls: { - bypass: 'AzureServices' - defaultAction: 'Allow' - } - blobServices: { - deleteRetentionPolicyEnabled: false - containerDeleteRetentionPolicyDays: 7 - containerDeleteRetentionPolicyEnabled: false - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - } - publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' - allowBlobPublicAccess: false - privateEndpoints: virtualNetworkEnabled - ? map(items(storageAccountPrivateDnsZones), zone => { - name: 'pep-${zone.value}-${aiFoundryStorageAccountResourceName}' - customNetworkInterfaceName: 'nic-${zone.value}-${aiFoundryStorageAccountResourceName}' - service: zone.value - subnetResourceId: aiFoundryStorageAccountConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] ?? '' - privateDnsZoneResourceIds: [resourceId('Microsoft.Network/privateDnsZones', zone.key)] - }) - : null - roleAssignments: [ - { - principalId: userAssignedIdentity.outputs.principalId - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - } - ] + properties: { + description: aiProjectDescription + displayName: aiFoundryAiProjectName } } -// AI Foundry: AI Hub -// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai -var mlTargetSubResource = 'amlworkspace' -var mlPrivateDnsZones = { - 'privatelink.api.azureml.ms': mlTargetSubResource - 'privatelink.notebooks.azure.net': mlTargetSubResource +resource aiUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '53ca6127-db72-4b80-b1b0-d745d6d5456d' } -module privateDnsZonesAiFoundryWorkspaceHub 'br/public:avm/res/network/private-dns-zone:0.3.1' = [ - for zone in objectKeys(mlPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryAiHubEnabled) { - name: take('avm.res.network.private-dns-zone.ai-hub.${uniqueString(aiFoundryAiHubName,zone)}.${solutionPrefix}', 64) - params: { - name: zone - enableTelemetry: enableTelemetry - tags: tags - virtualNetworkLinks: [ - { - name: 'vnetlink-${split(zone, '.')[1]}' - virtualNetworkResourceId: virtualNetwork.outputs.resourceId - } - ] - } - } -] -var aiFoundryAiHubEnabled = aiFoundryAiHubConfiguration.?enabled ?? true -var aiFoundryAiHubName = aiFoundryAiHubConfiguration.?name ?? 'aih-${solutionPrefix}' -module aiFoundryAiHub 'modules/ai-hub.bicep' = if (aiFoundryAiHubEnabled) { - name: take('module.ai-hub.${aiFoundryAiHubName}', 64) - dependsOn: [ - privateDnsZonesAiFoundryWorkspaceHub - ] - params: { - name: aiFoundryAiHubName - location: aiFoundryAiHubConfiguration.?location ?? azureOpenAILocation - tags: aiFoundryAiHubConfiguration.?tags ?? tags - sku: aiFoundryAiHubConfiguration.?sku ?? 'Basic' - aiFoundryAiServicesName: aiFoundryAiServices.outputs.name - applicationInsightsResourceId: applicationInsights.outputs.resourceId - enableTelemetry: enableTelemetry - logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceId - storageAccountResourceId: aiFoundryStorageAccount.outputs.resourceId - virtualNetworkEnabled: virtualNetworkEnabled - privateEndpoints: virtualNetworkEnabled - ? [ - { - name: 'pep-${aiFoundryAiHubName}' - customNetworkInterfaceName: 'nic-${aiFoundryAiHubName}' - service: mlTargetSubResource - subnetResourceId: virtualNetworkEnabled - ? aiFoundryAiHubConfiguration.?subnetResourceId ?? virtualNetwork.?outputs.?subnetResourceIds[0] - : null - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: map(objectKeys(mlPrivateDnsZones), zone => { - name: replace(zone, '.', '-') - privateDnsZoneResourceId: resourceId('Microsoft.Network/privateDnsZones', zone) - }) - } - } - ] - : [] + +resource aiUserAccessProj 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(containerApp.name, aiFoundryProject.id, aiUser.id) + scope: aiFoundryProject + properties: { + roleDefinitionId: aiUser.id + principalId: containerApp.outputs.?systemAssignedMIPrincipalId! } } -// AI Foundry: AI Project -// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai -var aiFoundryAiProjectEnabled = aiFoundryAiProjectConfiguration.?enabled ?? true -var aiFoundryAiProjectName = aiFoundryAiProjectConfiguration.?name ?? 'aihb-${solutionPrefix}' +resource aiDeveloper 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '64702f94-c441-49e6-a78b-ef80e0188fee' +} -module aiFoundryAiProject 'br/public:avm/res/machine-learning-services/workspace:0.12.0' = if (aiFoundryAiProjectEnabled) { - name: take('avm.res.machine-learning-services.workspace.${aiFoundryAiProjectName}', 64) - params: { - name: aiFoundryAiProjectName - location: aiFoundryAiProjectConfiguration.?location ?? azureOpenAILocation - tags: aiFoundryAiProjectConfiguration.?tags ?? tags - enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - sku: aiFoundryAiProjectConfiguration.?sku ?? 'Basic' - kind: 'Project' - hubResourceId: aiFoundryAiHub.outputs.resourceId - roleAssignments: [ - { - principalId: containerApp.outputs.?systemAssignedMIPrincipalId! - // Assigning the role with the role name instead of the role ID freezes the deployment at this point - roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' //'Azure AI Developer' - } - ] +resource aiUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(containerApp.name, aiServices.id, aiDeveloper.id) + scope: aiFoundryProject + properties: { + roleDefinitionId: aiDeveloper.id + principalId: containerApp.outputs.?systemAssignedMIPrincipalId! } } + // ========== Cosmos DB ========== // // WAF best practices for Cosmos DB: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/cosmos-db module privateDnsZonesCosmosDb 'br/public:avm/res/network/private-dns-zone:0.7.0' = if (virtualNetworkEnabled) { @@ -1189,11 +1244,11 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: applicationInsights.outputs.connectionString } - { - name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' - value: '${toLower(replace(azureOpenAILocation,' ',''))}.api.azureml.ms;${subscription().subscriptionId};${resourceGroup().name};${aiFoundryAiProjectName}' - //Location should be the AI Foundry AI Project location - } + // { + // name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' + // value: '${toLower(replace(azureOpenAILocation,' ',''))}.api.azureml.ms;${subscription().subscriptionId};${resourceGroup().name};${aiFoundryAiProjectName}' + // //Location should be the AI Foundry AI Project location + // } { name: 'AZURE_AI_SUBSCRIPTION_ID' value: subscription().subscriptionId @@ -1210,6 +1265,14 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container name: 'FRONTEND_SITE_NAME' value: 'https://${webSiteName}.azurewebsites.net' } + { + name: 'AZURE_AI_AGENT_ENDPOINT' + value: aiFoundryProject.properties.endpoints['AI Foundry API'] + } + { + name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' + value: aiFoundryAiServicesModelDeployment.name + } ] } ] @@ -1722,29 +1785,29 @@ type aiServicesConfigurationType = { modelCapacity: int? } -@export() -@description('The type for the Multi-Agent Custom Automation Engine Storage Account resource configuration.') -type storageAccountType = { - @description('Optional. If the Storage Account resource should be deployed or not.') - enabled: bool? +// @export() +// @description('The type for the Multi-Agent Custom Automation Engine Storage Account resource configuration.') +// type storageAccountType = { +// @description('Optional. If the Storage Account resource should be deployed or not.') +// enabled: bool? - @description('Optional. The name of the Storage Account resource.') - @maxLength(60) - name: string? +// @description('Optional. The name of the Storage Account resource.') +// @maxLength(60) +// name: string? - @description('Optional. Location for the Storage Account resource.') - @metadata({ azd: { type: 'location' } }) - location: string? +// @description('Optional. Location for the Storage Account resource.') +// @metadata({ azd: { type: 'location' } }) +// location: string? - @description('Optional. The tags to set for the Storage Account resource.') - tags: object? +// @description('Optional. The tags to set for the Storage Account resource.') +// tags: object? - @description('Optional. The SKU for the Storage Account resource.') - sku: ('Standard_LRS' | 'Standard_GRS' | 'Standard_RAGRS' | 'Standard_ZRS' | 'Premium_LRS' | 'Premium_ZRS')? +// @description('Optional. The SKU for the Storage Account resource.') +// sku: ('Standard_LRS' | 'Standard_GRS' | 'Standard_RAGRS' | 'Standard_ZRS' | 'Premium_LRS' | 'Premium_ZRS')? - @description('Optional. The resource Id of the subnet where the Storage Account private endpoint should be created.') - subnetResourceId: string? -} +// @description('Optional. The resource Id of the subnet where the Storage Account private endpoint should be created.') +// subnetResourceId: string? +// } @export() @description('The type for the Multi-Agent Custom Automation Engine AI Hub resource configuration.') diff --git a/infra/main.bicepparam b/infra/main.bicepparam index 5f32de008..60a29c75c 100644 --- a/infra/main.bicepparam +++ b/infra/main.bicepparam @@ -18,9 +18,9 @@ param applicationInsightsConfiguration = { param virtualNetworkConfiguration = { enabled: false } -param aiFoundryStorageAccountConfiguration = { - sku: 'Standard_LRS' -} +// param aiFoundryStorageAccountConfiguration = { +// sku: 'Standard_LRS' +// } param webServerFarmConfiguration = { skuCapacity: 1 skuName: 'B2' From dd786666fa7e60005630f028f0b88b5429dcb7e7 Mon Sep 17 00:00:00 2001 From: Abdul-Microsoft Date: Fri, 13 Jun 2025 17:49:09 +0530 Subject: [PATCH 02/14] role assignment changes --- infra/main.bicep | 60 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/infra/main.bicep b/infra/main.bicep index 37c56a591..0becd76c6 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -791,23 +791,23 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.11.0' } ]) : [] - roleAssignments: [ - // { - // principalId: userAssignedIdentity.outputs.principalId - // principalType: 'ServicePrincipal' - // roleDefinitionIdOrName: 'Cognitive Services OpenAI User' - // } - { - principalId: containerApp.outputs.?systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: 'Cognitive Services OpenAI User' - } - { - principalId: containerApp.outputs.?systemAssignedMIPrincipalId! - principalType: 'ServicePrincipal' - roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' - } - ] + // roleAssignments: [ + // // { + // // principalId: userAssignedIdentity.outputs.principalId + // // principalType: 'ServicePrincipal' + // // roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + // // } + // { + // principalId: containerApp.outputs.?systemAssignedMIPrincipalId! + // principalType: 'ServicePrincipal' + // roleDefinitionIdOrName: 'Cognitive Services OpenAI User' + // } + // { + // principalId: containerApp.outputs.?systemAssignedMIPrincipalId! + // principalType: 'ServicePrincipal' + // roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' + // } + // ] deployments: aiFoundryAiServicesConfiguration.?deployments ?? [ { name: aiFoundryAiServicesModelDeployment.name @@ -1007,6 +1007,9 @@ resource aiFoundryProject 'Microsoft.CognitiveServices/accounts/projects@2025-04 description: aiProjectDescription displayName: aiFoundryAiProjectName } + dependsOn:[ + aiServices + ] } resource aiUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { @@ -1022,11 +1025,20 @@ resource aiUserAccessProj 'Microsoft.Authorization/roleAssignments@2022-04-01' = } } +resource aiUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(containerApp.name, aiServices.id, aiUser.id) + scope: aiServices + properties: { + roleDefinitionId: aiUser.id + principalId: containerApp.outputs.?systemAssignedMIPrincipalId! + } +} + resource aiDeveloper 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { name: '64702f94-c441-49e6-a78b-ef80e0188fee' } -resource aiUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = { +resource aiDeveloperAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid(containerApp.name, aiServices.id, aiDeveloper.id) scope: aiFoundryProject properties: { @@ -1035,6 +1047,18 @@ resource aiUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01 } } +resource CognitiveServiceOpenAIUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' +} + +resource cognitiveServiceOpenAIUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(containerApp.name, aiServices.id, CognitiveServiceOpenAIUser.id) + scope: aiServices + properties: { + roleDefinitionId: CognitiveServiceOpenAIUser.id + principalId: containerApp.outputs.?systemAssignedMIPrincipalId! + } +} // ========== Cosmos DB ========== // // WAF best practices for Cosmos DB: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/cosmos-db From 8f00a7309fe45733bdf5498f2fc5b954cf1557a7 Mon Sep 17 00:00:00 2001 From: Abdul-Microsoft Date: Fri, 13 Jun 2025 19:33:24 +0530 Subject: [PATCH 03/14] added dependson to fix aiservice deployment issue --- infra/main.bicep | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/infra/main.bicep b/infra/main.bicep index 0becd76c6..2d45b3c8a 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -992,6 +992,9 @@ var aiFoundryAiProjectName = aiFoundryAiProjectConfiguration.?name ?? 'aifp-${so resource aiServices 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = { name: aiFoundryAiServicesResourceName + dependsOn:[ + aiFoundryAiServices + ] } var aiProjectDescription = 'AI Foundry Project' @@ -1007,9 +1010,6 @@ resource aiFoundryProject 'Microsoft.CognitiveServices/accounts/projects@2025-04 description: aiProjectDescription displayName: aiFoundryAiProjectName } - dependsOn:[ - aiServices - ] } resource aiUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { @@ -1268,11 +1268,11 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: applicationInsights.outputs.connectionString } - // { - // name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' - // value: '${toLower(replace(azureOpenAILocation,' ',''))}.api.azureml.ms;${subscription().subscriptionId};${resourceGroup().name};${aiFoundryAiProjectName}' - // //Location should be the AI Foundry AI Project location - // } + { + name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' + value: '${toLower(replace(azureOpenAILocation,' ',''))}.api.azureml.ms;${subscription().subscriptionId};${resourceGroup().name};${aiFoundryAiProjectName}' + //Location should be the AI Foundry AI Project location + } { name: 'AZURE_AI_SUBSCRIPTION_ID' value: subscription().subscriptionId From b711fc259fb290fb77006b06c54ff85234676dc8 Mon Sep 17 00:00:00 2001 From: UtkarshMishra-Microsoft Date: Fri, 13 Jun 2025 20:20:39 +0530 Subject: [PATCH 04/14] sample.env file --- src/backend/.env.sample | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backend/.env.sample b/src/backend/.env.sample index ddc1103d3..15bb1e0d4 100644 --- a/src/backend/.env.sample +++ b/src/backend/.env.sample @@ -9,13 +9,13 @@ AZURE_OPENAI_API_VERSION=2024-08-01-preview APPLICATIONINSIGHTS_INSTRUMENTATION_KEY= AZURE_AI_PROJECT_ENDPOINT= -AZURE_AI_SUBSCRIPTION_ID= +AZURE_AI_SUBSCRIPTION_ID=1 AZURE_AI_RESOURCE_GROUP= AZURE_AI_PROJECT_NAME= -AZURE_AI_AGENT_PROJECT_CONNECTION_STRING= AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o -APPLICATIONINSIGHTS_CONNECTION_STRING= +AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME=gpt-4o +#APPLICATIONINSIGHTS_CONNECTION_STRING= +AZURE_AI_AGENT_PROJECT_ENDPOINT= - -BACKEND_API_URL='http://localhost:8000' -FRONTEND_SITE_NAME='http://127.0.0.1:3000' \ No newline at end of file +BACKEND_API_URL=http://localhost:8000 +FRONTEND_SITE_NAME=http://127.0.0.1:3000 \ No newline at end of file From f413121e3c8ea36ebec33942cc5c9cca0ea086de Mon Sep 17 00:00:00 2001 From: UtkarshMishra-Microsoft Date: Fri, 13 Jun 2025 20:44:43 +0530 Subject: [PATCH 05/14] FDP-Backend_Changes --- src/backend/app_config.py | 10 ++-- src/backend/app_kernel.py | 20 ++++---- src/backend/config_kernel.py | 4 +- src/backend/kernel_agents/agent_base.py | 3 +- src/backend/kernel_agents/agent_factory.py | 13 ++---- src/backend/kernel_agents/planner_agent.py | 54 ++++++++++++---------- src/backend/pyproject.toml | 2 +- src/backend/requirements.txt | 6 +-- 8 files changed, 53 insertions(+), 59 deletions(-) diff --git a/src/backend/app_config.py b/src/backend/app_config.py index 798a510d2..7383018be 100644 --- a/src/backend/app_config.py +++ b/src/backend/app_config.py @@ -49,9 +49,7 @@ def __init__(self): self.AZURE_AI_SUBSCRIPTION_ID = self._get_required("AZURE_AI_SUBSCRIPTION_ID") self.AZURE_AI_RESOURCE_GROUP = self._get_required("AZURE_AI_RESOURCE_GROUP") self.AZURE_AI_PROJECT_NAME = self._get_required("AZURE_AI_PROJECT_NAME") - self.AZURE_AI_AGENT_PROJECT_CONNECTION_STRING = self._get_required( - "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING" - ) + self.AZURE_AI_AGENT_PROJECT_ENDPOINT = self._get_required("AZURE_AI_AGENT_PROJECT_ENDPOINT") # Cached clients and resources self._azure_credentials = None @@ -177,10 +175,8 @@ def get_ai_project_client(self): "Unable to acquire Azure credentials; ensure DefaultAzureCredential is configured" ) - connection_string = self.AZURE_AI_AGENT_PROJECT_CONNECTION_STRING - self._ai_project_client = AIProjectClient.from_connection_string( - credential=credential, conn_str=connection_string - ) + endpoint = self.AZURE_AI_AGENT_PROJECT_ENDPOINT + self._ai_project_client = AIProjectClient(endpoint=endpoint, credential=credential) return self._ai_project_client except Exception as exc: diff --git a/src/backend/app_kernel.py b/src/backend/app_kernel.py index a1ba44567..3d504e2b3 100644 --- a/src/backend/app_kernel.py +++ b/src/backend/app_kernel.py @@ -35,18 +35,18 @@ from utils_kernel import initialize_runtime_and_context, rai_success # Check if the Application Insights Instrumentation Key is set in the environment variables -connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") -if connection_string: +#connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") +#if connection_string: # Configure Application Insights if the Instrumentation Key is found #configure_azure_monitor(connection_string=connection_string) - logging.info( - "Application Insights configured with the provided Instrumentation Key" - ) -else: - # Log a warning if the Instrumentation Key is not found - logging.warning( - "No Application Insights Instrumentation Key found. Skipping configuration" - ) +# logging.info( +# "Application Insights configured with the provided Instrumentation Key" +# ) +#else: +# # Log a warning if the Instrumentation Key is not found +# logging.warning( +# "No Application Insights Instrumentation Key found. Skipping configuration" +# ) # Configure logging logging.basicConfig(level=logging.INFO) diff --git a/src/backend/config_kernel.py b/src/backend/config_kernel.py index 6227292dd..d1b41e6ed 100644 --- a/src/backend/config_kernel.py +++ b/src/backend/config_kernel.py @@ -26,9 +26,7 @@ class Config: AZURE_AI_SUBSCRIPTION_ID = config.AZURE_AI_SUBSCRIPTION_ID AZURE_AI_RESOURCE_GROUP = config.AZURE_AI_RESOURCE_GROUP AZURE_AI_PROJECT_NAME = config.AZURE_AI_PROJECT_NAME - AZURE_AI_AGENT_PROJECT_CONNECTION_STRING = ( - config.AZURE_AI_AGENT_PROJECT_CONNECTION_STRING - ) + AZURE_AI_AGENT_PROJECT_ENDPOINT = config.AZURE_AI_AGENT_PROJECT_ENDPOINT @staticmethod def GetAzureCredentials(): diff --git a/src/backend/kernel_agents/agent_base.py b/src/backend/kernel_agents/agent_base.py index 9abab5fbe..6a6c9bfa0 100644 --- a/src/backend/kernel_agents/agent_base.py +++ b/src/backend/kernel_agents/agent_base.py @@ -8,7 +8,8 @@ from event_utils import track_event_if_configured from models.messages_kernel import (ActionRequest, ActionResponse, AgentMessage, Step, StepStatus) -from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent +from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent, AzureAIAgentThread +from semantic_kernel.agents.azure_ai.azure_ai_agent_settings import AzureAIAgentSettings from semantic_kernel.functions import KernelFunction # Default formatting instructions used across agents diff --git a/src/backend/kernel_agents/agent_factory.py b/src/backend/kernel_agents/agent_factory.py index 440fa2058..535e79340 100644 --- a/src/backend/kernel_agents/agent_factory.py +++ b/src/backend/kernel_agents/agent_factory.py @@ -6,7 +6,7 @@ # Import the new AppConfig instance from app_config import config -from azure.ai.projects.models import (ResponseFormatJsonSchema, +from azure.ai.agents.models import (ResponseFormatJsonSchema, ResponseFormatJsonSchemaType) from context.cosmos_memory_kernel import CosmosMemoryContext from kernel_agents.agent_base import BaseAgent @@ -22,8 +22,8 @@ from kernel_agents.tech_support_agent import TechSupportAgent from models.messages_kernel import AgentType, PlannerResponsePlan # pylint:disable=E0611 -from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent - +from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent, AzureAIAgentThread +from semantic_kernel.agents.azure_ai.azure_ai_agent_settings import AzureAIAgentSettings logger = logging.getLogger(__name__) @@ -265,13 +265,6 @@ async def create_all_agents( temperature=temperature, agent_instances=agent_instances, # Pass agent instances to the planner client=client, - response_format=ResponseFormatJsonSchemaType( - json_schema=ResponseFormatJsonSchema( - name=PlannerResponsePlan.__name__, - description=f"respond with {PlannerResponsePlan.__name__.lower()}", - schema=PlannerResponsePlan.model_json_schema(), - ) - ), ) agent_instances[AgentType.PLANNER.value] = ( planner_agent # to pass it to group chat manager diff --git a/src/backend/kernel_agents/planner_agent.py b/src/backend/kernel_agents/planner_agent.py index 2bc5ad5b8..94105878e 100644 --- a/src/backend/kernel_agents/planner_agent.py +++ b/src/backend/kernel_agents/planner_agent.py @@ -3,7 +3,7 @@ import uuid from typing import Any, Dict, List, Optional, Tuple -from azure.ai.projects.models import (ResponseFormatJsonSchema, +from azure.ai.agents.models import (ResponseFormatJsonSchema, ResponseFormatJsonSchemaType) from context.cosmos_memory_kernel import CosmosMemoryContext from event_utils import track_event_if_configured @@ -133,37 +133,43 @@ async def create( try: logging.info("Initializing PlannerAgent from async init azure AI Agent") + # Construct response_format with the required 'type' field + response_format = { + "type": "json_schema", # Add the missing type field + "json_schema": { + "name": PlannerResponsePlan.__name__, + "description": f"respond with {PlannerResponsePlan.__name__.lower()}", + "schema": PlannerResponsePlan.model_json_schema() + } + } + # Create the Azure AI Agent using AppConfig with string instructions agent_definition = await cls._create_azure_ai_agent_definition( agent_name=agent_name, - instructions=cls._get_template(), # Pass the formatted string, not an object + instructions=cls._get_template(), # Pass the formatted string temperature=0.0, - response_format=ResponseFormatJsonSchemaType( - json_schema=ResponseFormatJsonSchema( - name=PlannerResponsePlan.__name__, - description=f"respond with {PlannerResponsePlan.__name__.lower()}", - schema=PlannerResponsePlan.model_json_schema(), - ) - ), + response_format=response_format, ) - return cls( - session_id=session_id, - user_id=user_id, - memory_store=memory_store, - tools=tools, - system_message=system_message, - agent_name=agent_name, - available_agents=available_agents, - agent_instances=agent_instances, - client=client, - definition=agent_definition, - ) - - except Exception as e: - logging.error(f"Failed to create Azure AI Agent for PlannerAgent: {e}") + except Exception as exc: + logging.error("Error initializing PlannerAgent definition: %s", exc) raise + return cls( + session_id=session_id, + user_id=user_id, + memory_store=memory_store, + tools=tools, + system_message=system_message, + agent_name=agent_name, + available_agents=available_agents, + agent_instances=agent_instances, + client=client, + definition=agent_definition, + ) + + + async def handle_input_task(self, input_task: InputTask) -> str: """Handle the initial input task from the user. diff --git a/src/backend/pyproject.toml b/src/backend/pyproject.toml index b989b2f14..e02186fdb 100644 --- a/src/backend/pyproject.toml +++ b/src/backend/pyproject.toml @@ -26,6 +26,6 @@ dependencies = [ "pytest-cov==5.0.0", "python-dotenv>=1.1.0", "python-multipart>=0.0.20", - "semantic-kernel>=1.28.1", + "semantic-kernel>=1.32.2", "uvicorn>=0.34.2", ] diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt index 76568fc86..5cac25b2f 100644 --- a/src/backend/requirements.txt +++ b/src/backend/requirements.txt @@ -14,9 +14,9 @@ opentelemetry-instrumentation-fastapi opentelemetry-instrumentation-openai opentelemetry-exporter-otlp-proto-http -semantic-kernel[azure]==1.28.1 -azure-ai-projects==1.0.0b10 -openai +semantic-kernel[azure]==1.32.2 +azure-ai-projects==1.0.0b11 +openai==1.84.0 azure-ai-inference==1.0.0b9 azure-search-documents azure-ai-evaluation From a1e385568826e66ec35a340bad9b3a19f04051b9 Mon Sep 17 00:00:00 2001 From: UtkarshMishra-Microsoft Date: Fri, 13 Jun 2025 20:58:34 +0530 Subject: [PATCH 06/14] Agent_factory Updated --- src/backend/kernel_agents/agent_factory.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/backend/kernel_agents/agent_factory.py b/src/backend/kernel_agents/agent_factory.py index 535e79340..d9c110a68 100644 --- a/src/backend/kernel_agents/agent_factory.py +++ b/src/backend/kernel_agents/agent_factory.py @@ -265,6 +265,14 @@ async def create_all_agents( temperature=temperature, agent_instances=agent_instances, # Pass agent instances to the planner client=client, + response_format = { + "type": "json_schema", + "json_schema": { + "name": PlannerResponsePlan.__name__, + "description": f"respond with {PlannerResponsePlan.__name__.lower()}", + "schema": PlannerResponsePlan.model_json_schema() + } + }, ) agent_instances[AgentType.PLANNER.value] = ( planner_agent # to pass it to group chat manager From ba6c85beabdb4b8b6698335a742780b44e710f38 Mon Sep 17 00:00:00 2001 From: UtkarshMishra-Microsoft Date: Fri, 13 Jun 2025 23:39:24 +0530 Subject: [PATCH 07/14] Endpoint Updated --- src/backend/.env.sample | 2 +- src/backend/app_config.py | 4 ++-- src/backend/config_kernel.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/.env.sample b/src/backend/.env.sample index 15bb1e0d4..970709a56 100644 --- a/src/backend/.env.sample +++ b/src/backend/.env.sample @@ -15,7 +15,7 @@ AZURE_AI_PROJECT_NAME= AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME=gpt-4o #APPLICATIONINSIGHTS_CONNECTION_STRING= -AZURE_AI_AGENT_PROJECT_ENDPOINT= +AZURE_AI_AGENT_ENDPOINT= BACKEND_API_URL=http://localhost:8000 FRONTEND_SITE_NAME=http://127.0.0.1:3000 \ No newline at end of file diff --git a/src/backend/app_config.py b/src/backend/app_config.py index 7383018be..d4b1a9e9a 100644 --- a/src/backend/app_config.py +++ b/src/backend/app_config.py @@ -49,7 +49,7 @@ def __init__(self): self.AZURE_AI_SUBSCRIPTION_ID = self._get_required("AZURE_AI_SUBSCRIPTION_ID") self.AZURE_AI_RESOURCE_GROUP = self._get_required("AZURE_AI_RESOURCE_GROUP") self.AZURE_AI_PROJECT_NAME = self._get_required("AZURE_AI_PROJECT_NAME") - self.AZURE_AI_AGENT_PROJECT_ENDPOINT = self._get_required("AZURE_AI_AGENT_PROJECT_ENDPOINT") + self.AZURE_AI_AGENT_ENDPOINT = self._get_required("AZURE_AI_AGENT_ENDPOINT") # Cached clients and resources self._azure_credentials = None @@ -175,7 +175,7 @@ def get_ai_project_client(self): "Unable to acquire Azure credentials; ensure DefaultAzureCredential is configured" ) - endpoint = self.AZURE_AI_AGENT_PROJECT_ENDPOINT + endpoint = self.AZURE_AI_AGENT_ENDPOINT self._ai_project_client = AIProjectClient(endpoint=endpoint, credential=credential) return self._ai_project_client diff --git a/src/backend/config_kernel.py b/src/backend/config_kernel.py index d1b41e6ed..80d0738af 100644 --- a/src/backend/config_kernel.py +++ b/src/backend/config_kernel.py @@ -26,7 +26,7 @@ class Config: AZURE_AI_SUBSCRIPTION_ID = config.AZURE_AI_SUBSCRIPTION_ID AZURE_AI_RESOURCE_GROUP = config.AZURE_AI_RESOURCE_GROUP AZURE_AI_PROJECT_NAME = config.AZURE_AI_PROJECT_NAME - AZURE_AI_AGENT_PROJECT_ENDPOINT = config.AZURE_AI_AGENT_PROJECT_ENDPOINT + AZURE_AI_AGENT_ENDPOINT = config.AZURE_AI_AGENT_ENDPOINT @staticmethod def GetAzureCredentials(): From 414ae4739f367f49ea8695d694933ee00cec7a73 Mon Sep 17 00:00:00 2001 From: UtkarshMishra-Microsoft Date: Fri, 13 Jun 2025 23:43:10 +0530 Subject: [PATCH 08/14] env changes --- src/backend/.env.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/.env.sample b/src/backend/.env.sample index 970709a56..a441829c4 100644 --- a/src/backend/.env.sample +++ b/src/backend/.env.sample @@ -9,7 +9,7 @@ AZURE_OPENAI_API_VERSION=2024-08-01-preview APPLICATIONINSIGHTS_INSTRUMENTATION_KEY= AZURE_AI_PROJECT_ENDPOINT= -AZURE_AI_SUBSCRIPTION_ID=1 +AZURE_AI_SUBSCRIPTION_ID= AZURE_AI_RESOURCE_GROUP= AZURE_AI_PROJECT_NAME= AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o From 1b38395f49c323d58a2de92238439adb9dfb0911 Mon Sep 17 00:00:00 2001 From: UtkarshMishra-Microsoft Date: Mon, 16 Jun 2025 13:06:21 +0530 Subject: [PATCH 09/14] Pylint Issue --- src/backend/app_kernel.py | 28 +++++++++++----------- src/backend/kernel_agents/agent_base.py | 3 +-- src/backend/kernel_agents/agent_factory.py | 4 ++-- src/backend/kernel_agents/planner_agent.py | 3 --- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/backend/app_kernel.py b/src/backend/app_kernel.py index 3d504e2b3..b7b22f07c 100644 --- a/src/backend/app_kernel.py +++ b/src/backend/app_kernel.py @@ -1,7 +1,6 @@ # app_kernel.py import asyncio import logging -import os import uuid from typing import Dict, List, Optional @@ -10,7 +9,7 @@ from auth.auth_utils import get_authenticated_user_details # Azure monitoring -from azure.monitor.opentelemetry import configure_azure_monitor +# from azure.monitor.opentelemetry import configure_azure_monitor from config_kernel import Config from event_utils import track_event_if_configured @@ -35,22 +34,23 @@ from utils_kernel import initialize_runtime_and_context, rai_success # Check if the Application Insights Instrumentation Key is set in the environment variables -#connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") -#if connection_string: - # Configure Application Insights if the Instrumentation Key is found - #configure_azure_monitor(connection_string=connection_string) -# logging.info( -# "Application Insights configured with the provided Instrumentation Key" -# ) -#else: -# # Log a warning if the Instrumentation Key is not found -# logging.warning( -# "No Application Insights Instrumentation Key found. Skipping configuration" -# ) +# connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") +# if connection_string: +# # Configure Application Insights if the Instrumentation Key is found +# configure_azure_monitor(connection_string=connection_string) +# logging.info( +# "Application Insights configured with the provided Instrumentation Key" +# ) +# else: +# # Log a warning if the Instrumentation Key is not found +# logging.warning( +# "No Application Insights Instrumentation Key found. Skipping configuration" +# ) # Configure logging logging.basicConfig(level=logging.INFO) + # Suppress INFO logs from 'azure.core.pipeline.policies.http_logging_policy' logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel( logging.WARNING diff --git a/src/backend/kernel_agents/agent_base.py b/src/backend/kernel_agents/agent_base.py index 6a6c9bfa0..9abab5fbe 100644 --- a/src/backend/kernel_agents/agent_base.py +++ b/src/backend/kernel_agents/agent_base.py @@ -8,8 +8,7 @@ from event_utils import track_event_if_configured from models.messages_kernel import (ActionRequest, ActionResponse, AgentMessage, Step, StepStatus) -from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent, AzureAIAgentThread -from semantic_kernel.agents.azure_ai.azure_ai_agent_settings import AzureAIAgentSettings +from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent from semantic_kernel.functions import KernelFunction # Default formatting instructions used across agents diff --git a/src/backend/kernel_agents/agent_factory.py b/src/backend/kernel_agents/agent_factory.py index d9c110a68..03f1409a4 100644 --- a/src/backend/kernel_agents/agent_factory.py +++ b/src/backend/kernel_agents/agent_factory.py @@ -23,7 +23,7 @@ from models.messages_kernel import AgentType, PlannerResponsePlan # pylint:disable=E0611 from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent, AzureAIAgentThread -from semantic_kernel.agents.azure_ai.azure_ai_agent_settings import AzureAIAgentSettings + logger = logging.getLogger(__name__) @@ -265,7 +265,7 @@ async def create_all_agents( temperature=temperature, agent_instances=agent_instances, # Pass agent instances to the planner client=client, - response_format = { + response_format= { "type": "json_schema", "json_schema": { "name": PlannerResponsePlan.__name__, diff --git a/src/backend/kernel_agents/planner_agent.py b/src/backend/kernel_agents/planner_agent.py index 94105878e..a7a21ec7a 100644 --- a/src/backend/kernel_agents/planner_agent.py +++ b/src/backend/kernel_agents/planner_agent.py @@ -3,8 +3,6 @@ import uuid from typing import Any, Dict, List, Optional, Tuple -from azure.ai.agents.models import (ResponseFormatJsonSchema, - ResponseFormatJsonSchemaType) from context.cosmos_memory_kernel import CosmosMemoryContext from event_utils import track_event_if_configured from kernel_agents.agent_base import BaseAgent @@ -21,7 +19,6 @@ from semantic_kernel.functions import KernelFunction from semantic_kernel.functions.kernel_arguments import KernelArguments - class PlannerAgent(BaseAgent): """Planner agent implementation using Semantic Kernel. From ac6240b604acd50ec400b052516df5dbe7eb99e5 Mon Sep 17 00:00:00 2001 From: UtkarshMishra-Microsoft Date: Mon, 16 Jun 2025 13:12:01 +0530 Subject: [PATCH 10/14] Pylint removal --- src/backend/kernel_agents/agent_factory.py | 7 +++---- src/backend/kernel_agents/planner_agent.py | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/backend/kernel_agents/agent_factory.py b/src/backend/kernel_agents/agent_factory.py index 03f1409a4..07f53ae49 100644 --- a/src/backend/kernel_agents/agent_factory.py +++ b/src/backend/kernel_agents/agent_factory.py @@ -6,8 +6,7 @@ # Import the new AppConfig instance from app_config import config -from azure.ai.agents.models import (ResponseFormatJsonSchema, - ResponseFormatJsonSchemaType) + from context.cosmos_memory_kernel import CosmosMemoryContext from kernel_agents.agent_base import BaseAgent from kernel_agents.generic_agent import GenericAgent @@ -22,7 +21,7 @@ from kernel_agents.tech_support_agent import TechSupportAgent from models.messages_kernel import AgentType, PlannerResponsePlan # pylint:disable=E0611 -from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent, AzureAIAgentThread +from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent logger = logging.getLogger(__name__) @@ -265,7 +264,7 @@ async def create_all_agents( temperature=temperature, agent_instances=agent_instances, # Pass agent instances to the planner client=client, - response_format= { + response_format={ "type": "json_schema", "json_schema": { "name": PlannerResponsePlan.__name__, diff --git a/src/backend/kernel_agents/planner_agent.py b/src/backend/kernel_agents/planner_agent.py index a7a21ec7a..00f02498a 100644 --- a/src/backend/kernel_agents/planner_agent.py +++ b/src/backend/kernel_agents/planner_agent.py @@ -19,6 +19,7 @@ from semantic_kernel.functions import KernelFunction from semantic_kernel.functions.kernel_arguments import KernelArguments + class PlannerAgent(BaseAgent): """Planner agent implementation using Semantic Kernel. @@ -165,8 +166,6 @@ async def create( definition=agent_definition, ) - - async def handle_input_task(self, input_task: InputTask) -> str: """Handle the initial input task from the user. From 3170e0113ec24531c6a9b318ddd95ce5e1ddc477 Mon Sep 17 00:00:00 2001 From: Abdul-Microsoft Date: Mon, 16 Jun 2025 16:17:40 +0530 Subject: [PATCH 11/14] Update Application Insights configuration and refactor response format handling in agent classes --- src/backend/.env.sample | 2 +- src/backend/app_kernel.py | 29 ++++++------ src/backend/kernel_agents/agent_factory.py | 20 ++++---- src/backend/kernel_agents/planner_agent.py | 54 +++++++++++----------- 4 files changed, 52 insertions(+), 53 deletions(-) diff --git a/src/backend/.env.sample b/src/backend/.env.sample index a441829c4..b0c3738b5 100644 --- a/src/backend/.env.sample +++ b/src/backend/.env.sample @@ -14,7 +14,7 @@ AZURE_AI_RESOURCE_GROUP= AZURE_AI_PROJECT_NAME= AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4o AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME=gpt-4o -#APPLICATIONINSIGHTS_CONNECTION_STRING= +APPLICATIONINSIGHTS_CONNECTION_STRING= AZURE_AI_AGENT_ENDPOINT= BACKEND_API_URL=http://localhost:8000 diff --git a/src/backend/app_kernel.py b/src/backend/app_kernel.py index b7b22f07c..6710e400c 100644 --- a/src/backend/app_kernel.py +++ b/src/backend/app_kernel.py @@ -1,6 +1,7 @@ # app_kernel.py import asyncio import logging +import os import uuid from typing import Dict, List, Optional @@ -9,7 +10,7 @@ from auth.auth_utils import get_authenticated_user_details # Azure monitoring -# from azure.monitor.opentelemetry import configure_azure_monitor +from azure.monitor.opentelemetry import configure_azure_monitor from config_kernel import Config from event_utils import track_event_if_configured @@ -33,19 +34,19 @@ # Updated import for KernelArguments from utils_kernel import initialize_runtime_and_context, rai_success -# Check if the Application Insights Instrumentation Key is set in the environment variables -# connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") -# if connection_string: -# # Configure Application Insights if the Instrumentation Key is found -# configure_azure_monitor(connection_string=connection_string) -# logging.info( -# "Application Insights configured with the provided Instrumentation Key" -# ) -# else: -# # Log a warning if the Instrumentation Key is not found -# logging.warning( -# "No Application Insights Instrumentation Key found. Skipping configuration" -# ) +#Check if the Application Insights Instrumentation Key is set in the environment variables +connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") +if connection_string: + # Configure Application Insights if the Instrumentation Key is found + configure_azure_monitor(connection_string=connection_string) + logging.info( + "Application Insights configured with the provided Instrumentation Key" + ) +else: + # Log a warning if the Instrumentation Key is not found + logging.warning( + "No Application Insights Instrumentation Key found. Skipping configuration" + ) # Configure logging logging.basicConfig(level=logging.INFO) diff --git a/src/backend/kernel_agents/agent_factory.py b/src/backend/kernel_agents/agent_factory.py index 07f53ae49..c098027ea 100644 --- a/src/backend/kernel_agents/agent_factory.py +++ b/src/backend/kernel_agents/agent_factory.py @@ -6,7 +6,8 @@ # Import the new AppConfig instance from app_config import config - +from azure.ai.agents.models import (ResponseFormatJsonSchema, + ResponseFormatJsonSchemaType) from context.cosmos_memory_kernel import CosmosMemoryContext from kernel_agents.agent_base import BaseAgent from kernel_agents.generic_agent import GenericAgent @@ -264,14 +265,13 @@ async def create_all_agents( temperature=temperature, agent_instances=agent_instances, # Pass agent instances to the planner client=client, - response_format={ - "type": "json_schema", - "json_schema": { - "name": PlannerResponsePlan.__name__, - "description": f"respond with {PlannerResponsePlan.__name__.lower()}", - "schema": PlannerResponsePlan.model_json_schema() - } - }, + response_format=ResponseFormatJsonSchemaType( + json_schema=ResponseFormatJsonSchema( + name=PlannerResponsePlan.__name__, + description=f"respond with {PlannerResponsePlan.__name__.lower()}", + schema=PlannerResponsePlan.model_json_schema(), + ) + ), ) agent_instances[AgentType.PLANNER.value] = ( planner_agent # to pass it to group chat manager @@ -326,4 +326,4 @@ def clear_cache(cls, session_id: Optional[str] = None) -> None: else: cls._agent_cache.clear() cls._azure_ai_agent_cache.clear() - logger.info("Cleared all agent caches") + logger.info("Cleared all agent caches") \ No newline at end of file diff --git a/src/backend/kernel_agents/planner_agent.py b/src/backend/kernel_agents/planner_agent.py index 00f02498a..e7b7f9117 100644 --- a/src/backend/kernel_agents/planner_agent.py +++ b/src/backend/kernel_agents/planner_agent.py @@ -3,6 +3,8 @@ import uuid from typing import Any, Dict, List, Optional, Tuple +from azure.ai.agents.models import (ResponseFormatJsonSchema, + ResponseFormatJsonSchemaType) from context.cosmos_memory_kernel import CosmosMemoryContext from event_utils import track_event_if_configured from kernel_agents.agent_base import BaseAgent @@ -131,40 +133,36 @@ async def create( try: logging.info("Initializing PlannerAgent from async init azure AI Agent") - # Construct response_format with the required 'type' field - response_format = { - "type": "json_schema", # Add the missing type field - "json_schema": { - "name": PlannerResponsePlan.__name__, - "description": f"respond with {PlannerResponsePlan.__name__.lower()}", - "schema": PlannerResponsePlan.model_json_schema() - } - } - # Create the Azure AI Agent using AppConfig with string instructions agent_definition = await cls._create_azure_ai_agent_definition( agent_name=agent_name, - instructions=cls._get_template(), # Pass the formatted string + instructions=cls._get_template(), # Pass the formatted string, not an object temperature=0.0, - response_format=response_format, + response_format=ResponseFormatJsonSchemaType( + json_schema=ResponseFormatJsonSchema( + name=PlannerResponsePlan.__name__, + description=f"respond with {PlannerResponsePlan.__name__.lower()}", + schema=PlannerResponsePlan.model_json_schema(), + ) + ), ) - except Exception as exc: - logging.error("Error initializing PlannerAgent definition: %s", exc) - raise + return cls( + session_id=session_id, + user_id=user_id, + memory_store=memory_store, + tools=tools, + system_message=system_message, + agent_name=agent_name, + available_agents=available_agents, + agent_instances=agent_instances, + client=client, + definition=agent_definition, + ) - return cls( - session_id=session_id, - user_id=user_id, - memory_store=memory_store, - tools=tools, - system_message=system_message, - agent_name=agent_name, - available_agents=available_agents, - agent_instances=agent_instances, - client=client, - definition=agent_definition, - ) + except Exception as e: + logging.error(f"Failed to create Azure AI Agent for PlannerAgent: {e}") + raise async def handle_input_task(self, input_task: InputTask) -> str: """Handle the initial input task from the user. @@ -598,4 +596,4 @@ def _get_template(): Choose from {{$agents_str}} ONLY for planning your steps. """ - return instruction_template + return instruction_template \ No newline at end of file From 23c469b8fd61e3f4045d5e455d7ac11fbe6cc222 Mon Sep 17 00:00:00 2001 From: Abdul-Microsoft Date: Mon, 16 Jun 2025 17:01:34 +0530 Subject: [PATCH 12/14] resolved pylint and agent recreation issue --- src/backend/app_kernel.py | 7 +++---- src/backend/kernel_agents/agent_base.py | 4 ++-- src/backend/kernel_agents/agent_factory.py | 4 ++-- src/backend/kernel_agents/planner_agent.py | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/backend/app_kernel.py b/src/backend/app_kernel.py index 6710e400c..217371d20 100644 --- a/src/backend/app_kernel.py +++ b/src/backend/app_kernel.py @@ -10,7 +10,7 @@ from auth.auth_utils import get_authenticated_user_details # Azure monitoring -from azure.monitor.opentelemetry import configure_azure_monitor +# from azure.monitor.opentelemetry import configure_azure_monitor from config_kernel import Config from event_utils import track_event_if_configured @@ -34,11 +34,11 @@ # Updated import for KernelArguments from utils_kernel import initialize_runtime_and_context, rai_success -#Check if the Application Insights Instrumentation Key is set in the environment variables +# Check if the Application Insights Instrumentation Key is set in the environment variables connection_string = os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING") if connection_string: # Configure Application Insights if the Instrumentation Key is found - configure_azure_monitor(connection_string=connection_string) + # configure_azure_monitor(connection_string=connection_string) logging.info( "Application Insights configured with the provided Instrumentation Key" ) @@ -51,7 +51,6 @@ # Configure logging logging.basicConfig(level=logging.INFO) - # Suppress INFO logs from 'azure.core.pipeline.policies.http_logging_policy' logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel( logging.WARNING diff --git a/src/backend/kernel_agents/agent_base.py b/src/backend/kernel_agents/agent_base.py index 9abab5fbe..2214751b5 100644 --- a/src/backend/kernel_agents/agent_base.py +++ b/src/backend/kernel_agents/agent_base.py @@ -276,8 +276,8 @@ async def _create_azure_ai_agent_definition( # # First try to get an existing agent with this name as assistant_id try: agent_id = None - agent_list = await client.agents.list_agents() - for agent in agent_list.data: + agent_list = client.agents.list_agents() + async for agent in agent_list: if agent.name == agent_name: agent_id = agent.id break diff --git a/src/backend/kernel_agents/agent_factory.py b/src/backend/kernel_agents/agent_factory.py index c098027ea..770dcf94f 100644 --- a/src/backend/kernel_agents/agent_factory.py +++ b/src/backend/kernel_agents/agent_factory.py @@ -7,7 +7,7 @@ # Import the new AppConfig instance from app_config import config from azure.ai.agents.models import (ResponseFormatJsonSchema, - ResponseFormatJsonSchemaType) + ResponseFormatJsonSchemaType) from context.cosmos_memory_kernel import CosmosMemoryContext from kernel_agents.agent_base import BaseAgent from kernel_agents.generic_agent import GenericAgent @@ -326,4 +326,4 @@ def clear_cache(cls, session_id: Optional[str] = None) -> None: else: cls._agent_cache.clear() cls._azure_ai_agent_cache.clear() - logger.info("Cleared all agent caches") \ No newline at end of file + logger.info("Cleared all agent caches") diff --git a/src/backend/kernel_agents/planner_agent.py b/src/backend/kernel_agents/planner_agent.py index e7b7f9117..c87516542 100644 --- a/src/backend/kernel_agents/planner_agent.py +++ b/src/backend/kernel_agents/planner_agent.py @@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional, Tuple from azure.ai.agents.models import (ResponseFormatJsonSchema, - ResponseFormatJsonSchemaType) + ResponseFormatJsonSchemaType) from context.cosmos_memory_kernel import CosmosMemoryContext from event_utils import track_event_if_configured from kernel_agents.agent_base import BaseAgent @@ -596,4 +596,4 @@ def _get_template(): Choose from {{$agents_str}} ONLY for planning your steps. """ - return instruction_template \ No newline at end of file + return instruction_template From adeea710f72096570cd8c8d68f16e51b339bbdc8 Mon Sep 17 00:00:00 2001 From: Abdul-Microsoft Date: Mon, 16 Jun 2025 18:33:46 +0530 Subject: [PATCH 13/14] Remove unused AI Foundry resource configurations and clean up related comments in main.bicep --- infra/main.bicep | 246 +---------------------------------------------- 1 file changed, 4 insertions(+), 242 deletions(-) diff --git a/infra/main.bicep b/infra/main.bicep index 00f1b14a9..ebaab8004 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -147,26 +147,6 @@ param aiFoundryAiServicesConfiguration aiServicesConfigurationType = { modelCapacity: 50 } -// @description('Optional. The configuration to apply for the AI Foundry Storage Account resource.') -// param aiFoundryStorageAccountConfiguration storageAccountType = { -// enabled: true -// name: replace('sthub${solutionPrefix}', '-', '') -// location: azureOpenAILocation -// tags: tags -// sku: 'Standard_ZRS' -// subnetResourceId: null //Default value set on module configuration -// } - -// @description('Optional. The configuration to apply for the AI Foundry AI Hub resource.') -// param aiFoundryAiHubConfiguration aiHubType = { -// enabled: true -// name: 'aih-${solutionPrefix}' -// location: azureOpenAILocation -// sku: 'Basic' -// tags: tags -// subnetResourceId: null //Default value set on module configuration -// } - @description('Optional. The configuration to apply for the AI Foundry AI Project resource.') param aiFoundryAiProjectConfiguration aiProjectConfigurationType = { enabled: true @@ -802,11 +782,6 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.11.0' // principalType: 'ServicePrincipal' // roleDefinitionIdOrName: 'Cognitive Services OpenAI User' // } - // { - // principalId: containerApp.outputs.?systemAssignedMIPrincipalId! - // principalType: 'ServicePrincipal' - // roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' - // } // ] deployments: aiFoundryAiServicesConfiguration.?deployments ?? [ { @@ -826,169 +801,11 @@ module aiFoundryAiServices 'br/public:avm/res/cognitive-services/account:0.11.0' } } -// AI Foundry: storage account -// WAF best practices for Azure Blob Storage: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-blob-storage -// var storageAccountPrivateDnsZones = { -// 'privatelink.blob.${environment().suffixes.storage}': 'blob' -// 'privatelink.file.${environment().suffixes.storage}': 'file' -// } - -// module privateDnsZonesAiFoundryStorageAccount 'br/public:avm/res/network/private-dns-zone:0.3.1' = [ -// for zone in objectKeys(storageAccountPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryStorageAccountEnabled) { -// name: take( -// 'avm.res.network.private-dns-zone.storage-account.${uniqueString(aiFoundryStorageAccountResourceName,zone)}.${solutionPrefix}', -// 64 -// ) -// params: { -// name: zone -// tags: tags -// enableTelemetry: enableTelemetry -// virtualNetworkLinks: [ -// { -// name: 'vnetlink-${split(zone, '.')[1]}' -// virtualNetworkResourceId: virtualNetwork.outputs.resourceId -// } -// ] -// } -// } -// ] -// var aiFoundryStorageAccountEnabled = aiFoundryStorageAccountConfiguration.?enabled ?? true -// var aiFoundryStorageAccountResourceName = aiFoundryStorageAccountConfiguration.?name ?? replace( -// 'sthub${solutionPrefix}', -// '-', -// '' -// ) - -// module aiFoundryStorageAccount 'br/public:avm/res/storage/storage-account:0.18.2' = if (aiFoundryStorageAccountEnabled) { -// name: take('avm.res.storage.storage-account.${aiFoundryStorageAccountResourceName}', 64) -// dependsOn: [ -// privateDnsZonesAiFoundryStorageAccount -// ] -// params: { -// name: aiFoundryStorageAccountResourceName -// location: aiFoundryStorageAccountConfiguration.?location ?? azureOpenAILocation -// tags: aiFoundryStorageAccountConfiguration.?tags ?? tags -// enableTelemetry: enableTelemetry -// diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] -// skuName: aiFoundryStorageAccountConfiguration.?sku ?? 'Standard_ZRS' -// allowSharedKeyAccess: false -// networkAcls: { -// bypass: 'AzureServices' -// defaultAction: 'Allow' -// } -// blobServices: { -// deleteRetentionPolicyEnabled: false -// containerDeleteRetentionPolicyDays: 7 -// containerDeleteRetentionPolicyEnabled: false -// diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] -// } -// publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' -// allowBlobPublicAccess: false -// privateEndpoints: virtualNetworkEnabled -// ? map(items(storageAccountPrivateDnsZones), zone => { -// name: 'pep-${zone.value}-${aiFoundryStorageAccountResourceName}' -// customNetworkInterfaceName: 'nic-${zone.value}-${aiFoundryStorageAccountResourceName}' -// service: zone.value -// subnetResourceId: aiFoundryStorageAccountConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] ?? '' -// privateDnsZoneResourceIds: [resourceId('Microsoft.Network/privateDnsZones', zone.key)] -// }) -// : null -// roleAssignments: [ -// { -// principalId: userAssignedIdentity.outputs.principalId -// roleDefinitionIdOrName: 'Storage Blob Data Contributor' -// } -// ] -// } -// } - -// AI Foundry: AI Hub -// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai -// var mlTargetSubResource = 'amlworkspace' -// var mlPrivateDnsZones = { -// 'privatelink.api.azureml.ms': mlTargetSubResource -// 'privatelink.notebooks.azure.net': mlTargetSubResource -// } -// module privateDnsZonesAiFoundryWorkspaceHub 'br/public:avm/res/network/private-dns-zone:0.3.1' = [ -// for zone in objectKeys(mlPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryAiHubEnabled) { -// name: take('avm.res.network.private-dns-zone.ai-hub.${uniqueString(aiFoundryAiHubName,zone)}.${solutionPrefix}', 64) -// params: { -// name: zone -// enableTelemetry: enableTelemetry -// tags: tags -// virtualNetworkLinks: [ -// { -// name: 'vnetlink-${split(zone, '.')[1]}' -// virtualNetworkResourceId: virtualNetwork.outputs.resourceId -// } -// ] -// } -// } -// ] -// var aiFoundryAiHubEnabled = aiFoundryAiHubConfiguration.?enabled ?? true -// var aiFoundryAiHubName = aiFoundryAiHubConfiguration.?name ?? 'aih-${solutionPrefix}' -// module aiFoundryAiHub 'modules/ai-hub.bicep' = if (aiFoundryAiHubEnabled) { -// name: take('module.ai-hub.${aiFoundryAiHubName}', 64) -// dependsOn: [ -// privateDnsZonesAiFoundryWorkspaceHub -// ] -// params: { -// name: aiFoundryAiHubName -// location: aiFoundryAiHubConfiguration.?location ?? azureOpenAILocation -// tags: aiFoundryAiHubConfiguration.?tags ?? tags -// sku: aiFoundryAiHubConfiguration.?sku ?? 'Basic' -// aiFoundryAiServicesName: aiFoundryAiServices.outputs.name -// applicationInsightsResourceId: applicationInsights.outputs.resourceId -// enableTelemetry: enableTelemetry -// logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceId -// storageAccountResourceId: aiFoundryStorageAccount.outputs.resourceId -// virtualNetworkEnabled: virtualNetworkEnabled -// privateEndpoints: virtualNetworkEnabled -// ? [ -// { -// name: 'pep-${aiFoundryAiHubName}' -// customNetworkInterfaceName: 'nic-${aiFoundryAiHubName}' -// service: mlTargetSubResource -// subnetResourceId: virtualNetworkEnabled -// ? aiFoundryAiHubConfiguration.?subnetResourceId ?? virtualNetwork.?outputs.?subnetResourceIds[0] -// : null -// privateDnsZoneGroup: { -// privateDnsZoneGroupConfigs: map(objectKeys(mlPrivateDnsZones), zone => { -// name: replace(zone, '.', '-') -// privateDnsZoneResourceId: resourceId('Microsoft.Network/privateDnsZones', zone) -// }) -// } -// } -// ] -// : [] -// } -// } - // AI Foundry: AI Project // WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai // var aiFoundryAiProjectEnabled = aiFoundryAiProjectConfiguration.?enabled ?? true var aiFoundryAiProjectName = aiFoundryAiProjectConfiguration.?name ?? 'aifp-${solutionPrefix}' - -// module aiFoundryAiProject 'br/public:avm/res/machine-learning-services/workspace:0.12.0' = if (aiFoundryAiProjectEnabled) { -// name: take('avm.res.machine-learning-services.workspace.${aiFoundryAiProjectName}', 64) -// params: { -// name: aiFoundryAiProjectName -// location: aiFoundryAiProjectConfiguration.?location ?? azureOpenAILocation -// tags: aiFoundryAiProjectConfiguration.?tags ?? tags -// enableTelemetry: enableTelemetry -// diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] -// sku: aiFoundryAiProjectConfiguration.?sku ?? 'Basic' -// kind: 'Project' -// hubResourceId: aiFoundryAiHub.outputs.resourceId -// roleAssignments: [ -// { -// principalId: containerApp.outputs.?systemAssignedMIPrincipalId! -// // Assigning the role with the role name instead of the role ID freezes the deployment at this point -// roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' //'Azure AI Developer' -// } -// ] -// } -// } +var aiProjectDescription = 'AI Foundry Project' resource aiServices 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = { name: aiFoundryAiServicesResourceName @@ -997,8 +814,6 @@ resource aiServices 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' ex ] } -var aiProjectDescription = 'AI Foundry Project' - resource aiFoundryProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' = { parent: aiServices name: aiFoundryAiProjectName @@ -1047,15 +862,15 @@ resource aiDeveloperAccessFoundry 'Microsoft.Authorization/roleAssignments@2022- } } -resource CognitiveServiceOpenAIUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { +resource cognitiveServiceOpenAIUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { name: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' } resource cognitiveServiceOpenAIUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(containerApp.name, aiServices.id, CognitiveServiceOpenAIUser.id) + name: guid(containerApp.name, aiServices.id, cognitiveServiceOpenAIUser.id) scope: aiServices properties: { - roleDefinitionId: CognitiveServiceOpenAIUser.id + roleDefinitionId: cognitiveServiceOpenAIUser.id principalId: containerApp.outputs.?systemAssignedMIPrincipalId! } } @@ -1268,11 +1083,6 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: applicationInsights.outputs.connectionString } - { - name: 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING' - value: '${toLower(replace(azureOpenAILocation,' ',''))}.api.azureml.ms;${subscription().subscriptionId};${resourceGroup().name};${aiFoundryAiProjectName}' - //Location should be the AI Foundry AI Project location - } { name: 'AZURE_AI_SUBSCRIPTION_ID' value: subscription().subscriptionId @@ -1809,54 +1619,6 @@ type aiServicesConfigurationType = { modelCapacity: int? } -// @export() -// @description('The type for the Multi-Agent Custom Automation Engine Storage Account resource configuration.') -// type storageAccountType = { -// @description('Optional. If the Storage Account resource should be deployed or not.') -// enabled: bool? - -// @description('Optional. The name of the Storage Account resource.') -// @maxLength(60) -// name: string? - -// @description('Optional. Location for the Storage Account resource.') -// @metadata({ azd: { type: 'location' } }) -// location: string? - -// @description('Optional. The tags to set for the Storage Account resource.') -// tags: object? - -// @description('Optional. The SKU for the Storage Account resource.') -// sku: ('Standard_LRS' | 'Standard_GRS' | 'Standard_RAGRS' | 'Standard_ZRS' | 'Premium_LRS' | 'Premium_ZRS')? - -// @description('Optional. The resource Id of the subnet where the Storage Account private endpoint should be created.') -// subnetResourceId: string? -// } - -@export() -@description('The type for the Multi-Agent Custom Automation Engine AI Hub resource configuration.') -type aiHubType = { - @description('Optional. If the AI Hub resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the AI Hub resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the AI Hub resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the AI Hub resource.') - tags: object? - - @description('Optional. The SKU of the AI Hub resource.') - sku: ('Basic' | 'Free' | 'Standard' | 'Premium')? - - @description('Optional. The resource Id of the subnet where the AI Hub private endpoint should be created.') - subnetResourceId: string? -} - @export() @description('The type for the Multi-Agent Custom Automation Engine AI Foundry AI Project resource configuration.') type aiProjectConfigurationType = { From 0b211d1377ec1d2ec178ba590eab767ee5dd0aae Mon Sep 17 00:00:00 2001 From: Abdul-Microsoft Date: Mon, 16 Jun 2025 19:30:56 +0530 Subject: [PATCH 14/14] removed storageaccount configuration param --- infra/main.bicepparam | 3 --- 1 file changed, 3 deletions(-) diff --git a/infra/main.bicepparam b/infra/main.bicepparam index 60a29c75c..e0be7c709 100644 --- a/infra/main.bicepparam +++ b/infra/main.bicepparam @@ -18,9 +18,6 @@ param applicationInsightsConfiguration = { param virtualNetworkConfiguration = { enabled: false } -// param aiFoundryStorageAccountConfiguration = { -// sku: 'Standard_LRS' -// } param webServerFarmConfiguration = { skuCapacity: 1 skuName: 'B2'