Foundry Agent Service POC - Implementation Summary
Status: ✅ POC Complete - Ready for Testing
Last Updated: January 2026
Impact: Zero production impact (all features disabled by default)
What Was Implemented
1. Configuration (backend/core/config.py)
Added Foundry Agent Service configuration with feature flags:
# Azure AI Foundry Agent Service (Optional - POC)
azure_foundry_agent_endpoint: Optional[str] = Field(None, alias="AZURE_FOUNDRY_AGENT_ENDPOINT")
azure_foundry_agent_project: Optional[str] = Field(None, alias="AZURE_FOUNDRY_AGENT_PROJECT")
azure_foundry_agent_key: Optional[str] = Field(None, alias="AZURE_FOUNDRY_AGENT_KEY")
azure_foundry_agent_api_version: str = Field("2024-10-01-preview", alias="AZURE_FOUNDRY_AGENT_API_VERSION")
# Feature flags - all disabled by default
use_foundry_threads: bool = Field(False, alias="USE_FOUNDRY_THREADS")
use_foundry_files: bool = Field(False, alias="USE_FOUNDRY_FILES")
use_foundry_vectors: bool = Field(False, alias="USE_FOUNDRY_VECTORS")
use_foundry_tools: bool = Field(False, alias="USE_FOUNDRY_TOOLS")
Key Points:
- ✅ All flags default to
False(zero production impact) - ✅ Configuration is optional (won’t break if not set)
- ✅ Supports both API key and Managed Identity authentication
2. Foundry Client (backend/agents/foundry_client.py)
Created FoundryAgentServiceClient class with REST API implementation:
Features:
- ✅ Thread management (create, get, list, delete)
- ✅ Message management (add, list)
- ✅ File upload support
- ✅ Project-based isolation support
- ✅ Automatic authentication (API key or Managed Identity)
- ✅ Comprehensive error handling and logging
Key Methods:
# Thread management
await client.create_thread(user_id, agent_id, project_id, metadata)
await client.get_thread(thread_id)
await client.list_threads(user_id, agent_id, project_id, limit)
await client.delete_thread(thread_id)
# Message management
await client.add_message(thread_id, role, content, metadata)
await client.list_messages(thread_id, limit)
# File management
await client.upload_file(thread_id, file_path, purpose)
Singleton Pattern:
get_foundry_client()returnsNoneif flags are disabled- Ensures zero impact when Foundry is not in use
- Lazy initialization (only created when needed)
3. Test Script (scripts/test_foundry_client.py)
Created comprehensive test script for POC validation:
Features:
- ✅ Tests thread creation and retrieval
- ✅ Tests message management
- ✅ Tests thread listing with filters
- ✅ Tests feature flag behavior
- ✅ Optional cleanup (controlled by env var)
Usage:
# Set environment variables
export AZURE_FOUNDRY_AGENT_ENDPOINT="https://<account>.services.ai.azure.com"
export AZURE_FOUNDRY_AGENT_PROJECT="<project-name>"
export AZURE_FOUNDRY_AGENT_KEY="<optional-api-key>" # Or use Managed Identity
export USE_FOUNDRY_THREADS=true # Enable for testing
# Run test
python scripts/test_foundry_client.py
# Optional: Enable cleanup
export FOUNDRY_TEST_CLEANUP=true
python scripts/test_foundry_client.py
Zero Impact Guarantees
✅ No Breaking Changes
- Feature Flags Disabled by Default:
- All
use_foundry_*flags default toFalse - Existing code continues to work unchanged
- All
- Optional Configuration:
- Foundry config is optional
- System works without Foundry configured
- Graceful Degradation:
get_foundry_client()returnsNonewhen disabled- No exceptions thrown when Foundry is not configured
- No Production Impact:
- Client is never initialized unless flags are enabled
- No API calls made unless explicitly enabled
Testing the POC
Prerequisites
- Azure AI Foundry Account:
- Create Foundry account and project
- Note the endpoint and project name
- Authentication:
- Option A: API key (set
AZURE_FOUNDRY_AGENT_KEY) - Option B: Managed Identity (no key needed, uses DefaultAzureCredential)
- Option A: API key (set
- Environment Variables:
export AZURE_FOUNDRY_AGENT_ENDPOINT="https://<account>.services.ai.azure.com" export AZURE_FOUNDRY_AGENT_PROJECT="<project-name>" export USE_FOUNDRY_THREADS=true # Enable for testing
Run Tests
# Test feature flags
python scripts/test_foundry_client.py
# Test with cleanup
FOUNDRY_TEST_CLEANUP=true python scripts/test_foundry_client.py
Expected Output
Foundry Agent Service Client POC Test
============================================================
Testing Feature Flags
============================================================
USE_FOUNDRY_THREADS: True
USE_FOUNDRY_FILES: False
USE_FOUNDRY_VECTORS: False
USE_FOUNDRY_TOOLS: False
✅ Client correctly initialized when flags are enabled
============================================================
Testing Foundry Agent Service Thread Management
============================================================
[Test 1] Creating thread...
✅ Created thread: thread_abc123...
[Test 2] Getting thread details...
✅ Retrieved thread: thread_abc123...
Metadata: {'user_id': 'test-user-123', 'agent_id': 'elena', ...}
[Test 3] Adding messages...
✅ Added user message: msg_xyz789...
✅ Added assistant message: msg_def456...
[Test 4] Listing messages...
✅ Retrieved 2 messages
1. [user] Hello, this is a test message...
2. [assistant] Hello! I'm Elena...
[Test 5] Listing threads...
✅ Found 1 threads
1. Thread thread_abc123... (agent: elena)
[Test 6] Cleaning up...
✅ Deleted thread: thread_abc123...
============================================================
✅ All tests passed!
============================================================
Next Steps (Optional Integration)
Phase 2: Thread Management Integration
Goal: Replace in-memory sessions with Foundry threads (optional)
Changes Required:
- Update
backend/api/routers/chat.py:async def get_or_create_session(...): if settings.use_foundry_threads: foundry_client = get_foundry_client() if foundry_client: # Use Foundry thread thread_id = await foundry_client.create_thread(...) # Load messages into EnterpriseContext messages = await foundry_client.list_messages(thread_id) context = EnterpriseContext.from_foundry_messages(thread_id, messages) return context # Fallback to existing in-memory sessions return get_or_create_session_legacy(...) -
Feature Flag:
USE_FOUNDRY_THREADS=true(disabled by default) - Rollback: Set flag to
falseto instantly revert
Benefits:
- ✅ Persistent conversation history
- ✅ Automatic thread management
- ✅ Project-based thread isolation
- ✅ Zero downtime migration
API Reference
FoundryAgentServiceClient
create_thread(user_id, agent_id, project_id=None, metadata=None) -> str
Create a new conversation thread.
Parameters:
user_id(str): User identifieragent_id(str): Agent identifier (elena, marcus, sage)project_id(str, optional): Project identifier for isolationmetadata(dict, optional): Additional metadata
Returns: Thread ID (str)
Example:
thread_id = await client.create_thread(
user_id="user-123",
agent_id="elena",
project_id="project-alpha",
metadata={"source": "web", "session_type": "chat"}
)
get_thread(thread_id) -> dict
Get thread details.
Parameters:
thread_id(str): Thread identifier
Returns: Thread details (dict)
list_threads(user_id=None, agent_id=None, project_id=None, limit=20) -> list[dict]
List threads with optional filters.
Parameters:
user_id(str, optional): Filter by useragent_id(str, optional): Filter by agentproject_id(str, optional): Filter by projectlimit(int): Maximum results (default: 20)
Returns: List of thread dictionaries
add_message(thread_id, role, content, metadata=None) -> dict
Add a message to a thread.
Parameters:
thread_id(str): Thread identifierrole(str): Message role (user, assistant, system)content(str): Message contentmetadata(dict, optional): Message metadata
Returns: Message details (dict)
list_messages(thread_id, limit=20) -> list[dict]
List messages in a thread.
Parameters:
thread_id(str): Thread identifierlimit(int): Maximum results (default: 20)
Returns: List of message dictionaries
upload_file(thread_id, file_path, purpose="assistant") -> dict
Upload a file to a thread.
Parameters:
thread_id(str): Thread identifierfile_path(str): Path to filepurpose(str): File purpose (default: “assistant”)
Returns: File details (dict)
delete_thread(thread_id) -> None
Delete a thread.
Parameters:
thread_id(str): Thread identifier
Error Handling
The client includes comprehensive error handling:
- HTTP Errors: Logged with status code and response text
- Network Errors: Caught and re-raised with context
- Configuration Errors: Clear error messages for missing config
- Graceful Degradation: Returns
Nonewhen flags are disabled
Example Error Handling:
try:
thread_id = await client.create_thread(...)
except httpx.HTTPStatusError as e:
logger.error(f"Foundry API error: {e.response.status_code}")
# Fallback to existing behavior
except Exception as e:
logger.error(f"Unexpected error: {e}")
# Fallback to existing behavior
Security Considerations
- Authentication:
- Supports Managed Identity (recommended for production)
- Falls back to API key for development/testing
- Credentials never logged
- Project Isolation:
- Threads include
project_idin metadata - Client-side filtering ensures proper isolation
- Aligns with existing
SecurityContext.project_idimplementation
- Threads include
- Feature Flags:
- All features disabled by default
- Requires explicit opt-in via environment variables
- No accidental production usage
Troubleshooting
Client Returns None
Cause: Feature flags are disabled or Foundry is not configured.
Solution:
# Enable feature flag
export USE_FOUNDRY_THREADS=true
# Set configuration
export AZURE_FOUNDRY_AGENT_ENDPOINT="https://..."
export AZURE_FOUNDRY_AGENT_PROJECT="..."
Authentication Errors
Cause: Invalid credentials or missing permissions.
Solution:
- Verify API key is correct (if using API key)
- Verify Managed Identity has proper permissions (if using MI)
- Check Azure portal for account/project access
API Version Errors
Cause: Unsupported API version.
Solution:
- Check Foundry documentation for latest API version
- Update
AZURE_FOUNDRY_AGENT_API_VERSIONif needed - Default:
2024-10-01-preview
Summary
✅ POC Complete: Foundry Agent Service client implemented
✅ Zero Impact: All features disabled by default
✅ Production Safe: No breaking changes, graceful degradation
✅ Tested: Comprehensive test script included
✅ Documented: Full API reference and usage examples
Ready for: Testing in development environment
Not Ready for: Production use (requires thorough testing first)
Last Updated: January 2026