重写为 AI 情报 Agent 并接入 Jenkins 流水线

This commit is contained in:
Codex
2026-07-08 21:41:46 +08:00
commit f471c2a08a
45 changed files with 2163 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
from fastapi.testclient import TestClient
from app.main import create_app
def test_health_endpoint_returns_app_identity() -> None:
# 健康检查只暴露服务身份,不触发Agent运行或数据库写入。
with TestClient(create_app()) as client:
response = client.get("/health")
assert response.status_code == 200
assert response.json()["status"] == "ok"
assert response.json()["app"] == "SignalScout"
+25
View File
@@ -0,0 +1,25 @@
from app.core.config import Settings
from app.integrations.github_client import GitHubHotProjectClient
def test_github_client_maps_repository_to_signal() -> None:
# GitHub仓库候选先标准化为信号,再交给模型做最终筛选。
client = GitHubHotProjectClient(Settings())
signal = client._to_signal_item(
{
"full_name": "example/agent-kit",
"description": "Agent framework for production workflows.",
"html_url": "https://github.com/example/agent-kit",
"stargazers_count": 2400,
"forks_count": 180,
"language": "Python",
"created_at": "2026-05-01T09:00:00Z",
"pushed_at": "2026-05-07T10:00:00Z",
}
)
assert signal.topic == "GitHub 热门项目"
assert signal.source_name == "GitHub"
assert signal.source_url == "https://github.com/example/agent-kit"
assert "2400 stars" in signal.summary
assert "2026-05-01" in signal.summary
+73
View File
@@ -0,0 +1,73 @@
from datetime import date, datetime
from app.core.config import Settings
from app.db.models import Topic
from app.llm.grok_client import GrokIntelligenceClient
from app.schemas.agent import SignalItem
class StubGrokClient(GrokIntelligenceClient):
def _chat_json(self, messages):
# 测试只验证提示词输入和结果契约,不访问真实模型服务。
assert "github_candidates" in messages[1]["content"]
return {
"title": "AI 情报日报 2026-07-08",
"signals": [
{
"topic": "GitHub 热门项目",
"title": "example/agent-kit",
"summary": "该项目提供生产级 Agent 工作流能力。",
"source_url": "https://github.com/example/agent-kit",
"source_name": "GitHub",
"published_at": "2026-07-08T00:00:00",
"importance": 4,
"entities": ["example/agent-kit", "Agent"],
}
],
"report_markdown": "# AI 情报日报 2026-07-08",
"raw_response": {"notes": "基于模型检索和 GitHub 候选筛选。"},
}
def test_grok_client_returns_agent_result() -> None:
# Grok客户端是日报与结构化情报的唯一生成入口。
client = StubGrokClient(Settings(llm_api_key="test-key"))
result = client.collect_daily_intelligence(
topics=[
Topic(
id=1,
name="Open-source AI projects",
description="Agent frameworks and open-source AI tools.",
enabled=True,
)
],
news_candidates=[
SignalItem(
topic="AI 新闻候选",
title="New model release",
summary="News candidate from example.com.",
source_url="https://example.com/model-release",
source_name="example.com",
published_at=datetime(2026, 7, 8),
importance=3,
entities=["example.com"],
)
],
github_projects=[
SignalItem(
topic="GitHub 热门项目",
title="example/agent-kit",
summary="Agent framework.",
source_url="https://github.com/example/agent-kit",
source_name="GitHub",
published_at=datetime(2026, 7, 8),
importance=4,
entities=["Agent"],
)
],
run_date=date(2026, 7, 8),
)
assert result.title == "AI 情报日报 2026-07-08"
assert result.signals[0].source_name == "GitHub"
assert result.report_markdown.startswith("# AI 情报日报")
+22
View File
@@ -0,0 +1,22 @@
from app.core.config import Settings
from app.integrations.news_search_client import NewsSearchClient
def test_news_search_client_maps_article_to_candidate() -> None:
# 新闻搜索结果会先转为候选信号,再交给模型筛选成最终情报。
client = NewsSearchClient(Settings())
signal = client._article_to_signal(
{
"title": "AI agent platform launches",
"url": "https://example.com/ai-agent-platform",
"domain": "example.com",
"sourcecountry": "US",
"seendate": "20260708T120000Z",
}
)
assert signal is not None
assert signal.topic == "AI 新闻候选"
assert signal.source_name == "example.com"
assert signal.published_at is not None
assert signal.published_at.year == 2026