[Feature Request/Design Proposal]: Use TypedDict for Model Configuration Options in Python SDK
Background
Currently, in the Genkit Python SDK, model configuration options (such as those for the Gemini plugin) can be specified using either plain dictionaries or typed config objects (e.g., GeminiConfigSchema which is typically a Pydantic model).
As noted in recent discussions, our current documentation frequently shows configuration options being passed as plain dictionaries:
# Current docs often show:
response = await ai.generate(
model='googleai/gemini-2.0-flash',
prompt='Write a python script to reverse a list.',
config={"temperature": 0.7, "maxOutputTokens": 100} # Untyped
)
While users can use the typed GeminiConfigSchema:
from genkit.plugins.google_genai import GeminiConfigSchema
gemini_config = GeminiConfigSchema(
temperature=0.7,
max_output_tokens=100,
code_execution=True
)
The Problem:
- Developer Experience: Plain dictionaries provide no IDE autocompletion, static type checking, or documentation hints. While Pydantic schema objects solve this, requiring users to import and instantiate specific Pydantic models can feel heavy for simple configuration tasks.
- AI Generation: LLMs and AI agents tend to generate plain dictionary configurations naturally.
- Documentation: Our docs heavily feature dicts, leading users away from the typed objects.
Proposed Solution
Introduce typing.TypedDict for model configuration options across the Python SDK.
Using TypedDict allows users to construct simple dictionaries while still benefiting from static type checking and IDE autocompletion.
from typing import TypedDict, NotRequired
class GeminiConfigDict(TypedDict):
temperature: NotRequired[float]
max_output_tokens: NotRequired[int]
code_execution: NotRequired[bool]
# Users can just pass a dict, and static analyzers/IDEs will validate keys and types!
response = await ai.generate(
model='googleai/gemini-2.0-flash',
prompt='...',
config={"temperature": 0.7, "max_output_tokens": 100}
)
Pros and Cons
Pros
- Frictionless DX: Users get the simplicity of dictionaries (no need to instantiate class objects) combined with the benefits of type hints (autocompletion, error checking in IDEs).
- AI-Friendly: Aligns with the tendency of AI agents to generate standard Python dictionaries.
- Documentation Alignment: If we type
config as Union[GeminiConfigDict, GeminiConfigSchema], the docs showing dict usage remain valid but are now implicitly typed.
Cons
- No Runtime Validation:
TypedDict only provides static type checking. Unlike Pydantic models, it does not validate data types at runtime.
- Case Conversion Complexity: (See below)
Key Considerations & Open Questions
1. Snake Case vs. Camel Case
The most significant hurdle is handling naming conventions. Python developers expect snake_case (e.g., max_output_tokens), while the underlying Genkit core or specific model SDKs (like Gemini) often expect camelCase (e.g., maxOutputTokens).
With Pydantic, we easily map snake_case to camelCase using aliases (alias_generator=to_camel). TypedDict does not have built-in runtime aliasing.
Potential Mitigations:
- Standardize on snake_case for the TypedDict: We would need a generic utility function in the SDK that recursively converts
snake_case keys to camelCase before passing the config payload to the core/underlying SDK.
- Require camelCase in TypedDict: This goes against Pythonic conventions and would lead to an awkward DX (
{"maxOutputTokens": 100}).
2. Static Typing vs. Runtime Validation
If a user bypasses static type checkers and passes an invalid type in a TypedDict at runtime (e.g., {"temperature": "hot"}), it will pass through.
Question: Is runtime validation of the config object strictly necessary at the SDK boundary, or is it acceptable to let the underlying Model Provider SDK throw the validation error?
3. Implementation Strategy
Do we replace GeminiConfigSchema (and other plugin schemas) entirely with TypedDict, or do we support both via Union[GeminiConfigDict, GeminiConfigSchema]?
Supporting both gives users a choice (Pydantic for runtime safety, TypedDict for convenience), but increases API surface area and maintenance.
Action Items
- Spike/Exploration: Create a proof-of-concept for replacing or augmenting a model plugin's config with a
TypedDict.
- Case Conversion Strategy: Design a clean mechanism for automatically mapping the
snake_case keys of the TypedDict to the camelCase expected by the internal Genkit engine/providers.
- Docstring Updates: Update the Python SDK docstrings and test cases to actively push towards the newly adopted typed config behavior, ensuring auto-generated documentation reflects best practices.
[Feature Request/Design Proposal]: Use
TypedDictfor Model Configuration Options in Python SDKBackground
Currently, in the Genkit Python SDK, model configuration options (such as those for the Gemini plugin) can be specified using either plain dictionaries or typed config objects (e.g.,
GeminiConfigSchemawhich is typically a Pydantic model).As noted in recent discussions, our current documentation frequently shows configuration options being passed as plain dictionaries:
While users can use the typed
GeminiConfigSchema:The Problem:
Proposed Solution
Introduce
typing.TypedDictfor model configuration options across the Python SDK.Using
TypedDictallows users to construct simple dictionaries while still benefiting from static type checking and IDE autocompletion.Pros and Cons
Pros
configasUnion[GeminiConfigDict, GeminiConfigSchema], the docs showing dict usage remain valid but are now implicitly typed.Cons
TypedDictonly provides static type checking. Unlike Pydantic models, it does not validate data types at runtime.Key Considerations & Open Questions
1. Snake Case vs. Camel Case
The most significant hurdle is handling naming conventions. Python developers expect
snake_case(e.g.,max_output_tokens), while the underlying Genkit core or specific model SDKs (like Gemini) often expectcamelCase(e.g.,maxOutputTokens).With Pydantic, we easily map
snake_casetocamelCaseusing aliases (alias_generator=to_camel).TypedDictdoes not have built-in runtime aliasing.Potential Mitigations:
snake_casekeys tocamelCasebefore passing the config payload to the core/underlying SDK.{"maxOutputTokens": 100}).2. Static Typing vs. Runtime Validation
If a user bypasses static type checkers and passes an invalid type in a
TypedDictat runtime (e.g.,{"temperature": "hot"}), it will pass through.Question: Is runtime validation of the config object strictly necessary at the SDK boundary, or is it acceptable to let the underlying Model Provider SDK throw the validation error?
3. Implementation Strategy
Do we replace
GeminiConfigSchema(and other plugin schemas) entirely withTypedDict, or do we support both viaUnion[GeminiConfigDict, GeminiConfigSchema]?Supporting both gives users a choice (Pydantic for runtime safety, TypedDict for convenience), but increases API surface area and maintenance.
Action Items
TypedDict.snake_casekeys of theTypedDictto thecamelCaseexpected by the internal Genkit engine/providers.