STATE bar påstanden «uverifisert: om FoundryChatClient kan binde en Claude- deployment» som en bisetning. Operatøren ba om at slikt ikke får ligge. Målt mot Microsoft Learn i stedet, og antakelsen er FALSIFISERT. Claude-modeller solgt via Azure Marketplace kalles med Anthropics egen Messages API på en egen endepunkt-form: https://<resource>.services.ai.azure.com/anthropic/v1/messages <- Claude https://<resource>.services.ai.azure.com/api/projects/<project> <- FoundryChatClient Klienter: `anthropic`-pakka, `@anthropic-ai/foundry-sdk`, eller REST med `anthropic-version: 2023-06-01`. Kun /v1/messages og /v1/messages/count_tokens er eksponert på «Hosted on Azure»-versjonen. Deployment-navnet er `model`-parameteren. Konsekvens for M1 (fase 1b), og den er en BESLUTNING, ikke en detalj: - Microsoft-solgt modell (gpt-5-mini o.l.) -> 1b er REN KONFIG, azure-profilen som shippet er riktig søm, ingenting å bygge. - Claude -> 1b krever en NY BACKEND-PROFIL i produksjonskode. Samme klasse som notatet under «Endpoint format»: *.openai.azure.com og *.cognitiveservices.azure.com er andre flater igjen. Tre flater, én ressurs-host. Samme pass fanget forutsetningene som gater portalarbeidet: Marketplace-subscribe- tillatelse, Contributor/Owner på ressursgruppa, prosjekt i støttet region, og data retention PÅ abonnementet for Covered Models (ZDR gir 400, og Microsoft kan ikke endre det for deg). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X737cbkG2uAXJ2Bvhf6X5M
5.7 KiB
Azure AI Foundry auth recipe (S4.1)
Verified against Microsoft Learn and the pinned
agent-framework-foundry==1.8.2in this repo's.venv. This note is the operator's manual auth recipe for the single planned live Foundry run (M1). The offlinepython -m portfolio_optimiser.preflight --profile azurechecks the config; this doc covers what preflight cannot: the actual authentication.
The recipe (local dev, Intel Mac)
az login— sign in to the correct Entra tenant with the Azure CLI. This is a manual operator step; the code never runs it (no auto-login).- The code passes a lazy
AzureCliCredential()(azure.identity.aio) toFoundryChatClient(AzureFoundryBackend.create_chat_client). Constructing the credential acquires no token — the token is fetched from theaz loginsession only on the first live call. So passing a credential object is not auto-login.AzureCliCredentialis preferred overDefaultAzureCredentialon a non-Azure host: the latter probes the IMDS managed-identity endpoint (times out / stalls) and can pick a stray identity.
- Set the config the preflight validates:
PORTFOLIO_FOUNDRY_PROJECT_ENDPOINT— the Foundry project endpoint (below).PORTFOLIO_MODEL_MAP— path to an out-of-tree model_map with real azure deployment names, so tenant-specific names are never committed. (Or replace theREPLACE-WITH-*placeholders.)
FoundryChatClient signature (pinned 1.8.2)
FoundryChatClient(*, project_endpoint, model, credential, ...) — all keyword-only. credential
is REQUIRED on the project_endpoint path: the 1.8.2 client raises
ValueError("Azure credential is required when using project_endpoint without a project_client.")
at construction if omitted. There is no lazy DefaultAzureCredential default. The model
parameter is model (the portal deployment name), not deployment_name.
Endpoint format
Canonical Foundry project endpoint:
https://<resource>.services.ai.azure.com/api/projects/<project>
The bare-host form https://<resource>.services.ai.azure.com also appears in official samples and
is accepted. The preflight requires https:// + a host ending .services.ai.azure.com; it does
not require the /api/projects/ path. A *.openai.azure.com or *.cognitiveservices.azure.com
endpoint is a different client surface (use OpenAIChatClient, not FoundryChatClient).
Claude models on Foundry are a THIRD client surface (measured 2026-08-13)
Verified against Microsoft Learn (microsoft_docs_search, "Deploy and use Claude models in Microsoft
Foundry" / "Claude models in Microsoft Foundry — API overview"), because the question came up while
planning M1 and an assumption was cheaper to falsify than to inherit.
FoundryChatClient CANNOT serve a Claude deployment. Claude models sold through the Azure
Marketplace are called with Anthropic's own Messages API, on their own endpoint shape:
https://<resource>.services.ai.azure.com/anthropic/v1/messages # Claude
https://<resource>.services.ai.azure.com/api/projects/<project> # FoundryChatClient
Clients: the anthropic Python package (or @anthropic-ai/foundry-sdk, or REST with the
anthropic-version: 2023-06-01 header). Only POST /v1/messages and POST /v1/messages/count_tokens
are exposed on the Hosted on Azure version. The deployment name is what goes in the model
parameter — same rule as the Foundry surface, different endpoint.
What this means for M1 (fase 1b):
- A Microsoft-sold model (
gpt-5-mini,gpt-4.1-mini, …) → M1 is configuration only. Theazureprofile as shipped is the right seam; nothing to build. - A Claude model → M1 needs a NEW backend profile (production code,
anthropicSDK, Entra ID or key auth). That is a decision to take before the portal work, not a discovery during it.
This is the same class as the note under Endpoint format: *.openai.azure.com and
*.cognitiveservices.azure.com are other surfaces again. Three surfaces, one resource host.
Extra prerequisites measured in the same pass (they gate the portal work, not the code):
Marketplace subscription permission, Contributor or Owner on the resource group, a project in a
region the model supports, and — for Anthropic-designated Covered Models — data retention enabled
on the subscription (zero-data-retention subscriptions get a 400 invalid_request_error, and
Microsoft cannot change that setting for you).
RBAC role
Assign Foundry User (role GUID 53ca6127-db72-4b80-b1b0-d745d6d5456d) to the identity, at the
Foundry resource/project scope. Do NOT use Azure AI Developer (scoped to hubs/ML
workspaces, not Foundry projects) or Cognitive Services User (the classic Azure OpenAI surface).
Note the recent rename: Foundry User was formerly Azure AI User — reference the GUID, not the
display name, since older community answers use both.
Preflight is necessary-but-not-sufficient
A green preflight rules out the offline-detectable misconfiguration class: unset endpoint,
malformed/wrong-surface endpoint URL, unresolved REPLACE-WITH-* placeholder deployments, and an
inconsistent model-map. It cannot prove the paid live call will succeed. The following surface
only at the live call and are out of scope for an offline check:
- RBAC — missing/wrong role → 403 (propagation lag can cause 401-then-200).
- Token / tenant / consent — expired or wrong-tenant credential → 401.
DeploymentNotFound— a well-formed deployment name that does not exist in the project → 404.- api-version skew and regional outages.
Treat a green preflight as "config is shaped correctly", never as "M1 will work".