fix(web): make processor debugging reliable

This commit is contained in:
RockChinQ
2026-08-25 15:52:59 +08:00
parent 781d8a9ac8
commit 6a6a2b865b
24 changed files with 788 additions and 160 deletions
+15 -1
View File
@@ -1,14 +1,17 @@
"""Agent runner errors."""
from __future__ import annotations
class AgentRunnerError(Exception):
"""Base error for agent runner operations."""
pass
class RunnerNotFoundError(AgentRunnerError):
"""Runner not found in registry."""
def __init__(self, runner_id: str):
self.runner_id = runner_id
super().__init__(f'Agent runner not found: {runner_id}')
@@ -16,6 +19,7 @@ class RunnerNotFoundError(AgentRunnerError):
class RunnerNotAuthorizedError(AgentRunnerError):
"""Runner not authorized for this binding."""
def __init__(self, runner_id: str, bound_plugins: list[str] | None):
self.runner_id = runner_id
self.bound_plugins = bound_plugins
@@ -24,6 +28,7 @@ class RunnerNotAuthorizedError(AgentRunnerError):
class RunnerProtocolError(AgentRunnerError):
"""Runner protocol version mismatch or invalid manifest."""
def __init__(self, runner_id: str, message: str):
self.runner_id = runner_id
super().__init__(f'Agent runner protocol error for {runner_id}: {message}')
@@ -31,7 +36,16 @@ class RunnerProtocolError(AgentRunnerError):
class RunnerExecutionError(AgentRunnerError):
"""Runner execution failed."""
def __init__(self, runner_id: str, message: str, retryable: bool = False):
def __init__(
self,
runner_id: str,
message: str,
retryable: bool = False,
error_code: str | None = None,
):
self.runner_id = runner_id
self.message = message
self.retryable = retryable
self.error_code = error_code
super().__init__(f'Agent runner {runner_id} execution failed: {message}')
+5 -5
View File
@@ -58,21 +58,21 @@ class AgentRunnerInvoker:
except asyncio.TimeoutError as e:
raise RunnerExecutionError(
descriptor.id,
'Runner timed out (code: runner.timeout)',
'Runner timed out',
retryable=True,
error_code='runner.timeout',
) from e
except ActionCallTimeoutError as e:
raise RunnerExecutionError(
descriptor.id,
f'{e} (code: runner.timeout)',
str(e),
retryable=True,
error_code='runner.timeout',
) from e
except RunnerExecutionError:
raise
except Exception as e:
self.ap.logger.error(
f'Runner {descriptor.id} unexpected error: {traceback.format_exc()}'
)
self.ap.logger.error(f'Runner {descriptor.id} unexpected error: {traceback.format_exc()}')
raise RunnerExecutionError(
descriptor.id,
str(e),
@@ -152,10 +152,14 @@ class AgentResultNormalizer:
error_msg = data.get('error', 'Unknown error')
error_code = data.get('code', 'unknown')
retryable = data.get('retryable', False)
normalized_error_code = str(error_code or '').strip()
raise RunnerExecutionError(
descriptor.id,
f'{error_msg} (code: {error_code})',
str(error_msg),
retryable=retryable,
error_code=(
normalized_error_code if normalized_error_code and normalized_error_code != 'unknown' else None
),
)
elif result_type == 'action.requested':
@@ -2,6 +2,13 @@ from __future__ import annotations
import quart
from .....agent.runner.errors import (
AgentRunnerError,
RunnerExecutionError,
RunnerNotAuthorizedError,
RunnerNotFoundError,
RunnerProtocolError,
)
from ...authz import Permission, require_permission
from ...context import RequestContext
from .. import group
@@ -63,6 +70,36 @@ class AgentsRouterGroup(group.RouterGroup):
)
except ValueError as exc:
return self.http_status(400, -1, str(exc))
except RunnerExecutionError as exc:
return self.http_status(
422,
exc.error_code or 'runner_execution_failed',
exc.message,
)
except RunnerNotFoundError:
return self.http_status(
409,
'runner_not_found',
'The configured Agent runner is unavailable',
)
except RunnerNotAuthorizedError:
return self.http_status(
403,
'runner_not_authorized',
'The configured Agent runner is not authorized',
)
except RunnerProtocolError:
return self.http_status(
502,
'runner_protocol_error',
'The Agent runner returned an invalid response',
)
except AgentRunnerError:
return self.http_status(
502,
'runner_error',
'The Agent runner could not complete this test',
)
return self.success(data=result)
@self.route(
@@ -25,7 +25,7 @@ class BanWordFilter(filter_model.ContentFilter):
return entities.FilterResult(
level=entities.ResultLevel.BLOCK,
replacement='',
user_notice='内容检查规则执行失败,请联系管理员',
user_notice='内容安全检查配置有误,请检查敏感词设置',
console_notice=f'Sensitive-word regex rejected: {exc}',
)
+4 -1
View File
@@ -7,7 +7,10 @@ from collections.abc import Sequence
import regex
MAX_PATTERN_COUNT = 64
# The bundled sensitive-word list already contains more than 64 entries. Keep
# the deterministic cap, but leave enough room for the built-in defaults and
# reasonable administrator customisation.
MAX_PATTERN_COUNT = 256
MAX_PATTERN_CHARS = 1024
MAX_INPUT_CHARS = 1024 * 1024
MAX_REPLACEMENT_CHARS = 64