agentiqa 1.0.3-staging.84bf502 → 1.0.3-staging.fc14e19
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/cli.js +9 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1330,6 +1330,13 @@ ${JSON.stringify({status:y,error:v,summary:`${g?"Interrupted":d?"Timed out":"Fai
|
|
|
1330
1330
|
window.__aqObserver = {
|
|
1331
1331
|
reset() { startObserver(); events.length = 0; t0 = Date.now(); lastY = window.scrollY; },
|
|
1332
1332
|
flush() { startObserver(); const r = events.splice(0); t0 = Date.now(); lastY = window.scrollY; return r; },
|
|
1333
|
+
peek() {
|
|
1334
|
+
let lastAt = 0;
|
|
1335
|
+
for (let i = 0; i < events.length; i++) {
|
|
1336
|
+
if (events[i].t > lastAt) lastAt = events[i].t;
|
|
1337
|
+
}
|
|
1338
|
+
return { count: events.length, lastAt: lastAt };
|
|
1339
|
+
},
|
|
1333
1340
|
};
|
|
1334
1341
|
|
|
1335
1342
|
startObserver();
|
|
@@ -1339,7 +1346,7 @@ ${JSON.stringify({status:y,error:v,summary:`${g?"Interrupted":d?"Timed out":"Fai
|
|
|
1339
1346
|
setTimeout(startObserver, 0);
|
|
1340
1347
|
}
|
|
1341
1348
|
})();
|
|
1342
|
-
`,Ji=new WeakMap,Pr=class{static script(){return nf}static async install(e){try{await e.evaluate(nf)}catch{}}static async reset(e){Ji.delete(e);try{await e.evaluate(()=>{window.__aqObserver?.reset()})}catch{}}static async flush(e){try{let t=await e.evaluate(()=>window.__aqObserver?.flush()??[]),n=Ji.get(e)??[],s=MI(t,n),o=t.filter(c=>c.type==="add"),a=t.filter(c=>c.type==="remove"),i=o.filter(c=>!a.find(l=>l.text===c.text&&l.role===c.role));return Ji.set(e,i),s}catch{return null}}};function MI(r,e=[]){if(r.length===0&&e.length===0)return null;let t=[],n=r.filter(a=>a.type==="add"),s=r.filter(a=>a.type==="remove");for(let a of n){let i=s.find(c=>c.text===a.text&&c.role===a.role);i&&t.push(`\u26A1 transient: "${a.text}" (role=${a.role}, appeared T+${(a.t/1e3).toFixed(1)}s, lasted ${i.t-a.t}ms)`)}for(let a of e){let i=s.find(l=>l.text===a.text&&l.role===a.role),c=n.find(l=>l.text===a.text&&l.role===a.role);i&&!c&&t.push(`\u26A1 transient: "${a.text}" (role=${a.role}, appeared in previous screenshot, now gone)`)}let o=r.filter(a=>a.type==="scroll").reduce((a,i)=>a+i.dy,0);Math.abs(o)>10&&t.push(`\u2195 scroll: ${o>0?"+":""}${o}px`);for(let a of r)a.type==="hash"&&t.push(`# hash: #${a.from} \u2192 #${a.to}`),a.type==="nav"&&t.push(`\u2192 nav: ${a.url}`);return t.length===0?null:`[Between screenshots]
|
|
1349
|
+
`,Ji=new WeakMap,Pr=class{static script(){return nf}static async install(e){try{await e.evaluate(nf)}catch{}}static async reset(e){Ji.delete(e);try{await e.evaluate(()=>{window.__aqObserver?.reset()})}catch{}}static async flush(e){try{let t=await e.evaluate(()=>window.__aqObserver?.flush()??[]),n=Ji.get(e)??[],s=MI(t,n),o=t.filter(c=>c.type==="add"),a=t.filter(c=>c.type==="remove"),i=o.filter(c=>!a.find(l=>l.text===c.text&&l.role===c.role));return Ji.set(e,i),s}catch{return null}}static async waitForQuiescence(e,t={}){let n=t.minQuietMs??100,s=t.maxMs??800;try{return await e.evaluate(async({minQuietMs:o,maxMs:a})=>{let i=window.__aqObserver;if(!i)return{kind:"quiet",quiescedAfterMs:0};let c=Date.now(),l=i.peek(),u=l.lastAt,f=l.count>0?Date.now():0;return await new Promise(g=>{let p=()=>{let h=Date.now(),d=h-c,y=i.peek();y.lastAt>u&&(u=y.lastAt,f=h);let v=y.count>0;if(v&&h-f>=o){g({kind:"settled",quiescedAfterMs:d});return}if(d>=a){g(v?{kind:"timeout",quiescedAfterMs:d}:{kind:"quiet",quiescedAfterMs:d});return}requestAnimationFrame(p)};requestAnimationFrame(p)})},{minQuietMs:n,maxMs:s})}catch{return{kind:"quiet"}}}};function MI(r,e=[]){if(r.length===0&&e.length===0)return null;let t=[],n=r.filter(a=>a.type==="add"),s=r.filter(a=>a.type==="remove");for(let a of n){let i=s.find(c=>c.text===a.text&&c.role===a.role);i&&t.push(`\u26A1 transient: "${a.text}" (role=${a.role}, appeared T+${(a.t/1e3).toFixed(1)}s, lasted ${i.t-a.t}ms)`)}for(let a of e){let i=s.find(l=>l.text===a.text&&l.role===a.role),c=n.find(l=>l.text===a.text&&l.role===a.role);i&&!c&&t.push(`\u26A1 transient: "${a.text}" (role=${a.role}, appeared in previous screenshot, now gone)`)}let o=r.filter(a=>a.type==="scroll").reduce((a,i)=>a+i.dy,0);Math.abs(o)>10&&t.push(`\u2195 scroll: ${o>0?"+":""}${o}px`);for(let a of r)a.type==="hash"&&t.push(`# hash: #${a.from} \u2192 #${a.to}`),a.type==="nav"&&t.push(`\u2192 nav: ${a.url}`);return t.length===0?null:`[Between screenshots]
|
|
1343
1350
|
`+t.join(`
|
|
1344
1351
|
`)}typeof process<"u"&&process.env&&(process.env.PW_TEST_SCREENSHOT_NO_FONTS_READY="1");var Ms=new WeakMap;function OI(){return{pendingWrites:new Set,rollingConsoleErrors:[],rollingPageErrors:[],rollingFailedRequests:[],rollingRecentWrites:[]}}function NI(r){try{return new URL(r).origin}catch{return null}}function Xo(r){if(Ms.has(r))return;let e=OI();Ms.set(r,e),r.on("request",t=>{let n;try{n=r.url()}catch{return}let s=NI(n);if(!s)return;let o={method:()=>t.method(),url:()=>t.url(),resourceType:()=>t.resourceType(),isMainFrame:t.frame()===r.mainFrame()};tf(o,s)&&e.pendingWrites.add({request:t,startTs:Date.now(),url:t.url(),method:t.method()})}),r.on("response",t=>{let n=t.request();for(let s of e.pendingWrites)if(s.request===n){e.pendingWrites.delete(s),e.rollingRecentWrites.push({url:s.url,method:s.method,status:t.status(),durationMs:Date.now()-s.startTs});break}}),r.on("requestfailed",t=>{for(let n of e.pendingWrites)if(n.request===t){e.pendingWrites.delete(n);let s=t.failure()?.errorText??"unknown";e.rollingFailedRequests.push({url:n.url,method:n.method,error:s});break}}),r.on("framenavigated",t=>{t===r.mainFrame()&&e.pendingWrites.clear()}),r.on("console",t=>{t.type()==="error"&&(e.rollingConsoleErrors.length>=5||e.rollingConsoleErrors.push({text:t.text().slice(0,500)}))}),r.on("pageerror",t=>{e.rollingPageErrors.length>=5||e.rollingPageErrors.push({name:t.name,message:String(t.message).slice(0,500)})})}async function PI(r,e){let t=e?.seedCookies,n=e?.seedLocalStorage;if(Array.isArray(t)&&t.length>0)try{await r.addCookies(t),console.log(`[BasePlaywright] Seeded ${t.length} cookie(s) into context`)}catch(s){let o=s instanceof Error?s.message:String(s);console.warn(`[BasePlaywright] addCookies failed: ${o}`)}if(Array.isArray(n)&&n.length>0){let s={};for(let o of n)try{let a=new URL(o.url).origin;s[a]={...s[a]??{},...o.items}}catch{}if(Object.keys(s).length===0)return;try{await r.addInitScript(o=>{try{let a=o.byOrigin[location.origin];if(!a)return;for(let i of Object.keys(a))try{localStorage.setItem(i,a[i])}catch{}}catch{}},{byOrigin:s}),console.log(`[BasePlaywright] Seeded localStorage for origins: ${Object.keys(s).join(", ")}`)}catch(o){let a=o instanceof Error?o.message:String(o);console.warn(`[BasePlaywright] addInitScript (seedLocalStorage) failed: ${a}`)}}}var sf={backspace:"Backspace",tab:"Tab",return:"Enter",enter:"Enter",shift:"Shift",control:"ControlOrMeta",alt:"Alt",escape:"Escape",space:"Space",pageup:"PageUp",pagedown:"PageDown",end:"End",home:"Home",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",insert:"Insert",delete:"Delete",semicolon:";",equals:"=",multiply:"Multiply",add:"Add",separator:"Separator",subtract:"Subtract",decimal:"Decimal",divide:"Divide",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",command:"Meta",meta:"Meta"},Ki=new Set(["Shift","Control","ControlOrMeta","Alt","Meta"]),Os=class r{browser=null;sessions=new Map;browserShutdownExpected=!1;onBrowserDisconnected;diagLog;async launchBrowser(){let{chromium:e}=await import("playwright");return e.launch({headless:!0,args:["--disable-extensions","--disable-file-system","--disable-plugins","--disable-dev-shm-usage","--disable-background-networking","--disable-default-apps","--disable-sync","--no-sandbox",...Wi]})}async createSession(e,t){let n=await this.ensureBrowser(),s=t?.screenWidth??1280,o=t?.screenHeight??720,a=await n.newContext({viewport:{width:s,height:o},acceptDownloads:!0,userAgent:Gi(n.version())});await Yi(a),await PI(a,t);let i=await a.newPage();process.env.AQ_NO_DOM_OBSERVER||(await i.addInitScript(Pr.script()),await Pr.install(i)),Xo(i);let c={sessionId:e,context:a,page:i,viewportWidth:s,viewportHeight:o,needsFullSnapshot:!1,isExtensionSession:!1,tab1:i,activeTab:"tab1",pendingExtensionPopup:!1,extensionId:void 0,lastInvokeAt:Date.now()};a.on("page",async u=>{Xo(u);try{if(await u.waitForLoadState("domcontentloaded",{timeout:5e3}).catch(()=>{}),c.tab2&&!c.tab2.isClosed())try{await c.tab2.close()}catch{}c.tab2=u,c.page=u,c.activeTab="tab2",c.needsFullSnapshot=!0,u.on("dialog",f=>f.accept()),u.on("close",()=>{c.tab2===u&&(c.tab2=void 0,c.activeTab==="tab2"&&(c.page=c.tab1,c.activeTab="tab1",c.needsFullSnapshot=!0))})}catch{try{await u.close()}catch{}}}),i.on("dialog",u=>u.accept());let l=t?.initialUrl;return l&&l!=="about:blank"&&(await i.goto($n(l)),await this.awaitPageReady(i)),c}async dispatchPlatformAction(e,t,n){}async onFilesUploaded(e){return[]}async onBeforeAction(e,t,n){if(!(t==null||n==null))try{await e.page.evaluate(({x:s,y:o})=>{let a=document.getElementById("__agentiqa_cursor");a||(a=document.createElement("div"),a.id="__agentiqa_cursor",a.style.cssText=`
|
|
1345
1352
|
position: fixed;
|
|
@@ -1368,7 +1375,7 @@ x-amz-content-sha256:${h}
|
|
|
1368
1375
|
x-amz-date:${u}
|
|
1369
1376
|
`,y="host;x-amz-content-sha256;x-amz-date",v=["PUT",c,"",d,y,h].join(`
|
|
1370
1377
|
`),w="AWS4-HMAC-SHA256",b=`${f}/${g}/${p}/aws4_request`,x=[w,u,b,Gf(v)].join(`
|
|
1371
|
-
`),S=iA(n.secretAccessKey,f,g,p),A=zs(S,x).toString("hex"),_=`${w} Credential=${n.accessKeyId}/${b}, SignedHeaders=${y}, Signature=${A}`;try{let k=await fetch(o,{method:"PUT",headers:{Host:i,"x-amz-date":u,"x-amz-content-sha256":h,Authorization:_,"Content-Type":t,"Content-Length":r.length.toString()},body:new Uint8Array(r)});if(k.ok)return n.publicUrl?`${n.publicUrl}/${e}`:o;if(cA.has(k.status)&&s<Hs){console.warn(`[R2Upload] ${k.status} on attempt ${s+1}, retrying in ${gl}ms...`),await new Promise(R=>setTimeout(R,gl));continue}return console.error(`[R2Upload] Upload failed: ${k.status} ${k.statusText} (attempt ${s+1}/${Hs+1})`),null}catch(k){if(s<Hs){console.warn(`[R2Upload] Network error on attempt ${s+1}, retrying: ${k.message}`),await new Promise(R=>setTimeout(R,gl));continue}return console.error(`[R2Upload] Upload failed after ${Hs+1} attempts: ${k.message}`),null}}return null}async function yl(r,e,t){let n=await aA(r);return Yf(n,e,t)}async function fa(r,e,t){return Yf(r,e,t)}var Ws=class{constructor(e){this.userId=e}async save(e){let t=this.decodeBase64(e.base64);if(!t)return{};let s=`${["analytics",this.userId,e.projectId,e.type,e.issueId??e.messageId??"unknown"].map(o=>o.replace(/:/g,"--")).join("/")}.png`;try{let o=await fa(t,s,"image/png");return o?{url:o}:{}}catch(o){return console.warn(`[R2ImageStorage] upload failed: ${o.message}`),{}}}async get(){return null}async delete(){}async deleteSession(){}async clearProject(){}decodeBase64(e){let t=e.includes(",")?e.split(",")[1]:e;if(!t)return null;try{return Buffer.from(t.replace(/\s/g,""),"base64")}catch{return null}}};var vl=()=>process.env.API_URL,vr=new ia,Kf=new la,Xf=new ua,dA=new da,Qf=new pa,Zf=new ma,pA=new ra,mA=new ha,hA={async store(){throw new Error("Not supported on cloud")},async read(r){let e=Jf(r,"utf-8");return{content:e,sizeBytes:Buffer.byteLength(e)}},async readBinary(r){let e=Jf(r);return{data:new Uint8Array(e),sizeBytes:e.length}},async getAbsolutePath(r){if(uA(r))return r;throw new Error(`Cannot resolve attachment path: ${r}`)},async addRef(){},async removeRef(){},async deleteUnreferenced(){return 0}};function eg(r){return{platform:r?.platform??"web",userId:r?.userId}}function tg(r){if(process.env.DIAG_LOCAL==="true")return new pn;let e=vl(),t=process.env.ADMIN_SERVICE_KEY;if(e&&t)return new mn(e,{kind:"service",serviceKey:t,fallbackUserId:r?.userId,bearerFallback:r?.userToken});let n=r?.userToken;return e&&n?new mn(e,{kind:"bearer",token:n}):process.env.NODE_ENV!=="production"?new pn:new ss}function Gs(r,e,t,n,s){let o=tg(t),a=vr,i=new Us,c=t?.userToken,l=vl(),u=l&&t?.userId?new qs(l,t.userId,c):(()=>{let h=new Ls;return t?.issues?.length&&h.seed(t.issues),h})(),f=l&&t?.userId?new Fs(l,t.userId,c):Kf,g=new Bs(t?.credentials??[]);t&&t.memoryItems?.length&&i.seed(t.projectId,t.memoryItems);let p=t?.userId?new Ws(t.userId):null;return{chatRepo:a,issuesRepo:u,memoryRepo:i,testPlanV2RunRepo:f,secretsService:g,model:r,computerUseService:e,mobileMcpService:n,authService:Xf,sink:o,sessionMetaExtras:eg(t),sampleFilesService:pA,attachmentStorageService:hA,imageStorageService:p,notificationService:dA,llmAccessService:Qf,errorReporter:Zf,supervisorService:new Rs(r),screencastService:s??void 0,createVideoRecorder:()=>new Vs,uploadVideo:(h,d)=>yl(h,d,"video/mp4")}}function rg(r,e,t,n,s,o){let a=tg(t),i=vr,c=new Us,l=t?.userToken,u=vl(),f=u&&t?.userId?new qs(u,t.userId,l):(()=>{let b=new Ls;return t?.issues?.length&&b.seed(t.issues),b})(),g=new Bs(t?.credentials??[]),p=u&&t?.userId?new Fs(u,t.userId,l):Kf;t&&t.memoryItems?.length&&c.seed(t.projectId,t.memoryItems);let h=o?nr(Ll,o):void 0,d=u&&l&&t?.userId?new oa(u,l,t.userId):(()=>{let b=new na;return t?.appMap&&b.seed(t.projectId,t.appMap),b})(),y=u&&l&&t?.userId?new aa(u,l,t.userId):(()=>{let b=new sa;return t?.journalEntries?.length&&b.seed(t.projectId,t.journalEntries),b})(),v=u&&l?new ca(u,l):mA,w=t?.userId?new Ws(t.userId):null;return{chatRepo:i,model:r,coordinatorModel:h,computerUseService:e,authService:Xf,sink:a,sessionMetaExtras:eg(t),memoryRepo:c,secretsService:g,issuesRepo:f,mobileMcpService:n,screencastService:s??void 0,errorReporter:Zf,llmAccessService:Qf,supervisorService:null,testPlanV2RunRepo:p,appMapRepo:d,journalRepo:y,projectsRepo:v,imageStorageService:w,createVideoRecorder:()=>new Vs,uploadVideo:(b,x)=>yl(b,x,"video/mp4")}}import ng from"express-rate-limit";var sg=ng({windowMs:6e4,max:60,standardHeaders:!0,legacyHeaders:!1,skip:r=>r.path==="/health",message:{error:"Too many requests, please try again later"}}),og=ng({windowMs:6e4,max:5,standardHeaders:!0,legacyHeaders:!1,message:{error:"Too many session creation requests, please try again later"}}),ag=20;import{z as V}from"zod";function jr(r){return(e,t,n)=>{let s=r.safeParse(e.body);if(!s.success){let o=s.error.issues.map(a=>({path:a.path.join("."),message:a.message}));console.error("[Validation] Failed:",e.method,e.path,JSON.stringify(o)),t.status(400).json({error:"Validation failed",details:o});return}e.body=s.data,n()}}var ig=V.union([V.number(),V.string()]).transform(r=>typeof r=="string"?new Date(r).getTime():r),lg=V.object({sessionId:V.string().max(100).optional(),sessionKind:V.string().max(50).optional(),sessionTitle:V.string().max(200).optional(),projectId:V.string().max(100).optional(),userId:V.string().max(100).optional(),userToken:V.string().max(4e3).optional(),model:V.string().max(100).optional(),screenWidth:V.number().int().min(320).max(3840).optional(),screenHeight:V.number().int().min(320).max(3840).optional(),initialUrl:V.string().max(2048).optional(),routingContext:V.object({bootstrapSource:V.enum(["welcome_url_form","chat_message"]).optional(),routingMode:V.enum(["mapper_then_coordinator","specific_task_via_coordinator"]).optional(),bootstrapStartedAt:V.number().optional(),bootstrapCompletedAt:V.number().optional()}).optional(),snapshotOnly:V.boolean().optional(),memoryItems:V.union([V.array(V.object({id:V.string().max(100).optional(),text:V.string().max(5e3),category:V.string().max(100).nullable().optional()}).passthrough()).max(100),V.array(V.string().max(5e3)).max(100)]).optional(),issues:V.array(V.record(V.string(),V.unknown())).max(200).optional(),credentials:V.array(V.object({name:V.string().max(500),secret:V.string().max(500)}).passthrough()).max(20).optional(),engineSessionKind:V.enum(["agent","runner"]).optional(),platform:V.string().max(50).optional(),autoApprove:V.boolean().optional(),goal:V.string().max(2e3).optional(),verbose:V.boolean().optional(),knownIssueTitles:V.array(V.string()).optional(),mobileConfig:V.object({platform:V.enum(["android","ios"]),deviceId:V.string().max(200).optional(),appIdentifier:V.string().max(500).optional()}).optional(),seedCookies:V.array(V.object({name:V.string().max(200),value:V.string().max(4096),domain:V.string().max(200),path:V.string().max(200).optional(),expires:V.number().optional(),httpOnly:V.boolean().optional(),secure:V.boolean().optional(),sameSite:V.enum(["Strict","Lax","None"]).optional()}).passthrough()).max(50).optional(),seedLocalStorage:V.array(V.object({url:V.string().max(2048),items:V.record(V.string().max(200),V.string().max(4096))})).max(20).optional()}).passthrough(),cg=V.object({text:V.string().min(1,"text is required").max(5e4),attachments:V.array(V.object({id:V.string().max(200),sessionId:V.string().max(200),originalName:V.string().max(500),mimeType:V.string().max(200),sizeBytes:V.number(),category:V.enum(["text","image","binary"]),r2Key:V.string().max(1e3),r2Url:V.string().max(2048)}).passthrough()).max(20).optional()}),fA=V.object({text:V.string().max(5e3),type:V.enum(["setup","action","verify"]).optional(),criteria:V.array(V.object({check:V.string().max(2e3),strict:V.boolean()})).max(50).optional(),fileAssets:V.array(V.object({storedPath:V.string().max(1e3),originalName:V.string().max(500)})).max(10).optional()}).passthrough(),bl=V.object({id:V.string().max(100),projectId:V.string().max(100),title:V.string().max(500),steps:V.array(fA).min(1).max(100),createdAt:ig,updatedAt:ig,sourceSessionId:V.string().max(100).nullish(),chatSessionId:V.string().max(100).nullish(),config:V.record(V.string(),V.unknown()).nullish(),labels:V.array(V.string().max(100)).max(50).nullish()}).passthrough(),ug=V.object({testPlan:bl,initialMemory:V.record(V.string().max(200),V.string().max(2e3)).optional()}),dg=V.object({plans:V.array(bl).min(1).max(20),mode:V.enum(["sequential","parallel"]),concurrency:V.number().int().min(1).max(5).optional(),initialMemory:V.record(V.string().max(200),V.string().max(2e3)).optional(),batchRunId:V.string().optional()}),pg=V.object({text:V.string().min(1,"text is required").max(5e4),testPlan:bl}),mg=V.object({expression:V.string().min(1,"expression is required").max(1e4)}),hg=V.object({text:V.string().min(1,"text is required").max(2e3)});process.on("uncaughtException",r=>{console.error("[Engine] Uncaught exception:",r)});process.on("unhandledRejection",r=>{console.error("[Engine] Unhandled rejection:",r)});function gg(r,e,t,n,s,o){let a=r.chatSession.config?.model??Tr,i=nr(a,n);s&&(i=on(i,o,!0,(f,g,p)=>{r.sink?.emit({kind:"log",ts:Date.now(),sessionId:r.id,level:"info",source:"LLMCache",message:`${f?"HIT":"MISS"} ${g.slice(0,8)} (msgs=${p})`})}));let c=new Dr(e),l=rg(i,e,r.seed,t,c,n);r.secretsService=l.secretsService,r.sink=l.sink,r.type="agent";let u=new Cs(r.id,l);return r._cleanupListeners=_A(r,u),u}function Ys(r,e,t){return r.engineSessionKind&&r.engineSessionKind!==e?(t.status(409).json({error:`Session "${r.engineSessionKind}" cannot use "${e}" endpoint`}),!1):!0}function Ue(r,e){r.lastActivityAt=Date.now();let{screenshotBase64:t,...n}=e;if(r.events.push(n),t&&e.message&&e.message.id){let o=e.message.id,i=`screenshots/${r.chatSession.projectId||"unknown"}/${r.id}/${o}.png`,c=Buffer.from(t,"base64");r.screenshotUrls||(r.screenshotUrls=new Map),r.pendingScreenshotUploads||(r.pendingScreenshotUploads=[]);let l=fa(c,i,"image/png").then(u=>{u?r.screenshotUrls.set(o,u):console.warn(`[Engine] Screenshot upload returned null for ${o}`)}).catch(u=>{console.warn(`[Engine] Screenshot upload error for ${o}: ${u.message}`)});r.pendingScreenshotUploads.push(l)}let s=JSON.stringify(e);for(let o of r.ws)o.readyState===Vn.OPEN&&o.send(s)}function _A(r,e){return e.on("action:progress",t=>{Ue(r,{type:"action:progress",...t})}),e.on("message:added",t=>{Ue(r,{type:"message:added",...t})}),e.on("session:stopped",t=>{Ue(r,{type:"session:stopped",...t})}),e.on("session:blocked",t=>{Ue(r,{type:"session:blocked",...t})}),e.on("session:error",t=>{Ue(r,{type:"session:error",...t})}),e.on("session:status-changed",t=>{Ue(r,{type:"session:status-changed",...t})}),e.on("context:updated",t=>{Ue(r,{type:"context:updated",...t})}),e.on("benchmark:milestone",t=>{Ue(r,{type:"benchmark:milestone",...t})}),e.on("session:coverage-requested",t=>{Ue(r,{type:"session:coverage-requested",...t})}),e.on("session:interrupt-requested",t=>{Ue(r,{type:"session:interrupt-requested",...t})}),e.on("screencast:frame",t=>{yg(r,{type:"screencast:frame",...t})}),e.on("screencast:started",t=>{Ue(r,{type:"screencast:started",...t})}),e.on("screencast:stopped",t=>{Ue(r,{type:"screencast:stopped",...t})}),()=>e.removeAllListeners()}function _l(r,e){return e.on("action:progress",t=>{Ue(r,{type:"action:progress",...t})}),e.on("message:added",t=>{Ue(r,{type:"message:added",...t})}),e.on("session:stopped",t=>{Ue(r,{type:"session:stopped",...t})}),e.on("session:error",t=>{Ue(r,{type:"session:error",...t})}),e.on("run:completed",async t=>{Ue(r,{type:"run:completed",...t}),r.lastRunOutcome={type:"run:completed",run:t.run,runMemory:t.runMemory};try{r.pendingScreenshotUploads?.length&&await Promise.allSettled(r.pendingScreenshotUploads);let n=t.run;if(n?.id&&r.seed?.userId&&process.env.API_URL){let s=await vr.listMessages(r.chatSession.id),o=s.filter(u=>!u.runId||u.runId===n.id),a=o.filter(u=>u.role==="user"||u.role==="model"&&(u.actionName||u.text&&!/^(<ctrl\d+>\s*)+$/.test(u.text))||u.role==="system"&&(u.hasScreenshot||r.screenshotUrls?.has(u.id)));console.log(`[Engine] Persisting messages for run ${n.id}: ${a.length} visible of ${o.length} run / ${s.length} total`);let i=(u,f)=>{if(!u)return;let g={};if(u.stepText&&(g.stepText=u.stepText),u.status&&(g.status=u.status),f==="report_issue")for(let p of["title","description","severity","confidence","issueId","issueConfirmed","issueDismissed"])u[p]!==void 0&&(g[p]=u[p]);return f==="propose_update"&&u.updates&&(g.updates=u.updates),f==="spawn_agent"&&u.childAgent&&(g.childAgent=u.childAgent),f==="child_completed"&&u.childAgent&&(g.childAgent=u.childAgent,u.status&&(g.status=u.status),u.summary&&(g.summary=u.summary)),Object.keys(g).length>0?g:void 0},c=a.map(u=>({id:u.id,role:u.role,text:u.text,timestamp:u.timestamp,actionName:u.actionName,actionArgs:i(u.actionArgs,u.actionName),url:u.url,hasScreenshot:u.hasScreenshot||r.screenshotUrls?.has(u.id)||!1,screenshotUrl:r.screenshotUrls?.get(u.id)??void 0,runId:u.runId})),l=await fetch(`${process.env.API_URL}/api/sync/entities/test-plan-runs/${n.id}`,{method:"PUT",headers:qn(r.seed?.userId??"",r.seed?.userToken),body:JSON.stringify({testPlanId:n.testPlanId,projectId:n.projectId,status:n.status,terminationReason:n.terminationReason,messages:c,updatedAt:Date.now()})});l.ok||console.error(`[Engine] Message persist API error for run ${n.id}: ${l.status} ${l.statusText}`)}}catch(n){console.error("[Engine] Error persisting run messages:",n.message)}finally{r.pendingScreenshotUploads=[]}}),e.on("session:status-changed",t=>{Ue(r,{type:"session:status-changed",...t})}),e.on("run:started",t=>{Ue(r,{type:"run:started",...t})}),e.on("benchmark:milestone",t=>{Ue(r,{type:"benchmark:milestone",...t})}),e.on("session:coverage-requested",t=>{Ue(r,{type:"session:coverage-requested",...t})}),e.on("session:interrupt-requested",t=>{Ue(r,{type:"session:interrupt-requested",...t})}),e.on("screencast:frame",t=>{yg(r,{type:"screencast:frame",...t})}),e.on("screencast:started",t=>{Ue(r,{type:"screencast:started",...t})}),e.on("screencast:stopped",t=>{Ue(r,{type:"screencast:stopped",...t})}),()=>e.removeAllListeners()}function yg(r,e){r.lastActivityAt=Date.now();let t=JSON.stringify(e);for(let n of r.ws)n.readyState===Vn.OPEN&&n.send(t)}function vg(r,e){let t={google:process.env.GOOGLE_API_KEY||process.env.GEMINI_API_KEY,anthropic:process.env.ANTHROPIC_API_KEY},n=process.env.NODE_ENV!=="production"&&process.env.LLM_CACHE!=="0",s=yA.join(gA.tmpdir(),"agentiqa-llm-cache"),o=fg(),a=process.env.ENGINE_API_TOKEN;o.use((p,h,d)=>{if(h.header("Access-Control-Allow-Origin","*"),h.header("Access-Control-Allow-Methods","GET, POST, DELETE, OPTIONS"),h.header("Access-Control-Allow-Headers","Content-Type, Authorization"),p.method==="OPTIONS"){h.sendStatus(204);return}d()}),o.use(fg.json({limit:"1mb"})),o.use(sg),o.use((p,h,d)=>{if(p.path==="/health"){d();return}if(!a){d();return}if(p.headers.authorization===`Bearer ${a}`){d();return}h.status(401).json({error:"Unauthorized"})});let i=vA.createServer(o),c=new bA({server:i,path:"/ws",perMessageDeflate:!1}),l=new Map,u=600*1e3,f=setInterval(()=>{let p=Date.now();for(let[h,d]of l){let y=!d.agent?.isRunning&&!d.runner?.isRunning,v=d.ws.size===0,w=p-d.lastActivityAt>u;if(y&&v&&w){console.log(`[Engine] Reaping idle session ${h} (age: ${Math.round((p-d.startedAt)/1e3)}s)`),d.agent?.stop(),d.runner?.stop(),d._cleanupListeners?.(),d.sink?.destroy?.(),Ue(d,{type:"session:error",error:"Session expired due to inactivity"});for(let b of d.ws)b.readyState===Vn.OPEN&&b.close(1e3,"Session expired");r.clearCredentials(h),r.cleanupSession(h).catch(()=>{}),r.cleanupSession(`${h}:child-browser`).catch(()=>{}),vr.deleteSession(h),l.delete(h)}}},6e4);i.on("close",()=>clearInterval(f)),r.onBrowserDisconnected=()=>{if(!r.isBrowserShutdownExpected()){console.error("[Engine] Browser crashed \u2014 stopping all active sessions");for(let[p,h]of l){h.agent?.stop(),h.runner?.stop(),h._cleanupListeners?.(),h.sink?.destroy?.(),Ue(h,{type:"session:error",error:"Browser process crashed"});for(let d of h.ws)d.close();r.clearCredentials(p),vr.deleteSession(p),l.delete(p)}}},o.post("/api/engine/session",og,jr(lg),(p,h)=>{if(l.size>=ag){h.status(503).json({error:"Server at capacity, try again later"});return}let{sessionId:d,sessionKind:y,sessionTitle:v,projectId:w,userId:b,userToken:x,model:S,screenWidth:A,screenHeight:_,initialUrl:k,routingContext:R,snapshotOnly:C,memoryItems:D,issues:te,credentials:P,engineSessionKind:X,mobileConfig:q,goal:oe,verbose:K,knownIssueTitles:U,autoApprove:ee,parallelChildren:le,platform:Q,seedCookies:Z,seedLocalStorage:Y}=p.body,M=d||pe("session"),N=l.get(M);if(N){if(X&&N.engineSessionKind&&X!==N.engineSessionKind){h.status(409).json({error:`Session ${M} exists with kind '${N.engineSessionKind}', cannot reuse as '${X}'`});return}console.log(`[Engine] Session ${M} already exists (running: ${N.agent?.isRunning??N.runner?.isRunning??!1}), returning existing`),h.json({sessionId:M,config:N.chatSession.config,existing:!0});return}let de=w??pe("project"),se={screenWidth:A??1280,screenHeight:_??720,model:S??Tr,initialUrl:k,snapshotOnly:C??!1,...q?{platform:"mobile",mobileConfig:q}:{},...ee!=null&&{autoApprove:ee},...le!=null&&{parallelChildren:le},...Array.isArray(Z)&&Z.length>0?{seedCookies:Z}:{},...Array.isArray(Y)&&Y.length>0?{seedLocalStorage:Y}:{}},j={id:M,projectId:de,title:v||"Cloud Session",createdAt:Date.now(),updatedAt:Date.now(),isArchived:!1,status:"idle",kind:y||"assistant_v2",config:se,routingContext:R},B={projectId:de,sessionId:M,userId:b??void 0,userToken:x??void 0,memoryItems:D??[],issues:te??[],credentials:P??[],platform:Q??void 0};console.log(`[Engine] Session ${M}: ${B.memoryItems?.length??0} memoryItems, ${B.issues?.length??0} issues, ${B.credentials?.length??0} credentials`),B.credentials?.length&&r.seedCredentials(M,B.credentials);let F={id:M,type:"agent",engineSessionKind:X??void 0,chatSession:j,seed:B,ws:new Set,events:[],startedAt:Date.now(),lastActivityAt:Date.now()};l.set(M,F),h.json({sessionId:M,config:se})}),o.get("/api/engine/session/:id",(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}h.json({id:d.id,type:d.type,status:d.chatSession.status,running:d.agent?.isRunning??d.runner?.isRunning??!1,eventCount:d.events.length,startedAt:d.startedAt,userId:d.seed?.userId??null})}),o.patch("/api/engine/session/:id/config",(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}let{autoApprove:y}=p.body??{};y!=null&&(d.chatSession.config.autoApprove=y),h.json({ok:!0,config:d.chatSession.config})}),o.post("/api/engine/session/:id/bootstrap",async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(Ys(d,"agent",h)){if(!d.agent){if(d._agentInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._agentInitializing=!0;try{d.agent=gg(d,r,e,t,n,s),await vr.upsertSession(d.chatSession)}finally{d._agentInitializing=!1}}try{d.agent.startWelcomeBootstrap(d.chatSession).catch(y=>{console.error(`[Engine] bootstrap error for session ${d.id}:`,y.message),Ue(d,{type:"session:error",error:y.message})}),h.json({ok:!0})}catch(y){h.status(500).json({error:y.message})}}}),o.post("/api/engine/session/:id/message",jr(cg),async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(!Ys(d,"agent",h))return;let{text:y}=p.body;if(!d.agent){if(d._agentInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._agentInitializing=!0;try{d.agent=gg(d,r,e,t,n,s),await vr.upsertSession(d.chatSession)}finally{d._agentInitializing=!1}}try{d.agent.sendMessage(d.chatSession,y).catch(v=>{console.error(`[Engine] sendMessage error for session ${d.id}:`,v.message),Ue(d,{type:"session:error",error:v.message})}),h.json({ok:!0})}catch(v){h.status(500).json({error:v.message})}}),o.post("/api/engine/session/:id/run",jr(ug),async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(!Ys(d,"runner",h))return;let{testPlan:y,initialMemory:v}=p.body,w=new Set(["setup","action","verify"]);for(let b of y.steps??[])if(!b.type||!w.has(b.type)){let x=(b.type??"").toLowerCase();b.type=x.includes("verify")?"verify":x.includes("setup")?"setup":"action"}if(!d.runner){if(d._runnerInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._runnerInitializing=!0;try{let b=d.chatSession.config?.model??Tr,x=nr(b,t);n&&(x=on(x,s,!0,(_,k,R)=>{d.sink?.emit({kind:"log",ts:Date.now(),sessionId:d.id,level:"info",source:"LLMCache",message:`${_?"HIT":"MISS"} ${k.slice(0,8)} (msgs=${R})`})}));let S=new Dr(r),A=Gs(x,r,d.seed,e,S);d.runner=new Ft(d.id,A),d.sink=A.sink,d.type="runner",d._cleanupListeners=_l(d,d.runner),d.chatSession={...d.chatSession,kind:"test_run",testPlanId:y.id},await A.chatRepo.upsertSession(d.chatSession)}finally{d._runnerInitializing=!1}}try{d.lastRunOutcome=void 0;let b=d.runner.startRun(d.chatSession,y,{initialMemory:v,onMemoryUpdate:x=>{Ue(d,{type:"memory:updated",memory:x})}});b&&typeof b.catch=="function"&&b.catch(x=>{console.error(`[Engine] startRun error for session ${d.id}:`,x.message),Ue(d,{type:"session:error",error:x.message})}),h.json({ok:!0})}catch(b){h.status(500).json({error:b.message})}}),o.post("/api/engine/session/:id/batch-run",jr(dg),async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(!Ys(d,"runner",h))return;let{plans:y,mode:v,concurrency:w,initialMemory:b,batchRunId:x}=p.body,S=new Set(["setup","action","verify"]);for(let _ of y)for(let k of _.steps??[])if(!k.type||!S.has(k.type)){let R=(k.type??"").toLowerCase();k.type=R.includes("verify")?"verify":R.includes("setup")?"setup":"action"}if(v==="sequential"&&!d.runner){if(d._runnerInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._runnerInitializing=!0;try{let _=d.chatSession.config?.model??Tr,k=nr(_,t);n&&(k=on(k,s,!0,(D,te,P)=>{d.sink?.emit({kind:"log",ts:Date.now(),sessionId:d.id,level:"info",source:"LLMCache",message:`${D?"HIT":"MISS"} ${te.slice(0,8)} (msgs=${P})`})}));let R=new Dr(r),C=Gs(k,r,d.seed,e,R);d.runner=new Ft(d.id,C),d.sink=C.sink,d.type="runner",d._cleanupListeners=_l(d,d.runner),d.chatSession={...d.chatSession,kind:"test_run"},await C.chatRepo.upsertSession(d.chatSession)}finally{d._runnerInitializing=!1}}let A=_=>{Ue(d,_)};try{let _=v==="sequential"?{runner:d.runner}:(()=>{let R=d.chatSession.config?.model??Tr,C=nr(R,t);n&&(C=on(C,s,!0,(te,P,X)=>{d.sink?.emit({kind:"log",ts:Date.now(),sessionId:d.id,level:"info",source:"LLMCache",message:`${te?"HIT":"MISS"} ${P.slice(0,8)} (msgs=${X})`})}));let D=new Dr(r);return{deps:Gs(C,r,d.seed,e,D),sessionId:d.id}})();zi(_,d.chatSession,y,{mode:v,concurrency:w,initialMemory:b,batchRunId:x},A).then(async R=>{x&&d.seed?.userId&&process.env.API_URL&&await fetch(`${process.env.API_URL}/api/sync/entities/batch-runs/${x}`,{method:"PUT",headers:qn(d.seed?.userId??"",d.seed?.userToken),body:JSON.stringify({status:R.status,updatedAt:Date.now(),endedAt:Date.now()})}).catch(()=>{})}).catch(async R=>{Ue(d,{type:"session:error",error:R.message}),x&&d.seed?.userId&&process.env.API_URL&&await fetch(`${process.env.API_URL}/api/sync/entities/batch-runs/${x}`,{method:"PUT",headers:qn(d.seed?.userId??"",d.seed?.userToken),body:JSON.stringify({status:"partial",updatedAt:Date.now(),endedAt:Date.now()})}).catch(()=>{})}),h.json({ok:!0})}catch(_){h.status(500).json({error:_.message})}}),o.post("/api/engine/session/:id/runner-message",jr(pg),async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(!Ys(d,"runner",h))return;let{text:y,testPlan:v}=p.body;if(!d.runner){if(d._runnerInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._runnerInitializing=!0;try{let w=d.chatSession.config?.model??Tr,b=nr(w,t);n&&(b=on(b,s,!0,(A,_,k)=>{d.sink?.emit({kind:"log",ts:Date.now(),sessionId:d.id,level:"info",source:"LLMCache",message:`${A?"HIT":"MISS"} ${_.slice(0,8)} (msgs=${k})`})}));let x=new Dr(r),S=Gs(b,r,d.seed,e,x);d.runner=new Ft(d.id,S),d.sink=S.sink,d.type="runner",d._cleanupListeners=_l(d,d.runner),d.chatSession={...d.chatSession,kind:"test_run",testPlanId:v.id},await S.chatRepo.upsertSession(d.chatSession)}finally{d._runnerInitializing=!1}}try{let w=d.runner.sendMessage(d.chatSession,v,y);w&&typeof w.catch=="function"&&w.catch(b=>{console.error(`[Engine] runner sendMessage error for session ${d.id}:`,b.message),Ue(d,{type:"session:error",error:b.message})}),h.json({ok:!0})}catch(w){h.status(500).json({error:w.message})}}),o.post("/api/engine/session/:id/evaluate",jr(mg),async(p,h)=>{if(!l.get(p.params.id)){h.status(404).json({error:"Session not found"});return}let{expression:y}=p.body;try{let v=await r.evaluate(p.params.id,y);h.json({result:v})}catch(v){h.status(500).json({error:v.message})}}),o.post("/api/engine/session/:id/stop",(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}d.agent?.stop("user_stopped"),d.runner?.stop("user_stopped"),h.json({ok:!0})}),o.post("/api/engine/session/:id/reset",async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"session_not_found"});return}if(d.type!=="runner"||!d.runner){h.status(400).json({error:"not_a_runner_session"});return}let y=p.body?.keepMemory??!0;try{await d.runner.resetForNextPlan({keepMemory:y}),d.events.length=0,h.status(200).json({ok:!0})}catch(v){if(v?.message?.includes("cannot reset while a run is in progress")){h.status(409).json({error:"run_in_progress"});return}h.status(500).json({error:"reset_failed",message:v?.message})}}),o.post("/api/engine/session/:id/credentials",(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}let{credentials:y}=p.body;if(!Array.isArray(y)||y.length===0){h.status(400).json({error:"credentials array required"});return}d.secretsService?.addCredentials(y);let w=[...d.seed?.credentials??[],...y];r.seedCredentials(p.params.id,w),d.seed&&(d.seed.credentials=w),console.log(`[Engine] Credentials added to session ${p.params.id}: ${y.map(b=>b.name).join(", ")}`),h.json({ok:!0,count:y.length})}),o.delete("/api/engine/session/:id",async(p,h)=>{let d=l.get(p.params.id);if(d){d.agent?.stop(),d.runner?.stop(),d._cleanupListeners?.(),d.sink?.destroy?.();for(let y of d.ws)y.close();r.clearCredentials(p.params.id),await r.cleanupSession(p.params.id),await r.cleanupSession(`${p.params.id}:child-browser`).catch(()=>{}),vr.deleteSession(p.params.id),l.delete(p.params.id)}h.json({ok:!0})}),o.post("/api/engine/chat-title",jr(hg),async(p,h)=>{let{text:d}=p.body;try{let y=`Generate a concise 3-5 word title summarizing WHAT is being tested or asked. Never include process words like "testing", "test", "verification", "check", "session", "QA", "validate". Focus only on the subject matter.
|
|
1378
|
+
`),S=iA(n.secretAccessKey,f,g,p),A=zs(S,x).toString("hex"),_=`${w} Credential=${n.accessKeyId}/${b}, SignedHeaders=${y}, Signature=${A}`;try{let k=await fetch(o,{method:"PUT",headers:{Host:i,"x-amz-date":u,"x-amz-content-sha256":h,Authorization:_,"Content-Type":t,"Content-Length":r.length.toString()},body:new Uint8Array(r)});if(k.ok)return n.publicUrl?`${n.publicUrl}/${e}`:o;if(cA.has(k.status)&&s<Hs){console.warn(`[R2Upload] ${k.status} on attempt ${s+1}, retrying in ${gl}ms...`),await new Promise(R=>setTimeout(R,gl));continue}return console.error(`[R2Upload] Upload failed: ${k.status} ${k.statusText} (attempt ${s+1}/${Hs+1})`),null}catch(k){if(s<Hs){console.warn(`[R2Upload] Network error on attempt ${s+1}, retrying: ${k.message}`),await new Promise(R=>setTimeout(R,gl));continue}return console.error(`[R2Upload] Upload failed after ${Hs+1} attempts: ${k.message}`),null}}return null}async function yl(r,e,t){let n=await aA(r);return Yf(n,e,t)}async function fa(r,e,t){return Yf(r,e,t)}var Ws=class{constructor(e){this.userId=e}async save(e){let t=this.decodeBase64(e.base64);if(!t)return{};let s=`${["analytics",this.userId,e.projectId,e.type,e.issueId??e.messageId??"unknown"].map(o=>o.replace(/:/g,"--")).join("/")}.png`;try{let o=await fa(t,s,"image/png");return o?{url:o}:{}}catch(o){return console.warn(`[R2ImageStorage] upload failed: ${o.message}`),{}}}async get(){return null}async delete(){}async deleteSession(){}async clearProject(){}decodeBase64(e){let t=e.includes(",")?e.split(",")[1]:e;if(!t)return null;try{return Buffer.from(t.replace(/\s/g,""),"base64")}catch{return null}}};var vl=()=>process.env.API_URL,vr=new ia,Kf=new la,Xf=new ua,dA=new da,Qf=new pa,Zf=new ma,pA=new ra,mA=new ha,hA={async store(){throw new Error("Not supported on cloud")},async read(r){let e=Jf(r,"utf-8");return{content:e,sizeBytes:Buffer.byteLength(e)}},async readBinary(r){let e=Jf(r);return{data:new Uint8Array(e),sizeBytes:e.length}},async getAbsolutePath(r){if(uA(r))return r;throw new Error(`Cannot resolve attachment path: ${r}`)},async addRef(){},async removeRef(){},async deleteUnreferenced(){return 0}};function eg(r){return{platform:r?.platform??"web",userId:r?.userId}}function tg(r){if(process.env.DIAG_LOCAL==="true")return new pn;let e=vl(),t=process.env.ADMIN_SERVICE_KEY;if(e&&t)return new mn(e,{kind:"service",serviceKey:t,fallbackUserId:r?.userId,bearerFallback:r?.userToken});let n=r?.userToken;return e&&n?new mn(e,{kind:"bearer",token:n}):process.env.NODE_ENV!=="production"?new pn:new ss}function Gs(r,e,t,n,s){let o=tg(t),a=vr,i=new Us,c=t?.userToken,l=vl(),u=l&&t?.userId?new qs(l,t.userId,c):(()=>{let h=new Ls;return t?.issues?.length&&h.seed(t.issues),h})(),f=l&&t?.userId?new Fs(l,t.userId,c):Kf,g=new Bs(t?.credentials??[]);t&&t.memoryItems?.length&&i.seed(t.projectId,t.memoryItems);let p=t?.userId?new Ws(t.userId):null;return{chatRepo:a,issuesRepo:u,memoryRepo:i,testPlanV2RunRepo:f,secretsService:g,model:r,computerUseService:e,mobileMcpService:n,authService:Xf,sink:o,sessionMetaExtras:eg(t),sampleFilesService:pA,attachmentStorageService:hA,imageStorageService:p,notificationService:dA,llmAccessService:Qf,errorReporter:Zf,supervisorService:new Rs(r),screencastService:s??void 0,createVideoRecorder:()=>new Vs,uploadVideo:(h,d)=>yl(h,d,"video/mp4")}}function rg(r,e,t,n,s,o){let a=tg(t),i=vr,c=new Us,l=t?.userToken,u=vl(),f=u&&t?.userId?new qs(u,t.userId,l):(()=>{let b=new Ls;return t?.issues?.length&&b.seed(t.issues),b})(),g=new Bs(t?.credentials??[]),p=u&&t?.userId?new Fs(u,t.userId,l):Kf;t&&t.memoryItems?.length&&c.seed(t.projectId,t.memoryItems);let h=o?nr(Ll,o):void 0,d=u&&l&&t?.userId?new oa(u,l,t.userId):(()=>{let b=new na;return t?.appMap&&b.seed(t.projectId,t.appMap),b})(),y=u&&l&&t?.userId?new aa(u,l,t.userId):(()=>{let b=new sa;return t?.journalEntries?.length&&b.seed(t.projectId,t.journalEntries),b})(),v=u&&l?new ca(u,l):mA,w=t?.userId?new Ws(t.userId):null;return{chatRepo:i,model:r,coordinatorModel:h,computerUseService:e,authService:Xf,sink:a,sessionMetaExtras:eg(t),memoryRepo:c,secretsService:g,issuesRepo:f,mobileMcpService:n,screencastService:s??void 0,errorReporter:Zf,llmAccessService:Qf,supervisorService:null,testPlanV2RunRepo:p,appMapRepo:d,journalRepo:y,projectsRepo:v,imageStorageService:w,createVideoRecorder:()=>new Vs,uploadVideo:(b,x)=>yl(b,x,"video/mp4")}}import ng from"express-rate-limit";var sg=ng({windowMs:6e4,max:60,standardHeaders:!0,legacyHeaders:!1,skip:r=>r.path==="/health",message:{error:"Too many requests, please try again later"}}),og=ng({windowMs:6e4,max:5,standardHeaders:!0,legacyHeaders:!1,message:{error:"Too many session creation requests, please try again later"}}),ag=20;import{z as V}from"zod";function jr(r){return(e,t,n)=>{let s=r.safeParse(e.body);if(!s.success){let o=s.error.issues.map(a=>({path:a.path.join("."),message:a.message}));console.error("[Validation] Failed:",e.method,e.path,JSON.stringify(o)),t.status(400).json({error:"Validation failed",details:o});return}e.body=s.data,n()}}var ig=V.union([V.number(),V.string()]).transform(r=>typeof r=="string"?new Date(r).getTime():r),lg=V.object({sessionId:V.string().max(100).optional(),sessionKind:V.string().max(50).optional(),sessionTitle:V.string().max(200).optional(),projectId:V.string().max(100).optional(),userId:V.string().max(100).optional(),userToken:V.string().max(4e3).optional(),model:V.string().max(100).optional(),screenWidth:V.number().int().min(320).max(3840).optional(),screenHeight:V.number().int().min(320).max(3840).optional(),initialUrl:V.string().max(2048).optional(),routingContext:V.object({bootstrapSource:V.enum(["welcome_url_form","chat_message"]).optional(),routingMode:V.enum(["mapper_then_coordinator","specific_task_via_coordinator"]).optional(),bootstrapStartedAt:V.number().optional(),bootstrapCompletedAt:V.number().optional()}).optional(),snapshotOnly:V.boolean().optional(),memoryItems:V.union([V.array(V.object({id:V.string().max(100).optional(),text:V.string().max(5e3),category:V.string().max(100).nullable().optional()}).passthrough()).max(100),V.array(V.string().max(5e3)).max(100)]).optional(),issues:V.array(V.record(V.string(),V.unknown())).max(200).optional(),credentials:V.array(V.object({name:V.string().max(500),secret:V.string().max(500)}).passthrough()).max(20).optional(),engineSessionKind:V.enum(["agent","runner"]).optional(),platform:V.string().max(50).optional(),autoApprove:V.boolean().optional(),goal:V.string().max(2e3).optional(),verbose:V.boolean().optional(),knownIssueTitles:V.array(V.string()).optional(),mobileConfig:V.object({platform:V.enum(["android","ios"]),deviceId:V.string().max(200).optional(),appIdentifier:V.string().max(500).optional()}).optional(),seedCookies:V.array(V.object({name:V.string().max(200),value:V.string().max(4096),domain:V.string().max(200),path:V.string().max(200).optional(),expires:V.number().optional(),httpOnly:V.boolean().optional(),secure:V.boolean().optional(),sameSite:V.enum(["Strict","Lax","None"]).optional()}).passthrough()).max(50).optional(),seedLocalStorage:V.array(V.object({url:V.string().max(2048),items:V.record(V.string().max(200),V.string().max(4096))})).max(20).optional()}).passthrough(),cg=V.object({text:V.string().min(1,"text is required").max(5e4),attachments:V.array(V.object({id:V.string().max(200),sessionId:V.string().max(200),originalName:V.string().max(500),mimeType:V.string().max(200),sizeBytes:V.number(),category:V.enum(["text","image","binary"]),r2Key:V.string().max(1e3),r2Url:V.string().max(2048)}).passthrough()).max(20).optional()}),fA=V.object({text:V.string().max(5e3),type:V.enum(["setup","action","verify"]).optional(),criteria:V.array(V.object({check:V.string().max(2e3),strict:V.boolean()})).max(50).optional(),fileAssets:V.array(V.object({storedPath:V.string().max(1e3),originalName:V.string().max(500)})).max(10).optional()}).passthrough(),bl=V.object({id:V.string().max(100),projectId:V.string().max(100),title:V.string().max(500),steps:V.array(fA).min(1).max(100),createdAt:ig,updatedAt:ig,sourceSessionId:V.string().max(100).nullish(),chatSessionId:V.string().max(100).nullish(),config:V.record(V.string(),V.unknown()).nullish(),labels:V.array(V.string().max(100)).max(50).nullish()}).passthrough(),ug=V.object({testPlan:bl,initialMemory:V.record(V.string().max(200),V.string().max(2e3)).optional()}),dg=V.object({plans:V.array(bl).min(1).max(20),mode:V.enum(["sequential","parallel"]),concurrency:V.number().int().min(1).max(5).optional(),initialMemory:V.record(V.string().max(200),V.string().max(2e3)).optional(),batchRunId:V.string().optional()}),pg=V.object({text:V.string().min(1,"text is required").max(5e4),testPlan:bl}),mg=V.object({expression:V.string().min(1,"expression is required").max(1e4)}),hg=V.object({text:V.string().min(1,"text is required").max(2e3)});process.on("uncaughtException",r=>{console.error("[Engine] Uncaught exception:",r)});process.on("unhandledRejection",r=>{console.error("[Engine] Unhandled rejection:",r)});function gg(r,e,t,n,s,o){let a=r.chatSession.config?.model??Tr,i=nr(a,n);s&&(i=on(i,o,!0,(f,g,p)=>{r.sink?.emit({kind:"log",ts:Date.now(),sessionId:r.id,level:"info",source:"LLMCache",message:`${f?"HIT":"MISS"} ${g.slice(0,8)} (msgs=${p})`})}));let c=new Dr(e),l=rg(i,e,r.seed,t,c,n);r.secretsService=l.secretsService,r.sink=l.sink,r.type="agent";let u=new Cs(r.id,l);return r._cleanupListeners=_A(r,u),u}function Ys(r,e,t){return r.engineSessionKind&&r.engineSessionKind!==e?(t.status(409).json({error:`Session "${r.engineSessionKind}" cannot use "${e}" endpoint`}),!1):!0}function Ue(r,e){r.lastActivityAt=Date.now();let{screenshotBase64:t,...n}=e;if(r.events.push(n),t&&e.message&&e.message.id){let o=e.message.id,i=`screenshots/${r.chatSession.projectId||"unknown"}/${r.id}/${o}.png`,c=Buffer.from(t,"base64");r.screenshotUrls||(r.screenshotUrls=new Map),r.pendingScreenshotUploads||(r.pendingScreenshotUploads=[]);let l=fa(c,i,"image/png").then(u=>{u?r.screenshotUrls.set(o,u):console.warn(`[Engine] Screenshot upload returned null for ${o}`)}).catch(u=>{console.warn(`[Engine] Screenshot upload error for ${o}: ${u.message}`)});r.pendingScreenshotUploads.push(l)}let s=JSON.stringify(e);for(let o of r.ws)o.readyState===Vn.OPEN&&o.send(s)}function _A(r,e){return e.on("action:progress",t=>{Ue(r,{type:"action:progress",...t})}),e.on("message:added",t=>{Ue(r,{type:"message:added",...t})}),e.on("session:stopped",t=>{Ue(r,{type:"session:stopped",...t})}),e.on("session:blocked",t=>{Ue(r,{type:"session:blocked",...t})}),e.on("session:error",t=>{Ue(r,{type:"session:error",...t})}),e.on("session:status-changed",t=>{Ue(r,{type:"session:status-changed",...t})}),e.on("context:updated",t=>{Ue(r,{type:"context:updated",...t})}),e.on("benchmark:milestone",t=>{Ue(r,{type:"benchmark:milestone",...t})}),e.on("session:coverage-requested",t=>{Ue(r,{type:"session:coverage-requested",...t})}),e.on("session:interrupt-requested",t=>{Ue(r,{type:"session:interrupt-requested",...t})}),e.on("screencast:frame",t=>{yg(r,{type:"screencast:frame",...t})}),e.on("screencast:started",t=>{Ue(r,{type:"screencast:started",...t})}),e.on("screencast:stopped",t=>{Ue(r,{type:"screencast:stopped",...t})}),()=>e.removeAllListeners()}function _l(r,e){return e.on("action:progress",t=>{Ue(r,{type:"action:progress",...t})}),e.on("message:added",t=>{Ue(r,{type:"message:added",...t})}),e.on("session:stopped",t=>{Ue(r,{type:"session:stopped",...t})}),e.on("session:error",t=>{Ue(r,{type:"session:error",...t})}),e.on("run:completed",async t=>{Ue(r,{type:"run:completed",...t}),r.lastRunOutcome={type:"run:completed",run:t.run,runMemory:t.runMemory};try{r.pendingScreenshotUploads?.length&&await Promise.allSettled(r.pendingScreenshotUploads);let n=t.run;if(n?.id&&r.seed?.userId&&process.env.API_URL){let s=await vr.listMessages(r.chatSession.id),o=s.filter(u=>!u.runId||u.runId===n.id),a=o.filter(u=>u.role==="user"||u.role==="model"&&(u.actionName||u.text&&!/^(<ctrl\d+>\s*)+$/.test(u.text))||u.role==="system"&&(u.hasScreenshot||r.screenshotUrls?.has(u.id)));console.log(`[Engine] Persisting messages for run ${n.id}: ${a.length} visible of ${o.length} run / ${s.length} total`);let i=(u,f)=>{if(!u)return;let g={};if(u.stepText&&(g.stepText=u.stepText),u.status&&(g.status=u.status),f==="report_issue")for(let p of["title","description","severity","confidence","issueId","issueConfirmed","issueDismissed"])u[p]!==void 0&&(g[p]=u[p]);return f==="propose_update"&&u.updates&&(g.updates=u.updates),f==="spawn_agent"&&u.childAgent&&(g.childAgent=u.childAgent),f==="child_completed"&&u.childAgent&&(g.childAgent=u.childAgent,u.status&&(g.status=u.status),u.summary&&(g.summary=u.summary)),Object.keys(g).length>0?g:void 0},c=a.map(u=>({id:u.id,role:u.role,text:u.text,timestamp:u.timestamp,actionName:u.actionName,actionArgs:i(u.actionArgs,u.actionName),url:u.url,hasScreenshot:u.hasScreenshot||r.screenshotUrls?.has(u.id)||!1,screenshotUrl:r.screenshotUrls?.get(u.id)??void 0,runId:u.runId})),l=await fetch(`${process.env.API_URL}/api/sync/entities/test-plan-runs/${n.id}`,{method:"PUT",headers:qn(r.seed?.userId??"",r.seed?.userToken),body:JSON.stringify({testPlanId:n.testPlanId,projectId:n.projectId,status:n.status,terminationReason:n.terminationReason,messages:c,updatedAt:Date.now()})});l.ok||console.error(`[Engine] Message persist API error for run ${n.id}: ${l.status} ${l.statusText}`)}}catch(n){console.error("[Engine] Error persisting run messages:",n.message)}finally{r.pendingScreenshotUploads=[]}}),e.on("session:status-changed",t=>{Ue(r,{type:"session:status-changed",...t})}),e.on("run:started",t=>{Ue(r,{type:"run:started",...t})}),e.on("benchmark:milestone",t=>{Ue(r,{type:"benchmark:milestone",...t})}),e.on("session:coverage-requested",t=>{Ue(r,{type:"session:coverage-requested",...t})}),e.on("session:interrupt-requested",t=>{Ue(r,{type:"session:interrupt-requested",...t})}),e.on("screencast:frame",t=>{yg(r,{type:"screencast:frame",...t})}),e.on("screencast:started",t=>{Ue(r,{type:"screencast:started",...t})}),e.on("screencast:stopped",t=>{Ue(r,{type:"screencast:stopped",...t})}),()=>e.removeAllListeners()}function yg(r,e){r.lastActivityAt=Date.now();let t=JSON.stringify(e);for(let n of r.ws)n.readyState===Vn.OPEN&&n.send(t)}function vg(r,e){let t={google:process.env.GOOGLE_API_KEY||process.env.GEMINI_API_KEY,anthropic:process.env.ANTHROPIC_API_KEY},n=process.env.NODE_ENV!=="production"&&process.env.LLM_CACHE!=="0",s=yA.join(gA.tmpdir(),"agentiqa-llm-cache"),o=fg(),a=process.env.ENGINE_API_TOKEN;o.use((p,h,d)=>{if(h.header("Access-Control-Allow-Origin","*"),h.header("Access-Control-Allow-Methods","GET, POST, DELETE, OPTIONS"),h.header("Access-Control-Allow-Headers","Content-Type, Authorization, X-Session-Token"),p.method==="OPTIONS"){h.sendStatus(204);return}d()}),o.use(fg.json({limit:"1mb"})),o.use(sg),o.use((p,h,d)=>{if(p.path==="/health"){d();return}if(!a){d();return}if(p.headers.authorization===`Bearer ${a}`){d();return}h.status(401).json({error:"Unauthorized"})});let i=vA.createServer(o),c=new bA({server:i,path:"/ws",perMessageDeflate:!1}),l=new Map,u=600*1e3,f=setInterval(()=>{let p=Date.now();for(let[h,d]of l){let y=!d.agent?.isRunning&&!d.runner?.isRunning,v=d.ws.size===0,w=p-d.lastActivityAt>u;if(y&&v&&w){console.log(`[Engine] Reaping idle session ${h} (age: ${Math.round((p-d.startedAt)/1e3)}s)`),d.agent?.stop(),d.runner?.stop(),d._cleanupListeners?.(),d.sink?.destroy?.(),Ue(d,{type:"session:error",error:"Session expired due to inactivity"});for(let b of d.ws)b.readyState===Vn.OPEN&&b.close(1e3,"Session expired");r.clearCredentials(h),r.cleanupSession(h).catch(()=>{}),r.cleanupSession(`${h}:child-browser`).catch(()=>{}),vr.deleteSession(h),l.delete(h)}}},6e4);i.on("close",()=>clearInterval(f)),r.onBrowserDisconnected=()=>{if(!r.isBrowserShutdownExpected()){console.error("[Engine] Browser crashed \u2014 stopping all active sessions");for(let[p,h]of l){h.agent?.stop(),h.runner?.stop(),h._cleanupListeners?.(),h.sink?.destroy?.(),Ue(h,{type:"session:error",error:"Browser process crashed"});for(let d of h.ws)d.close();r.clearCredentials(p),vr.deleteSession(p),l.delete(p)}}},o.post("/api/engine/session",og,jr(lg),(p,h)=>{if(l.size>=ag){h.status(503).json({error:"Server at capacity, try again later"});return}let{sessionId:d,sessionKind:y,sessionTitle:v,projectId:w,userId:b,userToken:x,model:S,screenWidth:A,screenHeight:_,initialUrl:k,routingContext:R,snapshotOnly:C,memoryItems:D,issues:te,credentials:P,engineSessionKind:X,mobileConfig:q,goal:oe,verbose:K,knownIssueTitles:U,autoApprove:ee,parallelChildren:le,platform:Q,seedCookies:Z,seedLocalStorage:Y}=p.body,M=d||pe("session"),N=l.get(M);if(N){if(X&&N.engineSessionKind&&X!==N.engineSessionKind){h.status(409).json({error:`Session ${M} exists with kind '${N.engineSessionKind}', cannot reuse as '${X}'`});return}console.log(`[Engine] Session ${M} already exists (running: ${N.agent?.isRunning??N.runner?.isRunning??!1}), returning existing`),h.json({sessionId:M,config:N.chatSession.config,existing:!0});return}let de=w??pe("project"),se={screenWidth:A??1280,screenHeight:_??720,model:S??Tr,initialUrl:k,snapshotOnly:C??!1,...q?{platform:"mobile",mobileConfig:q}:{},...ee!=null&&{autoApprove:ee},...le!=null&&{parallelChildren:le},...Array.isArray(Z)&&Z.length>0?{seedCookies:Z}:{},...Array.isArray(Y)&&Y.length>0?{seedLocalStorage:Y}:{}},j={id:M,projectId:de,title:v||"Cloud Session",createdAt:Date.now(),updatedAt:Date.now(),isArchived:!1,status:"idle",kind:y||"assistant_v2",config:se,routingContext:R},B={projectId:de,sessionId:M,userId:b??void 0,userToken:x??void 0,memoryItems:D??[],issues:te??[],credentials:P??[],platform:Q??void 0};console.log(`[Engine] Session ${M}: ${B.memoryItems?.length??0} memoryItems, ${B.issues?.length??0} issues, ${B.credentials?.length??0} credentials`),B.credentials?.length&&r.seedCredentials(M,B.credentials);let F={id:M,type:"agent",engineSessionKind:X??void 0,chatSession:j,seed:B,ws:new Set,events:[],startedAt:Date.now(),lastActivityAt:Date.now()};l.set(M,F),h.json({sessionId:M,config:se})}),o.get("/api/engine/session/:id",(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}h.json({id:d.id,type:d.type,status:d.chatSession.status,running:d.agent?.isRunning??d.runner?.isRunning??!1,eventCount:d.events.length,startedAt:d.startedAt,userId:d.seed?.userId??null})}),o.patch("/api/engine/session/:id/config",(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}let{autoApprove:y}=p.body??{};y!=null&&(d.chatSession.config.autoApprove=y),h.json({ok:!0,config:d.chatSession.config})}),o.post("/api/engine/session/:id/bootstrap",async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(Ys(d,"agent",h)){if(!d.agent){if(d._agentInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._agentInitializing=!0;try{d.agent=gg(d,r,e,t,n,s),await vr.upsertSession(d.chatSession)}finally{d._agentInitializing=!1}}try{d.agent.startWelcomeBootstrap(d.chatSession).catch(y=>{console.error(`[Engine] bootstrap error for session ${d.id}:`,y.message),Ue(d,{type:"session:error",error:y.message})}),h.json({ok:!0})}catch(y){h.status(500).json({error:y.message})}}}),o.post("/api/engine/session/:id/message",jr(cg),async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(!Ys(d,"agent",h))return;let{text:y}=p.body;if(!d.agent){if(d._agentInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._agentInitializing=!0;try{d.agent=gg(d,r,e,t,n,s),await vr.upsertSession(d.chatSession)}finally{d._agentInitializing=!1}}try{d.agent.sendMessage(d.chatSession,y).catch(v=>{console.error(`[Engine] sendMessage error for session ${d.id}:`,v.message),Ue(d,{type:"session:error",error:v.message})}),h.json({ok:!0})}catch(v){h.status(500).json({error:v.message})}}),o.post("/api/engine/session/:id/run",jr(ug),async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(!Ys(d,"runner",h))return;let{testPlan:y,initialMemory:v}=p.body,w=new Set(["setup","action","verify"]);for(let b of y.steps??[])if(!b.type||!w.has(b.type)){let x=(b.type??"").toLowerCase();b.type=x.includes("verify")?"verify":x.includes("setup")?"setup":"action"}if(!d.runner){if(d._runnerInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._runnerInitializing=!0;try{let b=d.chatSession.config?.model??Tr,x=nr(b,t);n&&(x=on(x,s,!0,(_,k,R)=>{d.sink?.emit({kind:"log",ts:Date.now(),sessionId:d.id,level:"info",source:"LLMCache",message:`${_?"HIT":"MISS"} ${k.slice(0,8)} (msgs=${R})`})}));let S=new Dr(r),A=Gs(x,r,d.seed,e,S);d.runner=new Ft(d.id,A),d.sink=A.sink,d.type="runner",d._cleanupListeners=_l(d,d.runner),d.chatSession={...d.chatSession,kind:"test_run",testPlanId:y.id},await A.chatRepo.upsertSession(d.chatSession)}finally{d._runnerInitializing=!1}}try{d.lastRunOutcome=void 0;let b=d.runner.startRun(d.chatSession,y,{initialMemory:v,onMemoryUpdate:x=>{Ue(d,{type:"memory:updated",memory:x})}});b&&typeof b.catch=="function"&&b.catch(x=>{console.error(`[Engine] startRun error for session ${d.id}:`,x.message),Ue(d,{type:"session:error",error:x.message})}),h.json({ok:!0})}catch(b){h.status(500).json({error:b.message})}}),o.post("/api/engine/session/:id/batch-run",jr(dg),async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(!Ys(d,"runner",h))return;let{plans:y,mode:v,concurrency:w,initialMemory:b,batchRunId:x}=p.body,S=new Set(["setup","action","verify"]);for(let _ of y)for(let k of _.steps??[])if(!k.type||!S.has(k.type)){let R=(k.type??"").toLowerCase();k.type=R.includes("verify")?"verify":R.includes("setup")?"setup":"action"}if(v==="sequential"&&!d.runner){if(d._runnerInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._runnerInitializing=!0;try{let _=d.chatSession.config?.model??Tr,k=nr(_,t);n&&(k=on(k,s,!0,(D,te,P)=>{d.sink?.emit({kind:"log",ts:Date.now(),sessionId:d.id,level:"info",source:"LLMCache",message:`${D?"HIT":"MISS"} ${te.slice(0,8)} (msgs=${P})`})}));let R=new Dr(r),C=Gs(k,r,d.seed,e,R);d.runner=new Ft(d.id,C),d.sink=C.sink,d.type="runner",d._cleanupListeners=_l(d,d.runner),d.chatSession={...d.chatSession,kind:"test_run"},await C.chatRepo.upsertSession(d.chatSession)}finally{d._runnerInitializing=!1}}let A=_=>{Ue(d,_)};try{let _=v==="sequential"?{runner:d.runner}:(()=>{let R=d.chatSession.config?.model??Tr,C=nr(R,t);n&&(C=on(C,s,!0,(te,P,X)=>{d.sink?.emit({kind:"log",ts:Date.now(),sessionId:d.id,level:"info",source:"LLMCache",message:`${te?"HIT":"MISS"} ${P.slice(0,8)} (msgs=${X})`})}));let D=new Dr(r);return{deps:Gs(C,r,d.seed,e,D),sessionId:d.id}})();zi(_,d.chatSession,y,{mode:v,concurrency:w,initialMemory:b,batchRunId:x},A).then(async R=>{x&&d.seed?.userId&&process.env.API_URL&&await fetch(`${process.env.API_URL}/api/sync/entities/batch-runs/${x}`,{method:"PUT",headers:qn(d.seed?.userId??"",d.seed?.userToken),body:JSON.stringify({status:R.status,updatedAt:Date.now(),endedAt:Date.now()})}).catch(()=>{})}).catch(async R=>{Ue(d,{type:"session:error",error:R.message}),x&&d.seed?.userId&&process.env.API_URL&&await fetch(`${process.env.API_URL}/api/sync/entities/batch-runs/${x}`,{method:"PUT",headers:qn(d.seed?.userId??"",d.seed?.userToken),body:JSON.stringify({status:"partial",updatedAt:Date.now(),endedAt:Date.now()})}).catch(()=>{})}),h.json({ok:!0})}catch(_){h.status(500).json({error:_.message})}}),o.post("/api/engine/session/:id/runner-message",jr(pg),async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}if(!Ys(d,"runner",h))return;let{text:y,testPlan:v}=p.body;if(!d.runner){if(d._runnerInitializing){h.status(409).json({error:"Session is initializing, retry shortly"});return}d._runnerInitializing=!0;try{let w=d.chatSession.config?.model??Tr,b=nr(w,t);n&&(b=on(b,s,!0,(A,_,k)=>{d.sink?.emit({kind:"log",ts:Date.now(),sessionId:d.id,level:"info",source:"LLMCache",message:`${A?"HIT":"MISS"} ${_.slice(0,8)} (msgs=${k})`})}));let x=new Dr(r),S=Gs(b,r,d.seed,e,x);d.runner=new Ft(d.id,S),d.sink=S.sink,d.type="runner",d._cleanupListeners=_l(d,d.runner),d.chatSession={...d.chatSession,kind:"test_run",testPlanId:v.id},await S.chatRepo.upsertSession(d.chatSession)}finally{d._runnerInitializing=!1}}try{let w=d.runner.sendMessage(d.chatSession,v,y);w&&typeof w.catch=="function"&&w.catch(b=>{console.error(`[Engine] runner sendMessage error for session ${d.id}:`,b.message),Ue(d,{type:"session:error",error:b.message})}),h.json({ok:!0})}catch(w){h.status(500).json({error:w.message})}}),o.post("/api/engine/session/:id/evaluate",jr(mg),async(p,h)=>{if(!l.get(p.params.id)){h.status(404).json({error:"Session not found"});return}let{expression:y}=p.body;try{let v=await r.evaluate(p.params.id,y);h.json({result:v})}catch(v){h.status(500).json({error:v.message})}}),o.post("/api/engine/session/:id/stop",(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}d.agent?.stop("user_stopped"),d.runner?.stop("user_stopped"),h.json({ok:!0})}),o.post("/api/engine/session/:id/reset",async(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"session_not_found"});return}if(d.type!=="runner"||!d.runner){h.status(400).json({error:"not_a_runner_session"});return}let y=p.body?.keepMemory??!0;try{await d.runner.resetForNextPlan({keepMemory:y}),d.events.length=0,h.status(200).json({ok:!0})}catch(v){if(v?.message?.includes("cannot reset while a run is in progress")){h.status(409).json({error:"run_in_progress"});return}h.status(500).json({error:"reset_failed",message:v?.message})}}),o.post("/api/engine/session/:id/credentials",(p,h)=>{let d=l.get(p.params.id);if(!d){h.status(404).json({error:"Session not found"});return}let{credentials:y}=p.body;if(!Array.isArray(y)||y.length===0){h.status(400).json({error:"credentials array required"});return}d.secretsService?.addCredentials(y);let w=[...d.seed?.credentials??[],...y];r.seedCredentials(p.params.id,w),d.seed&&(d.seed.credentials=w),console.log(`[Engine] Credentials added to session ${p.params.id}: ${y.map(b=>b.name).join(", ")}`),h.json({ok:!0,count:y.length})}),o.delete("/api/engine/session/:id",async(p,h)=>{let d=l.get(p.params.id);if(d){d.agent?.stop(),d.runner?.stop(),d._cleanupListeners?.(),d.sink?.destroy?.();for(let y of d.ws)y.close();r.clearCredentials(p.params.id),await r.cleanupSession(p.params.id),await r.cleanupSession(`${p.params.id}:child-browser`).catch(()=>{}),vr.deleteSession(p.params.id),l.delete(p.params.id)}h.json({ok:!0})}),o.post("/api/engine/chat-title",jr(hg),async(p,h)=>{let{text:d}=p.body;try{let y=`Generate a concise 3-5 word title summarizing WHAT is being tested or asked. Never include process words like "testing", "test", "verification", "check", "session", "QA", "validate". Focus only on the subject matter.
|
|
1372
1379
|
|
|
1373
1380
|
User message: "${String(d).slice(0,500)}"
|
|
1374
1381
|
|