Skip to content

fix(sdk): restore the previous context when an entity span ends (#4378) - #4395

Open
Anai-Guo wants to merge 1 commit into
traceloop:mainfrom
Anai-Guo:fix-agent-name-context-leak-4378
Open

fix(sdk): restore the previous context when an entity span ends (#4378)#4395
Anai-Guo wants to merge 1 commit into
traceloop:mainfrom
Anai-Guo:fix-agent-name-context-leak-4378

Conversation

@Anai-Guo

@Anai-Guo Anai-Guo commented Aug 2, 2026

Copy link
Copy Markdown

Fixes #4378.

Problem

_setup_span() sets the entity name with set_workflow_name() / set_agent_name(). Both do:

attach(set_value("agent_name", agent_name))

— they attach a new context and throw the token away. Nothing ever detaches it, so _cleanup_span()'s single detach(ctx_token) restores a context that still carries the entity name. The name then leaks onto every span created after the entity returns:

  • a @task run after a completed bare @agent is tagged gen_ai.agent.name = "planner"
  • a sibling @task inside the same @workflow, after a nested @agent finished, is tagged with the completed agent's name
  • the same applies to traceloop.workflow.name after a @workflow returns

Sibling work therefore appears to belong to the preceding agent in the backend.

Fix

Fold the entity name into the same context that _setup_span() attaches for the span, so the existing cleanup token restores both in one operation — no second, un-detached attach.

One subtlety worth calling out: the name has to be in the active context while tracer.start_span() runs, because the span processor's on_start (default_span_processor_on_start) reads get_value("workflow_name") / get_value("agent_name") off the current context, not off the span's parent context. Passing context= to start_span would not be enough. So the entity context is attached just around the start_span() call, detached immediately (properly nested), and then folded into the long-lived context that is attached for the span's children.

set_workflow_name() / set_agent_name() are public API and are left untouched.

Tests

Three regression tests added to tests/test_agent_workflow_context.py, which already covers this area:

  • test_task_after_bare_agent_is_not_tagged_with_agent_name
  • test_sibling_task_in_workflow_is_not_tagged_with_agent_name — also asserts the sibling keeps traceloop.workflow.name = "rag", per the issue's expected behavior
  • test_workflow_name_does_not_leak_after_workflow_returns

Verified against traceloop-sdk==0.62.1, whose decorators/base.py and tracing/tracing.py are byte-identical to main@93429cf:

before after
3 new tests 3 failed 3 passed
3 pre-existing tests in test_agent_workflow_context.py 3 passed 3 passed
test_class_tasks, test_conversation_id, test_nested_tasks, test_manual, test_workflows, test_privacy_no_prompts 27 passed / 5 failed 30 passed / 5 failed

The 5 remaining failures are pre-existing in my environment and identical before and after the change (VCR cassettes needing live OpenAI access, plus a timestamp assertion in test_manual). ruff check clean under the package's config (line-length = 120, select = ["E", "F", "W"]).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved context isolation for agent and workflow operations.
    • Prevented agent names from carrying over to sibling or standalone tasks.
    • Ensured workflow names remain correctly scoped and are cleared after completion.
  • Tests

    • Added regression coverage validating context restoration across agents, workflows, and tasks.

…eloop#4378)

`_setup_span` called `set_workflow_name`/`set_agent_name`, which attach a new
OTel context and drop the returned token. Nothing ever detaches it, so
`_cleanup_span`'s single detach of the span token restores a context that
still carries the entity name. Spans created after a completed `@agent`
therefore inherit `gen_ai.agent.name`, and the same applies to
`traceloop.workflow.name` after a `@workflow` returns.

Fold the entity name into the context that `_setup_span` attaches for the
span, so the existing cleanup token restores it in one operation. The name is
still active while `tracer.start_span()` runs -- the span processor's
`on_start` reads it from the active context -- so it is attached briefly
around the `start_span` call and then folded into the long-lived context.
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The decorator span setup now scopes workflow and agent names to each invocation. Regression tests cover standalone tasks, workflow siblings, and cleanup after workflow completion.

Changes

Context scoping

Layer / File(s) Summary
Scoped entity context
packages/traceloop-sdk/traceloop/sdk/decorators/base.py
_setup_span temporarily attaches entity-name context while starting a span, then detaches it before returning span context.
Context restoration regression coverage
packages/traceloop-sdk/tests/test_agent_workflow_context.py
Tests verify that agent names do not leak to later tasks, while workflow names remain available within scope and are cleared after completion.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the context restoration fix for entity spans and matches the primary change.
Linked Issues check ✅ Passed The implementation and regression tests satisfy issue #4378 by scoping agent and workflow names to the correct spans.
Out of Scope Changes check ✅ Passed The changes are limited to the context restoration implementation and regression tests required by issue #4378.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/traceloop-sdk/traceloop/sdk/decorators/base.py`:
- Around line 140-161: Update the synchronous generator path that calls
_handle_generator so it receives the context attachment token created for the
entity context. Ensure _handle_generator detaches that token and invokes
_cleanup_span in its finally block when generator execution completes,
preventing workflow or agent names from leaking to later spans. Add a regression
test covering a synchronous generator followed by a decorated `@task`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 308f3f01-a5e3-4510-8687-a74a69eb8ab6

📥 Commits

Reviewing files that changed from the base of the PR and between 93429cf and 7b2feeb.

📒 Files selected for processing (2)
  • packages/traceloop-sdk/tests/test_agent_workflow_context.py
  • packages/traceloop-sdk/traceloop/sdk/decorators/base.py

Comment on lines +140 to +161
# Build the entity name into a context value instead of attaching it on its
# own. `set_workflow_name`/`set_agent_name` attach and drop the token, so
# nothing ever restores it and the name leaks onto sibling spans created
# after this entity returns. The name still has to be in the *active*
# context while the span starts, because the span processor's `on_start`
# reads it from there -- so attach it, start the span, then fold it into the
# single long-lived context that `_cleanup_span` detaches.
entity_ctx = context_api.get_current()
if tlp_span_kind == TraceloopSpanKindValues.WORKFLOW:
set_workflow_name(entity_name)
entity_ctx = context_api.set_value("workflow_name", entity_name, entity_ctx)
elif tlp_span_kind == TraceloopSpanKindValues.AGENT:
set_agent_name(entity_name)
entity_ctx = context_api.set_value("agent_name", entity_name, entity_ctx)

span_name = f"{entity_name}.{tlp_span_kind.value}"

with get_tracer() as tracer:
span = tracer.start_span(span_name)
ctx = trace.set_span_in_context(span)
entity_token = context_api.attach(entity_ctx)
try:
span = tracer.start_span(span_name)
finally:
context_api.detach(entity_token)
ctx = trace.set_span_in_context(span, entity_ctx)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Clean up context for synchronous generator entities.

Line 161 creates a long-lived context that includes entity_ctx. The synchronous generator branch returns _handle_generator(span, res) without ctx_token. It cannot detach the attachment created at Line 162 when the generator completes.

A decorated synchronous generator can still leak its agent or workflow name to later spans. Pass ctx_token to the synchronous generator handler and call _cleanup_span in its finally block. Add a regression test for a synchronous generator followed by a @task.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/traceloop-sdk/traceloop/sdk/decorators/base.py` around lines 140 -
161, Update the synchronous generator path that calls _handle_generator so it
receives the context attachment token created for the entity context. Ensure
_handle_generator detaches that token and invokes _cleanup_span in its finally
block when generator execution completes, preventing workflow or agent names
from leaking to later spans. Add a regression test covering a synchronous
generator followed by a decorated `@task`.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: @agent leaks gen_ai.agent.name into subsequent spans

2 participants