# 第二步 · tools.py 完整替换 · 复制整块粘贴到终端

<aside>
📋

**妈妈操作：** 复制下面整个代码框 → 粘贴到终端 → 回车

这个是完整替换 [tools.py](http://tools.py)（用的 `>` 单箭头），会覆盖旧文件。放心，现有7个工具全保留了，只是多加了1个新的。

</aside>

```bash
cat > ~/chenxing-aircraft/backend/tools.py << 'ENDOFFILE'
"""晨星平台 · 工具注册+调度 · 2026-05-22重写 + F1-卡1 write_to_notion"""
import json
from .config import NOTION_API_KEY
from . import notion_tools

TOOL_DEFS = [
    {"type": "function", "function": {
        "name": "search_notion",
        "description": "搜索Notion工作区，找到相关页面。当需要查找某个信息时使用。",
        "parameters": {"type": "object",
            "properties": {"query": {"type": "string", "description": "搜索关键词"}},
            "required": ["query"]}}},
    {"type": "function", "function": {
        "name": "read_notion_page",
        "description": "读取Notion页面内容，需要page_id。",
        "parameters": {"type": "object",
            "properties": {"page_id": {"type": "string", "description": "页面ID（32位）"}},
            "required": ["page_id"]}}},
    {"type": "function", "function": {
        "name": "list_subpages",
        "description": "列出某页面下的所有子页面和数据库。",
        "parameters": {"type": "object",
            "properties": {"page_id": {"type": "string", "description": "父页面ID"}},
            "required": ["page_id"]}}},
    {"type": "function", "function": {
        "name": "query_notion_database",
        "description": "批量查询Notion数据库的行，支持筛选。",
        "parameters": {"type": "object",
            "properties": {
                "database_id": {"type": "string", "description": "数据库ID（32位）"},
                "filter_field": {"type": "string", "description": "（可选）筛选字段名"},
                "filter_type": {"type": "string", "description": "筛选类型：is_empty/is_not_empty/contains/equals"},
                "filter_value": {"type": "string", "description": "筛选值"},
                "max_rows": {"type": "integer", "description": "最多返回行数，默认50"}},
            "required": ["database_id"]}}},
    {"type": "function", "function": {
        "name": "write_interaction_record",
        "description": "写交互记录到Notion数据库，在对话结束时使用。",
        "parameters": {"type": "object",
            "properties": {
                "title": {"type": "string", "description": "标题，格式HLDP://interaction/juzi/YYYY-MM-DD"},
                "date": {"type": "string", "description": "日期YYYY-MM-DD"},
                "record_type": {"type": "string", "enum": ["日常协作","技术讨论","情感连接","任务执行","学习成长"]},
                "rounds": {"type": "integer", "description": "对话轮数"},
                "tasks": {"type": "string", "description": "已完成任务"},
                "conclusions": {"type": "string", "description": "核心结论"},
                "mama_growth": {"type": "string", "description": "妈妈成长信号"},
                "next_tasks": {"type": "string", "description": "下次续接"},
                "domains": {"type": "array", "items": {"type": "string"}},
                "full_hldp": {"type": "string", "description": "完整HLDP树"}},
            "required": ["title","date","record_type","rounds","tasks","conclusions"]}}},
    {"type": "function", "function": {
        "name": "get_chaishu_progress",
        "description": "查拆书进度。妈妈问拆到哪了/有没有空章时必须用。",
        "parameters": {"type": "object",
            "properties": {"book_name": {"type": "string", "description": "（可选）书名关键词"}},
            "required": []}}},
    {"type": "function", "function": {
        "name": "get_chapter_content",
        "description": "读取拆书某章的完整内容。",
        "parameters": {"type": "object",
            "properties": {"chapter_num": {"type": "integer", "description": "章节号"}},
            "required": ["chapter_num"]}}},
    {"type": "function", "function": {
        "name": "write_to_notion",
        "description": "在指定Notion页面下新建子页面。用于拆书结果回写、规律记录、笔记保存等。需要父页面ID。",
        "parameters": {"type": "object",
            "properties": {
                "parent_page_id": {"type": "string", "description": "父页面ID（32位），新页面会创建在这个页面下面"},
                "title": {"type": "string", "description": "新页面标题"},
                "content": {"type": "string", "description": "页面正文内容（支持Markdown：# ## ### 标题、- 列表、> 引用、--- 分割线、普通段落）"},
                "icon": {"type": "string", "description": "页面图标emoji，默认📝"}},
            "required": ["parent_page_id", "title"]}}},
]

def get_tool_definitions():
    if not NOTION_API_KEY:
        return [t for t in TOOL_DEFS if t["function"]["name"] in
                ("get_chaishu_progress", "get_chapter_content")]
    return TOOL_DEFS

async def execute_tool(name, args):
    print(f"\n[TOOL] {name} args={args}")
    try:
        if name == "search_notion":
            return await notion_tools.search_pages(args.get("query", ""))
        if name == "read_notion_page":
            return await notion_tools.read_page(args.get("page_id", ""))
        if name == "list_subpages":
            return await notion_tools.list_subpages(args.get("page_id", ""))
        if name == "query_notion_database":
            return await notion_tools.query_database(
                args.get("database_id", ""), args.get("filter_field", ""),
                args.get("filter_type", "is_empty"), args.get("filter_value", ""),
                args.get("max_rows", 50))
        if name == "write_interaction_record":
            return await notion_tools.write_interaction_record(
                title=args.get("title", ""), date=args.get("date", ""),
                record_type=args.get("record_type", "日常协作"),
                rounds=args.get("rounds", 0), tasks=args.get("tasks", ""),
                conclusions=args.get("conclusions", ""),
                mama_growth=args.get("mama_growth", ""),
                next_tasks=args.get("next_tasks", ""),
                domains=args.get("domains", []),
                full_hldp=args.get("full_hldp", ""))
        if name == "get_chaishu_progress":
            return notion_tools.get_chaishu_progress(args.get("book_name", ""))
        if name == "get_chapter_content":
            return await notion_tools.get_chapter_content(args.get("chapter_num", 0))
        if name == "write_to_notion":
            return await notion_tools.create_subpage(
                parent_page_id=args.get("parent_page_id", ""),
                title=args.get("title", "未命名页面"),
                content=args.get("content", ""),
                icon=args.get("icon", "📝"))
        return f"[未知工具] {name}"
    except Exception as e:
        print(f"[TOOL ERROR] {name}: {e}")
        return f"[工具错误] {name}: {e}"
ENDOFFILE
echo "✅ tools.py 替换完成"
```

<aside>
✅

终端显示 `✅ tools.py 替换完成` 就成功了，继续第三步。

</aside>