braintrust.wrappers.agno.setup_agno() patches Agent._run/_arun/_run_stream/_arun_stream and the equivalent Team methods (braintrust/integrations/agno/patchers.py), each opening a TASK-typed span that becomes the parent for the run's llm/tool spans.
It does not patch Agent.acontinue_run/Team.acontinue_run (nor the sync continue_run). These are the entrypoints agno's AG-UI interface calls from agno.os.interfaces.agui.resume.resume_paused_run() when a paused run (e.g. one blocked on an external_execution / client-side tool, such as a UI-rendering tool the frontend executes and answers) is resumed after the client answers it.
Because no TASK span is open during that resume, the model call inside acontinue_run still gets its own llm span (that patch — Model._aresponse_stream etc. — is unaffected), but with no ambient parent span, Braintrust opens it as a brand-new trace root instead of continuing the original conversation's trace. The result: every resumed paused-run turn shows up in the UI as its own disconnected "conversation," rather than as a continuation of the one the user was actually having.
Repro: any agno AgentOS app using the AG-UI interface, with a client tool that pauses the run (external_execution=True) and setup_agno() tracing enabled. Ask the agent something that triggers the client tool, resolve the tool call from the client, and diff the trace of the initial run vs. the resumed one — they land as two separate traces sharing no root span.
Suggested fix: add a wrapper for Agent.acontinue_run/Team.acontinue_run (and the sync variants) symmetric to the existing _arun/_run wrappers, opening the same kind of TASK span. That alone won't reconnect it to the original trace across the pause — the resume happens in a separate call/request with no ambient span — so instrumenting the resume path would also need some way to recover the original run's span reference. One option: persist the exported span alongside whatever agno already tracks for the paused run's continuation state (e.g. the run's own metadata, which agno already serializes and persists), so the new TASK span for the resume can be opened with parent=<that export> instead of as a fresh root.
We worked around this downstream, in application code, by hooking into agno's run-persistence path to stash the span export on the run object and reading it back when the paused run resumes. That works, but it depends on private/internal agno symbols and duplicates work setup_agno() is already positioned to do — a fix at the setup_agno() level, with access to whatever agno tracks internally for a paused/resumed run, would be the more robust place for it.
braintrust.wrappers.agno.setup_agno()patchesAgent._run/_arun/_run_stream/_arun_streamand the equivalentTeammethods (braintrust/integrations/agno/patchers.py), each opening aTASK-typed span that becomes the parent for the run'sllm/toolspans.It does not patch
Agent.acontinue_run/Team.acontinue_run(nor the synccontinue_run). These are the entrypoints agno's AG-UI interface calls fromagno.os.interfaces.agui.resume.resume_paused_run()when a paused run (e.g. one blocked on anexternal_execution/ client-side tool, such as a UI-rendering tool the frontend executes and answers) is resumed after the client answers it.Because no TASK span is open during that resume, the model call inside
acontinue_runstill gets its ownllmspan (that patch —Model._aresponse_streametc. — is unaffected), but with no ambient parent span, Braintrust opens it as a brand-new trace root instead of continuing the original conversation's trace. The result: every resumed paused-run turn shows up in the UI as its own disconnected "conversation," rather than as a continuation of the one the user was actually having.Repro: any agno
AgentOSapp using the AG-UI interface, with a client tool that pauses the run (external_execution=True) andsetup_agno()tracing enabled. Ask the agent something that triggers the client tool, resolve the tool call from the client, and diff the trace of the initial run vs. the resumed one — they land as two separate traces sharing no root span.Suggested fix: add a wrapper for
Agent.acontinue_run/Team.acontinue_run(and the sync variants) symmetric to the existing_arun/_runwrappers, opening the same kind of TASK span. That alone won't reconnect it to the original trace across the pause — the resume happens in a separate call/request with no ambient span — so instrumenting the resume path would also need some way to recover the original run's span reference. One option: persist the exported span alongside whatever agno already tracks for the paused run's continuation state (e.g. the run's own metadata, which agno already serializes and persists), so the new TASK span for the resume can be opened withparent=<that export>instead of as a fresh root.We worked around this downstream, in application code, by hooking into agno's run-persistence path to stash the span export on the run object and reading it back when the paused run resumes. That works, but it depends on private/internal agno symbols and duplicates work
setup_agno()is already positioned to do — a fix at thesetup_agno()level, with access to whatever agno tracks internally for a paused/resumed run, would be the more robust place for it.