This commit is contained in:
2026-05-17 23:09:56 +08:00
parent 1b4f4c836e
commit ddc285b8f4
36 changed files with 4552 additions and 872 deletions
+46 -17
View File
@@ -23,7 +23,7 @@ class CriticFeedbackRequest(BaseModel):
usefulness_override: float | None = None
safety_override: float | None = None
from app.core.permission_resolution import PermissionResolutionRequest, SecretResolutionRequest, PasswordResolutionRequest
from app.core.permission_resolution import PermissionResolutionRequest, SecretResolutionRequest, PasswordResolutionRequest, ReviewResolutionRequest
from app.core.contracts import UserTask
from app.runtime.runtime_controller import RuntimeController
from app.streaming.manager import StreamingManager
@@ -33,19 +33,24 @@ from app.streaming.manager import StreamingManager
async def lifespan(app: FastAPI):
"""Load models on startup."""
print("Lifespan: Starting model loading...")
loop = asyncio.get_event_loop()
def load_models():
try:
print("Lifespan: Loading models...")
runtime.load_models_at_startup()
print("Lifespan: Models loaded")
except Exception as e:
print(f"Lifespan: Failed to load models: {e}")
import traceback
traceback.print_exc()
await loop.run_in_executor(None, load_models)
try:
print("Lifespan: Loading models...")
runtime.load_models_at_startup()
print("Lifespan: Models loaded")
# Rebuild vector index if empty but memory store has data.
if runtime._memory_interface:
store_count = runtime._memory_interface.count()
if store_count > 0:
idx_count = runtime._memory_interface._vector_index.element_count
if idx_count == 0:
print(f"Lifespan: Rebuilding vector index ({store_count} entries)...")
runtime._memory_interface.reindex()
print("Lifespan: Vector index rebuilt")
except Exception as e:
print(f"Lifespan: Failed to load models: {e}")
import traceback
traceback.print_exc()
yield # Server runs here
@@ -80,24 +85,44 @@ def list_events(limit: int = 500) -> dict[str, object]:
@app.post("/chat")
def chat(task: UserTask) -> dict[str, object]:
submit = getattr(runtime, "submit_task", None)
if callable(submit):
return submit(task)
return runtime.handle_task(task)
@app.post("/permissions/resolve")
def resolve_permission(request: PermissionResolutionRequest) -> dict[str, object]:
submit = getattr(runtime, "submit_permission_resolution", None)
if callable(submit):
return submit(task_id=request.task_id, decision=request.decision)
return runtime.resolve_permission(task_id=request.task_id, decision=request.decision)
@app.post("/secrets/resolve")
def resolve_secret(request: SecretResolutionRequest) -> dict[str, object]:
submit = getattr(runtime, "submit_secret_resolution", None)
if callable(submit):
return submit(task_id=request.task_id, secret=request.secret)
return runtime.resolve_secret(task_id=request.task_id, secret=request.secret)
@app.post("/password/resolve")
def resolve_password(request: PasswordResolutionRequest) -> dict[str, object]:
submit = getattr(runtime, "submit_password_resolution", None)
if callable(submit):
return submit(task_id=request.task_id, password=request.password)
return runtime.resolve_password(task_id=request.task_id, password=request.password)
@app.post("/review/resolve")
def resolve_review(request: ReviewResolutionRequest) -> dict[str, object]:
submit = getattr(runtime, "submit_review_resolution", None)
if callable(submit):
return submit(task_id=request.task_id, decision=request.decision, correction=request.correction)
return runtime.resolve_review(task_id=request.task_id, decision=request.decision, correction=request.correction)
@app.post("/critic/feedback")
def critic_feedback(request: CriticFeedbackRequest) -> dict[str, object]:
feedback = runtime.handle_critic_feedback(
@@ -130,11 +155,15 @@ async def stream_task(websocket: WebSocket, task_id: str) -> None:
queue = streaming.subscribe(task_id)
try:
while True:
event = await asyncio.wait_for(queue.get(), timeout=15)
try:
event = await asyncio.wait_for(queue.get(), timeout=30)
except asyncio.TimeoutError:
await websocket.send_json({"type": "heartbeat", "task_id": task_id})
continue
await websocket.send_json(event.model_dump(mode="json"))
if event.type in {"task_completed", "task_failed", "task_awaiting_permission", "task_awaiting_input"}:
if event.type in {"task_completed", "task_failed", "task_awaiting_permission", "task_awaiting_input", "task_awaiting_review"}:
break
except (asyncio.TimeoutError, WebSocketDisconnect):
except WebSocketDisconnect:
pass
finally:
streaming.unsubscribe(task_id, queue)
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+1013 -739
View File
File diff suppressed because it is too large Load Diff