agentiqa 1.1.19-staging.8697cbb → 1.1.19-staging.952b4d6

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.
Files changed (2) hide show
  1. package/dist/cli.js +2 -2
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1532,7 +1532,7 @@ ${a}
1532
1532
  Present the SCOPE checkpoint now. Do NOT redo discovery.`;await this.runPostBootstrapCoordinatorLoop(e,l,t)}async sendMessage(e,t,n){if(n&&n.length>0&&(this.sessionAttachments=n),this.isRunning&&(this.log("info","CoordinatorRuntime","sendMessage during active turn \u2014 interrupting",{sessionId:this.sessionId,textPreview:t.slice(0,80)}),this.emit("session:interrupt-requested",{sessionId:this.sessionId,reason:"user-followup"}),await this.stop("user_followup")),this.isRunning){this.log("warn","CoordinatorRuntime","sendMessage: still running after stop, dropping follow-up",{sessionId:this.sessionId,textPreview:t.slice(0,80)}),this.emit("session:error",{sessionId:this.sessionId,error:"sendMessage dropped \u2014 previous stop still in progress"});return}let s=await this.baseDeps.chatRepo.getSession(e.id);if(s&&(e=s),e=await this.ensureTestingEmailPolicyAttached(e),e.pauseState?.reason==="awaiting_url_correction"){let i=this.extractLatestValidUrlFromText(t);if(i){try{await this.deps.projectsRepo?.updateDefaultUrl?.(e.projectId,i)}catch(l){this.log("warn","CoordinatorRuntime","failed to persist project.defaultUrl",{error:l?.message})}let a={...e,config:{...e.config,initialUrl:i},pauseState:void 0};await this.baseDeps.chatRepo.upsertSession(a),e=a,this.log("info","CoordinatorRuntime","resuming from url-correction pause",{host:i,sessionId:e.id})}else{let a={...e,pauseState:void 0};await this.baseDeps.chatRepo.upsertSession(a),e=a}}if(e.pauseState?.reason==="awaiting_device_setup"){let i={...e,pauseState:void 0};await this.baseDeps.chatRepo.upsertSession(i),e=i}let o=this.extractLatestValidUrlFromText(t);if(o&&this.isValidDiscoveryUrl(o)&&o!==e.config.initialUrl){e={...e,config:{...e.config,initialUrl:o}};try{await this.baseDeps.chatRepo.upsertSession(e)}catch(i){this.log("warn","CoordinatorRuntime","failed to persist updated initialUrl",{error:i?.message})}}if(await this.captureChatProvidedCredentials(e,t),!await this.maybeShortCircuitForGenericTarget(e,t)&&!await this.maybeShortCircuitForSessionLoopCap(e,t)){this.beginRun(),this.resetTurnState(),this.currentTurnTiming={startedAt:Date.now(),firstVisibleLogged:!1};try{if(await this.emitSessionStart(e),this.baseDeps.sink.emit({kind:"log",ts:this.currentTurnTiming.startedAt,sessionId:this.sessionId,level:"info",source:"TurnLatencyEngine",msg:"turn_request_received",data:{startedAt:this.currentTurnTiming.startedAt,textPreview:t.slice(0,200)}}),t.match(/^\[retest:(\S+?)\]/)){this.turnIndex++,this.currentTurnGoal=t,this.currentTurnLane="coordinator",await this.ensureCoordinatorTraceLoaded(e);let f=await this.enrichWithCurationContext(e,t);await this.persistRealUserMessage(e,t,f),await this.runLoop({session:e,maxIterations:50,snapshotOnly:!1,isMobile:!1,taskDescription:t}),await this.postLoopDrain(e);return}if(this._emailWaitPause){await this.ensureCoordinatorTraceLoaded(e),this.turnIndex++,this.currentTurnGoal=t,this.currentTurnLane="coordinator",await this.persistRealUserMessage(e,t);let f=await this.tryResumeEmailVerification(e,t);if(f==="present"){await this.runLoop({session:e,maxIterations:15,snapshotOnly:!1,isMobile:!1,taskDescription:"Present findings after wait resume"}),await this.postLoopDrain(e);return}if(f==="done"){await this.postLoopDrain(e);return}await this.stripPriorTurnActionDetailFromTrace(),await this.persistConversationTrace(e,this.conversationTrace);let p=await this.tryAutoFanOutFromScope(e,t);await this.runLoop({session:e,maxIterations:p?15:50,snapshotOnly:!1,isMobile:!1,taskDescription:p?"Present findings from auto-fan-out":t}),await this.postLoopDrain(e);return}let a=await this.baseDeps.chatRepo.listMessages(e.id),l=a.filter(f=>f.role==="user").length;await this.restorePendingScopeFromTrace(e,{logNoPending:!1});let c=[...a].reverse().find(f=>f.role==="model")?.text,u=Lv(c,t);if(u){this.log("info","CoordinatorRuntime","AG-5780: menu selection \u2192 coordinator (bypassing classifier)",{selected:u.selectedIndices,optionCount:u.allOptions.length}),this.turnIndex++,this.currentTurnGoal=t,this.currentTurnLane="coordinator",this.currentTurnTiming&&(this.currentTurnTiming.lane="coordinator"),await this.ensureCoordinatorTraceLoaded(e),await this.persistRealUserMessage(e,t),this.conversationTrace.push({role:"user",parts:[{text:ou(u)}]}),await this.persistConversationTrace(e,this.conversationTrace),await this.runLoop({session:e,maxIterations:50,snapshotOnly:!1,isMobile:!1,taskDescription:ou(u)}),await this.executeCapturedScope(e);return}if(this.hasPendingScopeApproval()&&this.classifyScopeApprovalReply(t)==="approval"){this.log("info","CoordinatorRuntime","scope approval \u2192 coordinator (bypassing classifier)",{planCount:this.lastScopeData?.initial_plans?.length??0,textPreview:t.slice(0,80)}),this.turnIndex++,this.currentTurnGoal=t,this.currentTurnLane="coordinator",this.currentTurnTiming&&(this.currentTurnTiming.lane="coordinator"),await this.ensureCoordinatorTraceLoaded(e);let f=await this.applyPersistedScopeAdjustments(e);await this.persistRealUserMessage(e,t,f?`${t}
1533
1533
 
