Research-spiken som åpner fase 4. Fire spørsmål, besvart med kjørte kommandoer og siterte Learn-kilder via et agent-team på fire spor. Tre premisser i planen viste seg gale: 1. «azd-utvidelsen heter enten microsoft.foundry eller azure.ai.agents — én er utdatert». Begge er gjeldende. Målt mot azds offisielle register: den ene er en meta-pakke uten egne kommandoer, den andre eier `azd ai agent`. Det som faktisk henger etter i doc-en er azd-minsteversjonen (1.25.2 vs >=1.27.1). 2. «Foundry injiserer FOUNDRY_PROJECT_ENDPOINT, AZURE_AI_MODEL_DEPLOYMENT_NAME og APPLICATIONINSIGHTS_CONNECTION_STRING». To av tre. Modelldeployment-navnet deklarerer vi selv. Kilden til antakelsen var MAF-hostingsiden, som motsier både plattformdoksettet og Microsofts eget kjørende sample. 3. «docker build og azd ai agent run mot localhost:8088 er testbare UTEN Azure». Halvveis: azd ai agent run krever azd auth login og provisjonerte ressurser, og modellkallene går fortsatt til Foundry. --local sparer deploy, ikke Azure. Kostnadsrelevant. Q4 avgjorde 4c-omfanget: Workflow.as_agent() KJØRER på vårt objekt (målt), men eksponerer bare debatten — validator, forankring, provenance og ledger ligger utenfor grafen. En hosted agent bygget på as_agent() alene ville servert ugatede forslag. Fase 4c er et signaturproblem rundt run_project, ikke et grafproblem. Q2/Q3: direct references resolverer i BÅDE uv og pip, anonymt, uten publisering. Base-image python:3.12-slim-bookworm; 3.14 faller fordi numpy 2.2.6 mangler cp314-hjul — den ferske resolusjonen skjuler det bak en sdist. Verktøykjeden reparert underveis: azd og docker manglet (Docker Desktop-casken var en foreldet 0 B-oppføring). colima valgt framfor Desktop — kjører fra terminalen, og VM-en er linux/amd64 nativt på Intel. IKKE gjort: containeren er ikke bygget. docker build ble avvist av tillatelsesklassifisereren. Uv-resolusjon viser at avhengighetene løser for linux, ikke at koden kjører der — og det er forskjellen fase 4d trenger. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jk8tauXXAojNKC7Tzq7ziF
20 KiB
Fase 4· — research-spike: hostingkontrakten for Foundry Agent Service
Dato: 2026-08-13 · Commit ved måling: f5ec8c8 · Metode: agent-team, fire parallelle
spor, alle Opus/xhigh · Leveranse: svar som kommandoer og siterte kilder, aldri vurderinger.
Denne rapporten åpner fase 4 i den kanoniske planen. Den bygger ingen produksjonskode og rører
ikke shared/. Alt som står her er enten kjørt på denne maskinen eller sitert fra Microsoft Learn
med URL. Det som ikke lot seg verifisere står under Ikke verifisert — ikke i brødteksten.
0. Sammendrag for den som bare leser ett avsnitt
Fire spørsmål ble stilt. Tre er besvart med kommandoer og kilder. Ett — om containeren faktisk bygger — er ikke fullført, fordi byggekommandoen ble blokkert av tillatelsesoppsettet etter at verktøykjeden var på plass.
Spiken felte tre premisser i planen:
| Premiss i planen | Dom |
|---|---|
«azd-utvidelsen heter enten microsoft.foundry eller azure.ai.agents — én er utdatert» |
Feil. Begge er gjeldende; den ene er en meta-pakke over den andre |
«Foundry injiserer FOUNDRY_PROJECT_ENDPOINT, AZURE_AI_MODEL_DEPLOYMENT_NAME og APPLICATIONINSIGHTS_CONNECTION_STRING» |
To av tre. AZURE_AI_MODEL_DEPLOYMENT_NAME injiseres IKKE — den deklarerer vi selv |
«docker build og azd ai agent run mot localhost:8088 er testbare UTEN Azure» |
Feil for azd ai agent run. Den krever azd auth login og provisjonerte ressurser |
Alt materialet er hentet mot det gjeldende hostingbackendet, ikke det gamle preview-et. Se §8 for hvorfor det skillet betyr noe når man leser eldre oppskrifter.
1. Hostingkontrakten
1.1 Runtime-kontrakten er kort og eksplisitt
Kilde: https://learn.microsoft.com/azure/foundry/agents/concepts/hosted-agent-contract
| Krav | Detalj (sitert) |
|---|---|
| Port | «Listen on port 8088 … HTTP/1.1, plain HTTP. The platform terminates TLS.» |
| Helse | «Return 200 OK from GET /readiness.» |
| Protokoll | «Serve at least one of POST /responses or POST /invocations.» |
| Miljø | «Read the variables the platform injects at startup.» |
| Avslutning | «Flush writes and close connections on SIGTERM.» |
Bind-adresse er 0.0.0.0, og porten kan overstyres med PORT. /readiness implementeres ikke av
oss: «The protocol libraries automatically expose a /readiness endpoint for platform health
checks. You don't need to implement this yourself.»
1.2 Filsettet
Learn oppgir intet normativt «required files»-sett. Det som finnes er hva azd ai agent init
skaper, og hva Microsofts egen MAF-sample faktisk inneholder.
Scaffold (https://learn.microsoft.com/azure/foundry/agents/how-to/init-agent-project):
.
|-- azure.yaml # Unified azd project and hosted agent configuration
|-- src/
| \-- <agent-name>/
| |-- Dockerfile # Container build definition
| \-- ... # Agent source code
|-- .azure/ # Environment configuration
\-- infra/ # Optional IaC, created only after you eject infrastructure
Agent-manifest er avviklet — dette er en bruddendring mot enhver eldre oppskrift:
«Agent manifests (
agent.manifest.yaml) and standalone agent definitions (agent.yaml) are deprecated. As of the Foundryazdextensions (azure.ai.agents1.0.0-beta.1), all hosted agent configuration lives in a singleazure.yaml.»
Microsofts referansesample for Python/MAF bærer i src/<agent>/: .azdignore, .dockerignore,
.env.example, Dockerfile, main.py, requirements.txt. Merk: ingen pyproject.toml — den
bruker requirements.txt. Det er relevant for oss, se §3.
Samplets Dockerfile, ordrett (https://raw.githubusercontent.com/microsoft-foundry/foundry-samples/main/samples/python/hosted-agents/agent-framework/responses/01-basic/src/agent-framework-agent-basic-responses/Dockerfile):
FROM python:3.12-slim
WORKDIR /app
COPY . user_agent/
WORKDIR /app/user_agent
RUN if [ -f requirements.txt ]; then pip install -r requirements.txt; else echo "No requirements.txt found"; fi
EXPOSE 8088
CMD ["python", "main.py"]
At Microsofts egen sample lander på python:3.12-slim er verdt å merke seg mot §4: det er samme
base-image vår egen resolusjon peker på, av uavhengige grunner.
1.3 azure.yaml — skjema og det uavklarte
$schema-linja:
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
host:-verdien for en hosted agent er azure.ai.agent («Must be azure.ai.agent»).
Sentrale felter (https://learn.microsoft.com/azure/foundry/agents/concepts/azure-yaml-reference):
kind: hosted, project (sti til kildekatalog), language, uses, protocols, env,
container, startupCommand, codeConfiguration, image.
Learn og Microsofts eget sample er uenige på fire punkter. Dette er ikke en detalj — det er
forskjellen mellom en azure.yaml som virker og en som avvises:
| Punkt | Learn-referansen | Samplet (det azd ai agent init -m faktisk adopterer) |
|---|---|---|
| Byggespråk | language: docker |
language: python + codeConfiguration |
| Miljøvariabler | env: som map |
environmentVariables: som liste av {name, value} |
| Entrypoint | entryPoint: main.py |
også entryPoint: ["python", "main.py"] i en annen artikkel |
| Protokollversjon | 2.0.0 i azure.yaml-eksempler |
1.0.0 i SDK/REST-eksempler |
Anbefaling: bruk samplet som fasit, fordi det er fila azd ai agent init -m kopierer. Men
protokollversjonen må avklares før vi skriver vår egen — se Ikke verifisert pkt. 4.
1.4 Container-krav
linux/amd64 er bekreftet påkrevd
(https://learn.microsoft.com/azure/foundry/agents/how-to/deploy-hosted-agent):
«The hosting platform requires x86_64 (linux/amd64) container images. If you build on Apple Silicon or other ARM-based machines, use
docker build --platform linux/amd64 .to avoid producing an incompatible ARM image.»
Planens observasjon står: på operatørens Intel-Mac er dette maskinens egen arkitektur, og vi har
målt at colima-VM-en rapporterer linux/x86_64 (§6). Ingen emulering.
CPU/minne motsier seg selv i Learn. Referansesiden sier fritt intervall («cpu from "0.25"
up to "4.0", and memory from 0.5Gi up to 8.0Gi»), mens konseptsiden gir tre faste tiers
(0.5 vCPU/1 GiB, 1/2, 2/4). Feilmeldingen avgjør tolkningen: 400 bad_request med «CPU and Memory
must be specified as a valid resource tier». Bruk tier-tabellen.
Dokumenterte tidsgrenser: idle-timeout 15 minutter, sesjonslevetid maks 30 dager, diskbudsjett opptil 20 GiB ved ≥1 vCPU hvorav ~20 % er systemreservert.
1.5 Headere under protokoll 2.0.0
Plattformen injiserer x-agent-user-id (per bruker) og x-agent-foundry-call-id (per request,
skal videresendes uendret på utgående Foundry-kall). Gatewayen dropper alt annet enn en
allowlist — Authorization, Host, Cookie og x-forwarded-* kommer aldri fram; egne headere
må prefikses x-client-. Begge de injiserte er «not guaranteed when you run locally», så koden må
tåle at de mangler.
2. azd-utvidelsens navn — planens premiss var feil
Planen antok at ett av navnene var utdatert. Målt mot azds offisielle register
(https://aka.ms/azd/extensions/registry, som redirecter til
raw.githubusercontent.com/Azure/azure-dev/refs/heads/main/cli/azd/extensions/registry.json,
451 555 bytes — byte-identisk med repo-URL-en, altså samme fil): begge ID-ene finnes samtidig, og
de gjør forskjellige ting.
| ID | Rolle | Siste versjon | Kommandogruppe |
|---|---|---|---|
microsoft.foundry |
Meta-pakke uten egne kommandoer og uten binærartefakter | 1.0.0-beta.2 | — |
azure.ai.agents |
Den faktiske utvidelsen; eier service-target-provideren «Deploys agents to the Foundry Agent Service» |
1.0.0-beta.9 (utgitt 2026-08-06) | azd ai agent |
Learn sier det selv rett ut (https://learn.microsoft.com/azure/foundry/agents/how-to/install-cli-foundry-extensions):
«The
microsoft.foundrypackage is a thin meta-package that doesn't contribute its own commands. Installing it pulls in every individual extension, which is the recommended starting point.»
Det som faktisk henger etter i doc-en er ikke ID-navnet, men versjonskravet. Flere Learn-sider
sier azd 1.25.2 eller senere; registeret krever >=1.27.1 for begge utvidelsene. Vi installerte
1.31.0 (§6), så vi ligger over.
darwin/amd64-artefaktet finnes for azure.ai.agents 1.0.0-beta.9 (sha256
f0750469a17c7370534db21d5542eb9241f2ffc1093361bf373b5ef71ff43c1f) — altså støttet på denne
maskinen.
Kommandoene, ordrett fra Learn:
azd ext install microsoft.foundry # meta-pakke, anbefalt start
azd ext install azure.ai.agents # bare agent-flaten (drar inn azure.ai.inspector)
azd ext list
azd ai agent version
azd extension og azd ext er samme kommando — verifisert i azds kildekode
(cli/azd/cmd/extension.go, linje 50: Aliases: []string{"ext"},), ikke bare i doc.
3. Avhengighetsformen i container — direct references, ingen publisering
Spørsmålet var om [tool.uv.sources]-git-pinnene overlever inn i en container, siden de ikke
finnes i wheel-metadata. Svaret er ja, i begge pakkeverktøy, uten publisering og uten auth.
| Måling | Kommando | Exit |
|---|---|---|
| uv resolverer direct references | uv pip compile req-direct-min.txt --python-version 3.12 --python-platform linux |
0 |
| pip gjør det samme | pip install --dry-run --report … -r req-direct-min.txt |
0 |
| Anonym git-lesing virker | env -u GIT_ASKPASS GIT_TERMINAL_PROMPT=0 git ls-remote https://git.fromaitochitta.com/open/llm-ingestion-okf.git v0.3.2 |
0 |
At pip klarer det er poenget: en Dockerfile er ikke bundet til uv. uv oppgraderer dessuten
tag → commit-SHA i outputen, så formen er selv-pinnende.
Alle tre pakkenavn er ledige på PyPI (HTTP 404 på /simple/), så publisering ville vært mulig —
men er unødvendig, og ville lagt en release-forpliktelse på to sikkerhetskomponenter som i dag er
tag-pinnet med vilje.
Én felle er målt. Default-eksporten fra lockfila produserer en fil pip avviser:
ERROR: Can't verify hashes for these requirements because we don't have a way
to hash version control repositories
pips hash-modus er alt-eller-ingenting, og en git-URL kan ikke hashes. Den målte veien rundt, som beholder hash-verifisering for de 64 PyPI-pakkene:
uv export --frozen --format requirements.txt --no-dev --no-emit-project -o requirements.txt
grep -v '^llm-ingestion' requirements.txt > requirements-pypi.txt # hashet
grep '^llm-ingestion' requirements.txt > requirements-git.txt # commit-pinnet
Base-imaget må da ha git installert. -slim-variantene har det ikke.
Bygg fra eksporten, ikke fra pyproject.toml. Fersk resolusjon velger
agent-framework-core==1.13.0 og mcp==2.0.0, mens uv.lock pinner 1.9.0 / 1.28.0. Begge er
lovlige innenfor spennet, men en container bygget fra pyproject.toml ville kjørt andre versjoner
enn utviklermaskinen — og MAF-pinnen <2 er tosidig nettopp fordi privat-API-premissene må
re-verifiseres ved bump.
4. Base-image — 3.10 til 3.13, aldri 3.14
Resolusjonsmatrise mot x86_64-unknown-linux-gnu, hele [project.dependencies]:
| Python | Fersk resolusjon | Med wheel-krav på numpy | numpy | agent-framework-core |
|---|---|---|---|---|
| 3.10 | ✅ | ✅ | 2.2.6 | 1.13.0 |
| 3.11 | ✅ | ✅ | 2.2.6 | 1.13.0 |
| 3.12 | ✅ | ✅ | 2.2.6 | 1.13.0 |
| 3.13 | ✅ | ✅ | 2.2.6 | 1.13.0 |
| 3.14 | ✅ | ❌ | kun via sdist | 1.13.0 |
Den ferske resolusjonen alene er villedende, og det er hele funnet. Alle fem «resolverer»,
fordi numpy 2.2.6 har en sdist. Men numpy 2.2.6 har manylinux-x86_64-hjul kun for cp310–cp313 —
ingen cp314. På 3.14 ville containeren kompilert numpy fra kilde, altså dratt inn en full
byggekjede og en byggetid ingen har budsjettert. --only-binary numpy gjør det til en hard feil i
stedet for en skjult kostnad:
× No solution found when resolving dependencies:
╰─▶ … numpy>=2.0.0,<=2.2.6 has no usable wheels …
your requirements are unsatisfiable.
Dette er numpy<2.3-taket i pyproject.toml som binder. Taket står der av to andre grunner
(3.10-støtte og mypys PEP 695-parsing), og 3.14-utfallet er en bivirkning av dem.
Valg: python:3.12-slim-bookworm — repoet pinner .python-version = 3.12, det ligger midt i
det lovlige båndet, og Microsofts egen MAF-sample bruker python:3.12-slim (§1.2).
5. Workflow.as_agent() — virker, men eksponerer feil ting
Målt mot det installerte (agent-framework-core 1.9.0), ikke mot dokumentasjonen:
fresh_workflow(...)returnerer en ekteagent_framework._workflows._workflow.Workflow.as_agent()konstruerer enWorkflowAgent(BaseAgent)som tilfredsstillerSupportsAgentRunawait ag.run(...)kjører, og returnerer proposer- og checker-meldingene
Learn bekrefter at dette er den offisielle mekanismen (https://learn.microsoft.com/agent-framework/hosting/foundry-hosted-agent):
«you can expose an
Agent, including a workflow wrapped withWorkflow.as_agent(), through the Foundry Responses or Invocations protocol with minimal code.»
Og likevel er svaret «wrapper», ikke «direkte». fresh_workflow er steg 3 av åtte i
run_project (src/portfolio_optimiser/run.py:554). Validatoren, kostbaseline-forankringen,
provenance-stempelet, checker-gaten, ledgeren og læringssløyfa ligger alle utenfor
Workflow-grafen. En hosted agent bygget på as_agent() alene ville servert ugatede agent-forslag
— altså brutt repoets egen invariant om at den deterministiske validatoren er obligatorisk og
blokkerende.
Signaturgapet er konkret: hosting-flaten tar str/Message inn og gir AgentResponse ut;
run_project tar project_id pluss to påkrevde keyword-argumenter uten default (docs_dir,
verdict_input) og gir en frozen RunResult-dataclass. Fase 4c er derfor et signaturproblem,
ikke et grafproblem.
To detaljer med konsekvens:
AgentResponse.textkonkatenerer proposer + checker + orkestratorens sluttnotis til én streng. Dagens kode skiller dem påauthor_name(run.py:330). En hosted flate som returnerer.textville slått de to falsifisererne sammen til én tekst.fresh_workflower en factory nettopp fordi et gjenbrukt workflow akkumulerer tråd på tvers av kall. En hostet agent er per definisjon ett langlevd objekt som betjener mange forespørsler. Dette er den største uavklarte risikoen spiken fant, og må måles før 4c-designet låses.
Dette bekrefter planens 4c-valg: Invocations, ikke Responses. run_project er ett kall med
strukturert inn og strukturert ut, ikke en samtale. Learn plasserer Invocations på «custom
payloads, non-conversational processing».
6. Miljøet — hva som ble reparert på maskinen
Verktøykjeden manglet ved oppstart. Målt før:
| Verktøy | Før | Etter |
|---|---|---|
az |
2.84.0 (var installert) | uendret |
azd |
not found | 1.31.0 (formelen heter azure-dev) |
docker |
not found | klient 29.7.2 / server 29.5.2 |
| daemon | ingen | colima 0.10.3 → linux/x86_64, 6 CPU, 10 GB |
Docker Desktop-casken var registrert som installert (4.50.0) mens /Applications/Docker.app ikke
fantes og Caskroom-katalogen var 0 B — en foreldet brew-oppføring. colima ble valgt framfor
Docker Desktop fordi Desktop krever GUI-oppstart og admin-passord, mens colima kjører fra
terminalen. På en Intel-Mac er colima-VM-en linux/amd64 nativt.
Én etterlatenskap måtte ryddes: ~/.docker/config.json pekte på credsStore: "desktop", en
credential-helper som ikke lenger fantes, og som feilet ethvert image-oppslag. auths var tom, så
linja ble fjernet (backup: ~/.docker/config.json.bak-20260813-213134).
7. Det som IKKE ble målt
Containeren er ikke bygget. Byggekonteksten er klar (git archive HEAD, 311 sporede filer,
3,7 MB — altså det en fremmed faktisk laster ned), daemonen kjører, og en måle-Dockerfile er
skrevet. docker build ble avvist av tillatelsesklassifisereren i auto-modus, to ganger.
Det gjenstående gapet er presist: uv-resolusjon viser at avhengighetene løser for linux, ikke at koden importerer og kjører der. For fase 4d er det forskjellen mellom en Dockerfile vi kan shippe og en påstand vi ikke kan stå inne for.
Ikke verifisert
- Lokal kjøring uten Azure. Planen og STATE påsto at
azd ai agent runmotlocalhost:8088er testbart uten Azure. Learn sier det motsatte: kommandoen kreverazd auth login, henter miljøvariabler fra et azd-miljø, og «The local agent still calls cloud-hosted models».--localsparer deploy, ikke Azure. Dette er kostnadsrelevant og bør inn i planen. AZURE_AI_MODEL_DEPLOYMENT_NAMEinjiseres ikke. Bekreftet injisert:FOUNDRY_PROJECT_ENDPOINT,FOUNDRY_PROJECT_ARM_ID,FOUNDRY_AGENT_NAME,FOUNDRY_AGENT_VERSION,FOUNDRY_AGENT_SESSION_ID,FOUNDRY_AGENT_ID,APPLICATIONINSIGHTS_CONNECTION_STRING,FOUNDRY_HOSTING_ENVIRONMENT,HOME,PORT. Modelldeployment-navnet deklarerer vi selv.FOUNDRY_PROJECT_ENDPOINTskal ikke redeklareres iazure.yaml— det risikerer å skygge plattformens verdi. Kilden til vår antakelse var MAF-hostingsiden, som motsier plattformdoksettet og Microsofts eget sample.- Rollen for deploy er
Foundry Project Managerpå prosjekt-scope, ikkeFoundry Usersom 1b-forberedelsen bruker. De to er ulike oppgaver (kjøre modellkall vs. deploye en agent) og bør ikke blandes. - Protokollversjon i
azure.yaml:1.0.0eller2.0.0. Learn viser begge i samme doksett. Container-protokoll 2.0.0 er separat fra protokoll-versjonsfeltet, og 1.0.0 er deprekert med blokkering etter fristen. Må avklares mot JSON-skjemaet før vi skriver fila. env:-map vsenvironmentVariables:-liste, oglanguage: dockervslanguage: python— Learn og samplet er uenige, og skjemafila er ikke lest.- Påkrevd vs valgfritt felt-for-felt for
azure.ai.agent-tjenesten. Learns tabell har ingen Required-kolonne; autoriteten erschemas/v1.0/azure.yaml.json, som ikke er lest. - Ikke-root-krav finnes ikke dokumentert, og Microsofts sample kjører som root uten
USER. Fravær av dokumentasjon er ikke en garanti. agent-framework-foundry-hostinger ikke installert, og import-stien er omstridt: Learn brukeragent_framework_foundry_hosting, et MAF-sample brukeragent_framework.foundry. Vår installerte 1.8.2 eksporterer ingen av host-server-klassene. Siste PyPI-versjon er1.0.0b260730— ingen stabil release finnes.- Kompatibilitet mellom hosting-pakka og
agent-framework-core1.9.0 er ikke testet. - Foundry Agent Service i Norway East — regionslista inkluderer den, men modell- og kvotedekning per region er ikke sjekket.
8. Hvorfor eldre oppskrifter ikke kan brukes
Foundry har byttet hostingbackend. Det gamle public-preview-backendet er under avvikling (https://learn.microsoft.com/azure/foundry/agents/how-to/migrate-hosted-agent-preview):
«The initial public preview hosting backend is retiring. … Existing agent deployments on the old backend aren't migrated automatically and are supported only until August 20, 2026.»
Dette er ingen frist for oss — vi har aldri deployet, og har derfor ingenting å migrere. Det er
en dateringsregel: en blogg, oppskrift eller Learn-side skrevet mot det gamle backendet beskriver
en flate som ikke lenger er den vi bygger mot, uansett hvor godt den er skrevet. Konkret er tre
ting fra den epoken allerede ugyldige: agent.manifest.yaml/agent.yaml (§1.2),
Foundry-Features: HostedAgents=V1Preview-headeren, og protokollversjonsformatet "v1".
Alt materialet i denne rapporten er hentet mot det gjeldende backendet. Det er også grunnen til at rapporten siterer URL og dato på hver påstand i stedet for å oppsummere: neste økt skal kunne se hva som var sant da, ikke bare hva jeg konkluderte.