From 2b5cbff7be4ae952450254749fe8bd626f78613a Mon Sep 17 00:00:00 2001 From: Liang Jiaqing Date: Sun, 12 Apr 2026 14:29:32 +0800 Subject: [PATCH] feat: --verbose flag, lazy mykeys loading, temperature config support - agentmain: add --verbose arg for subagent monitoring mode - llmcore: lazy-load mykeys/proxies via module __getattr__ - llmcore: fix auto_make_url regex for trailing slash cases - llmcore: support temperature override from session config - docs: update subagent.md with --verbose usage note --- agentmain.py | 3 ++- assets/insight_fixed_structure.txt | 2 +- llmcore.py | 30 +++++++++++++++++------------- memory/subagent.md | 1 + 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/agentmain.py b/agentmain.py index 1d2d963..f682c51 100644 --- a/agentmain.py +++ b/agentmain.py @@ -158,6 +158,7 @@ if __name__ == '__main__': parser.add_argument('--reflect', metavar='SCRIPT', help='反射模式:加载监控脚本,check()触发时发任务') parser.add_argument('--input', help='任务内容') parser.add_argument('--llm_no', type=int, default=0, help='LLM编号') + parser.add_argument('--verbose', action='store_true', help='输出包含工具执行结果(监察模式用)') parser.add_argument('--bg', action='store_true', help='后台自举: spawn自身去掉--bg, print PID, exit') args = parser.parse_args() @@ -173,7 +174,7 @@ if __name__ == '__main__': agent = GeneraticAgent() agent.next_llm(args.llm_no) - agent.verbose = False + agent.verbose = args.verbose threading.Thread(target=agent.run, daemon=True).start() if args.task: diff --git a/assets/insight_fixed_structure.txt b/assets/insight_fixed_structure.txt index 8d03a25..1683371 100644 --- a/assets/insight_fixed_structure.txt +++ b/assets/insight_fixed_structure.txt @@ -1,4 +1,4 @@ -Facts(L2): ../memory/global_mem.txt | Code: ../ | SOPs(L3): ../memory/*.md or *.py | META-SOP(L0): ../memory/memory_management_sop.md +Facts(L2): ../memory/global_mem.txt | CodeRoot: ../ | SOPs(L3): ../memory/*.md or *.py | META-SOP(L0): ../memory/memory_management_sop.md L1 Insight是极简索引,L2/L3变更时同步L1,索引必须极简。写记忆前先读META-SOP(L0)。 [CONSTITUTION] diff --git a/llmcore.py b/llmcore.py index f248f7f..e989ae2 100644 --- a/llmcore.py +++ b/llmcore.py @@ -10,9 +10,14 @@ def _load_mykeys(): if not os.path.exists(p): raise Exception('[ERROR] mykey.py or mykey.json not found, please create one from mykey_template.') with open(p, encoding='utf-8') as f: return json.load(f) -mykeys = _load_mykeys() -proxy = mykeys.get("proxy", 'http://127.0.0.1:2082') -proxies = {"http": proxy, "https": proxy} if proxy else None +def __getattr__(name): + if name in ('mykeys', 'proxies'): + mk = _load_mykeys() + proxy = mk.get("proxy", 'http://127.0.0.1:2082') + px = {"http": proxy, "https": proxy} if proxy else None + globals().update(mykeys=mk, proxies=px) + return globals()[name] + raise AttributeError(f"module 'llmcore' has no attribute {name}") def compress_history_tags(messages, keep_recent=10, max_len=800, force=False): """Compress // tags in older messages to save tokens.""" @@ -61,8 +66,7 @@ def _sanitize_leading_user_msg(msg): if isinstance(c, list): # content 本身也可能是 list[{type:text,text:...}] texts.extend(b.get('text', '') for b in c if isinstance(b, dict)) else: texts.append(str(c)) - elif block.get('type') == 'text': - texts.append(block.get('text', '')) + elif block.get('type') == 'text': texts.append(block.get('text', '')) msg['content'] = [{"type": "text", "text": '\n'.join(t for t in texts if t)}] return msg @@ -83,7 +87,8 @@ def trim_messages_history(history, context_win): def auto_make_url(base, path): b, p = base.rstrip('/'), path.strip('/') if b.endswith('$'): return b[:-1].rstrip('/') - return b if b.endswith(p) else f"{b}/{p}" if re.search(r'/v\d+$', b) else f"{b}/v1/{p}" + if b.endswith(p): return b + return f"{b}/{p}" if re.search(r'/v\d+(/|$)', b) else f"{b}/v1/{p}" def build_multimodal_content(prompt_text, image_paths): parts = [] @@ -439,6 +444,7 @@ class BaseSession: if effort and not self.reasoning_effort: print(f"[WARN] Invalid reasoning_effort {effort!r}, ignored.") mode = str(cfg.get('api_mode', 'chat_completions')).strip().lower().replace('-', '_') self.api_mode = 'responses' if mode in ('responses', 'response') else 'chat_completions' + self.temperature = cfg.get('temperature') def ask(self, prompt, stream=False): def _ask_gen(): content = '' @@ -519,6 +525,7 @@ class NativeClaudeSession(BaseSession): def raw_ask(self, messages, temperature=0.5, max_tokens=6144): messages = _fix_messages(messages) model = self.default_model + if self.temperature is not None: temperature = self.temperature beta_parts = ["claude-code-20250219", "interleaved-thinking-2025-05-14", "redact-thinking-2026-02-12", "prompt-caching-scope-2026-01-05"] if "[1m]" in model.lower(): beta_parts.insert(1, "context-1m-2025-08-07"); model = model.replace("[1m]", "").replace("[1M]", "") @@ -553,7 +560,6 @@ class NativeClaudeSession(BaseSession): self.history.append(msg) trim_messages_history(self.history, self.context_win) messages = [{"role": m["role"], "content": list(m["content"])} for m in self.history] - content_blocks = None gen = self.raw_ask(messages) try: @@ -580,8 +586,8 @@ class NativeOAISession(NativeClaudeSession): """OpenAI streaming. yields text chunks, generator return = list[content_block]""" msgs = ([{"role": "system", "content": self.system}] if self.system else []) + _msgs_claude2oai(messages) return (yield from _openai_stream(self.api_base, self.api_key, msgs, self.default_model, self.api_mode, - temperature=temperature, max_tokens=max_tokens, tools=self.tools, - reasoning_effort=self.reasoning_effort, + temperature=temperature, max_tokens=max_tokens, + tools=self.tools, reasoning_effort=self.reasoning_effort, max_retries=self.max_retries, connect_timeout=self.connect_timeout, read_timeout=self.read_timeout, proxies=self.proxies)) @@ -591,10 +597,8 @@ def openai_tools_to_claude(tools): for t in tools: if 'input_schema' in t: result.append(t); continue # 已是claude格式 fn = t.get('function', t) - result.append({ - 'name': fn['name'], 'description': fn.get('description', ''), - 'input_schema': fn.get('parameters', {'type': 'object', 'properties': {}}) - }) + result.append({'name': fn['name'], 'description': fn.get('description', ''), + 'input_schema': fn.get('parameters', {'type': 'object', 'properties': {}})}) return result diff --git a/memory/subagent.md b/memory/subagent.md index c091689..a505492 100644 --- a/memory/subagent.md +++ b/memory/subagent.md @@ -10,6 +10,7 @@ - 通信:output.txt(append,`[ROUND END]`=轮完成) → 写reply.txt继续 → 不写10min退出。reply后输出为output1/2/3.txt(同格式) - 干预文件:`_stop`(当轮结束退出) | `_keyinfo`(注入working memory) | `_intervene`(追加指令) - **主agent空闲时应读output观察进度,必要时用干预文件纠偏,禁止无脑长时间sleep轮询** +- 监察模式启动时加`--verbose`,output将包含工具执行结果,主agent可直接审查原始数据而非仅信任摘要 ## 场景1:测试模式 - 行为验证 **用途**:观察agent真实行为,修正RULES/L2/L3/SOP