Deploy Edmund (the Engineer) #8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Deploy Edmund Agent | |
on: | |
push: | |
branches: [ main ] | |
paths: | |
- 'agents/edmund/**' | |
pull_request: | |
branches: [ main ] | |
paths: | |
- 'agents/edmund/**' | |
workflow_dispatch: | |
env: | |
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
AZURE_RESOURCE_GROUP: copilot-edmund | |
AZURE_LOCATION: eastus | |
AGENT_NAME: edmund-engineer | |
AI_FOUNDRY_PROJECT: edmund-tminus15-project | |
AZURE_OPENAI_ENDPOINT: "https://copilot-edmund.openai.azure.com/" | |
AZURE_OPENAI_API_VERSION: "2024-12-01-preview" | |
AZURE_OPENAI_DEPLOYMENT_NAME: "gpt-4o" | |
jobs: | |
validate: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Python | |
uses: actions/setup-python@v4 | |
with: | |
python-version: '3.11' | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install jsonschema pyyaml | |
- name: Validate agent configuration | |
run: | | |
python -c " | |
import json | |
import yaml | |
# Validate agent-config.json | |
with open('agents/edmund/agent-config.json', 'r') as f: | |
config = json.load(f) | |
print('✓ agent-config.json is valid JSON') | |
# Validate deployment.yaml | |
with open('agents/edmund/deployment.yaml', 'r') as f: | |
deployment = yaml.safe_load_all(f) | |
for doc in deployment: | |
if doc: | |
print('✓ deployment.yaml document is valid YAML') | |
# Check required fields | |
required_fields = ['agent', 'model', 'instructions'] | |
for field in required_fields: | |
if field not in config: | |
raise ValueError(f'Missing required field: {field}') | |
print('✓ All configuration files are valid') | |
" | |
- name: Test configuration syntax | |
run: | | |
cd agents/edmund | |
python -m json.tool agent-config.json > /dev/null | |
echo "✓ agent-config.json syntax is valid" | |
deploy-dev: | |
runs-on: ubuntu-latest | |
needs: validate | |
if: github.ref == 'refs/heads/main' | |
environment: DEMO | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Azure Login | |
uses: azure/login@v1 | |
with: | |
creds: ${{ secrets.AZURE_CREDENTIALS }} | |
- name: Set up Azure CLI extensions | |
run: | | |
az extension add -n ml --yes | |
az version | |
- name: Verify Azure subscription and resource group | |
run: | | |
echo "Checking Azure subscription..." | |
az account show --output table | |
echo "Checking resource group..." | |
az group show --name $AZURE_RESOURCE_GROUP --output table || { | |
echo "Creating resource group $AZURE_RESOURCE_GROUP..." | |
az group create --name $AZURE_RESOURCE_GROUP --location $AZURE_LOCATION | |
} | |
- name: Create or update AI Foundry project | |
run: | | |
echo "Setting up AI Foundry project..." | |
# Try cognitive services approach first | |
if ! az cognitiveservices account show --name $AI_FOUNDRY_PROJECT --resource-group $AZURE_RESOURCE_GROUP >/dev/null 2>&1; then | |
echo "Creating AI Foundry resource using cognitive services..." | |
if ! az cognitiveservices account create \ | |
--name $AI_FOUNDRY_PROJECT \ | |
--resource-group $AZURE_RESOURCE_GROUP \ | |
--location $AZURE_LOCATION \ | |
--kind AIServices \ | |
--sku S0 \ | |
--custom-domain $AI_FOUNDRY_PROJECT; then | |
echo "Cognitive services approach failed, trying ML workspace..." | |
# Fallback to ML workspace approach | |
az ml workspace create \ | |
--name $AI_FOUNDRY_PROJECT \ | |
--resource-group $AZURE_RESOURCE_GROUP \ | |
--location $AZURE_LOCATION \ | |
--display-name "Edmund T-Minus-15 Agent Project" \ | |
--description "AI Foundry project for Edmund, the Engineering Agent from T-Minus-15 methodology" | |
fi | |
else | |
echo "AI Foundry resource already exists" | |
fi | |
- name: Configure AI Foundry connection | |
run: | | |
echo "Configuring AI Foundry connection..." | |
# Try to get endpoint from cognitive services first | |
AI_FOUNDRY_ENDPOINT=$(az cognitiveservices account show \ | |
--name $AI_FOUNDRY_PROJECT \ | |
--resource-group $AZURE_RESOURCE_GROUP \ | |
--query "properties.endpoint" -o tsv 2>/dev/null || echo "") | |
if [ -z "$AI_FOUNDRY_ENDPOINT" ]; then | |
echo "Cognitive services endpoint not found, trying ML workspace..." | |
# Fallback: construct endpoint from ML workspace | |
AI_FOUNDRY_ENDPOINT="https://$AI_FOUNDRY_PROJECT.api.azureml.ms" | |
fi | |
echo "AI Foundry endpoint: $AI_FOUNDRY_ENDPOINT" | |
echo "AI_FOUNDRY_ENDPOINT=$AI_FOUNDRY_ENDPOINT" >> $GITHUB_ENV | |
- name: Deploy Edmund agent to AI Foundry | |
run: | | |
cd agents/edmund | |
echo "Deploying Edmund agent to AI Foundry..." | |
# Get access token for AI Foundry API | |
ACCESS_TOKEN=$(az account get-access-token --resource 'https://ai.azure.com' --query accessToken -o tsv) | |
# Create agent using AI Foundry REST API | |
INSTRUCTIONS=$(cat agent-config.json | jq -r '.instructions.systemPrompt' | sed 's/"/\\"/g' | tr '\n' ' ') | |
# Build JSON payload using jq to avoid YAML parsing issues | |
echo '{}' | jq \ | |
--arg name "edmund-engineer" \ | |
--arg desc "AI Engineer specialized in development tasks and T-Minus-15 methodology" \ | |
--arg instructions "$INSTRUCTIONS" \ | |
--arg model "$AZURE_OPENAI_DEPLOYMENT_NAME" \ | |
'.name = $name | .description = $desc | .instructions = $instructions | .model = $model | .tools = [{"type": "code_interpreter"}, {"type": "file_search"}] | .metadata = {"version": "1.0.0", "methodology": "T-Minus-15", "deployment_environment": "production"}' \ | |
> agent-payload.json | |
# Deploy agent to AI Foundry | |
curl -X POST "$AI_FOUNDRY_ENDPOINT/agents" \ | |
-H "Authorization: Bearer $ACCESS_TOKEN" \ | |
-H "Content-Type: application/json" \ | |
-H "api-version: 2025-01-15-preview" \ | |
-d @agent-payload.json \ | |
-o deployment-response.json | |
# Check deployment response | |
if [ -f deployment-response.json ]; then | |
echo "Deployment response:" | |
cat deployment-response.json | |
# Extract agent ID if successful | |
AGENT_ID=$(cat deployment-response.json | jq -r '.id' 2>/dev/null || echo "") | |
if [ "$AGENT_ID" != "" ] && [ "$AGENT_ID" != "null" ]; then | |
echo "✅ Edmund agent deployed successfully with ID: $AGENT_ID" | |
echo "AGENT_ID=$AGENT_ID" >> $GITHUB_ENV | |
else | |
echo "❌ Agent deployment may have failed" | |
cat deployment-response.json | |
fi | |
else | |
echo "❌ No deployment response received" | |
fi | |
- name: Test deployment | |
run: | | |
echo "Testing Edmund agent deployment..." | |
if [ -z "$AGENT_ID" ]; then | |
echo "⚠️ No agent ID available, skipping test" | |
exit 0 | |
fi | |
# Get access token for AI Foundry API | |
ACCESS_TOKEN=$(az account get-access-token --resource 'https://ai.azure.com' --query accessToken -o tsv) | |
# Create a test thread | |
THREAD_PAYLOAD='{"metadata": {"test": "true"}}' | |
curl -X POST "$AI_FOUNDRY_ENDPOINT/threads" \ | |
-H "Authorization: Bearer $ACCESS_TOKEN" \ | |
-H "Content-Type: application/json" \ | |
-H "api-version: 2025-01-15-preview" \ | |
-d "$THREAD_PAYLOAD" \ | |
-o thread-response.json | |
THREAD_ID=$(cat thread-response.json | jq -r '.id' 2>/dev/null || echo "") | |
if [ "$THREAD_ID" != "" ] && [ "$THREAD_ID" != "null" ]; then | |
echo "✅ Test thread created: $THREAD_ID" | |
# Send test message to Edmund | |
MESSAGE_PAYLOAD='{"role": "user", "content": "Hello Edmund! Can you help me with a quick T-Minus-15 methodology question?"}' | |
curl -X POST "$AI_FOUNDRY_ENDPOINT/threads/$THREAD_ID/messages" \ | |
-H "Authorization: Bearer $ACCESS_TOKEN" \ | |
-H "Content-Type: application/json" \ | |
-H "api-version: 2025-01-15-preview" \ | |
-d "$MESSAGE_PAYLOAD" \ | |
-o message-response.json | |
echo "✅ Test message sent to Edmund" | |
echo "📋 Deployment test completed successfully" | |
else | |
echo "⚠️ Could not create test thread, but agent deployment appears successful" | |
fi | |
- name: Verify agent deployment | |
run: | | |
echo "Verifying Edmund agent deployment..." | |
if [ -n "$AGENT_ID" ]; then | |
# Get access token for AI Foundry API | |
ACCESS_TOKEN=$(az account get-access-token --resource 'https://ai.azure.com' --query accessToken -o tsv) | |
# Get agent details | |
curl -X GET "$AI_FOUNDRY_ENDPOINT/agents/$AGENT_ID" \ | |
-H "Authorization: Bearer $ACCESS_TOKEN" \ | |
-H "api-version: 2025-01-15-preview" \ | |
-o agent-details.json | |
echo "✅ Edmund agent details:" | |
cat agent-details.json | jq . | |
else | |
echo "⚠️ No agent ID available for verification" | |
fi | |
- name: Output deployment information | |
run: | | |
echo "=== Edmund Deployment Summary ===" | |
echo "Agent Name: $AGENT_NAME" | |
echo "Resource Group: $AZURE_RESOURCE_GROUP" | |
echo "AI Foundry Project: $AI_FOUNDRY_PROJECT" | |
echo "Location: $AZURE_LOCATION" | |
echo "AI Foundry Endpoint: $AI_FOUNDRY_ENDPOINT" | |
echo "Azure OpenAI Endpoint: ${{ env.AZURE_OPENAI_ENDPOINT }}" | |
echo "Model: ${{ env.AZURE_OPENAI_DEPLOYMENT_NAME }}" | |
if [ -n "$AGENT_ID" ]; then | |
echo "Agent ID: $AGENT_ID" | |
echo "✅ Edmund successfully deployed to Azure AI Foundry!" | |
else | |
echo "⚠️ Agent deployment status unclear" | |
fi | |
echo "=== Deployment Complete ===" | |