Version: 1.0 Last Updated: 2026-05-11 Status: Historical - superseded by ADR-005 direct-model policy and #990 Wave 4c cleanup
This document explains the PR #802 portal-agent runtime decision for audit history. The active runtime is now
DirectModelInvoker(agent_framework.Agentover a pluggableChatClient) per ADR-005.FoundryAgentInvoker,/foundry/agents/ensure, and the V2 provisioning code path were removed from framework runtime code in #990 Wave 4c.
Holiday Peak Hub uses Microsoft Agent Framework (MAF) as the runtime layer for all AI agent invocations. MAF is wrapped inside holiday-peak-lib rather than consumed directly by the 26 agent services. This document explains why, how, and what trade-offs this creates.
Each of the 26 agent services needs to:
- Invoke AI models via Azure AI Foundry (GPT-5, GPT-5-nano, etc.)
- Forward tool definitions so the model can call MCP tools
- Handle streaming and non-streaming responses
- Integrate with the three-tier memory architecture
- Emit structured telemetry to Azure Monitor
Without a shared abstraction, each service would independently:
- Depend on
agent-frameworkandazure-ai-projectsSDKs - Implement tool registration and forwarding logic
- Handle SDK version migrations separately
- Duplicate error handling, retry, and telemetry code
Wrap MAF behind FoundryAgentInvoker in holiday-peak-lib, making the lib the single consumer of agent-framework.
%%{init: {'theme':'base', 'themeVariables': {
'primaryColor':'#FFB3BA',
'primaryTextColor':'#000',
'primaryBorderColor':'#FF8B94',
'lineColor':'#BAE1FF',
'secondaryColor':'#BAE1FF',
'tertiaryColor':'#FFFFFF'
}}}%%
graph TB
subgraph "26 Agent Services"
S1["ecommerce-catalog-search"]
S2["crm-campaign-intelligence"]
S3["truth-ingestion"]
SN["... (23 more)"]
end
subgraph "holiday-peak-lib"
BA["BaseRetailAgent"]
AB["AgentBuilder"]
FAI["FoundryAgentInvoker"]
MT["ModelTarget"]
GR["Guardrails"]
MEM["MemoryClient"]
MCP["FastAPIMCPServer"]
end
subgraph "Microsoft Agent Framework"
MAF_BA["BaseAgent"]
MAF_FA["FoundryAgent"]
MAF_MSG["Message Protocol"]
end
subgraph "Azure AI Foundry"
PROJ["AIProjectClient"]
AGENT_FAST["Fast Agent (SLM)"]
AGENT_RICH["Rich Agent (LLM)"]
end
S1 & S2 & S3 & SN --> BA
BA -->|extends| MAF_BA
BA --> AB
AB --> FAI
FAI --> MAF_FA
MAF_FA --> PROJ
PROJ --> AGENT_FAST & AGENT_RICH
AB --> GR & MEM & MCP
| Layer | Responsibility | Package |
|---|---|---|
| Agent Services | Domain logic (handle() method), MCP tool definitions, event handlers |
Each app's src/ |
| holiday-peak-lib | Agent base class, builder, memory, guardrails, resilience, telemetry, MAF wrapping | holiday-peak-lib>=0.2.0 |
| Microsoft Agent Framework | Foundry agent runtime, message protocol, tool forwarding middleware | agent-framework>=1.0.1 |
| Azure AI Foundry | Model hosting, agent provisioning, Agents V2 API | azure-ai-projects>=2.0.0b4 |
The core adapter between the lib's ModelTarget interface and MAF's FoundryAgent runtime:
class FoundryAgentInvoker:
"""Wraps MAF FoundryAgent to produce ModelTarget-compatible invocations."""
async def invoke(self, messages, *, tools=None, **kwargs):
# 1. Create FoundryAgent with tools registered
# 2. Send messages through MAF middleware
# 3. Handle tool calls (forwarded by MAF, not dropped)
# 4. Aggregate streaming chunks when invoked via the streaming path
# 5. Return normalized responseCritical fix (PR #802): The legacy FoundryInvoker silently dropped tool definitions because it bypassed MAF's middleware layer. FoundryAgentInvoker routes through FoundryAgent.create(), which properly registers tools with the Foundry runtime.
Extends MAF's BaseAgent with retail-specific behavior:
- SLM-first routing: Every request starts with the fast (SLM) model; complex queries upgrade to the rich (LLM) model based on a configurable
complexity_threshold - Memory injection: Three-tier memory (hot/warm/cold) via
MemoryBuilder - Provider policy:
FoundryProviderPolicyStrategyenforces Foundry-specific message sanitization - Tool delegation: Tools are registered through
AgentBuilderand forwarded to the invocation layer
Fluent builder for agent assembly:
agent = (
AgentBuilder()
.with_agent(CatalogSearchAgent)
.with_foundry_models(slm_config=slm, llm_config=llm, complexity_threshold=0.7)
.with_memory_builder(memory_builder)
.with_mcp(mcp_server)
.with_tools(domain_tools)
.build()
)When migrating from FoundryInvoker to FoundryAgentInvoker (PR #802):
- 1 class changed in
lib/src→ 27 services updated via dependency - 0 application code changes needed in any agent service
- 55 files touched (mostly lockfile regeneration), but zero domain logic edits
Agent services never import from agent_framework directly:
# ✅ Correct — agent services import from lib
from holiday_peak_lib.agents import BaseRetailAgent, AgentBuilder
# ❌ Forbidden — no direct MAF imports in services
from agent_framework import BaseAgent # NEVERThis is enforced by convention and validated in PR reviews.
FoundryTracer (in utils/telemetry.py) wraps OpenTelemetry with Foundry-aware attributes:
- Span names include agent ID and model deployment
- Tool call durations measured per tool
- Memory tier latencies tracked
- All traces flow to Azure Application Insights
Services test their handle() logic with mock ModelTarget invokers — no MAF runtime needed:
async def mock_invoker(messages, **kwargs):
return {"role": "assistant", "content": "mock response"}
agent.slm = ModelTarget(name="mock", model="test", invoker=mock_invoker)This enables 1136 lib tests + 660 app tests to run without Azure credentials in CI.
| Trade-off | Impact | Mitigation |
|---|---|---|
| Coupling to lib | All services depend on holiday-peak-lib |
Versioned releases, backward compatibility policy |
| Indirection | One additional layer between service and MAF | Minimal runtime overhead (<1ms per invocation) |
| Feature lag | New MAF features require lib update first | Single codebase, rapid turnaround (PR #802: 1 day) |
| Monorepo assumption | lib installed from Git path, not PyPI | Standard for reference architectures; could publish to PyPI if needed |
| Resource | URL |
|---|---|
| Microsoft Agent Framework Python API | https://learn.microsoft.com/en-us/python/api/overview/azure/agent-framework |
| Azure AI Foundry documentation | https://learn.microsoft.com/en-us/azure/ai-studio/ |
| Azure AI Foundry Agents quickstart | https://learn.microsoft.com/en-us/azure/ai-studio/how-to/develop/agents |
| AI Project Client SDK | https://learn.microsoft.com/en-us/python/api/azure-ai-projects/ |
| OpenTelemetry for Azure Monitor | https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-enable |