Back to Blog

Microsoft Agent Framework with HopX: Secure Code Execution for AI Agents

TutorialsAlin Dobra11 min read

Microsoft Agent Framework with HopX: Secure Code Execution

Microsoft just unified the AI agent landscape. Agent Framework combines the best of AutoGen and Semantic Kernel into a single, enterprise-ready SDK. Both predecessors are now in maintenance mode—this is the future.

But Agent Framework inherits the same code execution challenge: where do you safely run AI-generated code? This guide shows how to integrate HopX sandboxes for secure, isolated execution.

What Is Agent Framework?

Agent Framework is Microsoft's new unified SDK for building AI agents:

text
1
2
                     Agent Framework                              
3
            (Successor to AutoGen + Semantic Kernel)             
4
                                                                  
5
      
6
    From AutoGen:                                               
7
     Simple multi-agent conversations                          
8
     Agent orchestration patterns                              
9
     Group chat abstractions                                   
10
      
11
                              +                                   
12
      
13
    From Semantic Kernel:                                       
14
     Enterprise-grade state management                         
15
     Thread-based conversations                                
16
     Type safety and observability                             
17
     Azure AI Foundry integration                              
18
      
19
                              +                                   
20
      
21
    New in Agent Framework:                                     
22
     Workflow graphs for explicit execution paths              
23
     Human-in-the-loop patterns                                
24
     A2A (Agent-to-Agent) connections                          
25
     MCP (Model Context Protocol) support                      
26
      
27
28
 

Why Migrate Now?

FeatureAutoGenSemantic KernelAgent Framework
StatusMaintenanceMaintenanceActive Development
Multi-agentLimited✅ Enhanced
Enterprise featuresLimited
Azure integrationBasic✅✅ Native
Workflow graphs✅ New
Code executionDocker/LocalPluginsExtensible

Prerequisites

bash
1
pip install agent-framework hopx-ai
2
 

Set environment variables:

bash
1
export OPENAI_API_KEY="sk-..."
2
export HOPX_API_KEY="..."
3
# Or for Azure OpenAI:
4
export AZURE_OPENAI_API_KEY="..."
5
export AZURE_OPENAI_ENDPOINT="https://..."
6
 

Step 1: Create a Code Execution Tool

Agent Framework uses a clean tool/function interface. Here's how to wrap HopX:

python
1
from agent_framework import ChatAgent, Tool, tool
2
from hopx import Sandbox
3
from typing import Optional
4
 
5
class HopXExecutor:
6
    """Manage HopX sandbox for code execution."""
7
    
8
    def __init__(self, persist: bool = True, ttl: int = 600):
9
        self.persist = persist
10
        self.ttl = ttl
11
        self._sandbox: Optional[Sandbox] = None
12
    
13
    @property
14
    def sandbox(self) -> Sandbox:
15
        """Get or create sandbox."""
16
        if self._sandbox is None:
17
            self._sandbox = Sandbox.create(
18
                template="code-interpreter",
19
                ttl=self.ttl if self.persist else 60
20
            )
21
        return self._sandbox
22
    
23
    def execute(self, code: str, language: str = "python") -> str:
24
        """Execute code in sandbox."""
25
        try:
26
            result = self.sandbox.runCode(code, language=language, timeout=60)
27
            
28
            if result.exitCode == 0:
29
                return result.stdout or "Code executed successfully (no output)"
30
            else:
31
                return f"Error (exit {result.exitCode}):\n{result.stderr}"
32
                
33
        except Exception as e:
34
            self._sandbox = None  # Reset on error
35
            return f"Execution failed: {str(e)}"
36
    
37
    def cleanup(self):
38
        """Destroy sandbox."""
39
        if self._sandbox:
40
            self._sandbox.kill()
41
            self._sandbox = None
42
 
43
 
44
# Create global executor
45
executor = HopXExecutor(persist=True)
46
 
47
 
48
@tool
49
def execute_python(code: str) -> str:
50
    """
51
    Execute Python code in a secure, isolated sandbox.
52
    
53
    Use this tool when you need to:
54
    - Perform calculations or mathematical operations
55
    - Analyze data with pandas, numpy
56
    - Create visualizations with matplotlib
57
    - Process files or data structures
58
    - Run any Python computation
59
    
60
    The sandbox has pandas, numpy, matplotlib, seaborn, scikit-learn installed.
61
    Always use print() to show results.
62
    State persists between calls within the same session.
63
    
64
    Args:
65
        code: Complete, executable Python code
66
        
67
    Returns:
68
        Output from code execution or error message
69
    """
70
    return executor.execute(code, "python")
71
 
72
 
73
@tool
74
def execute_bash(command: str) -> str:
75
    """
76
    Execute bash commands in a secure sandbox.
77
    
78
    Use for:
79
    - File operations (ls, cat, head)
80
    - Package installation (pip install)
81
    - System commands
82
    
83
    Args:
84
        command: Bash command to execute
85
        
86
    Returns:
87
        Command output or error
88
    """
89
    return executor.execute(command, "bash")
90
 

Step 2: Create a ChatAgent with Tools

Build an agent that can execute code:

python
1
from agent_framework import ChatAgent, ChatClient
2
from agent_framework.models import OpenAIChatClient
3
import os
4
 
5
# Create chat client
6
client = OpenAIChatClient(
7
    model="gpt-4o",
8
    api_key=os.environ["OPENAI_API_KEY"]
9
)
10
 
11
# Or for Azure OpenAI:
12
# from agent_framework.models import AzureOpenAIChatClient
13
# client = AzureOpenAIChatClient(
14
#     deployment_name="gpt-4o",
15
#     endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
16
#     api_key=os.environ["AZURE_OPENAI_API_KEY"]
17
# )
18
 
19
# Create agent with tools
20
agent = ChatAgent(
21
    name="CodeAssistant",
22
    client=client,
23
    tools=[execute_python, execute_bash],
24
    system_message="""You are a helpful AI assistant that can execute Python code.
25
 
26
When users ask questions that require computation:
27
1. Write clear, well-documented Python code
28
2. Use the execute_python tool to run it
29
3. Analyze the results and explain them
30
 
31
Available libraries: pandas, numpy, matplotlib, seaborn, scipy, scikit-learn.
32
For visualizations, save to /app/chart.png using plt.savefig().
33
Always print() results you want to see.
34
"""
35
)
36
 
37
# Get a new conversation thread
38
thread = agent.get_new_thread()
39
 
40
# Chat with the agent
41
response = await agent.chat(
42
    thread=thread,
43
    message="Calculate the first 50 prime numbers and find their sum"
44
)
45
 
46
print(response.content)
47
 
48
# Continue the conversation (state persists)
49
response = await agent.chat(
50
    thread=thread,
51
    message="Now find the average and standard deviation of those primes"
52
)
53
 
54
print(response.content)
55
 
56
# Cleanup
57
executor.cleanup()
58
 

Step 3: Multi-Agent Workflows

Agent Framework introduces workflow graphs for complex multi-agent scenarios:

python
1
from agent_framework import ChatAgent, Workflow, Node, Edge
2
from agent_framework.models import OpenAIChatClient
3
 
4
# Create specialized agents
5
researcher = ChatAgent(
6
    name="Researcher",
7
    client=client,
8
    system_message="You research topics and identify key questions to answer."
9
)
10
 
11
analyst = ChatAgent(
12
    name="Analyst",
13
    client=client,
14
    tools=[execute_python],
15
    system_message="You analyze data using Python. Always verify with code."
16
)
17
 
18
writer = ChatAgent(
19
    name="Writer",
20
    client=client,
21
    system_message="You create clear, well-structured reports from analysis results."
22
)
23
 
24
# Define workflow graph
25
workflow = Workflow(
26
    name="ResearchPipeline",
27
    nodes=[
28
        Node(id="research", agent=researcher),
29
        Node(id="analyze", agent=analyst),
30
        Node(id="report", agent=writer)
31
    ],
32
    edges=[
33
        Edge(source="research", target="analyze"),
34
        Edge(source="analyze", target="report")
35
    ]
36
)
37
 
38
# Execute workflow
39
result = await workflow.run(
40
    input="Analyze the relationship between company size and revenue growth"
41
)
42
 
43
print(result.output)
44
 

Step 4: Persistent State Across Agents

For workflows where agents need to share data:

python
1
from agent_framework import ChatAgent, tool
2
from hopx import Sandbox
3
from typing import Optional
4
import json
5
 
6
class SharedSandboxManager:
7
    """Singleton sandbox shared across all agents."""
8
    
9
    _instance: Optional['SharedSandboxManager'] = None
10
    _sandbox: Optional[Sandbox] = None
11
    
12
    @classmethod
13
    def get_instance(cls) -> 'SharedSandboxManager':
14
        if cls._instance is None:
15
            cls._instance = cls()
16
        return cls._instance
17
    
18
    def get_sandbox(self) -> Sandbox:
19
        if self._sandbox is None:
20
            self._sandbox = Sandbox.create(
21
                template="code-interpreter",
22
                ttl=900  # 15 minutes for long workflows
23
            )
24
            # Initialize common imports
25
            self._sandbox.runCode("""
26
import pandas as pd
27
import numpy as np
28
import matplotlib.pyplot as plt
29
import seaborn as sns
30
import json
31
from datetime import datetime
32
print("Shared environment ready!")
33
""", language="python", timeout=30)
34
        return self._sandbox
35
    
36
    def execute(self, code: str) -> str:
37
        sandbox = self.get_sandbox()
38
        result = sandbox.runCode(code, language="python", timeout=60)
39
        return result.stdout if result.exitCode == 0 else f"Error: {result.stderr}"
40
    
41
    def cleanup(self):
42
        if self._sandbox:
43
            self._sandbox.kill()
44
            self._sandbox = None
45
 
46
 
47
@tool
48
def shared_python(code: str) -> str:
49
    """
50
    Execute Python with SHARED STATE across all agents.
51
    
52
    Variables, DataFrames, and computations persist between calls
53
    from ANY agent in the workflow. Use for collaborative analysis.
54
    
55
    Args:
56
        code: Python code to execute
57
        
58
    Returns:
59
        Execution output
60
    """
61
    return SharedSandboxManager.get_instance().execute(code)
62
 
63
 
64
# Create agents that share state
65
data_engineer = ChatAgent(
66
    name="DataEngineer",
67
    client=client,
68
    tools=[shared_python],
69
    system_message="You prepare and clean data. Save results to variables for other agents."
70
)
71
 
72
data_scientist = ChatAgent(
73
    name="DataScientist",
74
    client=client,
75
    tools=[shared_python],
76
    system_message="You analyze prepared data. Build on variables created by DataEngineer."
77
)
78
 
79
# In a workflow, both agents access the same sandbox
80
# DataEngineer: df = pd.read_csv(...)
81
# DataScientist: df['new_col'] = ...  # Same df!
82
 

Step 5: Human-in-the-Loop Patterns

Agent Framework has first-class support for human approval:

python
1
from agent_framework import ChatAgent, HumanApprovalHandler
2
from agent_framework.handlers import ConsoleApprovalHandler
3
 
4
# Custom approval handler for code execution
5
class CodeApprovalHandler(HumanApprovalHandler):
6
    """Require human approval before executing code."""
7
    
8
    async def request_approval(self, action: str, details: dict) -> bool:
9
        if action == "tool_call" and details.get("tool") == "execute_python":
10
            code = details.get("arguments", {}).get("code", "")
11
            print("\n" + "="*60)
12
            print("🔍 Code Execution Request")
13
            print("="*60)
14
            print(code)
15
            print("="*60)
16
            
17
            response = input("Approve execution? [y/N]: ").strip().lower()
18
            return response == "y"
19
        
20
        return True  # Auto-approve other actions
21
 
22
 
23
# Create agent with approval handler
24
secure_agent = ChatAgent(
25
    name="SecureAssistant",
26
    client=client,
27
    tools=[execute_python],
28
    approval_handler=CodeApprovalHandler()
29
)
30
 
