Follow-up to the optional bonus in #601 that PR #602 (`to_wire_dict` seam) and #600 (annotation fixes) deliberately deferred.
Current behaviour
```python
def create_mcp_webhook_payload(...) -> dict[str, Any]:
...
```
Adopters who want a typed shape do the ceremony manually. From `salesagent/context_manager.py`:
```python
TODO: Fix in adcp python client - create_mcp_webhook_payload should return
McpWebhookPayload instead of dict[str, Any] for proper type safety
mcp_payload_dict = create_mcp_webhook_payload(step.step_id, status_enum, step.response_data)
payload = McpWebhookPayload.model_construct(**mcp_payload_dict)
```
Proposed change
```python
def create_mcp_webhook_payload(...) -> McpWebhookPayload:
...
```
Adopters drop `.model_construct(**dict)` and get a typed instance directly. Anyone who needs the wire dict calls `to_wire_dict(payload)` (#602) — the seam handles both shapes uniformly, so this is purely an ergonomics win.
Why this didn't ship in #602 / #600
Compatibility
Breaking for any adopter that mutates the dict, calls `.update()`, or reads keys without unwrapping. Migration:
| Old (dict) |
New (McpWebhookPayload) |
| `payload["task_id"]` |
`payload.task_id` |
| `payload.update(extra)` |
n/a — use the builder kwargs |
| `json.dumps(payload)` |
`to_wire_dict(payload)` (or `payload.model_dump(mode="json", exclude_none=True)`) |
| HTTP transport (`json=payload`) |
`json=to_wire_dict(payload)` |
Suggested rollout
One minor with widened return type `dict[str, Any] | McpWebhookPayload` and a deprecation note in the builder docstring, then drop `dict` in the next minor. Or skip the widening since runtime callers see no shape difference if they switch to `to_wire_dict` — strictly a typing-surface change for adopters who type-check.
Acceptance criteria
References
Follow-up to the optional bonus in #601 that PR #602 (`to_wire_dict` seam) and #600 (annotation fixes) deliberately deferred.
Current behaviour
```python
def create_mcp_webhook_payload(...) -> dict[str, Any]:
...
```
Adopters who want a typed shape do the ceremony manually. From `salesagent/context_manager.py`:
```python
TODO: Fix in adcp python client - create_mcp_webhook_payload should return
McpWebhookPayload instead of dict[str, Any] for proper type safety
mcp_payload_dict = create_mcp_webhook_payload(step.step_id, status_enum, step.response_data)
payload = McpWebhookPayload.model_construct(**mcp_payload_dict)
```
Proposed change
```python
def create_mcp_webhook_payload(...) -> McpWebhookPayload:
...
```
Adopters drop `.model_construct(**dict)` and get a typed instance directly. Anyone who needs the wire dict calls `to_wire_dict(payload)` (#602) — the seam handles both shapes uniformly, so this is purely an ergonomics win.
Why this didn't ship in #602 / #600
Compatibility
Breaking for any adopter that mutates the dict, calls `.update()`, or reads keys without unwrapping. Migration:
Suggested rollout
One minor with widened return type `dict[str, Any] | McpWebhookPayload` and a deprecation note in the builder docstring, then drop `dict` in the next minor. Or skip the widening since runtime callers see no shape difference if they switch to `to_wire_dict` — strictly a typing-surface change for adopters who type-check.
Acceptance criteria
References