Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
146e04e
tools/sdk-ai-bots: add standardized deployment scaffolding
qiaozha Jun 30, 2026
7c8ae2d
sdk-ai-bots: wire up dev env-suite values and deployment hooks/scripts
qiaozha Jul 1, 2026
9cdd492
sdk-ai-bots: make main.bicepparam and dev.parameters.json honor env-s…
qiaozha Jul 1, 2026
8f6d490
sdk-ai-bots: parameterize deployLayer + split provision/deploy orches…
qiaozha Jul 1, 2026
d6bc5eb
sdk-ai-bots: suffix all top-level Azure resource names with envName
qiaozha Jul 1, 2026
d47e27b
Rename qzqabot prefix to qabot in deployment bicep files
qiaozha Jul 2, 2026
9456ab6
Use uniqueString suffix for resources and wire frontend to shared sto…
qiaozha Jul 2, 2026
757e360
Add resource-quota preflight check with region-alternative suggestions
qiaozha Jul 3, 2026
bbe5fd9
Frontend uses shared container registry instead of a dedicated one
qiaozha Jul 3, 2026
7392a9a
Parameterize resource names per env; align pipelines and rollback wit…
qiaozha Jul 3, 2026
f7c01e6
Extract shared provision/deploy stage templates; orchestrators become…
qiaozha Jul 3, 2026
2074d63
Add ephemeral PR environments via Azure Deployment Environments
qiaozha Jul 6, 2026
bf1294d
Add per-env bot-configs upload (channel.yaml, tenant.yaml)
qiaozha Jul 7, 2026
a4ea8c0
sdk-ai-bots: merge provision into CD pipelines with infra-diff gating
qiaozha Jul 7, 2026
5095f64
fix: sdk-ai-bots deployment fixes for dev provision
qiaozha Jul 7, 2026
be5d615
Merge branch 'qiaozha/sdk-ai-bots-deployment' of github.com:Azure/azu…
qiaozha Jul 8, 2026
881216e
sdk-ai-bots: fix azd provision + deploy for TME dev env
qiaozha Jul 8, 2026
d2052c8
sdk-ai-bots: enable local azd deploy for all services without Docker
qiaozha Jul 10, 2026
24680fa
sdk-ai-bots: fix azd deploy for agent and backend, and postprovision …
qiaozha Jul 14, 2026
4f48d81
sdk-ai-bots: automate Entra auth, App Config/Key Vault seeding, and b…
qiaozha Jul 15, 2026
3a67dad
Merge branch 'main' into qiaozha/sdk-ai-bots-deployment
qiaozha Jul 15, 2026
05efdc1
sdk-ai-bots: refine deployment hooks, infra params, and workflow defi…
qiaozha Jul 15, 2026
2acabd4
Merge branch 'main' into qiaozha/sdk-ai-bots-deployment
qiaozha Jul 16, 2026
3d16091
sdk-ai-bots: fix hosted agent env injection, function-app deploy, ado…
qiaozha Jul 16, 2026
9bc30f7
docs(sdk-ai-bots): document re-provision idempotency caveats for depl…
qiaozha Jul 16, 2026
f9bce21
sdk-ai-bots: LA→bot UAMI auth, bot-configs URL templating, frontend c…
qiaozha Jul 17, 2026
8111946
Add azd deployment journey slides for SDK Q&A bot
qiaozha Jul 20, 2026
df24224
docs(sdk-ai-bots): add azd deployment reflection slides
qiaozha Jul 24, 2026
7af444c
sdk-ai-bots: native azd slot deploy for agent-server + scoped build c…
qiaozha Jul 27, 2026
9de630c
Centralize infra provisioning; remove dead layered-provision code
qiaozha Jul 27, 2026
17699f8
sdk-ai-bots: switch deploy pipelines to azd-only, replace backend wit…
qiaozha Jul 28, 2026
7642858
Merge remote-tracking branch 'origin/main' into qiaozha/sdk-ai-bots-d…
qiaozha Aug 3, 2026
b82d161
Remove obsolete sdk-ai-bots deployment workarounds
qiaozha Aug 3, 2026
05cb965
Document model deployment serialization
qiaozha Aug 3, 2026
1313afd
Serialize model deployments with a resource loop
qiaozha Aug 4, 2026
a73d5cf
Deploy agent server directly to production
qiaozha Aug 4, 2026
b33eb3b
Merge branch 'main' into qiaozha/sdk-ai-bots-deployment
qiaozha Aug 4, 2026
916a3e1
Update deployment docs for agent server
qiaozha Aug 5, 2026
9fbbed0
Fix sdk-ai-bots environment provisioning
qiaozha Aug 6, 2026
e28bacb
Merge remote-tracking branch 'origin/main' into qiaozha/sdk-ai-bots-d…
qiaozha Aug 20, 2026
6b72d28
Unify sdk-ai-bots azd provisioning
qiaozha Aug 20, 2026
2dd93c6
Complete layered sdk-ai-bots deployment
qiaozha Aug 26, 2026
40332b1
Remove unused ADE scaffolding
qiaozha Aug 26, 2026
81c6ddd
Retarget sdk-ai-bots dev deployment
qiaozha Aug 26, 2026
7154bd4
Update sdk-ai-bots model deployments
qiaozha Aug 27, 2026
2fc47ae
Merge remote-tracking branch 'origin/main' into qiaozha/sdk-ai-bots-d…
qiaozha Aug 31, 2026
3496b38
Enable standard AI Search knowledge retrieval
qiaozha Aug 31, 2026
a178d6f
Provision chatbot evolution settings
qiaozha Aug 31, 2026
dd1ef38
Provision AI Search resources after deployment
qiaozha Sep 1, 2026
447c6ff
Use pipeline service connection for dev provision
qiaozha Sep 1, 2026
f188ace
Remove Azure DevOps environment dependencies
qiaozha Sep 1, 2026
ce4ad84
Fix dev provisioning pipeline setup
qiaozha Sep 1, 2026
2eb4b4d
Install required azd agent extensions
qiaozha Sep 1, 2026
671c125
Authenticate azd in Azure Pipelines
qiaozha Sep 2, 2026
917ff41
Use UAMI directly for bot authentication
qiaozha Sep 2, 2026
f1cb864
Preconfigure backend Entra application
qiaozha Sep 2, 2026
ad3e23a
Disable local auth for AI Services
qiaozha Sep 2, 2026
5855a2f
Restore knowledge sync API key authentication
qiaozha Sep 2, 2026
a805f12
Retry App Configuration RBAC propagation
qiaozha Sep 2, 2026
52340dc
Fix Logic App connection discovery
qiaozha Sep 2, 2026
a1c1447
Preserve empty Logic App workflow shell
qiaozha Sep 3, 2026
867f445
Consolidate sdk-ai-bots deployment pipelines
qiaozha Sep 3, 2026
29687e1
Fix sdk-ai-bots service connection binding
qiaozha Sep 3, 2026
32cd720
Fix AzureCLI service connection expansion
qiaozha Sep 3, 2026
f238c39
Hydrate ACR endpoint before azd deploy
qiaozha Sep 3, 2026
c516bc6
Include agent dashboard in Docker context
qiaozha Sep 3, 2026
581da85
Retry transient ACR log failures
qiaozha Sep 3, 2026
ec0c90b
Hydrate Foundry project before agent deploy
qiaozha Sep 3, 2026
aebb328
Extend hosted agent deployment timeout
qiaozha Sep 3, 2026
670fa9e
Add Logic App Teams consent gate
qiaozha Sep 4, 2026
b9a6b6b
Show preflight results in approval gate
qiaozha Sep 4, 2026
708fa69
Run Teams consent only after provisioning
qiaozha Sep 4, 2026
77f2cf9
Align checklist with live dev environment
qiaozha Sep 4, 2026
b939cb5
Merge remote-tracking branch 'origin/main' into qiaozha/sdk-ai-bots-d…
qiaozha Sep 7, 2026
2bef4b0
Sync dev Teams channel configuration
qiaozha Sep 7, 2026
34e3b68
Run frontend tests with Vitest 4
qiaozha Sep 7, 2026
80e6538
Merge remote-tracking branch 'origin/main' into qiaozha/sdk-ai-bots-d…
qiaozha Sep 7, 2026
6a7d3ff
Align deployment with recent SDK AI bot changes
qiaozha Sep 7, 2026
d5ab77c
Fix QA bot deployment skill compliance
qiaozha Sep 7, 2026
04a2d29
Fix SDK AI bot documentation links
qiaozha Sep 7, 2026
71075a2
Seed web fetch domain allow-list
qiaozha Sep 7, 2026
b7c22ba
Remove unrelated QA bot deployment skill
qiaozha Sep 7, 2026
9fb0ea7
Consolidate SDK AI bot deployment docs
qiaozha Sep 7, 2026
94d0e80
Consolidate SDK AI bot deployment pipeline
qiaozha Sep 8, 2026
727392a
Remove redundant SDK AI bot pipelines
qiaozha Sep 8, 2026
0f15cde
Add configurable deployment image tags
qiaozha Sep 8, 2026
ac81e7a
Document SDK AI bot deployment maintenance
qiaozha Sep 8, 2026
18cc591
Separate developer and deployment identities
qiaozha Sep 8, 2026
16da068
Document SDK AI bot permissions
qiaozha Sep 8, 2026
6453fa6
Route Logic App config through backend
qiaozha Sep 9, 2026
37a6bc4
Fix sdk-ai-bots deployment lifecycle
qiaozha Sep 11, 2026
23aee26
Support pre-authorized local deployments
qiaozha Sep 11, 2026
3f0f5a0
Restore Foundry project deployment output
qiaozha Sep 11, 2026
4f02a95
Make deployment image tag optional
qiaozha Sep 11, 2026
6df26a4
Align deployment stages with runtime dependencies
qiaozha Sep 11, 2026
1cee8a7
Address Search RBAC and Logic App feedback
qiaozha Sep 20, 2026
96c6a01
Target existing SDK bot dev environment
qiaozha Sep 20, 2026
459e326
Merge origin/main into sdk-ai-bots deployment
qiaozha Sep 29, 2026
975060b
Port recent chatbot deployment changes
qiaozha Sep 29, 2026
398bc9c
Adopt existing SDK bot resource state
qiaozha Sep 30, 2026
e2674d6
Complete dev deployment adoption
qiaozha Sep 30, 2026
7d025c6
Merge origin/main into sdk-ai-bots deployment
qiaozha Oct 13, 2026
82dd601
Align chatbot deployment with merged changes
qiaozha Oct 13, 2026
5989e72
Merge latest main and fix stale-job recovery test mock
qiaozha Oct 13, 2026
a4b62eb
Merge origin/main and reconcile chatbot container deployment
qiaozha Oct 16, 2026
87fe535
Align deployment configuration and checks with recent chatbot changes
qiaozha Oct 16, 2026
44de4c7
Preserve JSON Bicep overrides in pipeline environment loading
qiaozha Oct 17, 2026
2c903c4
Focus chatbot documentation on the deployment process
qiaozha Oct 17, 2026
205d39c
Check incremental deployment quota in resource-specific regions
qiaozha Oct 17, 2026
fb7ccc1
Remove the application vault and vault-backed deployment notifications
qiaozha Oct 17, 2026
6797b6d
Verify the Teams connection selected by deployed Logic Apps
qiaozha Oct 17, 2026
2a41927
Reconcile Foundry deployment permissions idempotently
qiaozha Oct 17, 2026
0c3ff1f
Use Bicep-managed authorization for the dev environment
qiaozha Oct 17, 2026
4222d8e
Revert the last dev authorization push
qiaozha Oct 17, 2026
2e57f23
Automate chatbot resource roles and add dev bootstrap tooling
qiaozha Oct 31, 2026
00121c9
Require existing chatbot resource groups and permission-only bootstrap
qiaozha Oct 31, 2026
cacae3b
Use existing dev chatbot connection and remove unused slot swap
qiaozha Nov 2, 2026
0fa1011
Merge latest main for October chatbot deployment audit
qiaozha Nov 2, 2026
cb1b99d
Sync October chatbot deployment contracts and production-channel preview
qiaozha Nov 2, 2026
b5f9d97
Remove obsolete chatbot deployment paths and consolidate provisioning
qiaozha Nov 2, 2026
b794585
Sync chatbot frontend HTTP dependency updates
qiaozha Nov 3, 2026
39923c2
Merge origin/main and sync chatbot deployment requirements
qiaozha Nov 8, 2026
b4c7cee
Remove duplicated knowledge-sync deployment wiring
qiaozha Nov 8, 2026
d2068a7
Reuse adopted Search identity and existing model permissions
qiaozha Nov 8, 2026
e199a3e
Upgrade Foundry agents extension to stable 1.0.0
qiaozha Nov 8, 2026
38e551d
Pin pipeline azd and Foundry extension versions
qiaozha Nov 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions tools/sdk-ai-bots/azure-sdk-qa-bot-agent/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Build context for the agent-server image (see Dockerfile).
# Allowlist: ignore everything, then re-include only the paths the Dockerfile
# COPYs. This keeps the `az acr build` upload minimal (excludes images/, tests/,
# pipelines/, scripts/, tsp/, docs, dev deps, etc.).
*

!requirements.txt
!agents/
!agents/chat_agent/
!config/
!models/
!prompts/
!services/
!static/
!tools/
!utils/
!skills/
!server.py
!_version.py

# Drop caches that may live inside the re-included directories.
**/__pycache__
**/*.pyc
**/*.pyo
**/.pytest_cache
**/.mypy_cache
**/.ruff_cache
agents/chat_agent/chat_agent_env/
24 changes: 13 additions & 11 deletions tools/sdk-ai-bots/azure-sdk-qa-bot-agent/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@ RUN tdnf install -y ca-certificates tar gzip git openssh-clients && \
tdnf clean all

# Install dependencies first (layer caching)
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/requirements.txt .
# NOTE: paths are relative to the build context, which is the project directory
# (tools/sdk-ai-bots/azure-sdk-qa-bot-agent), not the repository root.
COPY requirements.txt .
RUN pip install --no-cache-dir --pre --timeout ${PIP_DEFAULT_TIMEOUT} --retries ${PIP_RETRIES} -r requirements.txt

# Copy application code
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/config/ ./config/
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/models/ ./models/
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/prompts/ ./prompts/
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/services/ ./services/
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/static/ ./static/
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/tools/ ./tools/
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/utils/ ./utils/
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/skills/ ./skills/
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/server.py .
COPY tools/sdk-ai-bots/azure-sdk-qa-bot-agent/_version.py .
COPY config/ ./config/
COPY models/ ./models/
COPY prompts/ ./prompts/
COPY services/ ./services/
COPY static/ ./static/
COPY tools/ ./tools/
COPY utils/ ./utils/
COPY skills/ ./skills/
COPY server.py .
COPY _version.py .

