Skip to content

Typing hardening: reduce defensive getattr / Any across the runtime #110

Description

This issue is for a: (mark with an x)

- [ ] bug report -> please search issues before submitting
- [x] feature request
- [ ] documentation issue or request
- [ ] regression (a behavior that used to work and stopped in a new release)

Minimal steps to reproduce

N/A — code-quality / tech-debt follow-up, not a runtime bug.

Any log messages given by the failure

N/A

Expected/desired behavior

Strengthen type annotations across the runtime so defensive getattr(...) access and loose Any typing can be replaced with direct, statically-verified attribute access wherever the type is knowable. Annotate framework-return boundaries with concrete Microsoft Agent Framework types (AgentResponse, FunctionTool, etc.), tighten our own signatures/returns/fields, and remove getattr/or <default> fallbacks that strong typing renders dead — keeping mypy --strict clean with no new # type: ignore.

OS and Version?

N/A (all platforms)

Versions

agent-framework-core==1.3.* (ships py.typed; azure_functions_agents.* already runs mypy strict = true).

Mention any other details that might be useful

Context. Surfaced during the FRD 0006 multi-agent delegation work. The new delegation code (delegate path in runner.py, config SubagentRef/validation, registration/catalog.py, app.py composition) was already brought to strict typing there; this issue tracks the remaining pre-existing footprint across the rest of the runtime, deliberately deferred rather than bundled into the delegation PR to keep it reviewable.

Rough scope (src/ only, ~40 files): ~50 getattr( and ~250 Any annotations. Highest-density: runner.py (~20 getattr / ~48 Any), registration/_handlers.py (8/17), registration/_trigger_serialization.py (5/5), workflows/tools.py (4/15), registration/endpoints.py (1/18), _function_tool.py (1/21), config/validation.py (3/1), registration/capabilities.py (2/7), _observability.py (0/14), _blob_history.py (0/12).

Judgment-heavy, not mechanical — much of the Any is legitimate and should stay:

  • Arbitrary user JSON/config (dict[str, Any]: args, workflows, metadata, input_schema/response_schema, TRIGGER_TYPES).
  • MAF tool union ToolTypes = FunctionTool | MCPTool | Mapping[str, Any] | object (the trailing object makes list[Any] accurate, not under-typing).
  • Dynamic MAF Contents union parsing (needs isinstance dispatch).
  • External libs without stubs (e.g. azure.durable_functions -> workflow_durable_client: Any).

Suggested approach: own dedicated PR (not folded into feature PRs); type at framework-return boundaries rather than scattering cast(); keep typed guards where values are genuinely dynamic; gate on mypy --strict for touched files, no behavior change.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions