Skip to content

fix: serialize nested BaseModel values in dict inputs (v0.5.7)#159

Open
dineshreddy91 wants to merge 1 commit intomainfrom
fix/serialize-nested-basemodel-in-dict-inputs
Open

fix: serialize nested BaseModel values in dict inputs (v0.5.7)#159
dineshreddy91 wants to merge 1 commit intomainfrom
fix/serialize-nested-basemodel-in-dict-inputs

Conversation

@dineshreddy91
Copy link
Copy Markdown
Contributor

Summary

  • Fixes TypeError: Object of type MessageContent is not JSON serializable when passing dict inputs containing nested Pydantic BaseModel values (e.g. MessageContent) to client.agent.execute().
  • Adds _serialize_value() static method that recursively walks dict/list structures and calls model_dump(exclude_none=True) on any BaseModel instances before the payload reaches json.dumps().
  • Fully backward compatible — plain dict inputs with string/int/bool values pass through unchanged.
  • Bumps version to 0.5.7.

Reproducer (before fix)

from vlmrun.client import VLMRun
from vlmrun.types import MessageContent

client = VLMRun(base_url="https://agent.vlm.run/v1", api_key="...")
response = client.agent.execute(
    inputs={"file": MessageContent(type="input_file", file_id="some-uuid")},
    batch=True,
)
# TypeError: Object of type MessageContent is not JSON serializable

Test plan

  • Existing TestAgentProcessInputs::test_process_inputs_with_dict — plain dict inputs still work
  • Existing TestAgentProcessInputs::test_process_inputs_with_basemodel — BaseModel inputs still work
  • Existing TestAgentProcessInputs::test_process_inputs_with_none — None inputs still work
  • New: test_process_inputs_dict_with_nested_basemodel — MessageContent in dict is serialized
  • New: test_process_inputs_dict_with_list_of_basemodels — list of MessageContent is serialized
  • New: test_process_inputs_dict_plain_values_unchanged — plain values pass through unchanged
  • New: test_process_inputs_dict_with_nested_dict_containing_basemodel — deeply nested BaseModel is serialized
  • All 24 tests pass

Made with Cursor

… TypeError

When passing dict inputs with nested Pydantic BaseModel values (e.g. MessageContent),
the requests library's json.dumps() would fail with "Object of type MessageContent is
not JSON serializable". This adds recursive serialization of BaseModel instances within
dict inputs via _serialize_value(), ensuring all nested models are converted to plain
dicts before HTTP transport.

Bump version to 0.5.7.

Made-with: Cursor
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical serialization issue where Pydantic BaseModel objects nested within dictionary inputs were not correctly converted to JSON-serializable formats, leading to TypeError exceptions. The solution introduces a robust, recursive serialization utility that ensures all BaseModel instances are properly dumped into dictionaries, thereby enabling seamless JSON serialization for complex input structures while maintaining compatibility with existing plain dictionary inputs.

Highlights

  • Serialization Fix: Resolved a TypeError occurring when dictionary inputs to client.agent.execute() contained nested Pydantic BaseModel values, preventing JSON serialization.
  • Recursive Serialization Utility: Implemented a new static method, _serialize_value(), which recursively traverses dictionary and list structures to convert BaseModel instances into dictionaries using model_dump(exclude_none=True) before JSON serialization.
  • Backward Compatibility: Ensured full backward compatibility, allowing plain dictionary inputs with primitive types to pass through without modification.
  • Version Bump: Incremented the package version to 0.5.7.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • tests/test_agent.py
    • Added json and MessageContent imports.
    • Introduced new test cases to validate the serialization of nested BaseModel objects within dictionaries and lists, and to confirm that plain dictionary values are unaffected.
  • vlmrun/client/agent.py
    • Implemented a new static method _serialize_value for recursively converting BaseModel instances to dictionaries.
    • Integrated _serialize_value into the _process_inputs method to handle dictionary inputs containing nested Pydantic models.
  • vlmrun/version.py
    • Updated the package version from 0.5.6 to 0.5.7.
Activity
  • The author, dineshreddy91, has provided a detailed summary of the fix, including a reproducer and a comprehensive test plan.
  • Existing tests for plain dict, BaseModel, and None inputs were verified to still pass.
  • Four new test cases were added to specifically cover nested BaseModel serialization within dicts and lists, and to confirm plain value preservation.
  • All 24 tests passed after the changes.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively addresses a TypeError during JSON serialization of nested Pydantic BaseModel instances within dictionary inputs by introducing a recursive _serialize_value helper. The changes are well-tested with new unit tests covering various scenarios. I have a few suggestions to improve the implementation's robustness and maintainability.

return value.model_dump(exclude_none=True)
elif isinstance(value, dict):
return {k: Agent._serialize_value(v) for k, v in value.items()}
elif isinstance(value, list):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation only handles lists. It would be more robust to also handle other sequence types like tuples, which might also contain BaseModel instances. If a tuple of BaseModels is passed, json.dumps will fail.

Suggested change
elif isinstance(value, list):
elif isinstance(value, (list, tuple)):

Comment on lines +305 to +310
class MockClient:
api_key = "test-key"
base_url = "https://api.vlm.run/v1"
timeout = 120.0
max_retries = 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve maintainability and reduce code duplication, consider defining the MockClient class once at the TestAgentProcessInputs class level or as a pytest fixture. It is repeated in every test method within this test class (e.g., test_process_inputs_with_dict, test_process_inputs_with_basemodel, etc.), including the newly added tests.

DeprecationWarning,
stacklevel=3,
)
return {k: self._serialize_value(v) for k, v in inputs.items()}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with how _serialize_value is called within itself recursively, it would be clearer to call it as a static method using Agent._serialize_value(...) here as well, instead of self._serialize_value(...). This makes it more explicit that it's a static method and doesn't depend on the instance state.

Suggested change
return {k: self._serialize_value(v) for k, v in inputs.items()}
return {k: Agent._serialize_value(v) for k, v in inputs.items()}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant