opencode-a2a 0.8.0__tar.gz → 0.8.2__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 (183) hide show
  1. {opencode_a2a-0.8.0/src/opencode_a2a.egg-info → opencode_a2a-0.8.2}/PKG-INFO +1 -1
  2. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/docs/guide.md +2 -1
  3. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/client.py +1 -1
  4. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/coordinator.py +13 -5
  5. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/executor.py +2 -2
  6. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/stream_runtime.py +4 -4
  7. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/opencode_upstream_client.py +1 -1
  8. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/application.py +2 -2
  9. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2/src/opencode_a2a.egg-info}/PKG-INFO +1 -1
  10. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/client/test_client_facade.py +40 -0
  11. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_agent_errors.py +24 -4
  12. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_metrics.py +7 -0
  13. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_streaming_output_contract_logging.py +44 -0
  14. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/upstream/test_opencode_upstream_client_params.py +16 -5
  15. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/.github/dependabot.yml +0 -0
  16. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/.github/workflows/dependency-review.yml +0 -0
  17. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/.github/workflows/publish.yml +0 -0
  18. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/.github/workflows/validate.yml +0 -0
  19. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/.gitignore +0 -0
  20. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/.pre-commit-config.yaml +0 -0
  21. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/.secrets.baseline +0 -0
  22. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/AGENTS.md +0 -0
  23. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/CODE_OF_CONDUCT.md +0 -0
  24. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/CONTRIBUTING.md +0 -0
  25. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/LICENSE +0 -0
  26. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/README.md +0 -0
  27. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/SECURITY.md +0 -0
  28. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/SUPPORT.md +0 -0
  29. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/docs/architecture.md +0 -0
  30. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/docs/compatibility.md +0 -0
  31. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/docs/conformance-triage.md +0 -0
  32. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/docs/conformance.md +0 -0
  33. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/docs/extension-specifications.md +0 -0
  34. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/docs/maintainer-architecture.md +0 -0
  35. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/pyproject.toml +0 -0
  36. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/scripts/README.md +0 -0
  37. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/scripts/check_coverage.py +0 -0
  38. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/scripts/conformance.sh +0 -0
  39. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/scripts/dependency_health.sh +0 -0
  40. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/scripts/doctor.sh +0 -0
  41. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/scripts/health_common.sh +0 -0
  42. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/scripts/lint.sh +0 -0
  43. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/scripts/smoke_test_built_cli.sh +0 -0
  44. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/setup.cfg +0 -0
  45. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/__init__.py +0 -0
  46. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/auth.py +0 -0
  47. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/cli.py +0 -0
  48. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/__init__.py +0 -0
  49. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/agent_card.py +0 -0
  50. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/auth.py +0 -0
  51. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/config.py +0 -0
  52. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/error_mapping.py +0 -0
  53. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/errors.py +0 -0
  54. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/payload_text.py +0 -0
  55. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/polling.py +0 -0
  56. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/client/request_context.py +0 -0
  57. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/config.py +0 -0
  58. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/contracts/__init__.py +0 -0
  59. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/contracts/extensions.py +0 -0
  60. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/__init__.py +0 -0
  61. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/event_helpers.py +0 -0
  62. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/metrics.py +0 -0
  63. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/request_context.py +0 -0
  64. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/session_manager.py +0 -0
  65. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/stream_events.py +0 -0
  66. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/stream_state.py +0 -0
  67. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/tool_error_mapping.py +0 -0
  68. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/tool_orchestration.py +0 -0
  69. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/execution/upstream_error_translator.py +0 -0
  70. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/invocation.py +0 -0
  71. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/__init__.py +0 -0
  72. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/application.py +0 -0
  73. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/dispatch.py +0 -0
  74. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/error_responses.py +0 -0
  75. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/__init__.py +0 -0
  76. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/common.py +0 -0
  77. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/interrupt_callbacks.py +0 -0
  78. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/interrupt_queries.py +0 -0
  79. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/provider_discovery.py +0 -0
  80. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/session_control.py +0 -0
  81. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/session_lifecycle.py +0 -0
  82. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/session_queries.py +0 -0
  83. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/handlers/workspace_control.py +0 -0
  84. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/methods.py +0 -0
  85. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/jsonrpc/params.py +0 -0
  86. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/metadata_access.py +0 -0
  87. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/output_modes.py +0 -0
  88. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/parsing.py +0 -0
  89. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/parts/__init__.py +0 -0
  90. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/parts/mapping.py +0 -0
  91. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/parts/text.py +0 -0
  92. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/profile/__init__.py +0 -0
  93. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/profile/runtime.py +0 -0
  94. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/protocol_versions.py +0 -0
  95. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/py.typed +0 -0
  96. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/runtime_state.py +0 -0
  97. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/sandbox_policy.py +0 -0
  98. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/__init__.py +0 -0
  99. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/agent_card.py +0 -0
  100. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/client_manager.py +0 -0
  101. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/lifespan.py +0 -0
  102. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/middleware.py +0 -0
  103. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/migrations.py +0 -0
  104. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/openapi.py +0 -0
  105. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/request_parsing.py +0 -0
  106. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/rest_tasks.py +0 -0
  107. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/state_store.py +0 -0
  108. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/server/task_store.py +0 -0
  109. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/task_states.py +0 -0
  110. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/trace_context.py +0 -0
  111. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a/upstream_taxonomy.py +0 -0
  112. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a.egg-info/SOURCES.txt +0 -0
  113. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a.egg-info/dependency_links.txt +0 -0
  114. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a.egg-info/entry_points.txt +0 -0
  115. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a.egg-info/requires.txt +0 -0
  116. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/src/opencode_a2a.egg-info/top_level.txt +0 -0
  117. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/__init__.py +0 -0
  118. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/client/__init__.py +0 -0
  119. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/client/test_agent_card.py +0 -0
  120. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/client/test_client_config.py +0 -0
  121. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/client/test_error_mapping.py +0 -0
  122. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/client/test_payload_text.py +0 -0
  123. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/client/test_polling.py +0 -0
  124. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/client/test_request_context.py +0 -0
  125. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/config/__init__.py +0 -0
  126. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/config/test_settings.py +0 -0
  127. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/conftest.py +0 -0
  128. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/contracts/__init__.py +0 -0
  129. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/contracts/test_extension_contract_consistency.py +0 -0
  130. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/__init__.py +0 -0
  131. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_agent_helpers.py +0 -0
  132. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_cancellation.py +0 -0
  133. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_directory_validation.py +0 -0
  134. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_multipart_input.py +0 -0
  135. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_opencode_agent_session_binding.py +0 -0
  136. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_session_lock_lifecycle.py +0 -0
  137. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_session_ownership.py +0 -0
  138. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_streaming_output_contract_blocks.py +0 -0
  139. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_streaming_output_contract_core.py +0 -0
  140. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/execution/test_streaming_output_contract_interrupts.py +0 -0
  141. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/__init__.py +0 -0
  142. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_dispatch_registry.py +0 -0
  143. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_error_responses.py +0 -0
  144. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_jsonrpc_methods.py +0 -0
  145. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_jsonrpc_params.py +0 -0
  146. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_jsonrpc_unsupported_method.py +0 -0
  147. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_opencode_session_extension_commands.py +0 -0
  148. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_opencode_session_extension_interrupts.py +0 -0
  149. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_opencode_session_extension_lifecycle.py +0 -0
  150. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_opencode_session_extension_prompt_async.py +0 -0
  151. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_opencode_session_extension_queries.py +0 -0
  152. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/jsonrpc/test_opencode_workspace_control_extension.py +0 -0
  153. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/package/__init__.py +0 -0
  154. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/package/test_logging.py +0 -0
  155. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/package/test_typing_contract.py +0 -0
  156. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/package/test_version.py +0 -0
  157. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/parts/__init__.py +0 -0
  158. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/parts/test_parts_text.py +0 -0
  159. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/profile/__init__.py +0 -0
  160. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/profile/test_profile_runtime.py +0 -0
  161. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/scripts/__init__.py +0 -0
  162. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/scripts/test_script_health_contract.py +0 -0
  163. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/__init__.py +0 -0
  164. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_a2a_client_manager.py +0 -0
  165. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_agent_card.py +0 -0
  166. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_app_behaviors.py +0 -0
  167. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_auth.py +0 -0
  168. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_call_context_builder.py +0 -0
  169. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_cancel_contract.py +0 -0
  170. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_cli.py +0 -0
  171. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_database_app_persistence.py +0 -0
  172. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_output_negotiation.py +0 -0
  173. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_state_store.py +0 -0
  174. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_task_store_factory.py +0 -0
  175. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/server/test_transport_contract.py +0 -0
  176. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/support/__init__.py +0 -0
  177. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/support/helpers.py +0 -0
  178. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/support/session_extensions.py +0 -0
  179. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/support/streaming_output.py +0 -0
  180. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/test_metadata_access.py +0 -0
  181. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/test_trace_context.py +0 -0
  182. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/tests/upstream/__init__.py +0 -0
  183. {opencode_a2a-0.8.0 → opencode_a2a-0.8.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencode-a2a
3
- Version: 0.8.0
3
+ Version: 0.8.2
4
4
  Summary: OpenCode A2A runtime
5
5
  Author: liujuanjuan1984@Intelligent-Internet
6
6
  License-Expression: Apache-2.0
@@ -1247,7 +1247,8 @@ If an SSE connection drops, use `GET /v1/tasks/{task_id}:subscribe` to re-subscr
1247
1247
  - Idempotency contract: repeated `tasks/cancel` on an already `canceled` task returns the current terminal task state without error.
1248
1248
  - Terminal subscribe contract: calling `subscribe` on a terminal task replays one terminal `Task` snapshot and then closes the stream.
1249
1249
  - These two semantics are also declared as machine-readable `service_behaviors` in the compatibility profile and wire contract extensions.
1250
- - The service emits lightweight metric log records (`logger=opencode_a2a.execution.executor`):
1250
+ - At `A2A_LOG_LEVEL=DEBUG`, the service emits lightweight metric log records
1251
+ (`logger=opencode_a2a.execution.executor`):
1251
1252
  - `a2a_stream_requests_total`
1252
1253
  - `a2a_stream_active` (`value=1` when a stream starts, `value=-1` when it closes)
1253
1254
  - `opencode_stream_retries_total`
@@ -295,7 +295,7 @@ class A2AClient:
295
295
  card = await self.get_agent_card()
296
296
  config = ClientConfig(
297
297
  streaming=True,
298
- polling=False,
298
+ polling=self._polling_fallback_policy.enabled,
299
299
  httpx_client=await self._get_httpx_client(),
300
300
  supported_transports=list(self._settings.supported_transports),
301
301
  use_client_preference=self._settings.use_client_preference,
@@ -174,7 +174,11 @@ class ExecutionCoordinator:
174
174
  break
175
175
 
176
176
  except httpx.HTTPStatusError as exc:
177
- logger.exception("OpenCode request failed with HTTP error")
177
+ logger.warning(
178
+ "OpenCode request failed with HTTP status=%s",
179
+ exc.response.status_code,
180
+ exc_info=logger.isEnabledFor(logging.DEBUG),
181
+ )
178
182
  error_type, state, message = _format_upstream_error(
179
183
  exc,
180
184
  request="send_message",
@@ -190,7 +194,11 @@ class ExecutionCoordinator:
190
194
  streaming_request=self._prepared.streaming_request,
191
195
  )
192
196
  except httpx.TimeoutException as exc:
193
- logger.exception("OpenCode request timed out")
197
+ logger.warning(
198
+ "OpenCode request timed out: %s",
199
+ exc,
200
+ exc_info=logger.isEnabledFor(logging.DEBUG),
201
+ )
194
202
  await self._executor._emit_error(
195
203
  self._event_queue,
196
204
  task_id=self._task_id,
@@ -212,7 +220,7 @@ class ExecutionCoordinator:
212
220
  streaming_request=self._prepared.streaming_request,
213
221
  )
214
222
  except UpstreamConcurrencyLimitError as exc:
215
- logger.warning("OpenCode request rejected by concurrency budget: %s", exc)
223
+ logger.debug("OpenCode request rejected by concurrency budget: %s", exc)
216
224
  await self._executor._emit_error(
217
225
  self._event_queue,
218
226
  task_id=self._task_id,
@@ -304,11 +312,11 @@ class ExecutionCoordinator:
304
312
  )
305
313
 
306
314
  logger.debug(
307
- "OpenCode response task_id=%s session_id=%s message_id=%s text=%s",
315
+ "OpenCode response task_id=%s session_id=%s message_id=%s text_len=%s",
308
316
  self._task_id,
309
317
  response.session_id,
310
318
  resolved_message_id,
311
- response_text,
319
+ len(response_text),
312
320
  )
313
321
 
314
322
  if response_error is not None:
@@ -310,7 +310,7 @@ class OpencodeAgentExecutor(AgentExecutor):
310
310
  (
311
311
  "Received message identity=%s credential_id=%s auth_scheme=%s trace_id=%s "
312
312
  "task_id=%s context_id=%s "
313
- "streaming=%s text=%s part_count=%s"
313
+ "streaming=%s text_len=%s part_count=%s"
314
314
  ),
315
315
  identity,
316
316
  credential_id,
@@ -319,7 +319,7 @@ class OpencodeAgentExecutor(AgentExecutor):
319
319
  task_id,
320
320
  context_id,
321
321
  streaming_request,
322
- user_text,
322
+ len(user_text),
323
323
  len(request_parts),
324
324
  )
325
325
  prepared = PreparedExecution(
@@ -138,14 +138,14 @@ class StreamRuntime:
138
138
  )
139
139
  logger.debug(
140
140
  "Stream chunk task_id=%s session_id=%s block_type=%s append=%s "
141
- "shared_source=%s internal_source=%s text=%s",
141
+ "shared_source=%s internal_source=%s content_len=%s",
142
142
  task_id,
143
143
  session_id,
144
144
  chunk.block_type,
145
145
  effective_append,
146
146
  chunk.shared_source,
147
147
  chunk.internal_source,
148
- chunk.content_key,
148
+ len(chunk.content_key),
149
149
  )
150
150
  if chunk.block_type == BlockType.TOOL_CALL:
151
151
  self._emit_metric("tool_call_chunks_emitted_total")
@@ -343,7 +343,7 @@ class StreamRuntime:
343
343
  )
344
344
  ]
345
345
  state.buffer = snapshot
346
- logger.warning(
346
+ logger.debug(
347
347
  "Suppressing non-prefix snapshot rewrite "
348
348
  "task_id=%s session_id=%s part_id=%s block_type=%s had_delta=%s",
349
349
  task_id,
@@ -593,7 +593,7 @@ class StreamRuntime:
593
593
  if stop_event.is_set():
594
594
  break
595
595
  self._emit_metric("opencode_stream_retries_total")
596
- logger.exception("OpenCode event stream failed; retrying")
596
+ logger.debug("OpenCode event stream failed; retrying", exc_info=True)
597
597
  await self._sleep(backoff)
598
598
  backoff = min(backoff * 2, max_backoff)
599
599
  except Exception:
@@ -72,7 +72,7 @@ class _FastFailConcurrencyBudget:
72
72
  async with self._lock:
73
73
  inflight = self._inflight
74
74
  if inflight >= self._limit:
75
- logger.warning(
75
+ logger.debug(
76
76
  "OpenCode upstream concurrency limit exceeded "
77
77
  "category=%s operation=%s limit=%s inflight=%s",
78
78
  self._category,
@@ -430,7 +430,7 @@ class OpencodeRequestHandler(DefaultRequestHandler):
430
430
  ):
431
431
  yield event
432
432
  except (asyncio.CancelledError, GeneratorExit):
433
- logger.warning("Client disconnected. Cancelling producer task %s", task_id)
433
+ logger.debug("Client disconnected. Cancelling producer task %s", task_id)
434
434
  producer_task.cancel()
435
435
  await queue.close(immediate=True)
436
436
  raise
@@ -504,7 +504,7 @@ class OpencodeRequestHandler(DefaultRequestHandler):
504
504
  try:
505
505
  current_task = asyncio.current_task()
506
506
  if current_task is not None and current_task.cancelled():
507
- logger.warning(
507
+ logger.debug(
508
508
  "Client disconnected from message request. Cancelling task %s", task_id
509
509
  )
510
510
  producer_task.cancel()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencode-a2a
3
- Version: 0.8.0
3
+ Version: 0.8.2
4
4
  Summary: OpenCode A2A runtime
5
5
  Author: liujuanjuan1984@Intelligent-Internet
6
6
  License-Expression: Apache-2.0
@@ -154,6 +154,46 @@ async def test_build_client_uses_settings_and_transport_config(
154
154
  assert actual is fake_sdk_client
155
155
 
156
156
 
157
+ @pytest.mark.asyncio
158
+ async def test_build_client_enables_sdk_polling_when_polling_fallback_enabled(
159
+ monkeypatch: pytest.MonkeyPatch,
160
+ ) -> None:
161
+ client = A2AClient(
162
+ "http://agent.example.com",
163
+ settings=A2AClientSettings(polling_fallback_enabled=True),
164
+ )
165
+ fake_sdk_client = _FakeClient()
166
+ factory_calls: dict[str, object] = {}
167
+
168
+ class _FakeFactory:
169
+ def __init__(self, config: ClientConfig, consumers: list[object] | None = None):
170
+ factory_calls["config"] = config
171
+ factory_calls["consumers"] = consumers
172
+
173
+ def create(
174
+ self,
175
+ _card: object,
176
+ consumers: list[object] | None = None,
177
+ interceptors: list[object] | None = None,
178
+ extensions: list[str] | None = None,
179
+ ) -> _FakeClient:
180
+ return fake_sdk_client
181
+
182
+ monkeypatch.setattr(client_module, "ClientFactory", _FakeFactory)
183
+ monkeypatch.setattr(
184
+ client_module,
185
+ "build_agent_card_resolver",
186
+ lambda *_args: _FakeCardResolver("agent-card"),
187
+ )
188
+
189
+ actual = await client._build_client()
190
+
191
+ config = factory_calls["config"]
192
+ assert isinstance(config, ClientConfig)
193
+ assert config.polling is True
194
+ assert actual is fake_sdk_client
195
+
196
+
157
197
  @pytest.mark.asyncio
158
198
  async def test_send_returns_last_event(monkeypatch: pytest.MonkeyPatch) -> None:
159
199
  client = A2AClient("http://agent.example.com")
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import logging
2
3
  from unittest.mock import AsyncMock, MagicMock
3
4
 
4
5
  import httpx
@@ -173,7 +174,7 @@ async def test_execute_http_error_maps_to_task_error_type_and_state(
173
174
 
174
175
 
175
176
  @pytest.mark.asyncio
176
- async def test_streaming_execute_http_error_emits_status_update_with_metadata() -> None:
177
+ async def test_streaming_execute_http_error_emits_status_update_with_metadata(caplog) -> None:
177
178
  request = httpx.Request("POST", "http://127.0.0.1:4096/message")
178
179
  response = httpx.Response(
179
180
  status_code=429,
@@ -204,7 +205,8 @@ async def test_streaming_execute_http_error_emits_status_update_with_metadata()
204
205
  )
205
206
  event_queue = AsyncMock(spec=EventQueue)
206
207
 
207
- await executor.execute(context, event_queue)
208
+ with caplog.at_level(logging.INFO, logger="opencode_a2a.execution.coordinator"):
209
+ await executor.execute(context, event_queue)
208
210
 
209
211
  status = None
210
212
  for call in event_queue.enqueue_event.call_args_list:
@@ -223,10 +225,20 @@ async def test_streaming_execute_http_error_emits_status_update_with_metadata()
223
225
  assert status.status.state == TaskState.failed
224
226
  assert status.metadata["opencode"]["error"]["type"] == "UPSTREAM_QUOTA_EXCEEDED"
225
227
  assert status.metadata["opencode"]["error"]["upstream_status"] == 429
228
+ http_logs = [
229
+ record
230
+ for record in caplog.records
231
+ if "OpenCode request failed with HTTP status=429" in record.message
232
+ ]
233
+ assert len(http_logs) == 1
234
+ assert http_logs[0].levelno == logging.WARNING
235
+ assert not http_logs[0].exc_info
226
236
 
227
237
 
228
238
  @pytest.mark.asyncio
229
- async def test_streaming_execute_upstream_backpressure_emits_status_update_with_metadata() -> None:
239
+ async def test_streaming_execute_upstream_backpressure_emits_status_update_with_metadata(
240
+ caplog,
241
+ ) -> None:
230
242
  client = AsyncMock()
231
243
 
232
244
  async def create_session(title: str | None = None, *, directory: str | None = None) -> str:
@@ -255,7 +267,8 @@ async def test_streaming_execute_upstream_backpressure_emits_status_update_with_
255
267
  )
256
268
  event_queue = AsyncMock(spec=EventQueue)
257
269
 
258
- await executor.execute(context, event_queue)
270
+ with caplog.at_level(logging.DEBUG, logger="opencode_a2a.execution.coordinator"):
271
+ await executor.execute(context, event_queue)
259
272
 
260
273
  status = None
261
274
  for call in event_queue.enqueue_event.call_args_list:
@@ -273,6 +286,13 @@ async def test_streaming_execute_upstream_backpressure_emits_status_update_with_
273
286
  assert status is not None
274
287
  assert status.status.state == TaskState.failed
275
288
  assert status.metadata["opencode"]["error"]["type"] == "UPSTREAM_BACKPRESSURE"
289
+ backpressure_logs = [
290
+ record
291
+ for record in caplog.records
292
+ if "OpenCode request rejected by concurrency budget" in record.message
293
+ ]
294
+ assert len(backpressure_logs) == 1
295
+ assert backpressure_logs[0].levelno == logging.DEBUG
276
296
 
277
297
 
278
298
  @pytest.mark.asyncio
@@ -202,3 +202,10 @@ async def test_streaming_retry_metric_increments_once_per_retry(monkeypatch, cap
202
202
 
203
203
  messages = [record.message for record in caplog.records]
204
204
  assert sum("metric=opencode_stream_retries_total" in message for message in messages) == 1
205
+ retry_logs = [
206
+ record
207
+ for record in caplog.records
208
+ if "OpenCode event stream failed; retrying" in record.message
209
+ ]
210
+ assert len(retry_logs) == 1
211
+ assert retry_logs[0].levelno == logging.DEBUG
@@ -18,6 +18,50 @@ from tests.support.streaming_output import (
18
18
  )
19
19
 
20
20
 
21
+ @pytest.mark.asyncio
22
+ async def test_execute_debug_log_records_text_length_without_raw_user_text(caplog) -> None:
23
+ raw_text = "do not write this prompt to logs"
24
+ response_text = "do not write this response to logs"
25
+ client = DummyStreamingClient(
26
+ stream_events_payload=[],
27
+ response_text=response_text,
28
+ )
29
+ client.settings = make_settings(
30
+ test_bearer_token="test",
31
+ opencode_base_url="http://localhost",
32
+ a2a_log_body_limit=64,
33
+ )
34
+ executor = OpencodeAgentExecutor(client, streaming_enabled=True)
35
+ executor._should_stream = lambda context: True # type: ignore[method-assign]
36
+ queue = DummyEventQueue()
37
+
38
+ with caplog.at_level(logging.DEBUG, logger="opencode_a2a.execution"):
39
+ await executor.execute(
40
+ make_request_context(
41
+ task_id="task-debug-input",
42
+ context_id="ctx-debug-input",
43
+ text=raw_text,
44
+ ),
45
+ queue,
46
+ )
47
+
48
+ received_messages = [
49
+ record.message for record in caplog.records if record.message.startswith("Received message")
50
+ ]
51
+ assert len(received_messages) == 1
52
+ assert f"text_len={len(raw_text)}" in received_messages[0]
53
+ opencode_response_messages = [
54
+ record.message
55
+ for record in caplog.records
56
+ if record.message.startswith("OpenCode response")
57
+ ]
58
+ assert len(opencode_response_messages) == 1
59
+ assert f"text_len={len(response_text)}" in opencode_response_messages[0]
60
+ all_messages = "\n".join(record.message for record in caplog.records)
61
+ assert raw_text not in all_messages
62
+ assert response_text not in all_messages
63
+
64
+
21
65
  @pytest.mark.asyncio
22
66
  async def test_streaming_logs_raw_upstream_events_at_debug(caplog) -> None:
23
67
  client = DummyStreamingClient(
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  import json as json_module
3
+ import logging
3
4
 
4
5
  import httpx
5
6
  import pytest
@@ -593,6 +594,7 @@ async def test_send_message_raises_upstream_contract_error_for_non_json_response
593
594
  @pytest.mark.asyncio
594
595
  async def test_send_message_raises_concurrency_limit_error_when_request_budget_exhausted(
595
596
  monkeypatch,
597
+ caplog,
596
598
  ):
597
599
  client = OpencodeUpstreamClient(
598
600
  make_settings(
@@ -618,11 +620,20 @@ async def test_send_message_raises_concurrency_limit_error_when_request_budget_e
618
620
  first_request = asyncio.create_task(client.send_message("ses-1", "hello"))
619
621
  await started.wait()
620
622
 
621
- with pytest.raises(
622
- UpstreamConcurrencyLimitError,
623
- match="request concurrency limit exceeded",
624
- ):
625
- await client.send_message("ses-2", "blocked")
623
+ with caplog.at_level(logging.DEBUG, logger="opencode_a2a.opencode_upstream_client"):
624
+ with pytest.raises(
625
+ UpstreamConcurrencyLimitError,
626
+ match="request concurrency limit exceeded",
627
+ ):
628
+ await client.send_message("ses-2", "blocked")
629
+
630
+ budget_logs = [
631
+ record
632
+ for record in caplog.records
633
+ if "OpenCode upstream concurrency limit exceeded" in record.message
634
+ ]
635
+ assert len(budget_logs) == 1
636
+ assert budget_logs[0].levelno == logging.DEBUG
626
637
 
627
638
  release.set()
628
639
  await first_request
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes