Skip to content

Fix handler signature validation for future annotations#11

Closed
moonbox3 wants to merge 6 commits intomainfrom
codex/fix/future-annotation-handler-validation
Closed

Fix handler signature validation for future annotations#11
moonbox3 wants to merge 6 commits intomainfrom
codex/fix/future-annotation-handler-validation

Conversation

@moonbox3
Copy link
Owner

@moonbox3 moonbox3 commented Feb 18, 2026

Summary

  • resolve handler annotations via typing.get_type_hints and surface invalid annotation errors
  • reuse resolved ctx annotation in explicit @handler mode
  • add regression tests for future annotations, explicit handler types, and forward references

Testing

  • python/packages/core/tests/workflow/test_executor_future_annotations.py

## Summary
- resolve handler annotations via `typing.get_type_hints` before validation
- reuse resolved ctx annotation in explicit @handler mode
- add regression test for future annotations on @handler methods

## Testing
- `python/packages/core/tests/workflow/test_executor_future_annotations.py`

Fixes #1
Copy link
Owner Author

@moonbox3 moonbox3 left a comment

Choose a reason for hiding this comment

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

Automated PR Review Round 1: CHANGES_REQUESTED

Issue: #1
The core change to resolve handler annotations via typing.get_type_hints addresses the reported from __future__ import annotations/PEP 563 failure and adds a regression test, but the PR also introduces unrelated GitHub Actions workflows with high-risk secret handling and supply-chain exposure. Additionally, _validate_handler_signature currently swallows all get_type_hints errors, which can silently mask real annotation/forward-ref problems and reduce validation reliability. As-is, this should not be merged until the workflow security issues are removed/hardened and the handler validation/test coverage gaps are addressed.

Blocking issues (3):

  • Remove or substantially harden the newly-added GitHub Actions workflows that clone/run external code with secrets (including secrets embedded in clone URLs) and unpinned dependenci
  • In python/packages/core/agent_framework/_workflows/_executor.py, _validate_handler_signature catches Exception around typing.get_type_hints and falls back to {} with no s
  • Add regression coverage for the explicit decorator mode (@handler(input=..., output=...) / skip_message_annotation=True) under from __future__ import annotations, since this

Suggestions (4):

  • Add a targeted forward-reference test (e.g., message: "MyMessage" or a string-annotated WorkflowContext[...]) to ensure get_type_hints resolution is actually exercised.
  • If keeping a fallback when get_type_hints fails, emit at least debug/warn logging with func.__qualname__ and the exception to aid diagnosis.
  • Consider passing appropriate globalns/localns into get_type_hints to improve forward-ref resolution for nested/local definitions.
  • +1 more

include_extras=True,
)
except Exception:
hints = {}
Copy link
Owner Author

Choose a reason for hiding this comment

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

Blocking (reliability): except Exception: hints = {} silently ignores typing.get_type_hints failures (e.g., NameError on forward refs), potentially allowing incorrect handler validation. Catch narrower exceptions and/or raise/log a clear ValueError so annotation issues are actionable.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r1): queued for remediation in this pass.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r2): queued for remediation in this pass.


executor = FutureExecutor(id="future")

assert dict[str, Any] in executor._handlers
Copy link
Owner Author

Choose a reason for hiding this comment

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

Blocking (coverage): add a regression test for explicit @handler(input=..., output=...) mode under from __future__ import annotations, since that path now depends on _validate_handler_signature returning ctx_annotation.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r1): queued for remediation in this pass.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r2): queued for remediation in this pass.

pass

executor = FutureExecutor(id="future")

Copy link
Owner Author

Choose a reason for hiding this comment

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

Suggestion: the test asserts against private internals (_handlers, _handler_spec) and may be brittle; prefer asserting observable behavior (e.g., registration/execution succeeds and output types match expectations).

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r1): queued for remediation in this pass.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r2): queued for remediation in this pass.

## Summary
- resolve handler annotations via `typing.get_type_hints` and surface invalid annotation errors
- reuse resolved ctx annotation in explicit @handler mode
- add regression tests for future annotations, explicit handler types, and forward references

## Testing
- `python/packages/core/tests/workflow/test_executor_future_annotations.py`

Fixes #1
Copy link
Owner Author

@moonbox3 moonbox3 left a comment

Choose a reason for hiding this comment

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

Automated PR Review Round 2: CHANGES_REQUESTED

