"""Narrow execution requirements grounded in the latest human instruction.""" from __future__ import annotations import re from backend.config import settings from backend.prospecting.contracts import IntentPlan, ProspectingBrief, TARGET_QUESTION from backend.browser.preflight_policy import PreflightPolicy, compile_preflight_policy def _clauses(message: str): text = re.sub(r"```[\s\S]*?```", "", message) # A tool name formatted inline may still be an instruction. Whole quoted # requests, code examples and block quotations remain untrusted material. text = re.sub(r"`(resolve_reply_target(?:\([^`\n]*\))?)`", r"\1", text) text = re.sub(r'''“[^”]*”|‘[^’]*’|「[^」]*」|『[^』]*』|"[^"\n]*"|'[^'\n]*'|`[^`\n]*`''', "", text) text = "\n".join(line for line in text.splitlines() if not line.lstrip().startswith(">")) for clause in re.split(r"[,,。;;!?!?\n]|(?:但是|但要|但请|不过|而是)", text): if clause.strip() and not re.search(r"例如|比如|示例|参考案例|只是.{0,8}(?:引用|日志|描述)|(?:日志|文档|网页|截图).{0,8}(?:写着|提示|显示|内容)|(?:解释|介绍|讨论|了解).{0,15}(?:resolve_reply_target|网页回查|返回原笔记)|resolve_reply_target.{0,6}(?:是什么|什么意思|怎么用)", clause): yield clause.strip() _BROWSER_RECHECK = re.compile( r"resolve_reply_target(?:\([^)]*\))?" r"|(?:原生历史|浏览历史|历史记录)(?:返回|回退|后退)" r"|(?:原生)?(?:历史)?(?:返回|回到|回退|退回)(?:到)?(?:原|刚才|之前|该|这篇|同一篇|实际|真实|当前|已保存的)?(?:笔记|详情页|页面|网页|浏览器)" r"|(?:网页|页面|浏览器|原页|原笔记|详情页)(?:上|中|里)?(?:实际|重新|再次|现场|直接|进行|去|上)?(?:回查|核对|复核|检查|确认|查证|验证)" r"|(?:回查|核对|复核|检查|确认|查证|验证)(?:一下|当前|实际|真实)?(?:网页|页面|原页|原笔记|浏览器)" r"|(?:点击|打开|进入).{0,20}(?:回复前缀|回复对象|目标主页|作者主页|发言人主页|实际主页|真实主页).{0,12}(?:核|查|确认|验证)" ) _NEGATIVE_PREFIX = re.compile(r"(?:不要|不用|无需|不必|不需要|不能|别|不再|停止|取消|放弃|暂不|先不|不是|不使用|不调用|不执行)[^,,。;;]{0,10}$") _NEGATIVE_SUFFIX = re.compile(r"\s*(?:先|暂时)?(?:不用|无需|不必|不要|取消|停止|不执行|不需要)(?:做|执行|操作)?") _BROWSER_DISABLED = re.compile(r"(?:不|不需要|无需|不用|不必|不要|别)(?:再|实际)?(?:操作|打开|访问|使用|进入)(?:任何|实际)?(?:网页|页面|浏览器)") _BROWSER_CANCELLED = re.compile(r"(?:取消|停止|放弃|不再|不要|不用|不需要|无需|不必)(?:(?:本次|本轮|当前|实际)的?)?(?:网页|页面|浏览器)?回查") def browser_recheck_requested(message: str) -> bool: """Stored sources do not imply an offline job when a web action is explicit.""" page_required = bool(settings.reply_relation_preflight_enabled and compile_preflight_policy(message).active and re.search( r"(?:当前|这篇|原)(?:笔记|页面).{0,16}预检|预检.{0,16}(?:当前|这篇|原)(?:笔记|页面)", message)) actions_required = set() for clause in _clauses(message): if _BROWSER_DISABLED.search(clause) or _BROWSER_CANCELLED.search(clause): page_required = False actions_required.clear() continue for match in _BROWSER_RECHECK.finditer(clause): value = match.group() is_tool = value.startswith("resolve_reply_target") if is_tool and not ( re.search(r"(?:用|使用|调用|执行|运行)(?:工具)?\s*$", clause[:match.start()]) or re.match(r"\s*(?:来|去)?(?:核对|核实|核|回查|检查)", clause[match.end():]) or _NEGATIVE_PREFIX.search(clause[:match.start()]) or _NEGATIVE_SUFFIX.match(clause[match.end():]) or clause == match.group()): continue negative = bool(_NEGATIVE_PREFIX.search(clause[:match.start()]) or _NEGATIVE_SUFFIX.match(clause[match.end():])) action = ('resolve_reply_target' if is_tool else 'return' if re.match( r"(?:原生历史|浏览历史|历史记录|(?:原生)?(?:历史)?(?:返回|回到|回退|退回))", value) else 'profile' if re.match(r"点击|打开|进入", value) else None) if action: # Cancelling one browser operation does not cancel an # independent instruction to inspect the actual page. if negative: actions_required.discard(action) else: actions_required.add(action) elif negative: page_required = False actions_required.clear() else: page_required = True return page_required or bool(actions_required) def browser_recheck_brief(brief: ProspectingBrief, message: str) -> ProspectingBrief: # A focused read-only recheck has an existing object and must not be # short-circuited by a discovery headcount or an export-only route. if browser_recheck_requested(message) and brief.intent in {"discover", "export"}: return brief.model_copy(update={"intent": "inspect"}) return brief def ground_execution_plan(plan: IntentPlan, message: str) -> IntentPlan: policy = (compile_preflight_policy(message, plan.brief.max_notes) if settings.reply_relation_preflight_enabled else PreflightPolicy()) if policy.active: brief = plan.brief.model_copy(update={"intent": "inspect", "max_notes": policy.max_notes}) return plan.model_copy(update={"brief": brief, "reuse_existing_sources": False, "missing": [item for item in plan.missing if item != TARGET_QUESTION], "summary": "只读预检当前可见回复关系,按实际记录交付范围与未读部分,本轮不保存来源或生成名单。", "stages": ["核对访问范围", "只读关系预检", "交付预检结果"]}) if not browser_recheck_requested(message): return plan brief = browser_recheck_brief(plan.brief, message) missing = [item for item in plan.missing if item != TARGET_QUESTION or TARGET_QUESTION in brief.missing()] return plan.model_copy(update={ "brief": brief, "reuse_existing_sources": False, "missing": missing, "summary": "按你的要求回到实际页面核对既有来源,保留采集范围和未知项。", "stages": list(dict.fromkeys(["实际页面回查", *plan.stages])), }) def recheck_without_analysis(message: str) -> bool: """Only an explicit analysis prohibition in an explicit recheck can skip it.""" if not browser_recheck_requested(message): return False forbidden = False for clause in _clauses(message): if re.search(r"(?:不|不想|无需|不用|不必|不要|别|禁止|停止|取消)(?:再|重新|重复)?(?:搜索(?:或|和|及))?(?:再|重新|重复)?(?:分析(?:名单|候选|需求)?|做(?:名单|候选|需求)分析)", clause): forbidden = True elif re.search(r"(?:重新|再次|再|仍要|继续|需要|只需|仍需|请|要)分析(?:名单|候选|需求)?", clause): forbidden = False return forbidden