codex-a2a 0.7.0__tar.gz → 0.7.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 (218) hide show
  1. {codex_a2a-0.7.0/src/codex_a2a.egg-info → codex_a2a-0.7.2}/PKG-INFO +1 -1
  2. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/docs/guide.md +1 -1
  3. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/__init__.py +2 -0
  4. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/auth.py +20 -0
  5. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/client.py +14 -1
  6. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/config.py +1 -0
  7. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/payload_text.py +11 -1
  8. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/config.py +1 -1
  9. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/cancellation.py +1 -1
  10. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/executor.py +1 -1
  11. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/output_mapping.py +17 -9
  12. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/stream_chunks.py +16 -0
  13. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/stream_processor.py +3 -3
  14. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/thread_lifecycle_runtime.py +2 -2
  15. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/application.py +2 -2
  16. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/http_middlewares.py +2 -2
  17. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/request_handler.py +2 -2
  18. {codex_a2a-0.7.0 → codex_a2a-0.7.2/src/codex_a2a.egg-info}/PKG-INFO +1 -1
  19. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_client_flow.py +53 -0
  20. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/config/test_settings.py +1 -0
  21. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_stream_chunks.py +18 -0
  22. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_streaming_output_contract.py +2 -2
  23. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_cli.py +6 -0
  24. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/.github/dependabot.yml +0 -0
  25. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/.github/workflows/ci.yml +0 -0
  26. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/.github/workflows/dependency-health.yml +0 -0
  27. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/.github/workflows/publish.yml +0 -0
  28. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/.gitignore +0 -0
  29. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/.pre-commit-config.yaml +0 -0
  30. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/.secrets.baseline +0 -0
  31. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/AGENTS.md +0 -0
  32. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/CONTRIBUTING.md +0 -0
  33. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/LICENSE +0 -0
  34. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/README.md +0 -0
  35. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/SECURITY.md +0 -0
  36. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/docs/architecture.md +0 -0
  37. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/docs/compatibility.md +0 -0
  38. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/docs/conformance-triage.md +0 -0
  39. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/docs/conformance.md +0 -0
  40. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/docs/extension-specifications.md +0 -0
  41. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/docs/maintainer-architecture.md +0 -0
  42. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/mypy.ini +0 -0
  43. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/pyproject.toml +0 -0
  44. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/README.md +0 -0
  45. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/conformance.sh +0 -0
  46. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/dependency_health.sh +0 -0
  47. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/doctor.sh +0 -0
  48. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/health_common.sh +0 -0
  49. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/publish_github_release.sh +0 -0
  50. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/smoke_test_built_cli.sh +0 -0
  51. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/sync_codex_docs.sh +0 -0
  52. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/validate_baseline.sh +0 -0
  53. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/scripts/validate_runtime_matrix.sh +0 -0
  54. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/setup.cfg +0 -0
  55. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/__init__.py +0 -0
  56. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/auth.py +0 -0
  57. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/cli.py +0 -0
  58. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/agent_card.py +0 -0
  59. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/errors.py +0 -0
  60. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/manager.py +0 -0
  61. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/request_context.py +0 -0
  62. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/client/types.py +0 -0
  63. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/contracts/__init__.py +0 -0
  64. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/contracts/extensions.py +0 -0
  65. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/contracts/runtime_output.py +0 -0
  66. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/__init__.py +0 -0
  67. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/directory_policy.py +0 -0
  68. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/discovery_runtime.py +0 -0
  69. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/exec_runtime.py +0 -0
  70. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/request_metadata.py +0 -0
  71. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/request_overrides.py +0 -0
  72. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/response_emitter.py +0 -0
  73. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/review_runtime.py +0 -0
  74. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/session_runtime.py +0 -0
  75. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/stream_interrupts.py +0 -0
  76. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/stream_state.py +0 -0
  77. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/streaming.py +0 -0
  78. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/tool_call_payloads.py +0 -0
  79. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/execution/watch_events.py +0 -0
  80. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/input_mapping.py +0 -0
  81. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/__init__.py +0 -0
  82. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/application.py +0 -0
  83. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/control_params.py +0 -0
  84. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/discovery_control.py +0 -0
  85. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/discovery_params.py +0 -0
  86. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/discovery_payload_mapping.py +0 -0
  87. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/discovery_query.py +0 -0
  88. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/dispatch.py +0 -0
  89. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/errors.py +0 -0
  90. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/exec_control.py +0 -0
  91. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/hooks.py +0 -0
  92. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/interrupt_lifecycle.py +0 -0
  93. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/interrupt_params.py +0 -0
  94. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/interrupt_recovery.py +0 -0
  95. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/interrupt_recovery_params.py +0 -0
  96. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/interrupts.py +0 -0
  97. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/owner_guard.py +0 -0
  98. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/params.py +0 -0
  99. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/params_common.py +0 -0
  100. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/payload_mapping.py +0 -0
  101. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/query_params.py +0 -0
  102. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/review_control.py +0 -0
  103. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/review_control_params.py +0 -0
  104. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/session_control.py +0 -0
  105. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/session_query.py +0 -0
  106. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/thread_lifecycle_control.py +0 -0
  107. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/thread_lifecycle_params.py +0 -0
  108. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/turn_control.py +0 -0
  109. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/jsonrpc/turn_control_params.py +0 -0
  110. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/logging_context.py +0 -0
  111. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/media_modes.py +0 -0
  112. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/metrics.py +0 -0
  113. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/parts/text.py +0 -0
  114. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/payload_helpers.py +0 -0
  115. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/profile/__init__.py +0 -0
  116. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/profile/runtime.py +0 -0
  117. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/protocol_versions.py +0 -0
  118. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/py.typed +0 -0
  119. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/__init__.py +0 -0
  120. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/agent_card.py +0 -0
  121. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/call_context.py +0 -0
  122. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/database.py +0 -0
  123. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/migrations.py +0 -0
  124. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/openapi.py +0 -0
  125. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/output_negotiation.py +0 -0
  126. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/runtime_state.py +0 -0
  127. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/server/task_store.py +0 -0
  128. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/__init__.py +0 -0
  129. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/client.py +0 -0
  130. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/conversation_facade.py +0 -0
  131. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/discovery_payloads.py +0 -0
  132. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/exec_facade.py +0 -0
  133. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/interrupt_bridge.py +0 -0
  134. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/interrupts.py +0 -0
  135. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/models.py +0 -0
  136. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/notification_mapping.py +0 -0
  137. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/request_mapping.py +0 -0
  138. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/startup.py +0 -0
  139. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/stream_bridge.py +0 -0
  140. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a/upstream/transport.py +0 -0
  141. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a.egg-info/SOURCES.txt +0 -0
  142. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a.egg-info/dependency_links.txt +0 -0
  143. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a.egg-info/entry_points.txt +0 -0
  144. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a.egg-info/requires.txt +0 -0
  145. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/src/codex_a2a.egg-info/top_level.txt +0 -0
  146. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/__init__.py +0 -0
  147. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/__init__.py +0 -0
  148. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_agent_card.py +0 -0
  149. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_cli.py +0 -0
  150. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_client_manager.py +0 -0
  151. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_errors.py +0 -0
  152. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_lifecycle.py +0 -0
  153. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_payload_text.py +0 -0
  154. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_request_context.py +0 -0
  155. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/client/test_types.py +0 -0
  156. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/config/__init__.py +0 -0
  157. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/contracts/__init__.py +0 -0
  158. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/contracts/test_extension_contract_consistency.py +0 -0
  159. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/__init__.py +0 -0
  160. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_agent_errors.py +0 -0
  161. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_cancellation.py +0 -0
  162. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_codex_agent_session_binding.py +0 -0
  163. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_directory_validation.py +0 -0
  164. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_discovery_exec_runtime.py +0 -0
  165. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_metrics.py +0 -0
  166. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_review_runtime.py +0 -0
  167. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_session_ownership.py +0 -0
  168. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_session_persistence.py +0 -0
  169. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_session_runtime.py +0 -0
  170. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_stream_interrupts.py +0 -0
  171. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_thread_lifecycle_runtime.py +0 -0
  172. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/execution/test_tool_call_payloads.py +0 -0
  173. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/fixtures/codex_app_server/command_execution_output_delta.json +0 -0
  174. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/fixtures/codex_app_server/file_change_output_delta.json +0 -0
  175. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/__init__.py +0 -0
  176. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/test_codex_discovery_extension.py +0 -0
  177. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/test_codex_exec_extension.py +0 -0
  178. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/test_codex_session_extension.py +0 -0
  179. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/test_codex_thread_lifecycle_extension.py +0 -0
  180. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/test_codex_turn_review_extension.py +0 -0
  181. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/test_dispatch.py +0 -0
  182. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/test_guard_hooks.py +0 -0
  183. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/jsonrpc/test_jsonrpc_models.py +0 -0
  184. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/package/__init__.py +0 -0
  185. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/package/test_logging.py +0 -0
  186. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/package/test_publish_github_release_script.py +0 -0
  187. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/package/test_release_distribution_contract.py +0 -0
  188. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/package/test_typing_contract.py +0 -0
  189. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/package/test_version.py +0 -0
  190. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/parts/__init__.py +0 -0
  191. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/parts/test_text.py +0 -0
  192. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/profile/__init__.py +0 -0
  193. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/profile/test_profile.py +0 -0
  194. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/scripts/__init__.py +0 -0
  195. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/scripts/test_script_health_contract.py +0 -0
  196. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/__init__.py +0 -0
  197. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_agent_card.py +0 -0
  198. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_auth.py +0 -0
  199. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_call_context_builder.py +0 -0
  200. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_database.py +0 -0
  201. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_database_app_persistence.py +0 -0
  202. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_migrations.py +0 -0
  203. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_request_handler.py +0 -0
  204. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_runtime_state.py +0 -0
  205. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_task_store.py +0 -0
  206. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/server/test_transport_contract.py +0 -0
  207. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/support/__init__.py +0 -0
  208. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/support/context.py +0 -0
  209. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/support/dummy_clients.py +0 -0
  210. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/support/fixtures.py +0 -0
  211. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/support/settings.py +0 -0
  212. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/test_input_mapping.py +0 -0
  213. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/test_protocol_versions.py +0 -0
  214. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/upstream/__init__.py +0 -0
  215. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/upstream/test_codex_client_params.py +0 -0
  216. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/upstream/test_interrupt_persistence.py +0 -0
  217. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/tests/upstream/test_modular_upstream_components.py +0 -0
  218. {codex_a2a-0.7.0 → codex_a2a-0.7.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-a2a
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Codex A2A runtime adapter
5
5
  Author: liujuanjuan1984@Intelligent-Internet
6
6
  License-Expression: Apache-2.0
@@ -191,7 +191,7 @@ Use the grouped sections below as the deployment-first reading order:
191
191
  - `A2A_DATABASE_URL` also owns the adapter-managed runtime-state schema lifecycle. On startup, `codex-a2a` auto-creates the runtime-state tables, records a schema version for the `runtime_state` scope, and applies in-place migrations for those tables only.
192
192
  - The adapter-managed runtime-state schema is limited to `a2a_session_bindings`, `a2a_session_owners`, `a2a_pending_session_claims`, `a2a_pending_interrupt_requests`, and `a2a_schema_version`. It does not own the A2A SDK task-store tables or any upstream Codex/provider-local state.
193
193
  - For deployment-specific durability constraints and migration-scope boundaries, see [compatibility.md](./compatibility.md).
194
- - `A2A_LOG_LEVEL`: `DEBUG/INFO/WARNING/ERROR`, default `INFO`
194
+ - `A2A_LOG_LEVEL`: `DEBUG/INFO/WARNING/ERROR`, default `WARNING`
195
195
  - `A2A_LOG_PAYLOADS`: log A2A/Codex payload bodies, default `false`
196
196
  - `A2A_LOG_BODY_LIMIT`: payload log body size limit, default `0` (no truncation)
197
197
  - `A2A_TITLE`: agent name, default `Codex A2A`
@@ -1,5 +1,6 @@
1
1
  """Minimal A2A client facade package."""
2
2
 
3
+ from .auth import StaticCredentialService
3
4
  from .client import A2AClient
4
5
  from .config import A2AClientConfig
5
6
  from .errors import (
@@ -25,6 +26,7 @@ __all__ = [
25
26
  "A2AClient",
26
27
  "A2AClientManager",
27
28
  "A2AClientConfig",
29
+ "StaticCredentialService",
28
30
  "A2AClientConfigError",
29
31
  "A2AClientError",
30
32
  "A2AClientLifecycleError",
@@ -2,6 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  from base64 import b64decode, b64encode
4
4
  from binascii import Error as BinasciiError
5
+ from collections.abc import Mapping
6
+
7
+ from a2a.client.auth.credentials import CredentialService
8
+ from a2a.client.middleware import ClientCallContext
5
9
 
6
10
  BASIC_AUTH_FORMAT_ERROR = (
7
11
  "A2A_CLIENT_BASIC_AUTH must be 'username:password' or a base64-encoded "
@@ -32,3 +36,19 @@ def _decode_basic_auth(value: str) -> bytes:
32
36
  return b64decode(padded_value, validate=True)
33
37
  except (BinasciiError, ValueError) as exc:
34
38
  raise ValueError(BASIC_AUTH_FORMAT_ERROR) from exc
39
+
40
+
41
+ class StaticCredentialService(CredentialService):
42
+ def __init__(self, credentials: Mapping[str, str]) -> None:
43
+ self._credentials = {
44
+ scheme_name: credential
45
+ for scheme_name, credential in dict(credentials).items()
46
+ if isinstance(scheme_name, str) and scheme_name and isinstance(credential, str)
47
+ }
48
+
49
+ async def get_credentials(
50
+ self,
51
+ security_scheme_name: str,
52
+ context: ClientCallContext | None,
53
+ ) -> str | None:
54
+ return self._credentials.get(security_scheme_name)
@@ -7,6 +7,8 @@ from uuid import uuid4
7
7
 
8
8
  import httpx
9
9
  from a2a.client import A2ACardResolver, ClientConfig, ClientFactory
10
+ from a2a.client.auth.credentials import CredentialService
11
+ from a2a.client.auth.interceptor import AuthInterceptor
10
12
  from a2a.client.middleware import ClientCallContext, ClientCallInterceptor
11
13
  from a2a.types import (
12
14
  AgentCard,
@@ -21,6 +23,7 @@ from a2a.types import (
21
23
  )
22
24
 
23
25
  from .agent_card import build_agent_card_request_kwargs, resolve_agent_card_endpoint
26
+ from .auth import StaticCredentialService
24
27
  from .config import A2AClientConfig
25
28
  from .errors import (
26
29
  A2AClientConfigError,
@@ -103,6 +106,7 @@ class A2AClient:
103
106
  httpx_client: httpx.AsyncClient | None = None,
104
107
  card_resolver_factory=A2ACardResolver,
105
108
  client_factory_type=ClientFactory,
109
+ credential_service: CredentialService | None = None,
106
110
  ) -> None:
107
111
  if not config.agent_url:
108
112
  raise A2AClientConfigError("agent_url is required")
@@ -118,6 +122,7 @@ class A2AClient:
118
122
  self._sdk_client: _SDKClientProtocol | None = None
119
123
  self._card_resolver_factory = card_resolver_factory
120
124
  self._client_factory_type = client_factory_type
125
+ self._credential_service = credential_service
121
126
  self._client_config = ClientConfig(
122
127
  streaming=True,
123
128
  supported_transports=list(config.supported_transports),
@@ -328,7 +333,15 @@ class A2AClient:
328
333
  return self._sdk_client
329
334
 
330
335
  def _build_interceptors(self) -> list[ClientCallInterceptor]:
331
- return [_HeaderInterceptor(self._config.default_headers)]
336
+ interceptors: list[ClientCallInterceptor] = [
337
+ _HeaderInterceptor(self._config.default_headers)
338
+ ]
339
+ credential_service = self._credential_service
340
+ if credential_service is None and self._config.auth_credentials:
341
+ credential_service = StaticCredentialService(self._config.auth_credentials)
342
+ if credential_service is not None:
343
+ interceptors.append(AuthInterceptor(credential_service))
344
+ return interceptors
332
345
 
333
346
  def _build_user_message(
334
347
  self,
@@ -14,6 +14,7 @@ class A2AClientConfig(BaseModel):
14
14
  request_timeout_seconds: float | None = None
15
15
  close_http_client: bool = True
16
16
  default_headers: dict[str, str] = Field(default_factory=dict)
17
+ auth_credentials: dict[str, str] = Field(default_factory=dict)
17
18
  accepted_output_modes: list[str] = Field(default_factory=list)
18
19
  extensions: list[str] = Field(default_factory=list)
19
20
 
@@ -3,7 +3,9 @@ from __future__ import annotations
3
3
  from collections.abc import Mapping
4
4
  from typing import Any
5
5
 
6
- from a2a.types import Message, TextPart
6
+ from a2a.types import Message, Part, TextPart
7
+ from a2a.utils.message import get_message_text
8
+ from a2a.utils.parts import get_text_parts
7
9
 
8
10
 
9
11
  def _extract_from_iterable(items: Any) -> str | None:
@@ -19,6 +21,11 @@ def _extract_from_iterable(items: Any) -> str | None:
19
21
  def _extract_from_parts(parts: Any) -> str | None:
20
22
  if not isinstance(parts, (list, tuple)):
21
23
  return None
24
+ if all(isinstance(part, Part) for part in parts):
25
+ sdk_text = "\n".join(text for text in get_text_parts(list(parts)) if text.strip())
26
+ if sdk_text:
27
+ return sdk_text
28
+
22
29
  collected: list[str] = []
23
30
  for part in parts:
24
31
  text_part = None
@@ -100,6 +107,9 @@ def extract_text_from_payload(payload: Any) -> str | None:
100
107
  return _extract_from_iterable(payload)
101
108
 
102
109
  if isinstance(payload, Message):
110
+ sdk_text = get_message_text(payload).strip()
111
+ if sdk_text:
112
+ return sdk_text
103
113
  return _extract_from_parts(payload.parts)
104
114
 
105
115
  if isinstance(payload, str):
@@ -330,7 +330,7 @@ class Settings(BaseSettings):
330
330
  a2a_enable_turn_control: bool = Field(default=True, alias="A2A_ENABLE_TURN_CONTROL")
331
331
  a2a_enable_review_control: bool = Field(default=False, alias="A2A_ENABLE_REVIEW_CONTROL")
332
332
  a2a_enable_exec_control: bool = Field(default=False, alias="A2A_ENABLE_EXEC_CONTROL")
333
- a2a_log_level: str = Field(default="INFO", alias="A2A_LOG_LEVEL")
333
+ a2a_log_level: str = Field(default="WARNING", alias="A2A_LOG_LEVEL")
334
334
  a2a_log_payloads: bool = Field(default=False, alias="A2A_LOG_PAYLOADS")
335
335
  a2a_log_body_limit: int = Field(default=0, alias="A2A_LOG_BODY_LIMIT")
336
336
  a2a_documentation_url: str | None = Field(default=None, alias="A2A_DOCUMENTATION_URL")
@@ -74,7 +74,7 @@ async def await_cancel_cleanup(
74
74
  return
75
75
 
76
76
  if waitables:
77
- logger.info(
77
+ logger.debug(
78
78
  "Cancel abort wait skipped task_id=%s context_id=%s abort_timeout_seconds=%.3f",
79
79
  task_id,
80
80
  context_id,
@@ -176,7 +176,7 @@ class CodexAgentExecutor(AgentExecutor):
176
176
  try:
177
177
  directory = self._resolve_and_validate_directory(requested_dir)
178
178
  except ValueError as e:
179
- logger.warning("Directory validation failed: %s", e)
179
+ logger.debug("Directory validation failed: %s", e)
180
180
  await self._emit_error(
181
181
  event_queue,
182
182
  task_id=task_id,
@@ -1,20 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
- import uuid
4
3
  from collections.abc import Mapping
5
4
  from typing import Any
6
5
 
7
6
  from a2a.server.agent_execution import RequestContext
8
7
  from a2a.server.events.event_queue import EventQueue
8
+ from a2a.server.tasks import TaskUpdater
9
9
  from a2a.types import (
10
10
  Artifact,
11
11
  DataPart,
12
12
  Message,
13
13
  Part,
14
- Role,
15
14
  TaskArtifactUpdateEvent,
16
15
  TextPart,
17
16
  )
17
+ from a2a.utils.message import new_agent_text_message
18
18
 
19
19
  from codex_a2a.contracts.runtime_output import (
20
20
  build_output_metadata as build_runtime_output_metadata,
@@ -28,13 +28,10 @@ def build_assistant_message(
28
28
  *,
29
29
  message_id: str | None = None,
30
30
  ) -> Message:
31
- return Message(
32
- message_id=message_id or str(uuid.uuid4()),
33
- role=Role.agent,
34
- parts=[Part(root=TextPart(text=text))],
35
- task_id=task_id,
36
- context_id=context_id,
37
- )
31
+ message = new_agent_text_message(text, context_id=context_id, task_id=task_id)
32
+ if message_id is None:
33
+ return message
34
+ return message.model_copy(update={"message_id": message_id})
38
35
 
39
36
 
40
37
  async def enqueue_artifact_update(
@@ -50,6 +47,17 @@ async def enqueue_artifact_update(
50
47
  event_metadata: Mapping[str, Any] | None = None,
51
48
  ) -> None:
52
49
  normalized_last_chunk = True if last_chunk is True else None
50
+ if event_metadata is None:
51
+ updater = TaskUpdater(event_queue, task_id, context_id)
52
+ await updater.add_artifact(
53
+ parts=[Part(root=part)],
54
+ artifact_id=artifact_id,
55
+ metadata=dict(artifact_metadata) if artifact_metadata else None,
56
+ append=append,
57
+ last_chunk=normalized_last_chunk,
58
+ )
59
+ return
60
+
53
61
  artifact = Artifact(
54
62
  artifact_id=artifact_id,
55
63
  parts=[Part(root=part)],
@@ -387,6 +387,14 @@ def tool_delta_chunks(
387
387
  if not isinstance(delta_value, Mapping):
388
388
  logger.warning(
389
389
  "Suppressing non-structured tool_call payload "
390
+ "task_id=%s session_id=%s source=%s payload_type=%s",
391
+ task_id,
392
+ session_id,
393
+ source,
394
+ type(delta_value).__name__,
395
+ )
396
+ logger.debug(
397
+ "Suppressed non-structured tool_call payload "
390
398
  "task_id=%s session_id=%s source=%s payload=%s",
391
399
  task_id,
392
400
  session_id,
@@ -398,6 +406,14 @@ def tool_delta_chunks(
398
406
  if payload is None:
399
407
  logger.warning(
400
408
  "Suppressing unrecognized tool_call payload "
409
+ "task_id=%s session_id=%s source=%s payload_keys=%s",
410
+ task_id,
411
+ session_id,
412
+ source,
413
+ sorted(str(key) for key in delta_value),
414
+ )
415
+ logger.debug(
416
+ "Suppressed unrecognized tool_call payload "
401
417
  "task_id=%s session_id=%s source=%s payload=%s",
402
418
  task_id,
403
419
  session_id,
@@ -122,7 +122,7 @@ class StreamEventProcessor:
122
122
  self._diagnostics = StreamDiagnostics(started_at=time.monotonic())
123
123
 
124
124
  def log_started(self, logger) -> None: # noqa: ANN001
125
- logger.info(
125
+ logger.debug(
126
126
  "Codex event stream started task_id=%s session_id=%s idle_diagnostic_seconds=%.1f",
127
127
  self._task_id,
128
128
  self._session_id,
@@ -178,7 +178,7 @@ class StreamEventProcessor:
178
178
  if self._diagnostics.completion_observed:
179
179
  return
180
180
  self._diagnostics.completion_observed = True
181
- logger.info(
181
+ logger.debug(
182
182
  "Codex event stream completion observed task_id=%s session_id=%s "
183
183
  "emitted_chunk_count=%s suppressed_chunk_count=%s",
184
184
  self._task_id,
@@ -192,7 +192,7 @@ class StreamEventProcessor:
192
192
  if self._completion_event.is_set():
193
193
  await self.observe_completion(logger)
194
194
  snapshot = self._diagnostics.snapshot(now=time.monotonic(), stream_open=False)
195
- logger.info(
195
+ logger.debug(
196
196
  "Codex event stream closed task_id=%s session_id=%s completion_observed=%s "
197
197
  "emitted_chunk_count=%s suppressed_chunk_count=%s started_ms_ago=%s "
198
198
  "last_upstream_event_ms_ago=%s last_visible_chunk_ms_ago=%s idle_log_count=%s",
@@ -334,7 +334,7 @@ class CodexThreadLifecycleRuntime:
334
334
  if subscription is None:
335
335
  return
336
336
  if subscription.connection_scope != self._client.connection_scope_id:
337
- logger.info(
337
+ logger.debug(
338
338
  "Skipping upstream thread/unsubscribe for subscription %s because "
339
339
  "connection_scope changed from %s to %s",
340
340
  subscription_key,
@@ -343,7 +343,7 @@ class CodexThreadLifecycleRuntime:
343
343
  )
344
344
  return
345
345
  if not subscription.thread_filter:
346
- logger.info(
346
+ logger.debug(
347
347
  "Skipping upstream thread/unsubscribe for subscription %s because "
348
348
  "thread_filter is not concrete",
349
349
  subscription_key,
@@ -241,13 +241,13 @@ def _normalize_log_level(value: str) -> str:
241
241
  normalized = (value or "").strip().upper()
242
242
  if normalized in {"CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"}:
243
243
  return normalized
244
- return "INFO"
244
+ return "WARNING"
245
245
 
246
246
 
247
247
  def _configure_logging(level: str) -> None:
248
248
  install_log_record_factory()
249
249
  logging.basicConfig(
250
- level=getattr(logging, level, logging.INFO),
250
+ level=getattr(logging, level, logging.WARNING),
251
251
  format=(
252
252
  "%(asctime)s %(levelname)s %(name)s [correlation_id=%(correlation_id)s]: %(message)s"
253
253
  ),
@@ -633,11 +633,11 @@ def install_http_middlewares(
633
633
  token = set_correlation_id(correlation_id)
634
634
  started_at = time.perf_counter()
635
635
  path = request.url.path
636
- logger.info("A2A request started method=%s path=%s", request.method, path)
636
+ logger.debug("A2A request started method=%s path=%s", request.method, path)
637
637
  try:
638
638
  response = await call_next(request)
639
639
  response.headers[CORRELATION_ID_HEADER] = correlation_id
640
- logger.info(
640
+ logger.debug(
641
641
  "A2A request completed method=%s path=%s status=%s duration_ms=%.2f",
642
642
  request.method,
643
643
  path,
@@ -386,7 +386,7 @@ class CodexRequestHandler(DefaultRequestHandler):
386
386
  ):
387
387
  yield event
388
388
  except (asyncio.CancelledError, GeneratorExit):
389
- logger.warning("Client disconnected. Cancelling producer task %s", task_id)
389
+ logger.debug("Client disconnected. Cancelling producer task %s", task_id)
390
390
  if producer_task is not None:
391
391
  producer_task.cancel()
392
392
  if queue is not None:
@@ -472,7 +472,7 @@ class CodexRequestHandler(DefaultRequestHandler):
472
472
  else:
473
473
  try:
474
474
  if asyncio.current_task() and asyncio.current_task().cancelled():
475
- logger.warning(
475
+ logger.debug(
476
476
  "Client disconnected from message request. Cancelling task %s", task_id
477
477
  )
478
478
  producer_task.cancel()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-a2a
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Codex A2A runtime adapter
5
5
  Author: liujuanjuan1984@Intelligent-Internet
6
6
  License-Expression: Apache-2.0
@@ -3,13 +3,16 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  import pytest
6
+ from a2a.client.auth.interceptor import AuthInterceptor
6
7
  from a2a.types import (
7
8
  AgentCapabilities,
8
9
  AgentCard,
9
10
  Artifact,
11
+ HTTPAuthSecurityScheme,
10
12
  Message,
11
13
  Part,
12
14
  Role,
15
+ SecurityScheme,
13
16
  Task,
14
17
  TaskArtifactUpdateEvent,
15
18
  TaskIdParams,
@@ -23,6 +26,7 @@ from codex_a2a.client import (
23
26
  A2AClient,
24
27
  A2AClientConfig,
25
28
  A2AUnsupportedBindingError,
29
+ StaticCredentialService,
26
30
  )
27
31
  from codex_a2a.client.types import A2ACancelTaskRequest, A2AGetTaskRequest, A2ASendRequest
28
32
 
@@ -203,6 +207,55 @@ async def test_build_client_maps_unsupported_transport_binding() -> None:
203
207
  await client._build_client()
204
208
 
205
209
 
210
+ def test_build_interceptors_adds_sdk_auth_interceptor_for_config_credentials() -> None:
211
+ client = A2AClient(
212
+ A2AClientConfig(
213
+ agent_url="https://example.org",
214
+ auth_credentials={"bearerAuth": "peer-token"},
215
+ ),
216
+ httpx_client=_MockAsyncHttpClient(),
217
+ card_resolver_factory=_MockAgentCardResolver,
218
+ )
219
+
220
+ interceptors = client._build_interceptors() # noqa: SLF001
221
+
222
+ assert any(isinstance(interceptor, AuthInterceptor) for interceptor in interceptors)
223
+
224
+
225
+ @pytest.mark.asyncio
226
+ async def test_static_credential_service_works_with_sdk_auth_interceptor() -> None:
227
+ card = AgentCard(
228
+ name="mock",
229
+ description="mock agent",
230
+ url="https://example.org",
231
+ version="1.0.0",
232
+ capabilities=AgentCapabilities(),
233
+ default_input_modes=["text/plain"],
234
+ default_output_modes=["text/plain"],
235
+ skills=[],
236
+ security_schemes={
237
+ "bearerAuth": SecurityScheme(
238
+ root=HTTPAuthSecurityScheme(
239
+ scheme="bearer",
240
+ bearer_format="opaque",
241
+ )
242
+ )
243
+ },
244
+ security=[{"bearerAuth": []}],
245
+ )
246
+ interceptor = AuthInterceptor(StaticCredentialService({"bearerAuth": "peer-token"}))
247
+
248
+ _payload, http_kwargs = await interceptor.intercept(
249
+ "message/send",
250
+ {},
251
+ {},
252
+ card,
253
+ None,
254
+ )
255
+
256
+ assert http_kwargs["headers"]["Authorization"] == "Bearer peer-token"
257
+
258
+
206
259
  def test_extract_text_prefers_stream_artifact_payload() -> None:
207
260
  task = Task(
208
261
  id="remote-task",
@@ -76,6 +76,7 @@ def test_settings_valid():
76
76
  assert settings.a2a_version == __version__
77
77
  assert settings.a2a_protocol_version == "0.3.0"
78
78
  assert settings.a2a_supported_protocol_versions == ["0.3", "1.0"]
79
+ assert settings.a2a_log_level == "WARNING"
79
80
 
80
81
 
81
82
  def test_settings_parse_a2a_supported_protocol_versions() -> None:
@@ -142,3 +142,21 @@ def test_tool_delta_chunks_normalizes_payload_and_rejects_unstructured_payload(c
142
142
 
143
143
  assert rejected == []
144
144
  assert "Suppressing non-structured tool_call payload" in caplog.text
145
+ assert "payload_type=str" in caplog.text
146
+ assert "bad-payload" not in caplog.text
147
+
148
+ caplog.clear()
149
+ with caplog.at_level(logging.WARNING):
150
+ rejected = tool_delta_chunks(
151
+ state=state,
152
+ delta_value={"unexpected": "secret-value"},
153
+ message_id=None,
154
+ source="delta",
155
+ task_id="task-1",
156
+ session_id="ses-1",
157
+ )
158
+
159
+ assert rejected == []
160
+ assert "Suppressing unrecognized tool_call payload" in caplog.text
161
+ assert "payload_keys=['unexpected']" in caplog.text
162
+ assert "secret-value" not in caplog.text
@@ -1899,7 +1899,7 @@ async def test_streaming_logs_idle_diagnostics_at_debug_when_only_transport_keep
1899
1899
 
1900
1900
 
1901
1901
  @pytest.mark.asyncio
1902
- async def test_streaming_logs_completion_observed_in_close_diagnostics(
1902
+ async def test_streaming_logs_completion_observed_in_close_diagnostics_at_debug(
1903
1903
  monkeypatch: pytest.MonkeyPatch,
1904
1904
  caplog: pytest.LogCaptureFixture,
1905
1905
  ) -> None:
@@ -1922,7 +1922,7 @@ async def test_streaming_logs_completion_observed_in_close_diagnostics(
1922
1922
  executor._should_stream = lambda context: True # type: ignore[method-assign]
1923
1923
  queue = DummyEventQueue()
1924
1924
 
1925
- caplog.set_level(logging.INFO, logger="codex_a2a.execution.streaming")
1925
+ caplog.set_level(logging.DEBUG, logger="codex_a2a.execution.streaming")
1926
1926
 
1927
1927
  await executor.execute(
1928
1928
  make_request_context(task_id="task-close-log", context_id="ctx-close-log", text="go"),
@@ -9,6 +9,7 @@ import pytest
9
9
  sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
10
10
 
11
11
  import codex_a2a.cli as cli
12
+ import codex_a2a.server.application as app_module
12
13
  from codex_a2a import __version__
13
14
 
14
15
 
@@ -39,3 +40,8 @@ def test_cli_defaults_to_serve_when_no_subcommand() -> None:
39
40
  assert cli.main([]) == 0
40
41
 
41
42
  serve_mock.assert_called_once_with()
43
+
44
+
45
+ def test_normalize_log_level_defaults_invalid_values_to_warning() -> None:
46
+ assert app_module._normalize_log_level("debug") == "DEBUG"
47
+ assert app_module._normalize_log_level("not-a-level") == "WARNING"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes