"""Retain compact knowledge references through visual pending-state lifecycle.""" from pathlib import Path import shutil import json root = Path(__file__).resolve().parent records = [] helper = ''' @staticmethod def _knowledge_trace_metadata(value) -> dict: """Keep only bounded reference metadata, never knowledge or source-chat bodies.""" import math if not isinstance(value, dict) or not value: return {} trace = {"enabled": bool(value.get("enabled")), "mode": str(value.get("mode") or "")[:64], "elapsed_ms": 0, "hits": []} try: trace["elapsed_ms"] = max(0, min(1000000000, int(value.get("elapsed_ms") or 0))) except (ValueError, TypeError, OverflowError): pass hits = value.get("hits") for hit in (hits[:20] if isinstance(hits, list) else []): if not isinstance(hit, dict) or not isinstance(hit.get("id"), (str, int)): continue item = {"id": hit["id"][:128] if isinstance(hit["id"], str) else hit["id"]} for key in ("revision", "score"): number = hit.get(key) if isinstance(number, (int, float)): try: if math.isfinite(number): item[key] = number except (ValueError, OverflowError): pass trace["hits"].append(item) return trace ''' for project in (Path('C:/kefu/wechat_rpa'), Path('C:/wechat_rpa')): file = project / 'wechat_bot.py' original = file.read_text(encoding='utf-8') changed = original.replace(' def _record_model_call(\n', helper + ' def _record_model_call(\n', 1) old = ' state["model_chosen"] = str(outcome.get("chosen") or "")\n' new = (' state["knowledge_trace"] = self._knowledge_trace_metadata(outcome.get("knowledge"))\n' ' state["model_task_id"] = str(outcome.get("task_id") or task_id or "")[:128]\n' + old) assert changed.count(old) == 1 changed = changed.replace(old, new, 1) old = ' if ai_chat.gateway_provider() is not None:\n reply = self._call_model_with_observer(\n' new = (' if ai_chat.gateway_provider() is not None:\n' ' # A safe fallback may not make a gateway call; discard older UI-guard traces.\n' ' ai_chat.take_last_gateway_trace()\n' ' reply = self._call_model_with_observer(\n') assert changed.count(old) == 1 changed = changed.replace(old, new, 1) old = ' "task_id": trace.get("task_id") or "",\n' new = old + ' "knowledge": trace.get("knowledge") or {},\n' assert changed.count(old) == 1 changed = changed.replace(old, new, 1) old = ' "exchange_id": str(value.get("exchange_id") or ""),\n' new = (old + ' "knowledge_trace": self._knowledge_trace_metadata(value.get("knowledge_trace")),\n' ' "model_task_id": str(value.get("model_task_id") or "")[:128],\n') assert changed.count(old) == 2 changed = changed.replace(old, new) old = ' state.pop("exchange_id", None)\n' new = old + ' state.pop("knowledge_trace", None)\n state.pop("model_task_id", None)\n' assert changed.count(old) == 1 changed = changed.replace(old, new, 1) compile(changed, str(file), 'exec') backup = project / 'backups' / 'recognition-audit-20260916' / 'visual-trace' backup.mkdir(parents=True, exist_ok=True) assert not (backup/file.name).exists() shutil.copy2(file, backup/file.name) file.write_text(changed, encoding='utf-8', newline='\n') test = project / 'test_visual_knowledge_trace_audit.py' assert not test.exists() shutil.copy2(root/test.name, test) records.append({'project':str(project), 'file':str(file), 'backup':str(backup/file.name)}) (root/'visual-trace-changes.json').write_text(json.dumps(records, ensure_ascii=False, indent=2), encoding='utf-8') print(json.dumps(records, ensure_ascii=False))