@vmosedge/workflow-agent-sdk 1.0.2 → 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.
- package/dist/chunks/scriptGenerator-CtSwPsED.js +1 -0
- package/dist/chunks/scriptGenerator-D_hIqEQc.cjs +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -1
- package/dist/runtime/index.cjs +1 -1
- package/dist/runtime/index.d.ts +7 -2
- package/dist/runtime/index.js +1 -1
- package/dist/types/index.d.ts +6 -0
- package/package.json +1 -1
- package/dist/chunks/scriptGenerator-CgLLATgN.js +0 -1
- package/dist/chunks/scriptGenerator-DzkshEpz.cjs +0 -1
|
@@ -0,0 +1 @@
|
|
|
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 o}from"@langchain/anthropic";import{coerceMessageLikeToMessage as r}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";function l(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 r({role:"assistant",content:e.content,...t.length>0?{tool_calls:t}:{}})}return"tool"===e.role?r({role:"tool",content:e.content,tool_call_id:e.toolCallId||""}):r({role:e.role,content:e.content})})}function p(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 d(e,t){if("string"!=typeof e||0===e.trim().length)throw new Error(`${t} is required`)}function u(e,t,n){return"anthropic"===e?function(e,t){return new o({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 _{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 d(e.apiKey,"provider.apiKey"),d(e.model,"provider.model"),"anthropic"===t||"google"===t||d(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=u(n,e,t)}getModel(){return this.model}async chatWithTools(e,t,n){const i=l(e),o=p(t),r=o.length>0&&"function"==typeof this.model.bindTools?this.model.bindTools(o):this.model,a=await r.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 d=a.tool_calls||[],u=a.response_metadata&&"object"==typeof a.response_metadata?a.response_metadata:null;return{content:s,toolCalls:d.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=l(e),o="anthropic"===(r=this.vendor)||"google"===r?[{method:"jsonSchema"},{method:"functionCalling"}]:[{method:"jsonSchema",strict:!0},{method:"functionCalling",strict:!0},{method:"jsonMode"}];var r;let a=null;for(const e of o)try{const o=this.model.withStructuredOutput(t,{name:"structured_output",method:e.method,..."boolean"==typeof e.strict?{strict:e.strict}:{}}),r=await o.invoke(i,{signal:n});return t.parse(r)}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 m(e){return new _(e)}const f=/[\u3400-\u9fff]/u,g=[/\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],y=[/直到/u,/等到/u,/出现/u,/找到/u,/\buntil\b/i,/\bwhen\b/i,/\bunless\b/i,/\bappears?\b/i,/\bfound\b/i],h=[/一直/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 b(e){return f.test(e||"")?"zh":"en"}function v(e){const t=e.trim();return t?g.some(e=>e.test(t))?"fixed_count":y.some(e=>e.test(t))?"until_condition":h.some(e=>e.test(t))?"infinite":"single_flow":"single_flow"}function w(e,t){return`## ${e}\n${t.map((e,t)=>`${t+1}. ${e}`).join("\n")}`}const x={primary:["每步前必须有最新 observe_screen / dump 证据,禁止基于过期界面继续执行。","每步后必须完成 success check;优先补齐 observe_screen -> verify_ui_state 再进入下一步。","页面发生变化后必须重新定位,不允许沿用旧页面的 selector 或入口。","必须按 stage 推进:一次只推进一个已验证子目标,不允许无限漂移或脱离当前阶段。","连续失败必须进入恢复分支,优先收敛、重试替代入口或暂停,而不是盲目重复。","高风险动作必须有显式授权,若用户目标未明确授权,不得擅自执行。"],secondary:["selector 优先最小唯一。","优先稳定属性,避免动态 text。","优先语义定位,不行再坐标。","可处理弹窗、广告、权限框。","可根据页面变化自动切换入口。"]},k={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;若当前主流程已明确,也可以继续执行,但要接受录制质量下降。"],S=["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."],$={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 q(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。","若目标存在前置状态依赖,必须先规划“进入前置状态 -> 验证前置状态”,再执行终态动作。","子任务按执行顺序排列,保持最短稳定路径。"],j=["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."],z={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 I=new Set(["start_app","stop_app","tap","tap_element","long_press_element","press_key"]),O=new Set(["verify_ui_state"]),R=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 M=C,T=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"]),W={observe_screen:"observeScreenMs",start_app:"startAppMs"};function E(e){return!e||"object"!=typeof e||Array.isArray(e)?null:e}function D(e){const t={};let n=!1;for(const[i,o]of Object.entries(e))null!=o&&""!==o&&(t[i]=o,n=!0);return n?t:void 0}function P(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 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 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 K(e){const t=E(e);if(t)return D({index:P(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=E(e?.script_selector);if(!t)return;const n=E(t.selector);return n?{selector:n,action_index:P(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=E(e);if(!t)return;const n=F(t,["page_kind"]),i=F(t,["criticality_hint"]),o=F(t,["include_mode_hint"]),r=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"===o||"log_only"===o||"exception_handler_candidate"===o?o:void 0,valid_until:"next_action"===r||"next_verified_transition"===r||"manual_close"===r?r: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 H(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 V=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 o of e){const e=o.toolName,r=E(o.arguments)||{},a=E(o.result.data);if("get_screen_info"===e&&o.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(r,["step_intent"]),merge_key:F(r,["merge_key"]),expected_result:F(r,["expected_result"]),wait_ms_hint:J(r.wait_ms_hint),target_desc:F(r,["target_desc"]),anchor:D(E(r.anchor_element)||{}),anchor_plan:E(a?.anchor_plan)||void 0,target:D(E(r.target_element)||{}),target_plan:E(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=D(E(r.verify_element)||{}),e.verify_desc=F(r,["step_desc"]),e.page_anchor=D(E(r.page_anchor)||{}),e.screen_desc=F(r,["screen_desc"]);const n=F(E(a?.recorded_page)||{},["page_kind"])||F(r,["page_kind"]);e.verified_wait_ms_hint=J(r.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=E(a?.verification_plan)||void 0,e.page_anchor_plan=E(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:o.result.success};o.result.success||"string"!=typeof o.result.error||(s.error=o.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=E(r.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=J(c.wait_ms_hint)||s.wait_ms_hint,s.target=D(E(c.target)||{})||s.target,s.anchor=D(E(c.anchor)||{})||s.anchor,s.recorded_context=Y(s.recorded_context,L(c))),s.selector=D(E(r.selector)||{}),s.action_index=P(r.action_index),"string"==typeof r.text&&(s.text=r.text),"number"==typeof r.key_code&&(s.key_code=r.key_code),"string"==typeof r.package_name&&(s.package_name=r.package_name),"number"==typeof r.duration&&"wait"===e&&(s.wait_duration=r.duration),"number"==typeof r.x&&"number"==typeof r.y&&"tap"===e&&(s.tap_position={x:r.x,y:r.y}),"swipe"===e&&(s.swipe={start_x:Number(r.start_x),start_y:Number(r.start_y),end_x:Number(r.end_x),end_y:Number(r.end_y),duration:"number"==typeof r.duration?r.duration:300});const l=E(a?.runtime_selector_evidence);if(l){const e=D(E(l.requested_selector)||{});!s.selector&&e&&(s.selector=e),s.runtime_selected_node=K(l.selected_node),s.runtime_candidate_nodes=Array.isArray(l.candidate_nodes)?l.candidate_nodes.map(e=>K(e)).filter(e=>!!e):void 0,s.runtime_matched_count="number"==typeof l.matched_count?l.matched_count:void 0,s.selector_profile=E(l.selector_profile)||void 0;const t=P(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:D({selector:t.selector,action:"click",action_index:t.action_index,wait_timeout:B})}]:[];case"long_press_element":return t?[{path:"accessibility/node",params:D({selector:t.selector,action:"long_click",action_index:t.action_index,wait_timeout:B})}]:[];case"set_text":return t?[{path:"accessibility/node",params:D({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),o=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),r=function(e){const t=[],{record:n,scriptSelector:i,replayActions:o,successCriteria:r}=e;return V.has(n.tool)&&!i&&t.push(`missing_script_selector: ${n.tool} requires a recording-approved script_selector`),Q.has(n.tool)&&0===o.length&&t.push(`missing_replay_action: ${n.tool} has no replay_plan.actions`),r.required&&"ready"!==r.materialization&&t.push(`missing_verification_plan: verification is required but materialization=${r.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:H([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:o},diagnostics:{matched_count:e.runtime_matched_count,selector_reusable:t?.reusable},warnings:r.length>0?r:void 0}}),o=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:o.length>0?o: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 hint for naming/grouping steps, but not sufficient on its own to decide merging or loop generation.\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 仅作为 step 分组提示;只有当相邻 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## 循环生成规则(LoopConfig)\nstep 支持 loop 字段实现循环执行,两种模式二选一:\n\n模式一:固定次数循环 \`{ "count": N }\`\n- 执行固定 N 次,不检查 completed。N=-1 表示无限循环(需外部取消)。\n- 禁止 count=1(无意义)或 count=0。\n- 禁止搭配 completed。\n\n模式二:条件循环 \`{ "max_count": N }\` + \`"completed": "success"\`\n- 每次循环后检查 completed 条件(由 throw_if_empty=["nodes"] 的 accessibility/node 驱动),找到目标元素即退出。\n- max_count=-1 表示无限循环直到成功。\n- 必须搭配 completed="success" 和至少一个带 throw_if_empty=["nodes"] 的 accessibility/node 动作。\n\n两种模式均可加 \`"interval": ms\` 指定循环间隔。\n\n### 何时生成循环\n1. 只有当用户目标和录制动作都清楚表达“同一操作需要重复执行”时,才生成 loop;不要仅凭 merge_key 相同就强制抽象成循环。\n2. 如果相邻动作虽然相似,但点击目标、selector、action_index、预期结果或页面语义不同,应保持为展开步骤,不要合并成 loop。\n3. 如果用户目标中包含"刷N个""滑动N次""连续播放"等明确重复意图,用 loop.count=N 或 loop.max_count=N。\n4. 如果目标是"找到某个元素"类的搜索滑动(swipe + 找目标),使用 max_count + completed="success",在 actions 中放置: 滑动动作 → base/sleep → accessibility/node(查找目标, throw_if_empty=["nodes"])。\n5. 如果用户目标含"一直""持续""不断"等无限循环意图,使用 count=-1 或 max_count=-1。\n6. 对不涉及重复的普通步骤,不要添加 loop。\n\n### 循环步骤示例\n\n滑动查找目标(条件循环):\n\`\`\`json\n{\n "scroll_find_target": {\n "description": "向下滑动列表查找目标内容",\n "loop": { "max_count": 10, "interval": 500 },\n "completed": "success",\n "actions": [\n { "path": "input/scroll_bezier", "params": { "start_x": 540, "start_y": 1600, "end_x": 540, "end_y": 600, "duration": 300 } },\n { "path": "base/sleep", "params": { "duration": 1000 } },\n { "path": "accessibility/node", "params": { "selector": { "text": "目标文本" }, "wait_timeout": 5000 }, "throw_if_empty": ["nodes"] }\n ]\n }\n}\n\`\`\`\n\n固定次数滑动浏览:\n\`\`\`json\n{\n "swipe_browse": {\n "description": "连续刷5个视频",\n "loop": { "count": 5, "interval": 2000 },\n "actions": [\n { "path": "input/scroll_bezier", "params": { "start_x": 540, "start_y": 1600, "end_x": 540, "end_y": 400, "duration": 300 } },\n { "path": "base/sleep", "params": { "duration": 1500 } }\n ]\n }\n}\n\`\`\`\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- loop.count 和 loop.max_count 只能是正整数或 -1(无限)\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- **循环决策**:仅当 goal 与录制动作共同表明“同一操作需要重复执行”时,才生成 loop。merge_key 只能作为弱提示,不能单独作为循环依据;若目标元素或语义发生变化,保持为展开步骤。\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. Treat merge_key only as a step-grouping hint; merge adjacent main_flow records into one step only when they truly represent the same reusable step semantics and target pattern.\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## Loop generation rules (LoopConfig)\nSteps support a \`loop\` field for repeated execution. Two mutually exclusive modes:\n\nMode 1: Fixed count loop \`{ "count": N }\`\n- Execute exactly N times without checking completed. N=-1 means infinite loop (requires external cancellation).\n- count=1 and count=0 are forbidden.\n- Must NOT include completed.\n\nMode 2: Conditional loop \`{ "max_count": N }\` + \`"completed": "success"\`\n- After each iteration, check the completed condition (driven by an accessibility/node with throw_if_empty=["nodes"]). Exit early when the target element is found.\n- max_count=-1 means loop infinitely until success.\n- Must include completed="success" and at least one accessibility/node action with throw_if_empty=["nodes"].\n\nBoth modes accept an optional \`"interval": ms\` for loop delay.\n\n### When to generate loops\n1. Generate a loop only when both the user goal and the recorded actions clearly indicate that the same operation should repeat; do not force a loop from merge_key similarity alone.\n2. If adjacent actions look similar but differ in clicked target, selector, action_index, expected outcome, or page semantics, keep them expanded instead of turning them into a loop.\n3. If the user goal contains explicit repetition intent (e.g. "swipe 10 times", "browse 5 videos", "play continuously"), use loop.count=N or loop.max_count=N accordingly.\n4. For search-style swiping (swipe to find a target element), use max_count + completed="success" with actions: swipe → base/sleep → accessibility/node(find target, throw_if_empty=["nodes"]).\n5. If the user goal implies infinite repetition ("keep going", "continuously", "non-stop"), use count=-1 or max_count=-1.\n6. Do not add loop to non-repetitive steps.\n\n### Loop step examples\n\nScroll to find target (conditional loop):\n\`\`\`json\n{\n "scroll_find_target": {\n "description": "Scroll down list to find target content",\n "loop": { "max_count": 10, "interval": 500 },\n "completed": "success",\n "actions": [\n { "path": "input/scroll_bezier", "params": { "start_x": 540, "start_y": 1600, "end_x": 540, "end_y": 600, "duration": 300 } },\n { "path": "base/sleep", "params": { "duration": 1000 } },\n { "path": "accessibility/node", "params": { "selector": { "text": "Target text" }, "wait_timeout": 5000 }, "throw_if_empty": ["nodes"] }\n ]\n }\n}\n\`\`\`\n\nFixed count browse:\n\`\`\`json\n{\n "swipe_browse": {\n "description": "Browse 5 videos by swiping",\n "loop": { "count": 5, "interval": 2000 },\n "actions": [\n { "path": "input/scroll_bezier", "params": { "start_x": 540, "start_y": 1600, "end_x": 540, "end_y": 400, "duration": 300 } },\n { "path": "base/sleep", "params": { "duration": 1500 } }\n ]\n }\n}\n\`\`\`\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- loop.count and loop.max_count must be positive integers or -1 (infinite)\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- **Loop decisions**: generate loop only when the goal and recorded actions clearly describe repeated execution of the same operation. Treat merge_key as a weak hint only; if the target element or semantics changes, keep separate expanded steps.\n\nOutput pure JSON only.`;function ie(e){return"zh"===b(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,t=!0){return function(e,t=!0){const n=b(e),i=v(e),o=z[n][i]||z[n].single_flow;return"zh"===n?["你是 Android 自动化任务规划助手。","根据用户目标和当前屏幕,生成可执行、可验证、可收敛的任务计划。",...t?["若缺少规划所需的关键信息,必须暂停并明确提出一个最小问题,禁止编造计划。"]:[],w("全局规则",N),w(`模式规则(${i})`,o),"## 输出 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."]:[],w("Global Rules",j),w(`Mode Rules (${i})`,o),"## 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 re(e,t){return function(e,t){const n=b(e),i=v(e),o=$[n][i]||$[n].single_flow;return"zh"===n?["你是 Android 自动化执行 Agent。你的职责是在真实设备上高成功率完成目标。",w("强制层",x.primary),w("建议层",x.secondary),w("核心执行规则",A),w(`任务模式规则(${i})`,o),"## 输出约束","- 优先一次只推进一个可验证子目标;若发生状态变化,必须先完成 wait -> observe_screen -> verify_ui_state 再继续。","- 非必要不输出长文本,优先通过 tool_calls 执行动作。","- 当缺少关键参数或验证证据时,先尝试基于当前界面补齐;确实无法判断时再暂停并明确提问。",q(t,n)].filter(Boolean).join("\n\n"):["You are an Android automation execution agent. Your objective is maximum completion reliability on real devices.",w("Hard Layer",k.primary),w("Suggestion Layer",k.secondary),w("Core Execution Rules",S),w(`Task Mode Rules (${i})`,o),"## 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.",q(t,n)].filter(Boolean).join("\n\n")}(e,t)}function ae(e){return function(e){return"zh"===b(e)?te:ne}(e)}function se(e,t,n){return function(e,t,n){const i=b(e),o=(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??[]}))}),r="zh"===i?Z:ee,a=[];var s;return o.screen&&a.push(`[Screen]\n${o.screen.width}x${o.screen.height}`),a.push(`[Goal]\n${e}`),a.push(`[RecordingArtifactFieldGuide]\n${r}`),a.push(`[RecordingArtifact]\n${JSON.stringify(o,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=i.object({path:i.string().min(1),params:i.record(i.unknown()).optional(),throw_if_empty:i.array(i.string()).optional()}),le=i.number().int().refine(e=>-1===e||e>0,{message:"loop count must be a positive integer or -1 (infinite)"}),pe=i.object({description:i.string().optional(),completed:i.literal("success").optional(),loop:i.union([i.object({count:le,interval:i.number().int().min(0).optional()}),i.object({max_count:le,interval:i.number().int().min(0).optional()})]).optional(),actions:i.array(ce).min(1)}),de=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(pe),flow:i.array(i.string()).min(1)}),ue=new Set(["activity/start","permission/set","activity/stop","accessibility/node","input/scroll_bezier","input/text","input/keyevent","input/click","base/sleep"]);function _e(e){return!e||"object"!=typeof e||Array.isArray(e)?null:e}function me(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function fe(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 ge(e){const t=_e(e.loop);if(!t)return void(me(e,"completed")&&delete e.completed);const n=(Array.isArray(e.actions)?e.actions:[]).map(e=>_e(e)).filter(e=>!!e),i=fe(t.interval),o=null!==i&&i>0?{interval:i}:{};if(me(t,"count")){return 1===fe(t.count)?(delete e.loop,void delete e.completed):void(me(e,"completed")&&delete e.completed)}if(!me(t,"max_count"))return;e.completed="success";if(n.some(e=>he(e.throw_if_empty)))return;const r=n.find(e=>{if("accessibility/node"!==e.path)return!1;const t=_e(e.params);return!t||!me(t,"action")});if(r)return void(r.throw_if_empty=["nodes"]);const a=n.find(e=>"accessibility/node"===e.path);if(a)return void(a.throw_if_empty=["nodes"]);const s=fe(t.max_count);if(null!==s){if(1===s)return delete e.loop,void delete e.completed;e.loop={count:s,...o},delete e.completed}}function ye(e){return"number"==typeof e&&Number.isInteger(e)&&e>0}function he(e){return Array.isArray(e)&&1===e.length&&"string"==typeof e[0]&&"nodes"===e[0]}function be(e,t,n,i){const o=`${e}.actions[${n}]`;if(ue.has(t.path)||i.push(`${o}: illegal path "${t.path}"`),t.throw_if_empty&&!he(t.throw_if_empty)&&i.push(`${o}: throw_if_empty must be exactly ["nodes"]`),"accessibility/node"===t.path){const e=t.params?.wait_timeout;ye(e)||i.push(`${o}: accessibility/node requires positive integer params.wait_timeout`)}if("base/sleep"===t.path){const e=t.params?.duration;ye(e)||i.push(`${o}: base/sleep requires positive integer params.duration`)}}function ve(e,t,n){const i=t.steps[e],o=i.loop,r=i.completed;if(!o)return void(void 0!==r&&n.push(`${e}: steps without loop must not define completed`));if("count"in o)return 0!==o.count&&1!==o.count||n.push(`${e}: loop.count=${o.count} is forbidden; remove loop or use count>=2 or -1`),o.count<-1&&n.push(`${e}: loop.count=${o.count} is invalid; use -1 for infinite`),void(void 0!==r&&n.push(`${e}: count loop must not define completed`));"success"!==r&&n.push(`${e}: max_count loop must define completed="success"`);i.actions.some(e=>he(e.throw_if_empty))||n.push(`${e}: max_count loop requires at least one action with throw_if_empty=["nodes"]`)}function we(e){const t=[];for(const[n,i]of Object.entries(e.steps)){ve(n,e,t);for(let e=0;e<i.actions.length;e++)be(n,i.actions[e],e,t)}if(function(e,t){const n=new Set;for(const i of e.flow){const o=e.steps[i];for(let e=0;e<o.actions.length;e++){const r=o.actions[e],a=r.params||{},s=`${i}.actions[${e}]`;if("permission/set"===r.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"===r.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 xe(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=_e(t.params)||{};if("base/sleep"===t.path){const e=fe(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=fe(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"])}ge(t)}}return e}(e),n=de.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),we(i),i}function ke(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 Ae(i,o,r,a,s){const c=m(r).getModel(),l=Math.max(1,a.scriptGeneration.maxAttempts),p=ae(i),d=e.fromMessages([["system","{systemPrompt}"],["human","{userMessage}"]]).pipe(c).pipe(new t).pipe(new n({func:e=>xe(e)})),u=[];let _;for(let e=1;e<=l;e++){const t=se(i,o,_);try{return{workflow:await d.invoke({systemPrompt:p,userMessage:t},{signal:s}),attempts:e,errors:u}}catch(t){const n=ke(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 Se={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 $e(e,t,n,i,o){return Ae(e,t,n,i,o)}async function qe(e,t,n,i){return(await Ae(e,t,n,Se,i)).workflow}export{R as A,Se as D,T as P,C as S,W as T,O as V,$e as a,M as b,m as c,oe as d,b as e,re as f,qe as g,I as h,U as i,ie as j};
|
|
@@ -0,0 +1 @@
|
|
|
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");function l(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 p(e){return a.tool(async()=>"schema-only tool placeholder",{name:e.name,description:e.description,schema:e.schema})}function d(e,t){if("string"!=typeof e||0===e.trim().length)throw new Error(`${t} is required`)}function u(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 _{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 d(e.apiKey,"provider.apiKey"),d(e.model,"provider.model"),"anthropic"===t||"google"===t||d(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=u(n,e,t)}getModel(){return this.model}async chatWithTools(e,t,n){const i=l(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)?p(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 d=a.tool_calls||[],u=a.response_metadata&&"object"==typeof a.response_metadata?a.response_metadata:null;return{content:s,toolCalls:d.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=l(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 m(e){return new _(e)}const f=/[\u3400-\u9fff]/u,g=[/\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],y=[/直到/u,/等到/u,/出现/u,/找到/u,/\buntil\b/i,/\bwhen\b/i,/\bunless\b/i,/\bappears?\b/i,/\bfound\b/i],h=[/一直/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 b(e){return f.test(e||"")?"zh":"en"}function v(e){const t=e.trim();return t?g.some(e=>e.test(t))?"fixed_count":y.some(e=>e.test(t))?"until_condition":h.some(e=>e.test(t))?"infinite":"single_flow":"single_flow"}function w(e,t){return`## ${e}\n${t.map((e,t)=>`${t+1}. ${e}`).join("\n")}`}const x={primary:["每步前必须有最新 observe_screen / dump 证据,禁止基于过期界面继续执行。","每步后必须完成 success check;优先补齐 observe_screen -> verify_ui_state 再进入下一步。","页面发生变化后必须重新定位,不允许沿用旧页面的 selector 或入口。","必须按 stage 推进:一次只推进一个已验证子目标,不允许无限漂移或脱离当前阶段。","连续失败必须进入恢复分支,优先收敛、重试替代入口或暂停,而不是盲目重复。","高风险动作必须有显式授权,若用户目标未明确授权,不得擅自执行。"],secondary:["selector 优先最小唯一。","优先稳定属性,避免动态 text。","优先语义定位,不行再坐标。","可处理弹窗、广告、权限框。","可根据页面变化自动切换入口。"]},k={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;若当前主流程已明确,也可以继续执行,但要接受录制质量下降。"],A=["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."],z={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 q(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。","若目标存在前置状态依赖,必须先规划“进入前置状态 -> 验证前置状态”,再执行终态动作。","子任务按执行顺序排列,保持最短稳定路径。"],N=["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."],O={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 $=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"]),R=new Set(["tap_element","long_press_element","set_text"]);new Set([...R,"verify_ui_state","record_search_context"]);const C=R,E=new Set([...R,"input_text"]),M=new Set(["start_app","stop_app","tap","tap_element","long_press_element","set_text","input_text","swipe","press_key"]);function U(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 P(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 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,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 F(e){const t=U(e);if(t)return L({index:P(t.index),resource_id:D(t,["resource_id","resource-id","resourceId","id"]),text:D(t,["text"]),content_desc:D(t,["content_desc","content-desc","contentDesc"]),class_name:D(t,["class_name","class","className"]),bounds:D(t,["bounds"])})}function J(e){const t=U(e?.script_selector);if(!t)return;const n=U(t.selector);return n?{selector:n,action_index:P(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 G(e){const t=U(e);if(!t)return;const n=D(t,["page_kind"]),i=D(t,["criticality_hint"]),r=D(t,["include_mode_hint"]),o=D(t,["valid_until"]);return{context_id:D(t,["context_id"]),page_kind:"home"===n||"list"===n||"detail"===n||"dialog"===n||"search"===n||"form"===n||"unknown"===n?n:void 0,target_role:D(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 K(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 V=3e3;const H=new Set(["tap_element","long_press_element","set_text"]),B=new Set(["start_app","stop_app","tap_element","long_press_element","set_text","input_text","press_key","swipe","tap","wait"]);function Q(e,t){const n=function(e){const t=[];let n,i=null;for(const r of e){const e=r.toolName,o=U(r.arguments)||{},a=U(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:D(o,["step_intent"]),merge_key:D(o,["merge_key"]),expected_result:D(o,["expected_result"]),wait_ms_hint:W(o.wait_ms_hint),target_desc:D(o,["target_desc"]),anchor:L(U(o.anchor_element)||{}),anchor_plan:U(a?.anchor_plan)||void 0,target:L(U(o.target_element)||{}),target_plan:U(a?.target_plan)||void 0,recorded_context:G(a?.recorded_context)};continue}if("verify_ui_state"===e){const e=t[t.length-1];if(!e)continue;e.verify=L(U(o.verify_element)||{}),e.verify_desc=D(o,["step_desc"]),e.page_anchor=L(U(o.page_anchor)||{}),e.screen_desc=D(o,["screen_desc"]);const n=D(U(a?.recorded_page)||{},["page_kind"])||D(o,["page_kind"]);e.verified_wait_ms_hint=W(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=U(a?.verification_plan)||void 0,e.page_anchor_plan=U(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=U(o.pre_context);c&&(s.step_intent=D(c,["step_intent"])||s.step_intent,s.intent_merge_key=D(c,["merge_key"])||s.intent_merge_key,s.expected_result_hint=D(c,["expected_result"])||s.expected_result_hint,s.wait_ms_hint=W(c.wait_ms_hint)||s.wait_ms_hint,s.target=L(U(c.target)||{})||s.target,s.anchor=L(U(c.anchor)||{})||s.anchor,s.recorded_context=Y(s.recorded_context,G(c))),s.selector=L(U(o.selector)||{}),s.action_index=P(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=U(a?.runtime_selector_evidence);if(l){const e=L(U(l.requested_selector)||{});!s.selector&&e&&(s.selector=e),s.runtime_selected_node=F(l.selected_node),s.runtime_candidate_nodes=Array.isArray(l.candidate_nodes)?l.candidate_nodes.map(e=>F(e)).filter(e=>!!e):void 0,s.runtime_matched_count="number"==typeof l.matched_count?l.matched_count:void 0,s.selector_profile=U(l.selector_profile)||void 0;const t=P(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=J(e.selector_profile),n=function(e){const t=J(e.page_anchor_plan),n=J(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&&M.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:V})}]:[];case"long_press_element":return t?[{path:"accessibility/node",params:L({selector:t.selector,action:"long_click",action_index:t.action_index,wait_timeout:V})}]:[];case"set_text":return t?[{path:"accessibility/node",params:L({selector:t.selector,action:"set_text",action_index:t.action_index,wait_timeout:V,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 H.has(n.tool)&&!i&&t.push(`missing_script_selector: ${n.tool} requires a recording-approved script_selector`),B.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=D(e.anchor||{},["desc"])||e.search_context||e.step_intent,s=e.screen_desc||D(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||D(e.target||{},["desc"])||e.search_context||`${e.tool} #${e.seq}`,f=e.expected_result_hint||D(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:K([a,s,e.search_context,D(e.target||{},["desc","text","content_desc"]),D(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:D(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 X="顶层字段:\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。",Z='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 hint for naming/grouping steps, but not sufficient on its own to decide merging or loop generation.\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.',ee=`你是 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${X}\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 仅作为 step 分组提示;只有当相邻 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## 循环生成规则(LoopConfig)\nstep 支持 loop 字段实现循环执行,两种模式二选一:\n\n模式一:固定次数循环 \`{ "count": N }\`\n- 执行固定 N 次,不检查 completed。N=-1 表示无限循环(需外部取消)。\n- 禁止 count=1(无意义)或 count=0。\n- 禁止搭配 completed。\n\n模式二:条件循环 \`{ "max_count": N }\` + \`"completed": "success"\`\n- 每次循环后检查 completed 条件(由 throw_if_empty=["nodes"] 的 accessibility/node 驱动),找到目标元素即退出。\n- max_count=-1 表示无限循环直到成功。\n- 必须搭配 completed="success" 和至少一个带 throw_if_empty=["nodes"] 的 accessibility/node 动作。\n\n两种模式均可加 \`"interval": ms\` 指定循环间隔。\n\n### 何时生成循环\n1. 只有当用户目标和录制动作都清楚表达“同一操作需要重复执行”时,才生成 loop;不要仅凭 merge_key 相同就强制抽象成循环。\n2. 如果相邻动作虽然相似,但点击目标、selector、action_index、预期结果或页面语义不同,应保持为展开步骤,不要合并成 loop。\n3. 如果用户目标中包含"刷N个""滑动N次""连续播放"等明确重复意图,用 loop.count=N 或 loop.max_count=N。\n4. 如果目标是"找到某个元素"类的搜索滑动(swipe + 找目标),使用 max_count + completed="success",在 actions 中放置: 滑动动作 → base/sleep → accessibility/node(查找目标, throw_if_empty=["nodes"])。\n5. 如果用户目标含"一直""持续""不断"等无限循环意图,使用 count=-1 或 max_count=-1。\n6. 对不涉及重复的普通步骤,不要添加 loop。\n\n### 循环步骤示例\n\n滑动查找目标(条件循环):\n\`\`\`json\n{\n "scroll_find_target": {\n "description": "向下滑动列表查找目标内容",\n "loop": { "max_count": 10, "interval": 500 },\n "completed": "success",\n "actions": [\n { "path": "input/scroll_bezier", "params": { "start_x": 540, "start_y": 1600, "end_x": 540, "end_y": 600, "duration": 300 } },\n { "path": "base/sleep", "params": { "duration": 1000 } },\n { "path": "accessibility/node", "params": { "selector": { "text": "目标文本" }, "wait_timeout": 5000 }, "throw_if_empty": ["nodes"] }\n ]\n }\n}\n\`\`\`\n\n固定次数滑动浏览:\n\`\`\`json\n{\n "swipe_browse": {\n "description": "连续刷5个视频",\n "loop": { "count": 5, "interval": 2000 },\n "actions": [\n { "path": "input/scroll_bezier", "params": { "start_x": 540, "start_y": 1600, "end_x": 540, "end_y": 400, "duration": 300 } },\n { "path": "base/sleep", "params": { "duration": 1500 } }\n ]\n }\n}\n\`\`\`\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- loop.count 和 loop.max_count 只能是正整数或 -1(无限)\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- **循环决策**:仅当 goal 与录制动作共同表明“同一操作需要重复执行”时,才生成 loop。merge_key 只能作为弱提示,不能单独作为循环依据;若目标元素或语义发生变化,保持为展开步骤。\n\n输出 pure JSON only.`,te=`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${Z}\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. Treat merge_key only as a step-grouping hint; merge adjacent main_flow records into one step only when they truly represent the same reusable step semantics and target pattern.\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## Loop generation rules (LoopConfig)\nSteps support a \`loop\` field for repeated execution. Two mutually exclusive modes:\n\nMode 1: Fixed count loop \`{ "count": N }\`\n- Execute exactly N times without checking completed. N=-1 means infinite loop (requires external cancellation).\n- count=1 and count=0 are forbidden.\n- Must NOT include completed.\n\nMode 2: Conditional loop \`{ "max_count": N }\` + \`"completed": "success"\`\n- After each iteration, check the completed condition (driven by an accessibility/node with throw_if_empty=["nodes"]). Exit early when the target element is found.\n- max_count=-1 means loop infinitely until success.\n- Must include completed="success" and at least one accessibility/node action with throw_if_empty=["nodes"].\n\nBoth modes accept an optional \`"interval": ms\` for loop delay.\n\n### When to generate loops\n1. Generate a loop only when both the user goal and the recorded actions clearly indicate that the same operation should repeat; do not force a loop from merge_key similarity alone.\n2. If adjacent actions look similar but differ in clicked target, selector, action_index, expected outcome, or page semantics, keep them expanded instead of turning them into a loop.\n3. If the user goal contains explicit repetition intent (e.g. "swipe 10 times", "browse 5 videos", "play continuously"), use loop.count=N or loop.max_count=N accordingly.\n4. For search-style swiping (swipe to find a target element), use max_count + completed="success" with actions: swipe → base/sleep → accessibility/node(find target, throw_if_empty=["nodes"]).\n5. If the user goal implies infinite repetition ("keep going", "continuously", "non-stop"), use count=-1 or max_count=-1.\n6. Do not add loop to non-repetitive steps.\n\n### Loop step examples\n\nScroll to find target (conditional loop):\n\`\`\`json\n{\n "scroll_find_target": {\n "description": "Scroll down list to find target content",\n "loop": { "max_count": 10, "interval": 500 },\n "completed": "success",\n "actions": [\n { "path": "input/scroll_bezier", "params": { "start_x": 540, "start_y": 1600, "end_x": 540, "end_y": 600, "duration": 300 } },\n { "path": "base/sleep", "params": { "duration": 1000 } },\n { "path": "accessibility/node", "params": { "selector": { "text": "Target text" }, "wait_timeout": 5000 }, "throw_if_empty": ["nodes"] }\n ]\n }\n}\n\`\`\`\n\nFixed count browse:\n\`\`\`json\n{\n "swipe_browse": {\n "description": "Browse 5 videos by swiping",\n "loop": { "count": 5, "interval": 2000 },\n "actions": [\n { "path": "input/scroll_bezier", "params": { "start_x": 540, "start_y": 1600, "end_x": 540, "end_y": 400, "duration": 300 } },\n { "path": "base/sleep", "params": { "duration": 1500 } }\n ]\n }\n}\n\`\`\`\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- loop.count and loop.max_count must be positive integers or -1 (infinite)\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- **Loop decisions**: generate loop only when the goal and recorded actions clearly describe repeated execution of the same operation. Treat merge_key as a weak hint only; if the target element or semantics changes, keep separate expanded steps.\n\nOutput pure JSON only.`;function ne(e){return function(e){return"zh"===b(e)?ee:te}(e)}function ie(e,t,n){return function(e,t,n){const i=b(e),r=(s=Q(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?X:Z,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 re=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()}),oe=i.z.number().int().refine(e=>-1===e||e>0,{message:"loop count must be a positive integer or -1 (infinite)"}),ae=i.z.object({description:i.z.string().optional(),completed:i.z.literal("success").optional(),loop:i.z.union([i.z.object({count:oe,interval:i.z.number().int().min(0).optional()}),i.z.object({max_count:oe,interval:i.z.number().int().min(0).optional()})]).optional(),actions:i.z.array(re).min(1)}),se=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(ae),flow:i.z.array(i.z.string()).min(1)}),ce=new Set(["activity/start","permission/set","activity/stop","accessibility/node","input/scroll_bezier","input/text","input/keyevent","input/click","base/sleep"]);function le(e){return!e||"object"!=typeof e||Array.isArray(e)?null:e}function pe(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function de(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 ue(e){const t=le(e.loop);if(!t)return void(pe(e,"completed")&&delete e.completed);const n=(Array.isArray(e.actions)?e.actions:[]).map(e=>le(e)).filter(e=>!!e),i=de(t.interval),r=null!==i&&i>0?{interval:i}:{};if(pe(t,"count")){return 1===de(t.count)?(delete e.loop,void delete e.completed):void(pe(e,"completed")&&delete e.completed)}if(!pe(t,"max_count"))return;e.completed="success";if(n.some(e=>me(e.throw_if_empty)))return;const o=n.find(e=>{if("accessibility/node"!==e.path)return!1;const t=le(e.params);return!t||!pe(t,"action")});if(o)return void(o.throw_if_empty=["nodes"]);const a=n.find(e=>"accessibility/node"===e.path);if(a)return void(a.throw_if_empty=["nodes"]);const s=de(t.max_count);if(null!==s){if(1===s)return delete e.loop,void delete e.completed;e.loop={count:s,...r},delete e.completed}}function _e(e){return"number"==typeof e&&Number.isInteger(e)&&e>0}function me(e){return Array.isArray(e)&&1===e.length&&"string"==typeof e[0]&&"nodes"===e[0]}function fe(e,t,n,i){const r=`${e}.actions[${n}]`;if(ce.has(t.path)||i.push(`${r}: illegal path "${t.path}"`),t.throw_if_empty&&!me(t.throw_if_empty)&&i.push(`${r}: throw_if_empty must be exactly ["nodes"]`),"accessibility/node"===t.path){const e=t.params?.wait_timeout;_e(e)||i.push(`${r}: accessibility/node requires positive integer params.wait_timeout`)}if("base/sleep"===t.path){const e=t.params?.duration;_e(e)||i.push(`${r}: base/sleep requires positive integer params.duration`)}}function ge(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 0!==r.count&&1!==r.count||n.push(`${e}: loop.count=${r.count} is forbidden; remove loop or use count>=2 or -1`),r.count<-1&&n.push(`${e}: loop.count=${r.count} is invalid; use -1 for infinite`),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=>me(e.throw_if_empty))||n.push(`${e}: max_count loop requires at least one action with throw_if_empty=["nodes"]`)}function ye(e){const t=[];for(const[n,i]of Object.entries(e.steps)){ge(n,e,t);for(let e=0;e<i.actions.length;e++)fe(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 he(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=le(t.params)||{};if("base/sleep"===t.path){const e=de(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=de(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"])}ue(t)}}return e}(e),n=se.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),ye(i),i}function be(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 ve(i,r,o,a,s){const c=m(o).getModel(),l=Math.max(1,a.scriptGeneration.maxAttempts),p=ne(i),d=e.ChatPromptTemplate.fromMessages([["system","{systemPrompt}"],["human","{userMessage}"]]).pipe(c).pipe(new t.JsonOutputParser).pipe(new n.RunnableLambda({func:e=>he(e)})),u=[];let _;for(let e=1;e<=l;e++){const t=ie(i,r,_);try{return{workflow:await d.invoke({systemPrompt:p,userMessage:t},{signal:s}),attempts:e,errors:u}}catch(t){const n=be(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 we={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_RELIABILITY_CONFIG=we,exports.POST_VERIFY_HINT_TOOLS=E,exports.PRE_CONTEXT_REQUIRED_TOOLS=C,exports.SELECTOR_ACTION_TOOLS=R,exports.SOFT_VERIFY_ACTIONS=M,exports.TOOL_TIMEOUT_OVERRIDES_MS={observe_screen:"observeScreenMs",start_app:"startAppMs"},exports.VERIFY_COMPLETION_TOOLS=j,exports.VERIFY_REQUIRED_ACTIONS=$,exports.buildAgentSystemPrompt=function(e,t){return function(e,t){const n=b(e),i=v(e),r=z[n][i]||z[n].single_flow;return"zh"===n?["你是 Android 自动化执行 Agent。你的职责是在真实设备上高成功率完成目标。",w("强制层",x.primary),w("建议层",x.secondary),w("核心执行规则",S),w(`任务模式规则(${i})`,r),"## 输出约束","- 优先一次只推进一个可验证子目标;若发生状态变化,必须先完成 wait -> observe_screen -> verify_ui_state 再继续。","- 非必要不输出长文本,优先通过 tool_calls 执行动作。","- 当缺少关键参数或验证证据时,先尝试基于当前界面补齐;确实无法判断时再暂停并明确提问。",q(t,n)].filter(Boolean).join("\n\n"):["You are an Android automation execution agent. Your objective is maximum completion reliability on real devices.",w("Hard Layer",k.primary),w("Suggestion Layer",k.secondary),w("Core Execution Rules",A),w(`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.",q(t,n)].filter(Boolean).join("\n\n")}(e,t)},exports.buildOptimizeIntentPrompt=function(e){return"zh"===b(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."},exports.buildTaskPlanPrompt=function(e,t=!0){return function(e,t=!0){const n=b(e),i=v(e),r=O[n][i]||O[n].single_flow;return"zh"===n?["你是 Android 自动化任务规划助手。","根据用户目标和当前屏幕,生成可执行、可验证、可收敛的任务计划。",...t?["若缺少规划所需的关键信息,必须暂停并明确提出一个最小问题,禁止编造计划。"]:[],w("全局规则",I),w(`模式规则(${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."]:[],w("Global Rules",N),w(`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)},exports.createProvider=m,exports.detectPromptLocale=b,exports.generateScript=async function(e,t,n,i){return(await ve(e,t,n,we,i)).workflow},exports.generateScriptWithReliability=async function(e,t,n,i,r){return ve(e,t,n,i,r)};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./chunks/scriptGenerator-
|
|
1
|
+
"use strict";var e=require("./chunks/scriptGenerator-D_hIqEQc.cjs");require("@langchain/core/prompts"),require("@langchain/core/output_parsers"),require("@langchain/core/runnables"),require("zod"),require("@langchain/anthropic"),require("@langchain/core/messages"),require("@langchain/core/tools"),require("@langchain/google-genai"),require("@langchain/openai"),exports.generateScript=e.generateScript,exports.generateScriptWithReliability=e.generateScriptWithReliability;
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,12 @@ interface ExceptionHandler {
|
|
|
51
51
|
interface WorkflowStep {
|
|
52
52
|
description?: string;
|
|
53
53
|
completed?: string;
|
|
54
|
+
/**
|
|
55
|
+
* 循环配置,两种模式二选一:
|
|
56
|
+
* - count: 固定次数循环(-1 表示无限循环,需外部取消)
|
|
57
|
+
* - max_count + completed="success": 条件循环(-1 表示无限循环直到成功)
|
|
58
|
+
* - interval: 循环间隔毫秒数,默认 0
|
|
59
|
+
*/
|
|
54
60
|
loop?: {
|
|
55
61
|
count: number;
|
|
56
62
|
interval?: number;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{g as generateScript,a as generateScriptWithReliability}from"./chunks/scriptGenerator-
|
|
1
|
+
export{g as generateScript,a as generateScriptWithReliability}from"./chunks/scriptGenerator-CtSwPsED.js";import"@langchain/core/prompts";import"@langchain/core/output_parsers";import"@langchain/core/runnables";import"zod";import"@langchain/anthropic";import"@langchain/core/messages";import"@langchain/core/tools";import"@langchain/google-genai";import"@langchain/openai";
|