1534
1534
  [User curation context: User adjusted scope to only these areas: ${f}]`:t);let p=await this.tryAutoFanOutFromScope(e,t);await this.runLoop({session:e,maxIterations:p?15:50,snapshotOnly:!1,isMobile:!1,taskDescription:p?"Present findings from auto-fan-out":t}),await this.postLoopDrain(e);return}let d=await nu({session:e,text:t,existingUserMessageCount:l,recentMessages:a,projectDefaultUrl:e.config.initialUrl,model:this.model,sink:this.baseDeps.sink});this.currentTurnTiming&&(this.currentTurnTiming.lane=d.lane),this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:this.sessionId,level:"info",source:"TurnLatencyEngine",msg:"turn_lane_selected",data:{lane:d.lane,intent:d.intent,scope:d.scope,coveragePlanning:d.coveragePlanning,intentClassificationMs:d.timings?.intentClassificationMs,scopeClassificationMs:d.timings?.scopeClassificationMs,sinceRequestMs:this.currentTurnTiming?Date.now()-this.currentTurnTiming.startedAt:void 0}});let h=e;switch(this.turnIndex++,this.currentTurnGoal=t,this.currentTurnLane=d.lane,this.currentTurnScope=d.scope,this.currentTurnCoveragePlanning=d.coveragePlanning,await this.persistTurnIntent(e,su({turnId:this.getCurrentRunId()??ce("turn"),statedIntent:t,decision:d})),d.lane){case"answer":await this.startAnswerTurn(e,t,d.answerMode??"normal"),await this.postLoopDrain(e);return;case"explorer_direct":await this.startDirectTaskTurn(e,t),await this.postLoopDrain(e);return;case"control":throw new Error("cancelled");case"refuse":await this.ensureCoordinatorTraceLoaded(e),await this.persistRealUserMessage(e,t),await this.emitCoordinatorMessage(e,"Sorry, I can\u2019t share internal details \u2014 but I\u2019d love to help with something else. Want to test something on your app?"),await this.postLoopDrain(e);return;case"coordinator":if(l===0&&d.scope){let f=d.scope==="specific"?"specific_task_via_coordinator":"mapper_then_coordinator";h=!e.routingContext?.routingMode||e.routingContext.routingMode!==f?await this.markBootstrapState(e,{routingMode:f}):e,d.scope==="specific"?await this.startSpecificFirstTurn(h,t):await this.startBroadFirstTurn(h,t)}else{await this.ensureCoordinatorTraceLoaded(h),await this.stripPriorTurnActionDetailFromTrace(),await this.persistConversationTrace(h,this.conversationTrace);let f=await this.enrichWithCurationContext(h,t,d.taskMode);await this.persistRealUserMessage(h,t,f);let p=await this.tryAutoFanOutFromScope(h,t);await this.runLoop({session:h,maxIterations:p?15:50,snapshotOnly:!1,isMobile:!1,taskDescription:p?"Present findings from auto-fan-out":t})}await this.postLoopDrain(h);return}}catch(i){let a=String(i?.message||"");if(i?.message==="cancelled"||i?.name==="AbortError"||a.toLowerCase().includes("aborted"))this.trimDanglingToolCalls(this.conversationTrace),await this.persistConversationTrace(e,this.conversationTrace);else{this.markRunErrored(),this.log("error","CoordinatorRuntime","sendMessage error",{error:i?.message}),this.baseDeps.errorReporter?.captureException?.(i),this.trimDanglingToolCalls(this.conversationTrace),await this.persistConversationTrace(e,this.conversationTrace);let c={sessionId:e.id,id:ce("msg"),role:"model",text:`An error occurred: ${i.message??"Unknown error"}. Reply "continue" to retry.`,timestamp:Date.now()};await this.baseDeps.chatRepo.addMessage(c),this.emit("message:added",{sessionId:e.id,message:c})}}finally{this.currentTurnTiming=null,this.endRun(),this.baseDeps.sink.emit({kind:"session_end",ts:Date.now(),sessionId:this.sessionId,status:this.coordinatorSessionEndStatus()}),this.baseDeps.sink.flush(),e.projectId&&this.emit("session:coverage-requested",{sessionId:this.sessionId,projectId:e.projectId})}}}async handleCheckpoint(e,t){let{type:n,title:s}=e.args,o=e.args.data;if(n==="findings"){o=this.normalizeFindingsCheckpointData(o);let p=[...this.childStates.values()].filter(m=>m.result);if(p.length>0&&this.childReportedIssues.length===0&&p.every(m=>du(m.result))){let m=p.find(v=>du(v.result)).result;return this.log("info","CoordinatorRuntime","handleCheckpoint: all areas terminal-access-blocked \u2014 Agent Blocked",{childCount:p.length,blockKind:m.blockKind}),await this.emitAgentBlocked(t.session,m),this.turnFindingsPresented=!0,{response:{status:"agent_blocked"},done:!0,isMetaTool:!0}}}let i=p=>vr(p).replace(/^smoke:\s*/i,"").trim(),a=(p,g)=>{let m=i(p),v=i(g);return!m||!v?!1:m===v||m.includes(v)||v.includes(m)},l=p=>{let g=i(p),m;for(let v of this.childStates.values())if(i(v.label)===g){m=v;break}if(m)return m;for(let v of this.childStates.values()){let _=i(v.label);if(_.includes(g)||g.includes(_))return v}},c=p=>p?p.result?p.result.status!=="completed":!0:!1;if(n==="plan"&&o?.plans&&this.lastScopeData){let g=(await this.deps.secretsService.listProjectCredentials(t.session.projectId)).length>0;if(this.lastScopeData.needs?.some(v=>v.type==="credentials")&&!g){let v=new Set((this.lastScopeData.areas??[]).filter(_=>_.requires_auth).map(_=>_.name));for(let _ of o.plans)if(v.has(_.area)){let w="Credentials not provided \u2014 testing unauthenticated flows only";_.skip=_.skip?`${_.skip}. ${w}`:w}}}if(n==="findings"&&this.childDraftTestCases.size>0){let p=o?.tested_areas??[];o.tested_areas=[...this.childDraftTestCases.entries()].map(([g,m])=>{let v=p.find(T=>a(T.name??"",g)),_=l(g),w=v?.status==="issues_found"||c(_)?"issues_found":"clean";return{name:v?.name??g,status:w,draft_steps:m.steps??[]}})}if(n==="findings"&&o?.tested_areas){let p=[];for(let[,w]of this.childStates)w.result?.coverage&&p.push(...w.result.coverage);if(p.length>0){let w=o.tested_areas;for(let T of w){let b=(T.name??"").toLowerCase().trim(),x=p.find(S=>{let I=S.area.toLowerCase().trim();return I===b||I.includes(b)||b.includes(I)});x&&(T.coverage_tested=x.tested,T.coverage_not_tested=x.notTested)}}let g=o.tested_areas,m=(o.reported_issues??[]).length>0,v=Array.isArray(o.suggestions)&&(o.suggestions?.length??0)>0,_=[...this.childStates.values()].some(w=>!w.result||w.result.status==="blocked"||w.result.status==="error");for(let w of g){if(w?.status!=="clean")continue;let b=w.name?String(w.name):"",x=l(b),S=c(x);if(_||v||S)if(w.status="issues_found",S||_){let I=`Testing was interrupted before this area completed; retry with an accessible target URL (${t.session.config.initialUrl??"configured target"}).`;o.verdict.not_tested=[...o.verdict.not_tested??[],{area:b||"Unknown area",reason:I}],o.verdict.rationale=o.verdict.rationale||"Environment or execution issues prevented reliable validation."}else m||(o.verdict.recommendation="ship_with_known_risks")}}if(n==="findings"&&o&&this.applyIncompleteChildCoverage(o),n==="findings"&&o&&this.applyRequestedCoverageContract(o),n==="findings"&&this.childReportedIssues.length>0&&(o.reported_issues=Cn(this.childReportedIssues)),n==="findings"){let p=await this.loadKnownOpenReportedIssuesForTurn(t,o?.tested_areas);p.length>0&&(o?.reported_issues?.length??0)===0&&(o.reported_issues=p);let v=[...this.childStates.values()].map(_=>_.result?.status).some(_=>_==="blocked"||_==="error")||(o?.reported_issues?.length??0)>0;if(v&&o?.verdict?.recommendation==="ship"){o.verdict.recommendation="conditional_ship";let _=`${o.verdict.rationale??""}`;_.toLowerCase().includes("known")?o.verdict.rationale=_.trim():o.verdict.rationale=`${_} Known issue(s) persist from the prior run.`.trim()}if((o?.tested_areas?.length??0)>0&&v)for(let _ of o.tested_areas)vr(_.status)==="clean"&&(_.status="issues_found")}if(n==="scope"&&o){let p=typeof t.session.config?.initialUrl=="string"&&t.session.config.initialUrl!=="about:blank"&&this.isValidDiscoveryUrl(t.session.config.initialUrl)?t.session.config.initialUrl:void 0;this.applyLatestExplicitUrlToScopeData(o,p);let m=(await this.deps.secretsService.listProjectCredentials(t.session.projectId)).length>0;if(Array.isArray(o.areas)&&Array.isArray(o.initial_plans)){let _=this.currentTurnScope==="specific"&&o.initial_plans.some(T=>T?.authSurfaceKind==="signup"),w=ob({areas:o.areas,initialPlans:o.initial_plans,hasProjectCredentials:m,preserveSignupWithCredentials:_});w.decision!=="no_change"&&this.log("info","CoordinatorRuntime","signup+login scope rewrite applied",{decision:w.decision,affected:w.affectedAreaNames,hasCredentials:m,preserveSignupWithCredentials:_}),o.areas=w.areas,o.initial_plans=w.initialPlans}this.currentTurnCoveragePlanning&&(o.show_requested_coverage=!0),this.lastScopeData=o,this.log("info","CoordinatorRuntime","lastScopeData captured",{sessionId:t.session.id,areaCount:Array.isArray(o?.areas)?o.areas.length:0,planCount:Array.isArray(o?.initial_plans)?o.initial_plans.length:0}),this.scopeCheckpointPresented=!0;let v=new Map;for(let _ of this.childStates.values()){let w=_.result?.notices;if(w)for(let T of w)v.has(T.kind)||v.set(T.kind,T)}if(v.size>0){let _=Array.isArray(o.notices)?o.notices:[];o.notices=[..._,...v.values()]}if(o.initial_plans&&o.needs?.some(w=>w.type==="credentials")&&!m){let w=new Set((o.areas??[]).filter(T=>T.requires_auth).map(T=>T.name));for(let T of o.initial_plans)if(w.has(T.area)){let b="Credentials not provided \u2014 testing unauthenticated flows only";T.skip=T.skip?`${T.skip}. ${b}`:b}}}if(n==="scope"&&(await this.persistScopeCheckpointToAppMap(t.session,o,t),o&&typeof o=="object"))try{let p=await this.deps.secretsService.listProjectCredentials(t.session.projectId);o.hasExistingCredentials=p.length>0}catch{}let u=n==="scope"&&xa(t.session),d=t.session.config.autoApprove===!0&&n!=="findings"&&!u,h={sessionId:t.session.id,id:ce("msg"),role:"model",text:s||`${n} checkpoint`,timestamp:Date.now(),actionName:"present_checkpoint",actionArgs:{type:n,title:s,data:o,...(d||u)&&{autoApproved:!0},...u&&{autoRunActive:!0}}};return await this.baseDeps.chatRepo.addMessage(h),this.emit("message:added",{sessionId:this.sessionId,message:h}),n==="findings"&&(this.turnFindingsPresented=!0),d?{response:{status:"auto_approved",type:n,message:"Checkpoint auto-approved (autopilot mode). Continue immediately."},done:!1,isMetaTool:!0}:{response:n==="scope"&&this.lastScopeData?{status:"awaiting_curation",instruction:"When the user approves, use ONLY the areas and plans listed below to spawn Explorers. Do NOT add pages, links, or features not listed here. If the user supplied or corrected an exact same-origin URL/path, preserve that path in the matching child prompt and scope.",approved_areas:this.lastScopeData.areas,approved_plans:this.lastScopeData.initial_plans}:{status:"awaiting_curation"},done:!0,isMetaTool:!0}}async loadKnownOpenReportedIssuesForTurn(e,t){if(!t||t.length===0)return[];let s=[...await this.baseDeps.chatRepo.listMessages(e.session.id)].reverse().find(c=>c.role==="model"&&c.actionName==="present_checkpoint"&&c.actionArgs?.type==="findings"),o=s?.actionArgs?.data??{};if(!s||!o.reported_issues)return[];let i=o.reported_issues??[],a=s.actionArgs.issueDecisions??void 0,l=i.filter(c=>{let u=RO(`${c.title} ${(c.description??"").toLowerCase()}`,t.map(h=>`${h.name??""}`));return(c.id?a?.[c.id]:void 0)==="dismissed"?!1:u});return Cn(l)}async handleAskUser(e,t){let{question:n,context:s}=e.args,o=t.session.config.autoApprove===!0,i={sessionId:t.session.id,id:ce("msg"),role:"model",text:n,timestamp:Date.now(),actionName:"ask_user",actionArgs:{question:n,context:s,...o&&{autoApproved:!0}}};return await this.baseDeps.chatRepo.addMessage(i),this.emit("message:added",{sessionId:this.sessionId,message:i}),o?{response:{status:"auto_skipped",message:"Running in autopilot mode \u2014 no user available. Use your best judgment and continue."},done:!1,isMetaTool:!0}:{response:{status:"awaiting_response"},done:!0,isMetaTool:!0}}async handleListTestPlans(e,t){return{response:{plans:(await this.deps.testPlanV2Repo?.list?.(t.session.projectId)??[]).map(s=>({id:s.id,title:s.title,stepCount:s.steps?.length}))},isMetaTool:!0}}async handleLoadTestPlan(e,t){let n=await this.deps.testPlanV2Repo?.get?.(e.args.id)??null;return{response:n?{plan:n}:{error:"Test plan not found"},isMetaTool:!0}}async handleSaveTestPlan(e,t){let{id:n,title:s,steps:o}=e.args,i=aa(o,ws(this.sessionAttachments)),{steps:a,authMode:l}=fa(i??[],{authModeHint:e.args.authMode}),c={id:n||ce("tp"),projectId:t.session.projectId,title:s,steps:a,authMode:l,createdAt:Date.now(),updatedAt:Date.now()};return await this.deps.testPlanV2Repo?.upsert?.(c),{response:{status:"saved",planId:c.id},isMetaTool:!0}}async handleGetRunResults(e,t){let n=await this.deps.testPlanV2RunRepo?.get?.(e.args.run_id)??null;return{response:n?{run:n}:{error:"Run not found"},isMetaTool:!0}}async handleListRuns(e,t){let n=await this.deps.testPlanV2RunRepo?.list?.(e.args.test_plan_id)??[],s=e.args.limit??5;return{response:{runs:n.slice(0,s).map(o=>({id:o.id,status:o.status,createdAt:o.createdAt,endedAt:o.endedAt,summary:o.summary,stepCount:o.stepResults?.length}))},isMetaTool:!0}}async persistScopeCheckpointToAppMap(e,t,n){let s=Array.isArray(t?.areas)?t.areas:[];if(s.length===0||!e.projectId||!this.deps.appMapRepo)return;let o=typeof e.config?.initialUrl=="string"&&e.config.initialUrl.trim()?e.config.initialUrl.trim():void 0,i=s.map(a=>{let l=String(a?.name??"").trim();if(!l)return null;let c=typeof a?.url=="string"&&a.url.trim()?a.url.trim():o;return{id:ub(l,c),name:l,url:c,kind:"page",auth_required:a?.requires_auth===!0,entities:[]}}).filter(Boolean);i.length!==0&&await this.handleUpdateAppMap({name:"update_app_map",args:{add_surfaces:i}},n)}collectChildCoverage(){let e=[];for(let[,t]of this.childStates)t.result?.coverage&&e.push(...t.result.coverage);return e}async persistFocusedTaskToAppMap(e,t,n){let s=t.trim();if(!s||!e.projectId||!this.deps.appMapRepo)return;let o=typeof e.config?.initialUrl=="string"&&e.config.initialUrl.trim()?e.config.initialUrl.trim():void 0,i={id:ub(s,o),name:s,url:o,kind:"page",auth_required:!1,entities:[],...n.trim()?{description:n.trim().slice(0,400)}:{}};await this.handleUpdateAppMap({name:"update_app_map",args:{add_surfaces:[i]}},this.buildBootstrapContext(e))}async handleUpdateAppMap(e,t){let n=t.session.projectId;if(!n||!this.deps.appMapRepo)return{response:"AppMap not available \u2014 no project context or repo configured",isMetaTool:!0};let s=await this.deps.appMapRepo.get(n)??{surfaces:[],entities:[],flows:[]},o=e.args,i=new Set(s.surfaces.map(h=>h.id)),a=new Set(s.entities.map(h=>h.id)),l=new Set(s.flows.map(h=>h.id)),c=(h,f)=>{let p=new Set,g=0;for(let m of h??[])!m.id||f.has(m.id)||p.has(m.id)||(p.add(m.id),g+=1);return g},u=ql(s,o);for(let h of u.surfaces)h.lastSeenInSession||(h.lastSeenInSession=this.sessionId);for(let h of u.entities)h.lastSeenInSession||(h.lastSeenInSession=this.sessionId);for(let h of u.flows)h.lastSeenInSession||(h.lastSeenInSession=this.sessionId);await this.deps.appMapRepo.save(n,u);let d={surfacesAdded:c(o.add_surfaces,i),entitiesAdded:c(o.add_entities,a),flowsAdded:c(o.add_flows,l),statesUpdated:o.update_entity_states?.length??0};return this.log("info","QAModel","AppMap updated",{delta:d,totalSurfaces:u.surfaces.length,totalEntities:u.entities.length,totalFlows:u.flows.length,removed:o.remove?.length??0}),this.currentTurnAppMapDelta.surfacesAdded+=d.surfacesAdded,this.currentTurnAppMapDelta.entitiesAdded+=d.entitiesAdded,this.currentTurnAppMapDelta.flowsAdded+=d.flowsAdded,this.currentTurnAppMapDelta.statesUpdated+=d.statesUpdated,{response:`AppMap updated: +${d.surfacesAdded} surfaces, +${d.entitiesAdded} entities, +${d.flowsAdded} flows, ${d.statesUpdated} entity state updates. Total: ${u.surfaces.length} surfaces, ${u.entities.length} entities, ${u.flows.length} flows.`,isMetaTool:!0}}async handleReadAppMap(e,t){let n=t.session.projectId;if(!n||!this.deps.appMapRepo)return{response:"AppMap not available",isMetaTool:!0};let s=await this.deps.appMapRepo.get(n);return{response:JSON.stringify(s??{surfaces:[],entities:[],flows:[]}),isMetaTool:!0}}async handleRememberForUser(e,t){let n=t.session.projectId,s=String(e.args?.text??"").trim();if(!n||!s||!this.deps.memoryRepo?.upsert)return{response:"Could not save \u2014 no project context or text provided",isMetaTool:!0};let o={id:ce("mem"),projectId:n,text:s,source:"user",createdAt:Date.now(),updatedAt:Date.now()};return await this.deps.memoryRepo.upsert(o),{response:`Saved to project memory: "${s}"`,isMetaTool:!0}}async handleCallServiceEndpoint(e,t){let n=t.session.projectId;if(!n||!this.deps.appMapRepo)return{response:"Service endpoints not available \u2014 no project context",isMetaTool:!0};let s=String(e.args?.entity_id??""),o=String(e.args?.endpoint_name??""),i=e.args?.body_overrides??{},a=await this.deps.appMapRepo.get(n);if(!a)return{response:"No AppMap found for this project",isMetaTool:!0};let l=a.entities.find(h=>h.id===s);if(!l)return{response:`Entity "${s}" not found in AppMap`,isMetaTool:!0};let c=l.service_endpoints?.find(h=>h.name===o);if(!c)return{response:`Endpoint "${o}" not found on entity "${l.name}". Available: ${(l.service_endpoints??[]).map(h=>h.name).join(", ")||"none"}`,isMetaTool:!0};let u={"Content-Type":"application/json"};c.auth&&(u.Authorization=c.auth);let d=c.body?{...c.body,...i}:i;this.log("info","QAModel","Calling service endpoint",{entityId:s,endpointName:o,method:c.method,url:c.url,sets_state:c.sets_state});try{let h=await fetch(c.url,{method:c.method,headers:u,...c.method!=="GET"&&Object.keys(d).length>0?{body:JSON.stringify(d)}:{}}),f=await h.text().catch(()=>""),p;try{p=JSON.parse(f)}catch{p=f}if(h.ok){let g=l.states.find(m=>m.name===c.sets_state);g&&(g.reachable=!0,g.setup_hint=`Via service endpoint: ${c.name}`,await this.deps.appMapRepo.save(n,a))}return{response:`${c.method} ${c.url} \u2192 ${h.status} ${h.statusText}
1535
- ${typeof p=="string"?p.slice(0,500):JSON.stringify(p,null,2).slice(0,500)}`,isMetaTool:!0}}catch(h){return{response:`Failed to call ${c.method} ${c.url}: ${h?.message}`,isMetaTool:!0}}}async handleResolveIssue(e,t){let n=String(e.args?.issue_id??""),s=String(e.args?.reason??"");if(!n)return{response:"No issue ID provided",isMetaTool:!0};let o=t.session.projectId,a=(await this.deps.issuesRepo.list(o)).find(c=>c.id===n);if(!a)return{response:`Issue "${n}" not found`,isMetaTool:!0};let l=a.status==="confirmed"?"resolved":"dismissed";return await this.deps.issuesRepo.upsert({...a,status:l,resolvedAt:Date.now(),updatedAt:Date.now()}),this.log("info","QAModel","Issue resolved via re-test",{issueId:n,previousStatus:a.status,newStatus:l,reason:s}),{response:`Issue "${a.title}" marked as ${l}. Reason: ${s}`,isMetaTool:!0}}formatTimeAgo(e){let t=Date.now()-e,n=Math.round(t/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;let s=Math.round(n/60);if(s<24)return`${s}h ago`;let o=Math.round(s/24);return o===1?"1 day ago":`${o} days ago`}async inferRequiredCapabilitiesForSpawn(e){let t=await cu({spawnArgs:{prompt:e}},{model:this.model,log:(n,s,o)=>this.log(n,"CoordinatorRuntime",s,o)});return t.provenance.requiredCapabilities==="legacy_prompt_detector"?t.requiredCapabilities:[]}getAvailableCapabilities(e){return DO(e.config.availableCapabilities?.capabilities)}requiredCapabilitiesMissing(e,t){return $v(e,t)}makeMissingCapabilityMessage(e){let t=n=>n.replace(/_/g," ");return[`I can't start browser automation for this step because required capability${e.length>1?"s":""} are unavailable: ${e.map(t).join(", ")}.`,"I can continue if you switch to a supported in-browser verification path (for example, validating the page state only), or run this from an environment that exposes that capability."].join(" ")}async normalizeAreaIntentForSpawn(e,t,n={}){let s=typeof e.args.prompt=="string"?e.args.prompt:void 0,o=this.readSpawnScope(e.args.scope),i={spawnArgs:{authMode:this.readAreaAuthMode(e.args.authMode),tests_logged_out:e.args.tests_logged_out===!0,authSurfaceKind:this.readAreaAuthSurfaceKind(e.args.authSurfaceKind),isDiscovery:e.args.is_discovery===!0,startUrl:o?.[0],scope:o,identityPosture:this.readAreaIdentityPosture(e.args.identityPosture),prompt:s,requiredCapabilities:e.args.requiredCapabilities,allowExternalNavigation:e.args.allowExternalNavigation}},a=n.legacyCapabilities===!0?await cu(i,{model:this.model,log:(l,c,u)=>this.log(l,"CoordinatorRuntime",c,u)}):lu(i);return this.enrichAreaIntentFromSession(a,t)}reResolveAreaIntentForSpawn(e,t){let n=this.revealedFactsForSpawn(e);return n.length===0?t:rb({base:t,revealedFacts:n})}revealedFactsForSpawn(e){let t=this.readSpawnScope(e.args.scope);return t?.length?this.revealedFactLedger.filter(n=>n.provenance==="runtime_observed"&&this.scopesOverlap(t,n.scope)):[]}scopesOverlap(e,t){if(!t?.length)return!1;let n=new Set(t);return e.some(s=>n.has(s))}writeRequiredCapabilitiesToSpawnArgs(e,t){t.length?e.args.requiredCapabilities={capabilities:t}:delete e.args.requiredCapabilities}writeResolvedAuthIntentToSpawnArgs(e,t){t.authMode?e.args.authMode=t.authMode:delete e.args.authMode,t.authMode==="under_test"?e.args.tests_logged_out=!0:t.authMode==="precondition"&&delete e.args.tests_logged_out}spawnDedupDiscriminator(e,t){let n=e.args.requiredCapabilities?.capabilities;return{authMode:t.authMode,startState:t.startState,isDiscovery:t.isDiscovery,scope:t.scope,requiredCapabilities:Array.isArray(n)?[...n].sort():void 0,allowExternalNavigation:t.allowExternalNavigation,authSurfaceKind:t.authSurfaceKind,identityPosture:t.identityPosture}}readAreaAuthMode(e){return e==="precondition"||e==="under_test"?e:void 0}readAreaAuthSurfaceKind(e){return e==="login"||e==="signup"||e==="logout"||e==="password_reset"||e==="authenticated_area"?e:void 0}readAreaIdentityPosture(e){return e==="project_credential"||e==="canonical_test_identity"||e==="user_provided_identity"?e:void 0}enrichAreaIntentFromSession(e,t){return e.identityPosture||!t?.config.userProvidedTestEmail?e:{...e,identityPosture:"user_provided_identity",provenance:{...e.provenance,identityPosture:"runtime_state"}}}modeAAuthSurfaceRequiresLogin(e){return e.authSurfaceKind==="authenticated_area"||e.authSurfaceKind==="login"||e.authSurfaceKind==="signup"}readSpawnScope(e){if(!Array.isArray(e))return;let t=e.map(n=>String(n).trim()).filter(Boolean);return t.length>0?t:void 0}cloneAreaIntent(e){return{...e,requiredCapabilities:[...e.requiredCapabilities],provenance:{...e.provenance}}}async persistTurnIntent(e,t){this.currentTurnIntent=t,e.turnIntent=t,await this.baseDeps.chatRepo.updateSessionFields(e.id,{turnIntent:t})}async appendChildIntent(e,t){this.currentTurnIntent&&await this.persistTurnIntent(e,{...this.currentTurnIntent,childIntents:[...this.currentTurnIntent.childIntents,t]})}async resolveLiveChildAuthContext(e,t){let[n,s]=await Promise.all([this.deps.secretsService.listProjectCredentials(e.projectId).catch(()=>[]),this.deps.computerUseService?.getProjectProfile?.(e.projectId)?.catch(()=>null)??Promise.resolve(null)]);return s&&this.log("info","CoordinatorRuntime","authPrepass:profile_available_for_child",{projectId:e.projectId}),No({projectId:e.projectId,runKind:"live_child",sessionConfig:e.config,areaIntent:t,projectCredentials:n,capturedProfile:s})}async setupChildAgent(e,t,n,s,o,i,a){let{prompt:l,scope:c,context:u,max_iterations:d}=o.args,h=a??await this.normalizeAreaIntentForSpawn(o,s.session),f=h.requiredCapabilities.includes("email_verification"),p=this.readSpawnScope(c),m=p?.[0]??h.startUrl,v=f&&m?Ia({area:o.args.label,url:m,focus:["email verification"]},p??[m]):p;f&&v!==p&&this.log("info","CoordinatorRuntime","spawn_agent: broadened scope for email_verification child",{childId:e,label:o.args.label,rawScope:c,broadenedScope:v}),v&&v!==p&&(h={...h,scope:v,startUrl:h.startUrl??v[0]});let _=h.isDiscovery===!0,w=h.requiredCapabilities.length?{capabilities:h.requiredCapabilities}:void 0,T={chatRepo:this.baseDeps.chatRepo,model:this.baseDeps.model,computerUseService:this.deps.computerUseService,authService:this.baseDeps.authService,sink:this.baseDeps.sink,sessionMetaExtras:this.baseDeps.sessionMetaExtras,issuesRepo:this.deps.issuesRepo,memoryRepo:this.deps.memoryRepo,secretsService:this.deps.secretsService,mobileMcpService:this.baseDeps.mobileMcpService,imageStorageService:this.baseDeps.imageStorageService,screencastService:this.baseDeps.screencastService,errorReporter:this.baseDeps.errorReporter,supervisorService:this.baseDeps.supervisorService,deviceManagementService:this.baseDeps.deviceManagementService,emailService:this.baseDeps.emailService,createVideoRecorder:this.baseDeps.createVideoRecorder,uploadVideo:this.baseDeps.uploadVideo,testPlanV2RunRepo:this.deps.testPlanV2RunRepo??null,isChildAgent:!0,isDiscoveryRun:_,getExtensionManifest:this.deps.getExtensionManifest,attachmentStorageService:this.baseDeps.attachmentStorageService},b=i??`${this.sessionId}:${e}`,x=new xs(b,T),S=oe=>ee=>this.emit(oe,{...ee,sessionId:this.sessionId,childAgent:t,traceId:n});x.on("message:added",oe=>{if(oe.message?.role==="user")return;let ee={...oe.message,sessionId:this.sessionId,childAgent:t,traceId:n},K=oe.screenshotBase64?{screenshotBase64:oe.screenshotBase64}:void 0;this.baseDeps.chatRepo.addMessage(ee,K).catch(()=>{}),oe.screenshotBase64&&oe.message?.hasScreenshot&&this.baseDeps.imageStorageService&&this.baseDeps.imageStorageService.save({projectId:s.session.projectId,sessionId:this.sessionId,messageId:ee.id,type:"message",base64:oe.screenshotBase64}).catch(()=>{}),S("message:added")({...oe,message:ee})}),x.on("action:progress",S("action:progress")),x.on("benchmark:milestone",S("benchmark:milestone")),x.on("screencast:frame",S("screencast:frame")),x.on("screencast:started",S("screencast:started")),x.on("screencast:stopped",S("screencast:stopped"));let I=h.startUrl,k=h.identityPosture==="user_provided_identity",E=s.session.config.userProvidedTestEmail,P=await this.resolveLiveChildAuthContext(s.session,h),j={...Fv(s.session.config,{inheritInitialUrl:!!i,overrideInitialUrl:I,browserNavigationScope:v,allowExternalNavigation:h.allowExternalNavigation,requiredCapabilities:w,testingEmailPolicy:k||_?null:s.session.config.testingEmailPolicy,userProvidedTestEmail:E,isDiscoveryRun:_,forceLoggedOut:P.forceLoggedOut}),...P.sessionConfigPatch},B={...s.session,id:b,kind:"assistant_v2",config:j,conversationTrace:void 0,contextSummary:void 0,lastTokenCount:void 0},C=l,F=s.session.config.userProvidedTestEmail,W=null;if(F)try{W=(await this.deps.secretsService.listProjectCredentials(s.session.projectId))[0]?.name??null}catch{}let U=this.modeAAuthSurfaceRequiresLogin(h),he=!!(F&&W)&&U&&!_?"login":"none";return he==="login"&&(C=`\u2550\u2550\u2550 MODE A \u2014 USER-PROVIDED IDENTITY (deterministic login override at dispatch) \u2550\u2550\u2550
1535
+ ${typeof p=="string"?p.slice(0,500):JSON.stringify(p,null,2).slice(0,500)}`,isMetaTool:!0}}catch(h){return{response:`Failed to call ${c.method} ${c.url}: ${h?.message}`,isMetaTool:!0}}}async handleResolveIssue(e,t){let n=String(e.args?.issue_id??""),s=String(e.args?.reason??"");if(!n)return{response:"No issue ID provided",isMetaTool:!0};let o=t.session.projectId,a=(await this.deps.issuesRepo.list(o)).find(c=>c.id===n);if(!a)return{response:`Issue "${n}" not found`,isMetaTool:!0};let l=a.status==="confirmed"?"resolved":"dismissed";return await this.deps.issuesRepo.upsert({...a,status:l,resolvedAt:Date.now(),updatedAt:Date.now()}),this.log("info","QAModel","Issue resolved via re-test",{issueId:n,previousStatus:a.status,newStatus:l,reason:s}),{response:`Issue "${a.title}" marked as ${l}. Reason: ${s}`,isMetaTool:!0}}formatTimeAgo(e){let t=Date.now()-e,n=Math.round(t/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;let s=Math.round(n/60);if(s<24)return`${s}h ago`;let o=Math.round(s/24);return o===1?"1 day ago":`${o} days ago`}async inferRequiredCapabilitiesForSpawn(e){let t=await cu({spawnArgs:{prompt:e}},{model:this.model,log:(n,s,o)=>this.log(n,"CoordinatorRuntime",s,o)});return t.provenance.requiredCapabilities==="legacy_prompt_detector"?t.requiredCapabilities:[]}getAvailableCapabilities(e){return DO(e.config.availableCapabilities?.capabilities)}requiredCapabilitiesMissing(e,t){return $v(e,t)}makeMissingCapabilityMessage(e){let t=n=>n.replace(/_/g," ");return[`I can't start browser automation for this step because required capability${e.length>1?"s":""} are unavailable: ${e.map(t).join(", ")}.`,"I can continue if you switch to a supported in-browser verification path (for example, validating the page state only), or run this from an environment that exposes that capability."].join(" ")}async normalizeAreaIntentForSpawn(e,t,n={}){let s=typeof e.args.prompt=="string"?e.args.prompt:void 0,o=this.readSpawnScope(e.args.scope),i={spawnArgs:{authMode:this.readAreaAuthMode(e.args.authMode),tests_logged_out:e.args.tests_logged_out===!0,authSurfaceKind:this.readAreaAuthSurfaceKind(e.args.authSurfaceKind),isDiscovery:e.args.is_discovery===!0,startUrl:o?.[0],scope:o,identityPosture:this.readAreaIdentityPosture(e.args.identityPosture),prompt:s,requiredCapabilities:e.args.requiredCapabilities,allowExternalNavigation:e.args.allowExternalNavigation}},a=n.legacyCapabilities===!0?await cu(i,{model:this.model,log:(l,c,u)=>this.log(l,"CoordinatorRuntime",c,u)}):lu(i);return this.enrichAreaIntentFromSession(a,t)}reResolveAreaIntentForSpawn(e,t){let n=this.revealedFactsForSpawn(e);return n.length===0?t:rb({base:t,revealedFacts:n})}revealedFactsForSpawn(e){let t=this.readSpawnScope(e.args.scope);return t?.length?this.revealedFactLedger.filter(n=>n.provenance==="runtime_observed"&&this.scopesOverlap(t,n.scope)):[]}scopesOverlap(e,t){if(!t?.length)return!1;let n=new Set(t);return e.some(s=>n.has(s))}writeRequiredCapabilitiesToSpawnArgs(e,t){t.length?e.args.requiredCapabilities={capabilities:t}:delete e.args.requiredCapabilities}spawnDedupDiscriminator(e,t){let n=e.args.requiredCapabilities?.capabilities;return{authMode:t.authMode,startState:t.startState,isDiscovery:t.isDiscovery,scope:t.scope,requiredCapabilities:Array.isArray(n)?[...n].sort():void 0,allowExternalNavigation:t.allowExternalNavigation,authSurfaceKind:t.authSurfaceKind,identityPosture:t.identityPosture}}readAreaAuthMode(e){return e==="precondition"||e==="under_test"?e:void 0}readAreaAuthSurfaceKind(e){return e==="login"||e==="signup"||e==="logout"||e==="password_reset"||e==="authenticated_area"?e:void 0}readAreaIdentityPosture(e){return e==="project_credential"||e==="canonical_test_identity"||e==="user_provided_identity"?e:void 0}enrichAreaIntentFromSession(e,t){return e.identityPosture||!t?.config.userProvidedTestEmail?e:{...e,identityPosture:"user_provided_identity",provenance:{...e.provenance,identityPosture:"runtime_state"}}}modeAAuthSurfaceRequiresLogin(e){return e.authSurfaceKind==="authenticated_area"||e.authSurfaceKind==="login"||e.authSurfaceKind==="signup"}readSpawnScope(e){if(!Array.isArray(e))return;let t=e.map(n=>String(n).trim()).filter(Boolean);return t.length>0?t:void 0}cloneAreaIntent(e){return{...e,requiredCapabilities:[...e.requiredCapabilities],provenance:{...e.provenance}}}async persistTurnIntent(e,t){this.currentTurnIntent=t,e.turnIntent=t,await this.baseDeps.chatRepo.updateSessionFields(e.id,{turnIntent:t})}async appendChildIntent(e,t){this.currentTurnIntent&&await this.persistTurnIntent(e,{...this.currentTurnIntent,childIntents:[...this.currentTurnIntent.childIntents,t]})}async resolveLiveChildAuthContext(e,t){let[n,s]=await Promise.all([this.deps.secretsService.listProjectCredentials(e.projectId).catch(()=>[]),this.deps.computerUseService?.getProjectProfile?.(e.projectId)?.catch(()=>null)??Promise.resolve(null)]);return s&&this.log("info","CoordinatorRuntime","authPrepass:profile_available_for_child",{projectId:e.projectId}),No({projectId:e.projectId,runKind:"live_child",sessionConfig:e.config,areaIntent:t,projectCredentials:n,capturedProfile:s})}async setupChildAgent(e,t,n,s,o,i,a){let{prompt:l,scope:c,context:u,max_iterations:d}=o.args,h=a??await this.normalizeAreaIntentForSpawn(o,s.session),f=h.requiredCapabilities.includes("email_verification"),p=this.readSpawnScope(c),m=p?.[0]??h.startUrl,v=f&&m?Ia({area:o.args.label,url:m,focus:["email verification"]},p??[m]):p;f&&v!==p&&this.log("info","CoordinatorRuntime","spawn_agent: broadened scope for email_verification child",{childId:e,label:o.args.label,rawScope:c,broadenedScope:v}),v&&v!==p&&(h={...h,scope:v,startUrl:h.startUrl??v[0]});let _=h.isDiscovery===!0,w=h.requiredCapabilities.length?{capabilities:h.requiredCapabilities}:void 0,T={chatRepo:this.baseDeps.chatRepo,model:this.baseDeps.model,computerUseService:this.deps.computerUseService,authService:this.baseDeps.authService,sink:this.baseDeps.sink,sessionMetaExtras:this.baseDeps.sessionMetaExtras,issuesRepo:this.deps.issuesRepo,memoryRepo:this.deps.memoryRepo,secretsService:this.deps.secretsService,mobileMcpService:this.baseDeps.mobileMcpService,imageStorageService:this.baseDeps.imageStorageService,screencastService:this.baseDeps.screencastService,errorReporter:this.baseDeps.errorReporter,supervisorService:this.baseDeps.supervisorService,deviceManagementService:this.baseDeps.deviceManagementService,emailService:this.baseDeps.emailService,createVideoRecorder:this.baseDeps.createVideoRecorder,uploadVideo:this.baseDeps.uploadVideo,testPlanV2RunRepo:this.deps.testPlanV2RunRepo??null,isChildAgent:!0,isDiscoveryRun:_,getExtensionManifest:this.deps.getExtensionManifest,attachmentStorageService:this.baseDeps.attachmentStorageService},b=i??`${this.sessionId}:${e}`,x=new xs(b,T),S=oe=>ee=>this.emit(oe,{...ee,sessionId:this.sessionId,childAgent:t,traceId:n});x.on("message:added",oe=>{if(oe.message?.role==="user")return;let ee={...oe.message,sessionId:this.sessionId,childAgent:t,traceId:n},K=oe.screenshotBase64?{screenshotBase64:oe.screenshotBase64}:void 0;this.baseDeps.chatRepo.addMessage(ee,K).catch(()=>{}),oe.screenshotBase64&&oe.message?.hasScreenshot&&this.baseDeps.imageStorageService&&this.baseDeps.imageStorageService.save({projectId:s.session.projectId,sessionId:this.sessionId,messageId:ee.id,type:"message",base64:oe.screenshotBase64}).catch(()=>{}),S("message:added")({...oe,message:ee})}),x.on("action:progress",S("action:progress")),x.on("benchmark:milestone",S("benchmark:milestone")),x.on("screencast:frame",S("screencast:frame")),x.on("screencast:started",S("screencast:started")),x.on("screencast:stopped",S("screencast:stopped"));let I=h.startUrl,k=h.identityPosture==="user_provided_identity",E=s.session.config.userProvidedTestEmail,P=await this.resolveLiveChildAuthContext(s.session,h),j={...Fv(s.session.config,{inheritInitialUrl:!!i,overrideInitialUrl:I,browserNavigationScope:v,allowExternalNavigation:h.allowExternalNavigation,requiredCapabilities:w,testingEmailPolicy:k||_?null:s.session.config.testingEmailPolicy,userProvidedTestEmail:E,isDiscoveryRun:_,forceLoggedOut:P.forceLoggedOut}),...P.sessionConfigPatch},B={...s.session,id:b,kind:"assistant_v2",config:j,conversationTrace:void 0,contextSummary:void 0,lastTokenCount:void 0},C=l,F=s.session.config.userProvidedTestEmail,W=null;if(F)try{W=(await this.deps.secretsService.listProjectCredentials(s.session.projectId))[0]?.name??null}catch{}let U=this.modeAAuthSurfaceRequiresLogin(h),he=!!(F&&W)&&U&&!_?"login":"none";return he==="login"&&(C=`\u2550\u2550\u2550 MODE A \u2014 USER-PROVIDED IDENTITY (deterministic login override at dispatch) \u2550\u2550\u2550
1536
1536
  The user provided their OWN credential. LOG IN as them FIRST using the stored credential, THEN continue with the task instructions below. Do NOT stop at login when the task has more steps \u2014 logging in is the first step, not the whole job.
1537
1537
  Hard rules that always apply here: do NOT sign up, do NOT create an account, do NOT submit a registration form (account creation needs the user's explicit consent); the credential IS the identity, so never substitute a canonical or testing email; NEVER call check_email (the user owns this inbox); do NOT tokenize or randomize the credential (login reuses the same email and password every run).
1538
1538
 
@@ -1555,7 +1555,7 @@ If you encounter a link outside this scope, record the link target and report th
1555
1555
  CONTEXT FROM PRIOR AGENTS:
1556
1556
  ${u}`),d&&(C+=`
1557
1557
 
1558
- ITERATION BUDGET: ${d} (wrap up before this limit)`),{child:x,childSession:B,childPrompt:C,overrideVariant:he}}async handleSpawnAgent(e,t){let{type:n,prompt:s}=e.args,o=typeof s=="string"?s:"";if(n==="runner")return this.handleSpawnRunner(e,t);let i=!!e.args.background,a=Yv({scopeIsKnown:this.scopeCheckpointPresented,sessionInitialUrl:t.session.config?.initialUrl,llmIsDiscoveryFlag:e.args.is_discovery===!0,taskScopeIsSpecific:this.currentTurnScope==="specific"});a.forceDiscovery&&(this.log("info","CoordinatorRuntime","spawn_agent: forcing is_discovery=true on pre-scope broad-intent spawn",{label:e.args.label,sessionInitialUrl:t.session.config?.initialUrl,reason:a.reason}),e.args.is_discovery=!0);let l=await this.normalizeAreaIntentForSpawn(e,t.session,{legacyCapabilities:!0});l=this.reResolveAreaIntentForSpawn(e,l),this.writeResolvedAuthIntentToSpawnArgs(e,l);let c=l.requiredCapabilities;this.writeRequiredCapabilitiesToSpawnArgs(e,c);let u=this.getAvailableCapabilities(t.session),d=this.requiredCapabilitiesMissing(c,u);if(d.length>0)return this.log("warn","CoordinatorRuntime","Spawn blocked by unavailable capability",{label:e.args.label,requiredCapabilities:c,availableCapabilities:u}),{response:this.makeMissingCapabilityMessage(d),isMetaTool:!0};if(c.includes("email_verification")&&l.identityPosture!=="user_provided_identity"&&!bt(t.session.config)?.canCheckInbox)return this.log("warn","CoordinatorRuntime","Spawn blocked by missing testing email policy",{label:e.args.label,requiredCapabilities:c,availableCapabilities:u}),{response:"I cannot start account creation or email verification because no reachable canonical testing inbox is configured for this session. I must not invent placeholder email addresses.",isMetaTool:!0};if(l.isDiscovery&&this.deps.appMapRepo){let k=t.session.projectId,E=k?await this.deps.appMapRepo.get(k):null;if(E&&E.surfaces.length>0)return this.log("info","QAModel","Discovery blocked \u2014 AppMap already populated",{surfaceCount:E.surfaces.length}),{response:`Discovery not needed \u2014 AppMap already has ${E.surfaces.length} surfaces. Use the existing map to plan testing. If you need to explore a specific new area, spawn a regular Explorer (without is_discovery) for that area.`,isMetaTool:!0}}let h=!!t.session.config.userProvidedTestEmail&&l.isDiscovery!==!0&&this.modeAAuthSurfaceRequiresLogin(l),f=i&&!h,p=this.readSpawnScope(e.args.scope),g=this.spawnDedupDiscriminator(e,l);if(Gv(this.spawnDedup,o,g))return this.log("warn","CoordinatorRuntime","spawn_agent: duplicate prompt detected, coalescing",{label:e.args.label,promptPreview:o.slice(0,120),dedupDiscriminator:g}),{response:"I already spawned an Explorer with this exact prompt and operational settings earlier in this session. Re-running it would duplicate work and waste tokens. If discovery is complete, present the scope checkpoint (present_checkpoint type=scope) using what was found. If you need a focused re-test of a specific area, change the prompt or operational intent to target that area concretely.",isMetaTool:!0};Kv(this.spawnDedup,o,g);let m=`child-${++this.childAgentCounter}`,v=e.args.label||s.slice(0,60),_={id:m,label:v,type:"explorer"},w=`coord-iter-${t.iteration}`,T=Date.now();await this.appendChildIntent(t.session,{area:this.cloneAreaIntent(l),taskText:o,label:v}),this.recordFirstChildSpawnTiming(v);let b={sessionId:t.session.id,id:ce("msg"),role:"system",text:`Spawning explorer${f?" (background)":""}: ${v}`,timestamp:Date.now(),actionName:"spawn_agent",actionArgs:{childAgent:_,traceId:w,prompt:s,background:!!f,...e.args.authMode?{authMode:e.args.authMode}:{},...e.args.tests_logged_out===!0?{tests_logged_out:!0}:{}}};if(await this.baseDeps.chatRepo.addMessage(b),this.emit("message:added",{sessionId:this.sessionId,message:b}),f){this.childStates.set(m,{id:m,label:v,type:"explorer",status:"pending",background:!0,startTime:T,...p?{scope:[...p]}:{},areaIntent:this.cloneAreaIntent(l)});let k=await this.acquireCapSlot(m,t.session.id),E=0;try{let P=this.countRunningBackground();for(this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"info",message:`[parallel] spawn ${m} (bg), running=${P}/${this.maxConcurrentChildren}, pendingResults=${this.pendingChildResults.length}`});P>=this.maxConcurrentChildren;){if(this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"info",message:`[parallel] ${m} cap hit (${P}/${this.maxConcurrentChildren}, pendingResults=${this.pendingChildResults.length}, wakeLoop=${E}) \u2014 awaiting child result`}),await this.waitForChildResult(),E++,!this._isRunning){let F=Date.now()-T;this.setChildCompleted(m,"interrupted",{status:"interrupted",summary:"Interrupted before a concurrency slot became available",issues:[]},"Interrupted before a concurrency slot became available");let W={sessionId:t.session.id,id:ce("msg"),role:"system",text:`Explorer ${m} interrupted before start (background, ${Math.round(F/1e3)}s): concurrency slot never became available`,timestamp:Date.now(),actionName:"child_completed",actionArgs:{childAgent:_,traceId:w,duration_ms:F,status:"interrupted",error:"Interrupted before a concurrency slot became available",background:!0,started:!1}};return await this.baseDeps.chatRepo.addMessage(W),this.emit("message:added",{sessionId:this.sessionId,message:W}),this.injectChildResult(m,`[CHILD_RESULT ${m} interrupted]
1558
+ ITERATION BUDGET: ${d} (wrap up before this limit)`),{child:x,childSession:B,childPrompt:C,overrideVariant:he}}async handleSpawnAgent(e,t){let{type:n,prompt:s}=e.args,o=typeof s=="string"?s:"";if(n==="runner")return this.handleSpawnRunner(e,t);let i=!!e.args.background,a=Yv({scopeIsKnown:this.scopeCheckpointPresented,sessionInitialUrl:t.session.config?.initialUrl,llmIsDiscoveryFlag:e.args.is_discovery===!0,taskScopeIsSpecific:this.currentTurnScope==="specific"});a.forceDiscovery&&(this.log("info","CoordinatorRuntime","spawn_agent: forcing is_discovery=true on pre-scope broad-intent spawn",{label:e.args.label,sessionInitialUrl:t.session.config?.initialUrl,reason:a.reason}),e.args.is_discovery=!0);let l=await this.normalizeAreaIntentForSpawn(e,t.session,{legacyCapabilities:!0});l=this.reResolveAreaIntentForSpawn(e,l);let c=l.requiredCapabilities;this.writeRequiredCapabilitiesToSpawnArgs(e,c);let u=this.getAvailableCapabilities(t.session),d=this.requiredCapabilitiesMissing(c,u);if(d.length>0)return this.log("warn","CoordinatorRuntime","Spawn blocked by unavailable capability",{label:e.args.label,requiredCapabilities:c,availableCapabilities:u}),{response:this.makeMissingCapabilityMessage(d),isMetaTool:!0};if(c.includes("email_verification")&&l.identityPosture!=="user_provided_identity"&&!bt(t.session.config)?.canCheckInbox)return this.log("warn","CoordinatorRuntime","Spawn blocked by missing testing email policy",{label:e.args.label,requiredCapabilities:c,availableCapabilities:u}),{response:"I cannot start account creation or email verification because no reachable canonical testing inbox is configured for this session. I must not invent placeholder email addresses.",isMetaTool:!0};if(l.isDiscovery&&this.deps.appMapRepo){let k=t.session.projectId,E=k?await this.deps.appMapRepo.get(k):null;if(E&&E.surfaces.length>0)return this.log("info","QAModel","Discovery blocked \u2014 AppMap already populated",{surfaceCount:E.surfaces.length}),{response:`Discovery not needed \u2014 AppMap already has ${E.surfaces.length} surfaces. Use the existing map to plan testing. If you need to explore a specific new area, spawn a regular Explorer (without is_discovery) for that area.`,isMetaTool:!0}}let h=!!t.session.config.userProvidedTestEmail&&l.isDiscovery!==!0&&this.modeAAuthSurfaceRequiresLogin(l),f=i&&!h,p=this.readSpawnScope(e.args.scope),g=this.spawnDedupDiscriminator(e,l);if(Gv(this.spawnDedup,o,g))return this.log("warn","CoordinatorRuntime","spawn_agent: duplicate prompt detected, coalescing",{label:e.args.label,promptPreview:o.slice(0,120),dedupDiscriminator:g}),{response:"I already spawned an Explorer with this exact prompt and operational settings earlier in this session. Re-running it would duplicate work and waste tokens. If discovery is complete, present the scope checkpoint (present_checkpoint type=scope) using what was found. If you need a focused re-test of a specific area, change the prompt or operational intent to target that area concretely.",isMetaTool:!0};Kv(this.spawnDedup,o,g);let m=`child-${++this.childAgentCounter}`,v=e.args.label||s.slice(0,60),_={id:m,label:v,type:"explorer"},w=`coord-iter-${t.iteration}`,T=Date.now();await this.appendChildIntent(t.session,{area:this.cloneAreaIntent(l),taskText:o,label:v}),this.recordFirstChildSpawnTiming(v);let b={sessionId:t.session.id,id:ce("msg"),role:"system",text:`Spawning explorer${f?" (background)":""}: ${v}`,timestamp:Date.now(),actionName:"spawn_agent",actionArgs:{childAgent:_,traceId:w,prompt:s,background:!!f}};if(await this.baseDeps.chatRepo.addMessage(b),this.emit("message:added",{sessionId:this.sessionId,message:b}),f){this.childStates.set(m,{id:m,label:v,type:"explorer",status:"pending",background:!0,startTime:T,...p?{scope:[...p]}:{},areaIntent:this.cloneAreaIntent(l)});let k=await this.acquireCapSlot(m,t.session.id),E=0;try{let P=this.countRunningBackground();for(this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"info",message:`[parallel] spawn ${m} (bg), running=${P}/${this.maxConcurrentChildren}, pendingResults=${this.pendingChildResults.length}`});P>=this.maxConcurrentChildren;){if(this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"info",message:`[parallel] ${m} cap hit (${P}/${this.maxConcurrentChildren}, pendingResults=${this.pendingChildResults.length}, wakeLoop=${E}) \u2014 awaiting child result`}),await this.waitForChildResult(),E++,!this._isRunning){let F=Date.now()-T;this.setChildCompleted(m,"interrupted",{status:"interrupted",summary:"Interrupted before a concurrency slot became available",issues:[]},"Interrupted before a concurrency slot became available");let W={sessionId:t.session.id,id:ce("msg"),role:"system",text:`Explorer ${m} interrupted before start (background, ${Math.round(F/1e3)}s): concurrency slot never became available`,timestamp:Date.now(),actionName:"child_completed",actionArgs:{childAgent:_,traceId:w,duration_ms:F,status:"interrupted",error:"Interrupted before a concurrency slot became available",background:!0,started:!1}};return await this.baseDeps.chatRepo.addMessage(W),this.emit("message:added",{sessionId:this.sessionId,message:W}),this.injectChildResult(m,`[CHILD_RESULT ${m} interrupted]
1559
1559
  ${JSON.stringify({status:"interrupted",error:"Interrupted before a concurrency slot became available",summary:"Interrupted before a concurrency slot became available",duration_ms:F,started:!1})}
1560
1560
  [/CHILD_RESULT]`),{response:{status:"interrupted",childId:m,label:v,error:"Interrupted before a concurrency slot became available"},isMetaTool:!0}}let C=this.countRunningBackground();C>=this.maxConcurrentChildren?this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"warn",message:`[parallel] ${m} stale wake (recount=${C}/${this.maxConcurrentChildren}, pendingResults=${this.pendingChildResults.length}, wakeLoop=${E}) \u2014 re-entering wait`}):this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"info",message:`[parallel] ${m} slot freed (recount=${C}/${this.maxConcurrentChildren}, pendingResults=${this.pendingChildResults.length}, wakeLoop=${E}) \u2014 proceeding`}),P=C}let j=this.childStates.get(m);j&&(j.status="running");let B=this.countRunningBackground();this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"info",message:`[parallel] ${m} registered running (now=${B}/${this.maxConcurrentChildren}, wakeLoops=${E})`})}finally{k()}return this.launchBackgroundChild(m,_,w,t,e,T,l),{response:{status:"spawned",childId:m,label:v},isMetaTool:!0}}this.childStates.set(m,{id:m,label:v,type:"explorer",status:"running",background:!1,startTime:T,...p?{scope:[...p]}:{},areaIntent:this.cloneAreaIntent(l)});let x=`${this.sessionId}:child-browser`;if((await this.resolveLiveChildAuthContext(t.session,l)).freshContextRequired){this.deps.computerUseService?.clearCredentials?.(x);try{await this.deps.computerUseService?.cleanupSession(x)}catch(k){this.log("warn","CoordinatorRuntime","spawn_agent: logged-out reset failed",{childSessionId:x,error:k instanceof Error?k.message:String(k)})}}let I;try{let k=await this.setupChildAgent(m,_,w,t,e,x,l);I=k.child,this.activeChildren.add(I),await I.sendMessage(k.childSession,k.childPrompt,this.sessionAttachments),this.deps.computerUseService?.saveExtensionTemplate?.(x);let E=I.getResult(),P=uu(E),j=P?{...E,revealedFacts:P}:E,B=Date.now()-T;if(this.setChildCompleted(m,pb(E),j),E.coverage?.length&&this.log("info","QAModel","Explorer coverage reported",{childId:m,label:_.label,areaCount:E.coverage.length,areas:E.coverage.map(J=>J.area)}),E.draftTestCase){l.isDiscovery&&(E.draftTestCase.title=`Smoke: ${E.draftTestCase.title||_.label}`);let J=l.isDiscovery?`Smoke: ${_.label}`:_.label;this.childDraftTestCases.set(J,E.draftTestCase)}E.issues?.length&&(this.childReportedIssues=Cn([...this.childReportedIssues,...E.issues]));let C=I.getLastDeviceInitError?.();if(C&&!this.turnPausedThisCall)return this.turnPausedThisCall=!0,await this.pauseTurnForDeviceInitError(t.session,C,this.lastUserTextFromTrace()),{response:{status:"error",summary:`Stopped: device init failed (${C.category})`,halted:!0,duration_ms:B},isMetaTool:!0};let F=await this.maybeHaltForChildTerminalError(t.session,I,B);if(F)return F;let W={sessionId:t.session.id,id:ce("msg"),role:"system",text:`Explorer completed (${Math.round(B/1e3)}s): ${E.summary.slice(0,200)}`,timestamp:Date.now(),actionName:"child_completed",actionArgs:{childAgent:_,traceId:w,duration_ms:B,status:E.status,summary:E.summary,issues_found:E.issues.length}};await this.baseDeps.chatRepo.addMessage(W),this.emit("message:added",{sessionId:this.sessionId,message:W});let U=(E.summary||"").trim();U.startsWith("login_ok:")?this.log("info","CoordinatorRuntime","modeA.login_outcome",{sessionId:t.session.id,spawnLabel:_.label,result:"success",rawSummary:U.slice(0,200)}):U.startsWith("login_failed:")?this.log("info","CoordinatorRuntime","modeA.login_outcome",{sessionId:t.session.id,spawnLabel:_.label,result:"failed",errorText:U.replace(/^login_failed:\s*/,"").slice(0,200)}):U.startsWith("signup_failed_already_registered:")?this.log("info","CoordinatorRuntime","modeA.signup_outcome",{sessionId:t.session.id,spawnLabel:_.label,result:"already_registered",rawSummary:U.slice(0,200)}):U.startsWith("signup_failed_other:")&&this.log("info","CoordinatorRuntime","modeA.signup_outcome",{sessionId:t.session.id,spawnLabel:_.label,result:"other_failure",errorText:U.replace(/^signup_failed_other:\s*/,"").slice(0,200)});let H=E.status==="blocked"&&(U.startsWith("ask_user:")||/please paste the verification (link|code)/i.test(U));return H&&!this.turnPausedThisCall&&(this.turnPausedThisCall=!0,this._emailWaitPause=Gy(U)?{kind:ma(U)?"email":"generic",waitingFor:Ky(U),pausedDraftLabel:E.draftTestCase?l.isDiscovery?`Smoke: ${_.label}`:_.label:null,pausedChildLabel:_.label,savedDrafts:[...this.childDraftTestCases.entries()],savedIssues:[...this.childReportedIssues]}:null,this.log("info","CoordinatorRuntime","modeA.turn_paused_for_user",{sessionId:t.session.id,spawnLabel:_.label,summary:U.slice(0,160),emailWait:this._emailWaitPause!==null,pausedDraftLabel:this._emailWaitPause?.pausedDraftLabel??null,savedDraftCount:this._emailWaitPause?.savedDrafts.length??0}),this.endRun()),{response:{status:E.status,summary:E.summary,discoveredAreas:E.discoveredAreas,draftTestCase:E.draftTestCase,issues:E.issues,duration_ms:B,...E.blockKind?{blockKind:E.blockKind}:{},...P?{revealedFacts:P}:{},...H?{halted:!0}:{}},isMetaTool:!0}}catch(k){let E=Date.now()-T,P=String(k?.message??k),j=Gr(P)?Kr({isChildAgent:!0}):P;this.setChildCompleted(m,"failed",void 0,j),this.log("error","CoordinatorRuntime","Child agent failed",{childId:m,error:j});let B;try{if(I){let U=I.getResult();U.status!=="error"&&U.status!=="interrupted"&&(B=U)}}catch{}let C=I?.getLastClassifiedError(),F=I?.getLastDeviceInitError?.();if(F&&!this.turnPausedThisCall)return this.turnPausedThisCall=!0,await this.pauseTurnForDeviceInitError(t.session,F,this.lastUserTextFromTrace()),{response:{status:"error",summary:`Stopped: device init failed (${F.category})`,halted:!0,duration_ms:E},isMetaTool:!0};if(this.shouldHaltForChildError(C)&&!this.turnPausedThisCall)return this.turnPausedThisCall=!0,await this.maybeOfferAssistantV2Fallback(t.session,I,C)||await this.pauseTurnForUrlCorrection(t.session,C,this.lastUserTextFromTrace()),{response:{status:"error",summary:`Stopped: ${C.code??"network error"} on ${C.host??"target"}`,halted:!0,duration_ms:E},isMetaTool:!0};let W={sessionId:t.session.id,id:ce("msg"),role:"system",text:`Explorer ${m} failed after ${Math.round(E/1e3)}s: ${j}`,timestamp:Date.now(),actionName:"child_completed",actionArgs:{childAgent:_,traceId:w,duration_ms:E,status:"failed",error:j}};return await this.baseDeps.chatRepo.addMessage(W),this.emit("message:added",{sessionId:this.sessionId,message:W}),{response:{status:"failed",error:j,summary:`Child agent failed after ${Math.round(E/1e3)}s: ${j}`,partialFindings:B,duration_ms:E},isMetaTool:!0}}finally{I&&this.activeChildren.delete(I)}}async handleSpawnRunner(e,t){let{prompt:n,background:s}=e.args,o=e.args.test_plan_id;if(!o)return{response:{status:"failed",error:"No test_plan_id specified \u2014 required for runner type"},isMetaTool:!0};let i=await this.deps.testPlanV2Repo?.get?.(o);if(!i)return{response:{status:"failed",error:`Test plan not found: ${o}`},isMetaTool:!0};let a=`child-${++this.childAgentCounter}`,l=`Run: ${i.title}`.slice(0,60),c={id:a,label:l,type:"runner"},u=`coord-iter-${t.iteration}`,d=Date.now(),h={sessionId:t.session.id,id:ce("msg"),role:"system",text:`Spawning runner${s?" (background)":""}: ${l}`,timestamp:Date.now(),actionName:"spawn_agent",actionArgs:{childAgent:c,traceId:u,prompt:n,test_plan_id:o,background:!!s}};if(await this.baseDeps.chatRepo.addMessage(h),this.emit("message:added",{sessionId:this.sessionId,message:h}),s){this.childStates.set(a,{id:a,label:l,type:"runner",status:"pending",background:!0,startTime:d});let p=await this.acquireCapSlot(a,t.session.id),g=0;try{let m=this.countRunningBackground();for(this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"info",message:`[parallel] spawn ${a} (bg), running=${m}/${this.maxConcurrentChildren}, pendingResults=${this.pendingChildResults.length}`});m>=this.maxConcurrentChildren;){if(this.baseDeps.sink.emit({kind:"log",ts:Date.now(),sessionId:t.session.id,level:"info",message:`[parallel] ${a} cap hit (${m}/${this.maxConcurrentChildren}, pendingResults=${this.pendingChildResults.length}, wakeLoop=${g}) \u2014 awaiting child result`}),await this.waitForChildResult(),g++,!this._isRunning){let T=Date.now()-d;this.setChildCompleted(a,"interrupted",{status:"interrupted",summary:"Interrupted before a concurrency slot became available",issues:[]},"Interrupted before a concurrency slot became available");let b={sessionId:t.session.id,id:ce("msg"),role:"system",text:`Runner ${a} interrupted before start (background, ${Math.round(T/1e3)}s): concurrency slot never became available`,timestamp:Date.now(),actionName:"child_completed",actionArgs:{childAgent:c,traceId:u,duration_ms:T,status:"interrupted",error:"Interrupted before a concurrency slot became available",background:!0,started:!1}};return await this.baseDeps.chatRepo.addMessage(b),this.emit("message:added",{sessionId:this.sessionId,message:b}),this.injectChildResult(a,`[CHILD_RESULT ${a} interrupted]
1561
1561
  ${JSON.stringify({status:"interrupted",error:"Interrupted before a concurrency slot became available",summary:"Interrupted before a concurrency slot became available",duration_ms:T,started:!1})}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentiqa",
3
- "version": "1.1.19-staging.8697cbb",
3
+ "version": "1.1.19-staging.952b4d6",
4
4
  "description": "AI-powered testing for web and mobile apps",
5
5
  "type": "module",
6
6
  "bin": "dist/cli.js",