What You’ll Learn
- Implementing the
CodeExecutor ABC from autogen_core.code_executor backed by Declaw sandboxes
- Supporting both Python and shell code blocks
- Integrating with
CodeExecutorAgent and AssistantAgent
- Running a
RoundRobinGroupChat team with termination conditions
- Demo mode that exercises the executor without needing an OpenAI key
Prerequisites
- Declaw instance running and
DECLAW_API_KEY / DECLAW_DOMAIN set
OPENAI_API_KEY (optional — the example runs in demo mode without it)
pip install declaw python-dotenv autogen-agentchat "autogen-ext[openai]"
This example is available in Python. TypeScript support coming soon.
Code Walkthrough
1. Implement DecawCodeExecutor
Subclass CodeExecutor and implement execute_code_blocks. The method receives a list of CodeBlock objects — each has a language and code field:
from autogen_core.code_executor import CodeBlock, CodeExecutor, CodeResult
from declaw import Sandbox
class DecawCodeExecutor(CodeExecutor):
"""AutoGen CodeExecutor that runs code in Declaw sandboxes."""
async def execute_code_blocks(
self,
code_blocks: list[CodeBlock],
cancellation_token=None,
) -> CodeResult:
sbx = Sandbox.create(template="python", timeout=300)
try:
outputs = []
last_exit_code = 0
for block in code_blocks:
if block.language in ("python", "py", "python3"):
sbx.files.write("/tmp/code.py", block.code)
result = sbx.commands.run("python3 /tmp/code.py", timeout=30)
elif block.language in ("bash", "sh", "shell"):
sbx.files.write("/tmp/script.sh", block.code)
result = sbx.commands.run("sh /tmp/script.sh", timeout=30)
else:
outputs.append(f"Unsupported language: {block.language}")
continue
outputs.append(result.stdout)
if result.stderr:
outputs.append(result.stderr)
last_exit_code = result.exit_code
return CodeResult(
exit_code=last_exit_code,
output="\n".join(outputs),
)
finally:
sbx.kill()
async def restart(self) -> None:
pass # Stateless — each call gets a fresh sandbox
async def stop(self) -> None:
pass
A fresh sandbox is created per execute_code_blocks call, ensuring full isolation between turns.
2. Wire into AutoGen agents
from autogen_agentchat.agents import CodeExecutorAgent, AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_ext.models.openai import OpenAIChatCompletionClient
model_client = OpenAIChatCompletionClient(model="gpt-4o-mini")
coder = AssistantAgent(
name="coder",
model_client=model_client,
system_message=(
"You write Python code to solve tasks. "
"Put code in ```python code blocks. "
"Say TERMINATE when done."
),
)
executor = CodeExecutorAgent(
name="executor",
code_executor=DecawCodeExecutor(),
)
3. Run the team
import asyncio
termination = TextMentionTermination("TERMINATE")
team = RoundRobinGroupChat(
[coder, executor],
termination_condition=termination,
max_turns=6,
)
result = await team.run(
task="Write Python code to find the 20th triangular number and print it."
)
for msg in result.messages:
print(f"\n[{msg.source}] {msg.content}")
4. Demo mode (no API key needed)
Run the executor directly without an AutoGen agent:
import asyncio
from declaw import Sandbox
code = """\
n = 20
triangular = n * (n + 1) // 2
print(f"The {n}th triangular number is {triangular}")
"""
sbx = Sandbox.create(template="python", timeout=300)
try:
sbx.files.write("/tmp/code.py", code)
result = sbx.commands.run("python3 /tmp/code.py", timeout=30)
print(result.stdout)
finally:
sbx.kill()
Expected Output
In demo mode:
=======================================================
AutoGen + Declaw Sandbox Example
=======================================================
No OPENAI_API_KEY found -- running demo mode.
--- CodeExecutor Definition ---
class DecawCodeExecutor(CodeExecutor):
async def execute_code_blocks(self, code_blocks, cancellation_token=None):
sbx = Sandbox.create(template="python", timeout=300)
...
--- Running Code Directly in Declaw Sandbox ---
Code:
n = 20
triangular = n * (n + 1) // 2
print(f"The {n}th triangular number is {triangular}")
stdout: The 20th triangular number is 210
stderr:
exit_code: 0
Sandbox cleaned up.
=======================================================
Done!
=======================================================