Repository navigation
fix(providers): keep protocol types narrow and unwrap PEP 695 aliases - #20
Merged
Merged
Conversation
Two type-erasure defects found while a strict downstream host consumed the
provider substrate. Both are silent: the annotation reads correctly at the
call site and the wrong type only shows up further downstream.
`protocol_of` and `thinking_format_for_protocol` were extracted with `-> str`
and `-> str | None`, widening what the host they came from declared. Their
outputs feed `ModelProfile.protocol` / `.thinking_format`, which are `Literal`
unions, so a value this module had just validated with `is_wire_protocol` was
no longer assignable to the very field it was validated for. This file is
checked at `basic` level, so nothing here caught it; a strict host did, with
four errors in code it had not touched.
`_schema_for_type` mapped a PEP 695 `type Alias = ...` straight to
`{"type": "string"}`: a TypeAliasType is not a primitive, has no origin, and is
not a Pydantic model, so it reached the `Any` floor. That floor is a deliberate
choice for under-annotated parameters — an alias is the opposite, and a tool
author who names a union to describe a parameter precisely got a schema
claiming it was a string. Unwrap `__value__` instead. `agent_core` uses `type`
statements itself (pause_check, openai_chat), so this was live.
Validation:
- uv run ruff check agent_core tests
- uv run pyright agent_core (0 errors)
- uv run pytest -q (1054 passed)
- both new alias tests fail with the unwrap removed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two silent type-erasure defects found while a strict downstream host consumed the provider substrate (FrontierAgent #104).
protocol_of/thinking_format_for_protocolwere widened tostrduring extraction. Their outputs feedModelProfile.protocol/.thinking_format, which areLiteralunions — so a value this module had just validated withis_wire_protocolwas no longer assignable to the very field it was validated for.protocol_client.pyis checked atbasiclevel, so nothing here caught it; the strict host did, with 4 pyright errors in code it had not touched. Restores the narrow aliases the host declared before extraction. Signatures only, no body changes._schema_for_typemapped a PEP 695type Alias = ...to{"type": "string"}. ATypeAliasTypeis not a primitive, has no origin, and is not a Pydantic model, so it fell through to theAnyfloor. That floor is a deliberate choice for under-annotated parameters — an alias is the opposite: a tool author who names a union to describe a parameter precisely got a schema claiming it was a string, with the annotation looking correct in the source. Now unwraps__value__.agent_coreusestypestatements itself (runtime/pause_check.py,providers/openai_chat.py), so this was live rather than hypothetical.Validation
uv run ruff check agent_core testsuv run pyright agent_core— 0 errorsuv run pytest -q— 1054 passed