Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/loongsuite_lint_0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:
shell: bash
env:
LOONGSUITE_ALL_JOBS: >-
[{"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-agno", "package": "loongsuite-instrumentation-agno", "tox_env": "lint-loongsuite-instrumentation-agno", "ui_name": "loongsuite-instrumentation-agno"}, {"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-deepagents", "package": "loongsuite-instrumentation-deepagents", "tox_env": "lint-loongsuite-instrumentation-deepagents", "ui_name": "loongsuite-instrumentation-deepagents"}, {"name": "lint-loongsuite-instrumentation-microsoft-agent-framework", "package": "loongsuite-instrumentation-microsoft-agent-framework", "tox_env": "lint-loongsuite-instrumentation-microsoft-agent-framework", "ui_name": "loongsuite-instrumentation-microsoft-agent-framework"}, {"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-hermes-agent", "package": "loongsuite-instrumentation-hermes-agent", "tox_env": "lint-loongsuite-instrumentation-hermes-agent", "ui_name": "loongsuite-instrumentation-hermes-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"}, {"name": "lint-loongsuite-instrumentation-algotune", "package": "loongsuite-instrumentation-algotune", "tox_env": "lint-loongsuite-instrumentation-algotune", "ui_name": "loongsuite-instrumentation-algotune"}, {"name": "lint-loongsuite-instrumentation-bfclv4", "package": "loongsuite-instrumentation-bfclv4", "tox_env": "lint-loongsuite-instrumentation-bfclv4", "ui_name": "loongsuite-instrumentation-bfclv4"}, {"name": "lint-loongsuite-instrumentation-claw-eval", "package": "loongsuite-instrumentation-claw-eval", "tox_env": "lint-loongsuite-instrumentation-claw-eval", "ui_name": "loongsuite-instrumentation-claw-eval"}, {"name": "lint-loongsuite-instrumentation-minisweagent", "package": "loongsuite-instrumentation-minisweagent", "tox_env": "lint-loongsuite-instrumentation-minisweagent", "ui_name": "loongsuite-instrumentation-minisweagent"}, {"name": "lint-loongsuite-instrumentation-openhands", "package": "loongsuite-instrumentation-openhands", "tox_env": "lint-loongsuite-instrumentation-openhands", "ui_name": "loongsuite-instrumentation-openhands"}, {"name": "lint-loongsuite-instrumentation-slop-code", "package": "loongsuite-instrumentation-slop-code", "tox_env": "lint-loongsuite-instrumentation-slop-code", "ui_name": "loongsuite-instrumentation-slop-code"}, {"name": "lint-loongsuite-instrumentation-terminus2", "package": "loongsuite-instrumentation-terminus2", "tox_env": "lint-loongsuite-instrumentation-terminus2", "ui_name": "loongsuite-instrumentation-terminus2"}, {"name": "lint-loongsuite-instrumentation-vita", "package": "loongsuite-instrumentation-vita", "tox_env": "lint-loongsuite-instrumentation-vita", "ui_name": "loongsuite-instrumentation-vita"}, {"name": "lint-loongsuite-instrumentation-webarena", "package": "loongsuite-instrumentation-webarena", "tox_env": "lint-loongsuite-instrumentation-webarena", "ui_name": "loongsuite-instrumentation-webarena"}, {"name": "lint-loongsuite-instrumentation-widesearch", "package": "loongsuite-instrumentation-widesearch", "tox_env": "lint-loongsuite-instrumentation-widesearch", "ui_name": "loongsuite-instrumentation-widesearch"}, {"name": "lint-loongsuite-instrumentation-wildtool", "package": "loongsuite-instrumentation-wildtool", "tox_env": "lint-loongsuite-instrumentation-wildtool", "ui_name": "loongsuite-instrumentation-wildtool"}]
[{"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-agno", "package": "loongsuite-instrumentation-agno", "tox_env": "lint-loongsuite-instrumentation-agno", "ui_name": "loongsuite-instrumentation-agno"}, {"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-autogen", "package": "loongsuite-instrumentation-autogen", "tox_env": "lint-loongsuite-instrumentation-autogen", "ui_name": "loongsuite-instrumentation-autogen"}, {"name": "lint-loongsuite-instrumentation-deepagents", "package": "loongsuite-instrumentation-deepagents", "tox_env": "lint-loongsuite-instrumentation-deepagents", "ui_name": "loongsuite-instrumentation-deepagents"}, {"name": "lint-loongsuite-instrumentation-microsoft-agent-framework", "package": "loongsuite-instrumentation-microsoft-agent-framework", "tox_env": "lint-loongsuite-instrumentation-microsoft-agent-framework", "ui_name": "loongsuite-instrumentation-microsoft-agent-framework"}, {"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-hermes-agent", "package": "loongsuite-instrumentation-hermes-agent", "tox_env": "lint-loongsuite-instrumentation-hermes-agent", "ui_name": "loongsuite-instrumentation-hermes-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"}, {"name": "lint-loongsuite-instrumentation-algotune", "package": "loongsuite-instrumentation-algotune", "tox_env": "lint-loongsuite-instrumentation-algotune", "ui_name": "loongsuite-instrumentation-algotune"}, {"name": "lint-loongsuite-instrumentation-bfclv4", "package": "loongsuite-instrumentation-bfclv4", "tox_env": "lint-loongsuite-instrumentation-bfclv4", "ui_name": "loongsuite-instrumentation-bfclv4"}, {"name": "lint-loongsuite-instrumentation-claw-eval", "package": "loongsuite-instrumentation-claw-eval", "tox_env": "lint-loongsuite-instrumentation-claw-eval", "ui_name": "loongsuite-instrumentation-claw-eval"}, {"name": "lint-loongsuite-instrumentation-minisweagent", "package": "loongsuite-instrumentation-minisweagent", "tox_env": "lint-loongsuite-instrumentation-minisweagent", "ui_name": "loongsuite-instrumentation-minisweagent"}, {"name": "lint-loongsuite-instrumentation-openhands", "package": "loongsuite-instrumentation-openhands", "tox_env": "lint-loongsuite-instrumentation-openhands", "ui_name": "loongsuite-instrumentation-openhands"}, {"name": "lint-loongsuite-instrumentation-slop-code", "package": "loongsuite-instrumentation-slop-code", "tox_env": "lint-loongsuite-instrumentation-slop-code", "ui_name": "loongsuite-instrumentation-slop-code"}, {"name": "lint-loongsuite-instrumentation-terminus2", "package": "loongsuite-instrumentation-terminus2", "tox_env": "lint-loongsuite-instrumentation-terminus2", "ui_name": "loongsuite-instrumentation-terminus2"}, {"name": "lint-loongsuite-instrumentation-vita", "package": "loongsuite-instrumentation-vita", "tox_env": "lint-loongsuite-instrumentation-vita", "ui_name": "loongsuite-instrumentation-vita"}, {"name": "lint-loongsuite-instrumentation-webarena", "package": "loongsuite-instrumentation-webarena", "tox_env": "lint-loongsuite-instrumentation-webarena", "ui_name": "loongsuite-instrumentation-webarena"}, {"name": "lint-loongsuite-instrumentation-widesearch", "package": "loongsuite-instrumentation-widesearch", "tox_env": "lint-loongsuite-instrumentation-widesearch", "ui_name": "loongsuite-instrumentation-widesearch"}, {"name": "lint-loongsuite-instrumentation-wildtool", "package": "loongsuite-instrumentation-wildtool", "tox_env": "lint-loongsuite-instrumentation-wildtool", "ui_name": "loongsuite-instrumentation-wildtool"}]
LOONGSUITE_FULL: ${{ steps.detect.outputs.full }}
LOONGSUITE_PACKAGES: ${{ steps.detect.outputs.packages }}
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/loongsuite_test_0.yml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Fixed

- Avoid enriching non-AutoGen spans that use overlapping GenAI operation names.

## Version 0.7.0 (2026-07-03)

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

from .config import is_agent_span_enabled, is_llm_span_enabled
from .semantic_conventions import (
AUTOGEN_LIVE_SPAN_MARKER,
AUTOGEN_PROVIDER_NAME,
GEN_AI_OPERATION_NAME,
GEN_AI_PROVIDER_NAME,
Expand Down Expand Up @@ -239,6 +240,16 @@ def _apply_invoke_agent_attrs(
logger.debug("AutoGen invoke_agent span enrichment failed: %s", exc)


def _mark_autogen_live_span(invocation: Any) -> None:
span = getattr(invocation, "span", None)
if span is None:
return
try:
setattr(span, AUTOGEN_LIVE_SPAN_MARKER, AUTOGEN_PROVIDER_NAME)
except Exception:
pass


def _model_client_arg(
args: tuple[Any, ...], kwargs: dict[str, Any], name: str
) -> Any:
Expand Down Expand Up @@ -433,6 +444,7 @@ async def _direct_model_create_wrapper(wrapped, instance, args, kwargs): # type
handler = _get_handler()
invocation = _make_direct_model_invocation(instance, args, kwargs)
handler.start_llm(invocation)
_mark_autogen_live_span(invocation)
try:
result = await wrapped(*args, **kwargs)
apply_create_result(invocation, result)
Expand All @@ -453,6 +465,7 @@ async def _generator(): # type: ignore[no-untyped-def]
handler = _get_handler()
invocation = _make_direct_model_invocation(instance, args, kwargs)
handler.start_llm(invocation)
_mark_autogen_live_span(invocation)
try:
async for item in wrapped(*args, **kwargs):
if (
Expand Down Expand Up @@ -511,6 +524,7 @@ async def _generator(): # type: ignore[no-untyped-def]
output_type=output_type,
)
handler.start_llm(invocation)
_mark_autogen_live_span(invocation)
try:
async for item in _contextual_async_iter(
wrapped(*args, **kwargs),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class GenAIOperation:


AUTOGEN_PROVIDER_NAME: Final = "autogen"
AUTOGEN_LIVE_SPAN_MARKER: Final = "_loongsuite_autogen_framework"

GEN_AI_AGENT_DESCRIPTION: Final = "gen_ai.agent.description"
GEN_AI_AGENT_ID: Final = "gen_ai.agent.id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@

import logging
import threading
from typing import Any, Optional
from typing import Any, Mapping, Optional

from opentelemetry.context import Context
from opentelemetry.sdk.trace import SpanProcessor
from opentelemetry.trace import Span as OtelSpan
from opentelemetry.trace import SpanKind

from .semantic_conventions import (
AUTOGEN_LIVE_SPAN_MARKER,
AUTOGEN_PROVIDER_NAME,
GEN_AI_AGENT_DESCRIPTION,
GEN_AI_AGENT_ID,
GEN_AI_AGENT_NAME,
GEN_AI_OPERATION_NAME,
GEN_AI_PROVIDER_NAME,
GEN_AI_SPAN_KIND,
Expand All @@ -42,9 +46,39 @@
f"{GenAIOperation.EXECUTE_TOOL} ",
f"{GenAIOperation.INVOKE_AGENT} ",
)
_AUTOGEN_PRIVATE_ATTRS = frozenset(
{
"autogen.code.block_count",
"autogen.code.exit_code",
"autogen.code.retry_attempt",
"autogen.handoff.context_count",
"autogen.handoff.source",
"autogen.handoff.target",
"autogen.memory.result_count",
"autogen.team.message_count",
"autogen.team.participants",
"autogen.team.stop_reason",
"autogen.team.type",
"autogen.user_input.request_id",
}
)
_CREATE_AGENT_LIFECYCLE_ATTRS = (
GEN_AI_AGENT_DESCRIPTION,
GEN_AI_AGENT_ID,
GEN_AI_AGENT_NAME,
GEN_AI_OPERATION_NAME,
GEN_AI_PROVIDER_NAME,
GEN_AI_SPAN_KIND,
GEN_AI_SYSTEM,
"gen_ai.agent.version",
"gen_ai.system_instructions",
"gen_ai.tool.definitions",
)


def _attr_value(span: Any, key: str) -> Any:
if isinstance(span, Mapping):
return span.get(key)
attrs = getattr(span, "_attributes", None)
if attrs is not None:
try:
Expand All @@ -57,6 +91,46 @@ def _attr_value(span: Any, key: str) -> Any:
return None


def _attr_values(value: Any) -> tuple[str, ...]:
if value is None:
return ()
if isinstance(value, (list, tuple)):
values = value
else:
values = (value,)
return tuple(str(item).lower() for item in values if item is not None)


def _span_attrs(span: Any) -> Mapping[Any, Any]:
if isinstance(span, Mapping):
return span
attrs = getattr(span, "_attributes", None)
if attrs is not None:
return attrs
attrs = getattr(span, "attributes", None)
if attrs is not None:
return attrs
return {}


def _has_live_autogen_marker(live: Any | None) -> bool:
if live is None:
return False
return (
getattr(live, AUTOGEN_LIVE_SPAN_MARKER, None) == AUTOGEN_PROVIDER_NAME
)


def _has_autogen_marker(readable: Any, live: Any | None = None) -> bool:
if _has_live_autogen_marker(live):
return True
for key in (GEN_AI_SYSTEM, GEN_AI_PROVIDER_NAME):
if AUTOGEN_PROVIDER_NAME in _attr_values(_attr_value(readable, key)):
return True
attrs = _span_attrs(readable)
return any(str(key) in _AUTOGEN_PRIVATE_ATTRS for key in attrs)


def _set_attr(live_span: OtelSpan, key: str, value: Any) -> None:
if value is None:
return
Expand Down Expand Up @@ -138,19 +212,9 @@ def _set_otel_span_kind(


def _is_autogen_span(
name: str, operation: Optional[str], readable: Any
_name: str, _operation: Optional[str], readable: Any, live: Any | None
) -> bool:
if _attr_value(readable, GEN_AI_SYSTEM) == AUTOGEN_PROVIDER_NAME:
return True
if _attr_value(readable, GEN_AI_PROVIDER_NAME) == AUTOGEN_PROVIDER_NAME:
return True
if operation in {
GenAIOperation.CREATE_AGENT,
GenAIOperation.EXECUTE_TOOL,
GenAIOperation.INVOKE_AGENT,
}:
return True
return name.startswith(_AUTOGEN_NAME_PREFIXES)
return _has_autogen_marker(readable, live)


def _classify_span(
Expand Down Expand Up @@ -208,10 +272,15 @@ def on_end(self, span: Any) -> None:
name = span.name or ""
existing_op = _attr_value(span, GEN_AI_OPERATION_NAME)
operation = existing_op if isinstance(existing_op, str) else None
if not _is_autogen_span(name, operation, span):
if not _is_autogen_span(name, operation, span, live):
return

span_kind, op_name = _classify_span(name, operation)
if op_name == GenAIOperation.CREATE_AGENT:
for attr_name in _CREATE_AGENT_LIFECYCLE_ATTRS:
_delete_attr_on_both(live, span, attr_name)
return

if span_kind and not _attr_value(span, GEN_AI_SPAN_KIND):
_set_attr_on_both(live, span, GEN_AI_SPAN_KIND, span_kind)
if not operation:
Expand All @@ -235,7 +304,11 @@ def on_end(self, span: Any) -> None:

if span_kind == GenAISpanKind.LLM:
_set_otel_span_kind(live, span, SpanKind.CLIENT)
elif span_kind in {GenAISpanKind.AGENT, GenAISpanKind.TOOL}:
elif span_kind == GenAISpanKind.AGENT and op_name == (
GenAIOperation.INVOKE_AGENT
):
_set_otel_span_kind(live, span, SpanKind.INTERNAL)
elif span_kind == GenAISpanKind.TOOL:
_set_otel_span_kind(live, span, SpanKind.INTERNAL)
except Exception as exc: # pragma: no cover - defensive
logger.warning("AutoGenSemanticProcessor.on_end failed: %s", exc)
Expand Down
Loading
Loading