Skip to content

Commit 01c32df

Browse files
address pr comments
1 parent 5918d7a commit 01c32df

6 files changed

Lines changed: 24 additions & 7 deletions

File tree

libraries/microsoft-agents-a365-observability-core/microsoft_agents_a365/observability/core/models/messages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class ToolCallRequestPart:
6666

6767
name: str
6868
id: str | None = None
69-
arguments: dict[str, object] | list[object] | None = None
69+
arguments: dict[str, object] | list[object] | str | None = None
7070
type: str = field(default="tool_call", init=False)
7171

7272

libraries/microsoft-agents-a365-observability-extensions-agentframework/docs/design.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,5 @@ microsoft_agents_a365/observability/extensions/agentframework/
5555

5656
## Dependencies
5757

58-
- `agent-framework-azure-ai` - Microsoft Agents SDK
58+
- `agent-framework` - Microsoft Agents SDK
5959
- `microsoft-agents-a365-observability-core` - Core observability

libraries/microsoft-agents-a365-observability-extensions-agentframework/microsoft_agents_a365/observability/extensions/agentframework/message_mapper.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def map_input_messages(messages_json: str) -> str | None:
5555
try:
5656
raw = json.loads(messages_json)
5757
except (json.JSONDecodeError, TypeError):
58+
logger.debug("Failed to parse input messages JSON: %s", messages_json[:200])
5859
return None
5960

6061
if not isinstance(raw, list):
@@ -88,6 +89,7 @@ def map_output_messages(messages_json: str) -> str | None:
8889
try:
8990
raw = json.loads(messages_json)
9091
except (json.JSONDecodeError, TypeError):
92+
logger.debug("Failed to parse output messages JSON: %s", messages_json[:200])
9193
return None
9294

9395
if not isinstance(raw, list):

libraries/microsoft-agents-a365-observability-extensions-agentframework/microsoft_agents_a365/observability/extensions/agentframework/trace_instrumentor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
# -----------------------------
2424
# 3) The Instrumentor class
2525
# -----------------------------
26-
_instruments = ("agent-framework-azure-ai >= 1.0.0rc1",)
26+
_instruments = ("agent-framework >= 1.0.0",)
2727

2828

2929
class AgentFrameworkInstrumentor(BaseInstrumentor):

libraries/microsoft-agents-a365-observability-extensions-langchain/microsoft_agents_a365/observability/extensions/langchain/message_mapper.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ def _extract_parts(msg: BaseMessage | Mapping[str, Any]) -> list[MessagePart]:
193193
try:
194194
args_str = json.dumps(args) if not isinstance(args, str) else args
195195
except (TypeError, ValueError):
196+
logger.debug("Failed to serialize tool call args for '%s': %s", name, args)
196197
args_str = str(args)
197198

198199
parts.append(

tests/observability/extensions/langchain/integration/test_observability_pipeline.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,20 @@
77
InvokeAgentScope → Inference (auto-instrumented) → ToolExecution (auto-instrumented)
88
99
The CustomLangChainInstrumentor automatically creates inference spans for LLM
10-
calls and execute_tool spans for tool runs. Wrapping the entire call in
11-
InvokeAgentScope makes all auto-instrumented spans children of the invoke_agent
12-
span (since separate_trace_from_runtime_context defaults to False).
10+
calls and execute_tool spans for tool runs. Its built-in message mapper
11+
converts LangChain messages into the versioned A365 message format
12+
(``{"version": "0.1.0", "messages": [...]}``) on ``gen_ai.input.messages``
13+
and ``gen_ai.output.messages`` span attributes.
14+
15+
Wrapping the entire call in InvokeAgentScope makes all auto-instrumented spans
16+
children of the invoke_agent span (since ``separate_trace_from_runtime_context``
17+
defaults to ``False``).
18+
19+
Note: the message-format assertions accept both the versioned dict structure
20+
*and* a raw JSON list. The raw-list branch exists for backward compatibility
21+
with older instrumentation versions or third-party LangChain instrumentors that
22+
emit ``gen_ai.*.messages`` as plain JSON arrays before the A365 mapper was
23+
integrated.
1324
"""
1425

1526
import json
@@ -101,7 +112,7 @@ class TestLangChainObservabilityPipeline:
101112
102113
Verifies that wrapping LangChain calls inside InvokeAgentScope
103114
produces a single trace with correct parent-child span hierarchy,
104-
operation names, and A365 message format attributes.
115+
operation names, and A365 versioned message format attributes.
105116
"""
106117

107118
@pytest.fixture(autouse=True)
@@ -302,6 +313,9 @@ async def test_pipeline_invoke_agent_with_tool_call(
302313
print(f"\n✓ Found {len(tool_spans)} tool execution spans")
303314

304315
# --- 8. A365 message format on inference spans ---
316+
# The A365 mapper emits the versioned format {"version": "0.1.0", "messages": [...]}.
317+
# Older or third-party instrumentors may emit a raw JSON list instead;
318+
# the raw-list branch is kept for backward compatibility.
305319
for inf_span in inference_spans:
306320
attrs = dict(inf_span.attributes or {})
307321
if GEN_AI_INPUT_MESSAGES_KEY in attrs:

0 commit comments

Comments
 (0)