Azure / Azure/azure-functions-agents-runtime

Typing hardening: reduce defensive getattr / Any across the runtime

Open
#110 0 comments 0 reactions 0 assignees View on GitHub
task
Dominant language
Python
Stars
9
Forks
7
Avg merge
1d 21h
Merged PRs (30d)
20

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 ` 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.

Contributor guide

Open the contributing guide

Research direction

Start with mypy --strict and the highest-density files named in the issue, especially runner.py, registration/_handlers.py, registration/_trigger_serialization.py, and workflows/tools.py. Trace framework-return boundaries and existing dynamic-value guards before changing annotations; done means touched runtime files remain strict-clean, with no new type ignores and no behavior change.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, python
Domain
backend, developer-experience
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.