Skip to content

Commit 651c3a3

Browse files
committed
fix(deepagents): register scoped LoongSuite CI
1 parent f023588 commit 651c3a3

8 files changed

Lines changed: 152 additions & 9 deletions

File tree

.github/workflows/loongsuite_lint_0.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jobs:
8484
shell: bash
8585
env:
8686
LOONGSUITE_ALL_JOBS: >-
87-
[{"name": "lint-loongsuite-instrumentation-agentscope", "package": "loongsuite-instrumentation-agentscope", "tox_env": "lint-loongsuite-instrumentation-agentscope", "ui_name": "loongsuite-instrumentation-agentscope"}, {"name": "lint-loongsuite-instrumentation-dashscope", "package": "loongsuite-instrumentation-dashscope", "tox_env": "lint-loongsuite-instrumentation-dashscope", "ui_name": "loongsuite-instrumentation-dashscope"}, {"name": "lint-loongsuite-instrumentation-claude-agent-sdk", "package": "loongsuite-instrumentation-claude-agent-sdk", "tox_env": "lint-loongsuite-instrumentation-claude-agent-sdk", "ui_name": "loongsuite-instrumentation-claude-agent-sdk"}, {"name": "lint-loongsuite-instrumentation-google-adk", "package": "loongsuite-instrumentation-google-adk", "tox_env": "lint-loongsuite-instrumentation-google-adk", "ui_name": "loongsuite-instrumentation-google-adk"}, {"name": "lint-loongsuite-instrumentation-langchain", "package": "loongsuite-instrumentation-langchain", "tox_env": "lint-loongsuite-instrumentation-langchain", "ui_name": "loongsuite-instrumentation-langchain"}, {"name": "lint-loongsuite-instrumentation-langgraph", "package": "loongsuite-instrumentation-langgraph", "tox_env": "lint-loongsuite-instrumentation-langgraph", "ui_name": "loongsuite-instrumentation-langgraph"}, {"name": "lint-loongsuite-instrumentation-qwen-agent", "package": "loongsuite-instrumentation-qwen-agent", "tox_env": "lint-loongsuite-instrumentation-qwen-agent", "ui_name": "loongsuite-instrumentation-qwen-agent"}, {"name": "lint-loongsuite-instrumentation-mem0", "package": "loongsuite-instrumentation-mem0", "tox_env": "lint-loongsuite-instrumentation-mem0", "ui_name": "loongsuite-instrumentation-mem0"}, {"name": "lint-util-genai", "package": "util-genai", "tox_env": "lint-util-genai", "ui_name": "util-genai"}, {"name": "lint-loongsuite-instrumentation-litellm", "package": "loongsuite-instrumentation-litellm", "tox_env": "lint-loongsuite-instrumentation-litellm", "ui_name": "loongsuite-instrumentation-litellm"}, {"name": "lint-loongsuite-instrumentation-crewai", "package": "loongsuite-instrumentation-crewai", "tox_env": "lint-loongsuite-instrumentation-crewai", "ui_name": "loongsuite-instrumentation-crewai"}, {"name": "lint-loongsuite-instrumentation-qwenpaw", "package": "loongsuite-instrumentation-qwenpaw", "tox_env": "lint-loongsuite-instrumentation-qwenpaw", "ui_name": "loongsuite-instrumentation-qwenpaw"}]
87+
[{"name": "lint-loongsuite-instrumentation-agentscope", "package": "loongsuite-instrumentation-agentscope", "tox_env": "lint-loongsuite-instrumentation-agentscope", "ui_name": "loongsuite-instrumentation-agentscope"}, {"name": "lint-loongsuite-instrumentation-dashscope", "package": "loongsuite-instrumentation-dashscope", "tox_env": "lint-loongsuite-instrumentation-dashscope", "ui_name": "loongsuite-instrumentation-dashscope"}, {"name": "lint-loongsuite-instrumentation-claude-agent-sdk", "package": "loongsuite-instrumentation-claude-agent-sdk", "tox_env": "lint-loongsuite-instrumentation-claude-agent-sdk", "ui_name": "loongsuite-instrumentation-claude-agent-sdk"}, {"name": "lint-loongsuite-instrumentation-google-adk", "package": "loongsuite-instrumentation-google-adk", "tox_env": "lint-loongsuite-instrumentation-google-adk", "ui_name": "loongsuite-instrumentation-google-adk"}, {"name": "lint-loongsuite-instrumentation-langchain", "package": "loongsuite-instrumentation-langchain", "tox_env": "lint-loongsuite-instrumentation-langchain", "ui_name": "loongsuite-instrumentation-langchain"}, {"name": "lint-loongsuite-instrumentation-langgraph", "package": "loongsuite-instrumentation-langgraph", "tox_env": "lint-loongsuite-instrumentation-langgraph", "ui_name": "loongsuite-instrumentation-langgraph"}, {"name": "lint-loongsuite-instrumentation-qwen-agent", "package": "loongsuite-instrumentation-qwen-agent", "tox_env": "lint-loongsuite-instrumentation-qwen-agent", "ui_name": "loongsuite-instrumentation-qwen-agent"}, {"name": "lint-loongsuite-instrumentation-deepagents", "package": "loongsuite-instrumentation-deepagents", "tox_env": "lint-loongsuite-instrumentation-deepagents", "ui_name": "loongsuite-instrumentation-deepagents"}, {"name": "lint-loongsuite-instrumentation-mem0", "package": "loongsuite-instrumentation-mem0", "tox_env": "lint-loongsuite-instrumentation-mem0", "ui_name": "loongsuite-instrumentation-mem0"}, {"name": "lint-util-genai", "package": "util-genai", "tox_env": "lint-util-genai", "ui_name": "util-genai"}, {"name": "lint-loongsuite-instrumentation-litellm", "package": "loongsuite-instrumentation-litellm", "tox_env": "lint-loongsuite-instrumentation-litellm", "ui_name": "loongsuite-instrumentation-litellm"}, {"name": "lint-loongsuite-instrumentation-crewai", "package": "loongsuite-instrumentation-crewai", "tox_env": "lint-loongsuite-instrumentation-crewai", "ui_name": "loongsuite-instrumentation-crewai"}, {"name": "lint-loongsuite-instrumentation-qwenpaw", "package": "loongsuite-instrumentation-qwenpaw", "tox_env": "lint-loongsuite-instrumentation-qwenpaw", "ui_name": "loongsuite-instrumentation-qwenpaw"}]
8888
LOONGSUITE_FULL: ${{ steps.detect.outputs.full }}
8989
LOONGSUITE_PACKAGES: ${{ steps.detect.outputs.packages }}
9090
run: |

.github/workflows/loongsuite_test_0.yml

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## Unreleased
9+
10+
## Version 0.6.0.dev
11+
12+
### Added
13+
14+
- Initial implementation of DeepAgents instrumentation.

instrumentation-loongsuite/loongsuite-instrumentation-deepagents/src/opentelemetry/instrumentation/deepagents/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
__version__ = "0.1.0"
15+
__version__ = "0.6.0.dev"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright The OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
6+
pytest
7+
8+
-e opentelemetry-instrumentation
9+
-e util/opentelemetry-util-genai
10+
-e instrumentation-loongsuite/loongsuite-instrumentation-langchain
11+
-e instrumentation-loongsuite/loongsuite-instrumentation-langgraph
12+
-e instrumentation-loongsuite/loongsuite-instrumentation-deepagents

instrumentation-loongsuite/loongsuite-instrumentation-langchain/src/opentelemetry/instrumentation/langchain/internal/_tracer.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
_GEN_AI_AGENT_NAME = "gen_ai.agent.name"
121121
_GEN_AI_AGENT_TYPE = "gen_ai.agent.type"
122122
_GEN_AI_AGENT_DESCRIPTION = "gen_ai.agent.description"
123+
_LANGGRAPH_RUN_NAME = "LangGraph"
123124

124125
# ---------------------------------------------------------------------------
125126
# _RunData — per-run bookkeeping
@@ -162,6 +163,11 @@ def _should_capture_chain_content() -> bool:
162163
return False
163164

164165

166+
def _span_start_context(parent_ctx: Context | None) -> Context:
167+
"""Use an empty context when no LangChain parent was resolved."""
168+
return parent_ctx if parent_ctx is not None else Context()
169+
170+
165171
# ---------------------------------------------------------------------------
166172
# LoongsuiteTracer
167173
# ---------------------------------------------------------------------------
@@ -326,7 +332,10 @@ def _handle_llm_start(self, run: Run) -> None:
326332
tool_defs = _extract_tool_definitions(run)
327333
if tool_defs:
328334
invocation.tool_definitions = tool_defs
329-
self._handler.start_llm(invocation, context=parent_ctx)
335+
self._handler.start_llm(
336+
invocation,
337+
context=_span_start_context(parent_ctx),
338+
)
330339
rd = _RunData(
331340
run_kind="llm",
332341
span=invocation.span,
@@ -425,7 +434,7 @@ def _resolve_langgraph_agent_name(self, run: Run) -> str:
425434
over the generic default.
426435
"""
427436
name = run.name or ""
428-
if not _has_langgraph_react_metadata(run) or name != "LangGraph":
437+
if not _has_langgraph_react_metadata(run) or name != _LANGGRAPH_RUN_NAME:
429438
return name
430439

431440
parent_id = getattr(run, "parent_run_id", None)
@@ -474,7 +483,10 @@ def _start_agent(self, run: Run) -> None:
474483
agent_name=agent_name,
475484
input_messages=input_messages,
476485
)
477-
self._handler.start_invoke_agent(invocation, context=parent_ctx)
486+
self._handler.start_invoke_agent(
487+
invocation,
488+
context=_span_start_context(parent_ctx),
489+
)
478490
_enrich_deepagents_agent_span(invocation.span, run)
479491
rd = _RunData(
480492
run_kind="agent",
@@ -494,7 +506,7 @@ def _start_chain(self, run: Run) -> None:
494506
span = self._tracer.start_span(
495507
name=f"chain {run.name}",
496508
kind=SpanKind.INTERNAL,
497-
context=parent_ctx,
509+
context=_span_start_context(parent_ctx),
498510
)
499511

500512
span.set_attribute(GEN_AI_OPERATION_NAME, "chain")
@@ -640,7 +652,10 @@ def _on_tool_start(self, run: Run) -> None:
640652
tool_call_arguments=input_str,
641653
tool_call_id=tool_call_id,
642654
)
643-
self._handler.start_execute_tool(invocation, context=parent_ctx)
655+
self._handler.start_execute_tool(
656+
invocation,
657+
context=_span_start_context(parent_ctx),
658+
)
644659
rd = _RunData(
645660
run_kind="tool",
646661
span=invocation.span,
@@ -701,7 +716,10 @@ def _on_retriever_start(self, run: Run) -> None:
701716
query = inputs.get("query") or ""
702717

703718
invocation = RetrievalInvocation(query=query)
704-
self._handler.start_retrieval(invocation, context=parent_ctx)
719+
self._handler.start_retrieval(
720+
invocation,
721+
context=_span_start_context(parent_ctx),
722+
)
705723
rd = _RunData(
706724
run_kind="retriever",
707725
span=invocation.span,
@@ -877,11 +895,14 @@ def _is_task_tool_span(span: Span | None) -> bool:
877895

878896

879897
def _is_deepagents_subagent_candidate(run: Run) -> bool:
898+
"""Detect deepagents subagent roots, preserving explicit metadata first."""
880899
metadata = getattr(run, "metadata", None) or {}
881900
if not isinstance(metadata, Mapping):
882901
return False
883902
if metadata.get("ls_agent_type") == "subagent":
884903
return True
904+
if getattr(run, "name", None) != _LANGGRAPH_RUN_NAME:
905+
return False
885906
return (
886907
metadata.get("ls_integration") == "deepagents"
887908
and _is_task_tool_span(get_current_span())

instrumentation-loongsuite/loongsuite-instrumentation-langchain/tests/test_agent_spans.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from opentelemetry.instrumentation.langchain.internal._tracer import (
2020
LoongsuiteTracer,
21+
_is_deepagents_subagent_candidate,
2122
_RunData,
2223
)
2324
from opentelemetry.instrumentation.langchain.internal._utils import (
@@ -91,6 +92,91 @@ def test_deepagents_subagent_prefers_current_task_tool_parent(
9192
assert get_current_span(context) is tool_span
9293

9394

95+
def test_deepagents_task_tool_parent_ignores_non_langgraph_runs(
96+
tracer_provider,
97+
):
98+
handler = ExtendedTelemetryHandler(tracer_provider=tracer_provider)
99+
tracer = LoongsuiteTracer(handler, tracer_provider=tracer_provider)
100+
otel_tracer = tracer_provider.get_tracer(__name__)
101+
102+
with otel_tracer.start_as_current_span("execute_tool task") as tool_span:
103+
tool_span.set_attribute("gen_ai.span.kind", "TOOL")
104+
tool_span.set_attribute("gen_ai.tool.name", "task")
105+
run = _FakeRun(
106+
"RetrievalQA",
107+
parent_run_id=uuid4(),
108+
metadata={
109+
"ls_integration": "deepagents",
110+
"lc_agent_name": "researcher",
111+
},
112+
)
113+
114+
context = tracer._get_parent_context(run)
115+
116+
assert context is None
117+
118+
119+
def test_parentless_chain_does_not_inherit_ambient_context(
120+
tracer_provider,
121+
):
122+
handler = ExtendedTelemetryHandler(tracer_provider=tracer_provider)
123+
tracer = LoongsuiteTracer(handler, tracer_provider=tracer_provider)
124+
otel_tracer = tracer_provider.get_tracer(__name__)
125+
126+
with otel_tracer.start_as_current_span("ambient") as ambient_span:
127+
run = _FakeRun("RetrievalQA")
128+
129+
tracer._on_chain_start(run)
130+
try:
131+
span = tracer._runs[run.id].span
132+
assert span.parent is None
133+
assert span.context.trace_id != ambient_span.context.trace_id
134+
finally:
135+
tracer._on_chain_end(run)
136+
137+
138+
def test_parentless_handler_spans_do_not_inherit_ambient_context(
139+
tracer_provider,
140+
):
141+
handler = ExtendedTelemetryHandler(tracer_provider=tracer_provider)
142+
tracer = LoongsuiteTracer(handler, tracer_provider=tracer_provider)
143+
otel_tracer = tracer_provider.get_tracer(__name__)
144+
cases = (
145+
(tracer._handle_llm_start, _FakeRun("ChatOpenAI")),
146+
(
147+
tracer._start_agent,
148+
_FakeRun("AgentExecutor", inputs={"input": "hello"}),
149+
),
150+
(tracer._on_tool_start, _FakeRun("search", inputs={"input": "q"})),
151+
(
152+
tracer._on_retriever_start,
153+
_FakeRun("retriever", inputs={"query": "q"}),
154+
),
155+
)
156+
157+
for start, run in cases:
158+
with otel_tracer.start_as_current_span("ambient") as ambient_span:
159+
start(run)
160+
try:
161+
span = tracer._runs[run.id].span
162+
assert span.parent is None
163+
assert span.context.trace_id != ambient_span.context.trace_id
164+
finally:
165+
tracer._runs.pop(run.id).span.end()
166+
167+
168+
def test_deepagents_explicit_subagent_metadata_bypasses_langgraph_name():
169+
run = _FakeRun(
170+
"CustomAgent",
171+
metadata={
172+
"ls_integration": "deepagents",
173+
"ls_agent_type": "subagent",
174+
},
175+
)
176+
177+
assert _is_deepagents_subagent_candidate(run)
178+
179+
94180
def test_deepagents_subagent_falls_back_to_active_task_tool_run(
95181
tracer_provider,
96182
):

tox-loongsuite.ini

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ envlist =
4848
py3{9,10,11,12,13}-test-loongsuite-instrumentation-qwen-agent-{oldest,latest}
4949
lint-loongsuite-instrumentation-qwen-agent
5050

51+
; loongsuite-instrumentation-deepagents
52+
py3{10,11,12,13}-test-loongsuite-instrumentation-deepagents
53+
lint-loongsuite-instrumentation-deepagents
54+
5155
; ; loongsuite-instrumentation-mcp
5256
; py3{9,10,11,12,13}-test-loongsuite-instrumentation-mcp
5357
; lint-loongsuite-instrumentation-mcp
@@ -134,6 +138,9 @@ deps =
134138
qwen-agent-latest: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-qwen-agent/tests/requirements.latest.txt
135139
lint-loongsuite-instrumentation-qwen-agent: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-qwen-agent/tests/requirements.oldest.txt
136140

141+
loongsuite-instrumentation-deepagents: {[testenv]test_deps}
142+
loongsuite-instrumentation-deepagents: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-deepagents/tests/test-requirements.txt
143+
137144
mcp: {[testenv]test_deps}
138145
mcp: -r {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mcp/test-requirements.txt
139146

@@ -203,6 +210,9 @@ commands =
203210
test-loongsuite-instrumentation-qwen-agent: pytest {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-qwen-agent/tests {posargs}
204211
lint-loongsuite-instrumentation-qwen-agent: python -m ruff check {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-qwen-agent
205212

213+
test-loongsuite-instrumentation-deepagents: pytest {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-deepagents/tests {posargs}
214+
lint-loongsuite-instrumentation-deepagents: python -m ruff check {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-deepagents
215+
206216
test-loongsuite-instrumentation-mcp: pytest {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mcp/tests {posargs}
207217
lint-loongsuite-instrumentation-mcp: python -m ruff check {toxinidir}/instrumentation-loongsuite/loongsuite-instrumentation-mcp
208218

0 commit comments

Comments
 (0)