Issue: #1
The annotation-resolution fix using typing.get_type_hints is on the right track for from __future__ import annotations, but the PR currently bundles high-risk GitHub Actions workflows that execute external code with secrets, which should not ship with this change. In the core code, get_type_hints failures are silently swallowed and explicit-mode ctx validation can mis-handle unresolved string annotations, risking unexpected runtime errors. Tests cover the scenario but are brittle because they assert private internals instead of user-observable behavior.

Blocking issues (4):

  • Remove or move the newly added GitHub Actions workflows that clone/execute external code with high-privilege secrets/tokens (supply-chain and secret-exfiltration risk) since it is
  • In python/packages/core/agent_framework/_workflows/_executor.py, do not swallow typing.get_type_hints exceptions silently: at minimum log (debug/warn) the exception with `func.
  • Fix _validate_handler_signature explicit-mode ctx handling: under future annotations ctx_annotation can be a string; ensure ctx_annotation is resolved to an actual type bef
  • Rewrite/adjust the new tests so they assert public/observable behavior rather than private internals (executor._handlers, handler_func._handler_spec), to keep the regression te

Suggestions (3):

  • Add a negative test for unresolvable forward refs (e.g., missing name) to validate the chosen behavior (clear error or logged fallback) and ensure it’s actionable.
  • Consider improving get_type_hints resolution by providing an appropriate localns (or documenting limitations) when nested/local handler definitions are expected.
  • Add coverage ensuring explicit @handler(input=..., output=...) still enforces ctx to be a WorkflowContext when annotated, and fails clearly for non-WorkflowContext types.

localns=None,
include_extras=True,
)
except Exception:
Copy link
Owner Author

Choose a reason for hiding this comment

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

Blocking/reliability: catching Exception from typing.get_type_hints and silently falling back to {} masks forward-ref/future-annotations failures and can change behavior without visibility. Log (debug/warn) with func.__qualname__ + exception details, and consider raising a clear error when resolution is required.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r2): queued for remediation in this pass.

if skip_message_annotation and ctx_param.annotation == inspect.Parameter.empty:
if skip_message_annotation and ctx_annotation == inspect.Parameter.empty:
# When explicit types are provided via @handler(input=..., output=...),
# the ctx parameter doesn't need a type annotation - types come from the decorator.
Copy link
Owner Author

Choose a reason for hiding this comment

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

Blocking/correctness: in explicit @handler(...) mode, ctx_annotation may be a string under future annotations; treating it as a real annotation will call validate_workflow_context_annotation on str and can raise unexpectedly. Resolve ctx_annotation via get_type_hints (or treat unresolved strings as absent/unresolved) before validation.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r2): queued for remediation in this pass.

pass

executor = FutureExecutor(id="future")

Copy link
Owner Author

Choose a reason for hiding this comment

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

Blocking: this test asserts on private internals (executor._handlers, _handler_spec), making it brittle. Prefer asserting observable behavior (registration via public API, executor.output_types, and/or a minimal execution path) to keep the regression test stable.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r2): queued for remediation in this pass.

async def handle(self, message, ctx: WorkflowContext[int]) -> None: # type: ignore[no-untyped-def]
pass

executor = ExplicitFutureExecutor(id="explicit_future")
Copy link
Owner Author

Choose a reason for hiding this comment

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

This assertion on _handler_spec["ctx_annotation"] is brittle; if possible assert the resolved types through public/observable surfaces (e.g., output types or successful execution) rather than internal spec structure.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Automated status (r2): queued for remediation in this pass.

@moonbox3 moonbox3 closed this Feb 18, 2026
moonbox3 added a commit that referenced this pull request Mar 5, 2026
Add test_deepcopy_shallow_copy_fields_override_default_exclude to verify
that a field in both DEFAULT_EXCLUDE and _SHALLOW_COPY_FIELDS is
shallow-copied (controlled by _SHALLOW_COPY_FIELDS), while a field in
DEFAULT_EXCLUDE only is still deep-copied. This addresses review comment
#11 ensuring the two class variables control independent concerns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
moonbox3 added a commit that referenced this pull request Mar 5, 2026
Add test_deepcopy_shallow_copy_fields_override_default_exclude to verify
that a field in both DEFAULT_EXCLUDE and _SHALLOW_COPY_FIELDS is
shallow-copied (controlled by _SHALLOW_COPY_FIELDS), while a field in
DEFAULT_EXCLUDE only is still deep-copied. This addresses review comment
#11 ensuring the two class variables control independent concerns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant