mirror of
https://github.com/langchain-ai/langchain.git
synced 2026-10-05 09:25:14 +03:00
fix(core): don't send a default project with agent-addressed runs
When LANGSMITH_AGENT_ID / LANGSMITH_AGENT_ENVIRONMENT address runs to a LangSmith agent and no project is configured, LangChainTracer fell back to the invented "default" project and assigned it to every run. The run then carried both agent_id and session_name, which the API rejects with a 400, dropping the trace. With agent addressing active, fall back only to a project the user configured. The agent helpers are looked up with getattr since they only exist in langsmith>=0.14.0. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
38cee0db98
commit
99ff594d5e
2 files changed
+90
-1
No files matched your search
@@ -81,6 +81,27 @@ def get_client() -> Client:
|
||||
return rt.get_cached_client()
|
||||
|
||||
|
||||
def _get_default_project_name() -> str | None:
|
||||
"""Get the project to trace to when none is passed to the tracer.
|
||||
|
||||
When the environment addresses runs to a LangSmith agent
|
||||
(`LANGSMITH_AGENT_ID` / `LANGSMITH_AGENT_ENVIRONMENT`), only a project the
|
||||
user configured is returned. Falling back to the invented `'default'`
|
||||
project would send it alongside the agent, and the API rejects a run
|
||||
addressed to both.
|
||||
|
||||
Agent addressing requires `langsmith>=0.14.0`; older versions have no agent
|
||||
to address, so the helpers are looked up rather than imported.
|
||||
"""
|
||||
get_agent_id = getattr(ls_utils, "get_tracer_agent_id", None)
|
||||
get_agent_environment = getattr(ls_utils, "get_tracer_agent_environment", None)
|
||||
if (get_agent_id is not None and get_agent_id() is not None) or (
|
||||
get_agent_environment is not None and get_agent_environment() is not None
|
||||
):
|
||||
return ls_utils.get_tracer_project(return_default_value=False)
|
||||
return ls_utils.get_tracer_project()
|
||||
|
||||
|
||||
def _get_executor() -> ThreadPoolExecutor:
|
||||
"""Get the executor."""
|
||||
global _EXECUTOR # noqa: PLW0603
|
||||
@@ -168,7 +189,7 @@ class LangChainTracer(BaseTracer):
|
||||
self.example_id = (
|
||||
UUID(example_id) if isinstance(example_id, str) else example_id
|
||||
)
|
||||
self.project_name = project_name or ls_utils.get_tracer_project()
|
||||
self.project_name = project_name or _get_default_project_name()
|
||||
self.client = client or get_client()
|
||||
self.tags = tags or []
|
||||
self.latest_run: Run | None = None
|
||||
|
||||
@@ -8,6 +8,7 @@ from uuid import UUID
|
||||
|
||||
import pytest
|
||||
from langsmith import Client
|
||||
from langsmith import utils as ls_utils
|
||||
from langsmith.run_trees import RunTree
|
||||
from langsmith.utils import get_env_var, get_tracer_project
|
||||
|
||||
@@ -154,6 +155,73 @@ def test_correct_get_tracer_project(
|
||||
assert projects == [expected_project_name]
|
||||
|
||||
|
||||
def _clear_tracer_env_caches() -> None:
|
||||
getters: tuple[Any, ...] = (
|
||||
get_env_var,
|
||||
get_tracer_project,
|
||||
getattr(ls_utils, "get_tracer_agent_id", None),
|
||||
getattr(ls_utils, "get_tracer_agent_environment", None),
|
||||
)
|
||||
for getter in getters:
|
||||
if hasattr(getter, "cache_clear"):
|
||||
getter.cache_clear()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("envvars", "expected_project_name"),
|
||||
[
|
||||
({"LANGSMITH_AGENT_ID": "my-agent"}, None),
|
||||
({"LANGSMITH_AGENT_ENVIRONMENT": "development"}, None),
|
||||
(
|
||||
{
|
||||
"LANGSMITH_AGENT_ID": "my-agent",
|
||||
"LANGSMITH_AGENT_ENVIRONMENT": "development",
|
||||
},
|
||||
None,
|
||||
),
|
||||
(
|
||||
{
|
||||
"LANGSMITH_AGENT_ID": "my-agent",
|
||||
"LANGSMITH_AGENT_ENVIRONMENT": "development",
|
||||
"LANGSMITH_PROJECT": "configured",
|
||||
},
|
||||
"configured",
|
||||
),
|
||||
],
|
||||
ids=[
|
||||
"no 'default' project with agent id",
|
||||
"no 'default' project with agent environment",
|
||||
"no 'default' project with agent pair",
|
||||
"keep a configured project with agent pair",
|
||||
],
|
||||
)
|
||||
def test_tracer_project_with_agent_addressing(
|
||||
envvars: dict[str, str], expected_project_name: str | None
|
||||
) -> None:
|
||||
if not hasattr(ls_utils, "get_tracer_agent_environment"):
|
||||
pytest.skip("agent addressing requires langsmith>=0.14.0")
|
||||
_clear_tracer_env_caches()
|
||||
try:
|
||||
with pytest.MonkeyPatch.context() as mp:
|
||||
for k in (
|
||||
"LANGSMITH_PROJECT",
|
||||
"LANGCHAIN_PROJECT",
|
||||
"LANGCHAIN_SESSION",
|
||||
"HOSTED_LANGSERVE_PROJECT_NAME",
|
||||
"LANGSMITH_AGENT_ID",
|
||||
"LANGSMITH_AGENT_ENVIRONMENT",
|
||||
):
|
||||
mp.delenv(k, raising=False)
|
||||
for k, v in envvars.items():
|
||||
mp.setenv(k, v)
|
||||
|
||||
tracer = LangChainTracer(client=unittest.mock.MagicMock(spec=Client))
|
||||
assert tracer.project_name == expected_project_name
|
||||
finally:
|
||||
# The env getters are cached, so leave nothing behind for later tests.
|
||||
_clear_tracer_env_caches()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("generations", "expected"),
|
||||
[
|
||||
|
||||
Reference in new issue
Block a user