diff --git a/IMPLEMENTATION_NOTES.md b/IMPLEMENTATION_NOTES.md index a60c90f..adb8c75 100644 --- a/IMPLEMENTATION_NOTES.md +++ b/IMPLEMENTATION_NOTES.md @@ -306,6 +306,10 @@ Each model registration includes: - `deployment.modelName` set to the Foundry deployment name from the final segment of the deployment resource ID +Each registration also has a default-workspace alias that maps the OpenAI +`model` value to the provider model resource. The runtime model route is not +created when the provider model exists without this alias. + The deployment name, not the backing catalog model name, is the OpenAI `model` value sent through AI Gateway. diff --git a/infra/ai-gateway/main.bicep b/infra/ai-gateway/main.bicep index 01e7068..7f558d0 100644 --- a/infra/ai-gateway/main.bicep +++ b/infra/ai-gateway/main.bicep @@ -149,7 +149,23 @@ resource foundryCatalogModels 'Microsoft.ApiManagement/service/workspaces/modelP type: 'tokenLimit' period: 'minute' count: model.?tokenLimit ?? 10000 - counterKey: 'Identity' + counterKey: [ + 'identity' + ] + } + ] + } +}] + +resource foundryModelAliases 'Microsoft.ApiManagement/service/workspaces/aliases@2025-09-01-preview' = [for (model, i) in foundryModels: if (deployFoundryProvider && deployApimGatewayViaBicep) { + parent: defaultWorkspace + name: model.armName + properties: { + aliasName: last(split(model.resourceId, '/')) + description: model.?description ?? null + backendModels: [ + { + resourceId: foundryCatalogModels[i].id } ] } diff --git a/infra/scripts/configure-ai-gateway.ps1 b/infra/scripts/configure-ai-gateway.ps1 index 0db0b19..8b34ae1 100644 --- a/infra/scripts/configure-ai-gateway.ps1 +++ b/infra/scripts/configure-ai-gateway.ps1 @@ -122,7 +122,7 @@ function Test-GatewayModelRoute($GatewayUrl, $Model, $ApiKey) { } } - throw "AI Gateway model route failed. The route requires an explicit Api-Key header. Last error: $lastError" + throw "AI Gateway model route did not become ready after 15 attempts. Last error: $lastError" } function Prepare-BicepRbac { diff --git a/infra/scripts/configure-ai-gateway.sh b/infra/scripts/configure-ai-gateway.sh index 930929a..a8cbf88 100755 --- a/infra/scripts/configure-ai-gateway.sh +++ b/infra/scripts/configure-ai-gateway.sh @@ -111,7 +111,7 @@ verify_gateway_model_route() { fi done - echo "AI Gateway model route failed with HTTP ${status:-unavailable}. The route requires an explicit Api-Key header." >&2 + echo "AI Gateway model route did not become ready after 15 attempts (HTTP ${status:-unavailable})." >&2 if [ -s "$response_file" ]; then cat "$response_file" >&2 echo >&2 diff --git a/tests/test-ai-gateway-model-registration.sh b/tests/test-ai-gateway-model-registration.sh index 67016d2..00ae1af 100755 --- a/tests/test-ai-gateway-model-registration.sh +++ b/tests/test-ai-gateway-model-registration.sh @@ -39,6 +39,36 @@ if [[ "$actual_token_limit" != *"$expected_token_limit"* ]]; then exit 1 fi +expected_counter_key="'counterKey', createArray('identity')" + +if [[ "$actual_token_limit" != *"$expected_counter_key"* ]]; then + echo "Gateway token limit counterKey must use the current array contract." >&2 + echo "Expected expression containing: $expected_counter_key" >&2 + echo "Actual: $actual_token_limit" >&2 + exit 1 +fi + +alias_properties="$(jq -r ' + .resources[] + | select(.type == "Microsoft.ApiManagement/service/workspaces/aliases") + | .properties +' "$compiled_template")" +expected_alias_name="last(split(parameters('foundryModels')[copyIndex()].resourceId, '/'))" +expected_backend_model="Microsoft.ApiManagement/service/workspaces/modelProviders/models" + +if [[ "$alias_properties" != *"$expected_alias_name"* ]]; then + echo "Gateway model alias must use the Foundry deployment name." >&2 + echo "Expected expression containing: $expected_alias_name" >&2 + echo "Actual: $alias_properties" >&2 + exit 1 +fi + +if [[ "$alias_properties" != *"$expected_backend_model"* ]]; then + echo "Gateway model alias must target the registered provider model." >&2 + echo "Actual: $alias_properties" >&2 + exit 1 +fi + az bicep build \ --file "$repo_root/infra/main.bicep" \ --outfile "$compiled_root_template" \