Files
nexus/openclaw/xingshu/agent_polling.py
2026-03-23 20:57:45 +08:00

216 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Agent 任务轮询脚本
每个 Agent 定时运行,查询分配给自己的任务并执行
"""
import os
import sys
import time
import logging
import requests
from datetime import datetime
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# 环境变量或配置
NOTION_TOKEN = os.environ.get("NOTION_TOKEN", "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")
AGENT_ID = os.environ.get("AGENT_ID", "yunjiang") # 当前 Agent ID
POLL_INTERVAL = int(os.environ.get("POLL_INTERVAL", "180")) # 轮询间隔默认3分钟
# Database IDs
TASKS_DB_ID = "32847fe1-da27-8135-af44-eefdbd3b1640"
AGENTS_DB_ID = "32847fe1-da27-8101-8758-d416db87d4de"
# Notion API 基础 URL
NOTION_API_BASE = "https://api.notion.com/v1"
def notion_request(method, endpoint, **kwargs):
"""Notion API 请求封装"""
url = f"{NOTION_API_BASE}{endpoint}"
headers = {
"Authorization": f"Bearer {NOTION_TOKEN}",
"Notion-Version": "2022-06-28",
"Content-Type": "application/json"
}
if method == "GET":
response = requests.get(url, headers=headers, **kwargs)
elif method == "POST":
response = requests.post(url, headers=headers, **kwargs)
elif method == "PATCH":
response = requests.patch(url, headers=headers, **kwargs)
else:
raise ValueError(f"Unsupported method: {method}")
response.raise_for_status()
return response.json()
def get_agent_info(agent_id):
"""获取 Agent 信息"""
response = notion_request("POST", f"/databases/{AGENTS_DB_ID}/query")
for page in response.get("results", []):
props = page.get("properties", {})
if "Agent ID" in props:
title = props["Agent ID"]["title"]
if title and title[0]["plain_text"] == agent_id:
return {
"id": page["id"],
"name": props["名称"]["rich_text"][0]["plain_text"] if props["名称"]["rich_text"] else agent_id,
"status": props["状态"]["select"]["name"] if props["状态"].get("select") else "离线"
}
return None
def query_todo_tasks(agent_page_id=None):
"""查询 TODO 任务"""
logger.info(f"查询 {AGENT_ID} 的 TODO 任务...")
# 如果有 agent_page_id使用 Relation 过滤
filter_dict = {
"property": "状态",
"select": {
"equals": "TODO"
}
}
# 这里简化处理:查询所有 TODO 任务
# 后续应该根据执行者 Relation 过滤
try:
response = notion_request(
"POST",
f"/databases/{TASKS_DB_ID}/query",
json={"filter": filter_dict}
)
tasks = response.get("results", [])
logger.info(f"找到 {len(tasks)} 个 TODO 任务")
return tasks
except Exception as e:
logger.error(f"查询任务失败: {e}")
return []
def claim_task(task_id):
"""领取任务:将状态改为进行中"""
try:
notion_request(
"PATCH",
f"/pages/{task_id}",
json={
"properties": {
"状态": {
"select": {"name": "进行中"}
}
}
}
)
logger.info(f"✓ 领取任务成功: {task_id}")
return True
except Exception as e:
logger.error(f"领取任务失败: {e}")
return False
def complete_task(task_id, report_link):
"""完成任务:将状态改为待验收"""
try:
notion_request(
"PATCH",
f"/pages/{task_id}",
json={
"properties": {
"状态": {
"select": {"name": "待验收"}
},
"报告链接": {
"url": report_link
}
}
}
)
logger.info(f"✓ 完成任务: {task_id}")
return True
except Exception as e:
logger.error(f"完成任务失败: {e}")
return False
def execute_task(task):
"""执行任务的逻辑(可自定义)"""
# 获取任务信息
props = task.get("properties", {})
task_name = props.get("任务名", {}).get("title", [{}])[0].get("plain_text", "未命名任务")
task_id = task["id"]
logger.info(f"开始执行任务: {task_name}")
# 1. 领取任务
if not claim_task(task_id):
return False
# 2. 执行任务(这里只是示例,实际应根据任务类型执行不同操作)
# 模拟执行
time.sleep(2)
# 3. 完成任务(生成报告链接)
# 这里应该生成实际的 Obsidian 报告
report_link = f"https://example.com/report/{task_id}"
return complete_task(task_id, report_link)
def polling_loop():
"""轮询主循环"""
logger.info(f"🚀 Agent {AGENT_ID} 任务轮询启动")
logger.info(f"轮询间隔: {POLL_INTERVAL}")
# 获取 Agent 信息
agent_info = get_agent_info(AGENT_ID)
if agent_info:
logger.info(f"Agent 信息: {agent_info['name']} (状态: {agent_info['status']})")
else:
logger.warning(f"未找到 Agent: {AGENT_ID}")
while True:
try:
# 查询 TODO 任务
tasks = query_todo_tasks(None)
if tasks:
logger.info(f"发现 {len(tasks)} 个待处理任务")
for task in tasks:
execute_task(task)
else:
logger.debug("没有待处理任务")
except Exception as e:
logger.error(f"轮询异常: {e}")
time.sleep(POLL_INTERVAL)
def main():
"""主入口"""
if len(sys.argv) > 1:
global AGENT_ID
AGENT_ID = sys.argv[1]
if len(sys.argv) > 2:
global POLL_INTERVAL
POLL_INTERVAL = int(sys.argv[2])
polling_loop()
if __name__ == "__main__":
main()