Skip to content

Conversation

darkhaniop
Copy link
Contributor

@darkhaniop darkhaniop commented Jun 19, 2025

BEGIN_COMMIT_OVERRIDE

Description

This update makes Starlette and FastAPI libraries as optional dependencies. Users can run uv add a2a-sdk[http-server] to install these dependencies.

Additional Checks

  • Verified that the "helloworld" agent sample works with this change.
  • Verified that a reasonable error message is printed when trying to use A2AFastAPIApplication.

Release-As: 0.3.1
END_COMMIT_OVERRIDE

With this update, using A2AFastAPIApplication requires either adding
the FastAPI package directly to the project or indicating the "fastapi"
group when installing a2a-sdk, e.g., with uv "uv add a2a-sdk[fastapi]"
or with pip "pip install a2a-sdk[fastapi]"
@darkhaniop darkhaniop requested a review from a team as a code owner June 19, 2025 12:03
@darkhaniop darkhaniop requested a review from mvakoc June 19, 2025 12:03
When defining missing optional dependencies from fastapi, mypy issues
errors of the following form: 'Name "FastAPI" already defined
(possibly by an import) [no-redef]'. This commit fixes such mypy errors.
Updates the FastAPI optional dependency installation instructions in
README.md.
On app initialization with app = A2aFastAPIApplication(), check that the
FastAPI package is installed and raise ImportError with the custom
messsage if necessary.
@holtskinner
Copy link
Member

This won't solve the core issue on its own, because starlette is also a dependency and it depends on fastapi, so you'll need to remove that dependency as well.

@darkhaniop
Copy link
Contributor Author

Hi @holtskinner,

This won't solve the core issue on its own, because starlette is also a dependency and it depends on fastapi, so you'll need to remove that dependency as well.

It seems the dependencies are the other way around, so if we do it one framework at a time, I think refactoring FastAPI first makes sense.

Starlette dependency tree

A quick dependency check shows that starlette (also sse-starlette) depends only on the anyio` package:

dummy-project v0.1.0
└── starlette v0.47.0
    └── anyio v4.9.0
        ├── idna v3.10
        └── sniffio v1.3.1
for reference, see FastAPI dependency tree here

FastAPI dependency tree

On the other hand, if a project requires fastapi, the dependency tree would also include starlette:

another-dummy-project v0.1.0
└── fastapi v0.115.13
    ├── pydantic v2.11.7
    │   ├── annotated-types v0.7.0
    │   ├── pydantic-core v2.33.2
    │   │   └── typing-extensions v4.14.0
    │   ├── typing-extensions v4.14.0
    │   └── typing-inspection v0.4.1
    │       └── typing-extensions v4.14.0
    ├── starlette v0.46.2
    │   └── anyio v4.9.0
    │       ├── idna v3.10
    │       └── sniffio v1.3.1
    └── typing-extensions v4.14.0

SDK development vs downstream project dependencies

I kept FastAPI in dev dependencies so that when working on the SDK itself, i.e., running uv sync in the SDK dir, all frameworks (both Starlette and FastAPI) would be installed in the environment.

At the same time, with this refactoring non-FastAPI downstream projects (agents) that use a2a-sdk should become lighter without FastAPI and its dependencies. And those that use (a potentially different version of) FastAPI would less likely to encounter dependency conflicts.

Considerations for next steps (refactoring starlette)

In this PR, I propose refactoring only the FastAPI dependency, as it requires fewer changes. After that, we can look into making the Starlette package optional.

As I stated earlier (see my comment in #101), it would be nice to eventually make all frameworks (both FastAPI and Starlette) optional.

However, since all of the samples and documentation are written under the assumption that installing a2a-sdk adds Starlette, making it optional would introduce a bigger breaking change and require more involved refactoring and testing:

  • Docs and tutorials would also need to be updated (would require a follow-up PR in google-a2a/a2a).
  • Samples would have to be updated to directly require Starlette (would require follow-up PRs in google-a2a/a2a-samples).

Package respx was added by another PR, so we need to resync uv.lock.
@holtskinner holtskinner force-pushed the make-fastapi-package-optional branch from 3788450 to 1d06e63 Compare June 23, 2025 12:20
@holtskinner holtskinner requested a review from a team as a code owner June 24, 2025 09:47
@holtskinner
Copy link
Member

@darkhaniop Sorry for the extra hassle, but could you make this work with the new refactoring in #348

pstephengoogle pushed a commit to a2aproject/a2a-samples that referenced this pull request Aug 4, 2025
* chore(deps): Update python samples' optional deps

In future versions of a2a-sdk, HTTP server packages may become optional.
See a2aproject/a2a-python/pull/217 for details. This PR ensures that
agents in `samples/python/agents/` continue to work with the future
versions on a2a-sdk.

Refs #190

* Add langchain-openai dep to the langgraph sample

This issue was noted by the automated code review bot.
Adds optional card_modifier and extended_card_modifier params to
A2AFastAPIApplication and A2AStarletteApplication constructors.
Additionally, coverage fails when test files have the same name:
./jsonrpc_test_fastapi_app.py and ./rest/test_fastapi_app.py
So, the latter one was renamed to ./rest/test_rest_fastapi_app.py
Ensures the version specifier is the same as on the main branch.
This ensures the importing of the upper level packages a2a.server.apps
succeed when optional http-server dependencies are not installed.
@darkhaniop
Copy link
Contributor Author

@darkhaniop Sorry for the extra hassle, but could you make this work with the new refactoring in #348

From what I understood, the newly added RESTful interface modules directly import Starlette and FastAPI (and since they are always initialized by the upper-level package in a2a.server.apps.__init__.py), we needed to refactor these new modules similar to the ones in ./apps/jsonrpc to ensure abstract apps continue working (e.g., the helloworld sample).

So, I refactored the imports and made other minor adjustments to make it work with recent changes from the main branch.

Please let me know if you find anything missing.

Copy link
Collaborator

@kthota-g kthota-g left a comment

Choose a reason for hiding this comment

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

Hi,
thanks for the PR. I see a couple of other places where the starlette imports are unhandled. Can you please address these as well?

from starlette.requests import Request

from starlette.responses import JSONResponse, Response

Ensures [http-server] optional dependency imports are handled within
try-except in utility modules:
- server/request_handlers/rest_handler.py
- and utils/error_handlers.py
Also, removes duplicate imports from `starlette` in `rest_adapter.py`.
@darkhaniop
Copy link
Contributor Author

@kthota-g, thanks for the review. I applied the changes.
No new unit tests were added. I don't think we need them for these cases.

In rest_handler.py, the import from starlette is currently used only for type annotations, so no additional tests are necessary.
And, it looks like methods in error_handlers.py are only used as decorators in RESTAdapter, which handles the import error message.

@kthota-g kthota-g merged commit eb24654 into a2aproject:main Aug 7, 2025
5 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.

7 participants