Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,20 @@ This document defines the compatibility promises `opencode-a2a` currently uphold

This is the single canonical place where the supported upstream OpenCode version line is declared. Keep it updated together with the live integration smoke check (`./scripts/live_opencode_smoke.sh`) and do not duplicate the version line elsewhere.

The repository currently pins one concrete SDK release in `pyproject.toml` within that v1 line. Upgrade the SDK deliberately rather than relying on floating dependency resolution. The SDK-owned core JSON-RPC method set follows that pinned release and is locked by repository tests so SDK upgrades trigger an explicit compatibility review.
The SDK-owned core JSON-RPC method set follows the supported SDK line and is locked by repository tests so SDK upgrades trigger an explicit compatibility review.

### SDK and Dependency Review
### SDK and Adapter Review

The [SDK 1.1.2 to 1.1.5 changes](https://github.com/a2aproject/a2a-python/compare/v1.1.2...v1.1.5) include cross-event-loop locking fixes, task-list ordering fixes, and protobuf 7 support. The adapter's reviewed integration boundaries are:
The [SDK 1.1.2 to 1.1.5 changes](https://github.com/a2aproject/a2a-python/compare/v1.1.2...v1.1.5) include cross-event-loop locking fixes and task-list ordering fixes. The adapter's reviewed integration boundaries are:

| Boundary | Decision and regression evidence |
| --- | --- |
| `DatabaseTaskStoreCompat` | Retained: SDK `DatabaseTaskStore.save` still performs an unconditional ORM merge. The adapter needs an atomic first-terminal-state-wins guard; task-store tests cover shape drift, ORM conversion parity, and independent store instances. |
| Legacy stored task conversion | Retained for SDK-owned persisted rows. This does not restore legacy A2A 0.3 wire support. |
| Request-handler hooks and queue lifecycle | Retained for output negotiation, cancel idempotency, and persistence after client disconnect. Handler regressions exercise these behaviors against the pinned SDK; private hooks remain an SDK upgrade review boundary. |
| Request-handler hooks and queue lifecycle | Retained for output negotiation, cancel idempotency, and persistence after client disconnect. Handler regressions exercise these behaviors against the SDK; private hooks remain an SDK upgrade review boundary. |
| Outbound header forwarding | Uses the SDK `service_parameters` channel. Client transport tests check the final HTTP request, including authentication and tracing headers. |
| Protobuf | Supports `>=6.33.5,<8.0`. The default CI uses locked 7.36.2; a separate Python 3.11 job installs 6.33.6 and disables uv synchronization throughout the test process tree, so nested protocol probes also exercise protobuf 6. SDK 1.1.5 removes the former protobuf 7 blocker, so the obsolete Dependabot ignore is removed. |
| Security floors | `click>=8.3.3` and `pyasn1>=0.6.4` remain necessary because upstream metadata permits older versions. They are runtime requirements so wheel and sdist installs enforce them without uv-specific constraints. Installed-metadata tests protect these floors and the SQLAlchemy asyncio extra. |

The missing-import typing overrides for `google.protobuf.*` and `jsonrpc.*` remain limited to those third-party modules. Runtime support is validated by the SDK and transport regressions, not inferred from the typing overrides. Ruff's local pre-commit hooks run through `uv run --locked --extra dev`, so `uv.lock` is the single version source for linting and formatting.
The missing-import typing overrides for `google.protobuf.*` and `jsonrpc.*` remain limited to those third-party modules. Runtime support is validated by the SDK and transport regressions, not inferred from the typing overrides.

## Contract Honesty

Expand Down
6 changes: 1 addition & 5 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,6 @@ The runtime configures local durability-oriented SQLite connection settings (`WA

Empty SQLite URLs, `:memory:` URLs, and `mode=memory` URIs explicitly use `StaticPool` to share one database connection across checkouts. This preserves the existing ephemeral database behavior when SQLAlchemy changes its automatic pool selection. File-backed databases retain SQLAlchemy's default connection pool and the file hardening described below.

The package declares `sqlalchemy[asyncio]` so standalone installs such as `uv tool install opencode-a2a` include `greenlet`, which is required by the async database engine. SQLAlchemy 2.1 no longer installs `greenlet` by default; declaring the extra in package metadata keeps wheel installs independent of the repository's `uv.lock`.

Published package metadata also enforces the security floors `click>=8.3.3` and `pyasn1>=0.6.4`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed.

Unhandled execution errors and shutdown interruptions persist `FAILED` when storage is available, preserving existing terminal states. Shutdown drains buffered output before closing clients and stores. SSE disconnects allow execution to continue; use `CancelTask` to request an upstream abort before stopping the application.

### SQLite Persistence Hardening
Expand Down Expand Up @@ -364,7 +360,7 @@ Current behavior:
- `all_jsonrpc_methods` is the runtime truth for the current deployment.
- The current SDK-owned core JSON-RPC surface includes `GetExtendedAgentCard` and `tasks/pushNotificationConfig/*`.
- The current SDK-owned REST surface also includes `GET /tasks` and the task push notification config routes.
- The SDK-owned core JSON-RPC method set follows the pinned `a2a-sdk` release and is locked by repository tests; review that surface deliberately when upgrading the SDK.
- The SDK-owned core JSON-RPC method set is locked by repository tests; review that surface deliberately when upgrading the SDK.
- Push notification config routes/methods are currently exposed only because they are part of the SDK-owned core surface. This runtime does not configure a push config store or push sender, so operations return the A2A 1.0 `PushNotificationNotSupportedError` contract: HTTP `400` for REST and JSON-RPC code `-32003`.

When `A2A_ENABLE_SESSION_SHELL=false`, `opencode.sessions.shell` is omitted from `all_jsonrpc_methods` and exposed only through `extensions.conditionally_available_methods`.
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ dependencies = [
"pyasn1>=0.6.4",
"sqlalchemy[asyncio]>=2.0,<3.0",
"sse-starlette>=2.1,<4.0",
# urllib3: PYSEC-2026-4175/4176/4177 (via requests <- google-api-core <- a2a-sdk).
"urllib3>=2.8.0",
"uvicorn>=0.29,<1.0",
]

Expand Down
24 changes: 0 additions & 24 deletions tests/package/test_dependency_contract.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from importlib.metadata import requires

import pytest
from packaging.requirements import Requirement


Expand All @@ -15,29 +14,6 @@ def _runtime_requirement(name: str) -> Requirement:
return requirements[0]


@pytest.mark.parametrize(
("name", "unsafe_version", "safe_version"),
[("click", "8.3.2", "8.3.3"), ("pyasn1", "0.6.3", "0.6.4")],
)
def test_installed_metadata_enforces_security_floors(
name: str, unsafe_version: str, safe_version: str
) -> None:
requirement = _runtime_requirement(name)
assert unsafe_version not in requirement.specifier
assert safe_version in requirement.specifier


def test_installed_metadata_requests_sqlalchemy_asyncio() -> None:
requirement = _runtime_requirement("sqlalchemy")
assert "asyncio" in requirement.extras
assert "2.0.54" in requirement.specifier
assert "2.1.1" in requirement.specifier
assert "3.0.0" not in requirement.specifier


def test_installed_metadata_bounds_supported_protobuf_versions() -> None:
requirement = _runtime_requirement("protobuf")
assert "6.33.4" not in requirement.specifier
assert "6.33.5" in requirement.specifier
assert "7.36.2" in requirement.specifier
assert "8.0.0" not in requirement.specifier
27 changes: 15 additions & 12 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading