opencode-a2a 0.5.0__tar.gz → 0.5.1__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-0.5.0 → opencode_a2a-0.5.1}/.github/workflows/ci.yml +13 -10
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/.github/workflows/dependency-health.yml +3 -5
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/.github/workflows/publish.yml +10 -7
- {opencode_a2a-0.5.0/src/opencode_a2a.egg-info → opencode_a2a-0.5.1}/PKG-INFO +18 -6
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/README.md +16 -5
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/docs/guide.md +0 -2
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/pyproject.toml +1 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/scripts/README.md +1 -1
- opencode_a2a-0.5.1/scripts/dependency_health.sh +19 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/cli.py +8 -17
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/client/agent_card.py +2 -1
- opencode_a2a-0.5.1/src/opencode_a2a/client/auth.py +38 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/client/client.py +16 -5
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/client/config.py +14 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/client/request_context.py +18 -7
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/config.py +0 -9
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/jsonrpc/application.py +0 -1
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/server/application.py +175 -36
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/server/state_store.py +4 -12
- opencode_a2a-0.5.1/src/opencode_a2a/server/task_store.py +210 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1/src/opencode_a2a.egg-info}/PKG-INFO +18 -6
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a.egg-info/SOURCES.txt +1 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a.egg-info/requires.txt +1 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/client/test_agent_card.py +14 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/client/test_client_config.py +17 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/client/test_client_facade.py +55 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/client/test_request_context.py +25 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_app_behaviors.py +121 -1
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_cli.py +10 -18
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_state_store.py +0 -31
- opencode_a2a-0.5.1/tests/server/test_task_store_factory.py +294 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_transport_contract.py +0 -6
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/uv.lock +5 -3
- opencode_a2a-0.5.0/scripts/dependency_health.sh +0 -13
- opencode_a2a-0.5.0/src/opencode_a2a/server/task_store.py +0 -116
- opencode_a2a-0.5.0/tests/server/test_task_store_factory.py +0 -78
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/.gitignore +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/.pre-commit-config.yaml +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/.secrets.baseline +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/AGENTS.md +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/CONTRIBUTING.md +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/LICENSE +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/SECURITY.md +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/scripts/check_coverage.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/scripts/doctor.sh +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/scripts/health_common.sh +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/scripts/lint.sh +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/scripts/smoke_test_built_cli.sh +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/setup.cfg +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/client/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/client/error_mapping.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/client/errors.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/client/payload_text.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/contracts/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/contracts/extensions.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/event_helpers.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/executor.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/request_context.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/session_manager.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/stream_events.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/stream_runtime.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/stream_state.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/tool_error_mapping.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/execution/upstream_error_translator.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/jsonrpc/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/jsonrpc/error_responses.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/jsonrpc/methods.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/jsonrpc/params.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/opencode_upstream_client.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/parts/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/parts/mapping.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/parts/text.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/profile/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/profile/runtime.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/runtime_state.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/sandbox_policy.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/server/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/server/agent_card.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/server/openapi.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/server/request_parsing.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a/upstream_taxonomy.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a.egg-info/dependency_links.txt +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a.egg-info/entry_points.txt +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/src/opencode_a2a.egg-info/top_level.txt +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/client/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/client/test_error_mapping.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/client/test_payload_text.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/config/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/config/test_settings.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/conftest.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/contracts/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/contracts/test_extension_contract_consistency.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_agent_errors.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_agent_helpers.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_cancellation.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_directory_validation.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_metrics.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_multipart_input.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_opencode_agent_session_binding.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_session_ownership.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_streaming_output_contract_blocks.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_streaming_output_contract_core.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_streaming_output_contract_interrupts.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/execution/test_streaming_output_contract_logging.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/test_error_responses.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/test_jsonrpc_methods.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/test_jsonrpc_params.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/test_jsonrpc_unsupported_method.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/test_opencode_session_extension_commands.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/test_opencode_session_extension_interrupts.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/test_opencode_session_extension_prompt_async.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/jsonrpc/test_opencode_session_extension_queries.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/package/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/package/test_version.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/parts/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/parts/test_parts_text.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/profile/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/profile/test_profile_runtime.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/scripts/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/scripts/test_script_health_contract.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_a2a_client_manager.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_agent_card.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_call_context_builder.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_cancel_contract.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/server/test_database_app_persistence.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/support/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/support/helpers.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/support/session_extensions.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/support/streaming_output.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/upstream/__init__.py +0 -0
- {opencode_a2a-0.5.0 → opencode_a2a-0.5.1}/tests/upstream/test_opencode_upstream_client_params.py +0 -0
|
@@ -8,8 +8,6 @@ on:
|
|
|
8
8
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
|
-
env:
|
|
12
|
-
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
13
11
|
|
|
14
12
|
jobs:
|
|
15
13
|
quality-gate:
|
|
@@ -17,15 +15,15 @@ jobs:
|
|
|
17
15
|
|
|
18
16
|
steps:
|
|
19
17
|
- name: Checkout
|
|
20
|
-
uses: actions/checkout@
|
|
18
|
+
uses: actions/checkout@v6
|
|
21
19
|
|
|
22
20
|
- name: Setup Python
|
|
23
|
-
uses: actions/setup-python@
|
|
21
|
+
uses: actions/setup-python@v6
|
|
24
22
|
with:
|
|
25
23
|
python-version: "3.13"
|
|
26
24
|
|
|
27
25
|
- name: Setup uv
|
|
28
|
-
uses: astral-sh/setup-uv@
|
|
26
|
+
uses: astral-sh/setup-uv@v7
|
|
29
27
|
with:
|
|
30
28
|
enable-cache: false
|
|
31
29
|
|
|
@@ -41,8 +39,13 @@ jobs:
|
|
|
41
39
|
- name: Enforce coverage policy
|
|
42
40
|
run: uv run python ./scripts/check_coverage.py
|
|
43
41
|
|
|
44
|
-
- name:
|
|
45
|
-
run:
|
|
42
|
+
- name: Export runtime requirements for vulnerability audit
|
|
43
|
+
run: >
|
|
44
|
+
uv export --format requirements.txt --no-dev --locked --no-emit-project
|
|
45
|
+
--output-file /tmp/runtime-requirements.txt >/dev/null
|
|
46
|
+
|
|
47
|
+
- name: Run runtime dependency vulnerability audit
|
|
48
|
+
run: uv run pip-audit --requirement /tmp/runtime-requirements.txt
|
|
46
49
|
|
|
47
50
|
- name: Clean previous build artifacts
|
|
48
51
|
run: rm -rf build dist
|
|
@@ -65,15 +68,15 @@ jobs:
|
|
|
65
68
|
|
|
66
69
|
steps:
|
|
67
70
|
- name: Checkout
|
|
68
|
-
uses: actions/checkout@
|
|
71
|
+
uses: actions/checkout@v6
|
|
69
72
|
|
|
70
73
|
- name: Setup Python
|
|
71
|
-
uses: actions/setup-python@
|
|
74
|
+
uses: actions/setup-python@v6
|
|
72
75
|
with:
|
|
73
76
|
python-version: ${{ matrix.python-version }}
|
|
74
77
|
|
|
75
78
|
- name: Setup uv
|
|
76
|
-
uses: astral-sh/setup-uv@
|
|
79
|
+
uses: astral-sh/setup-uv@v7
|
|
77
80
|
with:
|
|
78
81
|
enable-cache: false
|
|
79
82
|
|
|
@@ -8,8 +8,6 @@ on:
|
|
|
8
8
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
|
-
env:
|
|
12
|
-
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
13
11
|
|
|
14
12
|
jobs:
|
|
15
13
|
dependency-health:
|
|
@@ -17,15 +15,15 @@ jobs:
|
|
|
17
15
|
|
|
18
16
|
steps:
|
|
19
17
|
- name: Checkout
|
|
20
|
-
uses: actions/checkout@
|
|
18
|
+
uses: actions/checkout@v6
|
|
21
19
|
|
|
22
20
|
- name: Setup Python
|
|
23
|
-
uses: actions/setup-python@
|
|
21
|
+
uses: actions/setup-python@v6
|
|
24
22
|
with:
|
|
25
23
|
python-version: "3.13"
|
|
26
24
|
|
|
27
25
|
- name: Setup uv
|
|
28
|
-
uses: astral-sh/setup-uv@
|
|
26
|
+
uses: astral-sh/setup-uv@v7
|
|
29
27
|
with:
|
|
30
28
|
enable-cache: false
|
|
31
29
|
|
|
@@ -9,8 +9,6 @@ on:
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: write
|
|
11
11
|
id-token: write
|
|
12
|
-
env:
|
|
13
|
-
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
14
12
|
|
|
15
13
|
jobs:
|
|
16
14
|
publish:
|
|
@@ -18,25 +16,30 @@ jobs:
|
|
|
18
16
|
|
|
19
17
|
steps:
|
|
20
18
|
- name: Checkout
|
|
21
|
-
uses: actions/checkout@
|
|
19
|
+
uses: actions/checkout@v6
|
|
22
20
|
with:
|
|
23
21
|
fetch-depth: 0
|
|
24
22
|
|
|
25
23
|
- name: Setup Python
|
|
26
|
-
uses: actions/setup-python@
|
|
24
|
+
uses: actions/setup-python@v6
|
|
27
25
|
with:
|
|
28
26
|
python-version: "3.13"
|
|
29
27
|
|
|
30
28
|
- name: Setup uv
|
|
31
|
-
uses: astral-sh/setup-uv@
|
|
29
|
+
uses: astral-sh/setup-uv@v7
|
|
32
30
|
with:
|
|
33
31
|
enable-cache: false
|
|
34
32
|
|
|
35
33
|
- name: Run regression baseline
|
|
36
34
|
run: bash ./scripts/doctor.sh
|
|
37
35
|
|
|
38
|
-
- name:
|
|
39
|
-
run:
|
|
36
|
+
- name: Export runtime requirements for vulnerability audit
|
|
37
|
+
run: >
|
|
38
|
+
uv export --format requirements.txt --no-dev --locked --no-emit-project
|
|
39
|
+
--output-file /tmp/runtime-requirements.txt >/dev/null
|
|
40
|
+
|
|
41
|
+
- name: Run runtime dependency vulnerability audit
|
|
42
|
+
run: uv run pip-audit --requirement /tmp/runtime-requirements.txt
|
|
40
43
|
|
|
41
44
|
- name: Clean previous build artifacts
|
|
42
45
|
run: rm -rf build dist
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencode-a2a
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: OpenCode A2A runtime
|
|
5
5
|
Author: liujuanjuan1984@Intelligent-Internet
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -25,6 +25,7 @@ Requires-Dist: fastapi<1.0,>=0.110
|
|
|
25
25
|
Requires-Dist: httpx<1.0,>=0.27
|
|
26
26
|
Requires-Dist: pydantic<3.0,>=2.6
|
|
27
27
|
Requires-Dist: pydantic-settings<3.0,>=2.2
|
|
28
|
+
Requires-Dist: requests<3.0,>=2.33.0
|
|
28
29
|
Requires-Dist: sqlalchemy<3.0,>=2.0
|
|
29
30
|
Requires-Dist: sse-starlette<4.0,>=2.1
|
|
30
31
|
Requires-Dist: uvicorn<1.0,>=0.29
|
|
@@ -146,19 +147,30 @@ curl http://127.0.0.1:8000/.well-known/agent-card.json
|
|
|
146
147
|
Interact with other A2A agents directly from the command line:
|
|
147
148
|
|
|
148
149
|
```bash
|
|
149
|
-
|
|
150
|
+
# Using the target peer agent's Bearer token via environment injection
|
|
151
|
+
A2A_CLIENT_BEARER_TOKEN=your-outbound-token \
|
|
152
|
+
opencode-a2a call http://other-agent:8000 "How are you?"
|
|
153
|
+
|
|
154
|
+
# Using the target peer agent's Basic auth via environment injection
|
|
155
|
+
# Accepts raw user:pass or its base64-encoded value
|
|
156
|
+
A2A_CLIENT_BASIC_AUTH="user:pass" \
|
|
157
|
+
opencode-a2a call http://other-agent:8000 "How are you?"
|
|
150
158
|
```
|
|
151
159
|
|
|
152
160
|
### Outbound Agent Calls (Tools)
|
|
153
161
|
The server can autonomously execute `a2a_call(url, message)` tool calls emitted by the OpenCode runtime. Results are fetched via A2A and returned to the model as tool results, enabling multi-agent orchestration.
|
|
154
162
|
|
|
155
|
-
When the target peer requires bearer auth, configure
|
|
156
|
-
for server-side outbound calls.
|
|
157
|
-
`
|
|
163
|
+
When the target peer agent requires bearer auth, configure
|
|
164
|
+
`A2A_CLIENT_BEARER_TOKEN` for server-side outbound calls. When the target peer
|
|
165
|
+
agent requires Basic auth, use `A2A_CLIENT_BASIC_AUTH`.
|
|
166
|
+
These outbound credentials apply to the peer specified by `opencode-a2a call`
|
|
167
|
+
or `a2a_call(url, message)`, not to this service's inbound `A2A_BEARER_TOKEN`.
|
|
168
|
+
The CLI intentionally reads outbound credentials from environment variables only,
|
|
169
|
+
so secrets do not appear in shell history or process arguments.
|
|
158
170
|
|
|
159
171
|
Server-side outbound client settings are fully wired through runtime config:
|
|
160
172
|
`A2A_CLIENT_TIMEOUT_SECONDS`, `A2A_CLIENT_CARD_FETCH_TIMEOUT_SECONDS`,
|
|
161
|
-
`A2A_CLIENT_USE_CLIENT_PREFERENCE`, `A2A_CLIENT_BEARER_TOKEN`, and
|
|
173
|
+
`A2A_CLIENT_USE_CLIENT_PREFERENCE`, `A2A_CLIENT_BEARER_TOKEN`, `A2A_CLIENT_BASIC_AUTH`, and
|
|
162
174
|
`A2A_CLIENT_SUPPORTED_TRANSPORTS`.
|
|
163
175
|
|
|
164
176
|
Detailed protocol contracts, examples, and extension docs live in
|
|
@@ -106,19 +106,30 @@ curl http://127.0.0.1:8000/.well-known/agent-card.json
|
|
|
106
106
|
Interact with other A2A agents directly from the command line:
|
|
107
107
|
|
|
108
108
|
```bash
|
|
109
|
-
|
|
109
|
+
# Using the target peer agent's Bearer token via environment injection
|
|
110
|
+
A2A_CLIENT_BEARER_TOKEN=your-outbound-token \
|
|
111
|
+
opencode-a2a call http://other-agent:8000 "How are you?"
|
|
112
|
+
|
|
113
|
+
# Using the target peer agent's Basic auth via environment injection
|
|
114
|
+
# Accepts raw user:pass or its base64-encoded value
|
|
115
|
+
A2A_CLIENT_BASIC_AUTH="user:pass" \
|
|
116
|
+
opencode-a2a call http://other-agent:8000 "How are you?"
|
|
110
117
|
```
|
|
111
118
|
|
|
112
119
|
### Outbound Agent Calls (Tools)
|
|
113
120
|
The server can autonomously execute `a2a_call(url, message)` tool calls emitted by the OpenCode runtime. Results are fetched via A2A and returned to the model as tool results, enabling multi-agent orchestration.
|
|
114
121
|
|
|
115
|
-
When the target peer requires bearer auth, configure
|
|
116
|
-
for server-side outbound calls.
|
|
117
|
-
`
|
|
122
|
+
When the target peer agent requires bearer auth, configure
|
|
123
|
+
`A2A_CLIENT_BEARER_TOKEN` for server-side outbound calls. When the target peer
|
|
124
|
+
agent requires Basic auth, use `A2A_CLIENT_BASIC_AUTH`.
|
|
125
|
+
These outbound credentials apply to the peer specified by `opencode-a2a call`
|
|
126
|
+
or `a2a_call(url, message)`, not to this service's inbound `A2A_BEARER_TOKEN`.
|
|
127
|
+
The CLI intentionally reads outbound credentials from environment variables only,
|
|
128
|
+
so secrets do not appear in shell history or process arguments.
|
|
118
129
|
|
|
119
130
|
Server-side outbound client settings are fully wired through runtime config:
|
|
120
131
|
`A2A_CLIENT_TIMEOUT_SECONDS`, `A2A_CLIENT_CARD_FETCH_TIMEOUT_SECONDS`,
|
|
121
|
-
`A2A_CLIENT_USE_CLIENT_PREFERENCE`, `A2A_CLIENT_BEARER_TOKEN`, and
|
|
132
|
+
`A2A_CLIENT_USE_CLIENT_PREFERENCE`, `A2A_CLIENT_BEARER_TOKEN`, `A2A_CLIENT_BASIC_AUTH`, and
|
|
122
133
|
`A2A_CLIENT_SUPPORTED_TRANSPORTS`.
|
|
123
134
|
|
|
124
135
|
Detailed protocol contracts, examples, and extension docs live in
|
|
@@ -80,8 +80,6 @@ Key variables to understand protocol behavior:
|
|
|
80
80
|
`memory`. Default: `database`.
|
|
81
81
|
- `A2A_TASK_STORE_DATABASE_URL`: database URL used by the default durable
|
|
82
82
|
backend. Default: `sqlite+aiosqlite:///./opencode-a2a.db`.
|
|
83
|
-
- `A2A_TASK_STORE_TABLE_NAME` / `A2A_TASK_STORE_CREATE_TABLE`: database task
|
|
84
|
-
store table name and whether to auto-create database tables on startup.
|
|
85
83
|
- Runtime authentication is bearer-token only via `A2A_BEARER_TOKEN`.
|
|
86
84
|
- The same outbound client flags are also honored by the server-side embedded
|
|
87
85
|
A2A client used for peer calls and `a2a_call` tool execution:
|
|
@@ -13,7 +13,7 @@ remaining repository-maintenance helpers.
|
|
|
13
13
|
## Other Scripts
|
|
14
14
|
|
|
15
15
|
- [`doctor.sh`](./doctor.sh): primary local development regression entrypoint (uv sync + lint + tests + coverage)
|
|
16
|
-
- [`dependency_health.sh`](./dependency_health.sh): dependency review entrypoint (`sync`/`pip check` + outdated + audit)
|
|
16
|
+
- [`dependency_health.sh`](./dependency_health.sh): development dependency review entrypoint (`sync`/`pip check` + outdated + dev audit), while blocking CI/publish audits focus on runtime dependencies
|
|
17
17
|
- [`check_coverage.py`](./check_coverage.py): enforces the overall coverage floor and per-file minimums for critical modules
|
|
18
18
|
- [`lint.sh`](./lint.sh): lint helper
|
|
19
19
|
- [`smoke_test_built_cli.sh`](./smoke_test_built_cli.sh): built-artifact smoke test for the released CLI runtime; defaults to the only local wheel, supports explicit wheel/sdist paths, and rejects ambiguous local artifact selection
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# shellcheck source=./health_common.sh
|
|
5
|
+
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/health_common.sh"
|
|
6
|
+
|
|
7
|
+
run_shared_repo_health_prerequisites "dependency-health"
|
|
8
|
+
|
|
9
|
+
echo "[dependency-health] list outdated packages"
|
|
10
|
+
uv pip list --outdated
|
|
11
|
+
|
|
12
|
+
dev_requirements="$(mktemp)"
|
|
13
|
+
trap 'rm -f "${dev_requirements}"' EXIT
|
|
14
|
+
|
|
15
|
+
echo "[dependency-health] export dev extra requirements"
|
|
16
|
+
uv export --format requirements.txt --extra dev --no-dev --locked --no-emit-project --output-file "${dev_requirements}" >/dev/null
|
|
17
|
+
|
|
18
|
+
echo "[dependency-health] run dev dependency vulnerability audit"
|
|
19
|
+
uv run pip-audit --requirement "${dev_requirements}"
|
|
@@ -6,23 +6,19 @@ import os
|
|
|
6
6
|
import sys
|
|
7
7
|
from collections.abc import Sequence
|
|
8
8
|
|
|
9
|
+
from a2a.types import Message, TaskArtifactUpdateEvent, TaskStatusUpdateEvent
|
|
10
|
+
|
|
9
11
|
from . import __version__
|
|
12
|
+
from .client import A2AClient, load_settings
|
|
10
13
|
from .server.application import main as serve_main
|
|
11
14
|
|
|
12
15
|
|
|
13
|
-
async def run_call(agent_url: str, text: str
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
from .client import A2AClient
|
|
17
|
-
|
|
18
|
-
client = A2AClient(agent_url)
|
|
19
|
-
metadata = {}
|
|
20
|
-
if token:
|
|
21
|
-
# Use Authorization header for bearer auth.
|
|
22
|
-
metadata["authorization"] = f"Bearer {token}"
|
|
16
|
+
async def run_call(agent_url: str, text: str) -> int:
|
|
17
|
+
settings = load_settings(os.environ)
|
|
18
|
+
client = A2AClient(agent_url, settings=settings)
|
|
23
19
|
|
|
24
20
|
try:
|
|
25
|
-
async for event in client.send_message(text
|
|
21
|
+
async for event in client.send_message(text):
|
|
26
22
|
if isinstance(event, tuple):
|
|
27
23
|
_, update = event
|
|
28
24
|
if isinstance(update, TaskArtifactUpdateEvent):
|
|
@@ -73,11 +69,6 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
73
69
|
)
|
|
74
70
|
call_parser.add_argument("agent_url", help="URL of the agent to call.")
|
|
75
71
|
call_parser.add_argument("text", help="Text message to send.")
|
|
76
|
-
call_parser.add_argument(
|
|
77
|
-
"--token",
|
|
78
|
-
help="Bearer token for authentication (can also use A2A_CLIENT_BEARER_TOKEN env).",
|
|
79
|
-
default=os.environ.get("A2A_CLIENT_BEARER_TOKEN"),
|
|
80
|
-
)
|
|
81
72
|
|
|
82
73
|
return parser
|
|
83
74
|
|
|
@@ -92,7 +83,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
92
83
|
|
|
93
84
|
namespace = parser.parse_args(args)
|
|
94
85
|
if namespace.command == "call":
|
|
95
|
-
return asyncio.run(run_call(namespace.agent_url, namespace.text
|
|
86
|
+
return asyncio.run(run_call(namespace.agent_url, namespace.text))
|
|
96
87
|
|
|
97
88
|
if namespace.command is None:
|
|
98
89
|
serve_main()
|
|
@@ -66,9 +66,10 @@ def build_resolver_http_kwargs(
|
|
|
66
66
|
*,
|
|
67
67
|
bearer_token: str | None,
|
|
68
68
|
timeout: float,
|
|
69
|
+
basic_auth: str | None = None,
|
|
69
70
|
) -> dict[str, Any]:
|
|
70
71
|
http_kwargs: dict[str, Any] = {"timeout": timeout}
|
|
71
|
-
default_headers = build_default_headers(bearer_token)
|
|
72
|
+
default_headers = build_default_headers(bearer_token, basic_auth)
|
|
72
73
|
if default_headers:
|
|
73
74
|
http_kwargs["headers"] = default_headers
|
|
74
75
|
return http_kwargs
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Authentication helpers for outbound A2A client configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from base64 import b64decode, b64encode
|
|
6
|
+
from binascii import Error as BinasciiError
|
|
7
|
+
|
|
8
|
+
BASIC_AUTH_FORMAT_ERROR = (
|
|
9
|
+
"A2A_CLIENT_BASIC_AUTH must be 'username:password' or a base64-encoded "
|
|
10
|
+
"'username:password' value"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def validate_basic_auth(value: str) -> None:
|
|
15
|
+
"""Validate a raw or pre-encoded Basic Auth credential value."""
|
|
16
|
+
if ":" in value:
|
|
17
|
+
return
|
|
18
|
+
decoded = _decode_basic_auth(value)
|
|
19
|
+
if b":" not in decoded:
|
|
20
|
+
raise ValueError(BASIC_AUTH_FORMAT_ERROR)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def encode_basic_auth(value: str) -> str:
|
|
24
|
+
"""Normalize a raw or pre-encoded Basic Auth value to base64 credentials."""
|
|
25
|
+
if ":" in value:
|
|
26
|
+
return b64encode(value.encode()).decode()
|
|
27
|
+
decoded = _decode_basic_auth(value)
|
|
28
|
+
if b":" not in decoded:
|
|
29
|
+
raise ValueError(BASIC_AUTH_FORMAT_ERROR)
|
|
30
|
+
return b64encode(decoded).decode()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _decode_basic_auth(value: str) -> bytes:
|
|
34
|
+
padded_value = value + ("=" * (-len(value) % 4))
|
|
35
|
+
try:
|
|
36
|
+
return b64decode(padded_value, validate=True)
|
|
37
|
+
except (BinasciiError, ValueError) as exc:
|
|
38
|
+
raise ValueError(BASIC_AUTH_FORMAT_ERROR) from exc
|
|
@@ -83,6 +83,7 @@ class A2AClient:
|
|
|
83
83
|
http_kwargs=build_resolver_http_kwargs(
|
|
84
84
|
bearer_token=self._settings.bearer_token,
|
|
85
85
|
timeout=self._settings.card_fetch_timeout,
|
|
86
|
+
basic_auth=self._settings.basic_auth,
|
|
86
87
|
)
|
|
87
88
|
)
|
|
88
89
|
except (
|
|
@@ -121,7 +122,9 @@ class A2AClient:
|
|
|
121
122
|
try:
|
|
122
123
|
async for event in client.send_message(
|
|
123
124
|
request,
|
|
124
|
-
context=build_call_context(
|
|
125
|
+
context=build_call_context(
|
|
126
|
+
self._settings.bearer_token, extra_headers, self._settings.basic_auth
|
|
127
|
+
),
|
|
125
128
|
request_metadata=request_metadata,
|
|
126
129
|
extensions=extensions,
|
|
127
130
|
):
|
|
@@ -180,7 +183,9 @@ class A2AClient:
|
|
|
180
183
|
history_length=history_length,
|
|
181
184
|
metadata=request_metadata or {},
|
|
182
185
|
),
|
|
183
|
-
context=build_call_context(
|
|
186
|
+
context=build_call_context(
|
|
187
|
+
self._settings.bearer_token, extra_headers, self._settings.basic_auth
|
|
188
|
+
),
|
|
184
189
|
)
|
|
185
190
|
except (
|
|
186
191
|
A2AClientHTTPError,
|
|
@@ -206,7 +211,9 @@ class A2AClient:
|
|
|
206
211
|
try:
|
|
207
212
|
return await client.cancel_task(
|
|
208
213
|
TaskIdParams(id=task_id, metadata=request_metadata or {}),
|
|
209
|
-
context=build_call_context(
|
|
214
|
+
context=build_call_context(
|
|
215
|
+
self._settings.bearer_token, extra_headers, self._settings.basic_auth
|
|
216
|
+
),
|
|
210
217
|
)
|
|
211
218
|
except (
|
|
212
219
|
A2AClientHTTPError,
|
|
@@ -232,7 +239,9 @@ class A2AClient:
|
|
|
232
239
|
try:
|
|
233
240
|
async for event in client.resubscribe(
|
|
234
241
|
TaskIdParams(id=task_id, metadata=request_metadata or {}),
|
|
235
|
-
context=build_call_context(
|
|
242
|
+
context=build_call_context(
|
|
243
|
+
self._settings.bearer_token, extra_headers, self._settings.basic_auth
|
|
244
|
+
),
|
|
236
245
|
):
|
|
237
246
|
yield event
|
|
238
247
|
except (
|
|
@@ -264,7 +273,9 @@ class A2AClient:
|
|
|
264
273
|
factory = ClientFactory(config, consumers=None)
|
|
265
274
|
client = factory.create(
|
|
266
275
|
card,
|
|
267
|
-
interceptors=build_client_interceptors(
|
|
276
|
+
interceptors=build_client_interceptors(
|
|
277
|
+
self._settings.bearer_token, self._settings.basic_auth
|
|
278
|
+
),
|
|
268
279
|
)
|
|
269
280
|
except ValueError as exc:
|
|
270
281
|
raise A2AUnsupportedBindingError(
|
|
@@ -6,6 +6,8 @@ from collections.abc import Iterable, Mapping
|
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
+
from .auth import validate_basic_auth
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
def _read_setting(
|
|
11
13
|
source: Any,
|
|
@@ -106,6 +108,7 @@ class A2AClientSettings:
|
|
|
106
108
|
use_client_preference: bool = False
|
|
107
109
|
card_fetch_timeout: float = 5.0
|
|
108
110
|
bearer_token: str | None = None
|
|
111
|
+
basic_auth: str | None = None
|
|
109
112
|
supported_transports: tuple[str, ...] = (
|
|
110
113
|
"JSONRPC",
|
|
111
114
|
"HTTP+JSON",
|
|
@@ -153,6 +156,16 @@ def load_settings(raw_settings: Any) -> A2AClientSettings:
|
|
|
153
156
|
default=None,
|
|
154
157
|
),
|
|
155
158
|
)
|
|
159
|
+
basic_auth = _coerce_optional_str(
|
|
160
|
+
"A2A_CLIENT_BASIC_AUTH",
|
|
161
|
+
_read_setting(
|
|
162
|
+
raw_settings,
|
|
163
|
+
keys=("A2A_CLIENT_BASIC_AUTH", "a2a_client_basic_auth"),
|
|
164
|
+
default=None,
|
|
165
|
+
),
|
|
166
|
+
)
|
|
167
|
+
if basic_auth is not None:
|
|
168
|
+
validate_basic_auth(basic_auth)
|
|
156
169
|
supported_transports = _parse_transports(
|
|
157
170
|
_read_setting(
|
|
158
171
|
raw_settings,
|
|
@@ -170,6 +183,7 @@ def load_settings(raw_settings: Any) -> A2AClientSettings:
|
|
|
170
183
|
use_client_preference=use_client_preference,
|
|
171
184
|
card_fetch_timeout=card_fetch_timeout,
|
|
172
185
|
bearer_token=bearer_token,
|
|
186
|
+
basic_auth=basic_auth,
|
|
173
187
|
supported_transports=supported_transports,
|
|
174
188
|
)
|
|
175
189
|
|
|
@@ -7,6 +7,8 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from a2a.client.middleware import ClientCallContext, ClientCallInterceptor
|
|
9
9
|
|
|
10
|
+
from .auth import encode_basic_auth
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
class HeaderInterceptor(ClientCallInterceptor):
|
|
12
14
|
def __init__(self, default_headers: Mapping[str, str] | None = None) -> None:
|
|
@@ -36,10 +38,15 @@ class HeaderInterceptor(ClientCallInterceptor):
|
|
|
36
38
|
return request_payload, http_kwargs
|
|
37
39
|
|
|
38
40
|
|
|
39
|
-
def build_default_headers(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
def build_default_headers(
|
|
42
|
+
bearer_token: str | None,
|
|
43
|
+
basic_auth: str | None = None,
|
|
44
|
+
) -> dict[str, str]:
|
|
45
|
+
if bearer_token:
|
|
46
|
+
return {"Authorization": f"Bearer {bearer_token}"}
|
|
47
|
+
if basic_auth:
|
|
48
|
+
return {"Authorization": f"Basic {encode_basic_auth(basic_auth)}"}
|
|
49
|
+
return {}
|
|
43
50
|
|
|
44
51
|
|
|
45
52
|
def split_request_metadata(
|
|
@@ -59,8 +66,9 @@ def split_request_metadata(
|
|
|
59
66
|
def build_call_context(
|
|
60
67
|
bearer_token: str | None,
|
|
61
68
|
extra_headers: Mapping[str, str] | None,
|
|
69
|
+
basic_auth: str | None = None,
|
|
62
70
|
) -> ClientCallContext | None:
|
|
63
|
-
merged_headers = build_default_headers(bearer_token)
|
|
71
|
+
merged_headers = build_default_headers(bearer_token, basic_auth)
|
|
64
72
|
if extra_headers:
|
|
65
73
|
merged_headers.update(extra_headers)
|
|
66
74
|
if not merged_headers:
|
|
@@ -73,8 +81,11 @@ def build_call_context(
|
|
|
73
81
|
)
|
|
74
82
|
|
|
75
83
|
|
|
76
|
-
def build_client_interceptors(
|
|
77
|
-
|
|
84
|
+
def build_client_interceptors(
|
|
85
|
+
bearer_token: str | None,
|
|
86
|
+
basic_auth: str | None = None,
|
|
87
|
+
) -> list[ClientCallInterceptor]:
|
|
88
|
+
return [HeaderInterceptor(build_default_headers(bearer_token, basic_auth))]
|
|
78
89
|
|
|
79
90
|
|
|
80
91
|
__all__ = [
|
|
@@ -188,15 +188,6 @@ class Settings(BaseSettings):
|
|
|
188
188
|
default="sqlite+aiosqlite:///./opencode-a2a.db",
|
|
189
189
|
alias="A2A_TASK_STORE_DATABASE_URL",
|
|
190
190
|
)
|
|
191
|
-
a2a_task_store_table_name: str = Field(
|
|
192
|
-
default="tasks",
|
|
193
|
-
min_length=1,
|
|
194
|
-
alias="A2A_TASK_STORE_TABLE_NAME",
|
|
195
|
-
)
|
|
196
|
-
a2a_task_store_create_table: bool = Field(
|
|
197
|
-
default=True,
|
|
198
|
-
alias="A2A_TASK_STORE_CREATE_TABLE",
|
|
199
|
-
)
|
|
200
191
|
|
|
201
192
|
@model_validator(mode="after")
|
|
202
193
|
def _validate_sandbox_policy(self) -> Settings:
|
|
@@ -74,7 +74,6 @@ __all__ = [
|
|
|
74
74
|
|
|
75
75
|
ERR_SESSION_NOT_FOUND = SESSION_QUERY_ERROR_BUSINESS_CODES["SESSION_NOT_FOUND"]
|
|
76
76
|
ERR_SESSION_FORBIDDEN = SESSION_QUERY_ERROR_BUSINESS_CODES["SESSION_FORBIDDEN"]
|
|
77
|
-
ERR_METHOD_NOT_SUPPORTED = -32601
|
|
78
77
|
ERR_UPSTREAM_UNREACHABLE = SESSION_QUERY_ERROR_BUSINESS_CODES["UPSTREAM_UNREACHABLE"]
|
|
79
78
|
ERR_UPSTREAM_HTTP_ERROR = SESSION_QUERY_ERROR_BUSINESS_CODES["UPSTREAM_HTTP_ERROR"]
|
|
80
79
|
ERR_INTERRUPT_NOT_FOUND = INTERRUPT_ERROR_BUSINESS_CODES["INTERRUPT_REQUEST_NOT_FOUND"]
|