Skip to content

Python: Capture workflow telemetry input and output - #7565

Closed
slcnx wants to merge 2 commits into
microsoft:mainfrom
slcnx:fix/python-workflow-telemetry-io
Closed

Python: Capture workflow telemetry input and output#7565
slcnx wants to merge 2 commits into
microsoft:mainfrom
slcnx:fix/python-workflow-telemetry-io

Conversation

@slcnx

@slcnxslcnx commented Aug 7, 2026

Copy link
Copy Markdown

Motivation & Context

Python workflow spans currently expose structural metadata but omit the payloads processed by executors and sent between them. This prevents OpenTelemetry backends from showing useful workflow inputs and outputs.

This change closes the Python payload-capture gap identified in #3075, follows the sensitive-data behavior introduced for .NET in #3467, and adds vendor-neutral OpenInference attributes so compatible backends can render workflow I/O directly.

Description & Review Guide

  • What are the major changes?
    • Capture serialized input/output on executor processing spans and serialized content on message send spans when sensitive telemetry is enabled.
    • Add source and target executor routing metadata to message send spans.
    • Populate OpenInference input/output value and MIME type attributes on workflow, executor, and message spans.
    • Reuse the framework JSON-safe conversion path and fall back to a type-only placeholder if telemetry serialization fails.
    • Add focused tests for enabled, disabled, structured-output, routing, and serialization-failure behavior.
  • What is the impact of these changes?
    • Payload capture remains disabled by default and adds no workflow-output accumulation when sensitive telemetry is disabled.
    • When explicitly enabled, workflow traces contain inspectable inputs and outputs at workflow, executor, and message granularity.
    • Existing workflow behavior and existing telemetry attributes remain unchanged.
  • What do you want reviewers to focus on?
    • Whether emitting both .NET-parity attributes and OpenInference attributes is the desired interoperability contract for Python workflow spans.
    • Whether workflow-level output should remain limited to explicit output events, as implemented here.

Related Issue

Fixes#3075

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add [BREAKING] to the title prefix, before or after any language prefix) - a workflow keeps the label and title prefix in sync automatically.

CopilotAI balanced review requested due to automatic review settings August 7, 2026 07:57
@slcnx
slcnxtemporarily deployed to github-app-auth August 7, 2026 07:57 — with GitHub Actions Inactive
@slcnx
slcnxtemporarily deployed to github-app-auth August 7, 2026 07:57 — with GitHub Actions Inactive
@agent-framework-automationagent-framework-automationBot added the python Usage: [Issues, PRs], Target: Python label Aug 7, 2026
@slcnx
slcnxtemporarily deployed to github-app-auth August 7, 2026 07:58 — with GitHub Actions Inactive

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds opt-in workflow payload telemetry for improved OpenTelemetry/OpenInference observability.

Changes:

  • Captures workflow, executor, and message payloads when sensitive telemetry is enabled.
  • Adds message routing and OpenInference attributes.
  • Tests enabled, disabled, routing, structured-output, and serialization-failure behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
python/packages/core/agent_framework/observability.pyAdds payload attributes and serialization helpers.
python/packages/core/agent_framework/_workflows/_workflow.pyCaptures workflow input and explicit outputs.
python/packages/core/agent_framework/_workflows/_workflow_context.pyCaptures sent-message content and routing.
python/packages/core/agent_framework/_workflows/_executor.pyCaptures executor input and output.
python/packages/core/tests/workflow/test_workflow_observability.pyAdds focused telemetry tests.

Comment threadpython/packages/core/agent_framework/_workflows/_workflow.py Outdated
Comment threadpython/packages/core/agent_framework/observability.py Outdated
@slcnx
slcnx marked this pull request as ready for review August 7, 2026 08:17
@slcnx
slcnxtemporarily deployed to github-app-auth August 7, 2026 08:25 — with GitHub Actions Inactive
@slcnx

slcnx commented Aug 7, 2026

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree [company="yikaobang"]

@slcnx

slcnx commented Aug 7, 2026

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="yikaobang"

if event.type == "request_info":
saw_request = True
elif workflow_outputs is not None and event.type == "output":
workflow_outputs.append(event.data)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we please avoid retaining and serializing every streamed output as one span attribute? With sensitive telemetry enabled, workflow_outputs keeps the complete output set until convergence and _set_sensitive_span_attributes then builds another JSON representation of it, so a high-volume workflow can exhaust memory solely from payload capture. How about a bounded or truncated capture to preserve observability without making successful workflow execution depend on total output volume?

@github-actions

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework
observability.py10517992%486, 488–489, 492, 495, 498–499, 504–505, 511–512, 518–519, 526, 528–529, 532, 535, 538–539, 544–545, 551–552, 558–559, 566, 743–744, 954, 958–960, 962, 970–971, 975, 1019, 1021, 1032–1034, 1036–1038, 1042, 1050, 1174–1175, 1410, 1697–1698, 1961, 2004–2005, 2194, 2422–2423, 2427, 2467–2468, 2472, 2513–2516, 2557–2558, 2709, 2712, 2724, 2741, 2745–2746, 2749, 2755, 2875, 3096, 3098
packages/core/agent_framework/_workflows
_executor.py2011194%228, 381, 383, 392, 412, 415, 522, 527, 537, 710, 717
_workflow.py3742593%66, 68, 73, 97, 102, 163, 199, 418–420, 422–423, 447, 481, 631, 670, 965, 986, 1034, 1046, 1052, 1057, 1083–1085
_workflow_context.py1711889%62–63, 71, 75, 79–82, 84–86, 88–90, 165, 199, 311, 465
TOTAL45744425190%

Python Unit Test Overview

TestsSkippedFailuresErrorsTime
930136 💤0 ❌0 🔥2m 28s ⏱️

@moonbox3

Copy link
Copy Markdown
Contributor

/review

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (2 commit(s)): 51dc35679ae2, 7f0c8faa9820
Model:gpt-5.6-sol

Overview

The change gates payload capture on both sensitive-data enablement and recording spans, normalizes wrapped workflow inputs, and uses strict JSON with a type-only fallback on serialization errors. The focused tests cover enabled and disabled capture, routing, structured output, serialization failure, and non-finite values. Two residual risks remain: conversion hooks can mutate live payloads before execution, and outputs already delivered to consumers are omitted from workflow telemetry when execution does not converge successfully.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (2 medium) across 2 files. Details are attached to the affected lines below.

Affected areas:python/packages/core/agent_framework/_workflows/_workflow.py, python/packages/core/agent_framework/observability.py

def _serialize_for_telemetry(value: Any) -> str:
"""Serialize heterogeneous telemetry payloads without affecting application execution."""
try:
return json.dumps(make_json_safe(value), ensure_ascii=False, allow_nan=False)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make_json_safe invokes payload-defined model_dump(), to_dict(), or dict() methods on the live object. When one of those hooks is stateful, enabling sensitive telemetry mutates the payload before the workflow or executor handler receives it, so observability changes application behavior even though exceptions are caught. Please avoid invoking arbitrary conversion hooks on live application objects during telemetry capture, or otherwise isolate the conversion so handler-visible state cannot be changed.

# Track request events for final status determination
if event.type == "request_info":
saw_request = True
elif workflow_outputs is not None and event.type == "output":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Output capture only runs in the successful convergence loop and the attribute is written after that loop completes. If an executor queues an output and then fails, the exception path drains and yields that output without recording it; similarly, closing the stream after an output skips finalization. This leaves output.value absent even though the caller received workflow output. Please capture drained output events as well and finalize the accumulated attribute on failure or generator close without changing the workflow's output-designation rules.

@moonbox3

Copy link
Copy Markdown
Contributor

Please re-open the PR when ready to address the feedback.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pythonUsage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: Workflow Middleware to Support Customizing Telemetry

3 participants

@slcnx@moonbox3