@vmosedge/workflow-agent-sdk 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- import{ChatPromptTemplate as e}from"@langchain/core/prompts";import{JsonOutputParser as t}from"@langchain/core/output_parsers";import{RunnableLambda as n}from"@langchain/core/runnables";import{z as i}from"zod";import{ChatAnthropic as r}from"@langchain/anthropic";import{coerceMessageLikeToMessage as o}from"@langchain/core/messages";import{tool as a}from"@langchain/core/tools";import{ChatGoogleGenerativeAI as s}from"@langchain/google-genai";import{ChatOpenAI as c}from"@langchain/openai";import{createHash as l}from"crypto";function p(e){return e.map(e=>{if("assistant"===e.role){const t=(e.toolCalls||[]).map(e=>({type:"tool_call",id:e.id,name:e.name,args:e.arguments}));return o({role:"assistant",content:e.content,...t.length>0?{tool_calls:t}:{}})}return"tool"===e.role?o({role:"tool",content:e.content,tool_call_id:e.toolCallId||""}):o({role:e.role,content:e.content})})}function d(e){return e.map(e=>{return function(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.name&&"string"==typeof t.description&&!!t.schema&&"object"==typeof t.schema}(e)?a(async()=>"schema-only tool placeholder",{name:(t=e).name,description:t.description,schema:t.schema}):e;var t})}function u(e,t){if("string"!=typeof e||0===e.trim().length)throw new Error(`${t} is required`)}function _(e,t,n){return"anthropic"===e?function(e,t){return new r({model:e.model,apiKey:e.apiKey,temperature:.2,...e.baseUrl?{anthropicApiUrl:e.baseUrl}:{},...Object.keys(t).length>0?{clientOptions:{defaultHeaders:t}}:{}})}(t,n):"google"===e?function(e,t){return new s({model:e.model,apiKey:e.apiKey,temperature:.2,...e.baseUrl?{baseUrl:e.baseUrl}:{},...Object.keys(t).length>0?{customHeaders:t}:{}})}(t,n):function(e,t){return new c({model:e.model,apiKey:e.apiKey,temperature:.2,configuration:{...e.baseUrl?{baseURL:e.baseUrl}:{},...Object.keys(t).length>0?{defaultHeaders:t}:{}}})}(t,n)}class m{capabilities;vendor;model;constructor(e){const t={...e.headers||{}},n=function(e){const t=function(e){const t=(e||"").toLowerCase();return t.includes("deepseek")?"deepseek":t.includes("openai")?"openai":t.includes("custom")||t.includes("other")?"custom":t.includes("anthropic")||t.includes("claude")?"anthropic":t.includes("google")||t.includes("gemini")?"google":t.includes("azure")?"azure":"openai"}(String(e.vendor));return u(e.apiKey,"provider.apiKey"),u(e.model,"provider.model"),"anthropic"===t||"google"===t||u(e.baseUrl,"provider.baseUrl"),t}(e);this.vendor=n,this.capabilities=function(e){return{toolCalling:!0,structuredJson:!0,jsonMode:"openai"===e||"deepseek"===e||"azure"===e||"custom"===e}}(n),this.model=_(n,e,t)}getModel(){return this.model}async chatWithTools(e,t,n){const i=p(e),r=d(t),o=r.length>0&&"function"==typeof this.model.bindTools?this.model.bindTools(r):this.model,a=await o.invoke(i,{signal:n}),s="string"==typeof(c=a).text&&c.text.length>0?c.text:"string"==typeof c.content?c.content:Array.isArray(c.content)?c.content.map(e=>"string"==typeof e?e:e&&"object"==typeof e&&"text"in e&&"string"==typeof e.text?e.text:"").filter(e=>e.length>0).join("\n"):"";var c;const l=a.tool_calls||[],u=a.response_metadata&&"object"==typeof a.response_metadata?a.response_metadata:null;return{content:s,toolCalls:l.filter(e=>"string"==typeof e.name&&e.name.length>0).map((e,t)=>{return{id:"string"==typeof e.id&&e.id.length>0?e.id:`call_${Date.now()}_${t}`,name:e.name,arguments:(n=e.args,n&&"object"==typeof n&&!Array.isArray(n)?n:{})};var n}),finishReason:"string"==typeof u?.finish_reason&&u.finish_reason||"string"==typeof u?.stop_reason&&u.stop_reason||void 0}}async chatStructuredJson(e,t,n){const i=p(e),r="anthropic"===(o=this.vendor)||"google"===o?[{method:"jsonSchema"},{method:"functionCalling"}]:[{method:"jsonSchema",strict:!0},{method:"functionCalling",strict:!0},{method:"jsonMode"}];var o;let a=null;for(const e of r)try{const r=this.model.withStructuredOutput(t,{name:"structured_output",method:e.method,..."boolean"==typeof e.strict?{strict:e.strict}:{}}),o=await r.invoke(i,{signal:n});return t.parse(o)}catch(e){a=e}const s=a instanceof Error&&a.message?a.message:"langchain structured output failed with all methods";throw new Error(s)}}function f(e){return new m(e)}const g=/[\u3400-\u9fff]/u,y=[/\b\d+\s*(次|遍|个|条|张)\b/u,/第\s*\d+\s*(个|条|张)/u,/\b\d+\s*(times?|rounds?|steps?|items?)\b/i,/\bfor\s+\d+\s*(times?|rounds?)\b/i],h=[/直到/u,/等到/u,/出现/u,/找到/u,/\buntil\b/i,/\bwhen\b/i,/\bunless\b/i,/\bappears?\b/i,/\bfound\b/i],b=[/一直/u,/不停/u,/持续/u,/无限/u,/永远/u,/\bforever\b/i,/\bcontinuously\b/i,/\bendless(?:ly)?\b/i,/\bindefinitely\b/i,/\bkeep\b.*\bloop(?:ing)?\b/i];function v(e){return g.test(e||"")?"zh":"en"}function w(e){const t=e.trim();return t?y.some(e=>e.test(t))?"fixed_count":h.some(e=>e.test(t))?"until_condition":b.some(e=>e.test(t))?"infinite":"single_flow":"single_flow"}function x(e,t){return`## ${e}\n${t.map((e,t)=>`${t+1}. ${e}`).join("\n")}`}const k={primary:["每步前必须有最新 observe_screen / dump 证据,禁止基于过期界面继续执行。","每步后必须完成 success check;优先补齐 observe_screen -> verify_ui_state 再进入下一步。","页面发生变化后必须重新定位,不允许沿用旧页面的 selector 或入口。","必须按 stage 推进:一次只推进一个已验证子目标,不允许无限漂移或脱离当前阶段。","连续失败必须进入恢复分支,优先收敛、重试替代入口或暂停,而不是盲目重复。","高风险动作必须有显式授权,若用户目标未明确授权,不得擅自执行。"],secondary:["selector 优先最小唯一。","优先稳定属性,避免动态 text。","优先语义定位,不行再坐标。","可处理弹窗、广告、权限框。","可根据页面变化自动切换入口。"]},A={primary:["Each step must start from fresh observe_screen / dump evidence; never act on stale UI state.","Each step must end with a success check; prefer completing observe_screen -> verify_ui_state before advancing.","After a page change, re-locate everything; never reuse selectors or entry points from the previous page.","Advance by stage: move one verified sub-goal at a time and do not drift indefinitely.","Consecutive failures must enter a recovery branch: converge, retry an alternative path, or pause instead of repeating blindly.","High-risk actions require explicit authorization; if the user did not clearly authorize them, do not execute them."],secondary:["Prefer minimal unique selectors.","Prefer stable attributes and avoid dynamic text.","Prefer semantic locators; fall back to coordinates only when necessary.","You may handle popups, ads, and permission dialogs.","You may switch entry points automatically when the page changes."]},S=["首次动作前先 observe_screen,禁止盲操作。","每个会引发状态变化的动作后(包括 tap_element、set_text、input_text、start_app 等),优先执行 observe_screen(wait_ms) -> verify_ui_state 补齐录制信息。跳过 verify_ui_state 只会产生告警并降低脚本生成质量,不阻塞执行。","单轮最多一个状态变化动作;优先按“动作 -> wait(自适应时长) -> observe_screen -> verify_ui_state”闭环推进,以提高录制质量。","运行中仅执行与用户目标直接相关的动作;与任务无关的事情不要自行处理,禁止无关探索、浏览或演示性操作。","启动应用时优先使用包名;若当前只有应用名,先调用 get_installed_apps 确认 package_name,再使用 start_app,禁止臆测包名。","selector 必须来自最新 observe_screen 的真实内容。","selector 选择遵循“脚本优先”阶梯:稳定 resource_id -> 稳定 text -> 稳定 content_desc -> 最小组合 -> action_index。","校验场景(verify_ui_state / accessibility-node 纯查找)同样遵循最小唯一稳定策略,但每一步只用单字段(resource_id -> text -> content_desc),不做组合。","resource_id 唯一时只用 resource_id;若 resource_id 疑似混淆(如 obfuscated/数字前缀/高熵短串),不得单独依赖,退回稳定 text/content_desc。","组合唯一时优先 resource_id + 稳定 text/content_desc;禁止叠加动态值(时间、计数、row/column 等易变化文案)。bounds 仅作兜底消歧,不应作为通用脚本主 selector。","收到 VALIDATION 或 RUNTIME_GUARD 错误时,禁止原参数盲重试;必须先 observe_screen 刷新证据并调整 selector/动作。","禁止在无新观察证据的情况下重复完全相同的工具调用(同 tool + 同参数)。","界面方位只能依据 bounds 坐标与屏幕尺寸判断,禁止按节点顺序/缩进或经验臆测”顶部/底部”。","动作失败后最多允许一次替代路径,仍失败则暂停。","坐标点击仅作为 selector 无法稳定定位时的最后手段。","swipe 前优先调用 record_search_context 记录查找目标与页面锚点;跳过只会产生录制告警并降低脚本生成质量。","index 仅在“同屏同语义节点多匹配且必须按顺序区分”时使用,且必须与 resource_id/text/content_desc/class_name/bounds 之一组合,禁止单独使用 index。","tap_element/long_press_element/set_text 的序号定位必须使用顶层 action_index,禁止 selector.index;verify_ui_state / record_search_context 可记录元素 index 作为补充证据。","当 text/content_desc 不稳定但仍需顺序区分时,且列表顺序稳定,使用 resource_id + action_index;若顺序不稳定则必须回退到更稳定锚点。","列表可能刷新、重排或异步插入时禁止依赖 index,优先稳定 resource_id 或稳定控件标签;若无法证明顺序稳定,则不要把该定位策略带入脚本。",'pre_context.step_intent 优先包含:(1)当前页面位置 (2)操作目的 (3)预期结果。例如"在抖音搜索结果页,点击第一个视频进入播放页",而非"点击视频"。record_search_context 的 step_intent 同理。',"若你能把当前动作抽象成稳定可复用的步骤语义,请显式填写 pre_context / record_search_context 中的 merge_key 和 expected_result。merge_key 应是稳定短语,不要直接抄界面文案。","若你明确知道该步骤通常需要额外等待再验证,请显式填写 wait_ms_hint,帮助脚本生成更准确设置校验等待;不确定就省略。","若你能明确判断页面类型、目标角色、步骤关键性或是否属于异常处理,请显式填写 pre_context / record_search_context 中的 page_kind、target_role、criticality_hint、include_mode_hint;若动作后页面类型也能明确判断,可填写 verify_ui_state.page_kind。不确定就省略,禁止靠文案关键词猜。",'pre_context.target.desc 和 anchor.desc 优先描述元素的视觉特征和语义角色,例如"底部导航栏中的首页按钮"或"搜索结果列表中的第一个视频卡片",避免只写"按钮"或"文本"。','verify_ui_state 中优先填写 screen_desc,用一句话描述当前页面(如"抖音视频播放页"、"设置-通用页面"),帮助脚本生成理解上下文。',"当操作导致页面切换时,verify_ui_state 中优先包含 page_anchor(新页面的标志性元素),帮助脚本生成确认导航成功。","如果 verify_ui_state 返回“补录提醒”或提示未形成可回放 verification_plan,优先重新 observe_screen 并补一个可唯一回放的 verify_element/page_anchor;若当前主流程已明确,也可以继续执行,但要接受录制质量下降。"],$=["Call observe_screen before the first action; no blind operations.","After each state-changing action (including tap_element, set_text, input_text, start_app, etc.), prefer observe_screen(wait_ms) -> verify_ui_state to complete the recording. Skipping verify_ui_state should only produce a warning and lower script-generation quality, not block execution.","At most one state-changing action per turn; prefer the loop “act -> wait(adaptive) -> observe_screen -> verify_ui_state” to keep the recording high quality.","During execution, only perform actions directly related to the user goal; do not handle unrelated tasks on your own, and avoid unrelated exploration, browsing, or demo-only actions.","Prefer package names when starting apps; if you only know the app name, call get_installed_apps to confirm package_name before using start_app, and never guess package names.","Selectors must come from the latest observe_screen evidence.","Selector choice must follow the script-safe ladder: stable resource_id -> stable text -> stable content_desc -> minimal combination -> action_index.","For verification scenarios (verify_ui_state / accessibility-node pure find), apply the same minimum-unique stability ladder, but single-field only (resource_id -> text -> content_desc), with no combinations.","If resource_id is unique, use only resource_id; if resource_id looks obfuscated (e.g. obfuscated/numeric prefix/high-entropy short token), do not rely on it alone and fall back to stable text/content_desc.","When combinations are required, prefer resource_id + stable text/content_desc; avoid dynamic values (time/count/row/column or other volatile copy). bounds is fallback-only and should not become a reusable script selector.","On VALIDATION or RUNTIME_GUARD errors, never blind-retry with the same arguments; observe_screen first, then adjust selector/action.","Do not repeat identical tool calls (same tool + same args) without new observation evidence.","Infer UI position only from bounds + screen size; never infer top/bottom from node order, indentation, or prior assumptions.","After an action failure, allow at most one alternative path; then pause.","Coordinate taps are last resort only when selector-based targeting is unstable.","Before swipe, prefer record_search_context to record the search target and page anchor; skipping should only produce recording-quality warnings.","Use index only when same-screen nodes are still ambiguous and order is required; index must be combined with at least one of resource_id/text/content_desc/class_name/bounds, never used alone.","For tap_element/long_press_element/set_text, ordinal targeting must use top-level action_index, not selector.index; verify_ui_state / record_search_context may carry node index as supplemental evidence.","If text/content_desc is unstable but order still matters and list order is stable, use resource_id + action_index; if order is unstable, fall back to more stable anchors instead.","Do not rely on index when list order can change (refresh/reorder/async insertion); if order stability cannot be justified, do not carry that locator strategy into the script.",'pre_context.step_intent should preferably include: (1) current page location (2) action purpose (3) expected result. Example: "On TikTok search results page, tap the first video to enter playback page", not just "tap video". Same for record_search_context step_intent.',"If you can abstract the current action into a stable reusable step semantic, fill merge_key and expected_result in pre_context or record_search_context. merge_key should be a stable short phrase, not copied screen text.","If you explicitly know the step usually needs additional wait before verification, fill wait_ms_hint to help script generation set verification timing more accurately; omit it when unsure.","If you can explicitly determine page kind, target role, step criticality, or whether a record is an exception handler candidate, fill page_kind/target_role/criticality_hint/include_mode_hint in pre_context or record_search_context. If the resulting page kind is also explicit after an action, you may fill verify_ui_state.page_kind. If unsure, omit them; never guess from copy keywords.",'pre_context.target.desc and anchor.desc should preferably describe the element\'s visual characteristics and semantic role, e.g. "Home button in bottom navigation bar" or "First video card in search results list", not just "button" or "text".','Prefer filling verify_ui_state screen_desc with a one-sentence page summary (e.g. "TikTok video playback page", "Settings - General page") to help script generation understand context.',"When an action causes a page transition, verify_ui_state should preferably include page_anchor (a landmark element of the new page) to help script generation confirm navigation success.","If verify_ui_state returns a repair warning or says no replayable verification_plan was formed, prefer to re-run observe_screen and repair verify_element/page_anchor with a uniquely replayable locator; if the main task path is already clear, you may continue with degraded recording quality."],q={zh:{fixed_count:["严格按目标次数执行,不得提前结束。","每轮结束后验证累计进度。"],until_condition:["每轮都必须“检查 -> 动作 -> 等待 -> 再检查”。","达到条件立即收敛,未命中到上限后结束。"],infinite:["仅当目标明确要求持续执行时允许无限循环。"],single_flow:["完成主线后立即结束,不做无关探索。"]},en:{fixed_count:["Execute exactly the requested count and never finish early.","Validate cumulative progress after each loop."],until_condition:['Every loop must follow "check -> act -> wait -> re-check".',"Converge immediately when condition is met; stop at limit otherwise."],infinite:["Infinite loop is allowed only when explicitly requested."],single_flow:["Finish immediately after the main path; avoid unrelated exploration."]}};function j(e,t){if(!e||0===e.subtasks.length)return"";const n=e.subtasks.map(e=>"zh"===t?`- ${e.id}. ${e.description} (成功标准: ${e.successCriteria})`:`- ${e.id}. ${e.description} (Success: ${e.successCriteria})`).join("\n");return"zh"===t?`## 任务计划参考\n${n}`:`## Plan Reference\n${n}`}const N=["输出必须是合法 JSON 对象,禁止 markdown 代码块。","计划必须基于当前屏幕状态,不允许假设未观察到的页面。","计划仅包含与用户目标直接相关的步骤,禁止加入与目标无关的探索性动作。","每个子任务都要有可观察的 successCriteria。","若目标存在前置状态依赖,必须先规划“进入前置状态 -> 验证前置状态”,再执行终态动作。","子任务按执行顺序排列,保持最短稳定路径。"],z=["Output must be a valid JSON object, never markdown.","Plan must be grounded in the current observed screen only.","Plan must include only steps directly related to the user goal; do not add unrelated exploratory actions.","Each subtask must include observable successCriteria.",'If goal has prerequisite state dependencies, plan "enter prerequisite state -> verify prerequisite state" before terminal actions.',"Subtasks must be ordered for the shortest stable path."],I={zh:{fixed_count:["识别用户指定次数,子任务中体现计数闭环。","避免把固定次数任务改写为条件循环。"],until_condition:["计划中显式写出停止条件和最大探索轮次。","停止条件必须可观察,不能用抽象描述。"],infinite:["仅在目标明确要求持续执行时使用无限模式。","仍需给出安全中断条件与风险说明。"],single_flow:["保持单次流程简洁,避免过度拆分。"]},en:{fixed_count:["Capture user-requested counts and enforce count closure in subtasks.","Do not rewrite fixed-count goals into condition loops."],until_condition:["State explicit stop condition and max exploration rounds.","Stop condition must be observable, not abstract."],infinite:["Use infinite mode only when user explicitly requests continuous execution.","Still provide safety stop condition and risks."],single_flow:["Keep single-flow plans concise and avoid over-splitting."]}};const O=new Set(["start_app","stop_app","tap","tap_element","long_press_element","press_key"]),R=new Set(["verify_ui_state"]),C=new Set(["tap_element","long_press_element","set_text"]),U=new Set(["tap_element","long_press_element","set_text"]);new Set([...U,"verify_ui_state","record_search_context"]);const M=U,T=new Set([...U,"input_text"]),W=new Set(["start_app","stop_app","tap","tap_element","long_press_element","set_text","input_text","swipe","press_key"]),E={observe_screen:"observeScreenMs",start_app:"startAppMs"};function D(e){return!e||"object"!=typeof e||Array.isArray(e)?null:e}function P(e){const t={};let n=!1;for(const[i,r]of Object.entries(e))null!=r&&""!==r&&(t[i]=r,n=!0);return n?t:void 0}function J(e){if("number"==typeof e&&Number.isInteger(e)&&e>=0)return e;if("string"==typeof e&&e.trim().length>0){const t=Number(e);if(Number.isInteger(t)&&t>=0)return t}}function K(e){if("number"==typeof e&&Number.isInteger(e)&&e>0)return e;if("string"==typeof e&&e.trim().length>0){const t=Number(e);if(Number.isInteger(t)&&t>0)return t}}function F(e,t){for(const n of t){const t=e[n];if("string"==typeof t){const e=t.trim();if(e.length>0)return e}}}function G(e){const t=D(e);if(t)return P({index:J(t.index),resource_id:F(t,["resource_id","resource-id","resourceId","id"]),text:F(t,["text"]),content_desc:F(t,["content_desc","content-desc","contentDesc"]),class_name:F(t,["class_name","class","className"]),bounds:F(t,["bounds"])})}function Y(e){const t=D(e?.script_selector);if(!t)return;const n=D(t.selector);return n?{selector:n,action_index:J(t.action_index),stability:"string"==typeof t.stability?t.stability:void 0,reusable:"boolean"==typeof t.reusable?t.reusable:void 0,reason:"string"==typeof t.reason?t.reason:void 0,scope:"string"==typeof t.scope?t.scope:void 0,policy_decision:"string"==typeof t.policy_decision?t.policy_decision:void 0,policy_reason:"string"==typeof t.policy_reason?t.policy_reason:void 0}:void 0}function L(e){const t=D(e);if(!t)return;const n=F(t,["page_kind"]),i=F(t,["criticality_hint"]),r=F(t,["include_mode_hint"]),o=F(t,["valid_until"]);return{context_id:F(t,["context_id"]),page_kind:"home"===n||"list"===n||"detail"===n||"dialog"===n||"search"===n||"form"===n||"unknown"===n?n:void 0,target_role:F(t,["target_role"]),criticality_hint:"critical"===i||"supporting"===i||"noise"===i?i:void 0,include_mode_hint:"main_flow"===r||"log_only"===r||"exception_handler_candidate"===r?r:void 0,valid_until:"next_action"===o||"next_verified_transition"===o||"manual_close"===o?o:void 0}}function H(e,t){if(e||t)return{context_id:t?.context_id||e?.context_id,page_kind:t?.page_kind||e?.page_kind,target_role:t?.target_role||e?.target_role,criticality_hint:t?.criticality_hint||e?.criticality_hint,include_mode_hint:t?.include_mode_hint||e?.include_mode_hint,valid_until:t?.valid_until||e?.valid_until}}function V(e){const t=new Set,n=[];for(const i of e)if(i&&!t.has(i)&&(t.add(i),n.push(i),n.length>=6))break;return n}const B=3e3;const Q=new Set(["tap_element","long_press_element","set_text"]),X=new Set(["start_app","stop_app","tap_element","long_press_element","set_text","input_text","press_key","swipe","tap","wait"]);function Z(e,t){const n=function(e){const t=[];let n,i=null;for(const r of e){const e=r.toolName,o=D(r.arguments)||{},a=D(r.result.data);if("get_screen_info"===e&&r.result.success){const e="number"==typeof a?.width?a.width:void 0,t="number"==typeof a?.height?a.height:void 0;e&&t&&(n={width:e,height:t});continue}if("observe_screen"===e||"get_installed_apps"===e)continue;if("record_search_context"===e){i={step_intent:F(o,["step_intent"]),merge_key:F(o,["merge_key"]),expected_result:F(o,["expected_result"]),wait_ms_hint:K(o.wait_ms_hint),target_desc:F(o,["target_desc"]),anchor:P(D(o.anchor_element)||{}),anchor_plan:D(a?.anchor_plan)||void 0,target:P(D(o.target_element)||{}),target_plan:D(a?.target_plan)||void 0,recorded_context:L(a?.recorded_context)};continue}if("verify_ui_state"===e){const e=t[t.length-1];if(!e)continue;e.verify=P(D(o.verify_element)||{}),e.verify_desc=F(o,["step_desc"]),e.page_anchor=P(D(o.page_anchor)||{}),e.screen_desc=F(o,["screen_desc"]);const n=F(D(a?.recorded_page)||{},["page_kind"])||F(o,["page_kind"]);e.verified_wait_ms_hint=K(o.wait_ms_hint),e.verified_page_kind="home"===n||"list"===n||"detail"===n||"dialog"===n||"search"===n||"form"===n||"unknown"===n?n:void 0,e.verification_plan=D(a?.verification_plan)||void 0,e.page_anchor_plan=D(a?.page_anchor_plan)||void 0,"next_verified_transition"===i?.recorded_context?.valid_until&&(i=null);continue}const s={seq:t.length+1,tool:e,success:r.result.success};r.result.success||"string"!=typeof r.result.error||(s.error=r.result.error),i&&(s.step_intent=i.step_intent,s.intent_merge_key=i.merge_key,s.expected_result_hint=i.expected_result,s.wait_ms_hint=i.wait_ms_hint,s.search_context=i.target_desc,!s.anchor&&i.anchor&&(s.anchor=i.anchor),i.anchor_plan&&(s.anchor_plan=i.anchor_plan),!s.target&&i.target&&(s.target=i.target),i.target_plan&&(s.target_plan=i.target_plan),i.recorded_context&&(s.recorded_context=i.recorded_context),"next_action"===i.recorded_context?.valid_until&&(i=null));const c=D(o.pre_context);c&&(s.step_intent=F(c,["step_intent"])||s.step_intent,s.intent_merge_key=F(c,["merge_key"])||s.intent_merge_key,s.expected_result_hint=F(c,["expected_result"])||s.expected_result_hint,s.wait_ms_hint=K(c.wait_ms_hint)||s.wait_ms_hint,s.target=P(D(c.target)||{})||s.target,s.anchor=P(D(c.anchor)||{})||s.anchor,s.recorded_context=H(s.recorded_context,L(c))),s.selector=P(D(o.selector)||{}),s.action_index=J(o.action_index),"string"==typeof o.text&&(s.text=o.text),"number"==typeof o.key_code&&(s.key_code=o.key_code),"string"==typeof o.package_name&&(s.package_name=o.package_name),"number"==typeof o.duration&&"wait"===e&&(s.wait_duration=o.duration),"number"==typeof o.x&&"number"==typeof o.y&&"tap"===e&&(s.tap_position={x:o.x,y:o.y}),"swipe"===e&&(s.swipe={start_x:Number(o.start_x),start_y:Number(o.start_y),end_x:Number(o.end_x),end_y:Number(o.end_y),duration:"number"==typeof o.duration?o.duration:300});const l=D(a?.runtime_selector_evidence);if(l){const e=P(D(l.requested_selector)||{});!s.selector&&e&&(s.selector=e),s.runtime_selected_node=G(l.selected_node),s.runtime_candidate_nodes=Array.isArray(l.candidate_nodes)?l.candidate_nodes.map(e=>G(e)).filter(e=>!!e):void 0,s.runtime_matched_count="number"==typeof l.matched_count?l.matched_count:void 0,s.selector_profile=D(l.selector_profile)||void 0;const t=J(l.action_index);void 0!==t&&(s.action_index=t)}t.push(s)}return{screen:n,actions:t}}(t),i=n.actions.map(e=>{const t=Y(e.selector_profile),n=function(e){const t=Y(e.page_anchor_plan),n=Y(e.verification_plan);return t?{required:!0,materialization:"ready",signal_type:"page_arrived",rationale:"page transition uses page_anchor as the primary arrival signal",primary:t,fallback:n}:n?{required:!0,materialization:"ready",signal_type:"set_text"===e.tool||"input_text"===e.tool?"input_committed":"swipe"===e.tool?"list_progressed":"element_visible",rationale:"verify_ui_state provided a recording-time approved verification selector",primary:n}:e.verify?{required:!0,materialization:"missing_plan",signal_type:"element_visible",rationale:"raw verify evidence exists but recording-time verify plan is missing"}:e.success&&W.has(e.tool)?{required:!0,materialization:"missing_plan",signal_type:"set_text"===e.tool||"input_text"===e.tool?"input_committed":"swipe"===e.tool?"list_progressed":"state_changed",rationale:"state-changing action requires explicit post-action verification for unattended replay"}:{required:!1,materialization:"not_required",signal_type:e.success?"action_completed":"state_changed",rationale:"no post-action verification artifact recorded"}}(e),i=function(e,t){switch(e.tool){case"start_app":{const t=e.package_name;return t?[{path:"permission/set",params:{package_name:t,grant_all:!0}},{path:"activity/start",params:{package_name:t}}]:[]}case"stop_app":{const t=e.package_name;return t?[{path:"activity/stop",params:{package_name:t}}]:[]}case"tap_element":return t?[{path:"accessibility/node",params:P({selector:t.selector,action:"click",action_index:t.action_index,wait_timeout:B})}]:[];case"long_press_element":return t?[{path:"accessibility/node",params:P({selector:t.selector,action:"long_click",action_index:t.action_index,wait_timeout:B})}]:[];case"set_text":return t?[{path:"accessibility/node",params:P({selector:t.selector,action:"set_text",action_index:t.action_index,wait_timeout:B,action_params:e.text?{text:e.text}:void 0})}]:[];case"input_text":return e.text?[{path:"input/text",params:{text:e.text}}]:[];case"press_key":return"number"==typeof e.key_code?[{path:"input/keyevent",params:{key_code:e.key_code}}]:[];case"swipe":return e.swipe?[{path:"input/scroll_bezier",params:e.swipe}]:[];case"tap":return e.tap_position?[{path:"input/click",params:e.tap_position}]:[];case"wait":return"number"==typeof e.wait_duration?[{path:"base/sleep",params:{duration:e.wait_duration}}]:[];default:return[]}}(e,t),r=function(e,t){if("ready"!==e.materialization||!e.primary)return;const n="number"==typeof t&&Number.isFinite(t)&&t>0?Math.max(5e3,Math.trunc(t)):5e3;return{path:"accessibility/node",params:{selector:e.primary.selector,wait_timeout:n},throw_if_empty:["nodes"]}}(n,e.verified_wait_ms_hint||e.wait_ms_hint),o=function(e){const t=[],{record:n,scriptSelector:i,replayActions:r,successCriteria:o}=e;return Q.has(n.tool)&&!i&&t.push(`missing_script_selector: ${n.tool} requires a recording-approved script_selector`),X.has(n.tool)&&0===r.length&&t.push(`missing_replay_action: ${n.tool} has no replay_plan.actions`),o.required&&"ready"!==o.materialization&&t.push(`missing_verification_plan: verification is required but materialization=${o.materialization}`),t}({record:e,scriptSelector:t,replayActions:i,successCriteria:n}),a=F(e.anchor||{},["desc"])||e.search_context||e.step_intent,s=e.screen_desc||F(e.page_anchor||{},["desc"]),c=e.recorded_context?.page_kind||"unknown",l="page_arrived"===n.signal_type?e.verified_page_kind||"unknown":c,p=e.recorded_context?.criticality_hint,d=p||function(e,t){return"wait"===e.tool?"noise":"page_arrived"===t?"critical":e.success?"supporting":"noise"}(e,n.signal_type),u=e.recorded_context?.include_mode_hint,_=u||function(e){return"wait"===e.tool?"log_only":e.success?"main_flow":"log_only"}(e),m=e.step_intent||e.verify_desc||F(e.target||{},["desc"])||e.search_context||`${e.tool} #${e.seq}`,f=e.expected_result_hint||F(e.page_anchor||{},["desc"])||e.screen_desc||e.verify_desc||m,g=(e.intent_merge_key||m).normalize("NFKC").toLowerCase().replace(/[^a-z0-9\u4e00-\u9fa5]+/gu,"_").replace(/^_+|_+$/gu,"")||"step";return{id:`action_${e.seq}`,seq:e.seq,tool:e.tool,success:e.success,error:e.error,page:{before:{kind:c,description:a,anchor:e.anchor_plan||e.anchor},after:e.screen_desc||e.page_anchor?{kind:l,description:s,anchor:e.page_anchor_plan||e.page_anchor||e.verify}:void 0,key_features:V([a,s,e.search_context,F(e.target||{},["desc","text","content_desc"]),F(e.anchor||{},["desc","text","content_desc"])])},intent:{summary:m,purpose:m,expected_result:f,merge_key:g,sources:{expected_result:e.expected_result_hint?"explicit":"derived",merge_key:e.intent_merge_key?"explicit":"derived"}},target:{desc:F(e.target||{},["desc"])||e.search_context,role:e.recorded_context?.target_role||"generic_target",runtime_selector:e.selector,runtime_action_index:e.action_index,runtime_selected_node:e.runtime_selected_node,selector_profile:e.selector_profile,script_selector:t,selector_candidates:Array.isArray(e.selector_profile?.selector_candidates)?e.selector_profile?.selector_candidates:void 0},success_criteria:n,classification:{criticality:d,include_mode:_,step_is_key:"critical"===d,sources:{criticality:p?"explicit":"fallback",include_mode:u?"explicit":"fallback"}},replay_plan:{actions:i,verification:r},diagnostics:{matched_count:e.runtime_matched_count,selector_reusable:t?.reusable},warnings:o.length>0?o:void 0}}),r=i.flatMap(e=>(e.warnings||[]).map(t=>`${e.id}: ${t}`));return{version:"recording-artifact/v2",goal:e,screen:n.screen,design_principle:"Recording artifact already contains approved script selectors, verification plans, merge keys, and replay actions. Script generation must translate, not infer.",actions:i,warnings:r.length>0?r:void 0}}const ee="顶层字段:\n- version: RecordingArtifact 格式版本。\n- goal: 用户最终目标,决定脚本整体意图。\n- screen: 录制时屏幕尺寸,仅用于理解坐标类动作。\n- design_principle: 录制产物的设计原则,提醒你“翻译已有信息,而不是补推未知信息”。\n- warnings: 全局录制质量提醒,不阻塞生成。\n- actions: 已格式化的执行记录数组,按 seq 升序排列。\n\n单条 actions[*] 字段:\n- id: 该条记录的稳定 ID。\n- seq: 原始执行顺序。主流程应尊重这个顺序。\n- tool: 录制时调用的工具名。\n- success: 该次工具调用是否成功。\n- error: 失败时的错误信息;success=true 时通常为 null。\n\n页面上下文 page:\n- page.before: 动作前页面信息。\n- page.after: 动作后页面信息;如果缺失,表示录制时没有拿到可靠的动作后页面证据。\n- page.key_features: 页面关键特征摘要,只用于帮助你理解页面,不用于拼 selector。\n- page.before/after.kind: 粗粒度页面类型,例如 list/detail/dialog。\n- page.before/after.description: 页面自然语言描述,可用于步骤描述。\n- page.before/after.anchor: 录制时的页面锚点证据,可帮助理解页面是否切换。\n\n步骤意图 intent:\n- intent.summary: 最短步骤摘要。优先用于 step description。\n- intent.purpose: 该动作为什么执行。\n- intent.expected_result: 该动作执行后希望达到的结果。\n- intent.merge_key: 邻近动作是否可以合并为同一步的稳定键。\n\n目标与选择器 target:\n- target.desc: 人类可读的目标描述。\n- target.role: 目标元素角色提示。\n- target.runtime_selector: 录制时实际传入的 selector,仅作背景参考,不等于最终脚本批准 selector。\n- target.runtime_action_index: 录制时使用的序号定位。\n- target.runtime_selected_node: 录制时命中的真实节点快照。\n- target.selector_profile: 录制阶段对 selector 质量的分析信息。\n- target.script_selector: 已批准进入脚本的 selector。这是生成主动作时最优先的 selector 来源。\n- target.selector_candidates: 候选 selector 证据,仅用于理解,不用于重新拼接新 selector。\n\n成功判定 success_criteria:\n- success_criteria.required: 该动作理论上是否需要动作后验证。\n- success_criteria.materialization: ready 表示验证动作已可回放;missing_plan 表示需要验证但录制没形成可回放方案;not_required 表示无需验证。\n- success_criteria.signal_type: 该动作成功信号的类型,如 page_arrived / element_visible / state_changed。\n- success_criteria.rationale: 为什么采用这个成功判定策略。\n- success_criteria.primary/fallback: 已批准的验证 selector。只有存在时才能用于生成验证步骤。\n\n流程分类 classification:\n- classification.criticality: 对整体任务的重要程度。\n- classification.include_mode: main_flow / exception_handler_candidate / log_only。\n- classification.step_is_key: 是否是关键里程碑动作。\n\n可回放计划 replay_plan:\n- replay_plan.actions: 已批准的主动作 skeleton。生成主流程时优先直接使用。\n- replay_plan.verification: 已批准的验证动作 skeleton。只有存在时才生成验证。\n\n诊断 diagnostics 与 warnings:\n- diagnostics.matched_count: 录制时 selector 命中的节点数。\n- diagnostics.selector_reusable: selector 是否看起来可复用。\n- warnings: 当前 action 的录制质量提醒,不阻塞生成。\n\n解释原则:\n- null / [] / {} 表示“没录到”或“无可用信息”,直接忽略。\n- 最高可信字段是 replay_plan、target.script_selector、success_criteria.primary/fallback。\n- diagnostics、runtime_selector、runtime_selected_node、selector_candidates 主要用于理解上下文,不用于发明新 selector。",te='Top-level fields:\n- version: RecordingArtifact schema version.\n- goal: the final user goal that defines the workflow intent.\n- screen: recorded screen size, only for understanding coordinate-based actions.\n- design_principle: the artifact\'s design principle, reminding you to translate known data instead of inventing missing data.\n- warnings: global recording-quality warnings; they do not block generation.\n- actions: formatted execution records sorted by seq.\n\nPer actions[*] record:\n- id: stable record ID.\n- seq: original execution order. The main flow should respect this order.\n- tool: tool name used during recording.\n- success: whether the tool call succeeded.\n- error: failure message when success=false; usually null when success=true.\n\nPage context page:\n- page.before: page information before the action.\n- page.after: page information after the action; if missing, the recorder did not capture reliable post-action page evidence.\n- page.key_features: condensed page features for understanding only, not for building selectors.\n- page.before/after.kind: coarse page type such as list/detail/dialog.\n- page.before/after.description: natural-language page description that can help step descriptions.\n- page.before/after.anchor: recorded page-anchor evidence that helps you understand whether navigation happened.\n\nStep intent intent:\n- intent.summary: shortest step summary. Prefer it for step descriptions.\n- intent.purpose: why the action was executed.\n- intent.expected_result: expected outcome after the action.\n- intent.merge_key: stable key for deciding whether adjacent actions can be merged into one step.\n\nTarget and selector target:\n- target.desc: human-readable target description.\n- target.role: target element role hint.\n- target.runtime_selector: selector used during recording; background reference only, not automatically approved for final script use.\n- target.runtime_action_index: ordinal targeting used during recording.\n- target.runtime_selected_node: actual node snapshot matched during recording.\n- target.selector_profile: selector-quality analysis from recording.\n- target.script_selector: selector explicitly approved for final script use. This is the highest-priority selector source for main actions.\n- target.selector_candidates: candidate-selector evidence for understanding only, not for reconstructing a new selector.\n\nSuccess criteria success_criteria:\n- success_criteria.required: whether this action ideally needs post-action verification.\n- success_criteria.materialization: ready means replayable verification exists; missing_plan means verification is needed but replayable evidence is incomplete; not_required means verification is unnecessary.\n- success_criteria.signal_type: success signal type such as page_arrived / element_visible / state_changed.\n- success_criteria.rationale: why this verification policy was chosen.\n- success_criteria.primary/fallback: approved verification selectors. Use them only when they exist.\n\nFlow classification classification:\n- classification.criticality: importance to the overall task.\n- classification.include_mode: main_flow / exception_handler_candidate / log_only.\n- classification.step_is_key: whether the action is a key milestone.\n\nReplay plan replay_plan:\n- replay_plan.actions: approved main-action skeletons. Use them directly whenever possible.\n- replay_plan.verification: approved verification skeleton. Generate verification only when it exists.\n\nDiagnostics and warnings:\n- diagnostics.matched_count: number of nodes matched by the selector during recording.\n- diagnostics.selector_reusable: whether the selector appears reusable.\n- warnings: action-level recording-quality warnings; they do not block generation.\n\nInterpretation rules:\n- null / [] / {} means "not captured" or "not available", so ignore it.\n- The highest-trust fields are replay_plan, target.script_selector, and success_criteria.primary/fallback.\n- diagnostics, runtime_selector, runtime_selected_node, and selector_candidates are mainly for context understanding, not for inventing new selectors.',ne=`你是 Android 无人值守 WorkflowScript 工程师。输入不是原始日志,而是录制阶段已经提纯好的 RecordingArtifact。\n\nRole:\n- 你负责把已有执行记录翻译成稳定、可靠、可无人值守执行的 WorkflowScript。\n\nAction:\n- 基于 RecordingArtifact 生成最终脚本。\n- 优先复用已批准的 replay_plan、script_selector、verification selector。\n- 在信息缺失时继续基于已有记录生成,而不是阻塞或补编未知信息。\n\nContext:\n1. 只消费 RecordingArtifact 中已经批准进入脚本的结构化信息。\n2. 不自行猜 selector,不自行猜页面意图,不自行猜成功判定条件。\n3. 不从 diagnostics、raw desc、候选节点中发明新 selector。\n4. 你的目标是无人值守稳定回放,所以优先选择可回放、可验证、可复用的记录,而不是追求“看起来完整”。\n\nExpectation:\n- 输出纯 JSON WorkflowScript。\n- 主流程顺序清晰,验证闭环尽量完整。\n- 对缺失字段容忍,但绝不凭空补造。\n\n## 输入格式\nRecordingArtifact.actions[*] 已经包含:\n- intent.merge_key: 建议的步骤合并键\n- target.script_selector: 录制阶段批准进入脚本的目标 selector\n- success_criteria.primary: 录制阶段批准的成功判定 selector\n- success_criteria.materialization: 验证条件是否已经具备可回放计划\n- replay_plan.actions: 已经整理好的主动作 skeleton\n- replay_plan.verification: 已经整理好的验证动作 skeleton\n- classification.include_mode: main_flow / exception_handler_candidate / log_only\n- warnings: 录制阶段已经识别出的非阻断缺口(例如缺少可回放 verification_plan)\n- 某些字段可能是 null / [] / {}:这表示录制阶段没有拿到该信息,直接忽略,不要自行补编\n\n## 字段解释\n${ee}\n\n## 无人值守优先级\n1. 可回放性优先于表面完整性。\n2. 有 replay_plan.actions 就优先生成动作;没有就跳过,不补编。\n3. 有 replay_plan.verification 才生成验证;没有就接受该缺口,但不要发明验证。\n4. 有 target.script_selector / success_criteria.primary 才把 selector 写进脚本;没有就不要从其他字段反推。\n5. log_only 默认不进入主流程;exception_handler_candidate 优先转成 exception_handlers。\n\n## 绝对规则\n1. 生成脚本时,优先直接使用 replay_plan.actions;不要自己重建 path/params。\n2. 只要 main_flow 记录存在 replay_plan.verification,就必须在该记录的 replay_plan.actions 之后生成“base/sleep -> 验证动作”的闭环。\n3. base/sleep 的 duration 优先由你根据当前场景生成;若你无法判断,可省略 duration,系统会兜底为 2000ms。\n4. 带 action 的 accessibility/node params.wait_timeout 至少 3000ms;replay_plan.verification 的 params.wait_timeout 优先使用已给值,若你输出时缺失、不合法或低于最小值,系统会对纯校验 accessibility/node 兜底并提升到至少 5000ms。\n5. classification.include_mode="log_only" 的记录默认不进入主流程。\n6. classification.include_mode="exception_handler_candidate" 的记录优先抽成 workflow 顶层 exception_handlers,而不是普通步骤。\n7. selector 只能来自 target.script_selector 或 success_criteria.primary/fallback;禁止从 target.desc、screen_desc、diagnostics 反推。\n8. 不得把 bounds、动态文案、候选节点文本重新拼成新 selector。\n9. 相邻且 merge_key 相同的 main_flow 记录优先合并为同一 step。\n10. 如果 replay_plan.actions 为空,不要编造动作;跳过该记录。\n11. completed 只允许字面量 "success",且仅在 loop.max_count 场景使用。\n12. 如果 RecordingArtifact.warnings 存在,或 action.warnings 非空,继续基于已有 replay_plan 生成,但不要补编缺失的 selector / 验证动作。\n13. 如果 success_criteria.required=true 但 materialization 不是 "ready",视为录制不完整;保留已批准的 replay_plan.actions,但不要发明 replay_plan.verification。\n14. 输出纯 JSON,不要解释。\n\n## 工作流约束\n- 合法 path 仅限:activity/start, permission/set, activity/stop, accessibility/node, input/scroll_bezier, input/text, input/keyevent, input/click, base/sleep\n- accessibility/node 必须带正整数 wait_timeout\n- 带 action 的 accessibility/node wait_timeout 至少 3000ms;纯校验 accessibility/node 至少 5000ms\n- throw_if_empty 只能是 ["nodes"]\n- exception_handlers 只能放在 workflow 顶层\n\n## 输出格式(WorkflowScript)\n你必须输出一个合法的 WorkflowScript JSON,对象结构如下:\n\n\`\`\`json\n{\n "id": "workflow_id",\n "name": "工作流名称",\n "version": "1.0.0",\n "description": "工作流描述",\n "exception_handlers": [\n {\n "name": "handler_name",\n "selector": { "text": "关闭" },\n "action": "click",\n "max_trigger_count": 3\n }\n ],\n "steps": {\n "open_result_detail": {\n "description": "步骤描述",\n "actions": [\n { "path": "accessibility/node", "params": { "selector": { "resource_id": "com.example:id/video_card" }, "action": "click", "action_index": 0, "wait_timeout": 3000 } },\n { "path": "base/sleep", "params": { "duration": 2000 } },\n { "path": "accessibility/node", "params": { "selector": { "resource_id": "com.example:id/detail_title" }, "wait_timeout": 5000 }, "throw_if_empty": ["nodes"] }\n ]\n }\n },\n "flow": ["open_result_detail"]\n}\n\`\`\`\n\n补充约束:\n- \`steps\` 必须是对象,key 为 step id,value 为 step 定义\n- 每个 step 必须有 \`actions\`,且至少 1 个 action\n- \`flow\` 必须按执行顺序列出 step id,且每个 id 都必须存在于 \`steps\`\n- 仅当使用 \`loop.max_count\` 时,才允许 \`completed: "success"\`\n- \`exception_handlers\` 可以是空数组,但每个 handler 都必须满足合法字段结构\n\n## 生成策略\n- 主流程:按 actions 顺序消费 include_mode="main_flow" 的记录\n- 异常处理:从 include_mode="exception_handler_candidate" 中提取\n- 步骤命名:基于 intent.merge_key 生成稳定英文 step id\n- 步骤描述:使用 intent.summary 或 page.before/after.description 组织一句简洁描述\n- 验证:使用 replay_plan.verification,禁止回退到人工推理\n\n输出 pure JSON only.`,ie=`You are an Android unattended WorkflowScript engineer. The input is not a raw log. It is a RecordingArtifact already refined during recording.\n\nRole:\n- Your job is to translate existing execution evidence into a stable, reliable, unattended WorkflowScript.\n\nAction:\n- Generate the final script from RecordingArtifact.\n- Reuse approved replay_plan entries, script selectors, and verification selectors whenever available.\n- If some information is missing, continue from the available evidence instead of blocking or inventing missing data.\n\nContext:\n1. Consume only the structured fields already approved for script generation.\n2. Do not infer selectors, page intent, or success criteria on your own.\n3. Do not invent selectors from diagnostics, raw descriptions, or candidate nodes.\n4. Your objective is unattended replay stability, so prioritize replayability, verifiability, and selector reliability over superficial completeness.\n\nExpectation:\n- Output pure WorkflowScript JSON.\n- Keep the main flow clear and deterministic.\n- Tolerate missing fields, but never fabricate missing evidence.\n\n## Input format\nEach RecordingArtifact.actions[*] already includes:\n- intent.merge_key: suggested step merge key\n- target.script_selector: recording-approved selector for script usage\n- success_criteria.primary: recording-approved verification selector\n- success_criteria.materialization: whether verification is actually ready for replay\n- replay_plan.actions: prebuilt action skeletons\n- replay_plan.verification: prebuilt verification action skeleton\n- classification.include_mode: main_flow / exception_handler_candidate / log_only\n- warnings: recording-time non-blocking gaps (for example missing replayable verification plans)\n- Some fields may be null / [] / {}: that means the recorder did not capture them, so ignore them and do not invent replacements\n\n## Field guide\n${te}\n\n## Unattended replay priorities\n1. Replayability is more important than superficial completeness.\n2. If replay_plan.actions exists, prefer generating the action from it directly; if not, skip rather than invent.\n3. Generate verification only when replay_plan.verification exists.\n4. Write selectors into the script only when target.script_selector or success_criteria.primary/fallback exists; do not reverse-engineer selectors from lower-trust fields.\n5. log_only normally stays out of main flow; exception_handler_candidate should become exception_handlers first.\n\n## Hard rules\n1. Use replay_plan.actions directly whenever present; do not rebuild action params manually.\n2. Whenever a main_flow record has replay_plan.verification, you must emit a full “base/sleep -> verification” closure after the record's replay_plan.actions.\n3. Prefer generating a scene-specific duration for base/sleep yourself; if you cannot judge the timing, you may omit duration and the system will fall back to 2000ms.\n4. accessibility/node actions with an action param must use wait_timeout of at least 3000ms; for pure verification accessibility/node actions, prefer preserving replay_plan.verification.params.wait_timeout, and if it is missing, invalid, or below the minimum in your output, the system will fall back and clamp it to at least 5000ms.\n5. Records with classification.include_mode="log_only" should normally stay out of the main flow.\n6. Records with classification.include_mode="exception_handler_candidate" should become top-level exception_handlers first, not normal steps.\n7. Selectors may only come from target.script_selector or success_criteria.primary/fallback.\n8. Never reconstruct selectors from bounds, dynamic text, or candidate node text.\n9. Prefer merging adjacent main_flow records with the same merge_key into one step.\n10. If replay_plan.actions is empty, do not fabricate an action. Skip that record.\n11. completed may only be the literal "success", and only for loop.max_count.\n12. If RecordingArtifact.warnings exists or action.warnings is non-empty, continue from the approved replay_plan only; do not fabricate missing selectors or verification actions.\n13. If success_criteria.required=true but materialization is not "ready", treat the recording as incomplete; keep approved replay_plan.actions, but do not invent replay_plan.verification.\n14. Output pure JSON only.\n\n## Workflow constraints\n- Legal paths only: activity/start, permission/set, activity/stop, accessibility/node, input/scroll_bezier, input/text, input/keyevent, input/click, base/sleep\n- accessibility/node requires a positive integer wait_timeout\n- accessibility/node with an action param must use wait_timeout of at least 3000ms; pure verification accessibility/node must use at least 5000ms\n- throw_if_empty must be exactly ["nodes"]\n- exception_handlers are top-level only\n\n## Output format (WorkflowScript)\nYou must output one valid WorkflowScript JSON object with this shape:\n\n\`\`\`json\n{\n "id": "workflow_id",\n "name": "Workflow name",\n "version": "1.0.0",\n "description": "Workflow description",\n "exception_handlers": [\n {\n "name": "handler_name",\n "selector": { "text": "Close" },\n "action": "click",\n "max_trigger_count": 3\n }\n ],\n "steps": {\n "open_result_detail": {\n "description": "Step description",\n "actions": [\n { "path": "accessibility/node", "params": { "selector": { "resource_id": "com.example:id/video_card" }, "action": "click", "action_index": 0, "wait_timeout": 3000 } },\n { "path": "base/sleep", "params": { "duration": 2000 } },\n { "path": "accessibility/node", "params": { "selector": { "resource_id": "com.example:id/detail_title" }, "wait_timeout": 5000 }, "throw_if_empty": ["nodes"] }\n ]\n }\n },\n "flow": ["open_result_detail"]\n}\n\`\`\`\n\nAdditional constraints:\n- \`steps\` must be an object keyed by step id\n- every step must contain \`actions\` with at least one action\n- \`flow\` must list step ids in execution order, and every id must exist in \`steps\`\n- \`completed: "success"\` is only allowed with \`loop.max_count\`\n- \`exception_handlers\` may be an empty array, but every handler must follow the legal field shape\n\n## Generation strategy\n- Main flow: consume records with include_mode="main_flow" in order\n- Exception handling: extract from include_mode="exception_handler_candidate"\n- Step IDs: generate stable English ids from intent.merge_key\n- Step descriptions: use intent.summary or page.before/after.description\n- Verification: use replay_plan.verification only; never fall back to manual inference\n\nOutput pure JSON only.`;function re(e){return"zh"===e?"你是 Android 自动化需求优化助手。\n\n要求:\n1. 输出语言与输入一致。\n2. 只做表达优化,不新增用户未提及的目标。\n3. 保留次数、顺序、停止条件、应用名和关键文本。\n4. 输出仅保留优化后的最终描述,不要解释。":"You are an Android automation intent refinement assistant.\n\nRequirements:\n1. Keep output language consistent with input.\n2. Improve expression only; do not add new goals not mentioned by user.\n3. Preserve count, order, stop conditions, app names, and key text.\n4. Output only the final refined description without explanations."}function oe(e){return re(v(e))}function ae(e,t=!0){return function(e,t=!0){const n=v(e),i=w(e),r=I[n][i]||I[n].single_flow;return"zh"===n?["你是 Android 自动化任务规划助手。","根据用户目标和当前屏幕,生成可执行、可验证、可收敛的任务计划。",...t?["若缺少规划所需的关键信息,必须暂停并明确提出一个最小问题,禁止编造计划。"]:[],x("全局规则",N),x(`模式规则(${i})`,r),"## 输出 JSON 结构","{",...t?[' "status": "completed | paused(默认 completed)",']:[],' "goal": "string",',' "subtasks": [{"id":1,"description":"string","successCriteria":"string","estimatedActions":["tool"]}],',' "risks": ["string"],',' "assumptions": ["string"],',...t?[' "estimatedSteps": 1,',' "pauseMessage": "string,可选,仅 status=paused 时填写",',' "pauseReason": "string,可选,仅 status=paused 时填写"']:[' "estimatedSteps": 1'],"}"].join("\n\n"):["You are an Android automation planning assistant.","Generate an executable, verifiable, and convergent task plan based on goal and current screen.",...t?["If critical planning information is missing, pause and ask one minimal clarification question instead of inventing a plan."]:[],x("Global Rules",z),x(`Mode Rules (${i})`,r),"## Output JSON Schema","{",...t?[' "status": "completed | paused (default completed)",']:[],' "goal": "string",',' "subtasks": [{"id":1,"description":"string","successCriteria":"string","estimatedActions":["tool"]}],',' "risks": ["string"],',' "assumptions": ["string"],',...t?[' "estimatedSteps": 1,',' "pauseMessage": "string, optional, required when status=paused",',' "pauseReason": "string, optional, required when status=paused"']:[' "estimatedSteps": 1'],"}"].join("\n\n")}(e,t)}function se(e,t){return function(e,t){const n=v(e),i=w(e),r=q[n][i]||q[n].single_flow;return"zh"===n?["你是 Android 自动化执行 Agent。你的职责是在真实设备上高成功率完成目标。",x("强制层",k.primary),x("建议层",k.secondary),x("核心执行规则",S),x(`任务模式规则(${i})`,r),"## 输出约束","- 优先一次只推进一个可验证子目标;若发生状态变化,必须先完成 wait -> observe_screen -> verify_ui_state 再继续。","- 非必要不输出长文本,优先通过 tool_calls 执行动作。","- 当缺少关键参数或验证证据时,先尝试基于当前界面补齐;确实无法判断时再暂停并明确提问。",j(t,n)].filter(Boolean).join("\n\n"):["You are an Android automation execution agent. Your objective is maximum completion reliability on real devices.",x("Hard Layer",A.primary),x("Suggestion Layer",A.secondary),x("Core Execution Rules",$),x(`Task Mode Rules (${i})`,r),"## Output Constraints","- Advance one verifiable sub-goal at a time; after state changes, complete wait -> observe_screen -> verify_ui_state before continuing.","- Keep text brief unless necessary; prefer tool_calls for actions.","- If critical parameters or verification evidence are missing, first try to repair them from the current screen; pause and ask only when they remain unclear.",j(t,n)].filter(Boolean).join("\n\n")}(e,t)}function ce(e){return function(e){return"zh"===v(e)?ne:ie}(e)}function le(e,t,n){return function(e,t,n){const i=v(e),r=(s=Z(e,t),{version:s.version,goal:s.goal,screen:s.screen??null,design_principle:s.design_principle,warnings:s.warnings??[],actions:s.actions.map(e=>({id:e.id,seq:e.seq,tool:e.tool,success:e.success,error:e.error??null,page:{before:{kind:e.page.before.kind,description:e.page.before.description??null,anchor:e.page.before.anchor??{}},after:e.page.after?{kind:e.page.after.kind,description:e.page.after.description??null,anchor:e.page.after.anchor??{}}:null,key_features:e.page.key_features??[]},intent:{summary:e.intent.summary,purpose:e.intent.purpose,expected_result:e.intent.expected_result,merge_key:e.intent.merge_key},target:{desc:e.target.desc??null,role:e.target.role,runtime_selector:e.target.runtime_selector??{},runtime_action_index:e.target.runtime_action_index??null,runtime_selected_node:e.target.runtime_selected_node??{},selector_profile:e.target.selector_profile??{},script_selector:e.target.script_selector??null,selector_candidates:e.target.selector_candidates??[]},success_criteria:{required:e.success_criteria.required,materialization:e.success_criteria.materialization,signal_type:e.success_criteria.signal_type,rationale:e.success_criteria.rationale,primary:e.success_criteria.primary??null,fallback:e.success_criteria.fallback??null},classification:{criticality:e.classification.criticality,include_mode:e.classification.include_mode,step_is_key:e.classification.step_is_key},replay_plan:{actions:e.replay_plan.actions??[],verification:e.replay_plan.verification??null},diagnostics:{matched_count:e.diagnostics.matched_count??null,selector_reusable:e.diagnostics.selector_reusable??null},warnings:e.warnings??[]}))}),o="zh"===i?ee:te,a=[];var s;return r.screen&&a.push(`[Screen]\n${r.screen.width}x${r.screen.height}`),a.push(`[Goal]\n${e}`),a.push(`[RecordingArtifactFieldGuide]\n${o}`),a.push(`[RecordingArtifact]\n${JSON.stringify(r,null,2)}`),n&&a.push(`[PreviousFailure]\n${n}`),a.push("zh"===i?"请将 RecordingArtifact 翻译成最终 WorkflowScript。只使用 replay_plan、target.script_selector、success_criteria。不要自行推导 selector,不要补编未记录动作。遇到 warnings 时继续基于已批准信息生成,但不要发明缺失验证。只输出 WorkflowScript JSON。":"Translate the RecordingArtifact into the final WorkflowScript. Use replay_plan, target.script_selector, and success_criteria only. Do not derive selectors or invent unrecorded actions. When warnings exist, continue from approved data only and do not invent missing verification. Output WorkflowScript JSON only."),a.join("\n\n")}(e,t,n)}const pe=ae(""),de=se(""),ue=ce(""),_e=ue.length;l("sha256").update([re("zh"),re("en"),pe,de,ue,String(_e)].join("\n\n-----\n\n")).digest("hex");const me=i.object({path:i.string().min(1),params:i.record(i.unknown()).optional(),throw_if_empty:i.array(i.string()).optional()}),fe=i.object({description:i.string().optional(),completed:i.literal("success").optional(),loop:i.union([i.object({count:i.number().int(),interval:i.number().int().optional()}),i.object({max_count:i.number().int(),interval:i.number().int().optional()})]).optional(),actions:i.array(me).min(1)}),ge=i.object({id:i.string().min(1),name:i.string().min(1),version:i.string().min(1),description:i.string().optional(),timeout:i.number().int().positive().optional(),exception_handlers:i.array(i.object({description:i.string().optional(),name:i.string().optional(),selector:i.record(i.unknown()),action:i.string().min(1),action_params:i.record(i.unknown()).optional(),max_trigger_count:i.number().int().positive().optional()})).optional(),steps:i.record(fe),flow:i.array(i.string()).min(1)}),ye=new Set(["activity/start","permission/set","activity/stop","accessibility/node","input/scroll_bezier","input/text","input/keyevent","input/click","base/sleep"]);function he(e){return!e||"object"!=typeof e||Array.isArray(e)?null:e}function be(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function ve(e){if("number"==typeof e&&Number.isInteger(e))return e;if("string"==typeof e&&e.trim().length>0){const t=Number(e);if(Number.isFinite(t)&&Number.isInteger(t))return t}return null}function we(e){const t=he(e.loop);if(!t)return void(be(e,"completed")&&delete e.completed);const n=(Array.isArray(e.actions)?e.actions:[]).map(e=>he(e)).filter(e=>!!e);if(be(t,"count")){return 1===ve(t.count)?(delete e.loop,void delete e.completed):void(be(e,"completed")&&delete e.completed)}if(!be(t,"max_count"))return;e.completed="success";if(n.some(e=>ke(e.throw_if_empty)))return;const i=n.find(e=>{if("accessibility/node"!==e.path)return!1;const t=he(e.params);return!t||!be(t,"action")});if(i)return void(i.throw_if_empty=["nodes"]);const r=n.find(e=>"accessibility/node"===e.path);if(r)return void(r.throw_if_empty=["nodes"]);const o=ve(t.max_count);if(null!==o){if(1===o)return delete e.loop,void delete e.completed;e.loop={count:o},delete e.completed}}function xe(e){return"number"==typeof e&&Number.isInteger(e)&&e>0}function ke(e){return Array.isArray(e)&&1===e.length&&"string"==typeof e[0]&&"nodes"===e[0]}function Ae(e,t,n,i){const r=`${e}.actions[${n}]`;if(ye.has(t.path)||i.push(`${r}: illegal path "${t.path}"`),t.throw_if_empty&&!ke(t.throw_if_empty)&&i.push(`${r}: throw_if_empty must be exactly ["nodes"]`),"accessibility/node"===t.path){const e=t.params?.wait_timeout;xe(e)||i.push(`${r}: accessibility/node requires positive integer params.wait_timeout`)}if("base/sleep"===t.path){const e=t.params?.duration;xe(e)||i.push(`${r}: base/sleep requires positive integer params.duration`)}}function Se(e,t,n){const i=t.steps[e],r=i.loop,o=i.completed;if(!r)return void(void 0!==o&&n.push(`${e}: steps without loop must not define completed`));if("count"in r)return 1===r.count&&n.push(`${e}: loop.count=1 is forbidden; remove loop`),void(void 0!==o&&n.push(`${e}: count loop must not define completed`));"success"!==o&&n.push(`${e}: max_count loop must define completed="success"`);i.actions.some(e=>ke(e.throw_if_empty))||n.push(`${e}: max_count loop requires at least one action with throw_if_empty=["nodes"]`)}function $e(e){const t=[];for(const[n,i]of Object.entries(e.steps)){Se(n,e,t);for(let e=0;e<i.actions.length;e++)Ae(n,i.actions[e],e,t)}if(function(e,t){const n=new Set;for(const i of e.flow){const r=e.steps[i];for(let e=0;e<r.actions.length;e++){const o=r.actions[e],a=o.params||{},s=`${i}.actions[${e}]`;if("permission/set"===o.path){const e=a.package_name;if("string"!=typeof e||!e){t.push(`${s}: permission/set requires params.package_name`);continue}!0!==a.grant_all&&t.push(`${s}: permission/set requires params.grant_all=true`),n.add(e)}if("activity/start"===o.path){const e=a.package_name;if("string"!=typeof e||!e){t.push(`${s}: activity/start requires params.package_name`);continue}n.has(e)||t.push(`${s}: missing prior permission/set for package "${e}"`)}}}}(e,t),t.length>0)throw new Error(`workflow semantic validation failed:\n- ${t.join("\n- ")}`)}function qe(e){const t=function(e){const t=e.steps;if(!t||"object"!=typeof t||Array.isArray(t))return e;const n=e.exception_handlers;if(Array.isArray(n))for(const e of n)if(e&&"object"==typeof e&&!Array.isArray(e)){const t=e;t.action||(t.action="click")}for(const e of Object.values(t)){if(!e||"object"!=typeof e||Array.isArray(e))continue;const t=e,n=t.actions;if(Array.isArray(n)){for(const e of n){if(!e||"object"!=typeof e||Array.isArray(e))continue;const t=e;"wait"===t.path&&(t.path="base/sleep");const n=he(t.params)||{};if("base/sleep"===t.path){const e=ve(n.duration);t.params={...n,duration:null!==e&&e>0?Math.max(2e3,e):2e3}}if("accessibility/node"===t.path){const e="string"==typeof n.action?n.action:void 0,i=ve(n.wait_timeout);e&&(null===i||i<=0)?t.params={...n,wait_timeout:3e3}:e&&null!==i&&i>0?t.params={...n,wait_timeout:Math.max(3e3,i)}:!e&&(null===i||i<=0)?t.params={...n,wait_timeout:5e3}:!e&&null!==i&&i>0&&(t.params={...n,wait_timeout:Math.max(5e3,i)})}const i=t.throw_if_empty;Array.isArray(i)&&i.includes("nodes")&&(t.throw_if_empty=["nodes"])}we(t)}}return e}(e),n=ge.parse(t),i={...n,id:n.id||`workflow_${Date.now()}`,version:n.version||"1.0.0"};return function(e){for(const t of e.flow)if(!e.steps[t])throw new Error(`missing step referenced in flow: ${t}`)}(i),$e(i),i}function je(e){const t=e?.message||String(e),n=t.toLowerCase();return n.includes("json")||n.includes("schema")||n.includes("zod")||n.includes("strict")?{category:"STRUCTURE",message:t}:n.includes("missing step")||n.includes("flow")||n.includes("workflow semantic validation")||n.includes("recording artifact has blockers")||n.includes("artifact provenance validation")?{category:"SEMANTIC",message:t}:{category:"UNKNOWN",message:t}}async function Ne(i,r,o,a,s){const c=f(o).getModel(),l=Math.max(1,a.scriptGeneration.maxAttempts),p=ce(i),d=e.fromMessages([["system","{systemPrompt}"],["human","{userMessage}"]]).pipe(c).pipe(new t).pipe(new n({func:e=>qe(e)})),u=[];let _;for(let e=1;e<=l;e++){const t=le(i,r,_);try{return{workflow:await d.invoke({systemPrompt:p,userMessage:t},{signal:s}),attempts:e,errors:u}}catch(t){const n=je(t);if(u.push(`[${n.category}] ${n.message}`),_=n.message,e>=l)throw new Error(`script generation failed (maxAttempts=${l}): [${n.category}] ${n.message}`)}}throw new Error(`script generation failed (maxAttempts=${l}): [UNKNOWN] unreachable`)}const ze={vendor:"openai",baseUrl:"https://api.openai.com/v1",apiKey:"",model:"gpt-4o-mini"},Ie={retries:{observation:3,action:2},timeouts:{defaultMs:12e3,observeScreenMs:18e3,startAppMs:25e3},limits:{maxIterations:120,maxConsecutiveFailures:8,maxSameToolFingerprint:3},planner:{maxAttempts:3},scriptGeneration:{maxAttempts:3}};async function Oe(e,t,n,i,r){return Ne(e,t,n,i,r)}async function Re(e,t,n,i){return(await Ne(e,t,n,Ie,i)).workflow}export{C as A,Ie as D,T as P,U as S,E as T,R as V,Oe as a,M as b,f as c,ae as d,v as e,se as f,Re as g,O as h,W as i,oe as j,ze as k};
@@ -1 +0,0 @@
1
- "use strict";var e=require("@langchain/core/prompts"),t=require("@langchain/core/output_parsers"),n=require("@langchain/core/runnables"),i=require("zod"),r=require("@langchain/anthropic"),o=require("@langchain/core/messages"),a=require("@langchain/core/tools"),s=require("@langchain/google-genai"),c=require("@langchain/openai"),l=require("crypto");function p(e){return e.map(e=>{if("assistant"===e.role){const t=(e.toolCalls||[]).map(e=>({type:"tool_call",id:e.id,name:e.name,args:e.arguments}));return o.coerceMessageLikeToMessage({role:"assistant",content:e.content,...t.length>0?{tool_calls:t}:{}})}return"tool"===e.role?o.coerceMessageLikeToMessage({role:"tool",content:e.content,tool_call_id:e.toolCallId||""}):o.coerceMessageLikeToMessage({role:e.role,content:e.content})})}function d(e){return a.tool(async()=>"schema-only tool placeholder",{name:e.name,description:e.description,schema:e.schema})}function u(e,t){if("string"!=typeof e||0===e.trim().length)throw new Error(`${t} is required`)}function _(e,t,n){return"anthropic"===e?function(e,t){return new r.ChatAnthropic({model:e.model,apiKey:e.apiKey,temperature:.2,...e.baseUrl?{anthropicApiUrl:e.baseUrl}:{},...Object.keys(t).length>0?{clientOptions:{defaultHeaders:t}}:{}})}(t,n):"google"===e?function(e,t){return new s.ChatGoogleGenerativeAI({model:e.model,apiKey:e.apiKey,temperature:.2,...e.baseUrl?{baseUrl:e.baseUrl}:{},...Object.keys(t).length>0?{customHeaders:t}:{}})}(t,n):function(e,t){return new c.ChatOpenAI({model:e.model,apiKey:e.apiKey,temperature:.2,configuration:{...e.baseUrl?{baseURL:e.baseUrl}:{},...Object.keys(t).length>0?{defaultHeaders:t}:{}}})}(t,n)}class m{capabilities;vendor;model;constructor(e){const t={...e.headers||{}},n=function(e){const t=function(e){const t=(e||"").toLowerCase();return t.includes("deepseek")?"deepseek":t.includes("openai")?"openai":t.includes("custom")||t.includes("other")?"custom":t.includes("anthropic")||t.includes("claude")?"anthropic":t.includes("google")||t.includes("gemini")?"google":t.includes("azure")?"azure":"openai"}(String(e.vendor));return u(e.apiKey,"provider.apiKey"),u(e.model,"provider.model"),"anthropic"===t||"google"===t||u(e.baseUrl,"provider.baseUrl"),t}(e);this.vendor=n,this.capabilities=function(e){return{toolCalling:!0,structuredJson:!0,jsonMode:"openai"===e||"deepseek"===e||"azure"===e||"custom"===e}}(n),this.model=_(n,e,t)}getModel(){return this.model}async chatWithTools(e,t,n){const i=p(e),r=function(e){return e.map(e=>function(e){if(!e||"object"!=typeof e)return!1;const t=e;return"string"==typeof t.name&&"string"==typeof t.description&&!!t.schema&&"object"==typeof t.schema}(e)?d(e):e)}(t),o=r.length>0&&"function"==typeof this.model.bindTools?this.model.bindTools(r):this.model,a=await o.invoke(i,{signal:n}),s="string"==typeof(c=a).text&&c.text.length>0?c.text:"string"==typeof c.content?c.content:Array.isArray(c.content)?c.content.map(e=>"string"==typeof e?e:e&&"object"==typeof e&&"text"in e&&"string"==typeof e.text?e.text:"").filter(e=>e.length>0).join("\n"):"";var c;const l=a.tool_calls||[],u=a.response_metadata&&"object"==typeof a.response_metadata?a.response_metadata:null;return{content:s,toolCalls:l.filter(e=>"string"==typeof e.name&&e.name.length>0).map((e,t)=>{return{id:"string"==typeof e.id&&e.id.length>0?e.id:`call_${Date.now()}_${t}`,name:e.name,arguments:(n=e.args,n&&"object"==typeof n&&!Array.isArray(n)?n:{})};var n}),finishReason:"string"==typeof u?.finish_reason&&u.finish_reason||"string"==typeof u?.stop_reason&&u.stop_reason||void 0}}async chatStructuredJson(e,t,n){const i=p(e),r="anthropic"===(o=this.vendor)||"google"===o?[{method:"jsonSchema"},{method:"functionCalling"}]:[{method:"jsonSchema",strict:!0},{method:"functionCalling",strict:!0},{method:"jsonMode"}];var o;let a=null;for(const e of r)try{const r=this.model.withStructuredOutput(t,{name:"structured_output",method:e.method,..."boolean"==typeof e.strict?{strict:e.strict}:{}}),o=await r.invoke(i,{signal:n});return t.parse(o)}catch(e){a=e}const s=a instanceof Error&&a.message?a.message:"langchain structured output failed with all methods";throw new Error(s)}}function f(e){return new m(e)}const g=/[\u3400-\u9fff]/u,y=[/\b\d+\s*(次|遍|个|条|张)\b/u,/第\s*\d+\s*(个|条|张)/u,/\b\d+\s*(times?|rounds?|steps?|items?)\b/i,/\bfor\s+\d+\s*(times?|rounds?)\b/i],h=[/直到/u,/等到/u,/出现/u,/找到/u,/\buntil\b/i,/\bwhen\b/i,/\bunless\b/i,/\bappears?\b/i,/\bfound\b/i],b=[/一直/u,/不停/u,/持续/u,/无限/u,/永远/u,/\bforever\b/i,/\bcontinuously\b/i,/\bendless(?:ly)?\b/i,/\bindefinitely\b/i,/\bkeep\b.*\bloop(?:ing)?\b/i];function v(e){return g.test(e||"")?"zh":"en"}function w(e){const t=e.trim();return t?y.some(e=>e.test(t))?"fixed_count":h.some(e=>e.test(t))?"until_condition":b.some(e=>e.test(t))?"infinite":"single_flow":"single_flow"}function x(e,t){return`## ${e}\n${t.map((e,t)=>`${t+1}. ${e}`).join("\n")}`}const k={primary:["每步前必须有最新 observe_screen / dump 证据,禁止基于过期界面继续执行。","每步后必须完成 success check;优先补齐 observe_screen -> verify_ui_state 再进入下一步。","页面发生变化后必须重新定位,不允许沿用旧页面的 selector 或入口。","必须按 stage 推进:一次只推进一个已验证子目标,不允许无限漂移或脱离当前阶段。","连续失败必须进入恢复分支,优先收敛、重试替代入口或暂停,而不是盲目重复。","高风险动作必须有显式授权,若用户目标未明确授权,不得擅自执行。"],secondary:["selector 优先最小唯一。","优先稳定属性,避免动态 text。","优先语义定位,不行再坐标。","可处理弹窗、广告、权限框。","可根据页面变化自动切换入口。"]},S={primary:["Each step must start from fresh observe_screen / dump evidence; never act on stale UI state.","Each step must end with a success check; prefer completing observe_screen -> verify_ui_state before advancing.","After a page change, re-locate everything; never reuse selectors or entry points from the previous page.","Advance by stage: move one verified sub-goal at a time and do not drift indefinitely.","Consecutive failures must enter a recovery branch: converge, retry an alternative path, or pause instead of repeating blindly.","High-risk actions require explicit authorization; if the user did not clearly authorize them, do not execute them."],secondary:["Prefer minimal unique selectors.","Prefer stable attributes and avoid dynamic text.","Prefer semantic locators; fall back to coordinates only when necessary.","You may handle popups, ads, and permission dialogs.","You may switch entry points automatically when the page changes."]},A=["首次动作前先 observe_screen,禁止盲操作。","每个会引发状态变化的动作后(包括 tap_element、set_text、input_text、start_app 等),优先执行 observe_screen(wait_ms) -> verify_ui_state 补齐录制信息。跳过 verify_ui_state 只会产生告警并降低脚本生成质量,不阻塞执行。","单轮最多一个状态变化动作;优先按“动作 -> wait(自适应时长) -> observe_screen -> verify_ui_state”闭环推进,以提高录制质量。","运行中仅执行与用户目标直接相关的动作;与任务无关的事情不要自行处理,禁止无关探索、浏览或演示性操作。","启动应用时优先使用包名;若当前只有应用名,先调用 get_installed_apps 确认 package_name,再使用 start_app,禁止臆测包名。","selector 必须来自最新 observe_screen 的真实内容。","selector 选择遵循“脚本优先”阶梯:稳定 resource_id -> 稳定 text -> 稳定 content_desc -> 最小组合 -> action_index。","校验场景(verify_ui_state / accessibility-node 纯查找)同样遵循最小唯一稳定策略,但每一步只用单字段(resource_id -> text -> content_desc),不做组合。","resource_id 唯一时只用 resource_id;若 resource_id 疑似混淆(如 obfuscated/数字前缀/高熵短串),不得单独依赖,退回稳定 text/content_desc。","组合唯一时优先 resource_id + 稳定 text/content_desc;禁止叠加动态值(时间、计数、row/column 等易变化文案)。bounds 仅作兜底消歧,不应作为通用脚本主 selector。","收到 VALIDATION 或 RUNTIME_GUARD 错误时,禁止原参数盲重试;必须先 observe_screen 刷新证据并调整 selector/动作。","禁止在无新观察证据的情况下重复完全相同的工具调用(同 tool + 同参数)。","界面方位只能依据 bounds 坐标与屏幕尺寸判断,禁止按节点顺序/缩进或经验臆测”顶部/底部”。","动作失败后最多允许一次替代路径,仍失败则暂停。","坐标点击仅作为 selector 无法稳定定位时的最后手段。","swipe 前优先调用 record_search_context 记录查找目标与页面锚点;跳过只会产生录制告警并降低脚本生成质量。","index 仅在“同屏同语义节点多匹配且必须按顺序区分”时使用,且必须与 resource_id/text/content_desc/class_name/bounds 之一组合,禁止单独使用 index。","tap_element/long_press_element/set_text 的序号定位必须使用顶层 action_index,禁止 selector.index;verify_ui_state / record_search_context 可记录元素 index 作为补充证据。","当 text/content_desc 不稳定但仍需顺序区分时,且列表顺序稳定,使用 resource_id + action_index;若顺序不稳定则必须回退到更稳定锚点。","列表可能刷新、重排或异步插入时禁止依赖 index,优先稳定 resource_id 或稳定控件标签;若无法证明顺序稳定,则不要把该定位策略带入脚本。",'pre_context.step_intent 优先包含:(1)当前页面位置 (2)操作目的 (3)预期结果。例如"在抖音搜索结果页,点击第一个视频进入播放页",而非"点击视频"。record_search_context 的 step_intent 同理。',"若你能把当前动作抽象成稳定可复用的步骤语义,请显式填写 pre_context / record_search_context 中的 merge_key 和 expected_result。merge_key 应是稳定短语,不要直接抄界面文案。","若你明确知道该步骤通常需要额外等待再验证,请显式填写 wait_ms_hint,帮助脚本生成更准确设置校验等待;不确定就省略。","若你能明确判断页面类型、目标角色、步骤关键性或是否属于异常处理,请显式填写 pre_context / record_search_context 中的 page_kind、target_role、criticality_hint、include_mode_hint;若动作后页面类型也能明确判断,可填写 verify_ui_state.page_kind。不确定就省略,禁止靠文案关键词猜。",'pre_context.target.desc 和 anchor.desc 优先描述元素的视觉特征和语义角色,例如"底部导航栏中的首页按钮"或"搜索结果列表中的第一个视频卡片",避免只写"按钮"或"文本"。','verify_ui_state 中优先填写 screen_desc,用一句话描述当前页面(如"抖音视频播放页"、"设置-通用页面"),帮助脚本生成理解上下文。',"当操作导致页面切换时,verify_ui_state 中优先包含 page_anchor(新页面的标志性元素),帮助脚本生成确认导航成功。","如果 verify_ui_state 返回“补录提醒”或提示未形成可回放 verification_plan,优先重新 observe_screen 并补一个可唯一回放的 verify_element/page_anchor;若当前主流程已明确,也可以继续执行,但要接受录制质量下降。"],z=["Call observe_screen before the first action; no blind operations.","After each state-changing action (including tap_element, set_text, input_text, start_app, etc.), prefer observe_screen(wait_ms) -> verify_ui_state to complete the recording. Skipping verify_ui_state should only produce a warning and lower script-generation quality, not block execution.","At most one state-changing action per turn; prefer the loop “act -> wait(adaptive) -> observe_screen -> verify_ui_state” to keep the recording high quality.","During execution, only perform actions directly related to the user goal; do not handle unrelated tasks on your own, and avoid unrelated exploration, browsing, or demo-only actions.","Prefer package names when starting apps; if you only know the app name, call get_installed_apps to confirm package_name before using start_app, and never guess package names.","Selectors must come from the latest observe_screen evidence.","Selector choice must follow the script-safe ladder: stable resource_id -> stable text -> stable content_desc -> minimal combination -> action_index.","For verification scenarios (verify_ui_state / accessibility-node pure find), apply the same minimum-unique stability ladder, but single-field only (resource_id -> text -> content_desc), with no combinations.","If resource_id is unique, use only resource_id; if resource_id looks obfuscated (e.g. obfuscated/numeric prefix/high-entropy short token), do not rely on it alone and fall back to stable text/content_desc.","When combinations are required, prefer resource_id + stable text/content_desc; avoid dynamic values (time/count/row/column or other volatile copy). bounds is fallback-only and should not become a reusable script selector.","On VALIDATION or RUNTIME_GUARD errors, never blind-retry with the same arguments; observe_screen first, then adjust selector/action.","Do not repeat identical tool calls (same tool + same args) without new observation evidence.","Infer UI position only from bounds + screen size; never infer top/bottom from node order, indentation, or prior assumptions.","After an action failure, allow at most one alternative path; then pause.","Coordinate taps are last resort only when selector-based targeting is unstable.","Before swipe, prefer record_search_context to record the search target and page anchor; skipping should only produce recording-quality warnings.","Use index only when same-screen nodes are still ambiguous and order is required; index must be combined with at least one of resource_id/text/content_desc/class_name/bounds, never used alone.","For tap_element/long_press_element/set_text, ordinal targeting must use top-level action_index, not selector.index; verify_ui_state / record_search_context may carry node index as supplemental evidence.","If text/content_desc is unstable but order still matters and list order is stable, use resource_id + action_index; if order is unstable, fall back to more stable anchors instead.","Do not rely on index when list order can change (refresh/reorder/async insertion); if order stability cannot be justified, do not carry that locator strategy into the script.",'pre_context.step_intent should preferably include: (1) current page location (2) action purpose (3) expected result. Example: "On TikTok search results page, tap the first video to enter playback page", not just "tap video". Same for record_search_context step_intent.',"If you can abstract the current action into a stable reusable step semantic, fill merge_key and expected_result in pre_context or record_search_context. merge_key should be a stable short phrase, not copied screen text.","If you explicitly know the step usually needs additional wait before verification, fill wait_ms_hint to help script generation set verification timing more accurately; omit it when unsure.","If you can explicitly determine page kind, target role, step criticality, or whether a record is an exception handler candidate, fill page_kind/target_role/criticality_hint/include_mode_hint in pre_context or record_search_context. If the resulting page kind is also explicit after an action, you may fill verify_ui_state.page_kind. If unsure, omit them; never guess from copy keywords.",'pre_context.target.desc and anchor.desc should preferably describe the element\'s visual characteristics and semantic role, e.g. "Home button in bottom navigation bar" or "First video card in search results list", not just "button" or "text".','Prefer filling verify_ui_state screen_desc with a one-sentence page summary (e.g. "TikTok video playback page", "Settings - General page") to help script generation understand context.',"When an action causes a page transition, verify_ui_state should preferably include page_anchor (a landmark element of the new page) to help script generation confirm navigation success.","If verify_ui_state returns a repair warning or says no replayable verification_plan was formed, prefer to re-run observe_screen and repair verify_element/page_anchor with a uniquely replayable locator; if the main task path is already clear, you may continue with degraded recording quality."],q={zh:{fixed_count:["严格按目标次数执行,不得提前结束。","每轮结束后验证累计进度。"],until_condition:["每轮都必须“检查 -> 动作 -> 等待 -> 再检查”。","达到条件立即收敛,未命中到上限后结束。"],infinite:["仅当目标明确要求持续执行时允许无限循环。"],single_flow:["完成主线后立即结束,不做无关探索。"]},en:{fixed_count:["Execute exactly the requested count and never finish early.","Validate cumulative progress after each loop."],until_condition:['Every loop must follow "check -> act -> wait -> re-check".',"Converge immediately when condition is met; stop at limit otherwise."],infinite:["Infinite loop is allowed only when explicitly requested."],single_flow:["Finish immediately after the main path; avoid unrelated exploration."]}};function O(e,t){if(!e||0===e.subtasks.length)return"";const n=e.subtasks.map(e=>"zh"===t?`- ${e.id}. ${e.description} (成功标准: ${e.successCriteria})`:`- ${e.id}. ${e.description} (Success: ${e.successCriteria})`).join("\n");return"zh"===t?`## 任务计划参考\n${n}`:`## Plan Reference\n${n}`}const I=["输出必须是合法 JSON 对象,禁止 markdown 代码块。","计划必须基于当前屏幕状态,不允许假设未观察到的页面。","计划仅包含与用户目标直接相关的步骤,禁止加入与目标无关的探索性动作。","每个子任务都要有可观察的 successCriteria。","若目标存在前置状态依赖,必须先规划“进入前置状态 -> 验证前置状态”,再执行终态动作。","子任务按执行顺序排列,保持最短稳定路径。"],$=["Output must be a valid JSON object, never markdown.","Plan must be grounded in the current observed screen only.","Plan must include only steps directly related to the user goal; do not add unrelated exploratory actions.","Each subtask must include observable successCriteria.",'If goal has prerequisite state dependencies, plan "enter prerequisite state -> verify prerequisite state" before terminal actions.',"Subtasks must be ordered for the shortest stable path."],R={zh:{fixed_count:["识别用户指定次数,子任务中体现计数闭环。","避免把固定次数任务改写为条件循环。"],until_condition:["计划中显式写出停止条件和最大探索轮次。","停止条件必须可观察,不能用抽象描述。"],infinite:["仅在目标明确要求持续执行时使用无限模式。","仍需给出安全中断条件与风险说明。"],single_flow:["保持单次流程简洁,避免过度拆分。"]},en:{fixed_count:["Capture user-requested counts and enforce count closure in subtasks.","Do not rewrite fixed-count goals into condition loops."],until_condition:["State explicit stop condition and max exploration rounds.","Stop condition must be observable, not abstract."],infinite:["Use infinite mode only when user explicitly requests continuous execution.","Still provide safety stop condition and risks."],single_flow:["Keep single-flow plans concise and avoid over-splitting."]}};const N=new Set(["start_app","stop_app","tap","tap_element","long_press_element","press_key"]),j=new Set(["verify_ui_state"]),T=new Set(["tap_element","long_press_element","set_text"]),C=new Set(["tap_element","long_press_element","set_text"]);new Set([...C,"verify_ui_state","record_search_context"]);const E=C,M=new Set([...C,"input_text"]),U=new Set(["start_app","stop_app","tap","tap_element","long_press_element","set_text","input_text","swipe","press_key"]);function P(e){return!e||"object"!=typeof e||Array.isArray(e)?null:e}function L(e){const t={};let n=!1;for(const[i,r]of Object.entries(e))null!=r&&""!==r&&(t[i]=r,n=!0);return n?t:void 0}function W(e){if("number"==typeof e&&Number.isInteger(e)&&e>=0)return e;if("string"==typeof e&&e.trim().length>0){const t=Number(e);if(Number.isInteger(t)&&t>=0)return t}}function D(e){if("number"==typeof e&&Number.isInteger(e)&&e>0)return e;if("string"==typeof e&&e.trim().length>0){const t=Number(e);if(Number.isInteger(t)&&t>0)return t}}function F(e,t){for(const n of t){const t=e[n];if("string"==typeof t){const e=t.trim();if(e.length>0)return e}}}function J(e){const t=P(e);if(t)return L({index:W(t.index),resource_id:F(t,["resource_id","resource-id","resourceId","id"]),text:F(t,["text"]),content_desc:F(t,["content_desc","content-desc","contentDesc"]),class_name:F(t,["class_name","class","className"]),bounds:F(t,["bounds"])})}function G(e){const t=P(e?.script_selector);if(!t)return;const n=P(t.selector);return n?{selector:n,action_index:W(t.action_index),stability:"string"==typeof t.stability?t.stability:void 0,reusable:"boolean"==typeof t.reusable?t.reusable:void 0,reason:"string"==typeof t.reason?t.reason:void 0,scope:"string"==typeof t.scope?t.scope:void 0,policy_decision:"string"==typeof t.policy_decision?t.policy_decision:void 0,policy_reason:"string"==typeof t.policy_reason?t.policy_reason:void 0}:void 0}function K(e){const t=P(e);if(!t)return;const n=F(t,["page_kind"]),i=F(t,["criticality_hint"]),r=F(t,["include_mode_hint"]),o=F(t,["valid_until"]);return{context_id:F(t,["context_id"]),page_kind:"home"===n||"list"===n||"detail"===n||"dialog"===n||"search"===n||"form"===n||"unknown"===n?n:void 0,target_role:F(t,["target_role"]),criticality_hint:"critical"===i||"supporting"===i||"noise"===i?i:void 0,include_mode_hint:"main_flow"===r||"log_only"===r||"exception_handler_candidate"===r?r:void 0,valid_until:"next_action"===o||"next_verified_transition"===o||"manual_close"===o?o:void 0}}function Y(e,t){if(e||t)return{context_id:t?.context_id||e?.context_id,page_kind:t?.page_kind||e?.page_kind,target_role:t?.target_role||e?.target_role,criticality_hint:t?.criticality_hint||e?.criticality_hint,include_mode_hint:t?.include_mode_hint||e?.include_mode_hint,valid_until:t?.valid_until||e?.valid_until}}function V(e){const t=new Set,n=[];for(const i of e)if(i&&!t.has(i)&&(t.add(i),n.push(i),n.length>=6))break;return n}const H=3e3;const B=new Set(["tap_element","long_press_element","set_text"]),Q=new Set(["start_app","stop_app","tap_element","long_press_element","set_text","input_text","press_key","swipe","tap","wait"]);function X(e,t){const n=function(e){const t=[];let n,i=null;for(const r of e){const e=r.toolName,o=P(r.arguments)||{},a=P(r.result.data);if("get_screen_info"===e&&r.result.success){const e="number"==typeof a?.width?a.width:void 0,t="number"==typeof a?.height?a.height:void 0;e&&t&&(n={width:e,height:t});continue}if("observe_screen"===e||"get_installed_apps"===e)continue;if("record_search_context"===e){i={step_intent:F(o,["step_intent"]),merge_key:F(o,["merge_key"]),expected_result:F(o,["expected_result"]),wait_ms_hint:D(o.wait_ms_hint),target_desc:F(o,["target_desc"]),anchor:L(P(o.anchor_element)||{}),anchor_plan:P(a?.anchor_plan)||void 0,target:L(P(o.target_element)||{}),target_plan:P(a?.target_plan)||void 0,recorded_context:K(a?.recorded_context)};continue}if("verify_ui_state"===e){const e=t[t.length-1];if(!e)continue;e.verify=L(P(o.verify_element)||{}),e.verify_desc=F(o,["step_desc"]),e.page_anchor=L(P(o.page_anchor)||{}),e.screen_desc=F(o,["screen_desc"]);const n=F(P(a?.recorded_page)||{},["page_kind"])||F(o,["page_kind"]);e.verified_wait_ms_hint=D(o.wait_ms_hint),e.verified_page_kind="home"===n||"list"===n||"detail"===n||"dialog"===n||"search"===n||"form"===n||"unknown"===n?n:void 0,e.verification_plan=P(a?.verification_plan)||void 0,e.page_anchor_plan=P(a?.page_anchor_plan)||void 0,"next_verified_transition"===i?.recorded_context?.valid_until&&(i=null);continue}const s={seq:t.length+1,tool:e,success:r.result.success};r.result.success||"string"!=typeof r.result.error||(s.error=r.result.error),i&&(s.step_intent=i.step_intent,s.intent_merge_key=i.merge_key,s.expected_result_hint=i.expected_result,s.wait_ms_hint=i.wait_ms_hint,s.search_context=i.target_desc,!s.anchor&&i.anchor&&(s.anchor=i.anchor),i.anchor_plan&&(s.anchor_plan=i.anchor_plan),!s.target&&i.target&&(s.target=i.target),i.target_plan&&(s.target_plan=i.target_plan),i.recorded_context&&(s.recorded_context=i.recorded_context),"next_action"===i.recorded_context?.valid_until&&(i=null));const c=P(o.pre_context);c&&(s.step_intent=F(c,["step_intent"])||s.step_intent,s.intent_merge_key=F(c,["merge_key"])||s.intent_merge_key,s.expected_result_hint=F(c,["expected_result"])||s.expected_result_hint,s.wait_ms_hint=D(c.wait_ms_hint)||s.wait_ms_hint,s.target=L(P(c.target)||{})||s.target,s.anchor=L(P(c.anchor)||{})||s.anchor,s.recorded_context=Y(s.recorded_context,K(c))),s.selector=L(P(o.selector)||{}),s.action_index=W(o.action_index),"string"==typeof o.text&&(s.text=o.text),"number"==typeof o.key_code&&(s.key_code=o.key_code),"string"==typeof o.package_name&&(s.package_name=o.package_name),"number"==typeof o.duration&&"wait"===e&&(s.wait_duration=o.duration),"number"==typeof o.x&&"number"==typeof o.y&&"tap"===e&&(s.tap_position={x:o.x,y:o.y}),"swipe"===e&&(s.swipe={start_x:Number(o.start_x),start_y:Number(o.start_y),end_x:Number(o.end_x),end_y:Number(o.end_y),duration:"number"==typeof o.duration?o.duration:300});const l=P(a?.runtime_selector_evidence);if(l){const e=L(P(l.requested_selector)||{});!s.selector&&e&&(s.selector=e),s.runtime_selected_node=J(l.selected_node),s.runtime_candidate_nodes=Array.isArray(l.candidate_nodes)?l.candidate_nodes.map(e=>J(e)).filter(e=>!!e):void 0,s.runtime_matched_count="number"==typeof l.matched_count?l.matched_count:void 0,s.selector_profile=P(l.selector_profile)||void 0;const t=W(l.action_index);void 0!==t&&(s.action_index=t)}t.push(s)}return{screen:n,actions:t}}(t),i=n.actions.map(e=>{const t=G(e.selector_profile),n=function(e){const t=G(e.page_anchor_plan),n=G(e.verification_plan);return t?{required:!0,materialization:"ready",signal_type:"page_arrived",rationale:"page transition uses page_anchor as the primary arrival signal",primary:t,fallback:n}:n?{required:!0,materialization:"ready",signal_type:"set_text"===e.tool||"input_text"===e.tool?"input_committed":"swipe"===e.tool?"list_progressed":"element_visible",rationale:"verify_ui_state provided a recording-time approved verification selector",primary:n}:e.verify?{required:!0,materialization:"missing_plan",signal_type:"element_visible",rationale:"raw verify evidence exists but recording-time verify plan is missing"}:e.success&&U.has(e.tool)?{required:!0,materialization:"missing_plan",signal_type:"set_text"===e.tool||"input_text"===e.tool?"input_committed":"swipe"===e.tool?"list_progressed":"state_changed",rationale:"state-changing action requires explicit post-action verification for unattended replay"}:{required:!1,materialization:"not_required",signal_type:e.success?"action_completed":"state_changed",rationale:"no post-action verification artifact recorded"}}(e),i=function(e,t){switch(e.tool){case"start_app":{const t=e.package_name;return t?[{path:"permission/set",params:{package_name:t,grant_all:!0}},{path:"activity/start",params:{package_name:t}}]:[]}case"stop_app":{const t=e.package_name;return t?[{path:"activity/stop",params:{package_name:t}}]:[]}case"tap_element":return t?[{path:"accessibility/node",params:L({selector:t.selector,action:"click",action_index:t.action_index,wait_timeout:H})}]:[];case"long_press_element":return t?[{path:"accessibility/node",params:L({selector:t.selector,action:"long_click",action_index:t.action_index,wait_timeout:H})}]:[];case"set_text":return t?[{path:"accessibility/node",params:L({selector:t.selector,action:"set_text",action_index:t.action_index,wait_timeout:H,action_params:e.text?{text:e.text}:void 0})}]:[];case"input_text":return e.text?[{path:"input/text",params:{text:e.text}}]:[];case"press_key":return"number"==typeof e.key_code?[{path:"input/keyevent",params:{key_code:e.key_code}}]:[];case"swipe":return e.swipe?[{path:"input/scroll_bezier",params:e.swipe}]:[];case"tap":return e.tap_position?[{path:"input/click",params:e.tap_position}]:[];case"wait":return"number"==typeof e.wait_duration?[{path:"base/sleep",params:{duration:e.wait_duration}}]:[];default:return[]}}(e,t),r=function(e,t){if("ready"!==e.materialization||!e.primary)return;const n="number"==typeof t&&Number.isFinite(t)&&t>0?Math.max(5e3,Math.trunc(t)):5e3;return{path:"accessibility/node",params:{selector:e.primary.selector,wait_timeout:n},throw_if_empty:["nodes"]}}(n,e.verified_wait_ms_hint||e.wait_ms_hint),o=function(e){const t=[],{record:n,scriptSelector:i,replayActions:r,successCriteria:o}=e;return B.has(n.tool)&&!i&&t.push(`missing_script_selector: ${n.tool} requires a recording-approved script_selector`),Q.has(n.tool)&&0===r.length&&t.push(`missing_replay_action: ${n.tool} has no replay_plan.actions`),o.required&&"ready"!==o.materialization&&t.push(`missing_verification_plan: verification is required but materialization=${o.materialization}`),t}({record:e,scriptSelector:t,replayActions:i,successCriteria:n}),a=F(e.anchor||{},["desc"])||e.search_context||e.step_intent,s=e.screen_desc||F(e.page_anchor||{},["desc"]),c=e.recorded_context?.page_kind||"unknown",l="page_arrived"===n.signal_type?e.verified_page_kind||"unknown":c,p=e.recorded_context?.criticality_hint,d=p||function(e,t){return"wait"===e.tool?"noise":"page_arrived"===t?"critical":e.success?"supporting":"noise"}(e,n.signal_type),u=e.recorded_context?.include_mode_hint,_=u||function(e){return"wait"===e.tool?"log_only":e.success?"main_flow":"log_only"}(e),m=e.step_intent||e.verify_desc||F(e.target||{},["desc"])||e.search_context||`${e.tool} #${e.seq}`,f=e.expected_result_hint||F(e.page_anchor||{},["desc"])||e.screen_desc||e.verify_desc||m,g=(e.intent_merge_key||m).normalize("NFKC").toLowerCase().replace(/[^a-z0-9\u4e00-\u9fa5]+/gu,"_").replace(/^_+|_+$/gu,"")||"step";return{id:`action_${e.seq}`,seq:e.seq,tool:e.tool,success:e.success,error:e.error,page:{before:{kind:c,description:a,anchor:e.anchor_plan||e.anchor},after:e.screen_desc||e.page_anchor?{kind:l,description:s,anchor:e.page_anchor_plan||e.page_anchor||e.verify}:void 0,key_features:V([a,s,e.search_context,F(e.target||{},["desc","text","content_desc"]),F(e.anchor||{},["desc","text","content_desc"])])},intent:{summary:m,purpose:m,expected_result:f,merge_key:g,sources:{expected_result:e.expected_result_hint?"explicit":"derived",merge_key:e.intent_merge_key?"explicit":"derived"}},target:{desc:F(e.target||{},["desc"])||e.search_context,role:e.recorded_context?.target_role||"generic_target",runtime_selector:e.selector,runtime_action_index:e.action_index,runtime_selected_node:e.runtime_selected_node,selector_profile:e.selector_profile,script_selector:t,selector_candidates:Array.isArray(e.selector_profile?.selector_candidates)?e.selector_profile?.selector_candidates:void 0},success_criteria:n,classification:{criticality:d,include_mode:_,step_is_key:"critical"===d,sources:{criticality:p?"explicit":"fallback",include_mode:u?"explicit":"fallback"}},replay_plan:{actions:i,verification:r},diagnostics:{matched_count:e.runtime_matched_count,selector_reusable:t?.reusable},warnings:o.length>0?o:void 0}}),r=i.flatMap(e=>(e.warnings||[]).map(t=>`${e.id}: ${t}`));return{version:"recording-artifact/v2",goal:e,screen:n.screen,design_principle:"Recording artifact already contains approved script selectors, verification plans, merge keys, and replay actions. Script generation must translate, not infer.",actions:i,warnings:r.length>0?r:void 0}}const Z="顶层字段:\n- version: RecordingArtifact 格式版本。\n- goal: 用户最终目标,决定脚本整体意图。\n- screen: 录制时屏幕尺寸,仅用于理解坐标类动作。\n- design_principle: 录制产物的设计原则,提醒你“翻译已有信息,而不是补推未知信息”。\n- warnings: 全局录制质量提醒,不阻塞生成。\n- actions: 已格式化的执行记录数组,按 seq 升序排列。\n\n单条 actions[*] 字段:\n- id: 该条记录的稳定 ID。\n- seq: 原始执行顺序。主流程应尊重这个顺序。\n- tool: 录制时调用的工具名。\n- success: 该次工具调用是否成功。\n- error: 失败时的错误信息;success=true 时通常为 null。\n\n页面上下文 page:\n- page.before: 动作前页面信息。\n- page.after: 动作后页面信息;如果缺失,表示录制时没有拿到可靠的动作后页面证据。\n- page.key_features: 页面关键特征摘要,只用于帮助你理解页面,不用于拼 selector。\n- page.before/after.kind: 粗粒度页面类型,例如 list/detail/dialog。\n- page.before/after.description: 页面自然语言描述,可用于步骤描述。\n- page.before/after.anchor: 录制时的页面锚点证据,可帮助理解页面是否切换。\n\n步骤意图 intent:\n- intent.summary: 最短步骤摘要。优先用于 step description。\n- intent.purpose: 该动作为什么执行。\n- intent.expected_result: 该动作执行后希望达到的结果。\n- intent.merge_key: 邻近动作是否可以合并为同一步的稳定键。\n\n目标与选择器 target:\n- target.desc: 人类可读的目标描述。\n- target.role: 目标元素角色提示。\n- target.runtime_selector: 录制时实际传入的 selector,仅作背景参考,不等于最终脚本批准 selector。\n- target.runtime_action_index: 录制时使用的序号定位。\n- target.runtime_selected_node: 录制时命中的真实节点快照。\n- target.selector_profile: 录制阶段对 selector 质量的分析信息。\n- target.script_selector: 已批准进入脚本的 selector。这是生成主动作时最优先的 selector 来源。\n- target.selector_candidates: 候选 selector 证据,仅用于理解,不用于重新拼接新 selector。\n\n成功判定 success_criteria:\n- success_criteria.required: 该动作理论上是否需要动作后验证。\n- success_criteria.materialization: ready 表示验证动作已可回放;missing_plan 表示需要验证但录制没形成可回放方案;not_required 表示无需验证。\n- success_criteria.signal_type: 该动作成功信号的类型,如 page_arrived / element_visible / state_changed。\n- success_criteria.rationale: 为什么采用这个成功判定策略。\n- success_criteria.primary/fallback: 已批准的验证 selector。只有存在时才能用于生成验证步骤。\n\n流程分类 classification:\n- classification.criticality: 对整体任务的重要程度。\n- classification.include_mode: main_flow / exception_handler_candidate / log_only。\n- classification.step_is_key: 是否是关键里程碑动作。\n\n可回放计划 replay_plan:\n- replay_plan.actions: 已批准的主动作 skeleton。生成主流程时优先直接使用。\n- replay_plan.verification: 已批准的验证动作 skeleton。只有存在时才生成验证。\n\n诊断 diagnostics 与 warnings:\n- diagnostics.matched_count: 录制时 selector 命中的节点数。\n- diagnostics.selector_reusable: selector 是否看起来可复用。\n- warnings: 当前 action 的录制质量提醒,不阻塞生成。\n\n解释原则:\n- null / [] / {} 表示“没录到”或“无可用信息”,直接忽略。\n- 最高可信字段是 replay_plan、target.script_selector、success_criteria.primary/fallback。\n- diagnostics、runtime_selector、runtime_selected_node、selector_candidates 主要用于理解上下文,不用于发明新 selector。",ee='Top-level fields:\n- version: RecordingArtifact schema version.\n- goal: the final user goal that defines the workflow intent.\n- screen: recorded screen size, only for understanding coordinate-based actions.\n- design_principle: the artifact\'s design principle, reminding you to translate known data instead of inventing missing data.\n- warnings: global recording-quality warnings; they do not block generation.\n- actions: formatted execution records sorted by seq.\n\nPer actions[*] record:\n- id: stable record ID.\n- seq: original execution order. The main flow should respect this order.\n- tool: tool name used during recording.\n- success: whether the tool call succeeded.\n- error: failure message when success=false; usually null when success=true.\n\nPage context page:\n- page.before: page information before the action.\n- page.after: page information after the action; if missing, the recorder did not capture reliable post-action page evidence.\n- page.key_features: condensed page features for understanding only, not for building selectors.\n- page.before/after.kind: coarse page type such as list/detail/dialog.\n- page.before/after.description: natural-language page description that can help step descriptions.\n- page.before/after.anchor: recorded page-anchor evidence that helps you understand whether navigation happened.\n\nStep intent intent:\n- intent.summary: shortest step summary. Prefer it for step descriptions.\n- intent.purpose: why the action was executed.\n- intent.expected_result: expected outcome after the action.\n- intent.merge_key: stable key for deciding whether adjacent actions can be merged into one step.\n\nTarget and selector target:\n- target.desc: human-readable target description.\n- target.role: target element role hint.\n- target.runtime_selector: selector used during recording; background reference only, not automatically approved for final script use.\n- target.runtime_action_index: ordinal targeting used during recording.\n- target.runtime_selected_node: actual node snapshot matched during recording.\n- target.selector_profile: selector-quality analysis from recording.\n- target.script_selector: selector explicitly approved for final script use. This is the highest-priority selector source for main actions.\n- target.selector_candidates: candidate-selector evidence for understanding only, not for reconstructing a new selector.\n\nSuccess criteria success_criteria:\n- success_criteria.required: whether this action ideally needs post-action verification.\n- success_criteria.materialization: ready means replayable verification exists; missing_plan means verification is needed but replayable evidence is incomplete; not_required means verification is unnecessary.\n- success_criteria.signal_type: success signal type such as page_arrived / element_visible / state_changed.\n- success_criteria.rationale: why this verification policy was chosen.\n- success_criteria.primary/fallback: approved verification selectors. Use them only when they exist.\n\nFlow classification classification:\n- classification.criticality: importance to the overall task.\n- classification.include_mode: main_flow / exception_handler_candidate / log_only.\n- classification.step_is_key: whether the action is a key milestone.\n\nReplay plan replay_plan:\n- replay_plan.actions: approved main-action skeletons. Use them directly whenever possible.\n- replay_plan.verification: approved verification skeleton. Generate verification only when it exists.\n\nDiagnostics and warnings:\n- diagnostics.matched_count: number of nodes matched by the selector during recording.\n- diagnostics.selector_reusable: whether the selector appears reusable.\n- warnings: action-level recording-quality warnings; they do not block generation.\n\nInterpretation rules:\n- null / [] / {} means "not captured" or "not available", so ignore it.\n- The highest-trust fields are replay_plan, target.script_selector, and success_criteria.primary/fallback.\n- diagnostics, runtime_selector, runtime_selected_node, and selector_candidates are mainly for context understanding, not for inventing new selectors.',te=`你是 Android 无人值守 WorkflowScript 工程师。输入不是原始日志,而是录制阶段已经提纯好的 RecordingArtifact。\n\nRole:\n- 你负责把已有执行记录翻译成稳定、可靠、可无人值守执行的 WorkflowScript。\n\nAction:\n- 基于 RecordingArtifact 生成最终脚本。\n- 优先复用已批准的 replay_plan、script_selector、verification selector。\n- 在信息缺失时继续基于已有记录生成,而不是阻塞或补编未知信息。\n\nContext:\n1. 只消费 RecordingArtifact 中已经批准进入脚本的结构化信息。\n2. 不自行猜 selector,不自行猜页面意图,不自行猜成功判定条件。\n3. 不从 diagnostics、raw desc、候选节点中发明新 selector。\n4. 你的目标是无人值守稳定回放,所以优先选择可回放、可验证、可复用的记录,而不是追求“看起来完整”。\n\nExpectation:\n- 输出纯 JSON WorkflowScript。\n- 主流程顺序清晰,验证闭环尽量完整。\n- 对缺失字段容忍,但绝不凭空补造。\n\n## 输入格式\nRecordingArtifact.actions[*] 已经包含:\n- intent.merge_key: 建议的步骤合并键\n- target.script_selector: 录制阶段批准进入脚本的目标 selector\n- success_criteria.primary: 录制阶段批准的成功判定 selector\n- success_criteria.materialization: 验证条件是否已经具备可回放计划\n- replay_plan.actions: 已经整理好的主动作 skeleton\n- replay_plan.verification: 已经整理好的验证动作 skeleton\n- classification.include_mode: main_flow / exception_handler_candidate / log_only\n- warnings: 录制阶段已经识别出的非阻断缺口(例如缺少可回放 verification_plan)\n- 某些字段可能是 null / [] / {}:这表示录制阶段没有拿到该信息,直接忽略,不要自行补编\n\n## 字段解释\n${Z}\n\n## 无人值守优先级\n1. 可回放性优先于表面完整性。\n2. 有 replay_plan.actions 就优先生成动作;没有就跳过,不补编。\n3. 有 replay_plan.verification 才生成验证;没有就接受该缺口,但不要发明验证。\n4. 有 target.script_selector / success_criteria.primary 才把 selector 写进脚本;没有就不要从其他字段反推。\n5. log_only 默认不进入主流程;exception_handler_candidate 优先转成 exception_handlers。\n\n## 绝对规则\n1. 生成脚本时,优先直接使用 replay_plan.actions;不要自己重建 path/params。\n2. 只要 main_flow 记录存在 replay_plan.verification,就必须在该记录的 replay_plan.actions 之后生成“base/sleep -> 验证动作”的闭环。\n3. base/sleep 的 duration 优先由你根据当前场景生成;若你无法判断,可省略 duration,系统会兜底为 2000ms。\n4. 带 action 的 accessibility/node params.wait_timeout 至少 3000ms;replay_plan.verification 的 params.wait_timeout 优先使用已给值,若你输出时缺失、不合法或低于最小值,系统会对纯校验 accessibility/node 兜底并提升到至少 5000ms。\n5. classification.include_mode="log_only" 的记录默认不进入主流程。\n6. classification.include_mode="exception_handler_candidate" 的记录优先抽成 workflow 顶层 exception_handlers,而不是普通步骤。\n7. selector 只能来自 target.script_selector 或 success_criteria.primary/fallback;禁止从 target.desc、screen_desc、diagnostics 反推。\n8. 不得把 bounds、动态文案、候选节点文本重新拼成新 selector。\n9. 相邻且 merge_key 相同的 main_flow 记录优先合并为同一 step。\n10. 如果 replay_plan.actions 为空,不要编造动作;跳过该记录。\n11. completed 只允许字面量 "success",且仅在 loop.max_count 场景使用。\n12. 如果 RecordingArtifact.warnings 存在,或 action.warnings 非空,继续基于已有 replay_plan 生成,但不要补编缺失的 selector / 验证动作。\n13. 如果 success_criteria.required=true 但 materialization 不是 "ready",视为录制不完整;保留已批准的 replay_plan.actions,但不要发明 replay_plan.verification。\n14. 输出纯 JSON,不要解释。\n\n## 工作流约束\n- 合法 path 仅限:activity/start, permission/set, activity/stop, accessibility/node, input/scroll_bezier, input/text, input/keyevent, input/click, base/sleep\n- accessibility/node 必须带正整数 wait_timeout\n- 带 action 的 accessibility/node wait_timeout 至少 3000ms;纯校验 accessibility/node 至少 5000ms\n- throw_if_empty 只能是 ["nodes"]\n- exception_handlers 只能放在 workflow 顶层\n\n## 输出格式(WorkflowScript)\n你必须输出一个合法的 WorkflowScript JSON,对象结构如下:\n\n\`\`\`json\n{\n "id": "workflow_id",\n "name": "工作流名称",\n "version": "1.0.0",\n "description": "工作流描述",\n "exception_handlers": [\n {\n "name": "handler_name",\n "selector": { "text": "关闭" },\n "action": "click",\n "max_trigger_count": 3\n }\n ],\n "steps": {\n "open_result_detail": {\n "description": "步骤描述",\n "actions": [\n { "path": "accessibility/node", "params": { "selector": { "resource_id": "com.example:id/video_card" }, "action": "click", "action_index": 0, "wait_timeout": 3000 } },\n { "path": "base/sleep", "params": { "duration": 2000 } },\n { "path": "accessibility/node", "params": { "selector": { "resource_id": "com.example:id/detail_title" }, "wait_timeout": 5000 }, "throw_if_empty": ["nodes"] }\n ]\n }\n },\n "flow": ["open_result_detail"]\n}\n\`\`\`\n\n补充约束:\n- \`steps\` 必须是对象,key 为 step id,value 为 step 定义\n- 每个 step 必须有 \`actions\`,且至少 1 个 action\n- \`flow\` 必须按执行顺序列出 step id,且每个 id 都必须存在于 \`steps\`\n- 仅当使用 \`loop.max_count\` 时,才允许 \`completed: "success"\`\n- \`exception_handlers\` 可以是空数组,但每个 handler 都必须满足合法字段结构\n\n## 生成策略\n- 主流程:按 actions 顺序消费 include_mode="main_flow" 的记录\n- 异常处理:从 include_mode="exception_handler_candidate" 中提取\n- 步骤命名:基于 intent.merge_key 生成稳定英文 step id\n- 步骤描述:使用 intent.summary 或 page.before/after.description 组织一句简洁描述\n- 验证:使用 replay_plan.verification,禁止回退到人工推理\n\n输出 pure JSON only.`,ne=`You are an Android unattended WorkflowScript engineer. The input is not a raw log. It is a RecordingArtifact already refined during recording.\n\nRole:\n- Your job is to translate existing execution evidence into a stable, reliable, unattended WorkflowScript.\n\nAction:\n- Generate the final script from RecordingArtifact.\n- Reuse approved replay_plan entries, script selectors, and verification selectors whenever available.\n- If some information is missing, continue from the available evidence instead of blocking or inventing missing data.\n\nContext:\n1. Consume only the structured fields already approved for script generation.\n2. Do not infer selectors, page intent, or success criteria on your own.\n3. Do not invent selectors from diagnostics, raw descriptions, or candidate nodes.\n4. Your objective is unattended replay stability, so prioritize replayability, verifiability, and selector reliability over superficial completeness.\n\nExpectation:\n- Output pure WorkflowScript JSON.\n- Keep the main flow clear and deterministic.\n- Tolerate missing fields, but never fabricate missing evidence.\n\n## Input format\nEach RecordingArtifact.actions[*] already includes:\n- intent.merge_key: suggested step merge key\n- target.script_selector: recording-approved selector for script usage\n- success_criteria.primary: recording-approved verification selector\n- success_criteria.materialization: whether verification is actually ready for replay\n- replay_plan.actions: prebuilt action skeletons\n- replay_plan.verification: prebuilt verification action skeleton\n- classification.include_mode: main_flow / exception_handler_candidate / log_only\n- warnings: recording-time non-blocking gaps (for example missing replayable verification plans)\n- Some fields may be null / [] / {}: that means the recorder did not capture them, so ignore them and do not invent replacements\n\n## Field guide\n${ee}\n\n## Unattended replay priorities\n1. Replayability is more important than superficial completeness.\n2. If replay_plan.actions exists, prefer generating the action from it directly; if not, skip rather than invent.\n3. Generate verification only when replay_plan.verification exists.\n4. Write selectors into the script only when target.script_selector or success_criteria.primary/fallback exists; do not reverse-engineer selectors from lower-trust fields.\n5. log_only normally stays out of main flow; exception_handler_candidate should become exception_handlers first.\n\n## Hard rules\n1. Use replay_plan.actions directly whenever present; do not rebuild action params manually.\n2. Whenever a main_flow record has replay_plan.verification, you must emit a full “base/sleep -> verification” closure after the record's replay_plan.actions.\n3. Prefer generating a scene-specific duration for base/sleep yourself; if you cannot judge the timing, you may omit duration and the system will fall back to 2000ms.\n4. accessibility/node actions with an action param must use wait_timeout of at least 3000ms; for pure verification accessibility/node actions, prefer preserving replay_plan.verification.params.wait_timeout, and if it is missing, invalid, or below the minimum in your output, the system will fall back and clamp it to at least 5000ms.\n5. Records with classification.include_mode="log_only" should normally stay out of the main flow.\n6. Records with classification.include_mode="exception_handler_candidate" should become top-level exception_handlers first, not normal steps.\n7. Selectors may only come from target.script_selector or success_criteria.primary/fallback.\n8. Never reconstruct selectors from bounds, dynamic text, or candidate node text.\n9. Prefer merging adjacent main_flow records with the same merge_key into one step.\n10. If replay_plan.actions is empty, do not fabricate an action. Skip that record.\n11. completed may only be the literal "success", and only for loop.max_count.\n12. If RecordingArtifact.warnings exists or action.warnings is non-empty, continue from the approved replay_plan only; do not fabricate missing selectors or verification actions.\n13. If success_criteria.required=true but materialization is not "ready", treat the recording as incomplete; keep approved replay_plan.actions, but do not invent replay_plan.verification.\n14. Output pure JSON only.\n\n## Workflow constraints\n- Legal paths only: activity/start, permission/set, activity/stop, accessibility/node, input/scroll_bezier, input/text, input/keyevent, input/click, base/sleep\n- accessibility/node requires a positive integer wait_timeout\n- accessibility/node with an action param must use wait_timeout of at least 3000ms; pure verification accessibility/node must use at least 5000ms\n- throw_if_empty must be exactly ["nodes"]\n- exception_handlers are top-level only\n\n## Output format (WorkflowScript)\nYou must output one valid WorkflowScript JSON object with this shape:\n\n\`\`\`json\n{\n "id": "workflow_id",\n "name": "Workflow name",\n "version": "1.0.0",\n "description": "Workflow description",\n "exception_handlers": [\n {\n "name": "handler_name",\n "selector": { "text": "Close" },\n "action": "click",\n "max_trigger_count": 3\n }\n ],\n "steps": {\n "open_result_detail": {\n "description": "Step description",\n "actions": [\n { "path": "accessibility/node", "params": { "selector": { "resource_id": "com.example:id/video_card" }, "action": "click", "action_index": 0, "wait_timeout": 3000 } },\n { "path": "base/sleep", "params": { "duration": 2000 } },\n { "path": "accessibility/node", "params": { "selector": { "resource_id": "com.example:id/detail_title" }, "wait_timeout": 5000 }, "throw_if_empty": ["nodes"] }\n ]\n }\n },\n "flow": ["open_result_detail"]\n}\n\`\`\`\n\nAdditional constraints:\n- \`steps\` must be an object keyed by step id\n- every step must contain \`actions\` with at least one action\n- \`flow\` must list step ids in execution order, and every id must exist in \`steps\`\n- \`completed: "success"\` is only allowed with \`loop.max_count\`\n- \`exception_handlers\` may be an empty array, but every handler must follow the legal field shape\n\n## Generation strategy\n- Main flow: consume records with include_mode="main_flow" in order\n- Exception handling: extract from include_mode="exception_handler_candidate"\n- Step IDs: generate stable English ids from intent.merge_key\n- Step descriptions: use intent.summary or page.before/after.description\n- Verification: use replay_plan.verification only; never fall back to manual inference\n\nOutput pure JSON only.`;function ie(e){return"zh"===e?"你是 Android 自动化需求优化助手。\n\n要求:\n1. 输出语言与输入一致。\n2. 只做表达优化,不新增用户未提及的目标。\n3. 保留次数、顺序、停止条件、应用名和关键文本。\n4. 输出仅保留优化后的最终描述,不要解释。":"You are an Android automation intent refinement assistant.\n\nRequirements:\n1. Keep output language consistent with input.\n2. Improve expression only; do not add new goals not mentioned by user.\n3. Preserve count, order, stop conditions, app names, and key text.\n4. Output only the final refined description without explanations."}function re(e,t=!0){return function(e,t=!0){const n=v(e),i=w(e),r=R[n][i]||R[n].single_flow;return"zh"===n?["你是 Android 自动化任务规划助手。","根据用户目标和当前屏幕,生成可执行、可验证、可收敛的任务计划。",...t?["若缺少规划所需的关键信息,必须暂停并明确提出一个最小问题,禁止编造计划。"]:[],x("全局规则",I),x(`模式规则(${i})`,r),"## 输出 JSON 结构","{",...t?[' "status": "completed | paused(默认 completed)",']:[],' "goal": "string",',' "subtasks": [{"id":1,"description":"string","successCriteria":"string","estimatedActions":["tool"]}],',' "risks": ["string"],',' "assumptions": ["string"],',...t?[' "estimatedSteps": 1,',' "pauseMessage": "string,可选,仅 status=paused 时填写",',' "pauseReason": "string,可选,仅 status=paused 时填写"']:[' "estimatedSteps": 1'],"}"].join("\n\n"):["You are an Android automation planning assistant.","Generate an executable, verifiable, and convergent task plan based on goal and current screen.",...t?["If critical planning information is missing, pause and ask one minimal clarification question instead of inventing a plan."]:[],x("Global Rules",$),x(`Mode Rules (${i})`,r),"## Output JSON Schema","{",...t?[' "status": "completed | paused (default completed)",']:[],' "goal": "string",',' "subtasks": [{"id":1,"description":"string","successCriteria":"string","estimatedActions":["tool"]}],',' "risks": ["string"],',' "assumptions": ["string"],',...t?[' "estimatedSteps": 1,',' "pauseMessage": "string, optional, required when status=paused",',' "pauseReason": "string, optional, required when status=paused"']:[' "estimatedSteps": 1'],"}"].join("\n\n")}(e,t)}function oe(e,t){return function(e,t){const n=v(e),i=w(e),r=q[n][i]||q[n].single_flow;return"zh"===n?["你是 Android 自动化执行 Agent。你的职责是在真实设备上高成功率完成目标。",x("强制层",k.primary),x("建议层",k.secondary),x("核心执行规则",A),x(`任务模式规则(${i})`,r),"## 输出约束","- 优先一次只推进一个可验证子目标;若发生状态变化,必须先完成 wait -> observe_screen -> verify_ui_state 再继续。","- 非必要不输出长文本,优先通过 tool_calls 执行动作。","- 当缺少关键参数或验证证据时,先尝试基于当前界面补齐;确实无法判断时再暂停并明确提问。",O(t,n)].filter(Boolean).join("\n\n"):["You are an Android automation execution agent. Your objective is maximum completion reliability on real devices.",x("Hard Layer",S.primary),x("Suggestion Layer",S.secondary),x("Core Execution Rules",z),x(`Task Mode Rules (${i})`,r),"## Output Constraints","- Advance one verifiable sub-goal at a time; after state changes, complete wait -> observe_screen -> verify_ui_state before continuing.","- Keep text brief unless necessary; prefer tool_calls for actions.","- If critical parameters or verification evidence are missing, first try to repair them from the current screen; pause and ask only when they remain unclear.",O(t,n)].filter(Boolean).join("\n\n")}(e,t)}function ae(e){return function(e){return"zh"===v(e)?te:ne}(e)}function se(e,t,n){return function(e,t,n){const i=v(e),r=(s=X(e,t),{version:s.version,goal:s.goal,screen:s.screen??null,design_principle:s.design_principle,warnings:s.warnings??[],actions:s.actions.map(e=>({id:e.id,seq:e.seq,tool:e.tool,success:e.success,error:e.error??null,page:{before:{kind:e.page.before.kind,description:e.page.before.description??null,anchor:e.page.before.anchor??{}},after:e.page.after?{kind:e.page.after.kind,description:e.page.after.description??null,anchor:e.page.after.anchor??{}}:null,key_features:e.page.key_features??[]},intent:{summary:e.intent.summary,purpose:e.intent.purpose,expected_result:e.intent.expected_result,merge_key:e.intent.merge_key},target:{desc:e.target.desc??null,role:e.target.role,runtime_selector:e.target.runtime_selector??{},runtime_action_index:e.target.runtime_action_index??null,runtime_selected_node:e.target.runtime_selected_node??{},selector_profile:e.target.selector_profile??{},script_selector:e.target.script_selector??null,selector_candidates:e.target.selector_candidates??[]},success_criteria:{required:e.success_criteria.required,materialization:e.success_criteria.materialization,signal_type:e.success_criteria.signal_type,rationale:e.success_criteria.rationale,primary:e.success_criteria.primary??null,fallback:e.success_criteria.fallback??null},classification:{criticality:e.classification.criticality,include_mode:e.classification.include_mode,step_is_key:e.classification.step_is_key},replay_plan:{actions:e.replay_plan.actions??[],verification:e.replay_plan.verification??null},diagnostics:{matched_count:e.diagnostics.matched_count??null,selector_reusable:e.diagnostics.selector_reusable??null},warnings:e.warnings??[]}))}),o="zh"===i?Z:ee,a=[];var s;return r.screen&&a.push(`[Screen]\n${r.screen.width}x${r.screen.height}`),a.push(`[Goal]\n${e}`),a.push(`[RecordingArtifactFieldGuide]\n${o}`),a.push(`[RecordingArtifact]\n${JSON.stringify(r,null,2)}`),n&&a.push(`[PreviousFailure]\n${n}`),a.push("zh"===i?"请将 RecordingArtifact 翻译成最终 WorkflowScript。只使用 replay_plan、target.script_selector、success_criteria。不要自行推导 selector,不要补编未记录动作。遇到 warnings 时继续基于已批准信息生成,但不要发明缺失验证。只输出 WorkflowScript JSON。":"Translate the RecordingArtifact into the final WorkflowScript. Use replay_plan, target.script_selector, and success_criteria only. Do not derive selectors or invent unrecorded actions. When warnings exist, continue from approved data only and do not invent missing verification. Output WorkflowScript JSON only."),a.join("\n\n")}(e,t,n)}const ce=re(""),le=oe(""),pe=ae(""),de=pe.length;l.createHash("sha256").update([ie("zh"),ie("en"),ce,le,pe,String(de)].join("\n\n-----\n\n")).digest("hex");const ue=i.z.object({path:i.z.string().min(1),params:i.z.record(i.z.unknown()).optional(),throw_if_empty:i.z.array(i.z.string()).optional()}),_e=i.z.object({description:i.z.string().optional(),completed:i.z.literal("success").optional(),loop:i.z.union([i.z.object({count:i.z.number().int(),interval:i.z.number().int().optional()}),i.z.object({max_count:i.z.number().int(),interval:i.z.number().int().optional()})]).optional(),actions:i.z.array(ue).min(1)}),me=i.z.object({id:i.z.string().min(1),name:i.z.string().min(1),version:i.z.string().min(1),description:i.z.string().optional(),timeout:i.z.number().int().positive().optional(),exception_handlers:i.z.array(i.z.object({description:i.z.string().optional(),name:i.z.string().optional(),selector:i.z.record(i.z.unknown()),action:i.z.string().min(1),action_params:i.z.record(i.z.unknown()).optional(),max_trigger_count:i.z.number().int().positive().optional()})).optional(),steps:i.z.record(_e),flow:i.z.array(i.z.string()).min(1)}),fe=new Set(["activity/start","permission/set","activity/stop","accessibility/node","input/scroll_bezier","input/text","input/keyevent","input/click","base/sleep"]);function ge(e){return!e||"object"!=typeof e||Array.isArray(e)?null:e}function ye(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function he(e){if("number"==typeof e&&Number.isInteger(e))return e;if("string"==typeof e&&e.trim().length>0){const t=Number(e);if(Number.isFinite(t)&&Number.isInteger(t))return t}return null}function be(e){const t=ge(e.loop);if(!t)return void(ye(e,"completed")&&delete e.completed);const n=(Array.isArray(e.actions)?e.actions:[]).map(e=>ge(e)).filter(e=>!!e);if(ye(t,"count")){return 1===he(t.count)?(delete e.loop,void delete e.completed):void(ye(e,"completed")&&delete e.completed)}if(!ye(t,"max_count"))return;e.completed="success";if(n.some(e=>we(e.throw_if_empty)))return;const i=n.find(e=>{if("accessibility/node"!==e.path)return!1;const t=ge(e.params);return!t||!ye(t,"action")});if(i)return void(i.throw_if_empty=["nodes"]);const r=n.find(e=>"accessibility/node"===e.path);if(r)return void(r.throw_if_empty=["nodes"]);const o=he(t.max_count);if(null!==o){if(1===o)return delete e.loop,void delete e.completed;e.loop={count:o},delete e.completed}}function ve(e){return"number"==typeof e&&Number.isInteger(e)&&e>0}function we(e){return Array.isArray(e)&&1===e.length&&"string"==typeof e[0]&&"nodes"===e[0]}function xe(e,t,n,i){const r=`${e}.actions[${n}]`;if(fe.has(t.path)||i.push(`${r}: illegal path "${t.path}"`),t.throw_if_empty&&!we(t.throw_if_empty)&&i.push(`${r}: throw_if_empty must be exactly ["nodes"]`),"accessibility/node"===t.path){const e=t.params?.wait_timeout;ve(e)||i.push(`${r}: accessibility/node requires positive integer params.wait_timeout`)}if("base/sleep"===t.path){const e=t.params?.duration;ve(e)||i.push(`${r}: base/sleep requires positive integer params.duration`)}}function ke(e,t,n){const i=t.steps[e],r=i.loop,o=i.completed;if(!r)return void(void 0!==o&&n.push(`${e}: steps without loop must not define completed`));if("count"in r)return 1===r.count&&n.push(`${e}: loop.count=1 is forbidden; remove loop`),void(void 0!==o&&n.push(`${e}: count loop must not define completed`));"success"!==o&&n.push(`${e}: max_count loop must define completed="success"`);i.actions.some(e=>we(e.throw_if_empty))||n.push(`${e}: max_count loop requires at least one action with throw_if_empty=["nodes"]`)}function Se(e){const t=[];for(const[n,i]of Object.entries(e.steps)){ke(n,e,t);for(let e=0;e<i.actions.length;e++)xe(n,i.actions[e],e,t)}if(function(e,t){const n=new Set;for(const i of e.flow){const r=e.steps[i];for(let e=0;e<r.actions.length;e++){const o=r.actions[e],a=o.params||{},s=`${i}.actions[${e}]`;if("permission/set"===o.path){const e=a.package_name;if("string"!=typeof e||!e){t.push(`${s}: permission/set requires params.package_name`);continue}!0!==a.grant_all&&t.push(`${s}: permission/set requires params.grant_all=true`),n.add(e)}if("activity/start"===o.path){const e=a.package_name;if("string"!=typeof e||!e){t.push(`${s}: activity/start requires params.package_name`);continue}n.has(e)||t.push(`${s}: missing prior permission/set for package "${e}"`)}}}}(e,t),t.length>0)throw new Error(`workflow semantic validation failed:\n- ${t.join("\n- ")}`)}function Ae(e){const t=function(e){const t=e.steps;if(!t||"object"!=typeof t||Array.isArray(t))return e;const n=e.exception_handlers;if(Array.isArray(n))for(const e of n)if(e&&"object"==typeof e&&!Array.isArray(e)){const t=e;t.action||(t.action="click")}for(const e of Object.values(t)){if(!e||"object"!=typeof e||Array.isArray(e))continue;const t=e,n=t.actions;if(Array.isArray(n)){for(const e of n){if(!e||"object"!=typeof e||Array.isArray(e))continue;const t=e;"wait"===t.path&&(t.path="base/sleep");const n=ge(t.params)||{};if("base/sleep"===t.path){const e=he(n.duration);t.params={...n,duration:null!==e&&e>0?Math.max(2e3,e):2e3}}if("accessibility/node"===t.path){const e="string"==typeof n.action?n.action:void 0,i=he(n.wait_timeout);e&&(null===i||i<=0)?t.params={...n,wait_timeout:3e3}:e&&null!==i&&i>0?t.params={...n,wait_timeout:Math.max(3e3,i)}:!e&&(null===i||i<=0)?t.params={...n,wait_timeout:5e3}:!e&&null!==i&&i>0&&(t.params={...n,wait_timeout:Math.max(5e3,i)})}const i=t.throw_if_empty;Array.isArray(i)&&i.includes("nodes")&&(t.throw_if_empty=["nodes"])}be(t)}}return e}(e),n=me.parse(t),i={...n,id:n.id||`workflow_${Date.now()}`,version:n.version||"1.0.0"};return function(e){for(const t of e.flow)if(!e.steps[t])throw new Error(`missing step referenced in flow: ${t}`)}(i),Se(i),i}function ze(e){const t=e?.message||String(e),n=t.toLowerCase();return n.includes("json")||n.includes("schema")||n.includes("zod")||n.includes("strict")?{category:"STRUCTURE",message:t}:n.includes("missing step")||n.includes("flow")||n.includes("workflow semantic validation")||n.includes("recording artifact has blockers")||n.includes("artifact provenance validation")?{category:"SEMANTIC",message:t}:{category:"UNKNOWN",message:t}}async function qe(i,r,o,a,s){const c=f(o).getModel(),l=Math.max(1,a.scriptGeneration.maxAttempts),p=ae(i),d=e.ChatPromptTemplate.fromMessages([["system","{systemPrompt}"],["human","{userMessage}"]]).pipe(c).pipe(new t.JsonOutputParser).pipe(new n.RunnableLambda({func:e=>Ae(e)})),u=[];let _;for(let e=1;e<=l;e++){const t=se(i,r,_);try{return{workflow:await d.invoke({systemPrompt:p,userMessage:t},{signal:s}),attempts:e,errors:u}}catch(t){const n=ze(t);if(u.push(`[${n.category}] ${n.message}`),_=n.message,e>=l)throw new Error(`script generation failed (maxAttempts=${l}): [${n.category}] ${n.message}`)}}throw new Error(`script generation failed (maxAttempts=${l}): [UNKNOWN] unreachable`)}const Oe={retries:{observation:3,action:2},timeouts:{defaultMs:12e3,observeScreenMs:18e3,startAppMs:25e3},limits:{maxIterations:120,maxConsecutiveFailures:8,maxSameToolFingerprint:3},planner:{maxAttempts:3},scriptGeneration:{maxAttempts:3}};exports.ACCESSIBILITY_NODE_TOOLS=T,exports.DEFAULT_PROVIDER_CONFIG={vendor:"openai",baseUrl:"https://api.openai.com/v1",apiKey:"",model:"gpt-4o-mini"},exports.DEFAULT_RELIABILITY_CONFIG=Oe,exports.POST_VERIFY_HINT_TOOLS=M,exports.PRE_CONTEXT_REQUIRED_TOOLS=E,exports.SELECTOR_ACTION_TOOLS=C,exports.SOFT_VERIFY_ACTIONS=U,exports.TOOL_TIMEOUT_OVERRIDES_MS={observe_screen:"observeScreenMs",start_app:"startAppMs"},exports.VERIFY_COMPLETION_TOOLS=j,exports.VERIFY_REQUIRED_ACTIONS=N,exports.buildAgentSystemPrompt=oe,exports.buildOptimizeIntentPrompt=function(e){return ie(v(e))},exports.buildTaskPlanPrompt=re,exports.createProvider=f,exports.detectPromptLocale=v,exports.generateScript=async function(e,t,n,i){return(await qe(e,t,n,Oe,i)).workflow},exports.generateScriptWithReliability=async function(e,t,n,i,r){return qe(e,t,n,i,r)};