Sample #9 in the Embr × Foundry POC fleet. An Embr-hosted chat UI fronting Foundry's native Connected Agents primitive — where one agent declares another agent as a tool and Foundry handles the routing server-side.
The point of this sample is to make the ownership boundary concrete: Foundry owns the multi-agent orchestration; Embr just hosts the chat UI.
Three Foundry agents, created on first boot and reused by name:
| Agent | Role | Tools |
|---|---|---|
embr-connected-research-agent |
Topic research specialist | web_search (canned facts) |
embr-connected-math-agent |
Arithmetic specialist | calculate (AST-based safe eval) |
embr-connected-coordinator |
Delegates to the two specialists | 0 function tools + 2 ConnectedAgentTools |
When the user chats, Embr only ever talks to the coordinator. The
coordinator's requires_action loop never sees the specialists' tool calls —
Foundry runs the sub-agents internally and only returns the final composed
answer. The UI surfaces the otherwise-invisible Foundry-internal traffic via
runs.steps.list(...), where each tool_calls step of type=connected_agent
exposes which sub-agent ran and the message that was sent.
| Var | Purpose |
|---|---|
FOUNDRY_PROJECT_ENDPOINT |
e.g. https://{name}.services.ai.azure.com/api/projects/{project} |
FOUNDRY_MODEL_DEPLOYMENT |
Model deployment name (default: gpt-5.4-mini-1) |
AZURE_TENANT_ID |
Service principal tenant |
AZURE_CLIENT_ID |
Service principal client id |
AZURE_CLIENT_SECRET |
Service principal client secret |
Foundry Agents requires AAD (RBAC). Embr has no managed identity exposed to
app code yet, so the SP secret is bundled as env vars. Locally you can omit
the SP vars and rely on az login (DefaultAzureCredential fallback).
azure-ai-agents>=1.1is required.ConnectedAgentToolshipped in the1.1.0release of the Foundry Agents Python SDK. Older versions (1.0.x) will fail withImportError: cannot import name 'ConnectedAgentTool'.
git clone https://github.com/embr-devs/embr-foundry-connected-agents-sample
cd embr-foundry-connected-agents-sample
python3.12 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export FOUNDRY_PROJECT_ENDPOINT="https://your-foundry.services.ai.azure.com/api/projects/your-project"
export FOUNDRY_MODEL_DEPLOYMENT="gpt-5.4-mini-1"
export AZURE_TENANT_ID="…" AZURE_CLIENT_ID="…" AZURE_CLIENT_SECRET="…"
uvicorn app.main:app --reloadOpen http://localhost:8000 and try:
What is 17 * 23 and tell me about Foundry?
The coordinator should delegate the math half to math_agent and the research
half to research_agent, then combine the answers. Expand the trace panel
under the assistant reply to see the connected-agent calls.
embr quickstart deploy embr-devs/embr-foundry-connected-agents-sample -i 120233234
embr variables set FOUNDRY_PROJECT_ENDPOINT="…"
embr variables set FOUNDRY_MODEL_DEPLOYMENT="gpt-5.4-mini-1"
embr variables set AZURE_TENANT_ID="…"
embr variables set AZURE_CLIENT_ID="…"
embr variables set AZURE_CLIENT_SECRET="…"| Aspect | embr-foundry-multi-agent-sample |
embr-foundry-connected-agents-sample (this) |
|---|---|---|
| Orchestrator | Python loop in the Embr app | Foundry coordinator agent |
| Routing logic | Lives in your code | Lives in Foundry's prompt + SDK |
| Inter-agent traffic | Visible in Embr (you wrote it) | Invisible at runtime; surfaced via runs.steps.list |
| Sub-agent failure handling | Your try/except |
Foundry's run state machine |
| Tools per sub-agent | Run on Embr | Run on Embr (specialists still call back) |
| When to choose | You need custom routing, retries, fan-out, evaluators between hops | Foundry's default delegate-and-combine pattern is enough |
- Boundary is right-sized. When Foundry owns orchestration, Embr's role collapses to "host the entry point + ferry env vars" — exactly what the Microsoft strategy docs argue. Nothing in Embr knows or cares that there are three agents instead of one.
- Still no managed identity.
ConnectedAgentToolis a Foundry-create-time configuration, but creating the agents still hits the AAD wall — we bundle SP credentials as env vars (same finding as every other Foundry sample). - No
foundry-agent:dep type inembr.yaml. The coordinator's ConnectedAgentTools reference agent ids, but those ids only exist after the first boot creates the specialists. There's no way to declare "this app expects three Foundry agents named X/Y/Z" in the manifest — it's all ad-hoc env vars and runtimelist_agents()calls. - SDK version pin matters.
ConnectedAgentToolshipped inazure-ai-agents 1.1.0. The1.0.xline that other Foundry samples pin doesn't have it. Until Embr can pin transitive Python deps centrally, every sample'srequirements.txtis a copy-paste hazard.