From 0a045a0c4ba7dd0c067deba7b623c9693dc0e683 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 9 Jul 2026 00:38:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=AA=E8=A1=A8=E7=9B=98=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E6=9C=80=E6=96=B0=E8=BF=90=E8=A1=8C=E5=BF=AB=E7=85=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/routes.py | 22 +++++++++++-- tests/test_api_health.py | 68 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/app/api/routes.py b/app/api/routes.py index a2db2c6..9da625e 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -98,14 +98,25 @@ def latest_report(db: Session = Depends(get_db)) -> Optional[Report]: def dashboard(db: Session = Depends(get_db)) -> DashboardRead: # 单个仪表盘接口返回运行、信号、日报和主题,前端不需要理解内部调度细节。 runs = list(db.scalars(select(AgentRun).order_by(AgentRun.id.desc()).limit(10)).all()) + latest_completed_run = db.scalar( + select(AgentRun) + .where(AgentRun.status == "completed") + .order_by(AgentRun.id.desc()) + .limit(1) + ) + latest_run_id = latest_completed_run.id if latest_completed_run is not None else None news_signals = list( db.scalars( - _visible_signals_query(source_type="news").order_by(Signal.id.desc()).limit(80) + _visible_signals_query(source_type="news", run_id=latest_run_id) + .order_by(Signal.id.desc()) + .limit(80) ).all() ) github_signals = list( db.scalars( - _visible_signals_query(source_type="github").order_by(Signal.id.desc()).limit(80) + _visible_signals_query(source_type="github", run_id=latest_run_id) + .order_by(Signal.id.desc()) + .limit(80) ).all() ) report = db.scalar(select(Report).order_by(Report.id.desc()).limit(1)) @@ -144,9 +155,14 @@ def list_topics(db: Session = Depends(get_db)) -> list[Topic]: return list(db.scalars(select(Topic).order_by(Topic.id.asc())).all()) -def _visible_signals_query(source_type: Optional[Literal["news", "github"]] = None): +def _visible_signals_query( + source_type: Optional[Literal["news", "github"]] = None, + run_id: Optional[int] = None, +): # 运行中的信号和完成后的信号走同一张表,查询函数保留统一排序入口。 query = select(Signal).join(AgentRun, Signal.run_id == AgentRun.id) if source_type is not None: query = query.where(Signal.source_type == source_type) + if run_id is not None: + query = query.where(Signal.run_id == run_id) return query diff --git a/tests/test_api_health.py b/tests/test_api_health.py index 025ca22..da6323f 100644 --- a/tests/test_api_health.py +++ b/tests/test_api_health.py @@ -191,3 +191,71 @@ def test_dashboard_returns_news_and_github_signals_separately(monkeypatch) -> No assert [item["source_type"] for item in dashboard["github_signals"]] == ["github"] assert github_response.status_code == 200 assert [item["title"] for item in github_response.json()] == ["example/agent-kit"] + + +def test_dashboard_uses_latest_completed_run_signals(monkeypatch) -> None: + # 情报页展示最新完成运行的快照,历史运行只保留在记录和明细接口里。 + monkeypatch.setenv("SIGNALSCOUT_ENV", "test") + get_settings.cache_clear() + engine = create_engine( + "sqlite:///:memory:", + connect_args={"check_same_thread": False}, + poolclass=StaticPool, + future=True, + ) + TestingSessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True) + Base.metadata.create_all(engine) + + with TestingSessionLocal() as session: + old_run = AgentRun(status="completed", started_at=datetime(2026, 7, 8, 8, 0), request_payload={}) + new_run = AgentRun(status="completed", started_at=datetime(2026, 7, 8, 9, 0), request_payload={}) + session.add_all([old_run, new_run]) + session.flush() + session.add_all( + [ + Signal( + run_id=old_run.id, + source_type="news", + topic="AI 新闻", + title="Old signal", + summary="旧运行信号。", + source_url="https://example.com/old", + source_url_hash="old-hash", + source_name="Example", + published_at=datetime(2026, 7, 8, 8, 0), + importance=3, + entities=[], + ), + Signal( + run_id=new_run.id, + source_type="news", + topic="AI 新闻", + title="New signal", + summary="新运行信号。", + source_url="https://example.com/new", + source_url_hash="new-hash", + source_name="Example", + published_at=datetime(2026, 7, 8, 9, 0), + importance=4, + entities=[], + ), + ] + ) + session.commit() + + def override_get_db(): + # 仪表盘快照测试使用内存库构造多运行场景。 + db = TestingSessionLocal() + try: + yield db + finally: + db.close() + + app = create_app() + app.dependency_overrides[get_db] = override_get_db + with TestClient(app) as client: + response = client.get("/dashboard") + get_settings.cache_clear() + + assert response.status_code == 200 + assert [item["title"] for item in response.json()["news_signals"]] == ["New signal"]