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.
Files changed (212) hide show
  1. {opencode_a2a-1.0.0/src/opencode_a2a.egg-info → opencode_a2a-1.1.0}/PKG-INFO +1 -1
  2. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/compatibility.md +2 -1
  3. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/extension-specifications.md +31 -23
  4. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/guide.md +18 -14
  5. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/README.md +2 -1
  6. opencode_a2a-1.1.0/scripts/doctor.sh +71 -0
  7. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/config.py +2 -2
  8. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/error_mapping.py +1 -4
  9. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/payload_text.py +31 -26
  10. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/catalog.py +0 -7
  11. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/identifiers.py +10 -56
  12. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/public_params.py +53 -37
  13. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/coordinator.py +3 -3
  14. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/stream_runtime.py +11 -21
  15. opencode_a2a-1.1.0/src/opencode_a2a/interrupt_request_tracker.py +75 -0
  16. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/interrupt_callbacks.py +18 -28
  17. opencode_a2a-1.1.0/src/opencode_a2a/jsonrpc/params.py +131 -0
  18. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/database.py +18 -0
  19. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/openapi.py +39 -23
  20. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/task_store.py +2 -2
  21. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/task_store_sdk_compat.py +4 -1
  22. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0/src/opencode_a2a.egg-info}/PKG-INFO +1 -1
  23. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/SOURCES.txt +6 -0
  24. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_client_config.py +12 -0
  25. opencode_a2a-1.1.0/tests/client/test_error_mapping.py +254 -0
  26. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_payload_text.py +24 -0
  27. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/config/test_settings.py +30 -0
  28. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/contracts/test_extension_contract_consistency.py +36 -3
  29. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_directory_validation.py +2 -1
  30. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_metrics.py +6 -1
  31. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_multipart_input.py +6 -1
  32. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_opencode_agent_session_binding.py +5 -2
  33. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_session_ownership.py +1 -1
  34. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_streaming_output_contract_core.py +4 -1
  35. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_streaming_output_contract_interrupts.py +2 -2
  36. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_streaming_output_contract_logging.py +1 -1
  37. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_application_dispatch.py +2 -1
  38. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_dispatch_registry.py +15 -5
  39. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_jsonrpc_params.py +13 -28
  40. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_jsonrpc_unsupported_method.py +1 -1
  41. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_commands.py +5 -4
  42. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_interrupts.py +84 -4
  43. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_lifecycle.py +4 -4
  44. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_prompt_async.py +4 -4
  45. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_session_extension_queries.py +9 -7
  46. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_opencode_workspace_control_extension.py +5 -4
  47. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/profile/test_profile_runtime.py +1 -1
  48. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/scripts/test_script_health_contract.py +10 -0
  49. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_agent_card.py +9 -14
  50. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_app_behaviors.py +1 -1
  51. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_auth.py +1 -1
  52. opencode_a2a-1.1.0/tests/server/test_cli.py +312 -0
  53. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_database_app_persistence.py +1 -1
  54. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_state_store.py +1 -1
  55. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_task_store_factory.py +39 -2
  56. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_transport_contract.py +2 -2
  57. opencode_a2a-1.1.0/tests/support/helpers.py +231 -0
  58. opencode_a2a-1.1.0/tests/support/interrupt_clients.py +141 -0
  59. opencode_a2a-1.1.0/tests/support/session_query_client.py +449 -0
  60. opencode_a2a-1.1.0/tests/support/settings.py +82 -0
  61. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/streaming_output.py +5 -34
  62. opencode_a2a-1.1.0/tests/support/workspace_control_client.py +65 -0
  63. opencode_a2a-1.1.0/tests/test_parsing.py +126 -0
  64. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/upstream/test_opencode_upstream_client_params.py +1 -1
  65. opencode_a2a-1.0.0/scripts/doctor.sh +0 -26
  66. opencode_a2a-1.0.0/src/opencode_a2a/jsonrpc/params.py +0 -199
  67. opencode_a2a-1.0.0/tests/client/test_error_mapping.py +0 -85
  68. opencode_a2a-1.0.0/tests/server/test_cli.py +0 -134
  69. opencode_a2a-1.0.0/tests/support/helpers.py +0 -945
  70. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.github/dependabot.yml +0 -0
  71. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.github/workflows/dependency-review.yml +0 -0
  72. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.github/workflows/publish.yml +0 -0
  73. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.github/workflows/validate.yml +0 -0
  74. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.gitignore +0 -0
  75. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.pre-commit-config.yaml +0 -0
  76. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/.secrets.baseline +0 -0
  77. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/AGENTS.md +0 -0
  78. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/CODE_OF_CONDUCT.md +0 -0
  79. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/CONTRIBUTING.md +0 -0
  80. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/LICENSE +0 -0
  81. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/MANIFEST.in +0 -0
  82. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/README.md +0 -0
  83. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/SECURITY.md +0 -0
  84. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/SUPPORT.md +0 -0
  85. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/architecture.md +0 -0
  86. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/conformance-triage.md +0 -0
  87. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/conformance.md +0 -0
  88. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/docs/maintainer-architecture.md +0 -0
  89. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/pyproject.toml +0 -0
  90. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/check_coverage.py +0 -0
  91. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/conformance.sh +0 -0
  92. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/dependency_health.sh +0 -0
  93. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/find_thin_wrappers.py +0 -0
  94. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/health_common.sh +0 -0
  95. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/lint.sh +0 -0
  96. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/scripts/smoke_test_built_cli.sh +0 -0
  97. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/setup.cfg +0 -0
  98. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/__init__.py +0 -0
  99. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/a2a_protocol.py +0 -0
  100. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/a2a_utils.py +0 -0
  101. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/auth.py +0 -0
  102. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/cli.py +0 -0
  103. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/__init__.py +0 -0
  104. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/agent_card.py +0 -0
  105. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/auth.py +0 -0
  106. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/client.py +0 -0
  107. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/errors.py +0 -0
  108. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/polling.py +0 -0
  109. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/client/request_context.py +0 -0
  110. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/config.py +0 -0
  111. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/__init__.py +0 -0
  112. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/__init__.py +0 -0
  113. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/capabilities.py +0 -0
  114. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/compatibility.py +0 -0
  115. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/contract_docs.py +0 -0
  116. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/contracts/extensions/private_params.py +0 -0
  117. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/__init__.py +0 -0
  118. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/event_helpers.py +0 -0
  119. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/executor.py +0 -0
  120. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/metrics.py +0 -0
  121. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/session_manager.py +0 -0
  122. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/stream_events.py +0 -0
  123. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/stream_state.py +0 -0
  124. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/tool_error_mapping.py +0 -0
  125. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/tool_orchestration.py +0 -0
  126. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/execution/upstream_error_translator.py +0 -0
  127. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/extension_negotiation.py +0 -0
  128. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/__init__.py +0 -0
  129. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/application.py +0 -0
  130. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/dispatch.py +0 -0
  131. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/error_responses.py +0 -0
  132. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/__init__.py +0 -0
  133. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/common.py +0 -0
  134. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/interrupt_queries.py +0 -0
  135. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/provider_discovery.py +0 -0
  136. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/session_control.py +0 -0
  137. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/session_lifecycle.py +0 -0
  138. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/session_queries.py +0 -0
  139. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/handlers/workspace_control.py +0 -0
  140. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/methods.py +0 -0
  141. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/jsonrpc/models.py +0 -0
  142. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/metadata_access.py +0 -0
  143. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/opencode_upstream_client.py +0 -0
  144. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/output_modes.py +0 -0
  145. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/parsing.py +0 -0
  146. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/parts/__init__.py +0 -0
  147. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/parts/mapping.py +0 -0
  148. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/parts/text.py +0 -0
  149. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/profile/__init__.py +0 -0
  150. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/profile/runtime.py +0 -0
  151. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/protocol_versions.py +0 -0
  152. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/py.typed +0 -0
  153. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/runtime_state.py +0 -0
  154. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/sandbox_policy.py +0 -0
  155. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/__init__.py +0 -0
  156. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/agent_card.py +0 -0
  157. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/application.py +0 -0
  158. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/client_manager.py +0 -0
  159. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/context_helpers.py +0 -0
  160. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/lifespan.py +0 -0
  161. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/middleware.py +0 -0
  162. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/migrations.py +0 -0
  163. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/request_parsing.py +0 -0
  164. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/rest_tasks.py +0 -0
  165. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/server/state_store.py +0 -0
  166. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/task_states.py +0 -0
  167. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/trace_context.py +0 -0
  168. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a/upstream_taxonomy.py +0 -0
  169. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/dependency_links.txt +0 -0
  170. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/entry_points.txt +0 -0
  171. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/requires.txt +0 -0
  172. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/src/opencode_a2a.egg-info/top_level.txt +0 -0
  173. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/__init__.py +0 -0
  174. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/__init__.py +0 -0
  175. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_agent_card.py +0 -0
  176. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_client_facade.py +0 -0
  177. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_polling.py +0 -0
  178. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/client/test_request_context.py +0 -0
  179. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/config/__init__.py +0 -0
  180. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/conftest.py +0 -0
  181. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/contracts/__init__.py +0 -0
  182. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/__init__.py +0 -0
  183. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_agent_errors.py +0 -0
  184. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_agent_helpers.py +0 -0
  185. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_cancellation.py +0 -0
  186. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_session_lock_lifecycle.py +0 -0
  187. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/execution/test_streaming_output_contract_blocks.py +0 -0
  188. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/__init__.py +0 -0
  189. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_error_responses.py +0 -0
  190. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/jsonrpc/test_jsonrpc_methods.py +0 -0
  191. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/package/__init__.py +0 -0
  192. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/package/test_logging.py +0 -0
  193. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/package/test_typing_contract.py +0 -0
  194. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/package/test_version.py +0 -0
  195. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/parts/__init__.py +0 -0
  196. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/parts/test_parts_text.py +0 -0
  197. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/profile/__init__.py +0 -0
  198. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/scripts/__init__.py +0 -0
  199. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/__init__.py +0 -0
  200. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_a2a_client_manager.py +0 -0
  201. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_call_context_builder.py +0 -0
  202. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_cancel_contract.py +0 -0
  203. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/server/test_output_negotiation.py +0 -0
  204. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/__init__.py +0 -0
  205. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/async_iterators.py +0 -0
  206. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/fake_client_errors.py +0 -0
  207. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/jsonrpc_error_assertions.py +0 -0
  208. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/support/session_extensions.py +0 -0
  209. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/test_metadata_access.py +0 -0
  210. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/test_trace_context.py +0 -0
  211. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/tests/upstream/__init__.py +0 -0
  212. {opencode_a2a-1.0.0 → opencode_a2a-1.1.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencode-a2a
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: OpenCode A2A runtime
5
5
  Author: liujuanjuan1984@Intelligent-Internet
6
6
  License-Expression: Apache-2.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 the shared and provider-private 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).
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:shared:session-binding:v1` | [Shared Session Binding v1](#shared-session-binding-v1) |
30
- | Shared Model Selection v1 | Shared request metadata | Public + extended | `urn:opencode-a2a:extension:shared:model-selection:v1` | [Shared Model Selection v1](#shared-model-selection-v1) |
31
- | Shared Stream Hints v1 | Shared response/stream metadata | Public + extended | `urn:opencode-a2a:extension:shared:stream-hints:v1` | [Shared Stream Hints v1](#shared-stream-hints-v1) |
32
- | Shared Interactive Interrupt v1 | Shared JSON-RPC callback methods | Public + extended | `urn:opencode-a2a:extension:shared:interactive-interrupt:v1` | [Shared Interactive Interrupt v1](#shared-interactive-interrupt-v1) |
33
- | OpenCode Session Management v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:private:session-management:v1` | [OpenCode Session Management v1](#opencode-session-management-v1) |
34
- | OpenCode Provider Discovery v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:private:provider-discovery:v1` | [OpenCode Provider Discovery v1](#opencode-provider-discovery-v1) |
35
- | OpenCode Workspace Control v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:private:workspace-control:v1` | [OpenCode Workspace Control v1](#opencode-workspace-control-v1) |
36
- | OpenCode Interrupt Recovery v1 | Provider-private JSON-RPC methods | Extended only | `urn:opencode-a2a:extension:private:interrupt-recovery:v1` | [OpenCode Interrupt Recovery v1](#opencode-interrupt-recovery-v1) |
37
- | A2A Compatibility Profile v1 | Authenticated discovery metadata | Extended only | `urn:opencode-a2a:extension:private:compatibility-profile:v1` | [A2A Compatibility Profile v1](#a2a-compatibility-profile-v1) |
38
- | A2A Wire Contract v1 | Authenticated discovery metadata | Extended only | `urn:opencode-a2a:extension:private:wire-contract:v1` | [A2A Wire Contract v1](#a2a-wire-contract-v1) |
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:shared:session-binding:v1`
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:shared:model-selection:v1`
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:shared:stream-hints:v1`
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
- - Runtime fields: `metadata.shared.stream`, `metadata.shared.progress`, `metadata.shared.usage`
73
- - Detailed-only correlation fields: `metadata.shared.stream.message_id` and `metadata.shared.stream.event_id` may be emitted for timeline stitching and diagnostics, but are not part of the minimum public consumer contract
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:shared:interactive-interrupt:v1`
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:private:session-management:v1`
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:private:provider-discovery:v1`
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:private:workspace-control:v1`
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:private:interrupt-recovery:v1`
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:private:compatibility-profile:v1`
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:private:wire-contract:v1`
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
- - `artifact.metadata.shared.stream.event_id` preserves the original cross-artifact stream timeline, even when different logical lanes use different artifact IDs.
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
- - 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`.
246
- - Progress metadata at `metadata.shared.progress` is emitted only when the client negotiated `urn:opencode-a2a:extension:shared:stream-hints:v1`; baseline streams do not emit duplicate generic `working` status updates just to carry progress hints.
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:shared:interactive-interrupt:v1`.
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:shared:session-binding:v1`
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:shared:model-selection:v1`
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:shared:stream-hints:v1`
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
- - block-level stream metadata such as `block_type`, `message_id`, `event_id`, and `sequence`
575
+ - declared shared v1 fields: `block_type` and `sequence`
575
576
  - `metadata.shared.usage`
576
- - normalized usage data such as `input_tokens`, `output_tokens`, `total_tokens`, optional `reasoning_tokens`, optional `cache_tokens.read_tokens` / `cache_tokens.write_tokens`, and optional `cost`
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
- - Treat `message_id` and `event_id` as optional advanced correlation fields rather than baseline consumer requirements.
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
- - `message_id` and `event_id` preserve stable timeline identity where possible and are emitted only as optional advanced correlation hints
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 normalized usage after the streaming phase ends
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", "http_json", "http-json", "httpjson", "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
- return value.strip()
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 _attach_http_status(
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 isinstance(items, (list, tuple)):
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 isinstance(parts, (list, tuple)):
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 isinstance(value, (list, tuple)) and key in (
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 isinstance(payload, (list, tuple)):
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
- status_payload = getattr(payload, "status", None)
114
- if status_payload is not None:
115
- text = extract_text(status_payload)
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
- artifact_payload = getattr(payload, "artifact", None)
126
- if artifact_payload is not None:
127
- text = extract_text(artifact_payload)
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 isinstance(history, (list, tuple)) and history:
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"),
@@ -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
- def _extension_uri(*segments: str) -> str:
20
- normalized_segments = [segment.strip("/") for segment in segments if segment.strip("/")]
21
- return f"{EXTENSION_URI_NAMESPACE}{':'.join(normalized_segments)}"
22
-
23
-
24
- SESSION_BINDING_EXTENSION_URI = _extension_uri(
25
- "shared",
26
- "session-binding",
27
- "v1",
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,