Feat/semconv#224
Conversation
Add a LoongSuiteResourceDetector that contributes two resource attributes to the agent: * host.ip: the local host IP combined with the process id, formatted as <ip>-<pid> (e.g. 127.0.0.1-1). * gen_ai.instrumentation.sdk.name: set to "loongsuite-genai-utils". The detector is wired into LoongSuiteConfigurator so the attributes are always present on the SDK resource. Includes unit tests for the detector (ip-pid format, fixed sdk name, fallback on socket error) and the configurator wiring. Change-Id: I7fdfd07ffa8e2021e82c1d85d7d6b527c2cf8170 Co-developed-by: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add missing GenAI semantic convention attributes across instrumentation plugins: - execute_tool spans: add tool_type="function" (Recommended) - invoke_agent spans: add agent_id (Conditionally Required) - inference spans: add server_address/server_port (Conditionally Required) - inference spans: add response_id extraction (Recommended) Plugins modified: - hermes-agent: agent_id, server_address/port from base_url, tool_type - vita: agent_id, tool_type, response_id, server_address inference - langchain: agent_id, tool_type - dashscope: server_address/port - widesearch: agent_id - agentscope: tool_type - qwen-agent: agent_id, tool_type - minisweagent: agent_id - google-adk: agent_id, tool_type - claude-agent-sdk: tool_type Change-Id: I21fc87489630d2ac6a0d9df22ef70dde60c57fff Co-developed-by: Qoder <noreply@qoder.com>
There was a problem hiding this comment.
Pull request overview
Adds/aligns GenAI semantic-convention fields across LoongSuite distro + multiple LoongSuite instrumentations, including new resource attributes and additional invocation metadata.
Changes:
- Introduces
LoongSuiteResourceDetectorand wires it intoLoongSuiteConfiguratorto inject LoongSuite resource attributes. - Adds/propagates GenAI semconv fields (
agent_id,tool_type,response_id, and someserver_address/server_port) across several instrumentations. - Adds initial unit tests for the new LoongSuite distro resource/configurator behavior.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| loongsuite-distro/src/loongsuite/distro/resource.py | Adds a resource detector that provides host.ip and gen_ai.instrumentation.sdk.name. |
| loongsuite-distro/src/loongsuite/distro/init.py | Updates configurator to inject LoongSuite resource attributes during SDK configuration. |
| loongsuite-distro/tests/test_resource.py | Adds unit tests for the resource detector and host IP detection helpers. |
| loongsuite-distro/tests/test_configurator.py | Adds unit tests asserting injected resource attributes are forwarded into SDK initialization. |
| loongsuite-distro/tests/init.py | Adds package marker for distro tests. |
| instrumentation-loongsuite/loongsuite-instrumentation-widesearch/src/opentelemetry/instrumentation/widesearch/utils.py | Populates agent_id for agent invocations. |
| instrumentation-loongsuite/loongsuite-instrumentation-vita/src/opentelemetry/instrumentation/vita/utils.py | Adds server address inference helper (currently unused). |
| instrumentation-loongsuite/loongsuite-instrumentation-vita/src/opentelemetry/instrumentation/vita/patch.py | Adds agent_id, response_id, and tool_type for Vita spans/invocations. |
| instrumentation-loongsuite/loongsuite-instrumentation-qwen-agent/src/opentelemetry/instrumentation/qwen_agent/utils.py | Populates agent_id and tool_type in invocations. |
| instrumentation-loongsuite/loongsuite-instrumentation-minisweagent/src/opentelemetry/instrumentation/minisweagent/internal/agent_wrappers.py | Populates agent_id for agent invocations. |
| instrumentation-loongsuite/loongsuite-instrumentation-langchain/src/opentelemetry/instrumentation/langchain/internal/_tracer.py | Adds agent_id and tool_type for LangChain invocations. |
| instrumentation-loongsuite/loongsuite-instrumentation-hermes-agent/src/opentelemetry/instrumentation/hermes_agent/helpers.py | Adds agent_id, infers server info from base_url, and sets tool_type. |
| instrumentation-loongsuite/loongsuite-instrumentation-google-adk/src/opentelemetry/instrumentation/google_adk/internal/_plugin.py | Adds agent_id and tool_type for Google ADK invocations. |
| instrumentation-loongsuite/loongsuite-instrumentation-dashscope/src/opentelemetry/instrumentation/dashscope/utils/generation.py | Sets server_address/server_port on DashScope LLM invocations. |
| instrumentation-loongsuite/loongsuite-instrumentation-claude-agent-sdk/src/opentelemetry/instrumentation/claude_agent_sdk/patch.py | Populates tool_type for tool spans. |
| instrumentation-loongsuite/loongsuite-instrumentation-agentscope/tests/test_skill_detection.py | Updates tests to include tool_type. |
| instrumentation-loongsuite/loongsuite-instrumentation-agentscope/src/opentelemetry/instrumentation/agentscope/patch.py | Populates tool_type for tool invocations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def detect(self) -> Resource: | ||
| return Resource( | ||
| { | ||
| HOST_IP: _get_host_ip_with_pid(), | ||
| GEN_AI_INSTRUMENTATION_SDK_NAME: _GEN_AI_INSTRUMENTATION_SDK_NAME_VALUE, | ||
| } |
| def _extract_server_info(instance: Any) -> tuple[str | None, int | None]: | ||
| """Extract server address and port from instance base_url.""" | ||
| base_url = getattr(instance, "base_url", None) | ||
| if not base_url: | ||
| return None, None | ||
| base_url_str = str(base_url).rstrip("/") | ||
| try: | ||
| from urllib.parse import urlparse | ||
|
|
||
| parsed = urlparse(base_url_str) | ||
| address = parsed.hostname | ||
| port = parsed.port | ||
| if port is None: | ||
| port = 443 if parsed.scheme == "https" else 80 | ||
| return address, port | ||
| except Exception: | ||
| return None, None | ||
|
|
| def _infer_server_address(model: str) -> tuple[str | None, int | None]: | ||
| """Infer server address from model name for vita.""" | ||
| model_lower = model.lower() if model else "" | ||
| if "qwen" in model_lower or "dashscope" in model_lower: | ||
| return "dashscope.aliyuncs.com", 443 | ||
| if "gpt" in model_lower or "openai" in model_lower: | ||
| return "api.openai.com", 443 | ||
| if "claude" in model_lower or "anthropic" in model_lower: | ||
| return "api.anthropic.com", 443 | ||
| if "deepseek" in model_lower: | ||
| return "api.deepseek.com", 443 | ||
| return None, None | ||
|
|
ralf0131
left a comment
There was a problem hiding this comment.
Summary
PR #224 propagates GenAI semantic-convention fields (tool_type, agent_id, server_address/server_port, response_id) across multiple LoongSuite instrumentations and introduces a LoongSuiteResourceDetector that injects host.ip and gen_ai.instrumentation.sdk.name resource attributes. Overall direction is good — aligning with OTel GenAI semconv is the right move. The review below focuses on additional findings beyond what Copilot already flagged (host.ip format, unused _infer_server_address, schemeless-URL handling in _extract_server_info).
CLA is signed ✅.
Findings
- [Warning]
__init__.py:40— resource detector silently overrides user-providedhost.ip/gen_ai.instrumentation.sdk.nameviadict.update(); considersetdefaultso caller values win. - [Warning]
hermes_agent/helpers.py:574—agent_id="hermes-agent"is hardcoded for all instances; inconsistent with other instrumentations and defeats the uniqueness purpose ofagent.id. - [Info]
dashscope/utils/generation.py:471—server_address/server_porthardcoded; inconsistent with the dynamic extraction added for hermes-agent in this same PR. - [Info]
agentscope/patch.py:406—tool_typehardcoded to"function"across all instrumentations; consider deriving from framework metadata where available.
Additional Notes
agent_idalways mirrorsagent_name: across every instrumentation in this PR,agent_idis set toagent_name(or a derivative), so both attributes always carry the same value. The GenAI semconv distinguishesagent.id(unique instance identifier) fromagent.name(display name). If no truly unique per-instance ID is available right now, that's acceptable, but worth a follow-up to see whether session IDs or similar can provide real uniqueness.- PR description: The description body is still the unfilled GitHub template (no summary, no test instructions, checklist items unchecked). No changelog files appear to have been modified. Please fill in the description and update changelogs per the project's contributing guidelines.
Automated review by github-manager-bot
| """ | ||
|
|
||
| def _configure(self, **kwargs: Any) -> None: | ||
| resource_attributes = dict(kwargs.pop("resource_attributes", None) or {}) |
There was a problem hiding this comment.
[Warning] The dict.update() call gives the resource detector precedence over any user-provided resource_attributes. If a user explicitly configures host.ip or gen_ai.instrumentation.sdk.name, those values are silently overwritten by the detector. Consider merging the detector's attributes first (or using setdefault-style logic) so caller-provided values take precedence.
resource_attributes = dict(kwargs.pop("resource_attributes", None) or {})
# User values set first, detector only fills gaps:
detected = LoongSuiteResourceDetector().detect().attributes
for k, v in detected.items():
resource_attributes.setdefault(k, v)| invocation = InvokeAgentInvocation( | ||
| provider=_HERMES_AGENT_SYSTEM, | ||
| agent_name="Hermes", | ||
| agent_id="hermes-agent", |
There was a problem hiding this comment.
[Warning] agent_id is hardcoded to "hermes-agent" for every instance. Other instrumentations in this PR use agent_name (which at least varies per agent). The GenAI semconv agent.id is intended to uniquely identify an agent instance — a constant string here means all concurrent hermes-agent instances share the same ID, making the attribute non-discriminating. Consider deriving from a session/instance identifier, or at minimum use agent_name for consistency.
| @@ -469,6 +469,8 @@ def _create_invocation_from_generation( | |||
|
|
|||
| invocation = LLMInvocation(request_model=request_model) | |||
| invocation.provider = "dashscope" | |||
There was a problem hiding this comment.
[Info] server_address/server_port are hardcoded to "dashscope.aliyuncs.com"/443. This is inconsistent with the hermes-agent instrumentation in this same PR, which dynamically extracts server info from base_url. Users pointing DashScope-compatible SDKs at custom or regional endpoints won't see their actual endpoint reflected. Consider extracting from instance.base_url (or os.environ for DASHSCOPE_* base URL overrides) if available.
| # Create invocation object with all tool data | ||
| invocation = ExecuteToolInvocation( | ||
| tool_name=tool_name, | ||
| tool_type="function", |
There was a problem hiding this comment.
[Info] tool_type is unconditionally set to "function" here and across all other instrumentations in this PR. Some agent frameworks support non-function tool types (e.g., code_interpreter, retrieval, builtin). If the framework exposes the actual tool type, consider deriving it rather than hardcoding. If "function" is the only supported type today, a comment documenting this assumption would help future maintainers.
Description
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
Fixes # (issue)
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
Does This PR Require a Core Repo Change?
Checklist:
See contributing.md for styleguide, changelog guidelines, and more.