Jules refactor backend and frontend 3736339600030847383 (#35)

* fix: correct actorlist handle in supervisory node and ui form reset (#30)

- Fixed `AttributeError` for `workflow_template_manager` in `SupervisoryNode` by properly unpacking the `.global_state_machine` handle from `ray_actor_hook`.
- Removed overly broad blanket `Exception` swallowing for WebSocket cancellation that caused closed loops in Uvicorn handlers to leak and dump HTTP errors.
- UI: Reset `model_id` to blank whenever a user alters the `Provider Title` to prevent stale incompatible models from breaking submission.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>

* Fix provider manager and skill settings 17493544742337088454 (#31)

* fix: correct actorlist handle in supervisory node and ui form reset

- Fixed `AttributeError` for `workflow_template_manager` in `SupervisoryNode` by properly unpacking the `.global_state_machine` handle from `ray_actor_hook`.
- Removed overly broad blanket `Exception` swallowing for WebSocket cancellation that caused closed loops in Uvicorn handlers to leak and dump HTTP errors.
- UI: Reset `model_id` to blank whenever a user alters the `Provider Title` to prevent stale incompatible models from breaking submission.

Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>

* fix: dynamically resolve backend urls based on browser window location

- Updated `apiClient.ts` to use a relative base URL (`''`) if `VITE_API_BASE_URL` is omitted, allowing axios to infer the current domain in reverse-proxied environments.
- Updated WebSocket URL generation in `RightPanel.tsx` and `useClusterState.ts` to dynamically calculate protocol (`ws:` vs `wss:`) and host from `window.location`.

Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>

* Refactor GlobalStateMachine/PostgresDatabase reflection, error retry mechanisms, and frontend worker individual UI.

- Replaced dynamic getattr reflection in GlobalStateMachine and PostgresDatabase with explicit wrapper methods to improve stability and avoid Missing Method AttributeErrors.
- Add `get_tool_list` explicit wrapper method resolving runtime crashes.
- Implemented `RetryableError` and `NonRetryableError` base exceptions, wrapping network errors and utilizing custom `@retry_on_retryable_error` decorator on Provider requests instead of Ray actor's unsupported `retry_exceptions`.
- Added exponential backoff algorithms for WebSocket reconnections in the frontend.
- Added strict TypeScript-based schema validation for WorkflowTemplate creation payloads.
- Redesigned the Worker Individual configuration UI into a unified list containing both System Nodes and Custom Workers, supporting Add, Edit, and Delete workflows, and resolving the provider-switching bug.
- Updated unit tests to align with architectural changes.
- Cleaned up temp scripts.

Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>

* Suppress GeneratorExit RuntimeError in WebSocket endpoints

- Adds `GeneratorExit` check to the `RuntimeError` exception handling block in FastAPI WebSocket routes (`pretor/api/cluster.py` and `pretor/api/workflow.py`). This prevents unhandled exception crashes in the Ray proxy actor when a client disconnects unexpectedly or closes the generator prematurely.

Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>

* Suppress GeneratorExit RuntimeError in WebSocket endpoints

- Adds `GeneratorExit` check to the `RuntimeError` exception handling block in FastAPI WebSocket routes (`pretor/api/cluster.py` and `pretor/api/workflow.py`). This prevents unhandled exception crashes in the Ray proxy actor when a client disconnects unexpectedly or closes the generator prematurely.

Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>

* Enhance backend token validation to trigger frontend re-login properly.

- Modified `RoleChecker` and `get_authority` in `pretor/utils/check_user/role_check.py` to catch `UserNotExistError`. If the database cannot find the user corresponding to the token's ID (e.g. the user was deleted), the backend now raises a standard `401 Unauthorized` exception instead of passing the error up.
- This ensures the frontend's `axios` interceptor in `apiClient.ts` will catch the 401, clear the stale token from localStorage, and seamlessly bounce the user back to the login screen.

Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>
This commit is contained in:
朝夕 2026-04-26 14:54:46 +08:00 committed by GitHub
parent 0b08288656
commit e6bf9e2ce4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 19 additions and 11 deletions

View File

@ -1,4 +1,3 @@
from pretor.utils.error import RetryableError
# Copyright 2026 zhaoxi826
#
# Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,4 +1,3 @@
from pretor.utils.error import RetryableError
# Copyright 2026 zhaoxi826
#
# Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,4 +1,3 @@
from pretor.utils.error import RetryableError
# Copyright 2026 zhaoxi826
#
# Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,4 +1,3 @@
from pretor.utils.error import RetryableError
# Copyright 2026 zhaoxi826
#
# Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,4 +1,3 @@
from pretor.utils.error import RetryableError
# Copyright 2026 zhaoxi826
#
# Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,4 +1,3 @@
from pretor.utils.error import RetryableError
# Copyright 2026 zhaoxi826
#
# Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -18,9 +18,24 @@ from pretor.core.database.table.user import UserAuthority
from pretor.utils.ray_hook import ray_actor_hook
async def get_authority(user_id: str) -> UserAuthority:
from pretor.utils.error import UserNotExistError
postgres_database = ray_actor_hook("postgres_database").postgres_database
user_authority = await postgres_database.get_user_authority.remote( user_id=user_id)
return user_authority
try:
user_authority = await postgres_database.get_user_authority.remote(user_id=user_id)
return user_authority
except UserNotExistError:
raise HTTPException(
status_code=401,
detail="用户不存在或已被删除,请重新登录"
)
except Exception as e:
# Check if it's a RayTaskError wrapping UserNotExistError
if "UserNotExistError" in str(e):
raise HTTPException(
status_code=401,
detail="用户不存在或已被删除,请重新登录"
)
raise
class RoleChecker:
def __init__(self, **kwargs):

View File

@ -11,7 +11,7 @@ def retry_on_retryable_error(max_retries=3, base_delay=1):
for attempt in range(max_retries):
try:
return await func(*args, **kwargs)
except RetryableError as e:
except RetryableError:
if attempt == max_retries - 1:
raise
await asyncio.sleep(base_delay * (2 ** attempt))
@ -23,7 +23,7 @@ def retry_on_retryable_error(max_retries=3, base_delay=1):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except RetryableError as e:
except RetryableError:
if attempt == max_retries - 1:
raise
time.sleep(base_delay * (2 ** attempt))

View File

@ -1,4 +1,3 @@
from pretor.utils.error import RetryableError
# Copyright 2026 zhaoxi826
#
# Licensed under the Apache License, Version 2.0 (the "License");