Experimental reference sample

A real coding agent inside a Foundry hosted container.

This repository demonstrates a bring-your-own Azure AI Foundry hosted agent built with the OpenAI Agents SDK for Python. The container exposes Foundry's responses:1.0.0 contract, runs a model-and-tools loop, and adds bounded file, terminal, browser, memory, retrieval, safety, skill, and telemetry integrations.

community sample Python 3.12 OpenAI Agents SDK keyless Entra auth linux/amd64 no IaC
Not a Microsoft product No SLA, production support, or reference-architecture status.
Existing resources only The repository configures and deploys; it does not provision Azure resources.
Optional means optional Memory, retrieval, Content Safety, Toolbox, and telemetry are feature-gated.
8
canonical skills, loaded as one exact set
12
maximum local function tools before Toolbox tools
60
configured maximum Runner turns
2
independent acceptance applications and sites
Architecture

Foundry owns the front door. This repository owns the agent loop.

A caller targets a versioned hosted-agent endpoint. Foundry routes the request to ResponsesAgentServerHost in the custom container, which streams the turn through the OpenAI Agents SDK and a keyless Azure OpenAI client.

ARCHITECTURE.md + server_responses.py
Caller Foundry or OpenAI-compatible client
Foundry hosted endpoint versioned agent and response history
BYO container :8088 ResponsesAgentServerHost
server_responses.py
Agents SDK Runner instructions + tools + guardrails
Azure OpenAI deployment AsyncAzureOpenAI + Entra token
Local capability lane File, patch, Python, shell, and browser tools execute in the session context.
Optional Foundry lane Memory, web search, knowledge retrieval, Toolbox, and Content Safety.
Telemetry lane Agents SDK spans flow through OpenTelemetry to deployer-controlled App Insights.
repository-owned runtime platform or existing Azure resource
Protocol invariant. The platform contract is not raw FastAPI: the sample preserves ResponsesAgentServerHost, port 8088, and responses:1.0.0.
Runtime

One turn, seven deliberate stages.

The orchestration lives in src/agent/core.py. Optional dependencies degrade to a smaller tool surface; safety tripwires return a refusal and blocked content is not persisted to memory.

src/agent/core.py
1

Accept and scope the request

The host reads input text and prefers the platform caller key for per-user memory scope.

2

Search memory

When enabled, up to five relevant snippets are read and appended to the agent instructions.

3

Connect Toolbox and load skills

The immutable MCP endpoint is opened for the turn. The exact eight-skill set is read as resources and injected all-or-none.

4

Build the Agent

Instructions, optional context, the configured model, local tools, MCP servers, and enabled guardrails are assembled.

5

Run and stream

Runner.run_streamed(..., max_turns=60) drives model decisions and tool calls, yielding text deltas as they arrive.

6

Handle safety outcomes

SDK tripwires and model content-filter responses become explicit refusals instead of partial success.

7

Queue memory update and clean up

Successful exchanges start a non-blocking memory extraction operation; Toolbox connections close in finally.

Tools

A coding toolchain, not a chat-only demo.

The SDK derives tool schemas from Python functions. Configuration flags choose the active local surface, and an optional Toolbox adds centrally managed MCP tools without replacing local tools.

tools.py + fs_tools.py + shell_tools.py
CapabilityToolsBoundaryAvailability
Deterministic demos get_current_utc_time, add_numbers In-process Python core
Grounded retrieval web_search, knowledge_base_search Azure OpenAI Responses and Foundry IQ / AI Search feature-gated
Workspace files write_file, read_file, list_files, apply_patch Paths confined beneath AGENT_WORKSPACE enabled by default
Short execution run_python Fresh subprocess, 10-second timeout enabled by default
Real terminal run_shell Fresh process group, timeout, audit, redaction, deny-lists Linux container
Rendered verification browser_open, browser_open_local Fresh Chromium context with strict network policy Linux container
PATH SAFETY

Workspace confinement

Resolved file paths must remain under the configured workspace; patch paths reject absolute paths and traversal.

PROCESS SAFETY

Fresh subprocesses

Shell calls get independent process groups, bounded timeouts, truncated output, and per-session file-backed state.

BROWSER SAFETY

Verification, not general browsing

Remote targets must be public HTTPS; local artifacts use a tool-owned loopback server and a symlink-free directory.

Memory

Search before the turn. Extract after success.

Foundry memory is optional and store names are configuration, not architecture. The public sample defaults to agent-memory-store, but deployers supply their own existing resource and retention policy.

src/agent/memory.py
BEFORE

Search

Query the configured store for up to MEMORY_MAX_RESULTS relevant items and inject only returned snippets.

DURING

Use

Memory context is appended to instructions; it does not become a new tool or bypass safety controls.

AFTER

Update

A successful user/assistant exchange starts server-side extraction without waiting for the long-running operation.

Scope order: explicit platform hint, then MEMORY_SCOPE, then caller token {oid}_{tid}, then default-user. The last fallback is useful for demos but should not be treated as multi-user isolation.
Safety

Defense in depth, with the optional layers labeled.

The old explainer implied every layer was always active. In this sample, custom Content Safety guardrails are controlled by GUARDRAILS_ENABLED; the model deployment's platform content filter remains a separate control.

guardrails.py + SECURITY.md

Agent instructions and tool boundaries

core

Refusal guidance, workspace confinement, network restrictions, token redaction, command deny-lists, and bounded cloud identity reduce the reachable blast radius.

Agents SDK input and output guardrails

optional

Azure AI Content Safety Prompt Shields inspect input, and text moderation checks input and output. Positive detections fail closed; service errors fail open and are logged.

Azure OpenAI platform content filter

platform

A model content_filter response is converted into a clean refusal. This is independent of the app-level Content Safety feature flag.

Residual risk remains. Deny-lists are not a sandbox, packages and pages are supply-chain inputs, memory can preserve bad instructions, and telemetry or session files can contain sensitive content. The repository is for synthetic data in non-production environments.
Session runtime

A VM-isolated service contract, with defense-in-depth runtime design.

Foundry documents a VM-isolated sandbox per session. The repository's probes also observed shared host and parent-process identity while confirming isolated filesystem, environment, and /proc views. The implementation therefore keeps no mutable cross-session state in Python globals.

shell_tools.py + session_probe.py
OBSERVED

Contract and observation stay distinct

The service contract is per-session VM isolation. Concurrent probes still avoid assuming process separation: they reported the same host and parent process, but could not read each other's workspace, environment, or credential files.

DESIGN RESPONSE

State lives in session files

Every shell or browser action starts a fresh subprocess. Persistent working directory and audit state are stored beneath the session home.

FILES API

One pinned workspace

Agent file tools and Foundry session file operations address the pinned session workspace, enabling cross-turn artifact workflows.

RESPONSIBILITY

Platform and deployer boundary

The service owns isolation mechanics. The deployer still owns session retention, identity scope, data policy, and deletion.

Toolbox and skills

One immutable MCP endpoint, exactly eight skills.

coding-toolbox is additive to local function tools. A created Toolbox version can contain the eight versioned skills and, when configured, a project connection such as Web IQ.

toolbox.py + scripts/skill_manifest.py
TOOLS

MCP tools stay model-callable

The Agents SDK connects to the Toolbox through MCPServerStreamableHttp using a Foundry-scoped Entra token.

SKILLS

MCP resources become instructions

The runtime reads each skill://.../SKILL.md, removes frontmatter, sorts the set, enforces a 16,000-character budget, then injects all eight or none.

  • backend-dev
  • cloud-auth
  • code-review
  • frontend-design
  • frontend-dev
  • systematic-debugging
  • web-research-citation
  • webapp-testing
Supply-chain controls. Skill names are code-owned, local files are hashed, manifest versions are validated, duplicate or partial sets are rejected, and the configured Toolbox URL must name an immutable version rather than latest.
Observability

Agent, tool, token, and latency signals with correct identity.

When an Application Insights connection string is supplied, the Foundry host and OpenAI Agents instrumentation export OpenTelemetry data. The sample corrects per-agent attribution at span creation time and includes streaming token usage.

server_responses.py + Dockerfile
IDENTITY

Canonical agent ID

The live semantic processor is configured with the Foundry front-door identity before subsequent spans are created.

USAGE

Streaming token counts

ModelSettings(include_usage=True) makes usage available to the instrumentor for token metrics.

SAMPLING

Full capture for the sample

