Skip to content

feat(db): support multiple SQL backends with optional extras (cont. #80) #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Jun 2, 2025

Conversation

zboyles
Copy link

@zboyles zboyles commented May 25, 2025

What’s changed

  • Continued work from feat: Postgres task store #80 to remove the hard-coded PostgreSQL provider
  • Upgraded to SQLAlchemy 2.0 and introduced a generic DatabaseTaskStore interface
  • Added optional extras in pyproject.toml for database drivers:
    • a2a-sdk[postgresql]
    • a2a-sdk[mysql]
    • a2a-sdk[sqlite]
    • a2a-sdk[sql]
  • Updated example apps and README with installation/usage for each backend

Why

Per @kthota-g’s feedback (#80 (comment)), making the SDK database-agnostic increases flexibility and broadens adoption.

Testing

  • Tests have been updated for SQLAlchemy 2.0 and pass under pytest and nox locally
  • Note: not yet validated in an external project

Notes

  • Initial changes were generated by the Google-Labs-Jules bot; I’ve manual-refactored and resolved outdated SQLAlchemy patterns; See Jules commit if interested.
  • I’m less familiar with consuming this repo - would appreciate extra scrutiny around real-world initialization of each provider

Please focus review on: interface design/naming, optional-extra configuration, test coverage, and real-world usage scenarios.

LaurentMnr95 and others added 20 commits May 21, 2025 11:41
This commit replaces the PostgreSQL-specific TaskStore with a generic
`DatabaseTaskStore` that leverages SQLAlchemy for database interactions.
This change allows your A2A server to support multiple database backends,
including SQLite, PostgreSQL, and MySQL.

Key changes include:
- Definition of a SQLAlchemy model `TaskModel` for storing task data.
- Implementation of `DatabaseTaskStore` that uses the `TaskStore` interface
  and SQLAlchemy for CRUD operations.
- Update of example application configurations to use `DatabaseTaskStore`
  when a `DATABASE_URL` environment variable is provided, defaulting to
  `InMemoryTaskStore` otherwise.
- Creation of parameterized unit tests for `DatabaseTaskStore`, designed
  to run against SQLite, PostgreSQL, and MySQL to ensure compatibility.
- Removal of the old `PostgreSQLTaskStore` and its specific tests.
- Addition of necessary dependencies: `sqlalchemy`, `aiosqlite`, `aiomysql`.

The new implementation makes the task persistence layer more flexible
and extensible, allowing you to choose a database backend that best
suits your needs.
This commit replaces the PostgreSQL-specific TaskStore with a generic
`DatabaseTaskStore` that leverages SQLAlchemy for database interactions.
This change allows your A2A server to support multiple database backends,
including SQLite, PostgreSQL, and MySQL.

Key changes include:
- Definition of a SQLAlchemy model `TaskModel` for storing task data.
- Implementation of `DatabaseTaskStore` that uses the `TaskStore` interface
  and SQLAlchemy for CRUD operations.
- Update of example application configurations to use `DatabaseTaskStore`
  when a `DATABASE_URL` environment variable is provided, defaulting to
  `InMemoryTaskStore` otherwise.
- Creation of parameterized unit tests for `DatabaseTaskStore`, designed
  to run against SQLite, PostgreSQL, and MySQL to ensure compatibility.
- Removal of the old `PostgreSQLTaskStore` and its specific tests.
- Addition of necessary dependencies: `sqlalchemy`, `aiosqlite`, `aiomysql`.

The new implementation makes the task persistence layer more flexible
and extensible, allowing you to choose a database backend that best
suits your needs.
This commit introduces optional dependencies for PostgreSQL, MySQL, and SQLite support in the A2A SDK. Key changes include:
- Addition of optional dependencies in `pyproject.toml` for database drivers.
- Updates to example applications to demonstrate installation and usage with different databases.
- Refactoring of task management to utilize a generic `DatabaseTaskStore` for improved flexibility.
- Enhancements to the README for clearer instructions on database support.

These changes enhance the SDK's versatility, allowing users to choose their preferred database backend.
… gracefully skip when SQLAlchemy isn't installed locally
@zboyles
Copy link
Author

zboyles commented May 27, 2025

@kthota-g if you have a moment, could you please take a look at this PR and let me know if it's what you had in mind in #80, any feedback is welcome.

@zboyles zboyles marked this pull request as ready for review May 28, 2025 05:54
@holtskinner
Copy link
Collaborator

Can you please move the changes to the sample agents to the new samples repo? https://github.com/google-a2a/a2a-samples

@kthota-g
Copy link
Collaborator

@zboyles thanks for the PR. Few comments:

  • Since all the examples have already been moved to a2a-samples repo, can you remove the changes related to examples from this PR.
  • Table name for Tasks should be configurable value.
  • Types is a generated file based on the JSON schema, your changes to types.py should be discarded. I see the TaskState is updated to StrEnum in your PR. I will try to get this changed via the generator.

I will merge this PR to a new branch so change required for database based PushNotifier and common db connection are done and then will merge into main.

This allows users to choose their preferred database backend (PostgreSQL, MySQL, SQLite) while maintaining full compatibility and proper type safety.

- Replace PostgreSQL-specific JSONB with generic JSON type in models
- Implement SQLAlchemy 2.0 best practices with Mapped types and TypeDecorator
- Add configurable table name support via create_task_model() factory
- Updated metadata field mapping between Pydantic and SQLAlchemy using declared_attr
- Add comprehensive tests for metadata field mapping including complex nested data
- Update GitHub Actions to install SQL dependencies for tests
- Add pytest.importorskip to gracefully skip database tests when SQLAlchemy not installed
- Fix test_types.py to use 'id' instead of 'taskId' for JSON-RPC requests
- Add automatic cleanup of SQLite file::memory: files after tests
- Remove examples directory (moved to separate a2a-samples repo)
- Update pyproject.toml to remove workspace members reference and add `nox` for testing
@zboyles zboyles requested a review from a team as a code owner June 1, 2025 06:31
- Update repository reference to google-a2a/a2a-python
- Keep PostgreSQL service configuration for tests
- Regenerate uv.lock to resolve dependency conflicts
@zboyles
Copy link
Author

zboyles commented Jun 1, 2025

Thanks @holtskinner and @kthota-g.

  • Examples were removed (per request to use a2a-samples repo)
  • Implemented two options for creating a TaskModel with custom table names:
    • Via TaskMixin for custom implementations and
    • create_task_model() factory function
    • Kept a default TaskModel class for general compatibility with standard table name
  • Used @declared_attr decorator to map Pydantic's metadata to the task's metadata fieldname without the pydantic conflicts
    • Added tests to ensure the metadata field mapping works correctly in both directions
    • Updated tests for upstream changes to the id field per JSON Schema generated type
  • Added custom TypeDecorator classes, PydanticType and PydanticListType, to handle automatic serialization/deserialization between the SQLAlchemy JSON columns and their associated JSON schema generated pydantic types
  • Added nox to the dev group so the contribution instructions were functional
  • Added postgres GitHub Actions test

zboyles added 2 commits June 1, 2025 03:44
…patibility

The override decorator was added in Python 3.12. For compatibility with Python 3.10,
we import it from typing_extensions when not available in the typing module.
@kthota-g kthota-g changed the base branch from main to sql-support June 2, 2025 18:06
@kthota-g
Copy link
Collaborator

kthota-g commented Jun 2, 2025

Thanks for the changes. I will merge this PR into a sql-support branch to add support for PushNotifier and will merge into main.

@kthota-g kthota-g merged commit b00905a into google-a2a:sql-support Jun 2, 2025
6 checks passed
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.

4 participants