fix: resolve all flake8 lint errors (118 → 0) #10
@@ -5,17 +5,17 @@ from __future__ import annotations
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
|
||||
from src.blackboard.operations import Blackboard
|
||||
from src.blackboard.models import Task, Review
|
||||
from src.blackboard.queries import Queries
|
||||
from src.blackboard.db import VALID_STATUSES, VALID_TRANSITIONS, COMMENT_TYPES, OUTPUT_TYPES
|
||||
from src.blackboard.db import VALID_STATUSES, OUTPUT_TYPES
|
||||
from src.blackboard.registry import ProjectRegistry
|
||||
|
||||
from src.utils import get_data_root
|
||||
import src.utils as _utils
|
||||
|
||||
router = APIRouter(prefix="/api/projects/{project_id}", tags=["blackboard"])
|
||||
|
||||
@@ -27,7 +27,7 @@ def _validate_project(project_id: str) -> str:
|
||||
"""校验 project_id,已知项目/虚拟项目放行,未知项目返回 400"""
|
||||
if project_id in _VIRTUAL_PROJECTS:
|
||||
return project_id
|
||||
reg = ProjectRegistry(get_data_root())
|
||||
reg = ProjectRegistry(_utils.get_data_root())
|
||||
if reg.get_project(project_id):
|
||||
return project_id
|
||||
raise HTTPException(400, {
|
||||
@@ -43,12 +43,12 @@ def _validate_project(project_id: str) -> str:
|
||||
|
||||
def _bb(project_id: str) -> Blackboard:
|
||||
_validate_project(project_id)
|
||||
return Blackboard(get_data_root() / project_id / "blackboard.db")
|
||||
return Blackboard(_utils.get_data_root() / project_id / "blackboard.db")
|
||||
|
||||
|
||||
def _q(project_id: str) -> Queries:
|
||||
_validate_project(project_id)
|
||||
return Queries(get_data_root() / project_id / "blackboard.db")
|
||||
return Queries(_utils.get_data_root() / project_id / "blackboard.db")
|
||||
|
||||
|
||||
# --- Tasks ---
|
||||
@@ -100,7 +100,7 @@ async def create_task(project_id: str, body: Dict[str, Any]):
|
||||
date_str = datetime.now().strftime('%Y%m%d')
|
||||
# seq: 查当前项目最大 seq
|
||||
import sqlite3
|
||||
db_path = get_data_root() / project_id / "blackboard.db"
|
||||
db_path = _utils.get_data_root() / project_id / "blackboard.db"
|
||||
try:
|
||||
conn = sqlite3.connect(str(db_path), timeout=5)
|
||||
max_id_row = conn.execute(
|
||||
@@ -265,6 +265,7 @@ async def update_status(project_id: str, task_id: str, body: Dict[str, Any]):
|
||||
# --- @mention 自动提取(#04) ---
|
||||
_KNOWN_AGENT_IDS: list = []
|
||||
|
||||
|
||||
def _init_agent_ids():
|
||||
"""从配置文件加载 Agent ID 列表"""
|
||||
global _KNOWN_AGENT_IDS
|
||||
@@ -279,6 +280,7 @@ def _init_agent_ids():
|
||||
except Exception:
|
||||
_KNOWN_AGENT_IDS = []
|
||||
|
||||
|
||||
def _extract_mentions(text: str) -> list:
|
||||
"""从文本中自动提取 @agent-id 格式的 mention"""
|
||||
import re
|
||||
|
||||
@@ -10,7 +10,7 @@ from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
from src.blackboard.operations import Blackboard
|
||||
from src.utils import get_data_root
|
||||
import src.utils as _utils
|
||||
|
||||
router = APIRouter(prefix="/api/projects/{project_id}/tasks/{task_id}/checkpoints", tags=["checkpoints"])
|
||||
|
||||
@@ -33,7 +33,7 @@ class ResolveCheckpointRequest(BaseModel):
|
||||
# ── 工具 ──
|
||||
|
||||
def _bb(project_id: str) -> Blackboard:
|
||||
db_path = get_data_root() / project_id / "blackboard.db"
|
||||
db_path = _utils.get_data_root() / project_id / "blackboard.db"
|
||||
if not db_path.exists():
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
return Blackboard(db_path)
|
||||
|
||||
@@ -9,7 +9,7 @@ from __future__ import annotations
|
||||
import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
|
||||
@@ -17,7 +17,7 @@ from src.blackboard.db import init_db
|
||||
from src.blackboard.models import Task
|
||||
from src.blackboard.operations import Blackboard
|
||||
from src.blackboard.queries import Queries
|
||||
from src.utils import get_data_root
|
||||
import src.utils as _utils
|
||||
|
||||
|
||||
def _get_valid_agents() -> set:
|
||||
@@ -36,13 +36,14 @@ def _get_valid_agents() -> set:
|
||||
# fallback:硬编码
|
||||
return {"zhangfei-dev", "guanyu-dev", "zhaoyun-data", "jiangwei-infra", "pangtong-fujunshi", "simayi-challenger"}
|
||||
|
||||
|
||||
router = APIRouter(prefix="/api/mail", tags=["mail"])
|
||||
|
||||
MAIL_PROJECT_ID = "_mail"
|
||||
|
||||
|
||||
def _db_path() -> Path:
|
||||
root = get_data_root()
|
||||
root = _utils.get_data_root()
|
||||
db = root / MAIL_PROJECT_ID / "blackboard.db"
|
||||
db.parent.mkdir(parents=True, exist_ok=True)
|
||||
init_db(db)
|
||||
@@ -222,7 +223,7 @@ async def send_mail(body: Dict[str, Any]):
|
||||
|
||||
# A8: 只有原邮件的双方能回复(严格 1 对 1)
|
||||
if from_agent not in (orig_from, orig_to):
|
||||
raise HTTPException(400, f"只有邮件的发送者或接收者可以回复")
|
||||
raise HTTPException(400, "只有邮件的发送者或接收者可以回复")
|
||||
|
||||
# A6/A7: 自动纠正 to → 原邮件发件者
|
||||
to_agent = body.get("to", "").strip()
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
|
||||
from src.blackboard.registry import ProjectRegistry
|
||||
from src.utils import get_data_root
|
||||
import src.utils as _utils
|
||||
|
||||
router = APIRouter(prefix="/api/projects", tags=["projects"])
|
||||
|
||||
|
||||
def _registry() -> ProjectRegistry:
|
||||
return ProjectRegistry(get_data_root())
|
||||
return ProjectRegistry(_utils.get_data_root())
|
||||
|
||||
|
||||
@router.get("")
|
||||
@@ -76,7 +76,7 @@ async def list_projects():
|
||||
async def create_project(body: Dict[str, Any]):
|
||||
reg = _registry()
|
||||
try:
|
||||
info = reg.create_project(
|
||||
reg.create_project(
|
||||
body["id"], body["name"],
|
||||
agents=body.get("agents", []),
|
||||
description=body.get("description", ""),
|
||||
|
||||
@@ -28,7 +28,7 @@ from src.blackboard.models import Task
|
||||
from src.blackboard.operations import Blackboard
|
||||
from src.config.agents import AGENT_IDS
|
||||
from src.daemon.toolchain_templates import render_template
|
||||
from src.utils import get_data_root
|
||||
import src.utils as _utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -141,13 +141,12 @@ def _calc_risk_level(changed_files: List[str]) -> str:
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
MAIL_PROJECT_ID = "_mail"
|
||||
|
||||
|
||||
def _mail_db_path() -> Path:
|
||||
"""获取 Mail 数据库路径,确保目录存在。"""
|
||||
root = get_data_root()
|
||||
root = _utils.get_data_root()
|
||||
db = root / MAIL_PROJECT_ID / "blackboard.db"
|
||||
db.parent.mkdir(parents=True, exist_ok=True)
|
||||
init_db(db)
|
||||
|
||||
@@ -4,7 +4,6 @@ from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def init_db(db_path: Path) -> None:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, List, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -11,7 +11,6 @@ from typing import Any, Dict, List, Optional
|
||||
|
||||
from .db import (
|
||||
VALID_TRANSITIONS,
|
||||
VALID_STATUSES,
|
||||
COMMENT_TYPES,
|
||||
EVENT_TYPES,
|
||||
OUTPUT_TYPES,
|
||||
@@ -693,7 +692,6 @@ class Blackboard:
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
# ── Checkpoint CRUD(M3) ──
|
||||
|
||||
def create_checkpoint(
|
||||
|
||||
@@ -355,4 +355,3 @@ class ProjectRegistry:
|
||||
|
||||
def reload(self) -> None:
|
||||
"""兼容旧接口(SQLite 不需要 reload cache)"""
|
||||
pass
|
||||
|
||||
@@ -9,14 +9,14 @@ from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
from src.blackboard.operations import Blackboard
|
||||
from src.utils import get_data_root
|
||||
from src.blackboard.models import Task, Comment, Output, Decision, Observation, Review, Experience
|
||||
import src.utils as _utils
|
||||
from src.blackboard.models import Task, Review
|
||||
from src.blackboard.queries import Queries
|
||||
from src.blackboard.registry import ProjectRegistry
|
||||
|
||||
|
||||
def _find_project_root() -> Path:
|
||||
return get_data_root()
|
||||
return _utils.get_data_root()
|
||||
|
||||
|
||||
def _get_bb(project_id: str) -> Blackboard:
|
||||
@@ -262,7 +262,7 @@ def build_admin_parser() -> argparse.ArgumentParser:
|
||||
p_pc.add_argument("--description", default="")
|
||||
|
||||
# project list
|
||||
p_pl = sub.add_parser("project-list", help="List projects")
|
||||
sub.add_parser("project-list", help="List projects")
|
||||
|
||||
# project archive
|
||||
p_pa = sub.add_parser("project-archive", help="Archive project")
|
||||
|
||||
@@ -11,8 +11,7 @@ A 类 Skill 由引擎确定性注入全文,不靠 Description 触发。
|
||||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, List
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.bootstrap")
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
@@ -22,7 +21,7 @@ from typing import Any, Dict, List, Optional
|
||||
from src.blackboard.models import Task
|
||||
from src.blackboard.db import get_connection
|
||||
from src.daemon.spawner import AgentBusyError
|
||||
from src.daemon.router import AgentRouter, RouteDecision
|
||||
from src.daemon.router import AgentRouter
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.dispatcher")
|
||||
|
||||
@@ -194,6 +193,7 @@ class Dispatcher:
|
||||
_task_id = task.id
|
||||
_mail_db = db_path
|
||||
_disp = self
|
||||
|
||||
def _mail_on_checks_passed():
|
||||
nonlocal _mail_marked_working
|
||||
if not _disp._mail_auto_working(_task_id, _mail_db):
|
||||
@@ -858,7 +858,7 @@ class Dispatcher:
|
||||
logger.error("Task %s: mark status error: %s", task_id, e)
|
||||
|
||||
@staticmethod
|
||||
def _check_crash_limit(task_id: str, db_path: pathlib.Path, limit: int = 3,
|
||||
def _check_crash_limit(task_id: str, db_path: Path, limit: int = 3,
|
||||
window_minutes: int = 30) -> bool:
|
||||
"""v2.8.1 Fix-3c: 检查 task 最近 window_minutes 内的 crash 次数是否超限。
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import logging
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.experience")
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any, Dict
|
||||
|
||||
from src.blackboard.db import get_connection, init_db
|
||||
from src.blackboard.db import get_connection
|
||||
from src.blackboard.queries import Queries
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.health")
|
||||
@@ -41,7 +41,6 @@ class HealthChecker:
|
||||
{"healthy": bool, "zombie": bool, "stale_ticks": int,
|
||||
"alert_written": bool, "resolved": bool}
|
||||
"""
|
||||
db_key = str(db_path)
|
||||
result: Dict[str, Any] = {
|
||||
"healthy": True,
|
||||
"zombie": False,
|
||||
@@ -58,7 +57,6 @@ class HealthChecker:
|
||||
# 用 event count 变化判断是否有真实变更
|
||||
conn = queries._conn()
|
||||
try:
|
||||
total_events = conn.execute("SELECT COUNT(*) FROM events").fetchone()[0]
|
||||
non_tick_events = conn.execute(
|
||||
"SELECT COUNT(*) FROM events WHERE event_type != 'daemon_tick' "
|
||||
"AND event_type != 'agent_zombie_detected'"
|
||||
|
||||
@@ -15,7 +15,6 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Coroutine, Dict, List, Optional
|
||||
|
||||
|
||||
@@ -8,15 +8,12 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
|
||||
from src.blackboard.models import Task
|
||||
from src.blackboard.operations import Blackboard
|
||||
from src.blackboard.queries import Queries
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.review")
|
||||
|
||||
|
||||
@@ -10,12 +10,11 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.skill")
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from src.blackboard.db import get_connection, init_db
|
||||
from src.blackboard.db import get_connection
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.spawner")
|
||||
|
||||
@@ -163,6 +163,7 @@ class AgentBusyError(Exception):
|
||||
|
||||
#07: reason 字段区分具体原因,便于 dispatcher 层区分处理。
|
||||
"""
|
||||
|
||||
def __init__(self, agent_id: str, reason: str = "busy", detail: Optional[dict] = None):
|
||||
self.agent_id = agent_id
|
||||
self.reason = reason # counter_blocked / session_locked / session_running / session_compacting / session_stuck
|
||||
@@ -379,7 +380,6 @@ curl -X POST http://{self.api_host}:{self.api_port}/api/projects/{project_id}/ta
|
||||
return router.agent_profiles.get(agent_id)
|
||||
return None
|
||||
|
||||
|
||||
def _build_mail_prompt(self, task_id: str, title: str, description: str,
|
||||
must_haves: str, agent_id: str) -> str:
|
||||
"""构建 Mail 专用精简模板"""
|
||||
@@ -878,9 +878,6 @@ curl -X POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
stderr_text = b"".join(stderr_chunks).decode("utf-8", errors="replace")
|
||||
|
||||
# 检查 session 状态
|
||||
state = self._check_session_state(agent_id)
|
||||
|
||||
# B1: 假死 - 先复活,连续假死 ≥2 次再 failed
|
||||
@@ -1216,7 +1213,7 @@ curl -X POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_
|
||||
实测 50KB 在长对话中不够(compact 记录被推出窗口导致漏检)。
|
||||
正常扫描量不变:从尾部往前扫,遇到超过 15min 的 timestamp 即 break。
|
||||
"""
|
||||
if not session_file or not pathlib.Path(session_file).exists():
|
||||
if not session_file or not Path(session_file).exists():
|
||||
return False
|
||||
try:
|
||||
from datetime import datetime, timezone
|
||||
|
||||
+1
-4
@@ -9,14 +9,11 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import subprocess
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional, Set
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from src.blackboard.models import Event
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.sse")
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ from dataclasses import dataclass, field as dc_field
|
||||
|
||||
from src.blackboard.operations import Blackboard
|
||||
from src.blackboard.db import get_connection
|
||||
from src.blackboard.models import Task
|
||||
from src.daemon.spawner import AgentBusyError
|
||||
from src.blackboard.queries import Queries
|
||||
from src.blackboard.registry import ProjectRegistry
|
||||
@@ -35,6 +34,7 @@ class BroadcastRound:
|
||||
responded_agents: set = dc_field(default_factory=set) # 已返回反馈的 Agent(含 NO_REPLY)
|
||||
round_number: int = 0 # 当前第几轮(0=未开始,1=第1轮)
|
||||
|
||||
|
||||
logger = logging.getLogger("moziplus-v2.ticker")
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ class Ticker:
|
||||
"Round %d review spawned for parent %s (subs: %s)",
|
||||
new_round, parent_id, summary
|
||||
)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Round check error for parent %s", parent_id)
|
||||
|
||||
return reviewed
|
||||
@@ -543,7 +543,6 @@ Parent Task ID: {parent_task.id}
|
||||
"""
|
||||
try:
|
||||
agent_id = "pangtong-fujunshi"
|
||||
session_id = f"review-{parent_task.id}-r{new_round}"
|
||||
|
||||
# 构造 on_complete 回调:解析庞统结论,更新 parent 状态
|
||||
async def _on_review_complete(aid: str, outcome: str):
|
||||
@@ -586,7 +585,7 @@ Parent Task ID: {parent_task.id}
|
||||
self._set_parent_reviewing(parent_task.id, project_id)
|
||||
return True
|
||||
return False
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Failed to spawn pangtong review for %s", parent_task.id)
|
||||
return False
|
||||
|
||||
@@ -665,8 +664,8 @@ Parent Task ID: {parent_task.id}
|
||||
|
||||
def _resolve_db_path(self, project_id: str) -> Path:
|
||||
"""解析项目 DB 路径"""
|
||||
from src.utils import get_data_root
|
||||
return get_data_root() / project_id / "blackboard.db"
|
||||
import src.utils as _utils
|
||||
return _utils.get_data_root() / project_id / "blackboard.db"
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# @mention 通知处理 (v2.9 #01)
|
||||
@@ -805,7 +804,7 @@ Parent Task ID: {parent_task.id}
|
||||
# Agent 忙,不递增 retry_count,等下次 tick 自然重试
|
||||
logger.info("Mention spawn skipped: %s busy, will retry next tick", agent_id)
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger.exception("Mention processing error for agent %s", agent_id)
|
||||
for item in items:
|
||||
try:
|
||||
|
||||
+12
-12
@@ -23,7 +23,15 @@ from src.daemon.health import HealthChecker
|
||||
from src.daemon.experience import ExperienceDistiller, ExperienceStore
|
||||
from src.daemon.inbox import InboxWatcher
|
||||
from src.daemon.guardrails import GuardrailEngine
|
||||
from src.utils import get_data_root
|
||||
import src.utils as _utils
|
||||
|
||||
from src.api.blackboard_routes import router as blackboard_router
|
||||
from src.api.checkpoint_routes import router as checkpoint_router
|
||||
from src.api.daemon_routes import router as daemon_router
|
||||
from src.api.project_routes import router as project_router
|
||||
from src.api.sse_routes import router as sse_router
|
||||
from src.api.mail_routes import router as mail_router
|
||||
from src.api.toolchain_routes import router as toolchain_router
|
||||
|
||||
logger = logging.getLogger("moziplus-v2")
|
||||
|
||||
@@ -78,7 +86,7 @@ config = load_config()
|
||||
# 全局组件
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
DATA_ROOT = get_data_root()
|
||||
DATA_ROOT = _utils.get_data_root()
|
||||
|
||||
ticker: Optional[Ticker] = None
|
||||
|
||||
@@ -191,7 +199,6 @@ async def lifespan(app: FastAPI):
|
||||
)
|
||||
|
||||
# ExperienceDistiller(经验自动蒸馏)
|
||||
experience_config = config.get("experience", {})
|
||||
experience_distiller = ExperienceDistiller(
|
||||
store=ExperienceStore(store_path=DATA_ROOT / "experiences.jsonl"),
|
||||
)
|
||||
@@ -252,14 +259,6 @@ app.add_middleware(
|
||||
# API 路由注册
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
from src.api.blackboard_routes import router as blackboard_router
|
||||
from src.api.checkpoint_routes import router as checkpoint_router
|
||||
from src.api.daemon_routes import router as daemon_router
|
||||
from src.api.project_routes import router as project_router
|
||||
from src.api.sse_routes import router as sse_router
|
||||
from src.api.mail_routes import router as mail_router
|
||||
from src.api.toolchain_routes import router as toolchain_router
|
||||
|
||||
app.include_router(blackboard_router)
|
||||
app.include_router(checkpoint_router)
|
||||
app.include_router(daemon_router)
|
||||
@@ -289,16 +288,17 @@ async def list_projects_compat():
|
||||
DIST_DIR = Path(__file__).parent / "frontend" / "dist"
|
||||
if DIST_DIR.exists():
|
||||
# v3.1: 缓存策略 - HTML 不缓存(确保新版本生效),JS/CSS 长缓存(Vite content hash 已处理)
|
||||
import mimetypes
|
||||
_static_app = StaticFiles(directory=str(DIST_DIR), html=True)
|
||||
|
||||
class CachedStaticFiles:
|
||||
"""包装 StaticFiles,添加 Cache-Control 头"""
|
||||
|
||||
def __init__(self, app):
|
||||
self._app = app
|
||||
|
||||
async def __call__(self, scope, receive, send):
|
||||
original_send = send
|
||||
|
||||
async def patched_send(message):
|
||||
if message.get("type") == "http.response.start":
|
||||
headers = dict(message.get("headers", []))
|
||||
|
||||
@@ -10,7 +10,6 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def get_data_root() -> Path:
|
||||
|
||||
Reference in New Issue
Block a user