Skip to content

feat(foundry): add generated protocol wrapper target for AgentKit runtimes #6

Description

@sozercan

This was generated by AI during triage.

Summary

Add a Foundry-specific AgentKit deployment path that packages AgentKit-built agents behind Microsoft Foundry Hosted Agent protocols without adding Azure/Foundry dependencies to the generic runtimes/langgraph adapter.

This follow-up should productize the successful live smoke shape from PR #5:

  • AgentKit-authored LangGraph agent image
  • generated Foundry wrapper container
  • /readiness + /invocations and/or /responses on port 8088
  • Foundry agent.yaml container manifest
  • optional Foundry project model-auth mode using the Foundry project endpoint and managed identity

Triage

  • Category: enhancement
  • Suggested state: ready-for-human initially
  • Reason: this spans product/API design, Azure-specific packaging, managed identity behavior, and live Foundry validation. Parts can become ready-for-agent after the target UX and auth mode are confirmed.

Background

PR #5 adds the generic LangGraph runtime:

runtime: langgraph
AgentKit ABI (/agent/agent.yaml)
OpenAI-compatible /v1/chat/completions facade
stdio MCP tools via langchain-mcp-adapters

That runtime intentionally remains cloud-neutral and should not import Azure/Foundry packages.

Live validation showed AgentKit-built LangGraph containers can run behind Foundry protocol wrappers:

  • Invocations wrapper deployed and invoked successfully in Foundry.
  • Responses wrapper deployed and invoked successfully in Foundry.
  • Images were pushed to the project ACR and deployed as hosted agents.
  • Direct user-token calls to the project gpt-4.1-mini deployment worked.

However, a generic hosted container calling the real model with DefaultAzureCredential through the raw OpenAI-compatible account endpoint failed with:

{
  "error": "agent run failed: Error code: 401 - {'error': {'code': 'PermissionDenied', 'message': 'Principal does not have access to API/Operation.'}}"
}

This points to a Foundry managed-identity/project-model-auth design issue, not a bug in the generic LangGraph runtime.

Problem

Foundry Hosted Agents use a different serving and deployment contract from AgentKit's native OpenAI facade:

  • Foundry uses hosted protocols such as /responses and /invocations.
  • Hosted containers conventionally serve on port 8088.
  • Foundry has /readiness expectations.
  • Foundry deployment uses a container agent.yaml/manifest distinct from AgentKit's baked /agent/agent.yaml ABI.
  • Foundry project model auth should follow Foundry project identity/client patterns, not generic apiKeyEnv plumbing.

If we put this directly into runtimes/langgraph, the generic LangGraph runtime becomes Azure-specific and violates the lock-in boundary established by the runtime architecture.

Proposed direction

Add a separate Foundry deployment target/wrapper, not Azure imports in runtimes/langgraph.

Possible external UX options:

agentkit build --target foundry-invocations
agentkit build --target foundry-responses

or an additive config shape such as:

runtime: langgraph
expose:
  foundry:
    protocol: invocations

The exact UX needs maintainer decision.

Internally, the target should generate or package a wrapper image around a normal AgentKit-built image:

AgentKit agent image
  + /agent/agent.yaml
  + Foundry protocol wrapper
  + azure-ai-agentserver-* protocol package
  -> Foundry hosted container on :8088

Scope phase 1: Foundry protocol wrapper target

Implement one protocol first, preferably invocations because it maps naturally to AgentKit's request/response facade.

Requirements

  • Keep runtimes/langgraph free of Azure/Foundry imports.
  • Reuse the existing AgentKit baked ABI at /agent/agent.yaml.
  • Enter the normal AgentKit runtime async lifecycle once at server startup so MCP subprocesses are started and kept warm.
  • Expose Foundry /readiness and /invocations on port 8088.
  • Return a JSON response shaped like:
{
  "response": "...final assistant text...",
  "usage": {
    "prompt_tokens": 0,
    "completion_tokens": 0,
    "total_tokens": 0
  }
}
  • Generate or document a Foundry container manifest (kind: hosted, protocol version, resources, image).
  • Add a deterministic local smoke test using an in-container OpenAI-compatible mock model.
  • Add optional live Foundry smoke instructions.

Suggested package/dependency boundary

Foundry target/wrapper may depend on:

  • azure-ai-agentserver-invocations
  • later azure-ai-agentserver-responses
  • possibly azure-identity / azure-ai-projects only for Foundry model-auth mode

Generic runtime packages must not depend on those.

Scope phase 2: Responses protocol wrapper

After invocations is stable, add /responses support.

MVP semantics

  • Non-streaming only.
  • Final text response only.
  • Map AgentKit RunResult.text into a completed Responses API message item.
  • Do not claim full Responses parity yet.

Explicit non-goals for MVP

  • Streaming deltas.
  • Rich tool-call output item mapping.
  • Files protocol behavior.
  • Human-in-the-loop / interrupt item mapping.
  • Full previous_response_id conversation semantics.
  • A2A.

