Skip to content

Python: Resolve workflow request info from pending state - #7500

Open
moonbox3 wants to merge 1 commit into
microsoft:mainfrom
moonbox3:harden-workflow-request-info-resolving
Open

Python: Resolve workflow request info from pending state#7500
moonbox3 wants to merge 1 commit into
microsoft:mainfrom
moonbox3:harden-workflow-request-info-resolving

Conversation

@moonbox3

@moonbox3 moonbox3 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Motivation & Context

Keep workflow request-info resolution consistent with retained pending state while preserving existing transport and type compatibility.

Description & Review Guide

  • What are the major changes? Add pending-request lookup and agent resolution interfaces, retain legacy parsing through explicit type mappings, migrate first-party callers, and document the state model.
  • What is the impact of these changes? Existing wire and response flows remain compatible, including restored workflows and supported generic annotations.
  • What do you want reviewers to focus on? Correlation semantics and compatibility behavior for legacy and custom type resolution.

Related Issue

None.

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.

Copilot AI lite review requested due to automatic review settings August 4, 2026 04:35
@moonbox3
moonbox3 temporarily deployed to github-app-auth August 4, 2026 04:35 — with GitHub Actions Inactive
@moonbox3
moonbox3 temporarily deployed to github-app-auth August 4, 2026 04:35 — with GitHub Actions Inactive
@moonbox3
moonbox3 temporarily deployed to github-app-auth August 4, 2026 04:35 — with GitHub Actions Inactive
@agent-framework-automation agent-framework-automation Bot added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python labels Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework/_workflows
   _agent.py3803191%92, 96, 167–168, 394, 407, 474, 485, 487, 543, 609, 679, 757, 787, 815, 863, 872, 933, 940, 946–947, 958, 990, 997, 1018, 1027, 1031, 1033–1035, 1042
   _events.py1581292%91–92, 240, 244, 246, 278, 360, 375, 390, 405, 418, 458
   _typing_utils.py2594483%24, 39–40, 56, 103–104, 130, 132, 307, 331, 376–381, 435, 460, 515, 517–518, 527, 529, 536, 538, 558, 560, 562, 567–574, 577–578, 580–584, 586
   _workflow.py3682493%61, 63, 68, 92, 97, 158, 194, 434–436, 438–439, 463, 497, 625, 664, 955, 976, 1024, 1036, 1042, 1073–1075
TOTAL44637411690% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
9182 34 💤 0 ❌ 0 🔥 2m 22s ⏱️

Copilot AI 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

Introduces an authoritative, pending-state-based resolver for Python workflow request_info handling (including workflow-as-agent HITL), avoiding reliance on copied transport payloads for request data and Python type resolution while keeping the current wire shape compatible during a deprecation window.

Changes:

  • Add Workflow.get_pending_request_info(request_id) and WorkflowAgent.resolve_request_info(content) to resolve pending request-info data from workflow-held state with strict correlation validation.
  • Replace import-based type resolution with a safer compatibility mechanism (serialize_type registry + deserialize_type allowlist/registry/builtins), and deprecate legacy dict parsers with warnings.
  • Update first-party samples/docs and expand unit test coverage for tampering, correlation semantics, checkpoint rehydration, and generic response-type compatibility.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
python/samples/03-workflows/README.md Updates sample description to reflect authoritative pending request resolution for workflow-as-agent HITL.
python/samples/03-workflows/orchestrations/README.md Updates handoff workflow-as-agent sample description to reflect authoritative HITL request resolution.
python/samples/03-workflows/agents/workflow_as_agent_human_in_the_loop.py Migrates sample to agent.resolve_request_info(...) and uses authoritative request IDs for responses.
python/samples/03-workflows/agents/handoff_workflow_as_agent.py Migrates request extraction to agent.resolve_request_info(...) and adds runtime type validation.
python/packages/orchestrations/tests/test_handoff.py Adds coverage ensuring workflow-as-agent request-info remains usable with generic response type metadata.
python/packages/core/tests/workflow/test_workflow_agent.py Adds extensive resolve_request_info tests (correlation, tampering, replay/stale behavior, data non-trust).
python/packages/core/tests/workflow/test_typing_utils.py Adds tests for safer type serialization/deserialization, allowlists, ambiguity handling, and non-import behavior.
python/packages/core/tests/workflow/test_request_info_event_rehydrate.py Adds tests ensuring legacy reconstruction paths don’t import payload-selected modules and validates restored pending lookup.
python/packages/core/tests/workflow/test_request_info_and_response.py Adds tests for non-consuming pending lookup and consumption semantics after successful responses.
python/packages/core/AGENTS.md Documents the request-info trust boundary and preferred resolution APIs; notes legacy deprecations.
python/packages/core/agent_framework/_workflows/_workflow.py Adds get_pending_request_info public API backed by runner context pending state.
python/packages/core/agent_framework/_workflows/_typing_utils.py Reworks serialize_type/deserialize_type to avoid payload-driven imports and support explicit trusted mappings/registry.
python/packages/core/agent_framework/_workflows/_events.py Deprecates WorkflowEvent.from_dict, adds allowed_types, and routes through safer deserialize_type.
python/packages/core/agent_framework/_workflows/_agent.py Deprecates legacy request-info args parsing and adds resolve_request_info to validate and resolve authoritative pending events.
docs/decisions/0033-authoritative-workflow-request-info-resolution.md Adds ADR documenting the design decision, drivers, and migration plan.

