Skip to content

Parameters TypedDict subclasses missing total=False — every field becomes required under strict mypy #255

@Kamilbenkirane

Description

@Kamilbenkirane

Summary

All 5 modality Parameters TypedDict subclasses — TextParameters, ImageParameters, VideoParameters, AudioParameters, EmbeddingsParameters — declare their fields without total=False. Under strict mypy, every field on these classes is treated as required, which cascades through Unpack[...] (PEP 692) to break every caller of celeste.text.generate, celeste.images.generate, etc.

The templates/modalities/{modality_slug}/parameters.py.template has the same bug, so every new modality scaffolded from it inherits the issue.

Root cause

Per PEP 589:

"The totality flag only applies to items defined in the body of the TypedDict definition. Inherited items won't be affected, and instead use totality of the TypedDict type where they were defined."

The base class is correct:

# src/celeste/parameters.py:10
class Parameters(TypedDict, total=False):
    """Base parameters for all capabilities."""

But every subclass declares its own fields without carrying the flag over:

# src/celeste/modalities/text/parameters.py:44
class TextParameters(Parameters):          # ← missing total=False
    temperature: float
    max_tokens: int
    seed: int
    thinking_budget: int | str
    thinking_level: str
    output_schema: type[BaseModel]
    tools: list[ToolDefinition]
    tool_choice: ToolChoiceOption
    verbosity: str
    web_search: bool
    x_search: bool
    code_execution: bool

Because TextParameters itself does not declare total=False, every field in its own body is required from mypy's perspective.

Why it hasn't surfaced internally

pyproject.toml (lines 167-185) has [[tool.mypy.overrides]] blocks that blanket-disable call-arg on celeste.modalities.*.client, celeste.providers.*.*, and other internal modules. Those overrides silence the error at the internal call sites but do not protect downstream consumers.

How it surfaces downstream

A strict-mypy downstream package (celeste-tools, which uses celeste.text.generate with strict type-checking enabled) hits 37 [call-arg] errors like:

src/celeste_tools/web_fetch/web_fetch.py:182: error: Missing named argument "temperature" for "generate" of "TextNamespace"  [call-arg]
src/celeste_tools/web_fetch/web_fetch.py:182: error: Missing named argument "max_tokens" for "generate" of "TextNamespace"  [call-arg]
src/celeste_tools/web_fetch/web_fetch.py:182: error: Missing named argument "seed" for "generate" of "TextNamespace"  [call-arg]
...
src/celeste_tools/web_fetch/web_fetch.py:182: error: Missing named argument "code_execution" for "generate" of "TextNamespace"  [call-arg]

One error per TextParameters field, per call site.

Affected files

File Line Class
src/celeste/modalities/text/parameters.py 44 TextParameters
src/celeste/modalities/images/parameters.py 29 ImageParameters
src/celeste/modalities/videos/parameters.py 20 VideoParameters
src/celeste/modalities/audio/parameters.py 18 AudioParameters
src/celeste/modalities/embeddings/parameters.py 17 EmbeddingsParameters
templates/modalities/{modality_slug}/parameters.py.template 35 {Modality}Parameters

Fix

Six one-word changes. Add , total=False to each class declaration:

class TextParameters(Parameters, total=False):
class ImageParameters(Parameters, total=False):
class VideoParameters(Parameters, total=False):
class AudioParameters(Parameters, total=False):
class EmbeddingsParameters(Parameters, total=False):
# And in the template
class {Modality}Parameters(Parameters, total=False):

Why total=False and not PEP 655 NotRequired[...]

  • PEP 655 explicitly states the two forms are equivalent and does not deprecate total=False.
  • The Parameters base is already total=False — keeping the subclasses consistent.
  • Ecosystem precedent for all-optional TypedDicts used with Unpack[...]: pydantic.ConfigDict, openai.types.chat.CompletionCreateParamsBase, anthropic.types.MessageCreateParamsBase, google-genai param types, and typeshed stubs all use TypedDict, total=False with occasional Required[...] for the rare genuinely-required fields. Zero NotRequired hits in openai-python's and anthropic-sdk-python's types folders.

Follow-up (not this issue)

Once the root cause is fixed, several [[tool.mypy.overrides]] blocks in pyproject.toml that disable call-arg on celeste.modalities.*.client may no longer be needed. Worth auditing in a separate PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions