fix(cli): suppress LangSmith trace for _context_tokens state writes (#3317)

`_context_tokens` is declared with `PrivateStateAttr`, which keeps it
out of the graph's input/output schemas, but `Pregel.aupdate_state`
still emits its own top-level `UpdateState` run on every turn — so the
count surfaces as a noisy standalone trace in LangSmith on each LLM
response and offload.

Wrap the `aupdate_state` call in `_persist_context_tokens` with
`langsmith.tracing_context(enabled=False)` so the internal bookkeeping
write is fully suppressed from the active LangSmith project while still
being checkpointed for thread resume.

_Opened collaboratively by Mason Daugherty and open-swe._

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Mason Daugherty <61371264+mdrxy@users.noreply.github.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
This commit is contained in:
open-swe[bot]
2026-05-11 22:44:48 -07:00
committed by GitHub
parent 75d60cd82f
commit 63db13ee26
2 changed files with 35 additions and 1 deletions
+10 -1
View File
@@ -1432,13 +1432,22 @@ async def _persist_context_tokens(
) -> None:
"""Best-effort persist of the context token count into graph state.
The `aupdate_state` call is wrapped in `tracing_context(enabled=False)` so
this purely-internal bookkeeping write does not surface as a separate
`UpdateState` run in LangSmith. `_context_tokens` is already marked
`PrivateStateAttr`, but `aupdate_state` itself creates its own traced run
that would otherwise clutter the project's traces.
Args:
agent: The LangGraph agent (must support `aupdate_state`).
config: Runnable config with `thread_id`.
tokens: Total context tokens to persist.
"""
from langsmith import tracing_context
try:
await agent.aupdate_state(config, {"_context_tokens": tokens})
with tracing_context(enabled=False):
await agent.aupdate_state(config, {"_context_tokens": tokens})
except (httpx.TransportError, httpx.TimeoutException) as e:
logger.warning(
"Could not persist _context_tokens=%d (network): %s; "
@@ -123,3 +123,28 @@ class TestPersistContextTokens:
# Should not raise
await _persist_context_tokens(agent, config, 1000) # type: ignore[arg-type]
async def test_disables_tracing_during_update(self):
"""`aupdate_state` should run with LangSmith tracing disabled.
The token-count write is a private bookkeeping update; surfacing it as a
standalone `UpdateState` run in LangSmith clutters traces.
"""
from unittest.mock import AsyncMock
from langsmith import get_tracing_context
from deepagents_cli.textual_adapter import _persist_context_tokens
captured: dict[str, object] = {}
async def _capture(*_args: object, **_kwargs: object) -> None: # noqa: RUF029 # AsyncMock side_effect must be a coroutine function
captured["enabled"] = get_tracing_context().get("enabled")
agent = AsyncMock()
agent.aupdate_state.side_effect = _capture
config = {"configurable": {"thread_id": "t-1"}}
await _persist_context_tokens(agent, config, 4200) # type: ignore[arg-type]
assert captured["enabled"] is False