opencode-a2a 1.0.0__tar.gz → 1.1.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-1.0.0/src/opencode_a2a.egg-info → opencode_a2a-1.1.0}/PKG-INFO +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/compatibility.md +2 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/extension-specifications.md +31 -23
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/guide.md +18 -14
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/README.md +2 -1
- opencode_a2a-1.1.0/scripts/doctor.sh +71 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/config.py +2 -2
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/error_mapping.py +1 -4
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/payload_text.py +31 -26
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/catalog.py +0 -7
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/identifiers.py +10 -56
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/public_params.py +53 -37
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/coordinator.py +3 -3
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/stream_runtime.py +11 -21
- opencode_a2a-1.1.0/src/opencode_a2a/interrupt_request_tracker.py +75 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/interrupt_callbacks.py +18 -28
- opencode_a2a-1.1.0/src/opencode_a2a/jsonrpc/params.py +131 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/database.py +18 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/openapi.py +39 -23
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/task_store.py +2 -2
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/task_store_sdk_compat.py +4 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0/src/opencode_a2a.egg-info}/PKG-INFO +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/SOURCES.txt +6 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_client_config.py +12 -0
- opencode_a2a-1.1.0/tests/client/test_error_mapping.py +254 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_payload_text.py +24 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/config/test_settings.py +30 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/contracts/test_extension_contract_consistency.py +36 -3
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_directory_validation.py +2 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_metrics.py +6 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_multipart_input.py +6 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_opencode_agent_session_binding.py +5 -2
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_session_ownership.py +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_streaming_output_contract_core.py +4 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_streaming_output_contract_interrupts.py +2 -2
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_streaming_output_contract_logging.py +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_application_dispatch.py +2 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_dispatch_registry.py +15 -5
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_jsonrpc_params.py +13 -28
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_jsonrpc_unsupported_method.py +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_commands.py +5 -4
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_interrupts.py +84 -4
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_lifecycle.py +4 -4
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_prompt_async.py +4 -4
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_queries.py +9 -7
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_workspace_control_extension.py +5 -4
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/profile/test_profile_runtime.py +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/scripts/test_script_health_contract.py +10 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_agent_card.py +9 -14
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_app_behaviors.py +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_auth.py +1 -1
- opencode_a2a-1.1.0/tests/server/test_cli.py +312 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_database_app_persistence.py +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_state_store.py +1 -1
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_task_store_factory.py +39 -2
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_transport_contract.py +2 -2
- opencode_a2a-1.1.0/tests/support/helpers.py +231 -0
- opencode_a2a-1.1.0/tests/support/interrupt_clients.py +141 -0
- opencode_a2a-1.1.0/tests/support/session_query_client.py +449 -0
- opencode_a2a-1.1.0/tests/support/settings.py +82 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/streaming_output.py +5 -34
- opencode_a2a-1.1.0/tests/support/workspace_control_client.py +65 -0
- opencode_a2a-1.1.0/tests/test_parsing.py +126 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/upstream/test_opencode_upstream_client_params.py +1 -1
- opencode_a2a-1.0.0/scripts/doctor.sh +0 -26
- opencode_a2a-1.0.0/src/opencode_a2a/jsonrpc/params.py +0 -199
- opencode_a2a-1.0.0/tests/client/test_error_mapping.py +0 -85
- opencode_a2a-1.0.0/tests/server/test_cli.py +0 -134
- opencode_a2a-1.0.0/tests/support/helpers.py +0 -945
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.github/dependabot.yml +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.github/workflows/dependency-review.yml +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.github/workflows/publish.yml +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.github/workflows/validate.yml +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.gitignore +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.pre-commit-config.yaml +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.secrets.baseline +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/AGENTS.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/CODE_OF_CONDUCT.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/CONTRIBUTING.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/LICENSE +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/MANIFEST.in +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/README.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/SECURITY.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/SUPPORT.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/architecture.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/conformance-triage.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/conformance.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/maintainer-architecture.md +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/pyproject.toml +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/check_coverage.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/conformance.sh +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/dependency_health.sh +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/find_thin_wrappers.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/health_common.sh +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/lint.sh +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/smoke_test_built_cli.sh +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/setup.cfg +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/a2a_protocol.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/a2a_utils.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/auth.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/cli.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/agent_card.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/auth.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/client.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/errors.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/polling.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/request_context.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/config.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/capabilities.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/compatibility.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/contract_docs.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/private_params.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/event_helpers.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/executor.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/metrics.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/session_manager.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/stream_events.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/stream_state.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/tool_error_mapping.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/tool_orchestration.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/upstream_error_translator.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/extension_negotiation.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/application.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/dispatch.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/error_responses.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/common.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/interrupt_queries.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/provider_discovery.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/session_control.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/session_lifecycle.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/session_queries.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/workspace_control.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/methods.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/models.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/metadata_access.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/opencode_upstream_client.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/output_modes.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/parsing.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/parts/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/parts/mapping.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/parts/text.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/profile/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/profile/runtime.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/protocol_versions.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/py.typed +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/runtime_state.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/sandbox_policy.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/agent_card.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/application.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/client_manager.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/context_helpers.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/lifespan.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/middleware.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/migrations.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/request_parsing.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/rest_tasks.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/state_store.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/task_states.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/trace_context.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/upstream_taxonomy.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/dependency_links.txt +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/entry_points.txt +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/requires.txt +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/top_level.txt +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_agent_card.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_client_facade.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_polling.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_request_context.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/config/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/conftest.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/contracts/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_agent_errors.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_agent_helpers.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_cancellation.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_session_lock_lifecycle.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_streaming_output_contract_blocks.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_error_responses.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_jsonrpc_methods.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/package/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/package/test_logging.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/package/test_typing_contract.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/package/test_version.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/parts/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/parts/test_parts_text.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/profile/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/scripts/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_a2a_client_manager.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_call_context_builder.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_cancel_contract.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_output_negotiation.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/async_iterators.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/fake_client_errors.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/jsonrpc_error_assertions.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/session_extensions.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/test_metadata_access.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/test_trace_context.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/upstream/__init__.py +0 -0
- {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/uv.lock +0 -0
|
@@ -8,7 +8,7 @@ This document defines the compatibility promises `opencode-a2a` currently uphold
|
|
|
8
8
|
- A2A SDK line: `1.x.y`
|
|
9
9
|
- Supported A2A protocol line: `1.0`
|
|
10
10
|
|
|
11
|
-
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.
|
|
11
|
+
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.
|
|
12
12
|
|
|
13
13
|
## Contract Honesty
|
|
14
14
|
|
|
@@ -53,6 +53,7 @@ This repository still ships as an alpha project. Within that alpha line, these d
|
|
|
53
53
|
- authenticated extended card and OpenAPI wire-contract metadata
|
|
54
54
|
|
|
55
55
|
Changes to those surfaces should be treated as compatibility-sensitive and should include corresponding test updates.
|
|
56
|
+
- provider-private session query params use one top-level request shape; the repository does not promise parallel nested `query.*` aliases for the same filters.
|
|
56
57
|
|
|
57
58
|
Service-level behavior layered on top of those core methods should also be declared explicitly when interoperability depends on it. Current examples:
|
|
58
59
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Extension Specifications
|
|
2
2
|
|
|
3
|
-
This document is the stable specification index for
|
|
3
|
+
This document is the stable specification index for extension URIs published by `opencode-a2a`. It is intentionally a compact URI/spec map, not the main consumer guide. For runtime behavior, request examples, and operational setup, see [`guide.md`](./guide.md). For compatibility promises and stability expectations, see [`compatibility.md`](./compatibility.md).
|
|
4
4
|
|
|
5
5
|
## Discovery Surface Note
|
|
6
6
|
|
|
@@ -15,6 +15,7 @@ Provider-private contract note:
|
|
|
15
15
|
- `opencode.*` methods in this repository are deployment-specific provider extensions, not portable A2A baseline capabilities.
|
|
16
16
|
- Shared `metadata.shared.*` contracts are intended to remain low-risk and transportable.
|
|
17
17
|
- Compatibility and wire-contract URIs are descriptive metadata contracts, not activatable runtime capabilities.
|
|
18
|
+
- URI path segments identify the contract, not its auth or disclosure tier; public-vs-extended disclosure is controlled by Agent Card and OpenAPI surfaces.
|
|
18
19
|
|
|
19
20
|
## SDK and Discovery Compatibility
|
|
20
21
|
|
|
@@ -26,20 +27,20 @@ Provider-private contract note:
|
|
|
26
27
|
|
|
27
28
|
| Extension | Scope | Disclosure | URI | Section |
|
|
28
29
|
| --- | --- | --- | --- | --- |
|
|
29
|
-
| Shared Session Binding v1 | Shared request metadata | Public + extended | `urn:opencode-a2a:extension:
|
|
30
|
-
| Shared Model Selection v1 | Shared request metadata | Public + extended | `urn:opencode-a2a:extension:
|
|
31
|
-
| Shared Stream Hints v1 | Shared response/stream metadata | Public + extended | `urn:opencode-a2a:extension:
|
|
32
|
-
| Shared Interactive Interrupt v1 | Shared JSON-RPC callback methods | Public + extended | `urn:opencode-a2a:extension:
|
|
33
|
-
| OpenCode Session Management v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:
|
|
34
|
-
| OpenCode Provider Discovery v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:
|
|
35
|
-
| OpenCode Workspace Control v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:
|
|
36
|
-
| OpenCode Interrupt Recovery v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:
|
|
37
|
-
| A2A Compatibility Profile v1 | Authenticated discovery metadata | Extended only | `urn:opencode-a2a:extension:
|
|
38
|
-
| A2A Wire Contract v1 | Authenticated discovery metadata | Extended only | `urn:opencode-a2a:extension:
|
|
30
|
+
| Shared Session Binding v1 | Shared request metadata | Public + extended | `urn:opencode-a2a:extension:session-binding:v1` | [Shared Session Binding v1](#shared-session-binding-v1) |
|
|
31
|
+
| Shared Model Selection v1 | Shared request metadata | Public + extended | `urn:opencode-a2a:extension:model-selection:v1` | [Shared Model Selection v1](#shared-model-selection-v1) |
|
|
32
|
+
| Shared Stream Hints v1 | Shared response/stream metadata | Public + extended | `urn:opencode-a2a:extension:stream-hints:v1` | [Shared Stream Hints v1](#shared-stream-hints-v1) |
|
|
33
|
+
| Shared Interactive Interrupt v1 | Shared JSON-RPC callback methods | Public + extended | `urn:opencode-a2a:extension:interactive-interrupt:v1` | [Shared Interactive Interrupt v1](#shared-interactive-interrupt-v1) |
|
|
34
|
+
| OpenCode Session Management v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:session-management:v1` | [OpenCode Session Management v1](#opencode-session-management-v1) |
|
|
35
|
+
| OpenCode Provider Discovery v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:provider-discovery:v1` | [OpenCode Provider Discovery v1](#opencode-provider-discovery-v1) |
|
|
36
|
+
| OpenCode Workspace Control v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:workspace-control:v1` | [OpenCode Workspace Control v1](#opencode-workspace-control-v1) |
|
|
37
|
+
| OpenCode Interrupt Recovery v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:interrupt-recovery:v1` | [OpenCode Interrupt Recovery v1](#opencode-interrupt-recovery-v1) |
|
|
38
|
+
| A2A Compatibility Profile v1 | Authenticated discovery metadata | Extended only | `urn:opencode-a2a:extension:compatibility-profile:v1` | [A2A Compatibility Profile v1](#a2a-compatibility-profile-v1) |
|
|
39
|
+
| A2A Wire Contract v1 | Authenticated discovery metadata | Extended only | `urn:opencode-a2a:extension:wire-contract:v1` | [A2A Wire Contract v1](#a2a-wire-contract-v1) |
|
|
39
40
|
|
|
40
41
|
## Shared Session Binding v1
|
|
41
42
|
|
|
42
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
43
|
+
Extension URI: `urn:opencode-a2a:extension:session-binding:v1`
|
|
43
44
|
|
|
44
45
|
- Scope: shared A2A request metadata for rebinding to an existing upstream OpenCode session, plus negotiated response/task session metadata
|
|
45
46
|
- Disclosure: public Agent Card and authenticated extended Agent Card
|
|
@@ -51,7 +52,7 @@ Extension URI: `urn:opencode-a2a:extension:shared:session-binding:v1`
|
|
|
51
52
|
|
|
52
53
|
## Shared Model Selection v1
|
|
53
54
|
|
|
54
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
55
|
+
Extension URI: `urn:opencode-a2a:extension:model-selection:v1`
|
|
55
56
|
|
|
56
57
|
- Scope: shared request-scoped model override for the main chat path
|
|
57
58
|
- Disclosure: public Agent Card and authenticated extended Agent Card
|
|
@@ -64,20 +65,27 @@ Extension URI: `urn:opencode-a2a:extension:shared:model-selection:v1`
|
|
|
64
65
|
|
|
65
66
|
## Shared Stream Hints v1
|
|
66
67
|
|
|
67
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
68
|
+
Extension URI: `urn:opencode-a2a:extension:stream-hints:v1`
|
|
68
69
|
|
|
69
70
|
- Scope: shared response/task/stream metadata for block identity, progress, and usage hints
|
|
70
71
|
- Disclosure: public Agent Card and authenticated extended Agent Card
|
|
71
72
|
- Activation: client requests the URI via `A2A-Extensions`; runtime emits shared metadata on streamed events and final task payloads
|
|
72
|
-
-
|
|
73
|
-
-
|
|
73
|
+
- Declared field map:
|
|
74
|
+
- `metadata.shared.stream.block_type`
|
|
75
|
+
- `metadata.shared.stream.sequence`
|
|
76
|
+
- `metadata.shared.progress.type`
|
|
77
|
+
- `metadata.shared.progress.status`
|
|
78
|
+
- `metadata.shared.usage.input_tokens`
|
|
79
|
+
- `metadata.shared.usage.output_tokens`
|
|
80
|
+
- `metadata.shared.usage.total_tokens`
|
|
81
|
+
- Clients must not treat undeclared metadata under this namespace as part of the shared v1 contract
|
|
74
82
|
- Dependencies: none declared by this version
|
|
75
83
|
- Security boundary: this extension is observational metadata only; callback methods are defined by the separate shared interactive interrupt extension
|
|
76
84
|
- Versioning: breaking changes require a new versioned URI
|
|
77
85
|
|
|
78
86
|
## Shared Interactive Interrupt v1
|
|
79
87
|
|
|
80
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
88
|
+
Extension URI: `urn:opencode-a2a:extension:interactive-interrupt:v1`
|
|
81
89
|
|
|
82
90
|
- Scope: shared JSON-RPC callback methods used to answer interactive permission and question interrupts
|
|
83
91
|
- Disclosure: public Agent Card and authenticated extended Agent Card
|
|
@@ -90,7 +98,7 @@ Extension URI: `urn:opencode-a2a:extension:shared:interactive-interrupt:v1`
|
|
|
90
98
|
|
|
91
99
|
## OpenCode Session Management v1
|
|
92
100
|
|
|
93
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
101
|
+
Extension URI: `urn:opencode-a2a:extension:session-management:v1`
|
|
94
102
|
|
|
95
103
|
- Scope: OpenCode session read, mutation, and control methods exposed as A2A JSON-RPC extension methods
|
|
96
104
|
- Disclosure: authenticated extended Agent Card only
|
|
@@ -102,7 +110,7 @@ Extension URI: `urn:opencode-a2a:extension:private:session-management:v1`
|
|
|
102
110
|
|
|
103
111
|
## OpenCode Provider Discovery v1
|
|
104
112
|
|
|
105
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
113
|
+
Extension URI: `urn:opencode-a2a:extension:provider-discovery:v1`
|
|
106
114
|
|
|
107
115
|
- Scope: OpenCode provider and model discovery methods exposed as A2A JSON-RPC extension methods
|
|
108
116
|
- Disclosure: authenticated extended Agent Card only
|
|
@@ -114,7 +122,7 @@ Extension URI: `urn:opencode-a2a:extension:private:provider-discovery:v1`
|
|
|
114
122
|
|
|
115
123
|
## OpenCode Workspace Control v1
|
|
116
124
|
|
|
117
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
125
|
+
Extension URI: `urn:opencode-a2a:extension:workspace-control:v1`
|
|
118
126
|
|
|
119
127
|
- Scope: OpenCode project, workspace, and worktree discovery/control methods exposed as A2A JSON-RPC extension methods
|
|
120
128
|
- Disclosure: authenticated extended Agent Card only
|
|
@@ -126,7 +134,7 @@ Extension URI: `urn:opencode-a2a:extension:private:workspace-control:v1`
|
|
|
126
134
|
|
|
127
135
|
## OpenCode Interrupt Recovery v1
|
|
128
136
|
|
|
129
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
137
|
+
Extension URI: `urn:opencode-a2a:extension:interrupt-recovery:v1`
|
|
130
138
|
|
|
131
139
|
- Scope: local interrupt recovery methods exposed as A2A JSON-RPC extension methods
|
|
132
140
|
- Disclosure: authenticated extended Agent Card only
|
|
@@ -138,7 +146,7 @@ Extension URI: `urn:opencode-a2a:extension:private:interrupt-recovery:v1`
|
|
|
138
146
|
|
|
139
147
|
## A2A Compatibility Profile v1
|
|
140
148
|
|
|
141
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
149
|
+
Extension URI: `urn:opencode-a2a:extension:compatibility-profile:v1`
|
|
142
150
|
|
|
143
151
|
- Scope: authenticated discovery metadata describing protocol support, extension retention, and stable service behaviors
|
|
144
152
|
- Disclosure: authenticated extended Agent Card only
|
|
@@ -150,7 +158,7 @@ Extension URI: `urn:opencode-a2a:extension:private:compatibility-profile:v1`
|
|
|
150
158
|
|
|
151
159
|
## A2A Wire Contract v1
|
|
152
160
|
|
|
153
|
-
Extension URI: `urn:opencode-a2a:extension:
|
|
161
|
+
Extension URI: `urn:opencode-a2a:extension:wire-contract:v1`
|
|
154
162
|
|
|
155
163
|
- Scope: authenticated discovery metadata describing supported methods, HTTP endpoints, extension URIs, and unified error semantics
|
|
156
164
|
- Disclosure: authenticated extended Agent Card only
|
|
@@ -229,9 +229,7 @@ If one deployment works while another fails against the same upstream provider,
|
|
|
229
229
|
- text chunks use a stable text artifact ID
|
|
230
230
|
- reasoning chunks use a stable reasoning artifact ID
|
|
231
231
|
- tool-call updates use a stable per-tool-part artifact ID when the upstream part is identifiable
|
|
232
|
-
-
|
|
233
|
-
- `artifact.metadata.shared.stream.message_id` remains best-effort metadata: when upstream omits `message_id`, the service falls back to a stable request-scoped message identity.
|
|
234
|
-
- `message_id` and `event_id` are advanced correlation fields: they help timeline stitching, deduplication, diagnostics, and advanced UI linking, but generic A2A consumers must not require them.
|
|
232
|
+
- The shared stream-hints v1 contract only declares `block_type` and `sequence` under `artifact.metadata.shared.stream`.
|
|
235
233
|
- `artifact.metadata.shared.stream.sequence` carries the canonical per-request stream sequence.
|
|
236
234
|
- A final complete text snapshot is emitted only when streaming chunks did not already produce the same final text.
|
|
237
235
|
- That final complete text snapshot uses `append=false` on the text artifact so clients and the task store can treat it as the canonical replace-on-finish version rather than another fragment.
|
|
@@ -242,13 +240,15 @@ If one deployment works while another fails against the same upstream provider,
|
|
|
242
240
|
- 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.
|
|
243
241
|
- 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.
|
|
244
242
|
- Persistence is canonicalized separately from transport: stream subscribers still receive incremental artifact updates, while task-store persistence rewrites those updates into compact per-artifact snapshots so `GetTask` and terminal replay do not accumulate token-level fragments.
|
|
245
|
-
-
|
|
246
|
-
- Progress metadata at `metadata.shared.progress` is emitted only when the client negotiated `urn:opencode-a2a:extension:
|
|
243
|
+
- The shared stream-hints v1 contract declares normalized usage fields `input_tokens`, `output_tokens`, and `total_tokens` at `metadata.shared.usage`.
|
|
244
|
+
- Progress metadata at `metadata.shared.progress` is emitted only when the client negotiated `urn:opencode-a2a:extension:stream-hints:v1`; baseline streams do not emit duplicate generic `working` status updates just to carry progress hints.
|
|
247
245
|
- Usage is extracted from documented info payloads and supported usage parts such as `step-finish`; non-usage parts with similar fields are ignored.
|
|
248
|
-
- Interrupt events (`permission.asked` / `question.asked`) are mapped to `TaskStatusUpdateEvent(final=false, state=input-required)` with details at `metadata.shared.interrupt` when the client negotiated `urn:opencode-a2a:extension:
|
|
246
|
+
- Interrupt events (`permission.asked` / `question.asked`) are mapped to `TaskStatusUpdateEvent(final=false, state=input-required)` with details at `metadata.shared.interrupt` when the client negotiated `urn:opencode-a2a:extension:interactive-interrupt:v1`.
|
|
249
247
|
- Resolved interrupt events (`permission.replied` / `question.replied` / `question.rejected`) are emitted as `TaskStatusUpdateEvent(final=false, state=working)` with `metadata.shared.interrupt.phase=resolved` only when the same interactive interrupt extension is negotiated.
|
|
250
248
|
- Duplicate or unknown resolved events are suppressed unless the matching request is still pending.
|
|
251
249
|
- Non-streaming requests return a `Task` directly. When `configuration.returnImmediately=true`, the initial response is a working `Task` snapshot and completion continues in the background for later `GetTask` reads.
|
|
250
|
+
- For successful non-streaming `message:send` completions, `Task.artifacts` is the canonical carrier for the assistant result text.
|
|
251
|
+
- The terminal `Task.status.message` may carry a short completion status such as `Completed.`, but it does not duplicate the full result text.
|
|
252
252
|
- Non-streaming `message:send` responses may include normalized token usage at `Task.metadata.shared.usage` with the same field schema.
|
|
253
253
|
|
|
254
254
|
## Auth, Limits, and Failure Contract
|
|
@@ -286,6 +286,7 @@ Current behavior:
|
|
|
286
286
|
- `all_jsonrpc_methods` is the runtime truth for the current deployment.
|
|
287
287
|
- The current SDK-owned core JSON-RPC surface includes `GetExtendedAgentCard` and `tasks/pushNotificationConfig/*`.
|
|
288
288
|
- The current SDK-owned REST surface also includes `GET /v1/tasks` and the task push notification config routes.
|
|
289
|
+
- 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.
|
|
289
290
|
- 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 push notification operations remain unsupported. REST routes currently return HTTP `501`, while JSON-RPC methods surface SDK-owned unsupported error envelopes.
|
|
290
291
|
|
|
291
292
|
When `A2A_ENABLE_SESSION_SHELL=false`, `opencode.sessions.shell` is omitted from `all_jsonrpc_methods` and exposed only through `extensions.conditionally_available_methods`.
|
|
@@ -458,7 +459,7 @@ Important distinction:
|
|
|
458
459
|
|
|
459
460
|
Stable specification URI:
|
|
460
461
|
|
|
461
|
-
- `urn:opencode-a2a:extension:
|
|
462
|
+
- `urn:opencode-a2a:extension:session-binding:v1`
|
|
462
463
|
|
|
463
464
|
This section focuses on how clients should use the binding at runtime. For the stable URI record and public-vs-extended disclosure policy, see [`extension-specifications.md`](./extension-specifications.md).
|
|
464
465
|
|
|
@@ -505,7 +506,7 @@ curl -sS http://127.0.0.1:8000/v1/message:send \
|
|
|
505
506
|
|
|
506
507
|
Stable specification URI:
|
|
507
508
|
|
|
508
|
-
- `urn:opencode-a2a:extension:
|
|
509
|
+
- `urn:opencode-a2a:extension:model-selection:v1`
|
|
509
510
|
|
|
510
511
|
This section focuses on request-scoped usage. For the stable URI record and public-vs-extended disclosure policy, see [`extension-specifications.md`](./extension-specifications.md).
|
|
511
512
|
|
|
@@ -558,7 +559,7 @@ curl -sS http://127.0.0.1:8000/v1/message:send \
|
|
|
558
559
|
|
|
559
560
|
Stable specification URI:
|
|
560
561
|
|
|
561
|
-
- `urn:opencode-a2a:extension:
|
|
562
|
+
- `urn:opencode-a2a:extension:stream-hints:v1`
|
|
562
563
|
|
|
563
564
|
This section focuses on how clients should interpret runtime metadata. For the stable URI record and public-vs-extended disclosure policy, see [`extension-specifications.md`](./extension-specifications.md).
|
|
564
565
|
|
|
@@ -571,24 +572,25 @@ Runtime payload:
|
|
|
571
572
|
Shared runtime fields:
|
|
572
573
|
|
|
573
574
|
- `metadata.shared.stream`
|
|
574
|
-
-
|
|
575
|
+
- declared shared v1 fields: `block_type` and `sequence`
|
|
575
576
|
- `metadata.shared.usage`
|
|
576
|
-
-
|
|
577
|
+
- declared shared v1 fields: `input_tokens`, `output_tokens`, and `total_tokens`
|
|
578
|
+
- clients must ignore undeclared fields when interpreting the shared v1 contract
|
|
577
579
|
|
|
578
580
|
Consumer guidance:
|
|
579
581
|
|
|
580
582
|
- Use the extension declaration to know the server emits canonical shared stream hints.
|
|
581
583
|
- Use runtime metadata to render block timelines, progress states, and token usage.
|
|
582
|
-
-
|
|
584
|
+
- Do not rely on undeclared fields under `metadata.shared.stream` or `metadata.shared.usage` as stable contract surface.
|
|
583
585
|
- Do not infer capability support only from seeing one runtime field on one response; rely on Agent Card discovery first when possible.
|
|
584
586
|
|
|
585
587
|
Minimal stream semantics summary:
|
|
586
588
|
|
|
587
589
|
- `text`, `reasoning`, and `tool_call` are emitted as canonical block types
|
|
588
590
|
- `text` and `reasoning` blocks use text parts, while `tool_call` uses structured v1 part payloads
|
|
589
|
-
- `
|
|
591
|
+
- only `block_type` and `sequence` are part of the declared shared stream field map
|
|
590
592
|
- `sequence` is the per-request canonical stream sequence
|
|
591
|
-
- final task/status metadata may repeat
|
|
593
|
+
- final task/status metadata may repeat declared usage totals
|
|
592
594
|
|
|
593
595
|
## OpenCode Session Management A2A Extension
|
|
594
596
|
|
|
@@ -621,11 +623,13 @@ Detailed contract discovery for this provider-private surface is intentionally a
|
|
|
621
623
|
- Session list filters:
|
|
622
624
|
- optional `directory`, `roots`, `start`, `search`, `limit`
|
|
623
625
|
- optional `metadata.opencode.workspace.id`
|
|
626
|
+
- nested `query` objects are not supported; pass filters at the top level only
|
|
624
627
|
- `directory` is normalized through the same workspace-boundary rules used by other OpenCode directory overrides before reaching upstream
|
|
625
628
|
- when `metadata.opencode.workspace.id` is present, the adapter routes by workspace and ignores `directory`
|
|
626
629
|
- Session message history filters:
|
|
627
630
|
- optional `limit`, `before`
|
|
628
631
|
- optional `metadata.opencode.workspace.id`
|
|
632
|
+
- nested `query` objects are not supported; pass filters at the top level only
|
|
629
633
|
- `before` is an opaque cursor for loading older messages and is only supported on `opencode.sessions.messages.list`
|
|
630
634
|
- Mutation methods:
|
|
631
635
|
- `opencode.sessions.fork`
|
|
@@ -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 + dependency compatibility + lint + mypy + tests + coverage + built-wheel smoke test)
|
|
14
|
+
- [`doctor.sh`](./doctor.sh): primary local development regression entrypoint with explicit fix/verify/package phases (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
|
|
@@ -23,5 +23,6 @@ Executable scripts live in this directory. This file is the entry index for the
|
|
|
23
23
|
|
|
24
24
|
- `doctor.sh` and `dependency_health.sh` intentionally remain separate entrypoints and share common prerequisites through [`health_common.sh`](./health_common.sh).
|
|
25
25
|
- `doctor.sh` covers the default local validation baseline, while `dependency_health.sh` remains focused on standalone dependency review and audit flow.
|
|
26
|
+
- `doctor.sh` stops early when `pre-commit` rewrites files so you can review the changes and rerun `doctor.sh` from the updated worktree.
|
|
26
27
|
- [`.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.
|
|
27
28
|
- External conformance experiments remain intentionally separate from the default regression path. See [`../docs/conformance.md`](../docs/conformance.md).
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# shellcheck source=./health_common.sh
|
|
5
|
+
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/health_common.sh"
|
|
6
|
+
|
|
7
|
+
doctor_repo_state_fingerprint() {
|
|
8
|
+
{
|
|
9
|
+
git diff --no-ext-diff --binary --cached -- .
|
|
10
|
+
git diff --no-ext-diff --binary -- .
|
|
11
|
+
while IFS= read -r -d '' path; do
|
|
12
|
+
printf 'untracked %s\n' "$path"
|
|
13
|
+
cat "$path"
|
|
14
|
+
printf '\n'
|
|
15
|
+
done < <(git ls-files --others --exclude-standard -z)
|
|
16
|
+
} | git hash-object --stdin
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
run_doctor_fix_phase() {
|
|
20
|
+
local pre_commit_exit_code=0
|
|
21
|
+
local repo_state_before
|
|
22
|
+
local repo_state_after
|
|
23
|
+
|
|
24
|
+
echo "[doctor] run fix phase"
|
|
25
|
+
repo_state_before="$(doctor_repo_state_fingerprint)"
|
|
26
|
+
|
|
27
|
+
if uv run pre-commit run --all-files; then
|
|
28
|
+
pre_commit_exit_code=0
|
|
29
|
+
else
|
|
30
|
+
pre_commit_exit_code=$?
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
repo_state_after="$(doctor_repo_state_fingerprint)"
|
|
34
|
+
if [[ "$repo_state_before" != "$repo_state_after" ]]; then
|
|
35
|
+
echo "[doctor] pre-commit modified files; review the changes and rerun doctor" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
if (( pre_commit_exit_code != 0 )); then
|
|
40
|
+
exit "$pre_commit_exit_code"
|
|
41
|
+
fi
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
run_doctor_verify_phase() {
|
|
45
|
+
echo "[doctor] run verify phase"
|
|
46
|
+
|
|
47
|
+
echo "[doctor] run type checks"
|
|
48
|
+
uv run mypy src/opencode_a2a
|
|
49
|
+
|
|
50
|
+
echo "[doctor] run tests"
|
|
51
|
+
uv run pytest
|
|
52
|
+
|
|
53
|
+
echo "[doctor] enforce coverage policy"
|
|
54
|
+
uv run python ./scripts/check_coverage.py
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
run_doctor_package_phase() {
|
|
58
|
+
echo "[doctor] run package phase"
|
|
59
|
+
|
|
60
|
+
echo "[doctor] build release artifacts"
|
|
61
|
+
rm -f dist/opencode_a2a-*.whl dist/opencode_a2a-*.tar.gz
|
|
62
|
+
uv build --no-sources
|
|
63
|
+
|
|
64
|
+
echo "[doctor] smoke test built wheel"
|
|
65
|
+
bash ./scripts/smoke_test_built_cli.sh dist/opencode_a2a-*.whl
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
run_shared_repo_health_prerequisites "doctor"
|
|
69
|
+
run_doctor_fix_phase
|
|
70
|
+
run_doctor_verify_phase
|
|
71
|
+
run_doctor_package_phase
|
|
@@ -74,13 +74,13 @@ def _normalize_transport(value: str) -> str:
|
|
|
74
74
|
normalized = value.strip().lower()
|
|
75
75
|
if normalized in {"jsonrpc", "json-rpc", "json_rpc"}:
|
|
76
76
|
return "JSONRPC"
|
|
77
|
-
if normalized in {"http+json", "
|
|
77
|
+
if normalized in {"http+json", "http-json", "http_json"}:
|
|
78
78
|
return "HTTP+JSON"
|
|
79
79
|
if normalized in {"grpc"}:
|
|
80
80
|
return "GRPC"
|
|
81
81
|
if not normalized:
|
|
82
82
|
return "JSONRPC"
|
|
83
|
-
|
|
83
|
+
raise ValueError(f"supported_transports contains unsupported transport {value!r}")
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
def _parse_transports(
|
|
@@ -238,10 +238,7 @@ def map_agent_card_error(
|
|
|
238
238
|
) -> A2AClientError:
|
|
239
239
|
if isinstance(exc, AgentCardResolutionError):
|
|
240
240
|
if exc.status_code is not None:
|
|
241
|
-
return
|
|
242
|
-
map_client_error("agent-card/fetch", SDKClientError(str(exc))),
|
|
243
|
-
exc.status_code,
|
|
244
|
-
)
|
|
241
|
+
return map_http_error("agent-card/fetch", exc)
|
|
245
242
|
return A2APeerProtocolError(
|
|
246
243
|
"Remote A2A peer returned an invalid agent card payload",
|
|
247
244
|
error_code="invalid_agent_card",
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from collections.abc import Mapping
|
|
6
|
-
from typing import Any
|
|
5
|
+
from collections.abc import Iterable, Mapping
|
|
6
|
+
from typing import Any, cast
|
|
7
7
|
|
|
8
8
|
from a2a.types import Message, Part, StreamResponse
|
|
9
9
|
from google.protobuf.json_format import MessageToDict
|
|
@@ -11,8 +11,13 @@ from google.protobuf.message import Message as ProtoMessage
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def extract_text(payload: Any) -> str | None:
|
|
14
|
+
def is_item_sequence(value: Any) -> bool:
|
|
15
|
+
return isinstance(value, Iterable) and not isinstance(
|
|
16
|
+
value, (str, bytes, bytearray, Mapping)
|
|
17
|
+
)
|
|
18
|
+
|
|
14
19
|
def extract_from_iterable(items: Any) -> str | None:
|
|
15
|
-
if not
|
|
20
|
+
if not is_item_sequence(items):
|
|
16
21
|
return None
|
|
17
22
|
for item in items:
|
|
18
23
|
extracted = extract_text(item)
|
|
@@ -21,7 +26,7 @@ def extract_text(payload: Any) -> str | None:
|
|
|
21
26
|
return None
|
|
22
27
|
|
|
23
28
|
def extract_from_parts(parts: Any) -> str | None:
|
|
24
|
-
if not
|
|
29
|
+
if not is_item_sequence(parts):
|
|
25
30
|
return None
|
|
26
31
|
collected: list[str] = []
|
|
27
32
|
for part in parts:
|
|
@@ -47,14 +52,14 @@ def extract_text(payload: Any) -> str | None:
|
|
|
47
52
|
def extract_from_mapping(payload_map: Mapping[str, Any]) -> str | None:
|
|
48
53
|
for key in (
|
|
49
54
|
"content",
|
|
50
|
-
"message",
|
|
51
|
-
"messages",
|
|
52
55
|
"result",
|
|
53
|
-
"status",
|
|
54
56
|
"text",
|
|
55
57
|
"parts",
|
|
56
58
|
"artifact",
|
|
57
59
|
"artifacts",
|
|
60
|
+
"message",
|
|
61
|
+
"messages",
|
|
62
|
+
"status",
|
|
58
63
|
"history",
|
|
59
64
|
"events",
|
|
60
65
|
"root",
|
|
@@ -76,7 +81,7 @@ def extract_text(payload: Any) -> str | None:
|
|
|
76
81
|
artifact_text = extract_text(value)
|
|
77
82
|
if artifact_text:
|
|
78
83
|
return artifact_text
|
|
79
|
-
if
|
|
84
|
+
if is_item_sequence(value) and key in (
|
|
80
85
|
"messages",
|
|
81
86
|
"artifacts",
|
|
82
87
|
"history",
|
|
@@ -90,7 +95,7 @@ def extract_text(payload: Any) -> str | None:
|
|
|
90
95
|
return nested_text
|
|
91
96
|
return None
|
|
92
97
|
|
|
93
|
-
if
|
|
98
|
+
if is_item_sequence(payload):
|
|
94
99
|
return extract_from_iterable(payload)
|
|
95
100
|
|
|
96
101
|
if isinstance(payload, Message):
|
|
@@ -110,21 +115,30 @@ def extract_text(payload: Any) -> str | None:
|
|
|
110
115
|
if isinstance(payload, str):
|
|
111
116
|
return payload.strip() or None
|
|
112
117
|
|
|
113
|
-
|
|
114
|
-
if
|
|
115
|
-
text = extract_text(
|
|
118
|
+
artifact_payload = getattr(payload, "artifact", None)
|
|
119
|
+
if artifact_payload is not None:
|
|
120
|
+
text = extract_text(artifact_payload)
|
|
116
121
|
if text:
|
|
117
122
|
return text
|
|
118
123
|
|
|
124
|
+
artifacts = getattr(payload, "artifacts", None)
|
|
125
|
+
if is_item_sequence(artifacts):
|
|
126
|
+
for artifact in cast(Iterable[Any], artifacts):
|
|
127
|
+
artifact_parts = getattr(artifact, "parts", None)
|
|
128
|
+
if is_item_sequence(artifact_parts):
|
|
129
|
+
text = extract_from_parts(artifact_parts)
|
|
130
|
+
if text:
|
|
131
|
+
return text
|
|
132
|
+
|
|
119
133
|
message_payload = getattr(payload, "message", None)
|
|
120
134
|
if message_payload is not None:
|
|
121
135
|
text = extract_text(message_payload)
|
|
122
136
|
if text:
|
|
123
137
|
return text
|
|
124
138
|
|
|
125
|
-
|
|
126
|
-
if
|
|
127
|
-
text = extract_text(
|
|
139
|
+
status_payload = getattr(payload, "status", None)
|
|
140
|
+
if status_payload is not None:
|
|
141
|
+
text = extract_text(status_payload)
|
|
128
142
|
if text:
|
|
129
143
|
return text
|
|
130
144
|
|
|
@@ -135,21 +149,12 @@ def extract_text(payload: Any) -> str | None:
|
|
|
135
149
|
return text
|
|
136
150
|
|
|
137
151
|
history = getattr(payload, "history", None)
|
|
138
|
-
if
|
|
139
|
-
for item in reversed(history):
|
|
152
|
+
if is_item_sequence(history) and history:
|
|
153
|
+
for item in reversed(list(cast(Iterable[Any], history))):
|
|
140
154
|
text = extract_text(item)
|
|
141
155
|
if text:
|
|
142
156
|
return text
|
|
143
157
|
|
|
144
|
-
artifacts = getattr(payload, "artifacts", None)
|
|
145
|
-
if isinstance(artifacts, (list, tuple)):
|
|
146
|
-
for artifact in artifacts:
|
|
147
|
-
artifact_parts = getattr(artifact, "parts", None)
|
|
148
|
-
if isinstance(artifact_parts, (list, tuple)):
|
|
149
|
-
text = extract_from_parts(artifact_parts)
|
|
150
|
-
if text:
|
|
151
|
-
return text
|
|
152
|
-
|
|
153
158
|
text = extract_from_parts(getattr(payload, "parts", None))
|
|
154
159
|
if text:
|
|
155
160
|
return text
|
|
@@ -139,11 +139,6 @@ SESSION_METHOD_CONTRACTS: dict[str, SessionQueryMethodContract] = {
|
|
|
139
139
|
"roots",
|
|
140
140
|
"start",
|
|
141
141
|
"search",
|
|
142
|
-
"query.limit",
|
|
143
|
-
"query.directory",
|
|
144
|
-
"query.roots",
|
|
145
|
-
"query.start",
|
|
146
|
-
"query.search",
|
|
147
142
|
),
|
|
148
143
|
unsupported_params=SESSION_QUERY_PAGINATION_UNSUPPORTED,
|
|
149
144
|
result_fields=("items",),
|
|
@@ -158,8 +153,6 @@ SESSION_METHOD_CONTRACTS: dict[str, SessionQueryMethodContract] = {
|
|
|
158
153
|
"limit",
|
|
159
154
|
"before",
|
|
160
155
|
OPENCODE_WORKSPACE_METADATA_FIELD,
|
|
161
|
-
"query.limit",
|
|
162
|
-
"query.before",
|
|
163
156
|
),
|
|
164
157
|
unsupported_params=SESSION_QUERY_PAGINATION_UNSUPPORTED,
|
|
165
158
|
result_fields=("items", "next_cursor"),
|
{opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/identifiers.py
RENAMED
|
@@ -15,62 +15,16 @@ OPENCODE_WORKSPACE_METADATA_FIELD = "metadata.opencode.workspace.id"
|
|
|
15
15
|
EXTENSION_URI_NAMESPACE = "urn:opencode-a2a:extension:"
|
|
16
16
|
EXTENSION_SPEC_INDEX_DOCUMENT_PATH = "docs/extension-specifications.md"
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
MODEL_SELECTION_EXTENSION_URI = _extension_uri(
|
|
30
|
-
"shared",
|
|
31
|
-
"model-selection",
|
|
32
|
-
"v1",
|
|
33
|
-
)
|
|
34
|
-
STREAMING_EXTENSION_URI = _extension_uri(
|
|
35
|
-
"shared",
|
|
36
|
-
"stream-hints",
|
|
37
|
-
"v1",
|
|
38
|
-
)
|
|
39
|
-
SESSION_MANAGEMENT_EXTENSION_URI = _extension_uri(
|
|
40
|
-
"private",
|
|
41
|
-
"session-management",
|
|
42
|
-
"v1",
|
|
43
|
-
)
|
|
44
|
-
PROVIDER_DISCOVERY_EXTENSION_URI = _extension_uri(
|
|
45
|
-
"private",
|
|
46
|
-
"provider-discovery",
|
|
47
|
-
"v1",
|
|
48
|
-
)
|
|
49
|
-
INTERRUPT_CALLBACK_EXTENSION_URI = _extension_uri(
|
|
50
|
-
"shared",
|
|
51
|
-
"interactive-interrupt",
|
|
52
|
-
"v1",
|
|
53
|
-
)
|
|
54
|
-
INTERRUPT_RECOVERY_EXTENSION_URI = _extension_uri(
|
|
55
|
-
"private",
|
|
56
|
-
"interrupt-recovery",
|
|
57
|
-
"v1",
|
|
58
|
-
)
|
|
59
|
-
WORKSPACE_CONTROL_EXTENSION_URI = _extension_uri(
|
|
60
|
-
"private",
|
|
61
|
-
"workspace-control",
|
|
62
|
-
"v1",
|
|
63
|
-
)
|
|
64
|
-
COMPATIBILITY_PROFILE_EXTENSION_URI = _extension_uri(
|
|
65
|
-
"private",
|
|
66
|
-
"compatibility-profile",
|
|
67
|
-
"v1",
|
|
68
|
-
)
|
|
69
|
-
WIRE_CONTRACT_EXTENSION_URI = _extension_uri(
|
|
70
|
-
"private",
|
|
71
|
-
"wire-contract",
|
|
72
|
-
"v1",
|
|
73
|
-
)
|
|
18
|
+
SESSION_BINDING_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}session-binding:v1"
|
|
19
|
+
MODEL_SELECTION_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}model-selection:v1"
|
|
20
|
+
STREAMING_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}stream-hints:v1"
|
|
21
|
+
SESSION_MANAGEMENT_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}session-management:v1"
|
|
22
|
+
PROVIDER_DISCOVERY_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}provider-discovery:v1"
|
|
23
|
+
INTERRUPT_CALLBACK_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}interactive-interrupt:v1"
|
|
24
|
+
INTERRUPT_RECOVERY_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}interrupt-recovery:v1"
|
|
25
|
+
WORKSPACE_CONTROL_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}workspace-control:v1"
|
|
26
|
+
COMPATIBILITY_PROFILE_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}compatibility-profile:v1"
|
|
27
|
+
WIRE_CONTRACT_EXTENSION_URI = f"{EXTENSION_URI_NAMESPACE}wire-contract:v1"
|
|
74
28
|
PUBLIC_EXTENSION_URIS: tuple[str, ...] = (
|
|
75
29
|
SESSION_BINDING_EXTENSION_URI,
|
|
76
30
|
MODEL_SELECTION_EXTENSION_URI,
|