@playword/core
Version:
Supercharge your web test automation experience with AI
409 lines (366 loc) • 53.1 kB
JavaScript
var yt=Object.defineProperty;var Bt=Object.getOwnPropertyDescriptor;var Ht=(e,t)=>{for(var n in t)yt(e,n,{get:t[n],enumerable:!0})};var bt=(e,t,n,a)=>{for(var o=a>1?void 0:a?Bt(t,n):t,r=e.length-1,s;r>=0;r--)(s=e[r])&&(o=(a?s(t,n,o):s(o))||o);return a&&o&&yt(t,n,o),o};import{HumanMessage as te}from"@langchain/core/messages";import{setTimeout as V}from"timers/promises";var R={};Ht(R,{assertElementContains:()=>Y,assertElementContentEquals:()=>X,assertElementContentNotEqual:()=>Q,assertElementNotContain:()=>$,assertElementNotVisible:()=>tt,assertElementVisible:()=>Z,assertPageContains:()=>et,assertPageNotContain:()=>nt,assertPageTitleEquals:()=>at,assertPageUrlMatches:()=>ot,click:()=>it,goto:()=>st,hover:()=>rt,input:()=>ct,pressKeys:()=>lt,scroll:()=>dt,select:()=>pt,sleep:()=>mt,switchFrame:()=>q,switchPage:()=>ut,waitForText:()=>ht});import{setTimeout as Ut}from"timers/promises";var _=(e,t)=>{e.classList.add(t)},xt=async()=>{let e=await caches.keys();await Promise.all(e.map(t=>caches.delete(t)))},vt=async()=>{(await indexedDB.databases()).filter(t=>t.name).map(t=>indexedDB.deleteDatabase(t.name))},At=()=>{localStorage.clear(),sessionStorage.clear()},Ct=async()=>{let e=await navigator.serviceWorker.getRegistrations();await Promise.all(e.map(t=>t.unregister()))},C=e=>{let t=document.querySelectorAll("*:not(head):not(script):not(style)"),n=[],a=r=>{let s=[];for(;r&&r.nodeType==1;r=r.parentNode){let i=1;for(let l=r.previousSibling;l;l=l.previousSibling)l.nodeType===1&&l.nodeName===r.nodeName&&i++;s.unshift(`${r.nodeName.toLowerCase()}[${i}]`)}return"//"+s.join("/")},o=r=>e.includes(r.nodeName.toLowerCase())?r?.checkVisibility?.({checkOpacity:!0,checkVisibilityCSS:!0,contentVisibilityAuto:!0})??!0:!1;for(let r of t){if(!o(r))continue;let s=r.cloneNode(!0);s.innerHTML=[...s.childNodes].filter(i=>i.nodeType===3).map(i=>i.nodeValue).join("").trim(),!(s.outerHTML.length>1e3)&&n.push({html:s.outerHTML,xpath:a(r)})}return n},Et=(e,t)=>e.classList.contains(t),j=(e,t)=>{e.classList.remove(t)},K=(e,{name:t,value:n})=>{t==="value"&&e instanceof HTMLInputElement?e.value=n.toString():n?e.setAttribute(t,n.toString()):e.removeAttribute(t)},Pt=()=>{window.__name=i=>i;let e,t=i=>{i.preventDefault(),i.stopImmediatePropagation()},n=i=>{let l=i.cloneNode(!0),c=[...l.childNodes].filter(d=>d.nodeType===3).map(d=>d.nodeValue),m=[...l.attributes].map(d=>`${d.name}="${d.value}"`),u=i.nodeName.toLowerCase();return{frameSrc:o(),html:`<${u} ${m.join(" ")}>${c.join(" ").trim()}</${u}>`,xpath:a(i)}},a=i=>{let l=[];for(;i&&i.nodeType==1;i=i.parentNode){let c=1;for(let m=i.previousSibling;m;m=m.previousSibling)m.nodeType===1&&m.nodeName===i.nodeName&&c++;l.unshift(`${i.nodeName.toLowerCase()}[${c}]`)}return"//"+l.join("/")},o=()=>{if(window.self===window.top)return;let{origin:i,pathname:l,search:c,hash:m}=new URL(document.location.href);return i+decodeURIComponent(l)+c+m},r=async i=>window.emit({name:"click",params:{...n(i)}}),s=async i=>{let l=["color","date","datetime-local","email","text","month","number","password","range","search","tel","time","url","week"];if(i.value)return l.includes(i.type)||i.nodeName==="TEXTAREA"?window.emit({name:"input",params:{...n(i),text:i.value}}):window.emit({name:"click",params:{...n(i)}})};document.addEventListener("change",i=>{clearTimeout(e);let l=i.target;if(l.nodeName==="SELECT")return window.emit({name:"select",params:{...n(l),option:l.value}});if(l.className==="plwd-input")return window.updateInput(l.value)},!0),document.addEventListener("click",i=>{let l=document.elementFromPoint(i.clientX,i.clientY);clearTimeout(e),l.className.startsWith("plwd")&&l.className!=="plwd-input"&&t(i)},!0),document.addEventListener("keydown",i=>{let l=document.querySelector(".plwd-panel:not(.open)"),{activeElement:c}=document;if(clearTimeout(e),i.key==="Escape")return window.stopDryRun();if(!(c?.className==="plwd-input"||l)){if(t(i),["A","a"].includes(i.key))return window.accept();if(["C","c"].includes(i.key))return window.cancel()}},!0),document.addEventListener("mousedown",i=>{let l=document.elementFromPoint(i.clientX,i.clientY);l.className.startsWith("plwd")&&l.className!=="plwd-input"&&t(i)}),document.addEventListener("mouseleave",i=>{clearTimeout(e),document.querySelector(".plwd-panel.open")&&t(i)},!0),document.addEventListener("mouseout",i=>{clearTimeout(e),document.querySelector(".plwd-panel.open")&&t(i)},!0),document.addEventListener("mouseover",i=>{clearTimeout(e),document.elementFromPoint(i.clientX,i.clientY).nodeName!=="IFRAME"&&(document.querySelector(".plwd-panel.open")&&t(i),e=setTimeout(async()=>{let c=document.elementFromPoint(i.clientX,i.clientY);if(!c.className.startsWith("plwd"))return window.emit({name:"hover",params:{...n(c),duration:1e3}})},3e3))}),document.addEventListener("mouseup",i=>{let l=document.activeElement,c=document.elementFromPoint(i.clientX,i.clientY);if(clearTimeout(e),c.className.startsWith("plwd")&&c.className!=="plwd-input"&&t(i),!(["SELECT","OPTION"].includes(c.nodeName)||!l))return["INPUT","TEXTAREA"].includes(l.nodeName)&&!["INPUT","TEXTAREA"].includes(c.nodeName)&&l.blur(),c.classList.contains("plwd-accept-btn")?window.accept():c.classList.contains("plwd-cancel-btn")?window.cancel():c.classList.contains("plwd-clear-btn")?window.clearAll():c.classList.contains("plwd-delete-btn")?window.deleteStep(parseInt(c.getAttribute("data-index"))):c.classList.contains("plwd-dry-run-btn")?window.dryRun():["INPUT","TEXTAREA"].includes(c.nodeName)?s(c):r(c)})},Tt=e=>{window.addEventListener("load",()=>{let t=document.createElement("style");t.textContent=e,document.body.appendChild(t);let n=document.createElement("div");n.classList.add("plwd-banner"),n.innerText="PlayWord";let a=document.createElement("div");a.classList.add("plwd-loader-box");let o=document.createElement("input");o.classList.add("plwd-input"),o.placeholder="Step Description";let r=document.createElement("button");r.classList.add("plwd-accept-btn"),r.innerText="\u2713 Accept (a)",r.setAttribute("title","Add the step to the test case");let s=document.createElement("button");s.classList.add("plwd-cancel-btn"),s.innerText="\u2715 Cancel (c)",s.setAttribute("title","Undo the step");let i=document.createElement("div");i.classList.add("plwd-input-box"),i.appendChild(o),i.appendChild(a),i.appendChild(s),i.appendChild(r);let l=document.createElement("ul");l.classList.add("plwd-timeline");let c=document.createElement("button");c.classList.add("plwd-dry-run-btn"),c.innerText="Dry Run";let m=document.createElement("button");m.classList.add("plwd-clear-btn"),m.innerText="Clear All";let u=document.createElement("p");u.classList.add("plwd-preview-title"),u.innerText="Test Case Preview";let d=document.createElement("div");d.classList.add("plwd-preview"),d.appendChild(u),d.appendChild(c),d.appendChild(m),d.appendChild(l);let p=document.createElement("div");p.classList.add("plwd-toast-icon");let b=document.createElement("div");b.classList.add("plwd-toast-content");let k=document.createElement("div");k.classList.add("plwd-panel"),k.appendChild(n),k.appendChild(i),k.appendChild(d),document.body.appendChild(k);let N=document.createElement("div");N.classList.add("plwd-toast"),N.appendChild(p),N.appendChild(b),document.body.appendChild(N)})},St=(e,t)=>{let n=a=>{let o=document.createElementNS("http://www.w3.org/2000/svg","path");o.classList.add("plwd-trash-lid"),o.setAttribute("d","M6 15l4 0 0-3 8 0 0 3 4 0 0 2 -16 0zM12 14l4 0 0 1 -4 0z"),o.setAttribute("fill-rule","evenodd");let r=document.createElementNS("http://www.w3.org/2000/svg","path");r.classList.add("plwd-trash-can"),r.setAttribute("d","M8 17h2v9h8v-9h2v9a2 2 0 0 1-2 2h-8a2 2 0 0 1-2-2z");let s=document.createElementNS("http://www.w3.org/2000/svg","svg");s.classList.add("plwd-trash-icon"),s.setAttribute("viewBox","3 6 24 28"),s.appendChild(o),s.appendChild(r);let i=document.createElement("button");return i.classList.add("plwd-delete-btn"),i.setAttribute("data-index",a.toString()),i.appendChild(s),i};e.replaceChildren();for(let[a,o]of t.entries()){let r=n(a),s=document.createElement("li"),i=document.createElement("span"),l=document.createTextNode(o.input);"success"in o.actions[0]&&(i.innerText=o.actions[0].success?"\u2713":"\u2715",i.style.color=o.actions[0].success?"#26a69a":"#f44336"),i.classList.add("plwd-marker"),s.classList.add("plwd-timeline-item"),s.appendChild(i),s.appendChild(l),s.appendChild(r),e.appendChild(s)}},It=e=>{let t=document.querySelector(".plwd-toast-content"),n=document.querySelector(".plwd-toast-icon"),a=document.querySelector(".plwd-toast:not(.open)");t&&n&&a&&(t.innerText=e.content,n.innerText=e.icon,a.style.color=e.color,a.classList.add("open"),setTimeout(()=>a.classList.remove("open"),1900))},Lt=(e,t)=>{if(e.replaceChildren(),!t)return;let n=document.createElement("div");n.classList.add("plwd-loader"),e.appendChild(n)};import Gt from"sanitize-html";var J=new RegExp(/^\[\b(?:ai)\b\]/i),Nt=new RegExp(/^\b(?:are|assert|assure|can|check|compare|confirm|could|did|do|does|ensure|expect|guarantee|has|have|is|match|satisfy|shall|should|test|then|was|were|validate|verify)\b/i),kt=new RegExp(/(?<={)[^{}]+(?=})/g),E=["a","button","div","h1","h2","h3","h4","h5","h6","img","input","label","li","p","select","span","strong","td","textarea","th","ul"];var Ft=`
.plwd-panel {
background: rgba(0, 0, 0, .7);
height: 100%;
opacity: 0;
transition: all .3s;
visibility: hidden;
width: 100%;
}
.plwd-banner {
color: #ffffff !important;
font-size: 32px !important;
font-weight: bold;
left: 4vw;
position: absolute;
top: 6vh;
}
.plwd-input {
background: transparent;
border: none;
border-bottom: 1px solid #ffffff;
color: #ffffff !important;
font-size: 20px !important;
font-weight: bold;
letter-spacing: 2px;
padding: 12px;
width: 90%;
}
.plwd-input[disabled] {
cursor: not-allowed;
opacity: 0.5;
}
.plwd-input-box {
margin: 10% auto 0 auto;
width: 90%;
}
.plwd-timeline {
max-height: 55vh;
overflow-x: hidden;
overflow-y: auto;
padding: 0;
position: relative;
width: 100%;
}
.plwd-preview {
margin: auto;
width: 80%;
text-align: left;
}
.plwd-preview-title {
color: #ffffff !important;
display: inline-block;
float: left;
font-size: 32px !important;
font-weight: bold;
height: 40px;
line-height: 40px;
margin: 0;
visibility: hidden;
}
.plwd-panel {
display: block;
left: 0;
position: fixed;
text-align: center;
top: 50%;
transform: translateY(-50%);
z-index: 2147483647;
}
.plwd-toast {
background: #333333;
border-radius: 25px;
bottom: 30px;
font-size: 24px !important;
font-weight: bold;
height: 50px;
left: 0;
line-height: 50px;
margin: auto;
position: fixed;
right: 0;
text-align: center;
visibility: hidden;
width: 50px;
z-index: 2147483647;
}
.plwd-toast-icon {
float: left;
width: 50px;
}
.plwd-toast-content {
overflow: hidden;
white-space: nowrap;
}
.plwd-toast.open {
animation: fade-in 0.5s, expand 0.5s 0.5s, stay 0.5s 1s, fade-out 0.5s 1.5s;
visibility: visible;
}
.plwd-input:focus {
outline: none;
}
.plwd-input::placeholder {
color: #ffffff !important;
font-size: 20px !important;
opacity: 0.4;
padding: 12px;
}
.plwd-loader-box {
display: inline-block;
height: 20px;
width: 20px;
}
.plwd-accept-btn {
border-radius: 25px;
color: #4db6ac !important;
font-size: 20px !important;
height: 45px;
line-height: 45px;
margin: 8px;
width: 150px;
}
.plwd-cancel-btn {
border-radius: 25px;
color: #e0e0e0 !important;
font-size: 20px !important;
height: 45px;
line-height: 45px;
margin: 8px;
width: 150px;
}
.plwd-dry-run-btn {
border-radius: 25px;
color: #e5c07b !important;
float: right;
font-size: 20px !important;
height: 40px;
line-height: 40px;
width: 100px;
visibility: hidden;
}
.plwd-clear-btn {
border-radius: 25px;
color: #e0e0e0 !important;
float: right;
font-size: 20px !important;
height: 40px;
line-height: 40px;
width: 100px;
visibility: hidden;
}
.plwd-delete-btn {
border-radius: 25px;
color: #ff6c6c !important;
height: 40px;
line-height: 40px;
margin: 0 8px;
width: 80px;
}
.plwd-accept-btn, .plwd-cancel-btn, .plwd-dry-run-btn, .plwd-clear-btn, .plwd-delete-btn {
background: transparent;
border: none;
box-sizing: border-box;
cursor: pointer;
font-weight: bold;
outline: none;
overflow: hidden;
position: relative;
text-align: center;
vertical-align: middle;
}
.plwd-accept-btn::before,
.plwd-cancel-btn::before,
.plwd-dry-run-btn::before,
.plwd-clear-btn::before,
.plwd-delete-btn::before {
background: currentColor;
bottom: 0;
content: '';
left: 0;
opacity: 0;
position: absolute;
right: 0;
top: 0;
transition: opacity .3s;
}
.plwd-accept-btn::after,
.plwd-cancel-btn::after,
.plwd-dry-run-btn::after,
.plwd-clear-btn::after,
.plwd-delete-btn::after {
background: currentColor;
border-radius: 25px;
content: '';
height: 6vh;
left: 50%;
opacity: 0;
padding: 50%;
position: absolute;
transform: translate(-50%, -50%) scale(1);
transition: opacity 1s, transform .5s;
}
.plwd-accept-btn:hover::before,
.plwd-cancel-btn:hover::before,
.plwd-dry-run-btn:hover::before,
.plwd-clear-btn:hover::before,
.plwd-delete-btn:hover::before {
opacity: .1;
}
.plwd-accept-btn:active::after,
.plwd-cancel-btn:active::after,
.plwd-dry-run-btn:active::after,
.plwd-clear-btn:active::after,
.plwd-delete-btn:active::after {
opacity: .2;
transform: translate(-50%, -50%) scale(0);
transition: transform 0s;
}
.plwd-panel.open, .plwd-preview-title.open, .plwd-dry-run-btn.open, .plwd-clear-btn.open {
opacity: 1;
visibility: visible;
}
.plwd-loader {
animation: loading .75s infinite linear;
border-bottom: 4px solid rgba(255, 255, 255, .5);
border-left: 4px solid rgba(255, 255, 255, .5);
border-right: 4px solid rgba(255, 255, 255, .5);
border-top: 4px solid rgba(255, 255, 255, 1);
border-radius: 100%;
height: inherit;
width: inherit;
}
.plwd-marker {
font-size: 16px !important;
font-weight: bold;
padding: 0 16px;
}
.plwd-timeline-item {
animation: draw-border 1s;
color: #ffffff !important;
content-visibility: auto;
border-color: #26a69a;
border-style: solid;
border-width: 2px;
border-right-width: 0px;
border-top-width: 0px;
font-size: 24px !important;
height: 100px;
line-height: 100px;
list-style-type: none;
overflow-x: auto;
overflow-y: hidden;
padding: 0 16px;
position: relative;
text-align: left;
white-space: nowrap;
width: 100%;
}
.plwd-timeline-item:last-child {
border-bottom: none;
}
.plwd-delete-btn::before {
background: currentColor;
bottom: 0;
content: '';
left: 0;
opacity: 0;
position: absolute;
right: 0;
top: 0;
transition: opacity .3s;
}
.plwd-trash-icon {
fill: #ff6c6c;
height: 40px;
width: 40%;
}
.plwd-trash-lid {
transform-origin: right bottom;
transition: transform .2s cubic-bezier(0.4, 0.0, 0.2, 1);
}
.plwd-delete-btn:hover .plwd-trash-lid {
transform: translateY(-1px) rotate(10deg);
}
@keyframes expand {
from {
min-width: 50px;
}
to {
min-width: 250px;
}
}
@keyframes fade-in {
from {
bottom: 0;
opacity: 0;
}
to {
bottom: 30px;
opacity: 1;
}
}
@keyframes stay {
from {
min-width: 250px;
}
to {
min-width: 250px;
}
}
@keyframes fade-out {
from {
bottom: 30px;
min-width: 250px;
opacity: 1;
}
to {
bottom: 45px;
min-width: 250px;
opacity: 0;
}
}
@keyframes draw-border {
0% {
max-height: 0;
width: 0;
}
30% {
max-height: 100px;
width: 0;
}
100% {
max-height: 100px;
width: 100%;
}
}
@keyframes loading {
from {
transform: rotate(0deg);
}
to {
transform: rotate(359deg);
}
}
`,P=e=>Gt(e,{allowedAttributes:{"*":["aria*","class","data*","href","id","name","placeholder","title","type","value"]},allowedStyles:{"*":{"*":[]}},allowedTags:E});var h=(e,t="none",n=!1)=>{if(process.env.PLWD_DEBUG!=="true")return;let a={green:32,magenta:35,red:31};return n&&console.log("-".repeat(process.stdout.columns)),console.log(t==="none"?e:`\x1B[${a[t]}m${e}\x1B[0m`)};var A=async(e,t={})=>{if(e.frame=void 0,t.frameSrc&&await Kt(e,t.frameSrc)){let a=e.page?.frames().find(o=>o.url()===t.frameSrc);e.frame=a}let n=e.frame||e.page;return await n.waitForLoadState("domcontentloaded"),n},L=e=>{let t=e.match(kt);return t&&process.env[t[0]]||e},Kt=async(e,t,n=3e4)=>{let a=Date.now(),o=!1;for(;!o&&Date.now()-a<n;)o=!!e.page?.frames().some(r=>r.url()===t),await Ut(500);return o},Y=async(e,t)=>{try{let a=(await A(e,t)).locator(t.xpath).first(),o=L(t.text);return await a.waitFor({state:"visible",timeout:5e3}),!!(await a.textContent())?.includes(o)}catch{return!1}},$=async(e,t)=>{try{let a=(await A(e,t)).locator(t.xpath).first(),o=L(t.text);return await a.waitFor({state:"visible",timeout:5e3}),!(await a.textContent())?.includes(o)||!1}catch{return!1}},X=async(e,t)=>{try{let a=(await A(e,t)).locator(t.xpath).first(),o=L(t.text);return await a.waitFor({state:"visible",timeout:5e3}),(await a.textContent())?.trim()===o.trim()}catch{return!1}},Q=async(e,t)=>{try{let a=(await A(e,t)).locator(t.xpath).first(),o=L(t.text);return await a.waitFor({state:"visible",timeout:5e3}),(await a.textContent())?.trim()!==o.trim()}catch{return!1}},Z=async(e,t)=>{try{return await(await A(e,t)).locator(t.xpath).first().waitFor({state:"visible",timeout:5e3}),!0}catch{return!1}},tt=async(e,t)=>{try{return await(await A(e,t)).locator(t.xpath).first().waitFor({state:"hidden",timeout:5e3}),!0}catch{return!1}},et=async(e,t)=>{try{let n=await A(e,t),a=L(t.text),o=await n.getByText(a).all();return(await Promise.all(o.map(s=>s.isVisible()))).some(Boolean)}catch{return!1}},nt=async(e,t)=>{try{let n=await A(e,t),a=L(t.text),o=await n.getByText(a).all();return!(await Promise.all(o.map(s=>s.isVisible()))).some(Boolean)}catch{return!1}},at=async(e,t)=>{try{let n=L(t.text);return await e.page?.title()===n}catch{return!1}},ot=async(e,t)=>{try{let n=e.page.url();return new RegExp(t.pattern).test(n)}catch{return!1}},it=async(e,t)=>{try{let a=(await A(e,t)).locator(t.xpath).first();return await a.waitFor({state:"visible",timeout:5e3}),await a.click({timeout:5e3}),"Performed the click action"}catch{return"Failed to perform the action"}},st=async(e,t)=>{try{return await e.page?.goto(t.url),"Navigated to "+t.url}catch{return"Failed to perform the action"}},rt=async(e,t)=>{try{let a=(await A(e,t)).locator(t.xpath).first();return await a.waitFor({state:"visible",timeout:5e3}),await a.hover({timeout:5e3}),t.duration&&await e.page?.waitForTimeout(t.duration),"Performed the hover action"}catch{return"Failed to perform the action"}},ct=async(e,t)=>{try{let a=(await A(e,t)).locator(t.xpath).first(),o=L(t.text);return await a.waitFor({state:"visible",timeout:5e3}),await a.fill(o,{timeout:5e3}),"Performed the input action"}catch{return"Failed to perform the action"}},lt=async(e,t)=>{try{return await e.page?.keyboard.press(t.keys),"Pressed keys "+t.keys}catch{return"Failed to perform the action"}},dt=async(e,t)=>{try{let n=await A(e,t);switch(t.direction){case"up":return await n.evaluate(()=>window.scrollBy({top:window.innerHeight})),"scrolled up";case"down":return await n.evaluate(()=>window.scrollBy({top:window.innerHeight})),"scrolled down";case"top":return await n.evaluate(()=>window.scrollTo({top:0})),"scrolled to top";case"bottom":return await n.evaluate(()=>window.scrollTo({top:document.body.scrollHeight})),"scrolled to bottom";default:return`Unsupported scroll target ${t.direction}`}}catch{return"Failed to perform the action"}},pt=async(e,t)=>{try{let a=(await A(e,t)).locator(t.xpath).first();return await a.waitFor({state:"visible",timeout:5e3}),await a.selectOption({value:t.option},{timeout:5e3}),"Performed the select action"}catch{return"Failed to perform the action"}},mt=async(e,t)=>{try{return await e.page?.waitForTimeout(t.duration),"Slept for "+t.duration+" milliseconds"}catch{return"Failed to perform the action"}},q=async(e,t)=>{try{return e.frame=void 0,t.frameNumber!==void 0&&(e.frame=e.page?.frames()[t.frameNumber]),"Switched to frame"}catch{return"Failed to perform the action"}},ut=async(e,t)=>{try{return e.page=e.context.pages()[t.pageNumber||0],"Switched to page"}catch{return"Failed to perform the action"}},ht=async(e,t)=>{try{let n=await A(e,t),a=L(t.text);return await n.waitForSelector("text="+a,{state:"visible",timeout:3e4}),"Waited for text: "+a}catch{return"Failed to perform the action"}};import{access as Jt,mkdir as Yt,readFile as $t,writeFile as Xt}from"fs/promises";import{dirname as Qt}from"path";var D=class{constructor(t=""){this.recordPath=t}position=0;recordings=[];check=async t=>{try{return await Jt(t),t.endsWith(".json")}catch{return!1}};removeProperty=(t,n)=>{if(!(!t||typeof t!="object")){if(Array.isArray(t))return t.forEach(a=>this.removeProperty(a,n));for(let a of Object.keys(t))a===n?delete t[a]:this.removeProperty(t[a],n)}};addAction(t){this.recordings[this.position].actions.push(t)}clear(){this.recordings=[],this.position=0}count(){return this.recordings.length}delete(t){t<0||t>=this.recordings.length||(this.recordings.splice(t,1),this.position>=t&&this.position--,this.position<0&&(this.position=0))}initStep(t,n){this.position=t,this.recordings[t]={input:n,actions:[]}}list(){return this.recordings}async load(){await this.check(this.recordPath)&&(this.recordings=JSON.parse(await $t(this.recordPath,"utf-8")))}async save(t=[]){let n=structuredClone(this.recordings.slice(0,this.position+1));for(let a of t)this.removeProperty(n,a);await Yt(Qt(this.recordPath),{recursive:!0}),await Xt(this.recordPath,JSON.stringify(n,null,2))}};import{tool as S}from"@langchain/core/tools";import{z as y}from"zod";var ft=[S(async({keywords:e,text:t},{configurable:n})=>{let{ref:a}=n,{ai:o,input:r,page:s,recorder:i}=a,c=(await s.evaluate(C,E)).map(({html:p,xpath:b})=>({html:P(p),xpath:b}));h("Embedding the snapshot..."),await o.embedTexts(c.map(({html:p})=>p)),h("Snapshot embedded.");let m=await o.searchDocuments(e),u=await o.getBestCandidate(r,m),{xpath:d}=c.find(({html:p})=>p===m[u].pageContent);return i?.addAction({name:"assertElementContains",params:{text:t,xpath:d}}),await Y(a,{text:t,xpath:d})?"PASS: Element contains text: "+t:"FAIL: Element does not contain text: "+t},{name:"AssertElementContains",description:"Call to verify that an element contains specific text",schema:y.object({keywords:y.string().describe("Keywords for searching the relevant element from user input"),text:y.string().describe("The text to verify on the element")})}),S(async({keywords:e,text:t},{configurable:n})=>{let{ref:a}=n,{ai:o,input:r,page:s,recorder:i}=a,c=(await s.evaluate(C,E)).map(({html:p,xpath:b})=>({html:P(p),xpath:b}));h("Embedding the snapshot..."),await o.embedTexts(c.map(({html:p})=>p)),h("Snapshot embedded.");let m=await o.searchDocuments(e),u=await o.getBestCandidate(r,m),{xpath:d}=c.find(({html:p})=>p===m[u].pageContent);return i?.addAction({name:"assertElementNotContain",params:{text:t,xpath:d}}),await $(a,{text:t,xpath:d})?"PASS: Element does not contain text: "+t:"FAIL: Element contains text: "+t},{name:"AssertElementNotContain",description:"Call to verify that an element does not contain specific text",schema:y.object({keywords:y.string().describe("Keywords for searching the relevant element from user input"),text:y.string().describe("The text to verify on the element")})}),S(async({keywords:e,text:t},{configurable:n})=>{let{ref:a}=n,{ai:o,input:r,page:s,recorder:i}=a,c=(await s.evaluate(C,E)).map(({html:p,xpath:b})=>({html:P(p),xpath:b}));h("Embedding the snapshot..."),await o.embedTexts(c.map(({html:p})=>p)),h("Snapshot embedded.");let m=await o.searchDocuments(e),u=await o.getBestCandidate(r,m),{xpath:d}=c.find(({html:p})=>p===m[u].pageContent);return i?.addAction({name:"assertElementContentEquals",params:{xpath:d,text:t}}),await X(a,{xpath:d,text:t})?"PASS: Element content is equal to: "+t:"FAIL: Element content is not equal to: "+t},{name:"AssertElementContentEquals",description:"Call to verify that an element has specific text",schema:y.object({keywords:y.string().describe("Keywords for searching the relevant element from user input"),text:y.string().describe("The text to verify on the element")})}),S(async({keywords:e,text:t},{configurable:n})=>{let{ref:a}=n,{ai:o,input:r,page:s,recorder:i}=a,c=(await s.evaluate(C,E)).map(({html:p,xpath:b})=>({html:P(p),xpath:b}));h("Embedding the snapshot..."),await o.embedTexts(c.map(({html:p})=>p)),h("Snapshot embedded.");let m=await o.searchDocuments(e),u=await o.getBestCandidate(r,m),{xpath:d}=c.find(({html:p})=>p===m[u].pageContent);return i?.addAction({name:"assertElementContentNotEqual",params:{xpath:d,text:t}}),await Q(a,{xpath:d,text:t})?"PASS: Element content is not equal to: "+t:"FAIL: Element content is equal to: "+t},{name:"AssertElementContentNotEqual",description:"Call to verify that an element does not have specific text",schema:y.object({keywords:y.string().describe("Keywords for searching the relevant element from user input"),text:y.string().describe("The text to verify on the element")})}),S(async({keywords:e},{configurable:t})=>{let{ref:n}=t,{ai:a,input:o,page:r,recorder:s}=n,l=(await r.evaluate(C,E)).map(({html:d,xpath:p})=>({html:P(d),xpath:p}));h("Embedding the snapshot..."),await a.embedTexts(l.map(({html:d})=>d)),h("Snapshot embedded.");let c=await a.searchDocuments(e),m=await a.getBestCandidate(o,c),{xpath:u}=l.find(({html:d})=>d===c[m].pageContent);return s?.addAction({name:"assertElementVisible",params:{xpath:u}}),await Z(n,{xpath:u})?"PASS: Element is visible":"FAIL: Element is invisible"},{name:"AssertElementVisible",description:"Call to verify that an element is visible",schema:y.object({keywords:y.string().describe("Keywords for searching the relevant element from user input")})}),S(async({keywords:e},{configurable:t})=>{let{ref:n}=t,{ai:a,input:o,page:r,recorder:s}=n,l=(await r.evaluate(C,E)).map(({html:d,xpath:p})=>({html:P(d),xpath:p}));h("Embedding the snapshot..."),await a.embedTexts(l.map(({html:d})=>d)),h("Snapshot embedded.");let c=await a.searchDocuments(e),m=await a.getBestCandidate(o,c),{xpath:u}=l.find(({html:d})=>d===c[m].pageContent);return s?.addAction({name:"assertElementNotVisible",params:{xpath:u}}),await tt(n,{xpath:u})?"PASS: Element is invisible":"FAIL: Element is visible"},{name:"AssertElementNotVisible",description:"Call to verify that an element is not visible",schema:y.object({keywords:y.string().describe("Keywords for searching the relevant element from user input")})}),S(async({text:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"assertPageContains",params:{text:e}}),await et(n,{text:e})?"PASS: Page contains text: "+e:"FAIL: Page does not contain text: "+e},{name:"AssertPageContains",description:"Call to verify that the page contains specific text",schema:y.object({text:y.string().describe("The text to verify on the page")})}),S(async({text:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"assertPageNotContain",params:{text:e}}),await nt(n,{text:e})?"PASS: Page does not contain text: "+e:"FAIL: Page contains text: "+e},{name:"AssertPageNotContain",description:"Call to verify that the page does not contain specific text",schema:y.object({text:y.string().describe("The text to verify on the page")})}),S(async({text:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"assertPageTitleContains",params:{text:e}}),await at(n,{text:e})?"PASS: Page title is equal to: "+e:"FAIL: Page title is not equal to: "+e},{name:"AssertPageTitleEquals",description:"Call to verify that the page title is equal to specific text",schema:y.object({text:y.string().describe("The text to verify on the page title")})}),S(async({pattern:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"assertPageTitleMatches",params:{pattern:e}}),await ot(n,{pattern:e})?"PASS: Page URL matches the pattern: "+e:"FAIL: Page URL does not match the pattern: "+e},{name:"AssertPageUrlMatches",description:"Call to verify that the page URL matches a specific pattern",schema:y.object({pattern:y.string().describe("The pattern to verify on the page URL")})})];import{tool as v}from"@langchain/core/tools";import{z as f}from"zod";var gt=[v(async({text:e},{configurable:t})=>JSON.stringify({name:"assertElementContains",params:{...t.action.params,text:e}}),{name:"AssertElementContains",description:"Call to verify that an element contains specific text",schema:f.object({text:f.string().describe("The text to verify")})}),v(async({text:e},{configurable:t})=>JSON.stringify({name:"assertElementNotContain",params:{...t.action.params,text:e}}),{name:"AssertElementNotContain",description:"Call to verify that an element does not contain specific text",schema:f.object({text:f.string().describe("The text to verify")})}),v(async({text:e},{configurable:t})=>JSON.stringify({name:"assertElementContentEquals",params:{...t.action.params,text:e}}),{name:"AssertElementContentEquals",description:"Call to verify that an element has specific text",schema:f.object({text:f.string().describe("The text to verify")})}),v(async({text:e},{configurable:t})=>JSON.stringify({name:"assertElementContentNotEqual",params:{...t.action.params,text:e}}),{name:"AssertElementContentNotEqual",description:"Call to verify that an element does not have specific text",schema:f.object({text:f.string().describe("The text to verify")})}),v(async(e,{configurable:t})=>JSON.stringify({name:"assertElementVisible",params:t.action.params}),{name:"AssertElementVisible",description:"Call to verify that an element is visible"}),v(async(e,{configurable:t})=>JSON.stringify({name:"assertElementNotVisible",params:t.action.params}),{name:"AssertElementNotVisible",description:"Call to verify that an element is not visible"}),v(async({text:e})=>JSON.stringify({name:"assertPageContains",params:{text:e}}),{name:"AssertPageContains",description:"Call to verify that the page contains specific text",schema:f.object({text:f.string().describe("The text to verify")})}),v(async({text:e})=>JSON.stringify({name:"assertPageNotContain",params:{text:e}}),{name:"AssertPageNotContain",description:"Call to verify that the page does not contain specific text",schema:f.object({text:f.string().describe("The text to verify")})}),v(async({text:e})=>JSON.stringify({name:"assertPageTitleEquals",params:{text:e}}),{name:"AssertPageTitleEquals",description:"Call to verify that the page title equals specific text",schema:f.object({text:f.string().describe("The text to verify")})}),v(async({pattern:e})=>JSON.stringify({name:"assertPageUrlMatches",params:{pattern:e}}),{name:"AssertPageUrlMatches",description:"Call to verify that the page URL matches a specific pattern",schema:f.object({pattern:f.string().describe("The pattern to match")})}),v(async(e,{configurable:t})=>JSON.stringify({name:"click",params:t.action.params}),{name:"Click",description:"Call to handle the click event"}),v(async({url:e})=>JSON.stringify({name:"goto",params:{url:e}}),{name:"GoTo",description:"Call to handle the navigation event",schema:f.object({url:f.string().describe("The URL to navigate to")})}),v(async({duration:e},{configurable:t})=>JSON.stringify({name:"hover",params:{...t.action.params,duration:e}}),{name:"Hover",description:"Call to handle the hover event",schema:f.object({duration:f.number().describe("How long the hover event should last. Default is 1000ms")})}),v(async({text:e},{configurable:t})=>JSON.stringify({name:"input",params:{text:e,...t.action.params}}),{name:"Input",description:"Call to handle the input event",schema:f.object({text:f.string().describe("The text to input")})}),v(async({direction:e},{configurable:t})=>JSON.stringify({name:"scroll",params:{...t.action.params,direction:e}}),{name:"Scroll",description:"Call to handle the scroll event",schema:f.object({direction:f.enum(["up","down","top","bottom"]).describe("The direction to scroll")})}),v(async({option:e},{configurable:t})=>JSON.stringify({name:"select",params:{option:e,...t.action.params}}),{name:"Select",description:"Call to handle the select event",schema:f.object({option:f.string().describe("The option to select")})}),v(async({duration:e})=>JSON.stringify({name:"sleep",params:{duration:e}}),{name:"Sleep",description:"Call to handle the sleep event",schema:f.object({duration:f.number().describe("The duration to sleep in milliseconds")})}),v(async({text:e})=>JSON.stringify({name:"waitForText",params:{text:e}}),{name:"WaitForText",description:"Call to handle the wait for text event",schema:f.object({text:f.string().describe("The text to wait for")})})];import{Document as Zt}from"@langchain/core/documents";import{tool as T}from"@langchain/core/tools";import{z as w}from"zod";var wt=[T(async({keywords:e},{configurable:t})=>{let{ref:n}=t,{ai:a,input:o,page:r,recorder:s}=n,l=(await r.evaluate(C,E)).map(({html:d,xpath:p})=>({html:P(d),xpath:p}));h("Embedding the snapshot..."),await a.embedTexts(l.map(({html:d})=>d)),h("Snapshot embedded.");let c=await a.searchDocuments(e),m=await a.getBestCandidate(o,c),{xpath:u}=l.find(({html:d})=>d===c[m].pageContent);return s?.addAction({name:"click",params:{xpath:u}}),it(n,{xpath:u})},{name:"Click",description:"Call to click on an element",schema:w.object({keywords:w.string().describe("Keywords for searching the relevant element from user input")})}),T(async({url:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"goto",params:{url:e}}),st(n,{url:e})},{name:"GoTo",description:"Call to go to a specific URL",schema:w.object({url:w.string().describe("The URL to navigate to")})}),T(async({duration:e,keywords:t},{configurable:n})=>{let{ref:a}=n,{ai:o,input:r,page:s,recorder:i}=a,c=(await s.evaluate(C,E)).map(({html:p,xpath:b})=>({html:P(p),xpath:b}));h("Embedding the snapshot..."),await o.embedTexts(c.map(({html:p})=>p)),h("Snapshot embedded.");let m=await o.searchDocuments(t),u=await o.getBestCandidate(r,m),{xpath:d}=c.find(({html:p})=>p===m[u].pageContent);return i?.addAction({name:"hover",params:{duration:e,xpath:d}}),rt(a,{duration:e,xpath:d})},{name:"Hover",description:"Call to hover over an element",schema:w.object({duration:w.number().describe("The duration to hover over the element. Default is 1000ms"),keywords:w.string().describe("Keywords for searching the relevant element from user input")})}),T(async({keywords:e,text:t},{configurable:n})=>{let{ref:a}=n,{ai:o,input:r,page:s,recorder:i}=a,c=(await s.evaluate(C,["input","textarea"])).map(({html:p,xpath:b})=>({html:P(p),xpath:b}));h("Embedding the snapshot..."),await o.embedTexts(c.map(({html:p})=>p)),h("Snapshot embedded.");let m=await o.searchDocuments(e),u=await o.getBestCandidate(r,m),{xpath:d}=c.find(({html:p})=>p===m[u].pageContent);return i?.addAction({name:"input",params:{text:t,xpath:d}}),ct(a,{text:t,xpath:d})},{name:"Input",description:"Call to type text into the input field or textarea",schema:w.object({keywords:w.string().describe("Keywords for searching the relevant element from user input"),text:w.string().describe("Text to input")})}),T(async({keys:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"pressKeys",params:{keys:e}}),lt(n,{keys:e})},{name:"PressKeys",description:"Call to press a key or keys",schema:w.object({keys:w.string().describe("Keys to press. The format should match the Playwright API")})}),T(async({direction:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"scroll",params:{direction:e}}),dt(n,{direction:e})},{name:"Scroll",description:"Call to scroll the page",schema:w.object({direction:w.enum(["top","bottom","up","down"]).describe("The direction to scroll")})}),T(async({keywords:e,option:t},{configurable:n})=>{let{ref:a}=n,{ai:o,input:r,page:s,recorder:i}=a,c=(await s.evaluate(C,["select"])).map(({html:p,xpath:b})=>({html:P(p),xpath:b}));h("Embedding the snapshot..."),await o.embedTexts(c.map(({html:p})=>p)),h("Snapshot embedded.");let m=await o.searchDocuments(e),u=await o.getBestCandidate(r,m),{xpath:d}=c.find(({html:p})=>p===m[u].pageContent);return i?.addAction({name:"select",params:{option:t,xpath:d}}),pt(a,{option:t,xpath:d})},{name:"Select",description:"Call to select an option from a select element",schema:w.object({keywords:w.string().describe("Keywords for searching the relevant element from user input"),option:w.string().describe("The option to select")})}),T(async({duration:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"sleep",params:{duration:e}}),mt(n,{duration:e})},{name:"Sleep",description:"Call to wait for a certain amount of time",schema:w.object({duration:w.number().describe("The duration to wait in milliseconds")})}),T(async({enterFrame:e},{configurable:t})=>{let{ref:n}=t,{ai:a,input:o,page:r,recorder:s}=n,i=r?.frames().map(l=>JSON.stringify({name:l.name(),url:l.url()}));if(e&&i?.length){let l=i.map(m=>new Zt({pageContent:m})),c=await a.getBestCandidate(o,l);return s?.addAction({name:"switchFrame",params:{frameNumber:c}}),q(n,{frameNumber:c})}return s?.addAction({name:"switchFrame",params:{}}),q(n,{})},{name:"SwitchFrame",description:"Call to switch, enter or return to a frame",schema:w.object({enterFrame:w.boolean().describe("Return true to enter the frame, false to return to the main page")})}),T(async({pageNumber:e},{configurable:t})=>{let{ref:n}=t;return ut(n,{pageNumber:e})},{name:"SwitchPage",description:"Call to switch to a different page or tab",schema:w.object({pageNumber:w.number().describe("The index of the page to switch to. Starts from 0")})}),T(async({text:e},{configurable:t})=>{let{ref:n}=t;return n.recorder?.addAction({name:"waitForText",params:{text:e}}),ht(n,{text:e})},{name:"WaitForText",description:"Call to wait for text to appear on the page",schema:w.object({text:w.string().describe("Text to wait for")})})];var Ot=class{constructor(t,{delay:n=250,recordPath:a=".playword/recordings.json"}={}){this.playword=t;this.delay=Math.abs(n),this.recorder=new D(a),this.playword.recorder=void 0,this.observe=this.observe.bind(this)}action={name:"",params:{}};delay;input="";recorder;state={dryRunning:!1,waitingForAI:!1,waitingForUserAction:!1};ai(){return this.playword.ai}context(){return this.playword.context}page(){return this.playword.page}async setPageListeners(){let t=async()=>{this.state.waitingForAI||(await Promise.all([l(),d("Accepted","\u2713","#4db6ac")]),this.recorder.initStep(this.recorder.count(),this.input),this.recorder.addAction(this.action),await this.recorder.save(["html","success"]),this.state.waitingForUserAction=!1)},n=async()=>{this.state.waitingForAI||(this.state.waitingForUserAction=!1)},a=async()=>{this.recorder.clear(),await Promise.all([this.recorder.save(),b()])},o=async()=>{await Promise.all([u(".plwd-preview-title").evaluate(j,"open"),u(".plwd-clear-btn").evaluate(j,"open"),u(".plwd-dry-run-btn").evaluate(j,"open"),u(".plwd-panel").evaluate(j,"open")])},r=async g=>{this.recorder.delete(g),await Promise.all([this.recorder.save(["html","success"]),b()])},s=async g=>{G(""),await Promise.all([N(),F(!0)]);let x=await this.ai().summarizeAction(JSON.stringify(g));G(x),await Promise.all([N(),F(!1)])},i=async()=>{h("Starting the dry run process...","green",!0),this.state.dryRunning=!0,this.state.waitingForUserAction=!1,await Promise.all([d("Dry Run","\u{1F680}","#e5c07b"),k()]);for(let g of this.recorder.list())if(this.state.dryRunning){let x=g.actions[0],I=await R[x.name](this.playword,x.params);x.success=!!(I!=="Failed to perform the action"&&I),h((x.success?"PASS: ":"FAIL: ")+g.input),await V(this.delay)}await d("Completed","\u{1F680}","#e5c07b"),this.state.dryRunning=!1,h("Dry Run Completed")},l=async()=>{await F(!0);let{tool_calls:g}=await this.ai().useTools(gt,[new te(this.input)]);if(!g||!g.length)return F(!1);let x=gt.find(U=>U.name===g[0].name);if(!x)return F(!1);let{content:I}=await x.invoke(g[0],{configurable:{action:this.action}});return I&&(this.action=JSON.parse(I),h("Input: "+this.input+`
Action: `+JSON.stringify(this.action,null,2),"green",!0)),F(!1)},c=async g=>{if(!(this.state.dryRunning||this.state.waitingForAI||this.state.waitingForUserAction)){for(this.action=g,this.state.waitingForUserAction=!0,await V(500),s(g);this.state.waitingForUserAction;)await m()||await Promise.all([p(),b(),N()]),await V(200);await o()}},m=async()=>u(".plwd-panel").evaluate(Et,"open"),u=g=>this.page().locator(g).first(),d=async(g,x,I)=>{await this.page().evaluate(It,{content:g,icon:x,color:I})},p=async()=>{await u(".plwd-panel").evaluate(_,"open")},b=async()=>{this.recorder.count()>0&&await Promise.all([u(".plwd-preview-title").evaluate(_,"open"),u(".plwd-clear-btn").evaluate(_,"open"),u(".plwd-dry-run-btn").evaluate(_,"open")]),await u(".plwd-timeline").evaluate(St,this.recorder.list())},k=async()=>{let g=()=>this.page().evaluate(xt),x=()=>this.context().clearCookies(),I=()=>this.page().evaluate(vt),U=()=>this.page().evaluate(At),Vt=()=>this.page().evaluate(Ct);await Promise.all([g(),x(),I(),Vt(),U()]),await V(2e3);for(let zt of this.context().pages())await zt.close();await this.context().newPage()},N=async()=>{await u(".plwd-input").evaluate(K,{name:"value",value:this.input})},qt=()=>{this.state.dryRunning=!1},G=g=>{this.input=g},F=async g=>{await Promise.all([u(".plwd-input").evaluate(K,{name:"disabled",value:g}),u(".plwd-loader-box").evaluate(Lt,g)]),this.state.waitingForAI=g};this.page().on("framenavigated",g=>{let x=g.url();if(!(x==="about:blank"||x!==this.page().mainFrame().url()))return c({name:"goto",params:{url:x}})}),await Promise.all([this.page().addInitScript(Pt),this.page().addInitScript(Tt,Ft)]),await Promise.all([this.page().exposeFunction("accept",t),this.page().exposeFunction("cancel",n),this.page().exposeFunction("clearAll",a),this.page().exposeFunction("deleteStep",r),this.page().exposeFunction("dryRun",i),this.page().exposeFunction("emit",c),this.page().exposeFunction("notify",d),this.page().exposeFunction("stopDryRun",qt),this.page().exposeFunction("updateInput",G)])}async observe(){this.context().on("page",async()=>{await this.setPageListeners(),await this.page().reload()}),await this.recorder.load()}};import{HumanMessage as Te}from"@langchain/core/messages";import{randomUUID as Se}from"crypto";import{setTimeout as Ie}from"timers/promises";import{AIMessage as ee}from"@langchain/core/messages";import{Annotation as Dt,MemorySaver as ne,StateGraph as ae,messagesStateReducer as oe}from"@langchain/langgraph";import{ToolNode as Mt}from"@langchain/langgraph/prebuilt";var ie=Dt.Root({messages:Dt({reducer:oe})}),se=async({messages:e},{configurable:t})=>{let{ai:n}=t?.ref;return{messages:[await n.useTools(ft,e)]}},re=async({messages:e},{configurable:t})=>{let{ai:n}=t?.ref;return{messages:[await n.useTools(wt,e)]}},ce=async({messages:e},{configurable:t})=>{let{ai:n}=t?.ref,a=e[e.length-1].content.toString(),o=await n.parseResult(e);return h(`${a} => ${o}`),{messages:[new ee(o.toString())]}},le=async({messages:e})=>{let t=e[e.length-1];return Nt.test(t.content.toString())?"assert":"page"},de=({messages:e})=>{let{tool_calls:t}=e[e.length-1];return t&&t.length>0?"assertionTools":"result"},pe=({messages:e})=>{let{tool_calls:t}=e[e.length-1];return t&&t.length>0?"pageTools":"__end__"},_t=new ae(ie).addNode("assert",se).addNode("page",re).addNode("result",ce).addNode("assertionTools",new Mt(ft)).addNode("pageTools",new Mt(wt)).addConditionalEdges("__start__",le,["page","assert"]).addConditionalEdges("assert",de,["assertionTools","result"]).addConditionalEdges("page",pe,["pageTools","__end__"]).addEdge("assertionTools","assert").addEdge("pageTools","page").addEdge("result","__end__").compile({checkpointer:new ne});import{ChatAnthropic as ge}from"@langchain/anthropic";import{SystemMessage as we}from"@langchain/core/messages";import{ChatGoogleGenerativeAI as ye,GoogleGenerativeAIEmbeddings as be}from"@langchain/google-genai";import{ChatOpenAI as xe,OpenAIEmbeddings as ve}from"@langchain/openai";import{z as M}from"zod";import{getEnvironmentVariable as me}from"@langchain/core/utils/env";import{Embeddings as ue}from"@langchain/core/embeddings";import{chunkArray as he}from"@langchain/core/utils/chunk_array";var z=class extends ue{apiKey;headers={"Content-Type":"application/json"};batchSize;endpoint;inputType;model;outputDimension;outputDtype;truncation;constructor(t){if(super({...t}),this.apiKey=t?.apiKey||me("VOYAGEAI_API_KEY"),this.batchSize=t?.batchSize??8,this.endpoint=t?.endpoint??"https://api.voyageai.com/v1/embeddings",this.inputType=t?.inputType,this.model=t?.model??"voyage-3",this.outputDimension=t?.outputDimension,this.outputDtype=t?.outputDtype??"float",this.truncation=t?.truncation??!0,!this.apiKey)throw new Error("Voyage AI API key not found")}async embedDocuments(t){let a=he(t,this.batchSize).map(s=>{let i={input:s,input_type:this.inputType,model:this.model,output_dimension:this.outputDimension,output_dtype:this.outputDtype,truncation:this.truncation};return this.useVoyageAPI(i)});return(await Promise.all(a)).flatMap(({data:s})=>s.map(({embedding:i})=>i))}async embedQuery(t){let n={input:t,input_type:this.inputType,model:this.model,output_dimension:this.outputDimension,output_dtype:this.outputDtype,truncation:this.truncation};return(await this.useVoyageAPI(n)).data[0].embedding}async useVoyageAPI(t){return this.caller.call(async()=>{let n={body:JSON.stringify(t),headers:{Authorization:"Bearer "+this.apiKey,...this.headers},method:"POST"};return await(await fetch(this.endpoint,n)).json()})}};import{Document as jt}from"@langchain/core/documents";import{VectorStore as fe}from"@langchain/core/vectorstores";var W=class e extends fe{vectors=[];constructor(t){super(t,{})}_vectorstoreType(){return"memory"}static async fromDocuments(t,n){let a=new e(n);return await a.addDocuments(t),a}static async fromTexts(t,n){let a=t.filter(o=>o).map(o=>new jt({pageContent:o}));return this.fromDocuments(a,n)}async _queryVectors(t,n){return this.vectors.map(({content:a,embedding:o},r)=>({index:r,content:a,embedding:o,similarity:this.cosine(t,o)})).sort((a,o)=>a.similarity>o.similarity?-1:0).slice(0,n)}cosine(t,n){let[a,o,r]=[0,0,0];for(let s=0;s<t.length;s++)a+=t[s]*n[s],o+=t[s]*t[s],r+=n[s]*n[s];return a/(Math.sqrt(o)*Math.sqrt(r))}async addDocuments(t){let n=t.map(({pageContent:a})=>a);return this.addVectors(await this.embeddings.embedDocuments(n),t)}async addVectors(t,n){let a=t.map((o,r)=>({content:n[r].pageContent,embedding:o}));this.vectors.push(...a)}async similaritySearchVectorWithScore(t,n){return(await this._queryVectors(t,n)).map(o=>[new jt({pageContent:o.content}),o.similarity])}};var Ae=`Your goal is to find the most relevant element that user mentioned in the input from the list of elements provided.
When you find the element you believe to be the best match, return the index of that element.`,Ce=`Determine if the AI response is passed on the user's input.
Return true if the AI believes the assertion passes, false otherwise.`,Ee=`I will provide a JSON string that contains an action's name and its associated params.
Each JSON string represents a single test step within a test case.
Your tasks are as follows:
1. Action Summary:
- Objective: Create a concise summary of the action described in the JSON.
- Guidelines:
- The summary should be brief, clear, and accurately reflect the intent of the action.
- The action in the summary should not be changed to a different action.
- If the action is performed on a password field, avoid including the actual password in the summary.
- If the action is a navigation step, the summary should be "Navigate to [URL]."
2. HTML Element Simplification:
- Objective: When the params include details about an HTML element, present the element's information without using attributes that are random, dynamic, or difficult to interpret.
- Guidelines:
- Exclude: Attributes that are likely to change frequently (e.g., dynamically generated IDs, timestamps or session-specific data).
- Include:
- Static and meaningful attributes that clearly identify or describe the element (e.g., class, id with meaningful names, data-* attributes relevant to the test).
- If the element has text content, prioritize including the text content in the description.`,Pe=`Choose ONE appropriate tool to perform the action without asking the users any questions.
You should not call multiple tools.
If any unexpected error occurs, you should retry the call with different parameters from the previous attempt as much as possible, with a maximum of five retries.
If any failure occurs, you should return the error message without retrying.`,B=class{llm;store;constructor(t={}){let n,a;if("googleApiKey"in t||process.env.GOOGLE_API_KEY){let o=t.googleApiKey??process.env.GOOGLE_API_KEY;n=new be({apiKey:o,model:"text-embedding-004"}),a=new ye({...t,apiKey:o,model:t.model??"gemini-2.0-flash-lite"})}if(("openAIApiKey"in t||process.env.OPENAI_API_KEY)&&(n=new ve({...t,configuration:t,model:"text-embedding-3-small"}),a=new xe({...t,configuration:t,model:t.model??"gpt-4o-mini"})),("anthropicApiKey"in t||process.env.ANTHROPIC_API_KEY)&&(a=new ge({...t,clientOptions:t,model:t.model??"claude-3-5-haiku-latest"})),"voyageAIApiKey"in t||process.env.VOYAGEAI_API_KEY){let o=t.voyageAIApiKey||process.env