31
# Now code execution requires human approval
32
response = await secure_agent.chat(
33
    thread=thread,
34
    message="Delete all files in /app"  # This will prompt for approval!
35
)
36
 

Step 6: Migration from AutoGen

If you're migrating from AutoGen, here's a comparison:

AutoGen (Old)

python
1
# AutoGen way
2
from autogen import AssistantAgent, UserProxyAgent
3
 
4
assistant = AssistantAgent(
5
    name="assistant",
6
    llm_config={"config_list": [{"model": "gpt-4o"}]}
7
)
8
 
9
user_proxy = UserProxyAgent(
10
    name="user_proxy",
11
    code_execution_config={"executor": docker_executor}
12
)
13
 
14
user_proxy.initiate_chat(assistant, message="Hello")
15
 

Agent Framework (New)

python
1
# Agent Framework way
2
from agent_framework import ChatAgent
3
from agent_framework.models import OpenAIChatClient
4
 
5
agent = ChatAgent(
6
    name="assistant",
7
    client=OpenAIChatClient(model="gpt-4o"),
8
    tools=[execute_python]  # HopX-backed tool
9
)
10
 
11
thread = agent.get_new_thread()
12
response = await agent.chat(thread=thread, message="Hello")
13
 

Key Differences

AutoGenAgent Framework
AssistantAgent + UserProxyAgentSingle ChatAgent
llm_config dictChatClient object
initiate_chat()agent.chat() async
Docker executorCustom tools (HopX)
Implicit stateExplicit threads

Complete Working Example

Production-ready Agent Framework with HopX:

python
1
"""
2
Microsoft Agent Framework with HopX Code Execution
3
"""
4
 
5
import asyncio
6
import os
7
from typing import Optional
8
from agent_framework import ChatAgent, tool, Workflow, Node, Edge
9
from agent_framework.models import OpenAIChatClient
10
from hopx import Sandbox
11
 
12
# Verify environment
13
assert os.environ.get("OPENAI_API_KEY"), "Set OPENAI_API_KEY"
14
assert os.environ.get("HOPX_API_KEY"), "Set HOPX_API_KEY"
15
 
16
 
17
class SandboxManager:
18
    """Manage shared HopX sandbox."""
19
    _sandbox: Optional[Sandbox] = None
20
    
21
    @classmethod
22
    def execute(cls, code: str, language: str = "python") -> str:
23
        if cls._sandbox is None:
24
            cls._sandbox = Sandbox.create(template="code-interpreter", ttl=600)
25
        
26
        result = cls._sandbox.runCode(code, language=language, timeout=60)
27
        return result.stdout if result.exitCode == 0 else f"Error: {result.stderr}"
28
    
29
    @classmethod
30
    def cleanup(cls):
31
        if cls._sandbox:
32
            cls._sandbox.kill()
33
            cls._sandbox = None
34
 
35
 
36
@tool
37
def python(code: str) -> str:
38
    """Execute Python code. State persists between calls."""
39
    return SandboxManager.execute(code, "python")
40
 
41
 
42
@tool
43
def bash(command: str) -> str:
44
    """Execute bash commands."""
45
    return SandboxManager.execute(command, "bash")
46
 
47
 
48
async def main():
49
    # Create client
50
    client = OpenAIChatClient(
51
        model="gpt-4o",
52
        api_key=os.environ["OPENAI_API_KEY"]
53
    )
54
    
55
    # Create agent
56
    agent = ChatAgent(
57
        name="DataAnalyst",
58
        client=client,
59
        tools=[python, bash],
60
        system_message="""You are a data analyst. Use Python for all calculations.
61
Always verify results with code. Available: pandas, numpy, matplotlib."""
62
    )
63
    
64
    # Start conversation
65
    thread = agent.get_new_thread()
66
    
67
    try:
68
        # Multi-turn conversation with persistent state
69
        print("Query 1: Creating data...")
70
        r1 = await agent.chat(
71
            thread=thread,
72
            message="Create a DataFrame with 500 rows of sales data: date, product, region, amount"
73
        )
74
        print(r1.content)
75
        
76
        print("\nQuery 2: Analyzing...")
77
        r2 = await agent.chat(
78
            thread=thread,
79
            message="Calculate total sales by region and find the top performer"
80
        )
81
        print(r2.content)
82
        
83
        print("\nQuery 3: Visualization...")
84
        r3 = await agent.chat(
85
            thread=thread,
86
            message="Create a bar chart of sales by region"
87
        )
88
        print(r3.content)
89
        
90
    finally:
91
        SandboxManager.cleanup()
92
        print("\n✅ Sandbox cleaned up")
93
 
94
 
95
if __name__ == "__main__":
96
    asyncio.run(main())
97
 

Workflow Example: Research Pipeline

python
1
async def run_research_pipeline():
2
    """Run a multi-agent research workflow."""
3
    
4
    client = OpenAIChatClient(model="gpt-4o")
5
    
6
    # Specialized agents
7
    researcher = ChatAgent(
8
        name="Researcher",
9
        client=client,
10
        system_message="Identify key research questions and data requirements."
11
    )
12
    
13
    analyst = ChatAgent(
14
        name="Analyst", 
15
        client=client,
16
        tools=[python],
17
        system_message="Perform data analysis. Always use code for accuracy."
18
    )
19
    
20
    writer = ChatAgent(
21
        name="Writer",
22
        client=client,
23
        tools=[python],
24
        system_message="Create clear reports. Verify numbers with code."
25
    )
26
    
27
    # Define workflow
28
    workflow = Workflow(
29
        name="MarketResearch",
30
        nodes=[
31
            Node(id="research", agent=researcher),
32
            Node(id="analyze", agent=analyst),
33
            Node(id="report", agent=writer)
34
        ],
35
        edges=[
36
            Edge(source="research", target="analyze"),
37
            Edge(source="analyze", target="report")
38
        ]
39
    )
40
    
41
    try:
42
        result = await workflow.run(
43
            input="""
44
            Research Question: What factors correlate with high customer lifetime value?
45
            
46
            Create synthetic customer data and analyze:
47
            - Demographics (age, income, location)
48
            - Behavior (purchase frequency, avg order value)
49
            - Engagement (email opens, support tickets)
50
            
51
            Identify the top 3 predictive factors.
52
            """
53
        )
54
        
55
        print("="*60)
56
        print("RESEARCH REPORT")
57
        print("="*60)
58
        print(result.output)
59
        
60
    finally:
61
        SandboxManager.cleanup()
62
 
63
 
64
asyncio.run(run_research_pipeline())
65
 

Best Practices

1. Use Async/Await

python
1
# Agent Framework is async-first
2
response = await agent.chat(thread=thread, message=query)
3
 

2. Manage Thread Lifecycle

python
1
# Create thread for conversation
2
thread = agent.get_new_thread()
3
 
4
# Use same thread for multi-turn
5
r1 = await agent.chat(thread=thread, message="Step 1")
6
r2 = await agent.chat(thread=thread, message="Step 2")  # Continues context
7
 

3. Cleanup Resources

python
1
try:
2
    result = await workflow.run(input=task)
3
finally:
4
    SandboxManager.cleanup()
5
 

4. Handle Errors Gracefully

python
1
@tool
2
def safe_python(code: str) -> str:
3
    """Execute Python with error handling."""
4
    try:
5
        return SandboxManager.execute(code)
6
    except Exception as e:
7
        SandboxManager._sandbox = None  # Reset on failure
8
        return f"Execution failed: {e}. Please try again."
9
 

Conclusion

Microsoft Agent Framework represents the future of AI agent development at Microsoft. By integrating with HopX, you get:

  • Unified SDK: One framework instead of AutoGen + Semantic Kernel
  • Secure execution: Isolated microVMs for code execution
  • Enterprise-ready: Azure integration, observability, state management
  • Future-proof: Active development vs maintenance mode

Start migrating your AutoGen and Semantic Kernel projects now. The future is Agent Framework + HopX.


Ready to build with Agent Framework? Get started with HopX for secure code execution.

Further Reading