# SupplyAgent — project architecture

## Directory layout

```
SupplyAgent/
│
├── supply_agent/                  # 核心 Agent 框架（通用，不含业务）
│   ├── agent/                     #   Agent 主类 + ReAct 循环
│   ├── llm/                       #   OpenRouter LLM 客户端
│   ├── tools/                     #   @tool 装饰器 + 工具注册表
│   ├── skills/                    #   Skill 加载器
│   ├── logging/                   #   运行日志
│   └── config.py                  #   Agent 配置
│
├── supply_infra/                  # 共享基础设施（所有 Agent / 定时任务共用）
│   ├── config.py                  #   MySQL / ODPS / Scheduler 配置
│   ├── agent_logging/             #   注册 Agent 运行日志 OSS 发布 hook
│   ├── scoring/                   #   后验 diff / 排名归一化（分级与热度树共用）
│   ├── db/
│   │   ├── base.py                #   SQLAlchemy Base + TimestampMixin
│   │   ├── session.py             #   Engine + get_session()
│   │   ├── models/                #   ORM 实体类（一张表一个文件）
│   │   │   └── video_content.py
│   │   └── repositories/          #   数据访问层（CRUD / upsert）
│   │       ├── base.py
│   │       └── video_content_repo.py
│   ├── odps/
│   │   └── client.py              #   ODPS 查询封装
│   ├── scheduler/
│   │   ├── app.py                 #   APScheduler 调度器（随 API 启动）
│   │   └── jobs/                  #   流水线任务（含 python -m CLI）
│   │       ├── run_supply_pipeline.py
│   │       ├── demand_pool/
│   │       └── ...
│   └── tools/
│       └── db_tools.py            #   共享 MySQL 读写工具（供 Agent 调用）
│
├── agents/                        # 所有业务 Agent（一个 Agent 一个子目录）
│   ├── find_agent/                #   第一个 Agent：内容发现
│   │   ├── agent.py               #   create_find_agent() 工厂
│   │   ├── run.py                 #   交互式运行入口
│   │   └── tools/                 #   Agent 专属工具
│   │       ├── douyin_search.py
│   │       └── qwen_video_analyze.py
│   └── <your_next_agent>/         #   新增 Agent 按此结构复制
│       ├── agent.py
│       ├── run.py
│       └── tools/
│
├── skills/                        # 全局共享 Skills（SKILL.md）
├── examples/                      # 框架使用示例
├── tests/
├── logs/                          # 运行日志（自动生成）
├── requirements.txt
└── pyproject.toml
```

## Layer responsibilities

| 层 | 包 | 职责 | 谁用 |
|----|-----|------|------|
| 框架层 | `supply_agent` | LLM 调用、工具/技能机制、ReAct 循环；运行结束后通过 hook 发布产物（不含 OSS/DB） | 所有 Agent |
| 基础设施层 | `supply_infra` | DB ORM、ODPS、定时任务、共享 DB 工具；`agent_logging` 注册 OSS 日志发布 hook | 所有 Agent + 定时任务 |
| 业务层 | `agents/*` | 具体 Agent 逻辑、专属工具、工厂函数 | 业务开发 |

## Data flow

```
                    ┌─────────────┐
                    │   ODPS      │
                    └──────┬──────┘
                           │ 定时任务 (每天 15:00)
                           ▼
┌──────────┐    ┌─────────────────────┐    ┌──────────┐
│  Agent   │───▶│  Repository (ORM)   │◀───│  Agent   │
│  Tools   │    │  video_content 表    │    │  Tools   │
└──────────┘    └─────────────────────┘    └──────────┘
                           ▲
                           │ upsert / query
                    ┌──────┴──────┐
                    │   MySQL     │
                    └─────────────┘
```

**关键原则**：Agent Tools 和定时任务**不直接写 SQL**，统一通过 `Repository` 操作 ORM 实体。

## How to add a new Agent

```bash
agents/
└── report_agent/              # 1. 新建目录
    ├── agent.py               # 2. create_report_agent() 工厂
    ├── run.py                   # 3. 运行入口
    └── tools/                   # 4. 专属工具
        └── __init__.py
```

```python
# agents/report_agent/agent.py
from supply_agent import Agent
from agents.report_agent.tools import register_all_tools
from supply_infra.tools.db_tools import query_video_content  # 可复用共享工具

def create_report_agent(**kwargs) -> Agent:
    agent = Agent(system_prompt="你是报告生成助手...", **kwargs)
    register_all_tools(agent.tools)
    agent.tools.from_decorated(query_video_content)  # 复用基础设施
    return agent
```

## How to add a new ORM entity

```bash
supply_infra/db/
├── models/new_table.py          # 1. 定义实体类
└── repositories/new_table_repo.py  # 2. 定义 Repository
```

然后在 `models/__init__.py` 中导出，供 `init_db()` 自动建表。

## How to add a new scheduled job

```bash
# 1. 在 supply_infra/scheduler/jobs/ 中定义任务函数与 python -m CLI
# 2. 若需纳入日批，在 run_supply_pipeline 的 steps 中追加
# 3. 默认定时仍只注册 run_supply_pipeline；单步可通过 API manual_jobs 触发
```

```python
# 仅当确需独立 Cron 时，才在 supply_infra/scheduler/app.py 中额外注册
scheduler.add_job(new_job, trigger=CronTrigger(hour=3), id="new_job")
```

## CLI commands

```bash
# 初始化数据库表
python -m supply_infra.db

# 启动 API（同时启动定时任务，需 SCHEDULER_ENABLED=true）
python -m api

# 手动跑全链路
python -m supply_infra.scheduler.jobs.run_supply_pipeline

# 运行 find_agent
python agents/find_agent/run.py
```