EXPOSE 8089

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
name: azure-sdk-chat-agent
kind: hosted
description: Hosted container agent using pre-built image placeholder.azurecr.io/agent:v1
protocols:
- protocol: responses
version: 2.0.0
# NOTE: the hosted agent container's AZURE_APPCONFIG_ENDPOINT env var is NOT set
# here. azd's azure.ai.agents extension does not embed agent.yaml
# `environment_variables` into the deployed version's container definition (its
# "Registering agent environment variables" step is a no-op), so the container
# would still boot without it and crash in app_config.init(). The env var is
# injected reliably by deployment/hooks/agent-postdeploy.ts, which creates a
# follow-up agent version with environment_variables embedded in the definition.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ WORKDIR /app
ENV PYTHONUNBUFFERED=1
ENV ENABLE_INSTRUMENTATION=true

ARG AZSDK_CLI_VERSION=0.6.3
ARG AZSDK_CLI_VERSION=0.6.43
ARG NODE_VERSION=22.12.0
ARG ADO_MCP_VERSION=2.7.0

Expand Down
59 changes: 7 additions & 52 deletions tools/sdk-ai-bots/azure-sdk-qa-bot-agent/pipelines/agent-cd.yml
Comment thread
qiaozha marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ parameters:
variables:
- template: /eng/pipelines/templates/variables/globals.yml
- template: /eng/pipelines/templates/variables/image.yml
- ${{ if eq(parameters.environment, 'dev') }}:
- group: 'Azure SDK QA Bot Dev Variables'
- ${{ if eq(parameters.environment, 'prod') }}:
- group: 'Azure SDK QA Bot Prod Variables'
- template: /tools/sdk-ai-bots/deployment/pipelines/templates/service-connection.yml
parameters:
environment: ${{ parameters.environment }}
- name: workingDirectory
value: '$(System.DefaultWorkingDirectory)/tools/sdk-ai-bots/azure-sdk-qa-bot-agent'
- name: PythonIndexUrl
Expand All @@ -50,51 +49,7 @@ extends:
image: $(LINUXVMIMAGE)
os: linux
steps:
- checkout: self
displayName: 'Checkout repository'

- task: PipAuthenticate@1
displayName: 'Authenticate pip to Azure Artifacts'
inputs:
artifactFeeds: 'public/azure-sdk-for-python'

- task: AzureCLI@2
displayName: 'Build, Push & Deploy Agent'
inputs:
azureSubscription: $(SERVICE_CONNECTION)
scriptType: bash
scriptLocation: inlineScript
workingDirectory: $(workingDirectory)
inlineScript: |
set -euo pipefail

if [ "${{ parameters.agentName }}" = "chatbot_evolution_agent" ] && [ "${{ parameters.environment }}" != "prod" ]; then
echo "chatbot_evolution_agent is production-only."
exit 1
fi

# Suppress Azure CLI welcome banner on fresh CI agents.
export AZURE_CORE_WELCOME_MESSAGE=false
az version > /dev/null 2>&1 || true
az config set core.welcome_message=false 2>/dev/null || true

python -m pip install --upgrade pip
python -m pip install keyring artifacts-keyring --retries 5 --timeout 60

python -m pip config set global.index-url "$PIP_INDEX_URL"

pip install -r requirements.txt --retries 5 --timeout 60

python scripts/deploy_hosted_agent.py \
${{ parameters.agentName }} \
--tag "$(Build.BuildId)" \
--appconfig-endpoint "$(AZURE_APPCONFIG_ENDPOINT)"
env:
ENABLE_AI_FOUNDRY_AGENT_ROUTING: ${{ iif(eq(parameters.environment, 'dev'), 'true', 'false') }}
AZURE_CORE_WELCOME_MESSAGE: 'false'
AI_FOUNDRY_RAI_POLICY_ID: $(AI_FOUNDRY_RAI_POLICY_ID)
AI_FOUNDRY_PROJECT_NAME: $(AI_FOUNDRY_PROJECT_NAME)
ACR_NAME: $(ACR_NAME)
ACR_RESOURCE_GROUP: $(ACR_RESOURCE_GROUP)
CANDIDATE_APPCONFIG_ENDPOINT: $(CANDIDATE_APPCONFIG_ENDPOINT)
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- template: /tools/sdk-ai-bots/deployment/pipelines/templates/hosted-agent-deploy-steps.yml
parameters:
agentName: ${{ parameters.agentName }}
environment: ${{ parameters.environment }}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ parameters:
variables:
- template: /eng/pipelines/templates/variables/globals.yml
- template: /eng/pipelines/templates/variables/image.yml
- group: 'Azure SDK QA Bot Prod Variables'
- template: /tools/sdk-ai-bots/deployment/pipelines/templates/service-connection.yml
parameters:
environment: prod
- name: workingDirectory
value: '$(System.DefaultWorkingDirectory)/tools/sdk-ai-bots/azure-sdk-qa-bot-agent'
- name: PythonIndexUrl
Expand All @@ -53,7 +55,7 @@ extends:
jobs:
- job: RunFeedbackJobs
displayName: 'Run Feedback Jobs'
timeoutInMinutes: 120
timeoutInMinutes: 360
pool:
name: $(LINUXPOOL)
image: $(LINUXVMIMAGE)
Expand All @@ -62,6 +64,10 @@ extends:
- checkout: self
displayName: 'Checkout repository'

- template: /tools/sdk-ai-bots/deployment/pipelines/templates/load-environment-suite.yml
parameters:
environment: prod

- template: /eng/common/pipelines/templates/steps/login-to-github.yml

- task: PipAuthenticate@1
Expand All @@ -72,7 +78,8 @@ extends:
- task: AzureCLI@2
displayName: 'Run Feedback Job Scan'
inputs:
azureSubscription: $(SERVICE_CONNECTION)
azureSubscription: $(AZURE_SERVICE_CONNECTION)
addSpnToEnvironment: true
scriptType: bash
scriptLocation: inlineScript
workingDirectory: $(workingDirectory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,12 @@ extends:
inlineScript: |
set -euo pipefail
# Use remote ACR build to avoid hosted-agent network restrictions during pip install.
# Build context is scoped to the project directory (not the repo root) to keep the upload small.
az acr build \
--registry "$(ACR_NAME)" \
--image "$(imageName):$(imageTag)" \
--file "tools/sdk-ai-bots/azure-sdk-qa-bot-agent/Dockerfile" \
"$(System.DefaultWorkingDirectory)"
--file "$(workingDirectory)/Dockerfile" \
"$(workingDirectory)"
ACR_LOGIN_SERVER=$(az acr show --name "$(ACR_NAME)" --resource-group "$(ACR_RESOURCE_GROUP)" --query loginServer -o tsv)
echo "Image pushed: $ACR_LOGIN_SERVER/$(imageName):$(imageTag)"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ azure-appconfiguration==1.8.0
azure-cosmos==4.9.0
azure-identity==1.26.0b2
azure-keyvault-keys==4.11.0
azure-keyvault-secrets==4.9.0
azure-storage-blob==12.29.0
python-dotenv>=1.2.2
pyyaml>=6.0.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@

import argparse
import asyncio
import json
import os
import re
import subprocess
import sys
import time
from pathlib import Path
from urllib.parse import quote, urlparse
from urllib.request import Request, urlopen

os.environ.setdefault("AZURE_CORE_WELCOME_MESSAGE", "false")

Expand Down Expand Up @@ -70,6 +73,30 @@ def _git_short_sha() -> str:
return "latest"


def _qualify_rai_policy_id(
policy: str,
*,
subscription_id: str,
resource_group: str,
project_endpoint: str,
) -> str:
if policy.lower().startswith("/subscriptions/"):
return policy

hostname = urlparse(project_endpoint).hostname or ""
ai_resource_name = hostname.split(".", 1)[0]
if not subscription_id or not resource_group or not ai_resource_name:
raise RuntimeError(
"Cannot qualify the RAI policy name; AZURE_SUBSCRIPTION_ID, "
"AZURE_RESOURCE_GROUP, and AI Foundry project endpoint are required."
)
return (
f"/subscriptions/{subscription_id}/resourceGroups/{resource_group}"
f"/providers/Microsoft.CognitiveServices/accounts/{ai_resource_name}"
f"/raiPolicies/{policy}"
)


def _wait_for_version_active(
project: "AIProjectClient",
agent_name: str,
Expand Down Expand Up @@ -113,6 +140,37 @@ def _wait_for_version_active(
return False


def _resolve_agent_principal_id(
project_endpoint: str,
agent_name: str,
agent_version: str,
credential: AzureCliCredential,
) -> str:
"""Resolve the managed identity assigned to a hosted agent version."""
token = credential.get_token("https://ai.azure.com/.default").token
endpoint = (
f"{project_endpoint.rstrip('/')}/agents/{quote(agent_name, safe='')}"
f"/versions/{quote(agent_version, safe='')}?api-version=2025-05-15-preview"
)
last_error = "identity was not returned"
for _ in range(10):
try:
request = Request(endpoint, headers={"Authorization": f"Bearer {token}"})
with urlopen(request, timeout=60) as response:
body = json.load(response)
identity = body.get("instance_identity") or body.get("instanceIdentity") or {}
principal_id = identity.get("principal_id") or identity.get("principalId")
if principal_id:
return str(principal_id)
last_error = "instance identity has no principal ID"
except Exception as exc:
last_error = str(exc)
time.sleep(15)
raise RuntimeError(
f"Could not resolve the runtime identity for {agent_name} v{agent_version}: {last_error}"
)


def main() -> None:
parser = argparse.ArgumentParser(
description="Build, push, and deploy a hosted agent."
Expand Down Expand Up @@ -259,15 +317,23 @@ def main() -> None:
"ENABLE_INSTRUMENTATION": "true",
"APP_VERSION": next_version,
}
if candidate_appconfig_endpoint:
if args.agent_name == "chatbot_evolution_agent":
env_vars["CANDIDATE_APPCONFIG_ENDPOINT"] = candidate_appconfig_endpoint

# Ensure Content-safety guardrail.
rai_policy_id = os.environ.get("AI_FOUNDRY_RAI_POLICY_ID", "")
rai_policy_id = os.environ.get("AI_FOUNDRY_RAI_POLICY_ID") or cfg(
"AI_FOUNDRY_RAI_POLICY_ID"
)
if not rai_policy_id:
raise RuntimeError(
"Cannot apply guardrail because AI_FOUNDRY_RAI_POLICY_ID is not set."
)
rai_policy_id = _qualify_rai_policy_id(
rai_policy_id,
subscription_id=sub_id,
resource_group=os.environ.get("AZURE_RESOURCE_GROUP", ""),
project_endpoint=project_endpoint,
)
rai_config = RaiConfig(rai_policy_name=rai_policy_id)
print(f" Guardrail: {rai_policy_id}")

Expand Down Expand Up @@ -312,6 +378,22 @@ def main() -> None:
f'--url "{project_endpoint}/agents/{agent.name}/versions/{agent_version}" '
'--resource "https://ai.azure.com"'
)

principal_id = _resolve_agent_principal_id(
project_endpoint,
agent.name,
agent_version,
credential,
)
print(f"Runtime identity: {principal_id}")
print(
"##vso[task.setvariable variable=HOSTED_AGENT_PRINCIPAL_ID]"
f"{principal_id}"
)
print(
"##vso[task.setvariable variable=HOSTED_AGENT_VERSION]"
f"{agent_version}"
)
finally:
project.close()
credential.close()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Tests for hosted-agent deployment helpers."""

from scripts.deploy_hosted_agent import _qualify_rai_policy_id


def test_qualifies_short_rai_policy_name() -> None:
assert _qualify_rai_policy_id(
"Microsoft.DefaultV2",
subscription_id="00000000-0000-0000-0000-000000000001",
resource_group="qabot-dev",
project_endpoint=(
"https://qabot-ai.services.ai.azure.com/api/projects/qabot"
),
) == (
"/subscriptions/00000000-0000-0000-0000-000000000001"
"/resourceGroups/qabot-dev/providers/Microsoft.CognitiveServices"
"/accounts/qabot-ai/raiPolicies/Microsoft.DefaultV2"
)


def test_preserves_qualified_rai_policy_id() -> None:
policy_id = (
"/subscriptions/00000000-0000-0000-0000-000000000001"
"/resourceGroups/qabot-dev/providers/Microsoft.CognitiveServices"
"/accounts/qabot-ai/raiPolicies/custom"
)
assert _qualify_rai_policy_id(
policy_id,
subscription_id="ignored",
resource_group="ignored",
project_endpoint="https://ignored",
) == policy_id
Loading
Loading