opencode-a2a 1.1.0__tar.gz → 1.1.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.
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/.github/dependabot.yml +5 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/AGENTS.md +2 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/PKG-INFO +9 -9
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/README.md +6 -6
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/pyproject.toml +2 -2
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/a2a_protocol.py +0 -1
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/a2a_utils.py +0 -4
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/cli.py +15 -10
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/coordinator.py +1 -1
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/executor.py +0 -43
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/extension_negotiation.py +2 -4
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/interrupt_queries.py +14 -13
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/output_modes.py +20 -44
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/application.py +16 -13
- opencode_a2a-1.1.2/src/opencode_a2a/server/context_helpers.py +76 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/middleware.py +3 -3
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/task_store.py +2 -3
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/task_store_sdk_compat.py +3 -4
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a.egg-info/PKG-INFO +9 -9
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a.egg-info/SOURCES.txt +2 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a.egg-info/requires.txt +2 -2
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_agent_helpers.py +33 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_metrics.py +4 -3
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_cli.py +28 -6
- opencode_a2a-1.1.2/tests/server/test_context_helpers.py +61 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_output_negotiation.py +61 -0
- opencode_a2a-1.1.2/tests/test_a2a_utils.py +100 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/uv.lock +79 -69
- opencode_a2a-1.1.0/src/opencode_a2a/server/context_helpers.py +0 -97
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/.github/workflows/dependency-review.yml +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/.github/workflows/publish.yml +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/.github/workflows/validate.yml +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/.gitignore +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/.pre-commit-config.yaml +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/.secrets.baseline +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/CODE_OF_CONDUCT.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/CONTRIBUTING.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/LICENSE +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/MANIFEST.in +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/SECURITY.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/SUPPORT.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/docs/architecture.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/docs/compatibility.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/docs/conformance-triage.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/docs/conformance.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/docs/extension-specifications.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/docs/guide.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/docs/maintainer-architecture.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/README.md +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/check_coverage.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/conformance.sh +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/dependency_health.sh +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/doctor.sh +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/find_thin_wrappers.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/health_common.sh +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/lint.sh +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/scripts/smoke_test_built_cli.sh +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/setup.cfg +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/auth.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/agent_card.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/auth.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/client.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/config.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/error_mapping.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/errors.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/payload_text.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/polling.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/client/request_context.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/config.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/extensions/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/extensions/capabilities.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/extensions/catalog.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/extensions/compatibility.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/extensions/contract_docs.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/extensions/identifiers.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/extensions/private_params.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/contracts/extensions/public_params.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/event_helpers.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/metrics.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/session_manager.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/stream_events.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/stream_runtime.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/stream_state.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/tool_error_mapping.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/tool_orchestration.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/execution/upstream_error_translator.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/interrupt_request_tracker.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/application.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/dispatch.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/error_responses.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/common.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/interrupt_callbacks.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/provider_discovery.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/session_control.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/session_lifecycle.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/session_queries.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/workspace_control.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/methods.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/models.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/params.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/metadata_access.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/opencode_upstream_client.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/parsing.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/parts/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/parts/mapping.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/parts/text.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/profile/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/profile/runtime.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/protocol_versions.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/py.typed +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/runtime_state.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/sandbox_policy.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/agent_card.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/client_manager.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/database.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/lifespan.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/migrations.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/openapi.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/request_parsing.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/rest_tasks.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/server/state_store.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/task_states.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/trace_context.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/upstream_taxonomy.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a.egg-info/dependency_links.txt +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a.egg-info/entry_points.txt +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a.egg-info/top_level.txt +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/client/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/client/test_agent_card.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/client/test_client_config.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/client/test_client_facade.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/client/test_error_mapping.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/client/test_payload_text.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/client/test_polling.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/client/test_request_context.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/config/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/config/test_settings.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/conftest.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/contracts/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/contracts/test_extension_contract_consistency.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_agent_errors.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_cancellation.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_directory_validation.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_multipart_input.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_opencode_agent_session_binding.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_session_lock_lifecycle.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_session_ownership.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_streaming_output_contract_blocks.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_streaming_output_contract_core.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_streaming_output_contract_interrupts.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/execution/test_streaming_output_contract_logging.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_application_dispatch.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_dispatch_registry.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_error_responses.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_jsonrpc_methods.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_jsonrpc_params.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_jsonrpc_unsupported_method.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_opencode_session_extension_commands.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_opencode_session_extension_interrupts.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_opencode_session_extension_lifecycle.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_opencode_session_extension_prompt_async.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_opencode_session_extension_queries.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/jsonrpc/test_opencode_workspace_control_extension.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/package/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/package/test_logging.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/package/test_typing_contract.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/package/test_version.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/parts/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/parts/test_parts_text.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/profile/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/profile/test_profile_runtime.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/scripts/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/scripts/test_script_health_contract.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_a2a_client_manager.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_agent_card.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_app_behaviors.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_auth.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_call_context_builder.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_cancel_contract.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_database_app_persistence.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_state_store.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_task_store_factory.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/server/test_transport_contract.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/async_iterators.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/fake_client_errors.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/helpers.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/interrupt_clients.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/jsonrpc_error_assertions.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/session_extensions.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/session_query_client.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/settings.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/streaming_output.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/support/workspace_control_client.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/test_metadata_access.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/test_parsing.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/test_trace_context.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/upstream/__init__.py +0 -0
- {opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/tests/upstream/test_opencode_upstream_client_params.py +0 -0
|
@@ -5,6 +5,11 @@ updates:
|
|
|
5
5
|
directory: "/"
|
|
6
6
|
schedule:
|
|
7
7
|
interval: "weekly"
|
|
8
|
+
ignore:
|
|
9
|
+
# a2a-sdk still constrains protobuf to <7, so major protobuf bumps are unsatisfiable.
|
|
10
|
+
- dependency-name: "protobuf"
|
|
11
|
+
update-types:
|
|
12
|
+
- "version-update:semver-major"
|
|
8
13
|
open-pull-requests-limit: 1
|
|
9
14
|
commit-message:
|
|
10
15
|
prefix: "deps"
|
|
@@ -11,6 +11,8 @@ The following rules apply to coding agent collaboration in this repository. Thes
|
|
|
11
11
|
|
|
12
12
|
- Follow the Git, Issue, and PR workflow defined in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
13
13
|
- Use `gh` CLI for all issue/PR operations (reading, writing, and comments). Do not edit through the web UI.
|
|
14
|
+
- Do not use the Codex GitHub connector for any repository operation. Use `gh` CLI exclusively for issue, PR, review, comment, and metadata workflows.
|
|
15
|
+
- If `gh` CLI cannot complete a required GitHub operation because of permissions, authentication, or environment limits, stop and ask the human to perform or unblock the operation. Do not fall back to the Codex GitHub connector.
|
|
14
16
|
- Create a new tracking issue for any development task that does not already have one.
|
|
15
17
|
- Link the issue explicitly in PR descriptions (e.g., `Closes #xx`).
|
|
16
18
|
- Keep status updates synchronized to the relevant issue/PR to avoid duplicate manual work.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencode-a2a
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.2
|
|
4
4
|
Summary: OpenCode A2A runtime
|
|
5
5
|
Author: liujuanjuan1984@Intelligent-Internet
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -21,10 +21,10 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: a2a-sdk==1.0.2
|
|
23
23
|
Requires-Dist: aiosqlite<1.0,>=0.20
|
|
24
|
-
Requires-Dist: fastapi<1.0,>=0.
|
|
24
|
+
Requires-Dist: fastapi<1.0,>=0.139
|
|
25
25
|
Requires-Dist: httpx<1.0,>=0.27
|
|
26
26
|
Requires-Dist: pydantic<3.0,>=2.6
|
|
27
|
-
Requires-Dist: pydantic-settings<3.0,>=2.2
|
|
27
|
+
Requires-Dist: pydantic-settings<3.0,>=2.14.2
|
|
28
28
|
Requires-Dist: protobuf<7.0,>=6.33.5
|
|
29
29
|
Requires-Dist: sqlalchemy<3.0,>=2.0
|
|
30
30
|
Requires-Dist: sse-starlette<4.0,>=2.1
|
|
@@ -43,12 +43,12 @@ Dynamic: license-file
|
|
|
43
43
|
# opencode-a2a
|
|
44
44
|
|
|
45
45
|
```text
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
██████╗ ██████╗ ███████╗███╗ ██╗ ██████╗ ██████╗ ██████╗ ███████╗ █████╗ ██████╗ █████╗
|
|
47
|
+
██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔══██╗╚════██╗██╔══██╗
|
|
48
|
+
██║ ██║██████╔╝█████╗ ██╔██╗ ██║██║ ██║ ██║██║ ██║█████╗█████╗███████║ █████╔╝███████║
|
|
49
|
+
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██║ ██║ ██║██║ ██║██╔══╝╚════╝██╔══██║██╔═══╝ ██╔══██║
|
|
50
|
+
╚██████╔╝██║ ███████╗██║ ╚████║╚██████╗╚██████╔╝██████╔╝███████╗ ██║ ██║███████╗██║ ██║
|
|
51
|
+
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
> Expose OpenCode through A2A.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# opencode-a2a
|
|
2
2
|
|
|
3
3
|
```text
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
██████╗ ██████╗ ███████╗███╗ ██╗ ██████╗ ██████╗ ██████╗ ███████╗ █████╗ ██████╗ █████╗
|
|
5
|
+
██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔══██╗╚════██╗██╔══██╗
|
|
6
|
+
██║ ██║██████╔╝█████╗ ██╔██╗ ██║██║ ██║ ██║██║ ██║█████╗█████╗███████║ █████╔╝███████║
|
|
7
|
+
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██║ ██║ ██║██║ ██║██╔══╝╚════╝██╔══██║██╔═══╝ ██╔══██║
|
|
8
|
+
╚██████╔╝██║ ███████╗██║ ╚████║╚██████╗╚██████╔╝██████╔╝███████╗ ██║ ██║███████╗██║ ██║
|
|
9
|
+
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
> Expose OpenCode through A2A.
|
|
@@ -26,10 +26,10 @@ classifiers = [
|
|
|
26
26
|
dependencies = [
|
|
27
27
|
"a2a-sdk==1.0.2",
|
|
28
28
|
"aiosqlite>=0.20,<1.0",
|
|
29
|
-
"fastapi>=0.
|
|
29
|
+
"fastapi>=0.139,<1.0",
|
|
30
30
|
"httpx>=0.27,<1.0",
|
|
31
31
|
"pydantic>=2.6,<3.0",
|
|
32
|
-
"pydantic-settings>=2.2,<3.0",
|
|
32
|
+
"pydantic-settings>=2.14.2,<3.0",
|
|
33
33
|
"protobuf>=6.33.5,<7.0",
|
|
34
34
|
"sqlalchemy>=2.0,<3.0",
|
|
35
35
|
"sse-starlette>=2.1,<4.0",
|
|
@@ -5,5 +5,4 @@ from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH as SDK_AGENT_CARD_WEL
|
|
|
5
5
|
|
|
6
6
|
AGENT_CARD_WELL_KNOWN_PATH = SDK_AGENT_CARD_WELL_KNOWN_PATH
|
|
7
7
|
EXTENDED_AGENT_CARD_PATH = "/extendedAgentCard"
|
|
8
|
-
EXTENDED_AGENT_CARD_PATHS = (EXTENDED_AGENT_CARD_PATH,)
|
|
9
8
|
CORE_JSONRPC_METHODS = tuple(JsonRpcDispatcher.METHOD_TO_MODEL)
|
|
@@ -16,10 +16,6 @@ def clone_proto(message: ProtoT) -> ProtoT:
|
|
|
16
16
|
return cloned
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def proto_equals(left: ProtoMessage, right: ProtoMessage) -> bool:
|
|
20
|
-
return bool(left == right)
|
|
21
|
-
|
|
22
|
-
|
|
23
19
|
def _to_proto_value(value: Any) -> Value:
|
|
24
20
|
proto_value = Value()
|
|
25
21
|
if value is None:
|
|
@@ -15,12 +15,18 @@ from .config import Settings
|
|
|
15
15
|
from .server.application import main as serve_main
|
|
16
16
|
|
|
17
17
|
CLI_BRAND_BANNER = (
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
18
|
+
" ██████╗ ██████╗ ███████╗███╗ ██╗ ██████╗ ██████╗"
|
|
19
|
+
" ██████╗ ███████╗ █████╗ ██████╗ █████╗ \n"
|
|
20
|
+
"██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔════╝██╔═══██╗"
|
|
21
|
+
"██╔══██╗██╔════╝ ██╔══██╗╚════██╗██╔══██╗\n"
|
|
22
|
+
"██║ ██║██████╔╝█████╗ ██╔██╗ ██║██║ ██║ ██║"
|
|
23
|
+
"██║ ██║█████╗█████╗███████║ █████╔╝███████║\n"
|
|
24
|
+
"██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██║ ██║ ██║"
|
|
25
|
+
"██║ ██║██╔══╝╚════╝██╔══██║██╔═══╝ ██╔══██║\n"
|
|
26
|
+
"╚██████╔╝██║ ███████╗██║ ╚████║╚██████╗╚██████╔╝"
|
|
27
|
+
"██████╔╝███████╗ ██║ ██║███████╗██║ ██║\n"
|
|
28
|
+
" ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝"
|
|
29
|
+
" ╚═════╝ ╚══════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝"
|
|
24
30
|
)
|
|
25
31
|
PROJECT_REPOSITORY_URL = "https://github.com/Intelligent-Internet/opencode-a2a"
|
|
26
32
|
HELP_FLAGS = frozenset({"-h", "--help"})
|
|
@@ -95,9 +101,8 @@ CALL_HELP = (
|
|
|
95
101
|
" Service base URLs also work, but card URLs are the preferred example form."
|
|
96
102
|
)
|
|
97
103
|
|
|
98
|
-
ROOT_HELP_EPILOG =
|
|
104
|
+
ROOT_HELP_EPILOG = "Command-specific help:\n opencode-a2a serve --help\n opencode-a2a call --help"
|
|
99
105
|
SERVE_HELP_EPILOG = f"{OPENCODE_SETUP_HELP}\n\n{SERVE_ENVIRONMENT_HELP}"
|
|
100
|
-
CALL_HELP_EPILOG = CALL_HELP
|
|
101
106
|
|
|
102
107
|
|
|
103
108
|
class RootHelpFormatter(
|
|
@@ -224,7 +229,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
224
229
|
CLI_BRAND_BANNER
|
|
225
230
|
+ "\n\n"
|
|
226
231
|
+ f"repo: {PROJECT_REPOSITORY_URL}\n"
|
|
227
|
-
+ "uv tool install --upgrade opencode-a2a\n"
|
|
232
|
+
+ "uv tool install --upgrade opencode-a2a\n\n"
|
|
228
233
|
+ ROOT_DESCRIPTION
|
|
229
234
|
),
|
|
230
235
|
formatter_class=RootHelpFormatter,
|
|
@@ -258,7 +263,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
258
263
|
help="Call an A2A agent.",
|
|
259
264
|
description="Call an A2A agent using the A2A protocol. A2A Protocol 1.0 only.",
|
|
260
265
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
261
|
-
epilog=
|
|
266
|
+
epilog=CALL_HELP,
|
|
262
267
|
)
|
|
263
268
|
call_parser.add_argument(
|
|
264
269
|
"agent_url",
|
|
@@ -280,7 +280,7 @@ class ExecutionCoordinator:
|
|
|
280
280
|
if self._prepared.streaming_request:
|
|
281
281
|
self._stream_terminal_signal = asyncio.get_running_loop().create_future()
|
|
282
282
|
self._stream_task = asyncio.create_task(
|
|
283
|
-
self._executor.
|
|
283
|
+
self._executor._stream_runtime.consume(
|
|
284
284
|
session_id=self._session_id,
|
|
285
285
|
identity=self._prepared.identity,
|
|
286
286
|
task_id=self._task_id,
|
|
@@ -46,12 +46,6 @@ from .event_helpers import _enqueue_artifact_update
|
|
|
46
46
|
from .metrics import emit_metric
|
|
47
47
|
from .session_manager import SessionManager
|
|
48
48
|
from .stream_runtime import StreamRuntime
|
|
49
|
-
from .stream_state import (
|
|
50
|
-
_StreamOutputState,
|
|
51
|
-
)
|
|
52
|
-
from .upstream_error_translator import (
|
|
53
|
-
_StreamTerminalSignal,
|
|
54
|
-
)
|
|
55
49
|
|
|
56
50
|
logger = logging.getLogger(__name__)
|
|
57
51
|
_TEXT_PLAIN_MEDIA_TYPE = "text/plain"
|
|
@@ -497,40 +491,3 @@ class OpencodeAgentExecutor(AgentExecutor):
|
|
|
497
491
|
# JSON-RPC transport sets method in call context state.
|
|
498
492
|
method = call_context.state.get("method")
|
|
499
493
|
return method == "SendStreamingMessage"
|
|
500
|
-
|
|
501
|
-
async def _consume_opencode_stream(
|
|
502
|
-
self,
|
|
503
|
-
*,
|
|
504
|
-
session_id: str,
|
|
505
|
-
identity: str,
|
|
506
|
-
task_id: str,
|
|
507
|
-
context_id: str,
|
|
508
|
-
artifact_id: str,
|
|
509
|
-
stream_state: _StreamOutputState,
|
|
510
|
-
event_queue: EventQueue,
|
|
511
|
-
stop_event: asyncio.Event,
|
|
512
|
-
terminal_signal: asyncio.Future[_StreamTerminalSignal],
|
|
513
|
-
directory: str | None = None,
|
|
514
|
-
workspace_id: str | None = None,
|
|
515
|
-
allow_structured_output: bool = True,
|
|
516
|
-
emit_session_metadata: bool = True,
|
|
517
|
-
emit_streaming_metadata: bool = True,
|
|
518
|
-
emit_interrupt_metadata: bool = True,
|
|
519
|
-
) -> None:
|
|
520
|
-
await self._stream_runtime.consume(
|
|
521
|
-
session_id=session_id,
|
|
522
|
-
identity=identity,
|
|
523
|
-
task_id=task_id,
|
|
524
|
-
context_id=context_id,
|
|
525
|
-
artifact_id=artifact_id,
|
|
526
|
-
stream_state=stream_state,
|
|
527
|
-
event_queue=event_queue,
|
|
528
|
-
stop_event=stop_event,
|
|
529
|
-
terminal_signal=terminal_signal,
|
|
530
|
-
directory=directory,
|
|
531
|
-
workspace_id=workspace_id,
|
|
532
|
-
allow_structured_output=allow_structured_output,
|
|
533
|
-
emit_session_metadata=emit_session_metadata,
|
|
534
|
-
emit_streaming_metadata=emit_streaming_metadata,
|
|
535
|
-
emit_interrupt_metadata=emit_interrupt_metadata,
|
|
536
|
-
)
|
|
@@ -26,8 +26,7 @@ from .contracts.extensions import (
|
|
|
26
26
|
WORKSPACE_CONTROL_METHODS,
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
_STREAMING_SHARED_METADATA_KEYS =
|
|
30
|
-
_INTERRUPT_SHARED_METADATA_KEYS = frozenset({"interrupt"})
|
|
29
|
+
_STREAMING_SHARED_METADATA_KEYS = ("stream", "progress", "usage")
|
|
31
30
|
|
|
32
31
|
JSONRPC_EXTENSION_URI_BY_METHOD: dict[str, str] = {
|
|
33
32
|
**{method: SESSION_MANAGEMENT_EXTENSION_URI for method in SESSION_METHODS.values()},
|
|
@@ -107,8 +106,7 @@ def _set_filtered_metadata(
|
|
|
107
106
|
for key in _STREAMING_SHARED_METADATA_KEYS:
|
|
108
107
|
filtered_shared.pop(key, None)
|
|
109
108
|
if INTERRUPT_CALLBACK_EXTENSION_URI not in requested_extensions:
|
|
110
|
-
|
|
111
|
-
filtered_shared.pop(key, None)
|
|
109
|
+
filtered_shared.pop("interrupt", None)
|
|
112
110
|
if filtered_shared:
|
|
113
111
|
filtered_metadata["shared"] = filtered_shared
|
|
114
112
|
else:
|
{opencode_a2a-1.1.0 → opencode_a2a-1.1.2}/src/opencode_a2a/jsonrpc/handlers/interrupt_queries.py
RENAMED
|
@@ -10,18 +10,6 @@ from ..models import JSONRPCRequest
|
|
|
10
10
|
from .common import build_internal_error_response, build_success_response, reject_unknown_fields
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def _binding_to_result_item(binding: Any) -> dict[str, Any]:
|
|
14
|
-
return {
|
|
15
|
-
"request_id": binding.request_id,
|
|
16
|
-
"session_id": binding.session_id,
|
|
17
|
-
"interrupt_type": binding.interrupt_type,
|
|
18
|
-
"task_id": binding.task_id,
|
|
19
|
-
"context_id": binding.context_id,
|
|
20
|
-
"details": dict(binding.details) if isinstance(binding.details, dict) else None,
|
|
21
|
-
"expires_at": binding.expires_at,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
13
|
async def handle_interrupt_query_request(
|
|
26
14
|
context: ExtensionHandlerContext,
|
|
27
15
|
base_request: JSONRPCRequest,
|
|
@@ -58,5 +46,18 @@ async def handle_interrupt_query_request(
|
|
|
58
46
|
return build_success_response(
|
|
59
47
|
context,
|
|
60
48
|
base_request.id,
|
|
61
|
-
{
|
|
49
|
+
{
|
|
50
|
+
"items": [
|
|
51
|
+
{
|
|
52
|
+
"request_id": item.request_id,
|
|
53
|
+
"session_id": item.session_id,
|
|
54
|
+
"interrupt_type": item.interrupt_type,
|
|
55
|
+
"task_id": item.task_id,
|
|
56
|
+
"context_id": item.context_id,
|
|
57
|
+
"details": dict(item.details) if isinstance(item.details, dict) else None,
|
|
58
|
+
"expires_at": item.expires_at,
|
|
59
|
+
}
|
|
60
|
+
for item in items
|
|
61
|
+
]
|
|
62
|
+
},
|
|
62
63
|
)
|
|
@@ -32,35 +32,21 @@ OUTPUT_NEGOTIATION_ACCEPTED_OUTPUT_MODES_FIELD = "accepted_output_modes"
|
|
|
32
32
|
_OPENCODE_METADATA_KEY = "opencode"
|
|
33
33
|
_APPLICATION_JSON_MEDIA_TYPE = "application/json"
|
|
34
34
|
_TEXT_PLAIN_MEDIA_TYPE = "text/plain"
|
|
35
|
-
_STREAM_METADATA_SHARED_KEY = "shared"
|
|
36
|
-
_STREAM_METADATA_STREAM_KEY = "stream"
|
|
37
|
-
_STREAM_METADATA_BLOCK_TYPE_KEY = "block_type"
|
|
38
35
|
|
|
39
36
|
|
|
40
|
-
def
|
|
37
|
+
def normalize_accepted_output_modes(source: Any) -> tuple[str, ...] | None:
|
|
41
38
|
if source is None:
|
|
42
39
|
return None
|
|
43
|
-
|
|
44
40
|
accepted = getattr(source, "accepted_output_modes", None) or getattr(
|
|
45
41
|
source, "acceptedOutputModes", None
|
|
46
42
|
)
|
|
47
43
|
if accepted is not None:
|
|
48
44
|
source = accepted
|
|
49
|
-
|
|
50
|
-
if isinstance(source, str | bytes | bytearray | dict):
|
|
51
|
-
return None
|
|
52
|
-
if not isinstance(source, Iterable):
|
|
53
|
-
return None
|
|
54
|
-
return cast(Iterable[str], source)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def normalize_accepted_output_modes(source: Any) -> tuple[str, ...] | None:
|
|
58
|
-
accepted = _accepted_output_modes_source(source)
|
|
59
|
-
if accepted is None:
|
|
45
|
+
if isinstance(source, str | bytes | bytearray | dict) or not isinstance(source, Iterable):
|
|
60
46
|
return None
|
|
61
47
|
|
|
62
48
|
normalized: list[str] = []
|
|
63
|
-
for value in
|
|
49
|
+
for value in cast(Iterable[str], source):
|
|
64
50
|
if not isinstance(value, str):
|
|
65
51
|
continue
|
|
66
52
|
mode = value.strip().lower()
|
|
@@ -194,9 +180,11 @@ def apply_accepted_output_modes(
|
|
|
194
180
|
return replace_artifact_event_artifact(payload, artifact)
|
|
195
181
|
|
|
196
182
|
if isinstance(payload, TaskStatusUpdateEvent):
|
|
197
|
-
message =
|
|
198
|
-
|
|
199
|
-
|
|
183
|
+
message = (
|
|
184
|
+
_filter_message(payload.status.message, normalized)
|
|
185
|
+
if payload.status.HasField("message")
|
|
186
|
+
else None
|
|
187
|
+
)
|
|
200
188
|
return replace_status_event_message(payload, message)
|
|
201
189
|
|
|
202
190
|
if isinstance(payload, Task):
|
|
@@ -217,13 +205,13 @@ def _extract_artifact_stream_block_type(artifact: Artifact | None) -> str | None
|
|
|
217
205
|
metadata = _normalize_metadata_mapping(artifact.metadata)
|
|
218
206
|
if not metadata:
|
|
219
207
|
return None
|
|
220
|
-
shared = metadata.get(
|
|
208
|
+
shared = metadata.get("shared")
|
|
221
209
|
if not isinstance(shared, dict):
|
|
222
210
|
return None
|
|
223
|
-
stream = shared.get(
|
|
211
|
+
stream = shared.get("stream")
|
|
224
212
|
if not isinstance(stream, dict):
|
|
225
213
|
return None
|
|
226
|
-
block_type = stream.get(
|
|
214
|
+
block_type = stream.get("block_type")
|
|
227
215
|
return block_type.strip() if isinstance(block_type, str) and block_type.strip() else None
|
|
228
216
|
|
|
229
217
|
|
|
@@ -375,7 +363,7 @@ class NegotiatingResultAggregator(ResultAggregator):
|
|
|
375
363
|
def _filter_task(task: Task, accepted_output_modes: Collection[str]) -> Task:
|
|
376
364
|
updated = clone_proto(task)
|
|
377
365
|
if updated.status.HasField("message"):
|
|
378
|
-
filtered_message =
|
|
366
|
+
filtered_message = _filter_message(updated.status.message, accepted_output_modes)
|
|
379
367
|
if filtered_message is None:
|
|
380
368
|
updated.status.ClearField("message")
|
|
381
369
|
else:
|
|
@@ -404,15 +392,6 @@ def _filter_task(task: Task, accepted_output_modes: Collection[str]) -> Task:
|
|
|
404
392
|
return updated
|
|
405
393
|
|
|
406
394
|
|
|
407
|
-
def _filter_optional_message(
|
|
408
|
-
message: Message | None,
|
|
409
|
-
accepted_output_modes: Collection[str],
|
|
410
|
-
) -> Message | None:
|
|
411
|
-
if message is None:
|
|
412
|
-
return None
|
|
413
|
-
return _filter_message(message, accepted_output_modes)
|
|
414
|
-
|
|
415
|
-
|
|
416
395
|
def _filter_message(
|
|
417
396
|
message: Message,
|
|
418
397
|
accepted_output_modes: Collection[str],
|
|
@@ -439,7 +418,14 @@ def _filter_parts(
|
|
|
439
418
|
) -> list[Part]:
|
|
440
419
|
filtered: list[Part] = []
|
|
441
420
|
for part in parts:
|
|
442
|
-
|
|
421
|
+
if part.HasField("text"):
|
|
422
|
+
media_type = _TEXT_PLAIN_MEDIA_TYPE
|
|
423
|
+
elif part.HasField("data"):
|
|
424
|
+
media_type = _APPLICATION_JSON_MEDIA_TYPE
|
|
425
|
+
elif part.HasField("raw") or part.HasField("url"):
|
|
426
|
+
media_type = part.media_type or "application/octet-stream"
|
|
427
|
+
else:
|
|
428
|
+
media_type = None
|
|
443
429
|
if media_type is None or accepts_output_mode(accepted_output_modes, media_type):
|
|
444
430
|
filtered.append(part)
|
|
445
431
|
continue
|
|
@@ -459,13 +445,3 @@ def _filter_parts(
|
|
|
459
445
|
)
|
|
460
446
|
)
|
|
461
447
|
return filtered
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
def _part_media_type(part: Part) -> str | None:
|
|
465
|
-
if part.HasField("text"):
|
|
466
|
-
return _TEXT_PLAIN_MEDIA_TYPE
|
|
467
|
-
if part.HasField("data"):
|
|
468
|
-
return _APPLICATION_JSON_MEDIA_TYPE
|
|
469
|
-
if part.HasField("raw") or part.HasField("url"):
|
|
470
|
-
return part.media_type or "application/octet-stream"
|
|
471
|
-
return None
|
|
@@ -259,17 +259,6 @@ class OpencodeRequestHandler(LegacyRequestHandler):
|
|
|
259
259
|
return "Task store unavailable while deleting task state."
|
|
260
260
|
return "Task store unavailable."
|
|
261
261
|
|
|
262
|
-
@classmethod
|
|
263
|
-
def _task_store_failure_metadata(cls, operation: str) -> dict[str, dict[str, dict[str, str]]]:
|
|
264
|
-
return {
|
|
265
|
-
"opencode": {
|
|
266
|
-
"error": {
|
|
267
|
-
"type": TASK_STORE_ERROR_TYPE,
|
|
268
|
-
"operation": operation,
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
262
|
@classmethod
|
|
274
263
|
def _task_store_server_error(cls, exc: TaskStoreOperationError) -> InternalError:
|
|
275
264
|
return InternalError(message=cls._task_store_failure_message(exc.operation))
|
|
@@ -295,7 +284,14 @@ class OpencodeRequestHandler(LegacyRequestHandler):
|
|
|
295
284
|
context_id=context_id,
|
|
296
285
|
status=TaskStatus(state=TaskState.TASK_STATE_FAILED, message=error_message),
|
|
297
286
|
history=[error_message],
|
|
298
|
-
metadata=
|
|
287
|
+
metadata={
|
|
288
|
+
"opencode": {
|
|
289
|
+
"error": {
|
|
290
|
+
"type": TASK_STORE_ERROR_TYPE,
|
|
291
|
+
"operation": operation,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
},
|
|
299
295
|
)
|
|
300
296
|
|
|
301
297
|
@classmethod
|
|
@@ -322,7 +318,14 @@ class OpencodeRequestHandler(LegacyRequestHandler):
|
|
|
322
318
|
task_id=task_id,
|
|
323
319
|
context_id=context_id,
|
|
324
320
|
status=TaskStatus(state=TaskState.TASK_STATE_FAILED),
|
|
325
|
-
metadata=
|
|
321
|
+
metadata={
|
|
322
|
+
"opencode": {
|
|
323
|
+
"error": {
|
|
324
|
+
"type": TASK_STORE_ERROR_TYPE,
|
|
325
|
+
"operation": operation,
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
},
|
|
326
329
|
),
|
|
327
330
|
)
|
|
328
331
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping, MutableMapping
|
|
4
|
+
|
|
5
|
+
from a2a.auth.user import UnauthenticatedUser, User
|
|
6
|
+
from a2a.server.context import ServerCallContext
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AuthenticatedIdentityUser(User):
|
|
10
|
+
def __init__(self, identity: str) -> None:
|
|
11
|
+
self._identity = identity
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def is_authenticated(self) -> bool:
|
|
15
|
+
return True
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def user_name(self) -> str:
|
|
19
|
+
return self._identity
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def normalize_server_call_context(context: ServerCallContext | None) -> ServerCallContext:
|
|
23
|
+
if context is None:
|
|
24
|
+
return ServerCallContext()
|
|
25
|
+
|
|
26
|
+
raw_state = getattr(context, "state", None)
|
|
27
|
+
raw_requested_extensions = getattr(context, "requested_extensions", None)
|
|
28
|
+
raw_tenant = getattr(context, "tenant", "")
|
|
29
|
+
raw_user = getattr(context, "user", None)
|
|
30
|
+
|
|
31
|
+
if isinstance(raw_state, MutableMapping):
|
|
32
|
+
state = raw_state
|
|
33
|
+
elif isinstance(raw_state, Mapping):
|
|
34
|
+
state = dict(raw_state)
|
|
35
|
+
else:
|
|
36
|
+
state = {}
|
|
37
|
+
|
|
38
|
+
if raw_requested_extensions is None:
|
|
39
|
+
requested_extensions: set[str] = set()
|
|
40
|
+
elif isinstance(raw_requested_extensions, set):
|
|
41
|
+
requested_extensions = raw_requested_extensions
|
|
42
|
+
elif isinstance(raw_requested_extensions, str):
|
|
43
|
+
requested_extensions = {raw_requested_extensions}
|
|
44
|
+
else:
|
|
45
|
+
try:
|
|
46
|
+
requested_extensions = {str(value) for value in raw_requested_extensions}
|
|
47
|
+
except TypeError:
|
|
48
|
+
requested_extensions = set()
|
|
49
|
+
|
|
50
|
+
tenant = raw_tenant if isinstance(raw_tenant, str) else ""
|
|
51
|
+
identity = state.get("identity")
|
|
52
|
+
normalized_identity = identity if isinstance(identity, str) else None
|
|
53
|
+
if normalized_identity and (
|
|
54
|
+
not isinstance(raw_user, User) or isinstance(raw_user, UnauthenticatedUser)
|
|
55
|
+
):
|
|
56
|
+
user: User = AuthenticatedIdentityUser(normalized_identity)
|
|
57
|
+
elif isinstance(raw_user, User):
|
|
58
|
+
user = raw_user
|
|
59
|
+
else:
|
|
60
|
+
user = UnauthenticatedUser()
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
isinstance(context, ServerCallContext)
|
|
64
|
+
and raw_state is state
|
|
65
|
+
and raw_user is user
|
|
66
|
+
and raw_tenant == tenant
|
|
67
|
+
and raw_requested_extensions == requested_extensions
|
|
68
|
+
):
|
|
69
|
+
return context
|
|
70
|
+
|
|
71
|
+
return ServerCallContext(
|
|
72
|
+
state=state,
|
|
73
|
+
user=user,
|
|
74
|
+
tenant=tenant,
|
|
75
|
+
requested_extensions=requested_extensions,
|
|
76
|
+
)
|
|
@@ -14,7 +14,7 @@ from starlette.responses import StreamingResponse
|
|
|
14
14
|
|
|
15
15
|
from ..a2a_protocol import (
|
|
16
16
|
AGENT_CARD_WELL_KNOWN_PATH,
|
|
17
|
-
|
|
17
|
+
EXTENDED_AGENT_CARD_PATH,
|
|
18
18
|
)
|
|
19
19
|
from ..auth import (
|
|
20
20
|
authenticate_static_credential,
|
|
@@ -289,7 +289,7 @@ def install_runtime_middlewares(
|
|
|
289
289
|
path = request.url.path
|
|
290
290
|
if path == AGENT_CARD_WELL_KNOWN_PATH:
|
|
291
291
|
supported_extensions = PUBLIC_EXTENSION_URIS
|
|
292
|
-
elif path
|
|
292
|
+
elif path == EXTENDED_AGENT_CARD_PATH:
|
|
293
293
|
supported_extensions = ALL_EXTENSION_URIS
|
|
294
294
|
elif path == "/" or path.startswith("/v1/"):
|
|
295
295
|
supported_extensions = PUBLIC_EXTENSION_URIS
|
|
@@ -313,7 +313,7 @@ def install_runtime_middlewares(
|
|
|
313
313
|
|
|
314
314
|
path = request.url.path
|
|
315
315
|
is_public_card = path == AGENT_CARD_WELL_KNOWN_PATH
|
|
316
|
-
is_extended_card = path
|
|
316
|
+
is_extended_card = path == EXTENDED_AGENT_CARD_PATH
|
|
317
317
|
if not is_public_card and not is_extended_card:
|
|
318
318
|
return await call_next(request)
|
|
319
319
|
|
|
@@ -14,7 +14,6 @@ from a2a.server.tasks.task_store import TaskStore
|
|
|
14
14
|
from a2a.types import ListTasksRequest, ListTasksResponse, Task
|
|
15
15
|
from sqlalchemy.engine import make_url
|
|
16
16
|
|
|
17
|
-
from ..a2a_utils import proto_equals
|
|
18
17
|
from ..config import Settings
|
|
19
18
|
from ..task_states import TERMINAL_TASK_STATES
|
|
20
19
|
from .context_helpers import normalize_server_call_context
|
|
@@ -67,7 +66,7 @@ class FirstTerminalStateWinsPolicy(TaskWritePolicy):
|
|
|
67
66
|
persist=False,
|
|
68
67
|
reason="state_overwrite_after_terminal_persistence",
|
|
69
68
|
)
|
|
70
|
-
if
|
|
69
|
+
if incoming != existing:
|
|
71
70
|
return TaskPersistenceDecision(
|
|
72
71
|
persist=False,
|
|
73
72
|
reason="late_mutation_after_terminal_persistence",
|
|
@@ -238,7 +237,7 @@ class PolicyAwareTaskStore(TaskStoreDecorator):
|
|
|
238
237
|
if (
|
|
239
238
|
existing is not None
|
|
240
239
|
and existing.status.state in TERMINAL_TASK_STATES
|
|
241
|
-
and
|
|
240
|
+
and existing == task
|
|
242
241
|
):
|
|
243
242
|
return
|
|
244
243
|
raise RuntimeError(
|
|
@@ -71,13 +71,12 @@ class DatabaseTaskStoreCompat:
|
|
|
71
71
|
self._task_store.engine.url.render_as_string(hide_password=True)
|
|
72
72
|
)
|
|
73
73
|
table_name = self._shape.task_model.__table__.name
|
|
74
|
-
required_indexes = frozenset({f"idx_{table_name}_owner_last_updated"})
|
|
75
74
|
async with self._task_store.engine.begin() as conn:
|
|
76
75
|
await conn.run_sync(
|
|
77
76
|
lambda sync_conn: _validate_sdk_task_table_schema(
|
|
78
77
|
sync_conn,
|
|
79
78
|
table_name=table_name,
|
|
80
|
-
|
|
79
|
+
required_index=f"idx_{table_name}_owner_last_updated",
|
|
81
80
|
database_url=database_url,
|
|
82
81
|
)
|
|
83
82
|
)
|
|
@@ -247,7 +246,7 @@ def _validate_sdk_task_table_schema(
|
|
|
247
246
|
connection: Any,
|
|
248
247
|
*,
|
|
249
248
|
table_name: str,
|
|
250
|
-
|
|
249
|
+
required_index: str,
|
|
251
250
|
database_url: str,
|
|
252
251
|
) -> None:
|
|
253
252
|
inspector = inspect(connection)
|
|
@@ -257,7 +256,7 @@ def _validate_sdk_task_table_schema(
|
|
|
257
256
|
existing_columns = {column["name"] for column in inspector.get_columns(table_name)}
|
|
258
257
|
existing_indexes = {index["name"] for index in inspector.get_indexes(table_name)}
|
|
259
258
|
missing_columns = sorted(_REQUIRED_SCHEMA_COLUMNS - existing_columns)
|
|
260
|
-
missing_indexes =
|
|
259
|
+
missing_indexes = [] if required_index in existing_indexes else [required_index]
|
|
261
260
|
if not missing_columns and not missing_indexes:
|
|
262
261
|
return
|
|
263
262
|
|