diff --git a/.gitignore b/.gitignore index bfdd5cc..9be5089 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ auth.json # 忽略模型响应记录 model_responses.txt +# 任务调度目录 +tasks/ + *.zip # 存储敏感信息的记忆文件夹(除了公开的 SOP) @@ -42,6 +45,7 @@ memory/* # Allow tracking of specific SOPs !memory/web_setup_sop.md !memory/autonomous_operation_sop.md +!memory/scheduled_task_sop.md # ljqCtrl related tools !memory/ljqCtrl.py diff --git a/agent_loop.py b/agent_loop.py index 2f756c4..825a741 100644 --- a/agent_loop.py +++ b/agent_loop.py @@ -26,7 +26,7 @@ class BaseHandler: elif tool_name == 'bad_json': return StepOutcome(None, next_prompt=args.get('msg', 'bad_json'), should_exit=False) else: - yield f"❌ 未知工具: {tool_name}\n" + yield f"未知工具: {tool_name}\n" return StepOutcome(None, next_prompt=f"未知工具 {tool_name}", should_exit=False) def json_default(o): diff --git a/agentmain.py b/agentmain.py index 8fc3353..45f1727 100644 --- a/agentmain.py +++ b/agentmain.py @@ -1,4 +1,4 @@ -import os, sys, threading, queue, time, json, re +import os, sys, threading, queue, time, json, re, random if sys.stdout is None: sys.stdout = open(os.devnull, "w") elif hasattr(sys.stdout, 'reconfigure'): sys.stdout.reconfigure(errors='replace') if sys.stderr is None: sys.stderr = open(os.devnull, "w") @@ -110,3 +110,23 @@ class GeneraticAgent: if self.handler is not None: self.handler.code_stop_signal.append(1) +if __name__ == '__main__': + from datetime import datetime + agent = GeneraticAgent() + threading.Thread(target=agent.run, daemon=True).start() + def drain(dq, tag): + while True: + item = dq.get(); txt = item.get('done') or item.get('next', '') + open('./temp/scheduler_live.log', 'w', encoding='utf-8').write(txt) + if 'done' in item: break + open('./temp/scheduler.log', 'a', encoding='utf-8').write(f'[{datetime.now():%m-%d %H:%M}] {tag}\n{txt}\n\n') + while True: + now = datetime.now() + for f in os.listdir('./tasks/pending'): + m = re.match(r'(\d{4}-\d{2}-\d{2})_(\d{4})_', f) + if m and now >= datetime.strptime(f'{m[1]} {m[2]}', '%Y-%m-%d %H%M'): + raw = open(f'./tasks/pending/{f}', encoding='utf-8').read() + dq = agent.put_task(f'按scheduled_task_sop执行任务文件 ./tasks/pending/{f}(立刻移到running)\n内容:\n{raw}', source='scheduler') + threading.Thread(target=drain, args=(dq, f), daemon=True).start() + break + time.sleep(55 + random.random() * 10) \ No newline at end of file diff --git a/memory/scheduled_task_sop.md b/memory/scheduled_task_sop.md new file mode 100644 index 0000000..aaca4b8 --- /dev/null +++ b/memory/scheduled_task_sop.md @@ -0,0 +1,11 @@ +# 定时任务 SOP + +目录:`../tasks/{pending,running,done}/` +文件名:`YYYY-MM-DD_HHMM_描述.md`,内容含prompt和schedule + +## 流程 +1. [AUTO]唤醒 → `datetime.now()`取当前时间,`ls ../tasks/pending/`,文件名时间≤当前→到期,选择一个 +2. **立即rename到running/**(先占再读,防多进程重复领) +3. 读文件执行 +4. 完成→移到done/,**在文件内追加执行报告**供用户查阅 +5. schedule非once→算下次时间,新建文件到pending/ diff --git a/sidercall.py b/sidercall.py index 57ccd5c..0cefd2c 100644 --- a/sidercall.py +++ b/sidercall.py @@ -28,7 +28,7 @@ class SiderLLMSession: return full_text class ClaudeSession: - def __init__(self, api_key, api_base, model="claude-opus", context_win=12000): + def __init__(self, api_key, api_base, model="claude-opus", context_win=10000): self.api_key, self.api_base, self.default_model, self.context_win = api_key, api_base.rstrip('/'), model, context_win self.raw_msgs, self.lock = [], threading.Lock() def _trim_messages(self, messages):