OTEL_TRACES_SAMPLER=always_on avoids the distro's default rate limit while increasing telemetry volume and cost.

Telemetry is data. Depending on SDK settings, spans can include prompts, outputs, file names, command metadata, and URLs. The deployer owns sampling, access, retention, deletion, and cost.
Quality

Local gates first; cloud and acceptance gates by intent.

Unit and publication checks are cloud-free. Separate scripts cover deployed smoke, evaluation, red teaming, runtime probes, and deterministic end-to-end acceptance for Space Invaders and Todo applications.

tests/ + scripts/
LOCAL

Repository gates

Pytest, Python compilation, Node syntax, dry-run acceptance, and publication-safe source scanning.

DEPLOYED

Smoke and evaluation

Targeted invocation, traffic generation, Monitor queries, quality evaluation, and AI red-team scripts use explicit cloud configuration.

END TO END

Independent acceptance

Harnesses download artifacts, run final Node tests independently, and verify deterministic browser contracts. Live-URL-only mode is explicitly partial.

python -m pytest -p no:cacheprovider tests -q
python -m compileall -q src scripts server_responses.py
node --check src/agent/browser_probe.js
python scripts/build_space_invaders_demo.py --dry-run
python scripts/build_todo_demo.py --dry-run
Deployment

Parameterize existing resources; never invent infrastructure.

The deployment script builds a linux/amd64 image in an existing registry, registers a hosted-agent version, and applies tightly bounded roles. azure.yaml is an Agent Optimizer and deployment-discovery overlay, not Bicep, Terraform, or one-click IaC.

deploy_foundry.py + docs/deployment.md
1

Supply existing-resource identifiers

Foundry project, model deployment, registry, dedicated deployment resource group, and two distinct Static Web Apps are required; optional integrations need their own existing resources.

2

Build the target architecture

ACR builds the image for linux/amd64. The runtime contains Python 3.12, Node 20, Azure CLI, azd, GitHub CLI, SWA CLI, and Chromium tooling.

3

Register a hosted-agent version

python scripts/deploy_foundry.py --tag <image-tag> validates parameters and creates the hosted version using the preview SDK path.

4

Apply bounded roles

Model-use roles are limited to AI_ACCOUNT_RESOURCE_ID; Contributor is limited to DEPLOY_RESOURCE_GROUP_ARM_ID. Subscription-wide Contributor is rejected.

5

Persist state only after success

The script fails on missing principals or role-assignment errors and writes local generated deployment state only after full RBAC success.

Code map

Follow the runtime from the outside in.

These files are the shortest path from platform contract to behavior. Generated state stays outside source control under ignored directories.

AGENT.md
PathResponsibilityRead when
server_responses.pyFoundry responses host, streaming handler, telemetry identityTracing a request from the platform
src/agent/core.pyAgent construction and turn orchestrationUnderstanding the model/tool loop
src/agent/config.pyEnvironment contract, flags, defaults, optimizer hookChanging behavior safely
src/agent/azure_client.pyKeyless Azure OpenAI model and Responses clientsReviewing auth or model wiring
src/agent/tools.pyDemo, web, knowledge, and tool assemblySeeing the active tool catalog
src/agent/fs_tools.pyWorkspace-confined file, patch, and Python toolsReviewing artifact operations
src/agent/shell_tools.pyReal terminal, auth gates, browser wrapper, session-safe stateReviewing execution boundaries
src/agent/browser_probe.jsChromium network and rendered-output policyReviewing browser trust controls
src/agent/memory.pyScope resolution, search-before, update-afterReviewing personalization
src/agent/guardrails.pyOptional Prompt Shields and text moderation hooksReviewing Content Safety behavior
src/agent/toolbox.pyImmutable MCP connection and exact skill injectionReviewing centrally managed capabilities
scripts/Setup, deploy, verify, evaluate, probe, and acceptance entry pointsOperating the sample
One-minute summary. This is an experimental Foundry bring-your-own hosted coding agent. Foundry routes the Responses protocol into a Python container, where the OpenAI Agents SDK runs a keyless Azure OpenAI model with bounded file, shell, and browser tools. Memory, retrieval, Content Safety, Toolbox, and telemetry are optional. The runtime uses per-session files rather than process globals, loads exactly eight versioned skills, and deploys only to pre-existing resources with narrowly scoped identities.