Comment thread python/packages/core/agent_framework/_workflows/_agent.py

@github-actions github-actions Bot 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.

Automated Code Review

Reviewers: 5 | Confidence: 49%

✗ Correctness

Found one backward-compatibility bug: legacy typing-generic wire names are serialized but can no longer be deserialized.

✓ Security Reliability

I could not complete a verifiable review: every read tool call (view, grep, bash) in this session was blocked by the environment, so I was unable to open the changed production files (_typing_utils.py, _events.py, _agent.py, _workflow.py) or the surrounding runner-context/checkpoint code needed to confirm behavior. Reading the diff alone, the change is coherent with its stated rationale: deserialize_type no longer imports payload-selected modules and resolves only against builtins, a process-local weakref registry, and exact per-call allowed_types; Workflow.get_pending_request_info provides a non-consuming authoritative lookup; and WorkflowAgent.resolve_request_info strictly correlates call_id / arguments.request_id / request_event.request_id and compares only safely comparable metadata while ignoring copied request data. The main residual risk I would want a maintainer to consider is the deliberate loss of cross-process type resolution (a serialized name unknown to the current process now raises ValueError instead of importing), which the ADR explicitly acknowledges as a compatibility-window trade-off. I am reporting zero findings because I could not verify any concrete issue against source.

✓ Test Coverage

The generic compatibility test covers only serialization, missing a backward-compatibility regression in deserialization.

✓ Failure Modes

I could not perform this review. All read-only tool calls in this session (view, grep, bash) were rejected by the environment with 'unexpected user permission response', so I was unable to open python/packages/core/agent_framework/_workflows/_typing_utils.py, _agent.py, _workflow.py, _events.py, the checkpoint/serialization code paths, or the test files needed to verify any suspected failure mode. Per the evidence discipline requirements, I am omitting all findings rather than emitting unverified claims. Areas that a reviewer with working file access should verify: (1) deserialize_type no longer imports modules, so any cross-process consumer that previously relied on import-based resolution (e.g. checkpoint restore in a fresh process, distributed/devui hosts) must be confirmed to resolve types through serialize_type registration or an explicit allowed_types mapping, otherwise restore fails closed with 'Unknown serialized type'; (2) the process-global weakref registry in serialize_type and its Lock interacting with async event loops; (3) the warnings.catch_warnings() suppression inside RequestInfoFunctionArgs.from_dict, which mutates global warning filter state and is not thread-safe (note: the test asserting exactly one recorded warning appears to depend on this suppression, so any change there must keep that test passing).

✓ Design Approach

I was unable to perform the required verification pass: every file-read tool call in this session (view, grep, bash) failed with a permission error, so I could not open _typing_utils.py, _workflow.py, _agent.py, the checkpoint serialization paths, or any existing tests in the checkout. Reviewing the diff text alone, the design is coherent and internally consistent: pending workflow state becomes the single authority for request-info data and Python types, Workflow.get_pending_request_info is non-consuming and delegates to the runner context, WorkflowAgent.resolve_request_info validates only safely-comparable correlation and metadata fields while ignoring copied request data, and the legacy from_dict entry points are retained behind DeprecationWarnings with an allowed_types escape hatch so the wire shape is unchanged. The tests in the diff directly assert each of these properties (identity-preserving repeated lookup, consumption only on successful response, tamper rejection per field, no-import type resolution, restored-checkpoint lookup). The one area I would have wanted to check but could not is whether any cross-process checkpoint-restore path depends on deserialize_type resolving a type that was never passed through serialize_type in the loading process, since the registry is process-local; because I could not open the checkpoint code to confirm or refute that, I am omitting it as a finding rather than reporting it unverified. No findings are emitted.

Flagged Issues

  • python/packages/core/agent_framework/_workflows/_typing_utils.py:351 leaves legacy typing aliases such as typing.List unregistered and unresolvable during deserialization.

Automated review by moonbox3's agents

Comment thread python/packages/core/agent_framework/_workflows/_typing_utils.py Outdated
Comment thread python/packages/core/tests/workflow/test_typing_utils.py Outdated
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Flagged issue

python/packages/core/agent_framework/_workflows/_typing_utils.py:351 leaves legacy typing aliases such as typing.List unregistered and unresolvable during deserialization.


Source: automated DevFlow PR review

@moonbox3
moonbox3 temporarily deployed to github-app-auth August 4, 2026 04:44 — with GitHub Actions Inactive
@moonbox3
moonbox3 temporarily deployed to github-app-auth August 4, 2026 05:30 — with GitHub Actions Inactive
@moonbox3

moonbox3 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the DevFlow compatibility finding in 55ba857: supported historical typing aliases now use a fixed trusted resolution map, and the tests cover the deserialization round trip.

@moonbox3
moonbox3 force-pushed the harden-workflow-request-info-resolving branch from 55ba857 to c40e830 Compare August 4, 2026 05:55
@moonbox3
moonbox3 temporarily deployed to github-app-auth August 4, 2026 05:55 — with GitHub Actions Inactive
@moonbox3
moonbox3 marked this pull request as ready for review August 4, 2026 06:19
@moonbox3
moonbox3 temporarily deployed to github-app-auth August 4, 2026 06:19 — with GitHub Actions Inactive

@github-actions github-actions Bot 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.

Automated Code Review

Reviewers: 5 | Confidence: 44% | Result: All clear

Reviewed: Correctness, Security Reliability, Test Coverage, Failure Modes, Design Approach


Automated review by moonbox3's agents

Add authoritative pending request lookup and workflow-agent resolution, retain legacy parsing through trusted compatibility mappings, and migrate first-party consumers while preserving the existing wire shape.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a53fe20b-c3f0-4583-badc-d5deac7c1049
@moonbox3
moonbox3 force-pushed the harden-workflow-request-info-resolving branch from c40e830 to 68ecde7 Compare August 4, 2026 08:20
@moonbox3
moonbox3 temporarily deployed to github-app-auth August 4, 2026 08:20 — with GitHub Actions Inactive
)

@classmethod
def from_dict(

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.

nit: why are we renaming it to rehydrate?

def workflow(self) -> Workflow:
return self._workflow

async def resolve_request_info(self, content: Content) -> WorkflowEvent[Any]:

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.

I am not sure if I fully understand the purpose of this. What is a live workflow vs. a transport decoding?

"""
pending_requests = await self._runner.context.get_pending_request_info_events()
try:
return pending_requests[request_id]

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.

should this be a deep copy of the event?

Comment on lines +206 to +207
function-call `Content` to `await agent.resolve_request_info(content)`; the resolver validates correlation and
compatibility metadata, then returns the workflow-held event without trusting copied request data. Both lookups

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.

The content is also returned by the agent. At what stage the content become untrusted?

@github-actions github-actions Bot 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.

Agent Framework Skill Review

Skill: agent-framework-review-pass
Completed passes: 5 | Failed passes: 0 | Confidence: 50% | Result: No high-severity findings

Review passes

  • Correctness (gpt-5.6-sol) — No high-confidence issues found in this pass.
  • Security Reliability (claude-opus-4.8) — No high-confidence issues found in this pass.
  • Test Coverage (gpt-5.6-sol) — No high-confidence issues found in this pass.
  • Failure Modes (claude-opus-4.8) — No high-confidence issues found in this pass.
  • Design Approach (claude-opus-4.8) — No high-confidence issues found in this pass.

No high-severity findings survived the skill-backed review and verification pipeline.


Skill-backed ensemble review by moonbox3's agents

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

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants