import sys from pathlib import Path from contextlib import asynccontextmanager ROOT = Path(__file__).resolve().parents[2] FW = ROOT / "agent_framework_oci" / "libs" / "agent_framework" / "src" if str(FW) not in sys.path: sys.path.insert(0, str(FW)) from agent_framework.llm.providers import MockLLMProvider from agent_framework.observability.code_mapper import ObservabilityCodeMapper class _CaptureGeneration: def set_output(self, value): pass def set_usage(self, value): pass def set_metadata(self, **value): pass class _TelemetryWithoutOwnNormalization: """Capture the name exactly as received from the LLM provider.""" def __init__(self): self.code_mapper = ObservabilityCodeMapper({ "guardrail.dlex_in": "GRL.004", "guardrail.tox": "GRL.005", }) self.names = [] @asynccontextmanager async def generation_span(self, **attrs): self.names.append(attrs["name"]) yield _CaptureGeneration() async def test_provider_maps_guardrail_name_before_telemetry(): telemetry = _TelemetryWithoutOwnNormalization() provider = MockLLMProvider(telemetry=telemetry) await provider.ainvoke( [{"role": "user", "content": "x"}], generation_name="guardrail.dlex_in", component_name="guardrail.dlex_in", ) assert telemetry.names == ["GRL.004"] def test_mapping_path_can_resolve_from_python_import_root(tmp_path, monkeypatch): project = tmp_path / "agent" config = project / "config" config.mkdir(parents=True) mapping = config / "observability_mapping.yaml" mapping.write_text("mappings:\n guardrail.dlex_in: GRL.004\n", encoding="utf-8") elsewhere = tmp_path / "runner" elsewhere.mkdir() monkeypatch.chdir(elsewhere) monkeypatch.setattr(sys, "path", [str(project), *sys.path]) mapper = ObservabilityCodeMapper.from_yaml("./config/observability_mapping.yaml") assert mapper.map("guardrail.dlex_in") == "GRL.004"