opencode-a2a 1.1.2__tar.gz → 1.3.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 (224) hide show
  1. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/.github/workflows/publish.yml +20 -1
  2. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/PKG-INFO +8 -5
  3. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/README.md +5 -2
  4. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/SECURITY.md +3 -0
  5. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/docs/architecture.md +1 -0
  6. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/docs/compatibility.md +6 -3
  7. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/docs/extension-specifications.md +1 -0
  8. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/docs/guide.md +71 -16
  9. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/docs/maintainer-architecture.md +7 -5
  10. opencode_a2a-1.3.0/docs/security-architecture.md +175 -0
  11. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/pyproject.toml +9 -2
  12. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/README.md +1 -0
  13. opencode_a2a-1.3.0/scripts/live_opencode_smoke.sh +286 -0
  14. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/auth.py +7 -2
  15. opencode_a2a-1.3.0/src/opencode_a2a/client/network_policy.py +155 -0
  16. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/config.py +55 -3
  17. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/extensions/catalog.py +9 -9
  18. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/executor.py +2 -0
  19. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/session_manager.py +74 -42
  20. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/application.py +72 -17
  21. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/error_responses.py +11 -7
  22. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/workspace_control.py +65 -7
  23. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/opencode_upstream_client.py +9 -1
  24. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/profile/runtime.py +5 -1
  25. opencode_a2a-1.3.0/src/opencode_a2a/redact.py +82 -0
  26. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/agent_card.py +1 -4
  27. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/application.py +99 -21
  28. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/client_manager.py +28 -2
  29. opencode_a2a-1.3.0/src/opencode_a2a/server/database.py +152 -0
  30. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/middleware.py +194 -4
  31. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/openapi.py +2 -2
  32. opencode_a2a-1.3.0/src/opencode_a2a/server/runtime_limits.py +199 -0
  33. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/task_store.py +1 -15
  34. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/task_store_sdk_compat.py +1 -21
  35. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a.egg-info/PKG-INFO +8 -5
  36. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a.egg-info/SOURCES.txt +12 -0
  37. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a.egg-info/requires.txt +1 -1
  38. opencode_a2a-1.3.0/tests/client/test_network_policy.py +210 -0
  39. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/config/test_settings.py +98 -0
  40. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/conftest.py +6 -16
  41. opencode_a2a-1.3.0/tests/execution/test_error_redaction.py +57 -0
  42. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_opencode_agent_session_binding.py +4 -0
  43. opencode_a2a-1.3.0/tests/execution/test_session_lock_lifecycle.py +68 -0
  44. opencode_a2a-1.3.0/tests/jsonrpc/test_error_redaction.py +116 -0
  45. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_opencode_session_extension_queries.py +7 -0
  46. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_opencode_workspace_control_extension.py +126 -5
  47. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/profile/test_profile_runtime.py +13 -0
  48. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_a2a_client_manager.py +128 -0
  49. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_agent_card.py +20 -3
  50. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_app_behaviors.py +11 -10
  51. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_call_context_builder.py +2 -2
  52. opencode_a2a-1.3.0/tests/server/test_database.py +219 -0
  53. opencode_a2a-1.3.0/tests/server/test_http_boundary.py +282 -0
  54. opencode_a2a-1.3.0/tests/server/test_runtime_limits.py +450 -0
  55. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_state_store.py +0 -26
  56. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_task_store_factory.py +2 -26
  57. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_transport_contract.py +33 -33
  58. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/session_query_client.py +6 -0
  59. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/workspace_control_client.py +50 -6
  60. opencode_a2a-1.3.0/tests/test_redact.py +89 -0
  61. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/upstream/test_opencode_upstream_client_params.py +92 -0
  62. opencode_a2a-1.3.0/uv.lock +1941 -0
  63. opencode_a2a-1.1.2/src/opencode_a2a/server/database.py +0 -62
  64. opencode_a2a-1.1.2/tests/execution/test_session_lock_lifecycle.py +0 -33
  65. opencode_a2a-1.1.2/uv.lock +0 -1644
  66. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/.github/dependabot.yml +0 -0
  67. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/.github/workflows/dependency-review.yml +0 -0
  68. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/.github/workflows/validate.yml +0 -0
  69. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/.gitignore +0 -0
  70. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/.pre-commit-config.yaml +0 -0
  71. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/.secrets.baseline +0 -0
  72. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/AGENTS.md +0 -0
  73. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/CODE_OF_CONDUCT.md +0 -0
  74. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/CONTRIBUTING.md +0 -0
  75. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/LICENSE +0 -0
  76. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/MANIFEST.in +0 -0
  77. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/SUPPORT.md +0 -0
  78. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/docs/conformance-triage.md +0 -0
  79. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/docs/conformance.md +0 -0
  80. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/check_coverage.py +0 -0
  81. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/conformance.sh +0 -0
  82. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/dependency_health.sh +0 -0
  83. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/doctor.sh +0 -0
  84. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/find_thin_wrappers.py +0 -0
  85. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/health_common.sh +0 -0
  86. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/lint.sh +0 -0
  87. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/scripts/smoke_test_built_cli.sh +0 -0
  88. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/setup.cfg +0 -0
  89. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/__init__.py +0 -0
  90. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/a2a_protocol.py +0 -0
  91. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/a2a_utils.py +0 -0
  92. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/cli.py +0 -0
  93. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/__init__.py +0 -0
  94. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/agent_card.py +0 -0
  95. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/auth.py +0 -0
  96. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/client.py +0 -0
  97. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/config.py +0 -0
  98. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/error_mapping.py +0 -0
  99. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/errors.py +0 -0
  100. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/payload_text.py +0 -0
  101. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/polling.py +0 -0
  102. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/client/request_context.py +0 -0
  103. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/__init__.py +0 -0
  104. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/extensions/__init__.py +0 -0
  105. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/extensions/capabilities.py +0 -0
  106. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/extensions/compatibility.py +0 -0
  107. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/extensions/contract_docs.py +0 -0
  108. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/extensions/identifiers.py +0 -0
  109. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/extensions/private_params.py +0 -0
  110. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/contracts/extensions/public_params.py +0 -0
  111. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/__init__.py +0 -0
  112. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/coordinator.py +0 -0
  113. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/event_helpers.py +0 -0
  114. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/metrics.py +0 -0
  115. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/stream_events.py +0 -0
  116. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/stream_runtime.py +0 -0
  117. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/stream_state.py +0 -0
  118. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/tool_error_mapping.py +0 -0
  119. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/tool_orchestration.py +0 -0
  120. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/execution/upstream_error_translator.py +0 -0
  121. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/extension_negotiation.py +0 -0
  122. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/interrupt_request_tracker.py +0 -0
  123. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/__init__.py +0 -0
  124. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/dispatch.py +0 -0
  125. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/__init__.py +0 -0
  126. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/common.py +0 -0
  127. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/interrupt_callbacks.py +0 -0
  128. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/interrupt_queries.py +0 -0
  129. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/provider_discovery.py +0 -0
  130. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/session_control.py +0 -0
  131. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/session_lifecycle.py +0 -0
  132. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/handlers/session_queries.py +0 -0
  133. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/methods.py +0 -0
  134. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/models.py +0 -0
  135. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/jsonrpc/params.py +0 -0
  136. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/metadata_access.py +0 -0
  137. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/output_modes.py +0 -0
  138. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/parsing.py +0 -0
  139. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/parts/__init__.py +0 -0
  140. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/parts/mapping.py +0 -0
  141. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/parts/text.py +0 -0
  142. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/profile/__init__.py +0 -0
  143. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/protocol_versions.py +0 -0
  144. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/py.typed +0 -0
  145. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/runtime_state.py +0 -0
  146. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/sandbox_policy.py +0 -0
  147. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/__init__.py +0 -0
  148. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/context_helpers.py +0 -0
  149. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/lifespan.py +0 -0
  150. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/migrations.py +0 -0
  151. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/request_parsing.py +0 -0
  152. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/rest_tasks.py +0 -0
  153. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/server/state_store.py +0 -0
  154. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/task_states.py +0 -0
  155. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/trace_context.py +0 -0
  156. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a/upstream_taxonomy.py +0 -0
  157. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a.egg-info/dependency_links.txt +0 -0
  158. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a.egg-info/entry_points.txt +0 -0
  159. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/src/opencode_a2a.egg-info/top_level.txt +0 -0
  160. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/__init__.py +0 -0
  161. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/client/__init__.py +0 -0
  162. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/client/test_agent_card.py +0 -0
  163. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/client/test_client_config.py +0 -0
  164. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/client/test_client_facade.py +0 -0
  165. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/client/test_error_mapping.py +0 -0
  166. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/client/test_payload_text.py +0 -0
  167. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/client/test_polling.py +0 -0
  168. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/client/test_request_context.py +0 -0
  169. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/config/__init__.py +0 -0
  170. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/contracts/__init__.py +0 -0
  171. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/contracts/test_extension_contract_consistency.py +0 -0
  172. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/__init__.py +0 -0
  173. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_agent_errors.py +0 -0
  174. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_agent_helpers.py +0 -0
  175. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_cancellation.py +0 -0
  176. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_directory_validation.py +0 -0
  177. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_metrics.py +0 -0
  178. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_multipart_input.py +0 -0
  179. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_session_ownership.py +0 -0
  180. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_streaming_output_contract_blocks.py +0 -0
  181. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_streaming_output_contract_core.py +0 -0
  182. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_streaming_output_contract_interrupts.py +0 -0
  183. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/execution/test_streaming_output_contract_logging.py +0 -0
  184. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/__init__.py +0 -0
  185. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_application_dispatch.py +0 -0
  186. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_dispatch_registry.py +0 -0
  187. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_error_responses.py +0 -0
  188. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_jsonrpc_methods.py +0 -0
  189. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_jsonrpc_params.py +0 -0
  190. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_jsonrpc_unsupported_method.py +0 -0
  191. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_opencode_session_extension_commands.py +0 -0
  192. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_opencode_session_extension_interrupts.py +0 -0
  193. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_opencode_session_extension_lifecycle.py +0 -0
  194. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/jsonrpc/test_opencode_session_extension_prompt_async.py +0 -0
  195. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/package/__init__.py +0 -0
  196. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/package/test_logging.py +0 -0
  197. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/package/test_typing_contract.py +0 -0
  198. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/package/test_version.py +0 -0
  199. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/parts/__init__.py +0 -0
  200. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/parts/test_parts_text.py +0 -0
  201. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/profile/__init__.py +0 -0
  202. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/scripts/__init__.py +0 -0
  203. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/scripts/test_script_health_contract.py +0 -0
  204. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/__init__.py +0 -0
  205. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_auth.py +0 -0
  206. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_cancel_contract.py +0 -0
  207. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_cli.py +0 -0
  208. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_context_helpers.py +0 -0
  209. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_database_app_persistence.py +0 -0
  210. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/server/test_output_negotiation.py +0 -0
  211. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/__init__.py +0 -0
  212. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/async_iterators.py +0 -0
  213. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/fake_client_errors.py +0 -0
  214. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/helpers.py +0 -0
  215. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/interrupt_clients.py +0 -0
  216. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/jsonrpc_error_assertions.py +0 -0
  217. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/session_extensions.py +0 -0
  218. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/settings.py +0 -0
  219. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/support/streaming_output.py +0 -0
  220. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/test_a2a_utils.py +0 -0
  221. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/test_metadata_access.py +0 -0
  222. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/test_parsing.py +0 -0
  223. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/test_trace_context.py +0 -0
  224. {opencode_a2a-1.1.2 → opencode_a2a-1.3.0}/tests/upstream/__init__.py +0 -0
@@ -146,11 +146,30 @@ jobs:
146
146
 
147
147
  ensure_release
148
148
 
149
+ python - <<'PY'
150
+ import hashlib
151
+ from pathlib import Path
152
+
153
+ dist_dir = Path("dist")
154
+ lines = []
155
+ for asset in sorted(
156
+ (
157
+ path
158
+ for path in dist_dir.iterdir()
159
+ if path.is_file() and path.name.endswith((".whl", ".tar.gz"))
160
+ ),
161
+ key=lambda item: item.name,
162
+ ):
163
+ digest = hashlib.sha256(asset.read_bytes()).hexdigest()
164
+ lines.append(f"{digest} {asset.name}")
165
+ (dist_dir / "SHA256SUMS").write_text("\n".join(lines) + "\n", encoding="utf-8")
166
+ PY
167
+
149
168
  mapfile -t existing_assets < <(
150
169
  retry 3 5 gh release view "$RELEASE_TAG" --json assets --jq '.assets[].name'
151
170
  )
152
171
 
153
- for asset in dist/*.tar.gz dist/*.whl; do
172
+ for asset in dist/*.tar.gz dist/*.whl dist/SHA256SUMS; do
154
173
  asset_name="$(basename "$asset")"
155
174
  if printf '%s\n' "${existing_assets[@]}" | grep -Fxq "$asset_name"; then
156
175
  echo "Release asset already present: $asset_name"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencode-a2a
3
- Version: 1.1.2
3
+ Version: 1.3.0
4
4
  Summary: OpenCode A2A runtime
5
5
  Author: liujuanjuan1984@Intelligent-Internet
6
6
  License-Expression: Apache-2.0
@@ -8,7 +8,7 @@ Project-URL: Homepage, https://github.com/Intelligent-Internet/opencode-a2a
8
8
  Project-URL: Repository, https://github.com/Intelligent-Internet/opencode-a2a
9
9
  Project-URL: Issues, https://github.com/Intelligent-Internet/opencode-a2a/issues
10
10
  Keywords: a2a,opencode,fastapi,json-rpc,sse
11
- Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Programming Language :: Python :: 3.11
@@ -19,7 +19,7 @@ Classifier: Topic :: Internet :: WWW/HTTP
19
19
  Requires-Python: >=3.11
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
- Requires-Dist: a2a-sdk==1.0.2
22
+ Requires-Dist: a2a-sdk==1.1.2
23
23
  Requires-Dist: aiosqlite<1.0,>=0.20
24
24
  Requires-Dist: fastapi<1.0,>=0.139
25
25
  Requires-Dist: httpx<1.0,>=0.27
@@ -133,9 +133,9 @@ curl http://127.0.0.1:8000/.well-known/agent-card.json
133
133
 
134
134
  ## Capabilities
135
135
 
136
- - A2A HTTP+JSON endpoints such as `/v1/message:send` and `/v1/message:stream`
136
+ - A2A HTTP+JSON endpoints such as `/message:send` and `/message:stream`
137
137
  - A2A JSON-RPC support on `POST /`
138
- - SDK-owned A2A task surfaces such as `GET /v1/tasks`, task push notification config routes, JSON-RPC `GetExtendedAgentCard`, and HTTP `GET /extendedAgentCard`
138
+ - SDK-owned A2A task surfaces such as `GET /tasks`, task push notification config routes, JSON-RPC `GetExtendedAgentCard`, and HTTP `GET /extendedAgentCard`
139
139
  - Peering capabilities: can act as a client via `opencode-a2a call`
140
140
  - Autonomous tool execution: supports `a2a_call` tool for outbound agent-to-agent communication
141
141
  - SSE streaming with normalized `text`, `reasoning`, and `tool_call` blocks
@@ -201,6 +201,8 @@ This repository improves the service boundary around OpenCode, but it does not t
201
201
  - Provider auth and default model configuration remain on the OpenCode side; deployment-time precedence details and HOME/XDG state impact are documented in [docs/guide.md](docs/guide.md#troubleshooting-provider-auth-state).
202
202
  - Use `A2A_CLIENT_BEARER_TOKEN` for server-side outbound peer calls initiated by `a2a_call`.
203
203
  - Deployment supervision is intentionally BYO. Use `systemd`, Docker, Kubernetes, or another supervisor if you need long-running operation.
204
+ - The supported persistence profile runs one `opencode-a2a` application process against its own local SQLite database. Do not run multiple Uvicorn workers or replicas against the same database file.
205
+ - PostgreSQL and other SQLAlchemy dialects are not part of the supported deployment matrix.
204
206
  - For mutually untrusted tenants, run separate instance pairs with isolated users, containers, workspaces, credentials, and ports.
205
207
 
206
208
  Read before deployment:
@@ -216,6 +218,7 @@ Read before deployment:
216
218
  - [docs/maintainer-architecture.md](docs/maintainer-architecture.md) Internal module boundaries and maintainer call chains.
217
219
  - [docs/compatibility.md](docs/compatibility.md) Compatibility-sensitive surface and contract-honesty guidance.
218
220
  - [docs/guide.md](docs/guide.md) Usage guide, transport details, streaming behavior, extensions, and examples.
221
+ - [docs/security-architecture.md](docs/security-architecture.md) Security surface, boundaries, and residual-risk register.
219
222
  - [docs/conformance.md](docs/conformance.md) External TCK experiment workflow and artifact handling.
220
223
  - [SECURITY.md](SECURITY.md) Threat model, deployment caveats, and vulnerability disclosure guidance.
221
224
 
@@ -91,9 +91,9 @@ curl http://127.0.0.1:8000/.well-known/agent-card.json
91
91
 
92
92
  ## Capabilities
93
93
 
94
- - A2A HTTP+JSON endpoints such as `/v1/message:send` and `/v1/message:stream`
94
+ - A2A HTTP+JSON endpoints such as `/message:send` and `/message:stream`
95
95
  - A2A JSON-RPC support on `POST /`
96
- - SDK-owned A2A task surfaces such as `GET /v1/tasks`, task push notification config routes, JSON-RPC `GetExtendedAgentCard`, and HTTP `GET /extendedAgentCard`
96
+ - SDK-owned A2A task surfaces such as `GET /tasks`, task push notification config routes, JSON-RPC `GetExtendedAgentCard`, and HTTP `GET /extendedAgentCard`
97
97
  - Peering capabilities: can act as a client via `opencode-a2a call`
98
98
  - Autonomous tool execution: supports `a2a_call` tool for outbound agent-to-agent communication
99
99
  - SSE streaming with normalized `text`, `reasoning`, and `tool_call` blocks
@@ -159,6 +159,8 @@ This repository improves the service boundary around OpenCode, but it does not t
159
159
  - Provider auth and default model configuration remain on the OpenCode side; deployment-time precedence details and HOME/XDG state impact are documented in [docs/guide.md](docs/guide.md#troubleshooting-provider-auth-state).
160
160
  - Use `A2A_CLIENT_BEARER_TOKEN` for server-side outbound peer calls initiated by `a2a_call`.
161
161
  - Deployment supervision is intentionally BYO. Use `systemd`, Docker, Kubernetes, or another supervisor if you need long-running operation.
162
+ - The supported persistence profile runs one `opencode-a2a` application process against its own local SQLite database. Do not run multiple Uvicorn workers or replicas against the same database file.
163
+ - PostgreSQL and other SQLAlchemy dialects are not part of the supported deployment matrix.
162
164
  - For mutually untrusted tenants, run separate instance pairs with isolated users, containers, workspaces, credentials, and ports.
163
165
 
164
166
  Read before deployment:
@@ -174,6 +176,7 @@ Read before deployment:
174
176
  - [docs/maintainer-architecture.md](docs/maintainer-architecture.md) Internal module boundaries and maintainer call chains.
175
177
  - [docs/compatibility.md](docs/compatibility.md) Compatibility-sensitive surface and contract-honesty guidance.
176
178
  - [docs/guide.md](docs/guide.md) Usage guide, transport details, streaming behavior, extensions, and examples.
179
+ - [docs/security-architecture.md](docs/security-architecture.md) Security surface, boundaries, and residual-risk register.
177
180
  - [docs/conformance.md](docs/conformance.md) External TCK experiment workflow and artifact handling.
178
181
  - [SECURITY.md](SECURITY.md) Threat model, deployment caveats, and vulnerability disclosure guidance.
179
182
 
@@ -24,6 +24,9 @@ This project is currently best suited for trusted or internal environments. Impo
24
24
  - static credential auth only by default; stronger identity propagation is still a follow-up hardening area
25
25
  - operators remain responsible for host hardening, secret rotation, process access controls, and reverse-proxy exposure strategy
26
26
 
27
+ For the security surface mapping and residual-risk register, see
28
+ [docs/security-architecture.md](./docs/security-architecture.md).
29
+
27
30
  ## Reporting a Vulnerability
28
31
 
29
32
  Please avoid posting active secrets, bearer tokens, or reproduction payloads that contain private data in public issues.
@@ -96,6 +96,7 @@ Use the docs by responsibility:
96
96
  - [Usage Guide](guide.md): runtime configuration, transport contracts, extensions, and examples
97
97
  - [Maintainer Architecture Guide](maintainer-architecture.md): internal module boundaries, request call chains, and persistence touchpoints
98
98
  - [Extension Specifications](extension-specifications.md): stable extension URI/spec index and disclosure policy
99
+ - [Security Architecture](security-architecture.md): security surface mapping and residual-risk register
99
100
  - [Conformance Notes](conformance.md): external TCK experiment workflow
100
101
  - [Contributing Guide](../CONTRIBUTING.md): contributor workflow and validation
101
102
  - [Security Policy](../SECURITY.md): threat model and disclosure guidance
@@ -7,6 +7,9 @@ This document defines the compatibility promises `opencode-a2a` currently uphold
7
7
  - Python versions: 3.11, 3.12, 3.13
8
8
  - A2A SDK line: `1.x.y`
9
9
  - Supported A2A protocol line: `1.0`
10
+ - OpenCode runtime line: `1.18.x` (verified with `1.18.19`)
11
+
12
+ This is the single canonical place where the supported upstream OpenCode version line is declared. Keep it updated together with the live integration smoke check (`./scripts/live_opencode_smoke.sh`) and do not duplicate the version line elsewhere.
10
13
 
11
14
  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
15
 
@@ -41,7 +44,7 @@ External TCK runs and local conformance experiments are investigation inputs. Th
41
44
 
42
45
  ## Compatibility-Sensitive Surface
43
46
 
44
- This repository still ships as an alpha project. Within that alpha line, these declared surfaces should not drift silently:
47
+ This repository ships as a beta project. Its documented public contracts are intended to remain stable, while implementation details and explicitly provider-private surfaces may continue to evolve. These declared surfaces should not drift silently:
45
48
 
46
49
  - core A2A send / stream / task methods
47
50
  - v1-only request/response payloads and enum values
@@ -88,7 +91,7 @@ Task-store behavior that should remain stable for clients:
88
91
  - accepted output-mode negotiation for a task is persisted with the task so later reads keep the same filtered output contract
89
92
  - adapter-managed migrations only own adapter state tables; SDK-managed task schema remains SDK-owned
90
93
 
91
- The default SQLite-first profile is intended for local or controlled single-instance deployments. Wider SQLAlchemy dialect compatibility should be treated as implementation latitude rather than a strong public promise unless explicitly documented later.
94
+ The supported persistence profile is one application process using its own local SQLite database. Multiple Uvicorn workers or application replicas must not share that SQLite file. PostgreSQL and other SQLAlchemy dialects are not supported deployment targets; any apparent dialect compatibility is implementation latitude rather than a public promise.
92
95
 
93
96
  ## Extension Stability
94
97
 
@@ -97,7 +100,7 @@ The default SQLite-first profile is intended for local or controlled single-inst
97
100
  - Deployment-conditional methods must be declared as conditional rather than silently disappearing.
98
101
  - `opencode.sessions.prompt_async` input-part passthrough is compatibility-sensitive. Changes to supported part types, passthrough field semantics, or rejection behavior should be treated as wire-level changes.
99
102
  - `opencode.sessions.shell` is compatibility-sensitive as a deployment-conditional shell snapshot surface. It should not silently widen into a general interactive shell API.
100
- - `opencode.workspaces.*` and `opencode.worktrees.*` are boundary-sensitive and should remain explicitly provider-private, operator-scoped, and deployment-conditional where applicable.
103
+ - `opencode.workspaces.*` and `opencode.worktrees.*` are boundary-sensitive and should remain explicitly provider-private, operator-scoped, and deployment-conditional where applicable. Discovery responses are normalized summaries that exclude upstream local paths (`directory`, `canonical`, worktree paths) and raw/internal fields.
101
104
  - Interrupt callback and recovery methods are compatibility-sensitive because clients may depend on request ID lifecycle, expiry semantics, and identity scoping.
102
105
  - Agent Card media modes and `acceptedOutputModes` handling are compatibility-sensitive. Changes to declared chat modes, to task-scoped negotiation persistence, or to output filtering of structured tool payloads should be treated as wire-level changes.
103
106
  - Agent Card and OpenAPI publication of `protocol_compatibility`, `service_behaviors`, and runtime feature toggles is compatibility-sensitive discoverability surface.
@@ -130,6 +130,7 @@ Extension URI: `urn:opencode-a2a:extension:workspace-control:v1`
130
130
  - Methods: stable project discovery plus experimental workspace/worktree discovery and deployment-conditional mutation methods
131
131
  - Dependencies: none declared by this version
132
132
  - Security boundary: this extension is provider-private, operator-scoped, and partly deployment-conditional
133
+ - Response hygiene: discovery responses are normalized summaries; upstream local paths (`directory`, `canonical`, worktree paths), raw entries, and credential-like fields are excluded
133
134
  - Versioning: breaking changes require a new versioned URI
134
135
 
135
136
  ## OpenCode Interrupt Recovery v1
@@ -5,9 +5,11 @@ This guide covers configuration, authentication, API behavior, streaming re-subs
5
5
  ## Transport Contracts
6
6
 
7
7
  - The service supports both transports:
8
- - HTTP+JSON (REST endpoints such as `/v1/message:send`)
8
+ - HTTP+JSON (REST endpoints such as `/message:send`)
9
9
  - JSON-RPC (`POST /`)
10
10
  - Agent Card exposes both HTTP+JSON and JSON-RPC through `supportedInterfaces`.
11
+ - HTTP+JSON REST endpoints are served at the root path (e.g. `/message:send`, `/tasks`). A2A 1.0 negotiates protocol version via the `A2A-Version` header, not a URL prefix, so the URL path carries no version segment.
12
+ - Breaking change for earlier releases: versions through v1.1.2 served the HTTP+JSON surface under a `/v1` prefix. Deployments upgrading from those releases must repoint clients, reverse proxies, and any `/v1`-prefixed routes to the root paths.
11
13
  - The public Agent Card is intentionally slimmed to the minimum discovery surface; per-extension disclosure policy is defined in [`extension-specifications.md`](./extension-specifications.md).
12
14
  - Detailed provider-private contracts are served through the authenticated extended card endpoint `/extendedAgentCard`.
13
15
  - Agent Card responses emit weak `ETag` and `Cache-Control`; clients should revalidate cached cards instead of repeatedly fetching full payloads.
@@ -30,12 +32,15 @@ Key variables to understand protocol behavior:
30
32
  - `A2A_ALLOW_DIRECTORY_OVERRIDE`: controls whether clients may pass `metadata.opencode.directory`.
31
33
  - `A2A_ENABLE_SESSION_SHELL`: gates high-risk JSON-RPC method `opencode.sessions.shell`.
32
34
  - `A2A_ENABLE_WORKSPACE_MUTATIONS`: gates operator-only workspace/worktree mutation methods such as `opencode.workspaces.create` and `opencode.worktrees.reset`.
35
+ - `A2A_EXPOSE_WORKSPACE_ROOT_IN_CARD`: default `false`; controls whether the authenticated extended Agent Card includes the local `OPENCODE_WORKSPACE_ROOT` in the structured profile `runtime_context`. Keep disabled unless trusted callers explicitly need the host path.
33
36
  - `A2A_SANDBOX_MODE` / `A2A_SANDBOX_FILESYSTEM_SCOPE` / `A2A_SANDBOX_WRITABLE_ROOTS`: declarative execution-boundary metadata for sandbox mode, filesystem scope, and optional writable roots.
34
37
  - `A2A_NETWORK_ACCESS` / `A2A_NETWORK_ALLOWED_DOMAINS`: declarative execution-boundary metadata for network policy and optional allowlist disclosure.
35
38
  - `A2A_APPROVAL_POLICY` / `A2A_APPROVAL_ESCALATION_BEHAVIOR`: declarative execution-boundary metadata for approval workflow.
36
39
  - `A2A_WRITE_ACCESS_SCOPE` / `A2A_WRITE_ACCESS_OUTSIDE_WORKSPACE`: declarative execution-boundary metadata for write scope and whether writes may extend outside the primary workspace boundary.
37
40
  - `A2A_HOST` / `A2A_PORT`: runtime bind address. Defaults: `127.0.0.1:8000`.
38
41
  - `A2A_PUBLIC_URL`: public base URL advertised by the Agent Card. Default: `http://127.0.0.1:8000`.
42
+ - `A2A_ALLOWED_ORIGINS`: comma-separated extra browser-origin allowlist for inbound requests. Requests carrying an `Origin` header must match the origin of `A2A_PUBLIC_URL` or an entry here; mismatches are rejected with `403` (CSRF guard). Requests without an `Origin` header (CLI/SDK clients) are unaffected.
43
+ - `A2A_ALLOWED_HOSTS`: comma-separated `Host` header allowlist (exact names or `*.example.com` wildcards). When configured, every inbound request must present a matching `Host` header. Binding to a non-loopback address without this allowlist logs a startup warning (DNS rebinding risk).
39
44
  - `A2A_LOG_LEVEL`: runtime log level. Default: `WARNING`.
40
45
  - `A2A_LOG_PAYLOADS` / `A2A_LOG_BODY_LIMIT`: payload logging behavior and truncation. When `A2A_LOG_LEVEL=DEBUG`, upstream OpenCode stream events are also logged with preview truncation controlled by `A2A_LOG_BODY_LIMIT`.
41
46
  - The runtime accepts W3C `traceparent` / `tracestate` headers on inbound requests. When `traceparent` is missing or invalid, the runtime generates a fresh valid value and exposes it on the HTTP response header.
@@ -43,19 +48,24 @@ Key variables to understand protocol behavior:
43
48
  - Logs derive a stable `trace_id` from the active `traceparent` so request-scoped log lines can be correlated without introducing high-cardinality metric labels.
44
49
  - `A2A_HTTP_GZIP_MINIMUM_SIZE`: minimum eligible response-body size in bytes for global non-streaming HTTP gzip compression. Default: `8192`.
45
50
  - `A2A_MAX_REQUEST_BODY_BYTES`: runtime request-body limit. Oversized requests return HTTP `413`.
51
+ - `A2A_RATE_LIMIT_ENABLED` / `A2A_RATE_LIMIT_WINDOW_SECONDS` / `A2A_RATE_LIMIT_MAX_REQUESTS`: per-credential sliding-window rate limiting (per-peer-IP for the unauthenticated Agent Card surface). Defaults: `true` / `60` seconds / `120` requests. Exceeding the window returns HTTP `429` with a `Retry-After` header; `A2A_RATE_LIMIT_ENABLED=false` disables the limiter.
52
+ - `A2A_STREAM_MAX_BYTES` / `A2A_STREAM_MAX_DURATION_SECONDS` / `A2A_STREAM_IDLE_TIMEOUT_SECONDS`: streaming (SSE) response budgets for total bytes, total duration, and idle gap. Defaults: `67108864` bytes / `3600` seconds / `120` seconds; `0` disables the respective budget.
46
53
  - `A2A_PENDING_SESSION_CLAIM_TTL_SECONDS`: lease duration for pending preferred session claims before they expire and stop blocking other identities.
47
54
  - `A2A_INTERRUPT_REQUEST_TTL_SECONDS`: active retention window for the interrupt request binding registry used by `a2a.interrupt.*` callback methods. Default: `10800` seconds (`180` minutes).
48
55
  - `A2A_INTERRUPT_REQUEST_TOMBSTONE_TTL_SECONDS`: retention window for expired interrupt tombstones after active TTL has elapsed. During this window, repeated replies keep returning `INTERRUPT_REQUEST_EXPIRED` instead of falling through to `INTERRUPT_REQUEST_NOT_FOUND`. Default: `600` seconds (`10` minutes).
49
56
  - `A2A_CANCEL_ABORT_TIMEOUT_SECONDS`: best-effort timeout for upstream `session.abort` in cancel flow.
50
- - `OPENCODE_TIMEOUT` / `OPENCODE_TIMEOUT_STREAM`: upstream request timeout and optional stream timeout override.
51
- - `OPENCODE_MAX_CONCURRENT_REQUESTS`: optional fast-fail concurrency limit for unary/control upstream calls. `0` disables the limit.
52
- - `OPENCODE_MAX_CONCURRENT_STREAMS`: optional fast-fail concurrency limit for long-lived upstream `/event` streams. `0` disables the limit.
57
+ - `OPENCODE_TIMEOUT` / `OPENCODE_TIMEOUT_STREAM`: upstream request timeout and stream timeout. Defaults: `120` and `900` seconds.
58
+ - `OPENCODE_MAX_CONCURRENT_REQUESTS`: fast-fail concurrency limit for unary/control upstream calls. Default: `32`; `0` disables the limit explicitly.
59
+ - `OPENCODE_MAX_CONCURRENT_STREAMS`: fast-fail concurrency limit for long-lived upstream `/event` streams. Default: `8`; `0` disables the limit explicitly.
60
+ - `OPENCODE_AUTH_USERNAME` / `OPENCODE_AUTH_PASSWORD`: optional HTTP Basic credentials sent on every upstream OpenCode call. Set both when the upstream `opencode serve` is hardened with `OPENCODE_SERVER_PASSWORD`; the username defaults to `opencode` and must match `OPENCODE_SERVER_USERNAME` when that is overridden upstream. When unset, no `Authorization` header is sent.
53
61
  - `A2A_CLIENT_TIMEOUT_SECONDS`: outbound client timeout. Default: `30` seconds.
54
62
  - `A2A_CLIENT_CARD_FETCH_TIMEOUT_SECONDS`: outbound Agent Card fetch timeout. Default: `5` seconds.
55
63
  - `A2A_CLIENT_USE_CLIENT_PREFERENCE`: whether the outbound client prefers its own transport choices.
56
64
  - `A2A_CLIENT_BEARER_TOKEN`: optional bearer token attached to outbound peer calls made by the embedded A2A client and `a2a_call` tool path.
57
65
  - `A2A_CLIENT_BASIC_AUTH`: optional Basic auth credential attached to outbound peer calls made by the embedded A2A client and `a2a_call` tool path.
58
66
  - `A2A_CLIENT_SUPPORTED_TRANSPORTS`: ordered outbound transport preference list.
67
+ - `A2A_CLIENT_ALLOWED_HOSTS`: comma-separated allowlist of outbound target hosts for the embedded A2A client and `a2a_call` tool path (exact names or `*.example.com` wildcards). When configured, outbound calls are restricted to matching hosts, and outbound credentials (`A2A_CLIENT_BEARER_TOKEN` / `A2A_CLIENT_BASIC_AUTH`) are only sent to allowlisted hosts.
68
+ - `A2A_CLIENT_ALLOW_PRIVATE_HOSTS`: default `false`. When `false`, outbound `a2a_call(...)` targets that resolve to private, loopback, link-local, reserved, or multicast addresses are rejected (SSRF / DNS-rebinding guard). Set to `true` only when the deployment intentionally targets A2A peers on the local network.
59
69
  - `A2A_TASK_STORE_BACKEND`: unified lightweight persistence backend for SDK task rows plus adapter-managed session / interrupt state. Supported values: `database`, `memory`. Default: `database`.
60
70
  - `A2A_TASK_STORE_DATABASE_URL`: database URL used by the unified durable backend when `A2A_TASK_STORE_BACKEND=database`. Default: `sqlite+aiosqlite:///./opencode-a2a.db`.
61
71
  - On startup, the runtime only auto-migrates adapter-owned state tables; existing SDK-owned task tables must be upgraded explicitly with upstream `a2a-db`.
@@ -81,6 +91,20 @@ Key variables to understand protocol behavior:
81
91
  - `A2A_CLIENT_BASIC_AUTH`
82
92
  - `A2A_CLIENT_SUPPORTED_TRANSPORTS`
83
93
 
94
+ ## Inbound Origin and Host Boundary
95
+
96
+ Browsers store and automatically attach Basic credentials, and they send an `Origin` header with every request. Without an origin boundary, a malicious web page could cross-site trigger `SendMessage`, `CancelTask`, or task subscription against a Basic-protected service. The runtime therefore enforces:
97
+
98
+ - every request carrying an `Origin` header must match the origin of `A2A_PUBLIC_URL` (scheme, host, and non-default port) or an entry in `A2A_ALLOWED_ORIGINS`; mismatches return `403` before authentication. `Origin: null` (sandboxed iframes) is rejected unless explicitly allowlisted;
99
+ - requests without an `Origin` header — normal CLI/SDK peers — are not subject to origin checks;
100
+ - when `A2A_ALLOWED_HOSTS` is configured, every request must present a matching `Host` header (exact names, optional `host:port`, or `*.example.com` wildcards); mismatches return `403`. This also blocks DNS rebinding, where an attacker-controlled hostname resolves to the service address and the browser sends that hostname as `Host`;
101
+ - binding to a non-loopback address (`0.0.0.0`, `::`, or a LAN/interface address) without `A2A_ALLOWED_HOSTS` logs a startup warning: the service is then exposed to DNS rebinding and should only run behind a trusted network boundary or a reverse proxy that validates `Host`.
102
+
103
+ For browser-based clients, prefer the same origin as `A2A_PUBLIC_URL`, or explicitly allow the dashboard origin via `A2A_ALLOWED_ORIGINS` and treat `A2A_ALLOWED_HOSTS` as part of the deployment contract. Basic authentication should not be relied on as the sole browser-facing boundary: combine it with the origin/host checks above, short-lived credentials, and TLS at the public URL.
104
+
105
+ The security surface mapping and residual-risk register live in
106
+ [security-architecture.md](./security-architecture.md).
107
+
84
108
  ## Client Initialization Facade (Preview)
85
109
 
86
110
  `opencode-a2a` now includes a minimal client bootstrap module in `src/opencode_a2a/client/` to support downstream consumer usage while keeping server and client concerns separate.
@@ -100,6 +124,14 @@ Current client facade API:
100
124
 
101
125
  Server-side outbound peer calls read outbound credentials from environment variables. Configure `A2A_CLIENT_BEARER_TOKEN` or `A2A_CLIENT_BASIC_AUTH` when the remote agent protects its runtime surface. CLI outbound calls follow the same environment-only model.
102
126
 
127
+ The embedded `a2a_call(...)` tool lets the upstream model choose the target URL, so the adapter applies a fail-closed network policy before opening any connection:
128
+
129
+ - only `http`/`https` schemes are accepted, and URLs carrying userinfo credentials are rejected;
130
+ - when `A2A_CLIENT_ALLOWED_HOSTS` is set, the target host must match the allowlist (exact or `*.example.com` wildcard);
131
+ - unless `A2A_CLIENT_ALLOW_PRIVATE_HOSTS=true`, the resolved addresses must be public; private/loopback/link-local/reserved addresses are rejected even when the hostname matches the allowlist (DNS rebinding defense);
132
+ - outbound credentials are only attached to allowlisted hosts. If credentials are configured without an allowlist, they are never sent and a warning is logged;
133
+ - the `opencode-a2a call` CLI remains a manual operator action and is not subject to the allowlist, but still rejects non-http(s) schemes through the shared client URL handling.
134
+
103
135
  CLI outbound example:
104
136
 
105
137
  ```bash
@@ -174,11 +206,31 @@ With the default `database` backend, the unified lightweight persistence layer p
174
206
  - pending preferred-session claims
175
207
  - interrupt request bindings and tombstones
176
208
 
177
- This project is SQLite-first for local single-instance deployments. The runtime configures local durability-oriented SQLite connection settings (`WAL`, `busy_timeout`, `synchronous=NORMAL`) and creates missing parent directories for file-backed database paths.
209
+ The supported persistence profile is one `opencode-a2a` application process using its own local SQLite database. Run Uvicorn with one worker and do not share the SQLite file between processes, containers, or replicas. Horizontal application scaling and PostgreSQL deployments are outside the supported deployment matrix. SQLAlchemy remains an internal implementation detail rather than a promise of dialect portability.
210
+
211
+ The runtime configures local durability-oriented SQLite connection settings (`WAL`, `busy_timeout`, `synchronous=NORMAL`) and creates missing parent directories for file-backed database paths.
212
+
213
+ ### SQLite Persistence Hardening
214
+
215
+ File-backed SQLite databases are hardened at startup and on every new connection on POSIX systems:
216
+
217
+ - the database file must be a regular file; symlinks are rejected and fail startup;
218
+ - the file must be owned by the user running `opencode-a2a`; a database owned by another user fails startup;
219
+ - the database file is forced to mode `0600`, and existing SQLite sidecar files (`-wal`/`-shm`/`-journal`) are converged to the same mode;
220
+ - the parent directory is created with mode `0700` when it does not exist; keep the database directory private (no group/world access);
221
+ - if the database is replaced by a symlink, a special file, or a foreign-owned file while the service is running, the next connection fails closed.
222
+
223
+ `A2A_TASK_STORE_DATABASE_URL` values that do not map to a plain file path are exempt: `:memory:` and `file:` URI-style database components (including in-memory shared-cache databases) are not hardened. Prefer a plain absolute file path for deployments that need the startup guarantees. Non-POSIX platforms rely on the user account ACLs of the hosting directory; the same private-directory requirement applies there.
224
+
225
+ Deployment requirements:
226
+
227
+ - run `opencode-a2a` as a dedicated user and keep the database directory outside world-readable workspace trees;
228
+ - do not place the SQLite file on network-mounted or sync-managed directories;
229
+ - when migrating an existing database, fix ownership and mode before startup: `chown <service-user> <db>` and `chmod 600 <db>`, and ensure the parent directory is not group/world accessible.
178
230
 
179
231
  The runtime automatically applies lightweight schema migrations for its custom state tables and records the applied version in `a2a_schema_version`. Schema-version writes are idempotent across concurrent first-start races, pending preferred-session claims now persist absolute `expires_at` timestamps, legacy rows without `expires_at` are pruned during migration instead of being reconstructed from historical TTL assumptions, and the built-in path currently targets the local SQLite deployment profile without requiring Alembic.
180
232
 
181
- Database-backed task persistence also keeps the existing first-terminal-state-wins contract while tightening the SQLite path with an atomic terminal-write guard instead of relying only on process-local read-before-write checks. Any wider SQLAlchemy dialect compatibility should be treated as incidental implementation latitude rather than a documented deployment target.
233
+ Database-backed task persistence also keeps the existing first-terminal-state-wins contract while tightening the SQLite path with an atomic terminal-write guard instead of relying only on process-local read-before-write checks.
182
234
 
183
235
  At startup, the runtime logs a concise persistence summary covering the active backend, the redacted database URL when applicable, the shared persistence scope, and whether the SQLite local durability profile is active.
184
236
 
@@ -223,7 +275,7 @@ If one deployment works while another fails against the same upstream provider,
223
275
  ## Streaming Contract
224
276
 
225
277
  - Streaming is always enabled in this server profile; `message:stream` is part of the stable runtime baseline.
226
- - Streaming (`/v1/message:stream`) emits an initial working `Task`, then incremental `TaskArtifactUpdateEvent` / `TaskStatusUpdateEvent` updates, and finally a terminal `TaskStatusUpdateEvent(final=true)`.
278
+ - Streaming (`/message:stream`) emits an initial working `Task`, then incremental `TaskArtifactUpdateEvent` / `TaskStatusUpdateEvent` updates, and finally a terminal `TaskStatusUpdateEvent(final=true)`.
227
279
  - Stream artifacts carry `artifact.metadata.shared.stream.block_type` with values `text` / `reasoning` / `tool_call`.
228
280
  - Stream artifacts are scoped to logical output lanes rather than one shared catch-all artifact:
229
281
  - text chunks use a stable text artifact ID
@@ -255,6 +307,8 @@ If one deployment works while another fails against the same upstream provider,
255
307
 
256
308
  - Requests require either `Authorization: Bearer <token>` or a configured `Authorization: Basic <base64(username:password)>`; otherwise `401` is returned. Agent Card endpoints are public.
257
309
  - Requests above `A2A_MAX_REQUEST_BODY_BYTES` are rejected with HTTP `413` before transport handling.
310
+ - Inbound requests are rate limited with a sliding window keyed by `credential_id` when configured, otherwise by the authenticated principal; the public Agent Card surface is keyed by the direct peer IP (never `X-Forwarded-For`). Exceeding `A2A_RATE_LIMIT_MAX_REQUESTS` within `A2A_RATE_LIMIT_WINDOW_SECONDS` returns HTTP `429` with a `Retry-After` header. The limiter is process-local; multi-process deployments should place a shared gateway in front or rely on per-instance limits.
311
+ - Streaming responses (JSON-RPC `SendStreamingMessage` / `SubscribeToTask` and REST `/message:stream` / `/tasks/{id}:subscribe`) are bounded by `A2A_STREAM_MAX_BYTES`, `A2A_STREAM_MAX_DURATION_SECONDS`, and `A2A_STREAM_IDLE_TIMEOUT_SECONDS`; when a budget is exceeded the server ends the stream with an SSE `event: error` frame. If the very first event already exceeds the budget, REST requests are rejected with HTTP `429` `RESOURCE_EXHAUSTED` before the SSE stream starts.
258
312
  - For validation failures, missing context (`task_id` / `context_id`), or internal errors, the service attempts to return standard A2A failure events via `event_queue`.
259
313
  - Failure events include concrete error details with `failed` state.
260
314
 
@@ -285,7 +339,7 @@ Current behavior:
285
339
  - Shared metadata extension URIs such as session binding and streaming are listed under `extensions.extension_uris`.
286
340
  - `all_jsonrpc_methods` is the runtime truth for the current deployment.
287
341
  - The current SDK-owned core JSON-RPC surface includes `GetExtendedAgentCard` and `tasks/pushNotificationConfig/*`.
288
- - The current SDK-owned REST surface also includes `GET /v1/tasks` and the task push notification config routes.
342
+ - The current SDK-owned REST surface also includes `GET /tasks` and the task push notification config routes.
289
343
  - 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.
290
344
  - 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.
291
345
 
@@ -483,7 +537,7 @@ Consumer guidance:
483
537
  Minimal example:
484
538
 
485
539
  ```bash
486
- curl -sS http://127.0.0.1:8000/v1/message:send \
540
+ curl -sS http://127.0.0.1:8000/message:send \
487
541
  -H 'content-type: application/json' \
488
542
  -H 'Authorization: Bearer <your-token>' \
489
543
  -d '{
@@ -535,7 +589,7 @@ Consumer guidance:
535
589
  Minimal example:
536
590
 
537
591
  ```bash
538
- curl -sS http://127.0.0.1:8000/v1/message:send \
592
+ curl -sS http://127.0.0.1:8000/message:send \
539
593
  -H 'content-type: application/json' \
540
594
  -H 'Authorization: Bearer <your-token>' \
541
595
  -d '{
@@ -1034,6 +1088,7 @@ Behavior notes:
1034
1088
  - `metadata.opencode.workspace.id` is declared consistently across the adapter, but current workspace-control methods do not use it to change the target project.
1035
1089
  - `opencode.workspaces.*` and `opencode.worktrees.*` currently wrap upstream `/experimental/workspace` and `/experimental/worktree` endpoints; treat them as experimental-upstream surfaces even when declared by the adapter.
1036
1090
  - Mutating methods should be treated as operator-only control-plane actions and are disabled by default.
1091
+ - Discovery responses are normalized provider-private summaries: upstream entries are filtered to stable fields only (`id`/`name`/`vcs` for projects, `id`/`type`/`name`/`branch` for workspaces, `name`/`branch` for worktrees) and never include upstream local paths (`directory`, `canonical`, worktree paths), raw entries, or credential-like fields.
1037
1092
 
1038
1093
  ### Project Discovery (`opencode.projects.list`, `opencode.projects.current`)
1039
1094
 
@@ -1051,8 +1106,8 @@ curl -sS http://127.0.0.1:8000/ \
1051
1106
 
1052
1107
  Response:
1053
1108
 
1054
- - `opencode.projects.list` => `{"items": [...]}`
1055
- - `opencode.projects.current` => `{"item": {...}}`
1109
+ - `opencode.projects.list` => `{"items": [{"id": "<id>", "name": "<name>", "vcs": "<vcs>"}]}` (normalized summaries; no local paths)
1110
+ - `opencode.projects.current` => `{"item": {"id": "<id>", "name": "<name>", "vcs": "<vcs>"}}` (normalized summary; no local paths)
1056
1111
 
1057
1112
  ### Workspace Discovery
1058
1113
 
@@ -1070,7 +1125,7 @@ curl -sS http://127.0.0.1:8000/ \
1070
1125
 
1071
1126
  Response:
1072
1127
 
1073
- - `opencode.workspaces.list` => `{"items": [...]}`
1128
+ - `opencode.workspaces.list` => `{"items": [{"id": "<id>", "type": "<type>", "name": "<name>", "branch": "<branch>"}]}` (normalized summaries; no local paths)
1074
1129
 
1075
1130
  ### Workspace Mutation
1076
1131
 
@@ -1222,7 +1277,7 @@ curl -sS http://127.0.0.1:8000/ \
1222
1277
  ## Authentication Example (curl)
1223
1278
 
1224
1279
  ```bash
1225
- curl -sS http://127.0.0.1:8000/v1/message:send \
1280
+ curl -sS http://127.0.0.1:8000/message:send \
1226
1281
  -H 'content-type: application/json' \
1227
1282
  -H 'Authorization: Bearer <your-token>' \
1228
1283
  -d '{
@@ -1256,7 +1311,7 @@ curl -sS http://127.0.0.1:8000/ \
1256
1311
 
1257
1312
  ## Streaming Re-Subscription (`SubscribeToTask`)
1258
1313
 
1259
- If an SSE connection drops, use `GET /v1/tasks/{task_id}:subscribe` to re-subscribe while the task is still non-terminal.
1314
+ If an SSE connection drops, use `GET /tasks/{task_id}:subscribe` to re-subscribe while the task is still non-terminal.
1260
1315
 
1261
1316
  ## Cancellation Semantics (`CancelTask`)
1262
1317
 
@@ -1264,7 +1319,7 @@ If an SSE connection drops, use `GET /v1/tasks/{task_id}:subscribe` to re-subscr
1264
1319
  - For running tasks, the service attempts upstream OpenCode `POST /session/{sessionID}/abort` to stop generation.
1265
1320
  - Upstream interruption is best-effort: if upstream returns 404, network errors, or other HTTP errors, A2A cancellation still completes with `TaskState.TASK_STATE_CANCELED`.
1266
1321
  - Idempotency contract: repeated `CancelTask` on an already `canceled` task returns the current terminal task state without error.
1267
- - Terminal subscribe contract: calling `SubscribeToTask` or `GET /v1/tasks/{task_id}:subscribe` on a terminal task replays one terminal `Task` snapshot and then closes the stream.
1322
+ - Terminal subscribe contract: calling `SubscribeToTask` or `GET /tasks/{task_id}:subscribe` on a terminal task replays one terminal `Task` snapshot and then closes the stream.
1268
1323
  - Terminal persistence contract: once a terminal task snapshot is persisted, this service treats it as immutable. Producers must emit final text and artifact updates before the terminal event, and any final usage or stream metadata must be attached to that terminal event itself. Late terminal-state mutations are rejected by the task-store write policy.
1269
1324
  - These two semantics are also declared as machine-readable `service_behaviors` in the compatibility profile and wire contract extensions.
1270
1325
  - At `A2A_LOG_LEVEL=DEBUG`, the service emits lightweight metric log records (`logger=opencode_a2a.execution.executor`):
@@ -21,12 +21,11 @@ flowchart TD
21
21
 
22
22
  subgraph Upstream["OpenCode Upstream Layer"]
23
23
  UpstreamClient["opencode_upstream_client.py"]
24
- Invocation["invocation.py"]
25
24
  end
26
25
 
27
26
  subgraph Extensions["Extension / Contract Layer"]
28
27
  Jsonrpc["jsonrpc/"]
29
- Contracts["contracts/extensions.py"]
28
+ Contracts["contracts/extensions/"]
30
29
  Profile["profile/runtime.py"]
31
30
  end
32
31
 
@@ -61,7 +60,7 @@ flowchart TD
61
60
 
62
61
  1. `jsonrpc/application.py` owns the adapter-specific JSON-RPC application boundary.
63
62
  2. `jsonrpc/dispatch.py` and handler modules under `jsonrpc/handlers/` route provider-private methods.
64
- 3. `contracts/extensions.py` remains the SSOT for extension metadata exposed through Agent Card and OpenAPI.
63
+ 3. `contracts/extensions/` remains the SSOT for extension metadata exposed through Agent Card and OpenAPI.
65
64
  4. Tests under `tests/contracts/` and `tests/jsonrpc/` guard contract drift.
66
65
 
67
66
  ### Outbound Peer Call Path
@@ -89,7 +88,7 @@ flowchart TD
89
88
 
90
89
  ### Extension and Contract Layer
91
90
 
92
- - `contracts/extensions.py`: SSOT for extension metadata, compatibility profile, and wire-contract payloads
91
+ - `contracts/extensions/`: SSOT for extension metadata, compatibility profile, and wire-contract payloads
93
92
  - `jsonrpc/`: provider-private JSON-RPC extension surface
94
93
  - `profile/runtime.py`: runtime profile that feeds Agent Card, OpenAPI, and compatibility metadata
95
94
  - `protocol_versions.py`: protocol normalization and negotiation helpers
@@ -128,5 +127,8 @@ For maintainers new to the codebase, this order usually gives the fastest payoff
128
127
  2. `docs/architecture.md`
129
128
  3. `src/opencode_a2a/server/application.py`
130
129
  4. `src/opencode_a2a/execution/executor.py`
131
- 5. `src/opencode_a2a/contracts/extensions.py`
130
+ 5. `src/opencode_a2a/contracts/extensions/`
131
+
132
+ For security-focused contributors, `docs/security-architecture.md` additionally
133
+ consolidates the security surface mapping and residual-risk register.
132
134
  6. `docs/guide.md`