feat(sdk-py): add langsmith_tracing param to runs.create/stream/wait (#7431)

## Summary
- Adds a `langsmith_tracing` parameter to `runs.create()`,
`runs.stream()`, and `runs.wait()` on both async and sync SDK clients
- Accepts a `LangSmithTracing` TypedDict with optional `project_name`
and `example_id` fields
- Maps to the server's existing `langsmith_tracer` payload key, enabling
users to route traces to specific LangSmith projects or associate with
dataset examples from the SDK

## Test plan
- [x] Unit tests verify payload serialization (langsmith_tracing →
langsmith_tracer mapping)
- [x] Unit tests verify key is excluded when param not provided
- [x] Unit tests verify partial configs (project_name only) work
- [x] API parity tests pass (async/sync client signatures match)
- [x] Full test suite passes (86 tests)
- [x] Lint + type check pass

Release Notes: Added `langsmith_tracing` parameter to `runs.create()`,
`runs.stream()`, and `runs.wait()` in the Python SDK, allowing users to
route traces to a specific LangSmith project or associate with a dataset
example.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Will Fu-Hinthorn <will@langchain.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
William FH
2026-04-07 12:30:53 -07:00
committed by GitHub
co-authored by Will Fu-Hinthorn Claude Opus 4.6
parent 4811d42614
commit b8540449b4
4 changed files with 198 additions and 0 deletions
+21
View File
@@ -26,6 +26,7 @@ from langgraph_sdk.schema import (
Durability,
IfNotExists,
Input,
LangSmithTracing,
MultitaskStrategy,
OnCompletionBehavior,
QueryParamTypes,
@@ -93,6 +94,7 @@ class RunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -124,6 +126,7 @@ class RunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -152,6 +155,7 @@ class RunsClient:
if_not_exists: IfNotExists | None = None,
webhook: str | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -180,6 +184,7 @@ class RunsClient:
if_not_exists: IfNotExists | None = None,
webhook: str | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -211,6 +216,7 @@ class RunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -250,6 +256,8 @@ class RunsClient:
Must be either 'reject' (raise error if missing), or 'create' (create new thread).
after_seconds: The number of seconds to wait before starting the run.
Use to schedule future runs.
langsmith_tracing: LangSmith tracing configuration. Allows routing traces
to a specific project or associating with a dataset example.
headers: Optional custom headers to include with the request.
params: Optional query parameters to include with the request.
on_run_created: Callback when a run is created.
@@ -326,6 +334,7 @@ class RunsClient:
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
"langsmith_tracer": langsmith_tracing,
}
endpoint = (
f"/threads/{thread_id}/runs/stream"
@@ -371,6 +380,7 @@ class RunsClient:
on_completion: OnCompletionBehavior | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -399,6 +409,7 @@ class RunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -427,6 +438,7 @@ class RunsClient:
if_not_exists: IfNotExists | None = None,
on_completion: OnCompletionBehavior | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -462,6 +474,8 @@ class RunsClient:
Must be either 'reject' (raise error if missing), or 'create' (create new thread).
after_seconds: The number of seconds to wait before starting the run.
Use to schedule future runs.
langsmith_tracing: LangSmith tracing configuration. Allows routing traces
to a specific project or associating with a dataset example.
headers: Optional custom headers to include with the request.
on_run_created: Optional callback to call when a run is created.
durability: The durability to use for the run. Values are "sync", "async", or "exit".
@@ -572,6 +586,7 @@ class RunsClient:
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
"langsmith_tracer": langsmith_tracing,
}
payload = {k: v for k, v in payload.items() if v is not None}
@@ -626,6 +641,7 @@ class RunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
raise_error: bool = True,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
@@ -651,6 +667,7 @@ class RunsClient:
on_completion: OnCompletionBehavior | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
raise_error: bool = True,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
@@ -678,6 +695,7 @@ class RunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
raise_error: bool = True,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
@@ -712,6 +730,8 @@ class RunsClient:
Must be either 'reject' (raise error if missing), or 'create' (create new thread).
after_seconds: The number of seconds to wait before starting the run.
Use to schedule future runs.
langsmith_tracing: LangSmith tracing configuration. Allows routing traces
to a specific project or associating with a dataset example.
headers: Optional custom headers to include with the request.
on_run_created: Optional callback to call when a run is created.
durability: The durability to use for the run. Values are "sync", "async", or "exit".
@@ -798,6 +818,7 @@ class RunsClient:
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
"langsmith_tracer": langsmith_tracing,
}
endpoint = (
f"/threads/{thread_id}/runs/wait" if thread_id is not None else "/runs/wait"
+21
View File
@@ -26,6 +26,7 @@ from langgraph_sdk.schema import (
Durability,
IfNotExists,
Input,
LangSmithTracing,
MultitaskStrategy,
OnCompletionBehavior,
QueryParamTypes,
@@ -92,6 +93,7 @@ class SyncRunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -122,6 +124,7 @@ class SyncRunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -151,6 +154,7 @@ class SyncRunsClient:
if_not_exists: IfNotExists | None = None,
webhook: str | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -180,6 +184,7 @@ class SyncRunsClient:
if_not_exists: IfNotExists | None = None,
webhook: str | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -211,6 +216,7 @@ class SyncRunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -250,6 +256,8 @@ class SyncRunsClient:
Must be either 'reject' (raise error if missing), or 'create' (create new thread).
after_seconds: The number of seconds to wait before starting the run.
Use to schedule future runs.
langsmith_tracing: LangSmith tracing configuration. Allows routing traces
to a specific project or associating with a dataset example.
headers: Optional custom headers to include with the request.
on_run_created: Optional callback to call when a run is created.
durability: The durability to use for the run. Values are "sync", "async", or "exit".
@@ -321,6 +329,7 @@ class SyncRunsClient:
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
"langsmith_tracer": langsmith_tracing,
}
endpoint = (
f"/threads/{thread_id}/runs/stream"
@@ -366,6 +375,7 @@ class SyncRunsClient:
on_completion: OnCompletionBehavior | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -394,6 +404,7 @@ class SyncRunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -422,6 +433,7 @@ class SyncRunsClient:
if_not_exists: IfNotExists | None = None,
on_completion: OnCompletionBehavior | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
@@ -457,6 +469,8 @@ class SyncRunsClient:
Must be either 'reject' (raise error if missing), or 'create' (create new thread).
after_seconds: The number of seconds to wait before starting the run.
Use to schedule future runs.
langsmith_tracing: LangSmith tracing configuration. Allows routing traces
to a specific project or associating with a dataset example.
headers: Optional custom headers to include with the request.
on_run_created: Optional callback to call when a run is created.
durability: The durability to use for the run. Values are "sync", "async", or "exit".
@@ -567,6 +581,7 @@ class SyncRunsClient:
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
"langsmith_tracer": langsmith_tracing,
}
payload = {k: v for k, v in payload.items() if v is not None}
@@ -621,6 +636,7 @@ class SyncRunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
raise_error: bool = True,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
@@ -646,6 +662,7 @@ class SyncRunsClient:
on_completion: OnCompletionBehavior | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
raise_error: bool = True,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
@@ -673,6 +690,7 @@ class SyncRunsClient:
multitask_strategy: MultitaskStrategy | None = None,
if_not_exists: IfNotExists | None = None,
after_seconds: int | None = None,
langsmith_tracing: LangSmithTracing | None = None,
raise_error: bool = True,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
@@ -707,6 +725,8 @@ class SyncRunsClient:
Must be either 'reject' (raise error if missing), or 'create' (create new thread).
after_seconds: The number of seconds to wait before starting the run.
Use to schedule future runs.
langsmith_tracing: LangSmith tracing configuration. Allows routing traces
to a specific project or associating with a dataset example.
raise_error: Whether to raise an error if the run fails.
headers: Optional custom headers to include with the request.
on_run_created: Optional callback to call when a run is created.
@@ -796,6 +816,7 @@ class SyncRunsClient:
"after_seconds": after_seconds,
"raise_error": raise_error,
"durability": durability,
"langsmith_tracer": langsmith_tracing,
}
def on_response(res: httpx.Response):
+10
View File
@@ -107,6 +107,16 @@ Durability = Literal["sync", "async", "exit"]
- `"async"`: Changes are persisted asynchronously while the next step executes.
- `"exit"`: Changes are persisted only when the graph exits."""
class LangSmithTracing(TypedDict, total=False):
"""Configuration for LangSmith tracing."""
project_name: str
"""The LangSmith project name to trace to."""
example_id: str
"""The LangSmith example/dataset ID to associate with the trace."""
All = Literal["*"]
"""Represents a wildcard or 'all' selector."""
+146
View File
@@ -0,0 +1,146 @@
"""Test that langsmith_tracing parameter is correctly mapped to langsmith_tracer in payloads."""
from __future__ import annotations
from typing import Any
from unittest.mock import AsyncMock, MagicMock
import pytest
from langgraph_sdk.schema import LangSmithTracing
@pytest.fixture
def tracing_config() -> LangSmithTracing:
return LangSmithTracing(
project_name="my-project",
example_id="example-123",
)
class TestLangSmithTracingPayload:
"""Verify langsmith_tracing param maps to langsmith_tracer in request payload."""
@pytest.mark.asyncio
async def test_async_create_includes_langsmith_tracer(self, tracing_config):
"""Test that async create sends langsmith_tracer in payload."""
from langgraph_sdk._async.runs import RunsClient
captured: dict[str, Any] = {}
async def mock_post(_path, *, json=None, **_kwargs):
captured["json"] = json
return {"run_id": "r1", "status": "pending"}
http = MagicMock()
http.post = AsyncMock(side_effect=mock_post)
client = RunsClient(http)
await client.create(
thread_id="t1",
assistant_id="a1",
langsmith_tracing=tracing_config,
)
assert "langsmith_tracer" in captured["json"]
assert captured["json"]["langsmith_tracer"] == {
"project_name": "my-project",
"example_id": "example-123",
}
def test_sync_create_includes_langsmith_tracer(self, tracing_config):
"""Test that sync create sends langsmith_tracer in payload."""
from langgraph_sdk._sync.runs import SyncRunsClient
captured: dict[str, Any] = {}
def mock_post(_path, *, json=None, **_kwargs):
captured["json"] = json
return {"run_id": "r1", "status": "pending"}
http = MagicMock()
http.post = MagicMock(side_effect=mock_post)
client = SyncRunsClient(http)
client.create(
thread_id="t1",
assistant_id="a1",
langsmith_tracing=tracing_config,
)
assert "langsmith_tracer" in captured["json"]
assert captured["json"]["langsmith_tracer"] == {
"project_name": "my-project",
"example_id": "example-123",
}
def test_sync_wait_includes_langsmith_tracer(self, tracing_config):
"""Test that sync wait sends langsmith_tracer in payload."""
from langgraph_sdk._sync.runs import SyncRunsClient
captured: dict[str, Any] = {}
def mock_request_reconnect(_path, _method, *, json=None, **_kwargs):
captured["json"] = json
return {"messages": []}
http = MagicMock()
http.request_reconnect = MagicMock(side_effect=mock_request_reconnect)
client = SyncRunsClient(http)
client.wait(
thread_id="t1",
assistant_id="a1",
langsmith_tracing=tracing_config,
)
assert "langsmith_tracer" in captured["json"]
assert captured["json"]["langsmith_tracer"] == {
"project_name": "my-project",
"example_id": "example-123",
}
def test_create_without_langsmith_tracing_excludes_key(self):
"""Test that langsmith_tracer is not in payload when not provided."""
from langgraph_sdk._sync.runs import SyncRunsClient
captured: dict[str, Any] = {}
def mock_post(_path, *, json=None, **_kwargs):
captured["json"] = json
return {"run_id": "r1", "status": "pending"}
http = MagicMock()
http.post = MagicMock(side_effect=mock_post)
client = SyncRunsClient(http)
client.create(
thread_id="t1",
assistant_id="a1",
)
assert "langsmith_tracer" not in captured["json"]
def test_langsmith_tracing_project_name_only(self):
"""Test that langsmith_tracing works with only project_name."""
from langgraph_sdk._sync.runs import SyncRunsClient
captured: dict[str, Any] = {}
def mock_post(_path, *, json=None, **_kwargs):
captured["json"] = json
return {"run_id": "r1", "status": "pending"}
http = MagicMock()
http.post = MagicMock(side_effect=mock_post)
client = SyncRunsClient(http)
client.create(
thread_id="t1",
assistant_id="a1",
langsmith_tracing={"project_name": "my-project"},
)
assert captured["json"]["langsmith_tracer"] == {
"project_name": "my-project",
}