> ## Documentation Index
> Fetch the complete documentation index at: https://developers.agentx.so/llms.txt
> Use this file to discover all available pages before exploring further.

# AutoGen

> Trace Microsoft AutoGen agent and team runs with AgentXAutoGenObserver

Targets the modern `autogen-agentchat` / `autogen-core` architecture (the actively maintained v0.4+ rewrite) - not the older `pyautogen` / `ag2` fork.

Install the integration extra:

```bash theme={null}
pip install "agentx-python[autogen]"
```

## `observer.run()`

Wraps an `AssistantAgent` or `Team`'s `.run(task=...)` call. Since AutoGen's own API is async-native, `observer.run()` is async too - `await` it the same way you'd `await agent.run(...)`.

```python theme={null}
from agentx import AgentX
from agentx.integrations.autogen import AgentXAutoGenObserver
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient

agentx = AgentX.from_env()
observer = AgentXAutoGenObserver(
    tracer=agentx.tracer,
    name="support-agent",
    metadata={"env": "production"},
)

model_client = OpenAIChatCompletionClient(model="gpt-4o-mini")
agent = AssistantAgent("assistant", model_client=model_client)

result = await observer.run(agent, task="How do I cancel my subscription?")
print(result.messages[-1].content)

agentx.tracer.flush(timeout=10)
```

Works the same way for a `Team`:

```python theme={null}
result = await observer.run(team, task="Research and summarize the cancellation policy.")
```

## What gets traced

Each `.run()` call produces one trace.

| Field                          | Source                                                                                                                                                                                                                                                                                      |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `input`                        | `TaskResult.messages[0].content` - the task, normalized to a real message regardless of whether you passed a plain string or a message object                                                                                                                                               |
| `output`                       | The last message's `content`                                                                                                                                                                                                                                                                |
| `latencyMs`                    | Wall-clock time of the full `.run()` call                                                                                                                                                                                                                                                   |
| `performanceSummary`           | One execution step per message with `models_usage` set (a real LLM call produced it), **named by the speaking agent** (`message.source`) so a multi-agent team reads as its agent-turn trajectory, plus one tool-call step per matched `ToolCallRequestEvent`/`ToolCallExecutionEvent` pair |
| `inputTokens` / `outputTokens` | Summed from each message's `models_usage.prompt_tokens` / `.completion_tokens`                                                                                                                                                                                                              |
| `error`                        | Exception message if `.run()` raises                                                                                                                                                                                                                                                        |

<Note>
  Per-step timing is derived from each message's real `created_at` timestamp,
  chained against the previous message's timestamp. AutoGen's message schema
  has no explicit start/end pair per LLM call, so this is real but
  approximate - the same caveat CrewAI's per-task timing has.
</Note>

<Note>
  `observer.run()` covers `.run()` only, not `.run_stream()` - a deliberate
  scope boundary, the same as this SDK's OpenAI and Google Gen AI streaming
  coverage.
</Note>

## `AgentXAutoGenObserver` reference

```python theme={null}
AgentXAutoGenObserver(
    tracer: Tracer,
    name: str = "autogen-agent",
    metadata: dict | None = None,
    session_id: str | None = None,
)
```

| Parameter    | Description                                       |
| ------------ | ------------------------------------------------- |
| `tracer`     | `agentx.tracer` from your `AgentX` instance       |
| `name`       | Label shown in the AgentX UI                      |
| `metadata`   | Static key-value metadata attached to every trace |
| `session_id` | Links traces from the same conversation thread    |

### `observer.run()` parameters

```python theme={null}
observer.run(
    agent_or_team: AssistantAgent | Team,
    task: str | BaseChatMessage | Sequence[BaseChatMessage] | None = None,
    **kwargs,
) -> TaskResult
```

Any additional keyword arguments are passed straight through to `agent_or_team.run(...)`.

<Note>
  Call `tracer.flush()` before your process exits in scripts or one-shot jobs.
  In long-running servers it is not required: traces drain automatically in the
  background.
</Note>