Scope phase 3: Foundry project model auth

Support an explicit Foundry model-auth mode for hosted deployments.

The Microsoft LangGraph Hosted Agents samples build the model client from the Foundry project endpoint rather than treating Foundry as a plain static baseURL:

from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from langchain_openai import ChatOpenAI

credential = DefaultAzureCredential()
project = AIProjectClient(
    endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    credential=credential,
)
openai_client = project.get_openai_client()
token_provider = get_bearer_token_provider(
    credential,
    "https://ai.azure.com/.default",
)

model = ChatOpenAI(
    model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
    base_url=str(openai_client.base_url),
    api_key=token_provider,
)

AgentKit should expose this as a Foundry-specific model mode, not overload generic apiKeyEnv.

Possible config direction:

model:
  provider: foundry-project
  deployment: gpt-4.1-mini

or target-specific config:

expose:
  foundry:
    modelAuth: project
    deployment: gpt-4.1-mini

Exact schema is TBD.

Live validation evidence from PR #5 follow-up testing

Subscription/resource group used for validation:

subscription: 9d9ce910-f02f-42a0-a07f-7e411ee703ae
resource group: rg-agentkit-foundry-smoke-dev-909dc13a
project: ai-project-agentkit-foundry-smoke-dev
ACR: cryk63bbzzkx6cc.azurecr.io

Successful Foundry invocations validation:

agent: agentkit-langgraph-invocations-live
version: 1
protocol: invocations
image: cryk63bbzzkx6cc.azurecr.io/agentkit-langgraph-foundry-invocations@sha256:40d760a4bdd34a0fc83379bd74f17e8e8ba282c5d47381351d2bc11cc52d7119
result: HTTP/2 200
sentinel: DONE_FOUNDRY_AGENTKIT_123

Successful Foundry responses validation:

agent: agentkit-langgraph-responses-live
version: 1
protocol: responses
image: cryk63bbzzkx6cc.azurecr.io/agentkit-langgraph-foundry-responses@sha256:050032faa14eb3363c50bec506df86c00d3d9b0b0fb4dcd8cd220f7d48e66418
result: HTTP/2 200
response status: completed
sentinel: DONE_FOUNDRY_AGENTKIT_RESPONSES_456

Blocked real-model managed identity validation:

agent: agentkit-langgraph-real-multi-live
version: 2
protocols: responses, invocations
image: cryk63bbzzkx6cc.azurecr.io/agentkit-langgraph-foundry-real-multi@sha256:d73b62426d41708a93f4a903d8ac6340c8c2b6da459b6f00425d2341722e0ef3
result: model call returned 401 PermissionDenied from inside hosted container

Direct user-token model call to the same gpt-4.1-mini deployment succeeded, so the model deployment itself was healthy.

Acceptance criteria

Protocol wrapper MVP

  • There is a documented Foundry invocations target/wrapper path for an AgentKit-built LangGraph image.
  • Generic runtimes/langgraph still has no Azure/Foundry imports or dependencies.
  • Local smoke test builds an AgentKit image, wraps it, runs /readiness, and invokes /invocations successfully.
  • Wrapper enters and exits the AgentKit runtime lifecycle correctly.
  • The wrapper preserves AgentKit RunResult.text and RunResult.usage in the Foundry invocation response.
  • Foundry manifest example is documented.
  • CI or a documented manual command validates the wrapper locally.

Responses follow-up

  • Responses wrapper returns a completed Responses API object with final assistant text.
  • MVP limitations are documented.
  • Local smoke validates /responses.

Foundry project model auth follow-up

  • There is an explicit Foundry project model-auth mode.
  • Model client construction follows the Foundry project client pattern.
  • Live validation can invoke gpt-4.1-mini from inside a hosted container using managed identity.
  • Required RBAC roles/scopes and identity involved are documented.
  • Failure modes for 401 PermissionDenied are documented with troubleshooting steps.

Risks

  • Foundry protocol SDKs are preview and may have version churn.
  • Responses protocol supports richer semantics than AgentKit's current RunResult; MVP must not overpromise.
  • Managed identity auth requires exact identity/scope alignment and may not match generic OpenAI-compatible endpoint assumptions.
  • Arbitrary custom-code support could weaken AgentKit's deterministic ABI story if introduced too early.

Non-goals

  • Do not add Azure-specific imports to runtimes/langgraph.
  • Do not make arbitrary user-authored Python the default support path.
  • Do not implement full Foundry Responses streaming/HITL/files/A2A in the first wrapper PR.
  • Do not delete or mutate shared Foundry resources as part of tests without explicit maintainer approval.

Suggested implementation order

  1. Add generated foundry-invocations wrapper target around existing AgentKit images.
  2. Add local deterministic smoke coverage.
  3. Add docs for ACR push + Foundry deploy.
  4. Add foundry-responses wrapper with final-text-only support.
  5. Add Foundry project model-auth mode once the wrapper boundary is stable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions