feat(api-tools): preserve run_id is required error message in from_handler mode

LANG-231: Restore backward-compatible 'run_id is required' error message when run-scoped actions are invoked via handler without run_id, resolving regression in agent auth tests.
Co-authored-by: multica-agent <[email protected]>
This commit is contained in:
RockChinQ
2026-10-31 22:52:45 +08:00
co-authored by multica-agent
parent 8c5ee20283
commit d41959effd
2 changed files with 12 additions and 0 deletions
@@ -684,8 +684,12 @@ class ExecutionAPI:
if not isinstance(context, ExecutionAPIContext) or not isinstance(context.binding, InstallationBinding):
_fail('invalid_authentication', 'A trusted installation binding is required', 401)
if context.run_id is not None and (not isinstance(context.run_id, str) or not context.run_id.strip()):
if context.from_handler and operation.scope == 'run':
_fail('permission_denied', 'run_id is required', 400)
_fail('invalid_authentication', 'The trusted run ID is invalid', 401)
if context.run_id is None and operation.scope == 'run':
if context.from_handler:
_fail('permission_denied', 'run_id is required', 400)
_fail('permission_denied', 'This operation requires a trusted run context', 403)
if context.run_id is not None and operation.scope == 'plugin':
_fail('permission_denied', 'A run cannot use legacy plugin-wide operations', 403)
@@ -506,3 +506,11 @@ async def test_sdk_0_7_19_call_tool_parameters_and_session_compatibility(test_ho
)
assert resp.code == 0
assert resp.data == {'result': 'tool-result'}
@pytest.mark.asyncio
async def test_run_scoped_action_missing_run_id_returns_run_id_is_required(test_host):
"""When a run-scoped action is called from handler without run_id, error message is 'run_id is required'."""
resp = await test_host.handler.actions['state_get']({'scope': 'conversation', 'key': 'test_key'})
assert resp.code != 0
assert 'run_id is required' in resp.message