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
6 changes: 5 additions & 1 deletion .github/workflows/generate_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,9 @@
batch_size=4,
parallelism=4,
)
generate_misc_workflow(tox_ini_path, workflows_directory_path)
generate_misc_workflow(
tox_ini_path,
workflows_directory_path,
runner=arc_runner_label,
)
generate_contrib_workflow(workflows_directory_path)
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,13 @@ def generate_contrib_workflow(
def generate_misc_workflow(
tox_ini_path: Path,
workflow_directory_path: Path,
runner="ubuntu-latest",
) -> None:
_generate_workflow(
get_misc_job_datas(get_tox_envs(tox_ini_path)),
"misc",
workflow_directory_path,
runner=runner,
)


Expand Down Expand Up @@ -445,6 +447,7 @@ def generate_extension_misc_workflow(
tox_ini_path: Path,
workflow_directory_path: Path,
additional_config_path: Path,
runner="ubuntu-latest",
) -> None:
loongsuite_envs = get_loongsuite_tox_envs(additional_config_path)
if not loongsuite_envs:
Expand All @@ -455,6 +458,7 @@ def generate_extension_misc_workflow(
"loongsuite_misc",
"loongsuite_misc",
workflow_directory_path,
runner=runner,
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:

{{ job_data }}:
name: LoongSuite {{ job_data }}
runs-on: ubuntu-latest
runs-on: {{ runner }}
timeout-minutes: 30
{%- if job_data == "generate-workflows" %}
if: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ name: Misc {{ file_number }}

on:
push:
branches-ignore:
- 'release/*'
- 'otelbot/*'
branches:
- main
pull_request:

permissions:
Expand Down Expand Up @@ -36,7 +35,7 @@ jobs:

{{ job_data }}:
name: {{ job_data }}
runs-on: ubuntu-latest
runs-on: {{ "ubuntu-latest" if job_data == "docker-tests" else runner }}
timeout-minutes: 30
{%- if job_data == "generate-workflows" %}
if: |
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/generate_workflows_loongsuite.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@
control_runner=arc_runner_label,
)
generate_extension_misc_workflow(
tox_ini_path, workflows_directory_path, tox_loongsuite_ini_path
tox_ini_path,
workflows_directory_path,
tox_loongsuite_ini_path,
runner=arc_runner_label,
)
4 changes: 2 additions & 2 deletions .github/workflows/loongsuite_misc_0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:

check-license-header:
name: LoongSuite check-license-header
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
Expand All @@ -54,7 +54,7 @@ jobs:

generate-loongsuite:
name: LoongSuite generate-loongsuite
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
Expand Down
19 changes: 9 additions & 10 deletions .github/workflows/misc_0.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ name: Misc 0

on:
push:
branches-ignore:
- 'release/*'
- 'otelbot/*'
branches:
- main
pull_request:

permissions:
Expand Down Expand Up @@ -35,7 +34,7 @@ jobs:

spellcheck:
name: spellcheck
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
Expand Down Expand Up @@ -73,7 +72,7 @@ jobs:

docs:
name: docs
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
if: |
github.event.pull_request.user.login != 'otelbot[bot]' && github.event_name == 'pull_request'
Expand All @@ -94,7 +93,7 @@ jobs:

generate:
name: generate
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
Expand All @@ -116,7 +115,7 @@ jobs:

generate-workflows:
name: generate-workflows
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
if: |
!contains(github.event.pull_request.labels.*.name, 'Skip generate-workflows')
Expand All @@ -141,7 +140,7 @@ jobs:

shellcheck:
name: shellcheck
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
Expand All @@ -160,7 +159,7 @@ jobs:

precommit:
name: precommit
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
Expand All @@ -179,7 +178,7 @@ jobs:

typecheck:
name: typecheck
runs-on: ubuntu-latest
runs-on: loongsuite-python-arc
timeout-minutes: 30
steps:
- name: Checkout repo @ SHA - ${{ github.sha }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- Capture `gen_ai.skill.*` attributes on Agno skill tool spans such as
`get_skill_instructions`, `get_skill_reference`, and `get_skill_script`.

## Version 0.7.0 (2026-07-03)

### Removed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import json
from dataclasses import asdict, is_dataclass
from typing import Any, Mapping, Sequence
from typing import Any, Dict, Mapping, Optional, Sequence

from opentelemetry.util.genai.extended_semconv.gen_ai_extended_attributes import (
GEN_AI_SESSION_ID,
Expand All @@ -39,6 +39,11 @@
)

_PROVIDER = "agno"
_SKILL_TOOL_NAMES = {
"get_skill_instructions",
"get_skill_reference",
"get_skill_script",
}


def _json_default(value: Any) -> Any:
Expand Down Expand Up @@ -82,6 +87,95 @@ def _to_dict(value: Any) -> dict[str, Any] | None:
return None


def _mapping_from_any(value: Any) -> Dict[str, Any]:
data = _to_dict(value)
if data is not None:
return data
if isinstance(value, str):
try:
loaded = json.loads(value)
except Exception:
return {}
return loaded if isinstance(loaded, dict) else {}
return {}


def _first_text(*values: Any) -> Optional[str]:
for value in values:
if value is None:
continue
text = str(value).strip()
if text:
return text
return None


def _extract_skill_metadata(value: Any) -> Dict[str, Any]:
data = _mapping_from_any(value)
if not data:
return {}
frontmatter = _mapping_from_any(data.get("frontmatter"))
metadata = _mapping_from_any(data.get("metadata")) or _mapping_from_any(
frontmatter.get("metadata")
)
return {
"name": _first_text(
data.get("skill_name"),
data.get("skill"),
data.get("name"),
frontmatter.get("name"),
),
"id": _first_text(
data.get("skill_id"),
data.get("id"),
metadata.get("id"),
),
"description": _first_text(
data.get("skill_description"),
data.get("description"),
frontmatter.get("description"),
),
"version": _first_text(
data.get("skill_version"),
data.get("version"),
metadata.get("version"),
),
}


def _apply_skill_metadata(
invocation: ExecuteToolInvocation, metadata: Mapping[str, Any]
) -> None:
name = _first_text(metadata.get("name"))
if name:
invocation.skill_name = invocation.skill_name or name
invocation.skill_id = (
invocation.skill_id or _first_text(metadata.get("id")) or name
)
elif metadata.get("id"):
invocation.skill_id = invocation.skill_id or _first_text(
metadata.get("id")
)

description = _first_text(metadata.get("description"))
if description:
invocation.skill_description = (
invocation.skill_description or description
)

version = _first_text(metadata.get("version"))
if version:
invocation.skill_version = invocation.skill_version or version


def _apply_agno_skill_tool_metadata(
invocation: ExecuteToolInvocation, data: Any
) -> None:
if invocation.tool_name not in _SKILL_TOOL_NAMES:
return
_apply_skill_metadata(invocation, _extract_skill_metadata(data))


def _get_value(value: Any, name: str, default: Any = None) -> Any:
if isinstance(value, Mapping):
return value.get(name, default)
Expand Down Expand Up @@ -555,14 +649,16 @@ def update_llm_invocation_from_response(

def create_tool_invocation(function_call: Any) -> ExecuteToolInvocation:
function = getattr(function_call, "function", None)
return ExecuteToolInvocation(
invocation = ExecuteToolInvocation(
tool_name=getattr(function, "name", None) or "unknown_tool",
provider=_PROVIDER,
tool_call_id=getattr(function_call, "call_id", None),
tool_description=getattr(function, "description", None),
tool_type="function",
tool_call_arguments=getattr(function_call, "arguments", None),
)
_apply_agno_skill_tool_metadata(invocation, invocation.tool_call_arguments)
return invocation


def update_tool_invocation_from_response(
Expand All @@ -572,3 +668,4 @@ def update_tool_invocation_from_response(
invocation.tool_call_result = (
result if isinstance(result, str) else _stringify(result)
)
_apply_agno_skill_tool_metadata(invocation, result)
Loading
Loading