AutoGen
Verified 2026-08-19 — PASS, 5s. Session persistence: save_state() / load_state() blob.
AutoGen serialises the agent’s whole conversation state, so resume keeps structured turns rather than replayed text.
The runner
Section titled “The runner”import sys, os, json, asyncio, pathlibsys.path.insert(0, os.path.expanduser("~/agenttests"))import azcfg, hetool
from autogen_agentchat.agents import AssistantAgentfrom autogen_ext.models.openai import OpenAIChatCompletionClient
STATE_DIR = pathlib.Path(os.path.expanduser("~/agenttests/autogen/state"))STATE_DIR.mkdir(parents=True, exist_ok=True)
def get_working_folder() -> str: """Return the agent's current working folder (absolute path).""" return hetool.get_working_folder()
def run_shell(command: str) -> str: """Run a shell command in the working folder and return its output.""" return hetool.run_shell(command)
async def invoke(sid, message): c = azcfg.load() model_client = OpenAIChatCompletionClient( model=c["model"], base_url=c["base_url"], api_key=c["api_key"], model_info={"vision": False, "function_calling": True, "json_output": True, "family": "unknown", "structured_output": True}, ) agent = AssistantAgent("assistant", model_client=model_client, system_message="Be concise. Use tools for operational questions.", tools=[get_working_folder, run_shell], reflect_on_tool_use=True)
f = STATE_DIR / f"{sid}.json" if f.exists(): await agent.load_state(json.loads(f.read_text()))
result = await agent.run(task=message) reply = result.messages[-1].content.strip()
f.write_text(json.dumps(await agent.save_state())) await model_client.close() return replyAsync — the adapter drives the coroutine, so invoke may be async def.
Engine definition
Section titled “Engine definition”Same shape as every other framework; only file and the runner path change.
{ "type": "process", "file": "/home/you/autogen/.venv/bin/python3", "nativeSession": true, "argsNew": ["/home/you/he_adapter.py", "/home/you/autogen_session.py", "", "{message}"], "argsResume": ["/home/you/he_adapter.py", "/home/you/autogen_session.py", "{sessionId}", "{message}"], "replyField": "result", "sessionIdField": "session_id", "approve": false, "workdir": "/home/you/work", "proxy": { "shape": "openai", "baseUrlEnv": "OPENAI_BASE_URL", "keyEnv": "OPENAI_API_KEY", "modelEnv": "OPENAI_MODEL", "model": "<route>|<provider model>" }}Adoption
Section titled “Adoption”- Keep your
AssistantAgentand tools as they are. - Wrap
agent.run(...)inasync def invoke(sid, message). - Add
load_state/save_statekeyed onsid. - Build
OpenAIChatCompletionClientfromazcfg.load(). - Seal the engine, point
external.engineat it, restart.
Gotchas
Section titled “Gotchas”model_info is required for any non-OpenAI model. The client cannot infer capabilities for an
unknown model id and will refuse to start without it. function_calling: True is the field that
matters if you bind tools.
reflect_on_tool_use=True or you get the raw tool output. Without it the agent’s last message is
the tool result, not a composed answer — so result.messages[-1].content is JSON rather than prose.
Close the client. await model_client.close() before returning, or the process can hang with the
connection pool open — which surfaces as a turn that never completes.
Plain callables are fine as tools. No decorator needed; AutoGen introspects the signature and docstring, so write a real docstring — it becomes the tool description the model sees.