Skip to main content

traceAI-ag2-classic

Send AG2 Classic traces to Future AGI. AG2 Classic is the autogen distribution at 0.14.x, imported as autogen, from ag2ai/ag2classic. It ships its own OpenTelemetry instrumentation, autogen.opentelemetry. This package turns that on against a Future AGI tracer provider and maps its span attributes to Future AGI conventions. Alpha. Validated against fixtures and a loopback fake model, and re-verified 2026-10-16 end to end against a local Future AGI stack with a real model (autogen 0.14.1 and 0.14.0).

You installed Import Package
autogen 0.14.x autogen traceAI-ag2-classic (this package)
ag2 1.x ag2 traceAI-ag2
autogen-agentchat autogen_agentchat (Microsoft AutoGen) traceAI-autogen
pyautogen older alias not supported

Supported: autogen 0.14.0 and 0.14.1. Upstream ag2ai/ag2classic at 86fa5ccb3f9424cee87edb4a9ea58f191ea958ba, Apache-2.0, copyright AG2ai. autogen is a normal dependency (>=0.14.0,<0.15); it is never vendored.

Note on 0.14.0: PyPI autogen==0.14.0 is a small alias whose only requirement is ag2==0.14.0, and the autogen module is shipped by that ag2 0.14.0 distribution. Its autogen/opentelemetry tree is identical to 0.14.1's, so the version guard accepts exactly that pairing. autogen==0.14.1 ships the module itself and installs no ag2. ag2 1.x ships only an ag2 module.

Install

pip install traceAI-ag2-classic "autogen[openai]"

traceAI-ag2-classic pins autogen to >=0.14.0,<0.15. Plain autogen installs no model client; the openai extra adds the OpenAI client the quick start below needs (without it, creating an agent with an llm_config raises ImportError: ... 'openai' is not installed). For another provider, use its extra instead or as well, for example "autogen[anthropic]" or "autogen[gemini]".

autogen[openai,tracing] also works. The tracing extra adds opentelemetry-sdk and the OTLP gRPC exporter; this package never constructs that exporter.

export FI_API_KEY="YOUR_API_KEY"
export FI_SECRET_KEY="YOUR_SECRET_KEY"
export FI_PROJECT_NAME="my-chatbot"

Set up

from autogen import ConversableAgent
from fi_instrumentation import register
from fi_instrumentation.fi_types import ProjectType
from traceai_ag2_classic import setup

trace_provider = register(
    project_type=ProjectType.OBSERVE,
    project_name="my-chatbot",
)

assistant = ConversableAgent("assistant", llm_config={"config_list": [{"model": "gpt-4o-mini"}]})
user = ConversableAgent("user", llm_config=False, human_input_mode="NEVER")

tracing = setup(tracer_provider=trace_provider, agents=[assistant, user])
user.initiate_chat(assistant, message="Hello", max_turns=2)

trace_provider.force_flush()  # short scripts: flush before exit

Upstream instruments agents per instance, so pass every agent you want traced, or call tracing.instrument_agent(agent) for agents created later. Pass a GroupChatManager and its group chat members and speaker selection are instrumented too. Pass group patterns with patterns=[...] or tracing.instrument_pattern(pattern). tracing.instrument_a2a_server(server) is available only when upstream exports it (the autogen[a2a] extra); it is never called unless you ask.

setup():

  1. Checks that autogen is AG2 Classic 0.14.x. It raises AG2ClassicCompatibilityError, naming the packages above, when autogen is missing (for example only ag2 1.x or Microsoft AutoGen is installed), when the version is not 0.14.x, when autogen.opentelemetry is missing, or when the autogen module comes from pyautogen or from ag2 outside the 0.14.0 alias pairing.
  2. Puts AG2ClassicSpanProcessor first on the provider you pass, ahead of the Future AGI exporter.
  3. Calls upstream instrument_llm_wrapper(capture_messages=...) (on unless every content side is hidden), then instrument_agent and instrument_pattern for what you pass. If one of those raises (for example a non-agent in agents=), setup() restores OpenAIWrapper.create and re-raises.

It never creates a provider, never sets the global provider, and never adds an exporter. One provider, the one register() returned. HTTP to the collector is the default; pass transport=Transport.GRPC (from fi_instrumentation.otel) to register() for gRPC. Do not also install the [tracing] extra's gRPC exporter as a global provider, or spans are duplicated.

tracing.uninstrument() restores OpenAIWrapper.create, so no new LLM spans. If another library wrapped OpenAIWrapper.create after setup(), that wrapper is left in place and a WARNING is logged; call uninstrument() again once it is removed. Agents stay instrumented; upstream has no per-agent undo. The processor stays on the provider, so spans from those agents still have content removed and aggregate usage moved off non-LLM spans. It is shared by every handle on that provider and shuts down with trace_provider.shutdown().

Conformance

Every row was read from autogen/opentelemetry/instrumentators/ at 0.14.1. LLM, agent, tool, conversation, group-chat speaker selection, pattern and initiate_chats spans are exercised by real autogen runs against a loopback fake model in tests/; code execution, human input and remote-agent spans are covered by mapping unit tests only.

Field What you get When it is omitted
Span kind gen_ai.span.kind from upstream ag2.span.type: llm → LLM; agent → AGENT; tool, code_execution → TOOL; conversation, multi_conversation, speaker_selection, human_input → CHAIN; handoff → CHAIN (declared upstream as TODO, never emitted at 0.14.x). ag2.span.type and gen_ai.operation.name are kept. The a2a-execution span from instrument_a2a_server has no ag2.span.type and gets no kind.
Model, provider gen_ai.request.model, gen_ai.provider.name on LLM, agent and conversation spans; gen_ai.response.model on LLM spans. Upstream keys, passed through. Agents without an LLM config carry no model or provider.
Tokens gen_ai.usage.input_tokens, gen_ai.usage.output_tokens on LLM spans (from the response usage), plus gen_ai.usage.total_tokens added here. A response without usage gives no token keys. Conversation spans carry upstream's aggregate input/output tokens for the whole chat. Future AGI sums tokens over every span in a trace, so those move to ag2.usage.input_tokens / ag2.usage.output_tokens; each LLM call counts once.
Cost gen_ai.cost.total on LLM spans, copied from upstream gen_ai.usage.cost (AG2's own price table) when it is above 0. AG2 reports 0 for a model its price table lacks (it logs "The cost will be 0"); that 0 is not copied, so Future AGI prices the call from its tokens and its own model table. Upstream also reports response.cost on a cache hit (oai/client.py:1230-1241 returns the cached response with its stored cost), so with cache_seed set a cached reply carries the cost of the original call and Future AGI over-reports cost for cached responses; its token counts are the original call's too. Not fixed here; upstream behaviour. Conversation spans carry upstream's aggregate gen_ai.usage.cost; it moves to ag2.usage.cost, so no gen_ai.usage.* or gen_ai.cost.total key is left on any non-LLM span.
Session session.id from upstream gen_ai.conversation.id (ChatResult.chat_id) on the outermost conversation span. Inside using_session(...) or using_attributes(session_id=...) (from fi_instrumentation), that id is set on every AG2 span instead and wins over the chat id. Only conversation spans from initiate_chat / a_initiate_chat keep their chat id in gen_ai.conversation.id; every other AG2 span (LLM, agent, tool, initiate_chats, resumed conversations) carries the session id there, as Future AGI's own tracer does. Nested chats (for example the internal chat behind group-chat speaker selection, or an inner chat a tool starts) keep gen_ai.conversation.id but get no session.id. Child spans end before the chat id exists, so only the conversation span carries it. A GroupChatManager run emits no own conversation span at 0.14.x. initiate_chats gives one session per chat: each chat is its own outermost conversation, and the parent initiate_chats span (multi_conversation) has no session.id, so one trace holds several sessions. For one session over the whole call, wrap it in with using_session("..."):.
User user.id (and metadata, tag.tags) from using_user(...) / using_attributes(...), set on every AG2 span started inside it. Not emitted upstream; absent without that context.
Tools gen_ai.tool.name, gen_ai.tool.type (function), gen_ai.tool.call.id. Arguments and result (gen_ai.tool.call.arguments / .result) hidden by FI_HIDE_INPUTS (arguments) / FI_HIDE_OUTPUTS (result).
Errors Exceptions keep OTel's ERROR status. A model call that raises keeps ERROR, and upstream sets error.type to the exception class (for example BadRequestError, llm_wrapper.py:97-101); the span has no usage or cost. A failing tool is caught inside ConversableAgent.execute_function, so upstream only sets error.type=ExecutionError; this package sets status ERROR from error.type. A non-zero code exit (error.type=CodeExecutionError) also becomes ERROR.
Retrieval Not emitted upstream. Always.

Limits

  • To tell a nested chat from the outermost one, AG2ClassicSpanProcessor tracks every live span on the provider (AG2 or not) and frees each entry when its span ends. Tracking caps at 10000 live spans. The nested-session split (an inner chat getting its own session.id) returns only if that many spans leak (start and never end) or run concurrently on the provider; spans started past the cap are not tracked. Upstream ends every span it starts (with tracer.start_as_current_span(...)), so a leak needs other code on the same provider.

Privacy

Content follows the traceAI TraceConfig convention, like every traceAI instrumentor: message bodies, tool arguments and results are exported by default, and hidden with the standard variables (no package-specific switch):

export FI_HIDE_INPUTS=true        # input side: messages in, tool arguments, human prompt
export FI_HIDE_OUTPUTS=true       # output side: messages out, tool results, code output, chat summaries
# also honoured: FI_HIDE_INPUT_MESSAGES, FI_HIDE_OUTPUT_MESSAGES, FI_HIDE_INPUT_TEXT, FI_HIDE_OUTPUT_TEXT

or in code, setup(..., config=TraceConfig(hide_inputs=True, hide_outputs=True)) (from fi_instrumentation import TraceConfig). setup(..., capture_content=False) hides both sides and capture_content=True keeps both; either overrides config.

Upstream has a content flag only on instrument_llm_wrapper (capture_messages). Its agent, conversation, tool, human-input and code-execution spans always record message bodies, tool arguments and results, the human prompt and answer, code output and chat summaries. This package removes the keys of a hidden side before export. Input side: gen_ai.input.messages, gen_ai.tool.call.arguments, ag2.human_input.prompt and input.value. Output side: gen_ai.output.messages, gen_ai.tool.call.result, ag2.human_input.response, ag2.code_execution.output, ag2.chats.summaries and output.value. That is stricter than upstream. Kept content is lifted into input.value / output.value. Note that a conversation's output messages carry the whole chat history, so the prompt also appears there unless FI_HIDE_OUTPUTS is set.

Never exported in either mode: local paths, user names, host names, e-mail addresses and stack traces (spans carry the exception class in error.type and OpenTelemetry's status; checked on a real run). Exception messages from the model provider or your tool do appear in the span status text, as with any OpenTelemetry instrumentation; hide them by not putting secrets in exception messages.

The filtering lives in AG2ClassicSpanProcessor, which must run before any exporting processor. setup() keeps it first on the provider:

  • trace_provider.add_span_processor(...) after setup(): Future AGI's provider shuts down and removes every processor on the first such call after register() (fi_instrumentation/otel.py:336-339), this one included. setup() wraps that method on your provider instance, so after the call this processor is put back first and re-enabled. Your processor sees filtered spans.
  • tracing.uninstrument() leaves the processor in place, because agents instrumented earlier keep emitting spans.
  • Editing _active_span_processor._span_processors yourself, or shutting the processor down without going through trace_provider.add_span_processor, bypasses this; call setup() again to put the processor back first and re-enable it.
  • A provider built with the SDK's ConcurrentMultiSpanProcessor runs every processor's on_end in parallel, so an exporter can send a span before its content is removed. setup() logs a WARNING for it; use the default SynchronousMultiSpanProcessor, which register() uses.

Attribute inventory (autogen 0.14.1)

Paths are relative to autogen/opentelemetry/. Scope name opentelemetry.instrumentation.ag2, schema https://opentelemetry.io/schemas/1.11.0 (consts.py:25-26).

Span (name) ag2.span.type Keys emitted Source
chat {model} llm gen_ai.operation.name=chat, gen_ai.provider.name, gen_ai.request.model, gen_ai.agent.name, gen_ai.request.{temperature,max_tokens,top_p,frequency_penalty,presence_penalty}, gen_ai.response.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.response.finish_reasons, gen_ai.usage.cost, error.type; messages only if capture_messages instrumentators/llm_wrapper.py:74-135,153, utils.py:213-222
invoke_agent {agent} agent gen_ai.operation.name=invoke_agent, gen_ai.agent.name, gen_ai.provider.name, gen_ai.request.model, gen_ai.input.messages, gen_ai.output.messages (always) instrumentators/agent_instrumentators/reply.py:36-58,75-95
invoke_agent {agent} (remote) agent gen_ai.agent.remote, server.address instrumentators/agent_instrumentators/remote.py:43-48
conversation {agent} conversation gen_ai.operation.name=conversation, gen_ai.agent.name, gen_ai.provider.name, gen_ai.request.model, gen_ai.conversation.max_turns, gen_ai.input.messages, gen_ai.conversation.id, gen_ai.conversation.turns, gen_ai.output.messages, gen_ai.usage.cost, gen_ai.response.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens instrumentators/agent_instrumentators/chat.py:33-82,100-147
conversation {agent} (resume, run_chat) conversation gen_ai.conversation.resumed; run_chat: messages instrumentators/agent_instrumentators/chat.py:167-170,191-237
agent.initiate_chats / initiate_chats multi_conversation gen_ai.operation.name=initiate_chats, ag2.chats.{count,mode,recipients,ids,summaries,prerequisites} instrumentators/agent_instrumentators/chat.py:253-318
execute_tool {name} tool gen_ai.operation.name=execute_tool, gen_ai.tool.name, gen_ai.tool.type, gen_ai.tool.call.id, gen_ai.tool.call.arguments, gen_ai.tool.call.result, error.type=ExecutionError instrumentators/agent_instrumentators/tool.py:26-47,65-86
execute_code {agent} code_execution gen_ai.operation.name=execute_code, gen_ai.agent.name, ag2.code_execution.exit_code, ag2.code_execution.output, error.type=CodeExecutionError instrumentators/agent_instrumentators/code.py:43-68
await_human_input {agent} human_input gen_ai.operation.name=await_human_input, gen_ai.agent.name, ag2.human_input.prompt, ag2.human_input.response instrumentators/agent_instrumentators/human_input.py:24-32,48-55
speaker_selection speaker_selection gen_ai.operation.name=speaker_selection, ag2.speaker_selection.candidates, ag2.speaker_selection.selected instrumentators/pattern.py:163-176,193-206
a2a-execution none none instrumentators/a2a.py:61

Troubleshooting

  • No traces: register() needs project_name or FI_PROJECT_NAME; the collector drops a batch whose resource has no project_name.
  • No LLM spans after a second setup() on another provider: upstream patches OpenAIWrapper.create once and keeps the first provider (llm_wrapper.py:64-65). Call uninstrument() on the first handle first.
  • Calling trace_provider.add_span_processor(...) after register() drops Future AGI's default exporter; that is fi_instrumentation behaviour. setup() does not use it, and puts this package's processor back first when you call it (see Privacy).
  • setup() raises and names three packages: you have Microsoft AutoGen, ag2 1.x, or pyautogen instead of autogen 0.14.x.
  • Content missing: check FI_HIDE_INPUTS / FI_HIDE_OUTPUTS (and the _MESSAGES / _TEXT variants) and any TraceConfig you pass to setup().
  • Exporter errors are logged and never fail the agent.

Metadata

Release files for traceAI-ag2-classic 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for traceAI-ag2-classic 0.1.0
File Size Uploaded Provenance Actions
traceai_ag2_classic-0.1.0.tar.gz 24.4 kB With provenance Details for traceai_ag2_classic-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for traceAI-ag2-classic 0.1.0
File Interpreter ABI Platform Actions
traceai_ag2_classic-0.1.0-py3-none-any.whl Python 3 none any Details for traceai_ag2_classic-0.1.0-py3-none-any.whl

Total release size: 46.1 kB

Release files / traceai_ag2_classic-0.1.0.tar.gz

Download URL traceai_ag2_classic-0.1.0.tar.gz
Size 24.4 kB
Tags Source
SHA-256 checksum
How to use checksums
72bdca60d909659e41c81fabf330e0444d6d1fc935d4b7234638b0f9a2cf5581
BLAKE2b-256 checksum
How to use checksums
9f972feede0774f9984e68f4c00017b5241896b0d7f2e0026ac6ccdf8d85d01c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / traceai_ag2_classic-0.1.0-py3-none-any.whl

Download URL traceai_ag2_classic-0.1.0-py3-none-any.whl
Size 21.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
59939566eba0b7abea5f59a86a9135e54970eeb608d96d3fde4eeeeeff4a28e7
BLAKE2b-256 checksum
How to use checksums
9e78db7d5ba5e0dde6dde654d82d35e96e281d640158f2b62efc442c39d43532
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Security for traceAI-ag2-classic 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for traceai_ag2_classic-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page