opencode-a2a 0.7.1__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opencode_a2a-0.8.0/.github/dependabot.yml +16 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/CONTRIBUTING.md +5 -4
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/PKG-INFO +7 -3
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/README.md +5 -1
- opencode_a2a-0.8.0/docs/architecture.md +101 -0
- opencode_a2a-0.8.0/docs/compatibility.md +147 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/docs/extension-specifications.md +1 -1
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/docs/guide.md +5 -1
- opencode_a2a-0.8.0/docs/maintainer-architecture.md +132 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/pyproject.toml +1 -1
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/scripts/README.md +3 -1
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/scripts/doctor.sh +10 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/polling.py +3 -9
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/executor.py +1 -7
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/request_context.py +12 -23
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/stream_runtime.py +15 -1
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/common.py +261 -41
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/interrupt_callbacks.py +9 -9
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/interrupt_queries.py +9 -11
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/provider_discovery.py +25 -50
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/session_control.py +90 -144
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/session_lifecycle.py +209 -259
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/session_queries.py +34 -49
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/workspace_control.py +158 -106
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/methods.py +84 -94
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/params.py +37 -78
- opencode_a2a-0.8.0/src/opencode_a2a/metadata_access.py +39 -0
- opencode_a2a-0.8.0/src/opencode_a2a/output_modes.py +386 -0
- opencode_a2a-0.8.0/src/opencode_a2a/parsing.py +86 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/application.py +44 -4
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/rest_tasks.py +48 -29
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/task_store.py +6 -13
- opencode_a2a-0.8.0/src/opencode_a2a/task_states.py +12 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a.egg-info/PKG-INFO +7 -3
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a.egg-info/SOURCES.txt +9 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a.egg-info/requires.txt +1 -1
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_streaming_output_contract_blocks.py +4 -2
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/scripts/test_script_health_contract.py +13 -0
- opencode_a2a-0.8.0/tests/server/test_output_negotiation.py +217 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_transport_contract.py +60 -0
- opencode_a2a-0.8.0/tests/test_metadata_access.py +49 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/uv.lock +123 -112
- opencode_a2a-0.7.1/src/opencode_a2a/output_modes.py +0 -29
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/.github/workflows/dependency-review.yml +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/.github/workflows/publish.yml +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/.github/workflows/validate.yml +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/.gitignore +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/.pre-commit-config.yaml +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/.secrets.baseline +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/AGENTS.md +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/CODE_OF_CONDUCT.md +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/LICENSE +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/SECURITY.md +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/SUPPORT.md +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/docs/conformance-triage.md +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/docs/conformance.md +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/scripts/check_coverage.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/scripts/conformance.sh +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/scripts/dependency_health.sh +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/scripts/health_common.sh +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/scripts/lint.sh +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/scripts/smoke_test_built_cli.sh +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/setup.cfg +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/auth.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/cli.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/agent_card.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/auth.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/client.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/config.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/error_mapping.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/errors.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/payload_text.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/client/request_context.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/config.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/contracts/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/contracts/extensions.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/coordinator.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/event_helpers.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/metrics.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/session_manager.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/stream_events.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/stream_state.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/tool_error_mapping.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/tool_orchestration.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/execution/upstream_error_translator.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/invocation.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/application.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/dispatch.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/error_responses.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/jsonrpc/handlers/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/opencode_upstream_client.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/parts/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/parts/mapping.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/parts/text.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/profile/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/profile/runtime.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/protocol_versions.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/py.typed +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/runtime_state.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/sandbox_policy.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/agent_card.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/client_manager.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/lifespan.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/middleware.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/migrations.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/openapi.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/request_parsing.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/server/state_store.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/trace_context.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a/upstream_taxonomy.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a.egg-info/dependency_links.txt +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a.egg-info/entry_points.txt +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/src/opencode_a2a.egg-info/top_level.txt +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/client/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/client/test_agent_card.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/client/test_client_config.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/client/test_client_facade.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/client/test_error_mapping.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/client/test_payload_text.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/client/test_polling.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/client/test_request_context.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/config/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/config/test_settings.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/conftest.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/contracts/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/contracts/test_extension_contract_consistency.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_agent_errors.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_agent_helpers.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_cancellation.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_directory_validation.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_metrics.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_multipart_input.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_opencode_agent_session_binding.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_session_lock_lifecycle.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_session_ownership.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_streaming_output_contract_core.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_streaming_output_contract_interrupts.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/execution/test_streaming_output_contract_logging.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_dispatch_registry.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_error_responses.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_jsonrpc_methods.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_jsonrpc_params.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_jsonrpc_unsupported_method.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_opencode_session_extension_commands.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_opencode_session_extension_interrupts.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_opencode_session_extension_lifecycle.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_opencode_session_extension_prompt_async.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_opencode_session_extension_queries.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/jsonrpc/test_opencode_workspace_control_extension.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/package/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/package/test_logging.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/package/test_typing_contract.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/package/test_version.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/parts/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/parts/test_parts_text.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/profile/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/profile/test_profile_runtime.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/scripts/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_a2a_client_manager.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_agent_card.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_app_behaviors.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_auth.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_call_context_builder.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_cancel_contract.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_cli.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_database_app_persistence.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_state_store.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/server/test_task_store_factory.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/support/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/support/helpers.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/support/session_extensions.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/support/streaming_output.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/test_trace_context.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/upstream/__init__.py +0 -0
- {opencode_a2a-0.7.1 → opencode_a2a-0.8.0}/tests/upstream/test_opencode_upstream_client_params.py +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
updates:
|
|
4
|
+
- package-ecosystem: "uv"
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: "weekly"
|
|
8
|
+
open-pull-requests-limit: 1
|
|
9
|
+
commit-message:
|
|
10
|
+
prefix: "deps"
|
|
11
|
+
labels:
|
|
12
|
+
- "dependencies"
|
|
13
|
+
groups:
|
|
14
|
+
uv-all-updates:
|
|
15
|
+
patterns:
|
|
16
|
+
- "*"
|
|
@@ -44,10 +44,11 @@ uv run opencode-a2a serve
|
|
|
44
44
|
Run the default validation baseline before opening a PR:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
|
|
48
|
-
uv run pytest
|
|
47
|
+
bash ./scripts/doctor.sh
|
|
49
48
|
```
|
|
50
49
|
|
|
50
|
+
`doctor.sh` is the primary repository validation entrypoint. It currently runs locked-environment sync, dependency compatibility checks, `pre-commit`, `mypy`, `pytest`, the repository coverage gate, package build, and a built-wheel smoke test.
|
|
51
|
+
|
|
51
52
|
If you change shell scripts, also run `bash -n` on each modified script, for example:
|
|
52
53
|
|
|
53
54
|
```bash
|
|
@@ -63,7 +64,7 @@ bash ./scripts/conformance.sh
|
|
|
63
64
|
|
|
64
65
|
Treat that output as investigation input. Do not fold it into `doctor.sh` or the default CI quality gate unless the repository explicitly decides to promote a specific experiment into a maintained policy.
|
|
65
66
|
|
|
66
|
-
If you change extension methods, extension metadata, or Agent Card/OpenAPI contract surfaces, also
|
|
67
|
+
If you change extension methods, extension metadata, or Agent Card/OpenAPI contract surfaces, also make sure the targeted contract checks stay green:
|
|
67
68
|
|
|
68
69
|
```bash
|
|
69
70
|
uv run pytest tests/contracts/test_extension_contract_consistency.py
|
|
@@ -107,7 +108,7 @@ Update docs together with code whenever you change:
|
|
|
107
108
|
- user-facing request or response shapes
|
|
108
109
|
- operational scripts
|
|
109
110
|
|
|
110
|
-
Keep
|
|
111
|
+
Keep usage details in [docs/guide.md](docs/guide.md) and compatibility-sensitive stability guidance in [docs/compatibility.md](docs/compatibility.md).
|
|
111
112
|
|
|
112
113
|
When changing extension contracts, update [`src/opencode_a2a/contracts/extensions.py`](src/opencode_a2a/contracts/extensions.py) first and keep these generated/documented surfaces aligned:
|
|
113
114
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencode-a2a
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: OpenCode A2A runtime
|
|
5
5
|
Author: liujuanjuan1984@Intelligent-Internet
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: a2a-sdk==0.3.
|
|
22
|
+
Requires-Dist: a2a-sdk==0.3.26
|
|
23
23
|
Requires-Dist: aiosqlite<1.0,>=0.20
|
|
24
24
|
Requires-Dist: fastapi<1.0,>=0.110
|
|
25
25
|
Requires-Dist: httpx<1.0,>=0.27
|
|
@@ -139,7 +139,7 @@ curl http://127.0.0.1:8000/.well-known/agent-card.json
|
|
|
139
139
|
- Declared supported protocol lines: `0.3`, `1.0`
|
|
140
140
|
- `0.3` is the stable interoperability baseline for the current runtime surface.
|
|
141
141
|
- `1.0` currently covers version negotiation plus protocol-aware JSON-RPC and REST error shaping, while transport payloads, enums, pagination, signatures, and interface-level protocol declarations still follow the shipped SDK baseline.
|
|
142
|
-
- The detailed compatibility matrix and machine-readable support boundary are documented in [`docs/guide.md`](docs/guide.md).
|
|
142
|
+
- The detailed compatibility matrix and machine-readable support boundary are documented in [`docs/guide.md`](docs/guide.md) and [`docs/compatibility.md`](docs/compatibility.md).
|
|
143
143
|
|
|
144
144
|
## Peering Node / Outbound Access
|
|
145
145
|
|
|
@@ -203,7 +203,11 @@ Read before deployment:
|
|
|
203
203
|
|
|
204
204
|
## Further Reading
|
|
205
205
|
|
|
206
|
+
- [docs/architecture.md](docs/architecture.md) Service responsibility boundaries and request flow.
|
|
207
|
+
- [docs/maintainer-architecture.md](docs/maintainer-architecture.md) Internal module boundaries and maintainer call chains.
|
|
208
|
+
- [docs/compatibility.md](docs/compatibility.md) Compatibility-sensitive surface and contract-honesty guidance.
|
|
206
209
|
- [docs/guide.md](docs/guide.md) Usage guide, transport details, streaming behavior, extensions, and examples.
|
|
210
|
+
- [docs/conformance.md](docs/conformance.md) External TCK experiment workflow and artifact handling.
|
|
207
211
|
- [SECURITY.md](SECURITY.md) Threat model, deployment caveats, and vulnerability disclosure guidance.
|
|
208
212
|
|
|
209
213
|
## Development
|
|
@@ -98,7 +98,7 @@ curl http://127.0.0.1:8000/.well-known/agent-card.json
|
|
|
98
98
|
- Declared supported protocol lines: `0.3`, `1.0`
|
|
99
99
|
- `0.3` is the stable interoperability baseline for the current runtime surface.
|
|
100
100
|
- `1.0` currently covers version negotiation plus protocol-aware JSON-RPC and REST error shaping, while transport payloads, enums, pagination, signatures, and interface-level protocol declarations still follow the shipped SDK baseline.
|
|
101
|
-
- The detailed compatibility matrix and machine-readable support boundary are documented in [`docs/guide.md`](docs/guide.md).
|
|
101
|
+
- The detailed compatibility matrix and machine-readable support boundary are documented in [`docs/guide.md`](docs/guide.md) and [`docs/compatibility.md`](docs/compatibility.md).
|
|
102
102
|
|
|
103
103
|
## Peering Node / Outbound Access
|
|
104
104
|
|
|
@@ -162,7 +162,11 @@ Read before deployment:
|
|
|
162
162
|
|
|
163
163
|
## Further Reading
|
|
164
164
|
|
|
165
|
+
- [docs/architecture.md](docs/architecture.md) Service responsibility boundaries and request flow.
|
|
166
|
+
- [docs/maintainer-architecture.md](docs/maintainer-architecture.md) Internal module boundaries and maintainer call chains.
|
|
167
|
+
- [docs/compatibility.md](docs/compatibility.md) Compatibility-sensitive surface and contract-honesty guidance.
|
|
165
168
|
- [docs/guide.md](docs/guide.md) Usage guide, transport details, streaming behavior, extensions, and examples.
|
|
169
|
+
- [docs/conformance.md](docs/conformance.md) External TCK experiment workflow and artifact handling.
|
|
166
170
|
- [SECURITY.md](SECURITY.md) Threat model, deployment caveats, and vulnerability disclosure guidance.
|
|
167
171
|
|
|
168
172
|
## Development
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Architecture Guide
|
|
2
|
+
|
|
3
|
+
This document explains what `opencode-a2a` is responsible for, what remains inside OpenCode, and how requests move through the adapter boundary.
|
|
4
|
+
|
|
5
|
+
## System Role
|
|
6
|
+
|
|
7
|
+
`opencode-a2a` is an adapter layer between A2A clients and an OpenCode runtime.
|
|
8
|
+
|
|
9
|
+
It is responsible for:
|
|
10
|
+
|
|
11
|
+
- exposing A2A-facing HTTP+JSON and JSON-RPC endpoints
|
|
12
|
+
- normalizing transport, streaming, session, and interrupt contracts
|
|
13
|
+
- applying authentication, logging, persistence, and deployment-side guardrails
|
|
14
|
+
- hosting an outbound A2A client for peer calls triggered by CLI usage or `a2a_call`
|
|
15
|
+
|
|
16
|
+
It is not responsible for:
|
|
17
|
+
|
|
18
|
+
- replacing OpenCode's own provider or model selection internals
|
|
19
|
+
- hard multi-tenant isolation inside one shared deployment by default
|
|
20
|
+
- acting as a general OpenCode process supervisor
|
|
21
|
+
|
|
22
|
+
## Adapter Layers
|
|
23
|
+
|
|
24
|
+
```mermaid
|
|
25
|
+
flowchart LR
|
|
26
|
+
Client["A2A Client / Hub / Gateway"] --> Gateway["opencode-a2a"]
|
|
27
|
+
Gateway --> Contracts["A2A contracts\ntransport/session/interrupt"]
|
|
28
|
+
Gateway --> Ops["Auth / logging / persistence / deployment boundary"]
|
|
29
|
+
Contracts --> OpenCode["OpenCode runtime"]
|
|
30
|
+
Ops --> OpenCode
|
|
31
|
+
Gateway --> Peer["Embedded outbound A2A client"]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This view emphasizes service responsibility boundaries rather than internal module structure. The root [README](../README.md) keeps the overview path for first-time readers, while [maintainer-architecture.md](./maintainer-architecture.md) covers module boundaries and request call chains for contributors.
|
|
35
|
+
|
|
36
|
+
## Request Flow
|
|
37
|
+
|
|
38
|
+
### Standard send/stream flow
|
|
39
|
+
|
|
40
|
+
1. A client calls the REST or JSON-RPC endpoint.
|
|
41
|
+
2. FastAPI middleware validates auth, request size, protocol version, and logging policy.
|
|
42
|
+
3. The adapter maps transport payloads into the OpenCode-facing execution path.
|
|
43
|
+
4. The execution layer calls the upstream OpenCode runtime and consumes its stream or unary response.
|
|
44
|
+
5. The service maps the result back into shared A2A-facing task, message, and stream event contracts.
|
|
45
|
+
|
|
46
|
+
### Streaming flow
|
|
47
|
+
|
|
48
|
+
For streaming requests, the adapter does more than simple passthrough:
|
|
49
|
+
|
|
50
|
+
- classifies stream blocks into shared types such as `text`, `reasoning`, and `tool_call`
|
|
51
|
+
- preserves stable event and message identity where possible
|
|
52
|
+
- emits shared interrupt lifecycle state
|
|
53
|
+
- avoids duplicate final snapshots when streaming already produced the final text
|
|
54
|
+
|
|
55
|
+
Detailed streaming contract: [Usage Guide](guide.md)
|
|
56
|
+
|
|
57
|
+
### Session flow
|
|
58
|
+
|
|
59
|
+
The service keeps a shared session continuation contract around `metadata.shared.session.id` and adapter-derived `contextId`, so clients can continue work without binding directly to raw OpenCode session IDs.
|
|
60
|
+
|
|
61
|
+
### Outbound peer flow
|
|
62
|
+
|
|
63
|
+
The same process can also act as an embedded A2A client:
|
|
64
|
+
|
|
65
|
+
- CLI calls route through the local client facade
|
|
66
|
+
- server-side `a2a_call` tool execution uses the same outbound client settings
|
|
67
|
+
- outbound auth, timeouts, and transport preferences are configured independently from inbound auth
|
|
68
|
+
|
|
69
|
+
## Boundary Model
|
|
70
|
+
|
|
71
|
+
The adapter improves the runtime boundary, but it is not a full trust-boundary replacement.
|
|
72
|
+
|
|
73
|
+
### What the adapter boundary helps with
|
|
74
|
+
|
|
75
|
+
- stable A2A-facing contract shape
|
|
76
|
+
- auth enforcement on A2A entrypoints
|
|
77
|
+
- payload logging controls
|
|
78
|
+
- lightweight persistence for SDK task rows plus adapter-managed runtime state
|
|
79
|
+
- compatibility metadata for clients and operators
|
|
80
|
+
|
|
81
|
+
### What still belongs to the OpenCode runtime boundary
|
|
82
|
+
|
|
83
|
+
- provider credential consumption
|
|
84
|
+
- workspace side effects
|
|
85
|
+
- upstream model/provider behavior
|
|
86
|
+
- host-level process supervision and isolation
|
|
87
|
+
|
|
88
|
+
That is why deployments should still be treated as trusted or controlled unless stronger isolation is added outside this repository.
|
|
89
|
+
|
|
90
|
+
## Documentation Split
|
|
91
|
+
|
|
92
|
+
Use the docs by responsibility:
|
|
93
|
+
|
|
94
|
+
- [README](../README.md): project overview, install/start path, and entry navigation
|
|
95
|
+
- [Compatibility Guide](compatibility.md): compatibility-sensitive surface and stability expectations
|
|
96
|
+
- [Usage Guide](guide.md): runtime configuration, transport contracts, extensions, and examples
|
|
97
|
+
- [Maintainer Architecture Guide](maintainer-architecture.md): internal module boundaries, request call chains, and persistence touchpoints
|
|
98
|
+
- [Extension Specifications](extension-specifications.md): stable extension URI/spec index and disclosure policy
|
|
99
|
+
- [Conformance Notes](conformance.md): external TCK experiment workflow
|
|
100
|
+
- [Contributing Guide](../CONTRIBUTING.md): contributor workflow and validation
|
|
101
|
+
- [Security Policy](../SECURITY.md): threat model and disclosure guidance
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Compatibility Guide
|
|
2
|
+
|
|
3
|
+
This document explains the compatibility promises `opencode-a2a` currently tries to uphold for A2A consumers, operators, and maintainers.
|
|
4
|
+
|
|
5
|
+
## Runtime Support
|
|
6
|
+
|
|
7
|
+
- Python versions: 3.11, 3.12, 3.13
|
|
8
|
+
- A2A SDK line: `0.3.x`
|
|
9
|
+
- Default advertised protocol line: `0.3`
|
|
10
|
+
- Declared supported protocol lines: `0.3`, `1.0`
|
|
11
|
+
|
|
12
|
+
The repository pins the SDK version in `pyproject.toml`. Upgrade the SDK deliberately rather than relying on floating dependency resolution.
|
|
13
|
+
|
|
14
|
+
## Contract Honesty
|
|
15
|
+
|
|
16
|
+
Machine-readable discovery surfaces must reflect actual runtime behavior:
|
|
17
|
+
|
|
18
|
+
- public Agent Card
|
|
19
|
+
- authenticated extended card
|
|
20
|
+
- OpenAPI metadata
|
|
21
|
+
- JSON-RPC wire contract
|
|
22
|
+
- compatibility profile
|
|
23
|
+
|
|
24
|
+
If runtime support is not actually implemented, do not publish it as a supported machine-readable capability.
|
|
25
|
+
|
|
26
|
+
Consumer guidance:
|
|
27
|
+
|
|
28
|
+
- Treat the core A2A send / stream / task methods as the portable baseline.
|
|
29
|
+
- Treat `urn:a2a:*` entries in this repository as shared repo-family conventions, not as a claim that they are part of the A2A core baseline.
|
|
30
|
+
- Treat `opencode.*` methods and `metadata.opencode.*` fields as provider-private OpenCode control and discovery surfaces layered on top of the portable A2A baseline.
|
|
31
|
+
- Treat [extension-specifications.md](./extension-specifications.md) as the stable URI/spec index, not as the main usage guide.
|
|
32
|
+
|
|
33
|
+
## Normative Sources
|
|
34
|
+
|
|
35
|
+
When docs or reference material disagree, treat these as normative in this order:
|
|
36
|
+
|
|
37
|
+
- runtime behavior validated by tests
|
|
38
|
+
- machine-readable discovery output such as Agent Card, authenticated extended card, and OpenAPI metadata
|
|
39
|
+
- repository-owned docs in `README.md`, `docs/`, and `CONTRIBUTING.md`
|
|
40
|
+
|
|
41
|
+
External TCK runs and local conformance experiments are investigation inputs. They do not override the repository's declared contract by themselves.
|
|
42
|
+
|
|
43
|
+
## Compatibility-Sensitive Surface
|
|
44
|
+
|
|
45
|
+
This repository still ships as an alpha project. Within that alpha line, these declared surfaces should not drift silently:
|
|
46
|
+
|
|
47
|
+
- core A2A send / stream / task methods
|
|
48
|
+
- version negotiation and protocol-aware error shaping
|
|
49
|
+
- shared session-binding metadata
|
|
50
|
+
- shared model-selection metadata
|
|
51
|
+
- shared streaming metadata
|
|
52
|
+
- declared custom JSON-RPC extension methods
|
|
53
|
+
- authenticated extended card and OpenAPI wire-contract metadata
|
|
54
|
+
|
|
55
|
+
Changes to those surfaces should be treated as compatibility-sensitive and should include corresponding test updates.
|
|
56
|
+
|
|
57
|
+
Service-level behavior layered on top of those core methods should also be declared explicitly when interoperability depends on it. Current examples:
|
|
58
|
+
|
|
59
|
+
- `tasks/resubscribe` replay-once behavior for terminal updates
|
|
60
|
+
- first-terminal-state-wins task persistence policy
|
|
61
|
+
- task-scoped `acceptedOutputModes` negotiation persistence across send / stream / get / resubscribe
|
|
62
|
+
- request-body rejection behavior for oversized transport payloads
|
|
63
|
+
|
|
64
|
+
## Deployment Profile
|
|
65
|
+
|
|
66
|
+
The current service profile is intentionally:
|
|
67
|
+
|
|
68
|
+
- single-tenant
|
|
69
|
+
- shared-workspace
|
|
70
|
+
- adapter boundary around one OpenCode deployment
|
|
71
|
+
|
|
72
|
+
One deployed instance should be treated as a single-tenant trust boundary, not as a secure multi-tenant runtime boundary.
|
|
73
|
+
|
|
74
|
+
Execution-environment boundary fields published through the runtime profile are declarative deployment metadata. They are not promises that every host-side approval, sandbox escalation, or filesystem change will be reflected live per request.
|
|
75
|
+
|
|
76
|
+
## Persistence Compatibility
|
|
77
|
+
|
|
78
|
+
Task durability is deployment-dependent:
|
|
79
|
+
|
|
80
|
+
- `A2A_TASK_STORE_BACKEND=database` preserves SDK task rows plus adapter-managed session and interrupt state across restarts
|
|
81
|
+
- `A2A_TASK_STORE_BACKEND=memory` keeps the service in an ephemeral development profile
|
|
82
|
+
|
|
83
|
+
Task-store behavior that should remain stable for clients:
|
|
84
|
+
|
|
85
|
+
- once a task reaches a terminal state, later conflicting writes are dropped on a first-terminal-state-wins basis
|
|
86
|
+
- task-store I/O failures are surfaced as stable service errors instead of leaking backend-specific exceptions
|
|
87
|
+
- accepted output-mode negotiation for a task is persisted with the task so later reads keep the same filtered output contract
|
|
88
|
+
- adapter-managed migrations only own adapter state tables; SDK-managed task schema remains SDK-owned
|
|
89
|
+
|
|
90
|
+
The default SQLite-first profile is intended for local or controlled single-instance deployments. Wider SQLAlchemy dialect compatibility should be treated as implementation latitude rather than a strong public promise unless explicitly documented later.
|
|
91
|
+
|
|
92
|
+
## Extension Stability
|
|
93
|
+
|
|
94
|
+
- Shared metadata and extension contracts should stay synchronized across Agent Card, OpenAPI, and runtime behavior.
|
|
95
|
+
- Public Agent Card should stay intentionally minimal. Detailed extension params belong in the authenticated extended card and OpenAPI, not back in the anonymous discovery surface.
|
|
96
|
+
- Deployment-conditional methods must be declared as conditional rather than silently disappearing.
|
|
97
|
+
- `opencode.sessions.prompt_async` input-part passthrough is compatibility-sensitive. Changes to supported part types, passthrough field semantics, or rejection behavior should be treated as wire-level changes.
|
|
98
|
+
- `opencode.sessions.shell` is compatibility-sensitive as a deployment-conditional shell snapshot surface. It should not silently widen into a general interactive shell API.
|
|
99
|
+
- `opencode.workspaces.*` and `opencode.worktrees.*` are boundary-sensitive and should remain explicitly provider-private, operator-scoped, and deployment-conditional where applicable.
|
|
100
|
+
- Interrupt callback and recovery methods are compatibility-sensitive because clients may depend on request ID lifecycle, expiry semantics, and identity scoping.
|
|
101
|
+
- Agent Card media modes and `acceptedOutputModes` handling are compatibility-sensitive. Changes to declared chat modes, to task-scoped negotiation persistence, or to `DataPart` -> `TextPart` downgrade behavior should be treated as wire-level changes.
|
|
102
|
+
- Agent Card and OpenAPI publication of `protocol_compatibility`, `service_behaviors`, and runtime feature toggles is compatibility-sensitive discoverability surface.
|
|
103
|
+
|
|
104
|
+
## Extension Boundary Governance
|
|
105
|
+
|
|
106
|
+
When evaluating or evolving `opencode.*` methods, this repository uses the following rules:
|
|
107
|
+
|
|
108
|
+
- The adapter may document, validate, route, and normalize stable upstream-facing behavior, but it should not grow into a general replacement for upstream private runtime internals or host-level control planes.
|
|
109
|
+
- New `opencode.*` methods default to provider-private extension status.
|
|
110
|
+
- Read-only discovery, compatibility-preserving projections, and low-risk control methods are preferred over stronger mutating or destructive provider controls.
|
|
111
|
+
- A2A core object mappings should be used only for stable, low-ambiguity read projections.
|
|
112
|
+
- Subtask/subagent fan-out, task-tool internals, and similar upstream execution mechanisms should stay framed as upstream runtime behavior even when passthrough compatibility exists.
|
|
113
|
+
|
|
114
|
+
Each new extension proposal should answer:
|
|
115
|
+
|
|
116
|
+
- what client value exists beyond the current chat/session flow?
|
|
117
|
+
- is the upstream behavior stable enough to carry as a maintained contract?
|
|
118
|
+
- should the surface be provider-private, deployment-conditional, or excluded?
|
|
119
|
+
- are authorization and destructive-side-effect boundaries enforceable?
|
|
120
|
+
- can the result shape avoid overfitting OpenCode internals into fake A2A core semantics?
|
|
121
|
+
|
|
122
|
+
## Extension Taxonomy
|
|
123
|
+
|
|
124
|
+
This repository distinguishes between three layers:
|
|
125
|
+
|
|
126
|
+
- core A2A surface
|
|
127
|
+
- standard send / stream / task methods
|
|
128
|
+
- shared extensions
|
|
129
|
+
- repo-family conventions such as session binding, model selection, stream hints, and interrupt callbacks
|
|
130
|
+
- OpenCode-specific extensions
|
|
131
|
+
- `opencode.*` JSON-RPC methods plus `metadata.opencode.*`
|
|
132
|
+
|
|
133
|
+
Important note:
|
|
134
|
+
|
|
135
|
+
- `urn:a2a:*` extension URIs used here should be read as shared conventions in this repository family.
|
|
136
|
+
- They are not a claim that those extensions are part of the A2A core baseline.
|
|
137
|
+
- `opencode.*` methods are intentionally product-specific. They improve OpenCode-aware workflows but should not be assumed to transfer unchanged to unrelated A2A agents.
|
|
138
|
+
|
|
139
|
+
## Non-Goals
|
|
140
|
+
|
|
141
|
+
This repository does not currently promise:
|
|
142
|
+
|
|
143
|
+
- hard multi-tenant isolation inside one instance
|
|
144
|
+
- generic provider-auth orchestration on behalf of OpenCode
|
|
145
|
+
- a claim that all declared `1.0` protocol surfaces are fully implemented beyond the documented compatibility matrix
|
|
146
|
+
|
|
147
|
+
Those areas may evolve later, but they should not be implied by current machine-readable discovery output.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Extension Specifications
|
|
2
2
|
|
|
3
|
-
This document is the stable specification surface referenced by the extension URIs published in the Agent Card. It is intentionally a compact URI/spec index, not the main consumer guide. For runtime behavior, request/response examples, and client integration guidance, see [`guide.md`](./guide.md).
|
|
3
|
+
This document is the stable specification surface referenced by the extension URIs published in the Agent Card. It is intentionally a compact URI/spec index, not the main consumer guide. For runtime behavior, request/response examples, and client integration guidance, see [`guide.md`](./guide.md). For compatibility-sensitive surface and contract-honesty guidance, see [`compatibility.md`](./compatibility.md).
|
|
4
4
|
|
|
5
5
|
## SDK Compatibility Note
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Usage Guide
|
|
2
2
|
|
|
3
|
-
This guide covers configuration, authentication, API behavior, streaming re-subscription, and A2A client examples. It is the canonical document for implementation-level protocol contracts and JSON-RPC extension details; README stays at overview level.
|
|
3
|
+
This guide covers configuration, authentication, API behavior, streaming re-subscription, and A2A client examples. It is the canonical document for implementation-level protocol contracts and JSON-RPC extension details; [README](../README.md) stays at overview level, [architecture.md](./architecture.md) explains the service boundary, [maintainer-architecture.md](./maintainer-architecture.md) covers the internal module view for contributors, and [compatibility.md](./compatibility.md) defines the compatibility-sensitive surface.
|
|
4
4
|
|
|
5
5
|
## Transport Contracts
|
|
6
6
|
|
|
@@ -199,6 +199,8 @@ If one deployment works while another fails against the same upstream provider,
|
|
|
199
199
|
- Main chat requests that explicitly send `configuration.acceptedOutputModes` must stay compatible with the declared chat output modes.
|
|
200
200
|
- Current main chat requests must continue accepting `text/plain`; requests that only accept `application/json` or other incompatible modes are rejected before execution starts.
|
|
201
201
|
- `application/json` is additive structured-output support for incremental `tool_call` payloads. It does not guarantee that ordinary assistant prose can always be losslessly represented as JSON, so consumers that expect normal chat text should keep accepting `text/plain`.
|
|
202
|
+
- When a client accepts `text/plain` but not `application/json`, structured `tool_call` payloads are downgraded to compact JSON text instead of being silently dropped.
|
|
203
|
+
- Accepted output-mode negotiation is persisted as task-scoped metadata so later `tasks/get` and `tasks/resubscribe` reads keep the same filtered response contract as the original `message/send` or `message:stream` request.
|
|
202
204
|
- Main chat input supports structured A2A `parts` passthrough:
|
|
203
205
|
- `TextPart` is forwarded as an OpenCode text part.
|
|
204
206
|
- `FilePart(FileWithBytes)` is forwarded as a `file` part with a `data:` URL.
|
|
@@ -220,6 +222,8 @@ If one deployment works while another fails against the same upstream provider,
|
|
|
220
222
|
- `message.part.delta` and `message.part.updated` are merged per `part_id`; out-of-order deltas are buffered and replayed when the corresponding `part.updated` arrives.
|
|
221
223
|
- Structured `tool` parts are emitted as `tool_call` blocks backed by `DataPart(data={...})`, while `text` and `reasoning` continue to use `TextPart`.
|
|
222
224
|
- `tool_call` block payloads are normalized structured objects that may expose fields such as `call_id`, `tool`, `status`, `title`, `subtitle`, `input`, `output`, and `error`.
|
|
225
|
+
- If `application/json` is not accepted but `text/plain` is still accepted, those `tool_call` blocks are downgraded to stable compact JSON text so text-only clients retain the same observable state transitions.
|
|
226
|
+
- When a request restricts `acceptedOutputModes`, the stream applies the same output filtering before persistence so later task snapshots do not re-expose filtered structured blocks.
|
|
223
227
|
- Final status event metadata may include normalized token usage at `metadata.shared.usage` with fields such as `input_tokens`, `output_tokens`, `total_tokens`, optional `reasoning_tokens`, optional `cache_tokens.read_tokens` / `cache_tokens.write_tokens`, and optional `cost`.
|
|
224
228
|
- Usage is extracted from documented info payloads and supported usage parts such as `step-finish`; non-usage parts with similar fields are ignored.
|
|
225
229
|
- Interrupt events (`permission.asked` / `question.asked`) are mapped to `TaskStatusUpdateEvent(final=false, state=input-required)` with details at `metadata.shared.interrupt`, including `request_id`, interrupt `type`, `phase=asked`, and a normalized minimal callback payload.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Maintainer Architecture Guide
|
|
2
|
+
|
|
3
|
+
This document describes the internal structure, module boundaries, and main request call chains of `opencode-a2a`. It is intended for maintainers and contributors. Use [architecture.md](./architecture.md) for the higher-level service boundary view and [guide.md](./guide.md) for deployment-facing runtime configuration.
|
|
4
|
+
|
|
5
|
+
## Core Component Map
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart TD
|
|
9
|
+
subgraph Inbound["Server Layer (src/opencode_a2a/server/)"]
|
|
10
|
+
App["application.py (FastAPI assembly)"]
|
|
11
|
+
Middleware["middleware.py"]
|
|
12
|
+
AgentCard["agent_card.py / openapi.py"]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
subgraph Execution["Execution Layer (src/opencode_a2a/execution/)"]
|
|
16
|
+
Executor["executor.py"]
|
|
17
|
+
Coordinator["coordinator.py"]
|
|
18
|
+
StreamRuntime["stream_runtime.py"]
|
|
19
|
+
ToolOrch["tool_orchestration.py"]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
subgraph Upstream["OpenCode Upstream Layer"]
|
|
23
|
+
UpstreamClient["opencode_upstream_client.py"]
|
|
24
|
+
Invocation["invocation.py"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
subgraph Extensions["Extension / Contract Layer"]
|
|
28
|
+
Jsonrpc["jsonrpc/"]
|
|
29
|
+
Contracts["contracts/extensions.py"]
|
|
30
|
+
Profile["profile/runtime.py"]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
subgraph Persistence["Persistence Layer"]
|
|
34
|
+
TaskStore["server/task_store.py"]
|
|
35
|
+
StateStore["server/state_store.py"]
|
|
36
|
+
Migrations["server/migrations.py"]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Inbound --> Execution
|
|
40
|
+
Inbound --> Extensions
|
|
41
|
+
Execution --> Upstream
|
|
42
|
+
Inbound --> Persistence
|
|
43
|
+
Execution --> Persistence
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Request Call Chain
|
|
47
|
+
|
|
48
|
+
### Inbound Message Send / Stream
|
|
49
|
+
|
|
50
|
+
1. `server/application.py` assembles the FastAPI app, SDK adapters, and middleware stack.
|
|
51
|
+
2. `server/middleware.py` handles auth, request sizing, protocol negotiation, logging, and response headers.
|
|
52
|
+
3. The SDK-backed handler delegates execution to `execution/executor.py`.
|
|
53
|
+
4. The execution layer coordinates session continuity, stream handling, tool calls, and error translation through:
|
|
54
|
+
- `execution/coordinator.py`
|
|
55
|
+
- `execution/stream_runtime.py`
|
|
56
|
+
- `execution/tool_orchestration.py`
|
|
57
|
+
5. `opencode_upstream_client.py` sends requests to the upstream OpenCode runtime.
|
|
58
|
+
6. The adapter maps upstream responses back into A2A tasks, messages, artifacts, and stream events.
|
|
59
|
+
|
|
60
|
+
### JSON-RPC Extension Path
|
|
61
|
+
|
|
62
|
+
1. `jsonrpc/application.py` owns the adapter-specific JSON-RPC application boundary.
|
|
63
|
+
2. `jsonrpc/dispatch.py` and handler modules under `jsonrpc/handlers/` route provider-private methods.
|
|
64
|
+
3. `contracts/extensions.py` remains the SSOT for extension metadata exposed through Agent Card and OpenAPI.
|
|
65
|
+
4. Tests under `tests/contracts/` and `tests/jsonrpc/` guard contract drift.
|
|
66
|
+
|
|
67
|
+
### Outbound Peer Call Path
|
|
68
|
+
|
|
69
|
+
1. CLI or server-side tool execution asks `server/client_manager.py` for an outbound client.
|
|
70
|
+
2. `client/` builds and configures the embedded A2A client facade.
|
|
71
|
+
3. Outbound peer responses are normalized before being reintroduced into the local runtime surface.
|
|
72
|
+
|
|
73
|
+
## Module Responsibilities
|
|
74
|
+
|
|
75
|
+
### Server Layer
|
|
76
|
+
|
|
77
|
+
- `server/application.py`: app assembly, route wiring, request handler customization, and top-level lifecycle integration
|
|
78
|
+
- `server/middleware.py`: auth, protocol negotiation, payload/body guards, logging, and response decoration
|
|
79
|
+
- `server/agent_card.py` / `server/openapi.py`: machine-readable contract publication
|
|
80
|
+
- `server/rest_tasks.py`: SDK-owned REST task routes plus adapter-specific list behavior
|
|
81
|
+
|
|
82
|
+
### Execution Layer
|
|
83
|
+
|
|
84
|
+
- `execution/executor.py`: main orchestration entrypoint
|
|
85
|
+
- `execution/coordinator.py`: OpenCode session coordination and request shaping
|
|
86
|
+
- `execution/stream_runtime.py` / `execution/stream_events.py`: stream normalization and event conversion
|
|
87
|
+
- `execution/tool_orchestration.py`: embedded peer-call tool handling
|
|
88
|
+
- `execution/upstream_error_translator.py` / `execution/tool_error_mapping.py`: upstream-facing error normalization
|
|
89
|
+
|
|
90
|
+
### Extension and Contract Layer
|
|
91
|
+
|
|
92
|
+
- `contracts/extensions.py`: SSOT for extension metadata, compatibility profile, and wire-contract payloads
|
|
93
|
+
- `jsonrpc/`: provider-private JSON-RPC extension surface
|
|
94
|
+
- `profile/runtime.py`: runtime profile that feeds Agent Card, OpenAPI, and compatibility metadata
|
|
95
|
+
- `protocol_versions.py`: protocol normalization and negotiation helpers
|
|
96
|
+
|
|
97
|
+
### Persistence Layer
|
|
98
|
+
|
|
99
|
+
- `server/task_store.py`: SDK task store construction plus adapter policy wrappers
|
|
100
|
+
- `server/state_store.py`: session binding and interrupt repositories
|
|
101
|
+
- `server/migrations.py`: adapter-managed state schema migrations
|
|
102
|
+
|
|
103
|
+
### Client Layer
|
|
104
|
+
|
|
105
|
+
- `client/`: outbound peer card discovery, request context, auth handling, polling fallback, and error mapping
|
|
106
|
+
|
|
107
|
+
## Key Persistence Points
|
|
108
|
+
|
|
109
|
+
- SDK task rows stored through the configured task store backend
|
|
110
|
+
- adapter-managed session binding / ownership state
|
|
111
|
+
- interrupt request bindings and tombstones
|
|
112
|
+
- pending preferred-session claims
|
|
113
|
+
|
|
114
|
+
The custom migration runner owns only adapter-managed state tables; SDK-managed task schema still follows the SDK path.
|
|
115
|
+
|
|
116
|
+
## Configuration Layering
|
|
117
|
+
|
|
118
|
+
Configuration is handled in [config.py](../src/opencode_a2a/config.py) with `pydantic-settings`.
|
|
119
|
+
|
|
120
|
+
- `A2A_*`: inbound runtime, outbound peer client, protocol, persistence, and deployment metadata
|
|
121
|
+
- `OPENCODE_*`: upstream OpenCode connection and request behavior
|
|
122
|
+
|
|
123
|
+
## Practical Reading Order
|
|
124
|
+
|
|
125
|
+
For maintainers new to the codebase, this order usually gives the fastest payoff:
|
|
126
|
+
|
|
127
|
+
1. `README.md`
|
|
128
|
+
2. `docs/architecture.md`
|
|
129
|
+
3. `src/opencode_a2a/server/application.py`
|
|
130
|
+
4. `src/opencode_a2a/execution/executor.py`
|
|
131
|
+
5. `src/opencode_a2a/contracts/extensions.py`
|
|
132
|
+
6. `docs/guide.md`
|
|
@@ -11,7 +11,7 @@ Executable scripts live in this directory. This file is the entry index for the
|
|
|
11
11
|
|
|
12
12
|
## Other Scripts
|
|
13
13
|
|
|
14
|
-
- [`doctor.sh`](./doctor.sh): primary local development regression entrypoint (uv sync + lint + tests + coverage)
|
|
14
|
+
- [`doctor.sh`](./doctor.sh): primary local development regression entrypoint (uv sync + dependency compatibility + lint + mypy + tests + coverage + built-wheel smoke test)
|
|
15
15
|
- [`conformance.sh`](./conformance.sh): local/manual external A2A conformance experiment entrypoint; caches the official TCK, can launch a dummy-backed local SUT, and preserves raw artifacts under `run/conformance/`
|
|
16
16
|
- [`dependency_health.sh`](./dependency_health.sh): development dependency review entrypoint (`sync`/`pip check` + outdated + dev audit), while blocking CI/publish audits focus on runtime dependencies
|
|
17
17
|
- [`check_coverage.py`](./check_coverage.py): enforces the overall coverage floor and per-file minimums for critical modules
|
|
@@ -21,4 +21,6 @@ Executable scripts live in this directory. This file is the entry index for the
|
|
|
21
21
|
## Notes
|
|
22
22
|
|
|
23
23
|
- `doctor.sh` and `dependency_health.sh` intentionally remain separate entrypoints and share common prerequisites through [`health_common.sh`](./health_common.sh).
|
|
24
|
+
- `doctor.sh` covers the default local validation baseline, while `dependency_health.sh` remains focused on standalone dependency review and audit flow.
|
|
25
|
+
- [`.github/dependabot.yml`](../.github/dependabot.yml) prefers a single weekly grouped Dependabot PR for `uv`, while `dependency_health.sh` remains the explicit review/audit entrypoint.
|
|
24
26
|
- External conformance experiments remain intentionally separate from the default regression path. See [`../docs/conformance.md`](../docs/conformance.md).
|
|
@@ -9,8 +9,18 @@ run_shared_repo_health_prerequisites "doctor"
|
|
|
9
9
|
echo "[doctor] run lint"
|
|
10
10
|
uv run pre-commit run --all-files
|
|
11
11
|
|
|
12
|
+
echo "[doctor] run type checks"
|
|
13
|
+
uv run mypy src/opencode_a2a
|
|
14
|
+
|
|
12
15
|
echo "[doctor] run tests"
|
|
13
16
|
uv run pytest
|
|
14
17
|
|
|
15
18
|
echo "[doctor] enforce coverage policy"
|
|
16
19
|
uv run python ./scripts/check_coverage.py
|
|
20
|
+
|
|
21
|
+
echo "[doctor] build release artifacts"
|
|
22
|
+
rm -f dist/opencode_a2a-*.whl dist/opencode_a2a-*.tar.gz
|
|
23
|
+
uv build --no-sources
|
|
24
|
+
|
|
25
|
+
echo "[doctor] smoke test built wheel"
|
|
26
|
+
bash ./scripts/smoke_test_built_cli.sh dist/opencode_a2a-*.whl
|
|
@@ -6,14 +6,8 @@ from dataclasses import dataclass
|
|
|
6
6
|
|
|
7
7
|
from a2a.types import TaskState
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
TaskState.completed,
|
|
12
|
-
TaskState.canceled,
|
|
13
|
-
TaskState.failed,
|
|
14
|
-
TaskState.rejected,
|
|
15
|
-
}
|
|
16
|
-
)
|
|
9
|
+
from ..task_states import TERMINAL_TASK_STATES
|
|
10
|
+
|
|
17
11
|
_AUTO_POLLING_TASK_STATES = frozenset(
|
|
18
12
|
{
|
|
19
13
|
TaskState.submitted,
|
|
@@ -37,7 +31,7 @@ class PollingFallbackPolicy:
|
|
|
37
31
|
return state in _AUTO_POLLING_TASK_STATES
|
|
38
32
|
|
|
39
33
|
def is_terminal_state(self, state: TaskState) -> bool:
|
|
40
|
-
return state in
|
|
34
|
+
return state in TERMINAL_TASK_STATES
|
|
41
35
|
|
|
42
36
|
def next_interval_seconds(self, current_interval_seconds: float) -> float:
|
|
43
37
|
return min(
|
|
@@ -73,7 +73,7 @@ from .stream_state import (
|
|
|
73
73
|
_StreamOutputState,
|
|
74
74
|
_TTLCache,
|
|
75
75
|
)
|
|
76
|
-
from .tool_orchestration import
|
|
76
|
+
from .tool_orchestration import maybe_handle_tools, merge_streamed_tool_output
|
|
77
77
|
from .upstream_error_translator import (
|
|
78
78
|
_await_stream_terminal_signal,
|
|
79
79
|
_extract_upstream_error_detail,
|
|
@@ -186,12 +186,6 @@ class OpencodeAgentExecutor(AgentExecutor):
|
|
|
186
186
|
a2a_client_manager=self._a2a_client_manager,
|
|
187
187
|
)
|
|
188
188
|
|
|
189
|
-
async def _handle_a2a_call_tool(self, part: dict[str, Any]) -> dict[str, Any]:
|
|
190
|
-
return await handle_a2a_call_tool(
|
|
191
|
-
part,
|
|
192
|
-
a2a_client_manager=self._a2a_client_manager,
|
|
193
|
-
)
|
|
194
|
-
|
|
195
189
|
@staticmethod
|
|
196
190
|
def _merge_streamed_tool_output(current: str, incoming: str) -> str:
|
|
197
191
|
return merge_streamed_tool_output(current, incoming)
|