const state={runId:null,validationRunId:null,validationPoll:null,validationPollToken:null,validationRequestSeq:0,validationMode:'idle',validationArgsDirty:false,validationPollErrors:0,validationDetail:null,validationPrefillDraft:null,validationTerminalByRun:{},centerTab:'active',spaceLinksUnlockedFor:null,bucketName:'space-factory-runs',bucketSource:null,bucketReady:false,poll:null,activeLinks:{},activeRunProgress:null,selectedRunDetail:null,runStatusFilter:'all',runSearch:'',runPage:0,runsPerPage:5,runsCache:[],runsLastLoaded:0,lastRunsRefreshFromPoll:0,lastJobLogPoll:0,pollErrors:0,busy:false,user:null,currentView:'onepage',modelScan:null,runDetailCache:{},runDetailCacheTtlMs:300000,deleteModalPromise:null,deleteModalRunId:null,deletingRuns:{},deletedRuns:{}}; const TERMINAL_STATUSES=new Set(['done','success','failed','full_inference_success','full_inference_candidate_health_passed','manual_hardware_required','generated_needs_manual_hardware','technical_blocker','health_only','repair_success','repair_failed','succeeded','waiting_manual_action','blocked','stale','cancelled','canceled']); const DEFAULT_TIMELINE=[{label:'Bootstrap',status:'pending'},{label:'Dependencies',status:'pending'},{label:'Auth',status:'pending'},{label:'Model analysis',status:'pending'},{label:'Workspace',status:'pending'},{label:'Node/npm',status:'pending'},{label:'Pi install',status:'pending'},{label:'Pi config',status:'pending'},{label:'Pi run',status:'pending'},{label:'Pi verification',status:'pending'},{label:'Metadata sanitize',status:'pending'},{label:'Requirements sanitize',status:'pending'},{label:'Hardware strategy',status:'pending'},{label:'Create with hardware',status:'pending'},{label:'Create Space',status:'pending'},{label:'Repair pass',status:'pending'},{label:'Upload files',status:'pending'},{label:'Space runtime',status:'pending'},{label:'Space logs',status:'pending'},{label:'API validation',status:'pending'},{label:'Live wait',status:'pending'},{label:'Generation smoke',status:'pending'},{label:'Inference gate',status:'pending'},{label:'Report',status:'pending'},{label:'Done',status:'pending'},{label:'Failure',status:'pending'}]; function bindOnce(el,eventName,key,handler,options){ if(!el)return; const attr='bound'+String(key||eventName).replace(/[^a-zA-Z0-9]/g,''); if(el.dataset[attr]==='true')return; el.dataset[attr]='true'; el.addEventListener(eventName,handler,options); } function bindAllOnce(selector,eventName,key,handler,options){ document.querySelectorAll(selector).forEach((el,index)=>bindOnce(el,eventName,`${key}${index}`,handler,options)); } function updateImplementationModeHelp(){ const value=formValue('implementationMode')||'full-inference-gated'; const copy=implementationModeCopy(value); const el=$('implementationModeHelp'); if(!el)return; el.innerHTML=`${escapeHtml(copy.title)}${escapeHtml(copy.description)}`; } function saveActiveRun(){try{localStorage.setItem('asf.activeRun',JSON.stringify({runId:state.runId,bucketName:state.bucketName,links:state.activeLinks||{}}))}catch(_){}} function clearSavedRun(){try{localStorage.removeItem('asf.activeRun')}catch(_){} state.spaceLinksUnlockedFor=null} function artifactUrl(runId,bucketSource){if(!runId||!bucketSource)return'';return `https://huggingface.co/buckets/${bucketSource}/tree/runs/${runId}`} function ownerFromBucketSource(bucket){return bucket?String(bucket).split('/')[0]:''} function normalizeLinks(links={}){const out={...links};const bucket=out.bucket_source||state.bucketSource;const run=out.run_id||state.runId;if(!out.artifacts_url&&bucket&&run)out.artifacts_url=artifactUrl(run,bucket);if(!out.job_url){const jobId=out.job_id||out.jobId;const owner=out.job_owner||out.created_by||out.owner||out.username||state.user?.username||ownerFromBucketSource(bucket);if(jobId&&owner)out.job_url=`https://huggingface.co/jobs/${owner}/${jobId}`}return out} function runPassedSpaceCreation(payload={}){ const events=payload.events||payload.view?.activity||payload.detail?.events||[]; const summary=payload.summary||payload.detail?.summary||{}; const stateObj=payload.state||payload.detail?.state||{}; const success=String(payload.status||summary.status||stateObj.status||'').toLowerCase(); if(success.includes('success')||success.includes('succeed')||success==='done'||success==='completed')return true; const passedSteps=new Set(['create_space','upload_files','space_runtime','space_logs','api_validation','live_wait','generation_smoke','inference_gate','report_write','done']); return Array.isArray(events)&&events.some(e=>passedSteps.has(String(e.step||''))&&String(e.status||'').toLowerCase()!=='started'); } function isValidationRunDetail(detail={}){ const summary=detail.summary||{}; const launch=detail.launch||{}; const stateObj=detail.state||{}; const view=detail.view||{}; const values=[detail.kind,summary.kind,launch.kind,stateObj.kind,view.kind,summary.run_type,launch.run_type,stateObj.run_type,detail.run_type]; return values.some(v=>String(v||'').toLowerCase().includes('validate_existing_space')||String(v||'').toLowerCase().includes('validation')); } const VALIDATION_PHASES=[ ['start','Start'], ['runtime','Runtime'], ['api','API'], ['endpoint','Endpoint'], ['payload','Payload'], ['smoke','Smoke test'], ['result','Result'], ['report','Report'], ]; function validationStatusText(detail={}){ const summary=detail.summary||{}; const stateObj=detail.state||{}; const smoke=detail.generation_smoke||summary.generation_smoke||stateObj.generation_smoke||{}; const gate=detail.inference_gate||summary.inference_gate||stateObj.inference_gate||{}; return [ detail.verdict,detail.validation_status,detail.status,detail.result_status, detail.view?.header?.status,stateObj.verdict,stateObj.validation_status,stateObj.status, summary.verdict,summary.validation_status,summary.status,summary.gate_status,summary.smoke_status, gate.status,smoke.status ].map(x=>String(x||'').toLowerCase()).filter(Boolean).join(' '); } function validationCanonicalStatus(detail={}){ const text=validationStatusText(detail); if(!text||text.includes('idle')||text.includes('no_validation')||text.includes('deleted'))return 'idle'; if(text.includes('stale'))return 'stale'; if(text.includes('manual')||text.includes('blocked')||text.includes('requires_action'))return 'manual_hardware_required'; if(text.includes('failed')||text.includes('failure')||text.includes('error')||text.includes('timeout'))return 'failed'; if(text.includes('full_inference_candidate_health_passed')||text.includes('health_only')||text.includes('partial')||text.includes('warning')||text.includes('not_verified')||text.includes('completed_with_warnings'))return 'partial_validation'; if(text.includes('success')||text.includes('succeed')||text.includes('passed')||text.includes('full_inference_success')||text.includes('done')||text.includes('completed'))return 'full_inference_success'; if(text.includes('cancelled')||text.includes('canceled')||text.includes('stopped'))return 'stopped'; if(text.includes('running')||text.includes('queued')||text.includes('pending')||text.includes('started')||text.includes('waiting')||text.includes('building'))return 'running'; return 'running'; } function validationEventPhase(step=''){ const s=String(step||'').toLowerCase(); if(['token_context','bootstrap','dependencies','auth'].includes(s))return 'start'; if(['space_runtime','live_wait','space_logs'].includes(s))return 'runtime'; if(['api_validation','api_discovery','gradio_config','gradio_client'].includes(s))return 'api'; if(['endpoint_selection','endpoint_schema','api_schema','gradio_schema'].includes(s))return 'endpoint'; if(['payload','payload_prepare','test_payload','validation_payload'].includes(s))return 'payload'; if(['generation_smoke','smoke_test','client_predict'].includes(s))return 'smoke'; if(['inference_gate','result','validation_result'].includes(s))return 'result'; if(['report_write','report','done','failure'].includes(s))return 'report'; return ''; } function validationPhaseStatusFromEventStatus(status=''){ const s=String(status||'').toLowerCase(); if(s.includes('success')||s==='done'||s==='complete'||s==='completed'||s==='passed')return 'success'; if(s.includes('failed')||s.includes('error')||s.includes('timeout'))return 'failed'; if(s.includes('warning')||s.includes('partial'))return 'warning'; if(s.includes('running')||s.includes('started')||s.includes('waiting')||s.includes('pending'))return 'running'; return 'pending'; } function validationTimelineItems(detail={}){ const events=Array.isArray(detail.events)?detail.events:(Array.isArray(detail.view?.activity)?detail.view.activity:[]); const canonical=validationCanonicalStatus(detail); const schema=detail.api_schema||detail.tests?.api_schema||{}; const smoke=detail.generation_smoke||detail.summary?.generation_smoke||detail.state?.generation_smoke||{}; const gate=detail.inference_gate||detail.summary?.inference_gate||detail.state?.inference_gate||{}; const endpointNames=validationEndpointNames(detail); const hasPayload=Array.isArray(smoke.test_args)||Boolean(detail.launch?.test_args_json)||Boolean(detail.summary?.test_args_json)||Object.keys(smoke.test_kwargs||{}).length; const byPhase=new Map(VALIDATION_PHASES.map(([id,label])=>[id,{step:id,label,status:'pending',message:''}])); const mark=(id,status,message='')=>{ const item=byPhase.get(id); if(!item)return; const rank={pending:0,running:1,success:2,warning:3,failed:4,manual_hardware_required:4,stopped:3}; const next=status==='done'?'success':status; if((rank[next]??0)>=(rank[item.status]??0)){item.status=next;item.message=message||item.message;} }; for(const e of events){ const phase=validationEventPhase(e?.step); if(!phase)continue; mark(phase,validationPhaseStatusFromEventStatus(e.status),e.message||''); } if(events.length)mark('start','success'); if(endpointNames.length||Object.keys(schema||{}).length){mark('api','success');mark('endpoint','success');} if(hasPayload)mark('payload','success'); const smokeStatus=String(smoke.status||detail.summary?.smoke_status||'').toLowerCase(); if(smokeStatus){ if(smokeStatus.includes('success')||smokeStatus.includes('passed'))mark('smoke','success',smoke.message||'Generation smoke passed'); else if(smokeStatus.includes('failed')||smokeStatus.includes('error'))mark('smoke','failed',smoke.error||smoke.message||'Generation smoke failed'); else if(smokeStatus.includes('warning')||smokeStatus.includes('partial'))mark('smoke','warning',smoke.error||smoke.message||'Generation not fully verified'); } const gateStatus=String(gate.status||detail.summary?.gate_status||'').toLowerCase(); if(gateStatus){ if(gateStatus.includes('success')||gateStatus.includes('passed'))mark('result','success'); else if(gateStatus.includes('failed')||gateStatus.includes('error'))mark('result','failed'); else if(gateStatus.includes('partial')||gateStatus.includes('warning')||gateStatus.includes('health'))mark('result','warning'); } if(canonical==='full_inference_success'){VALIDATION_PHASES.forEach(([id])=>mark(id,'success'));} else if(canonical==='partial_validation'){['start','runtime','api','endpoint','payload','report'].forEach(id=>mark(id,'success'));mark('smoke','warning');mark('result','warning');} else if(canonical==='failed'){ mark('report','success'); if(byPhase.get('smoke')?.status==='pending'&&byPhase.get('api')?.status==='success')mark('smoke','failed'); if(byPhase.get('result')?.status==='pending')mark('result','failed'); }else if(canonical==='manual_hardware_required'){mark('result','manual_hardware_required');} else if(canonical==='stopped'||canonical==='stale'){mark('result','stopped');} const firstPending=[...byPhase.values()].find(x=>x.status==='pending'); if(canonical==='running'&&firstPending){mark(firstPending.step,'running');} return VALIDATION_PHASES.map(([id])=>byPhase.get(id)); } function validationProgressPercent(detail={}){ const explicit=Number(detail.progress||detail.percent||detail.summary?.progress); if(Number.isFinite(explicit)&&explicit>0)return Math.max(0,Math.min(100,explicit)); const canonical=validationCanonicalStatus(detail); if(canonical&&canonical!=='running')return 100; const items=validationTimelineItems(detail); let score=0; items.forEach((item,idx)=>{ const st=String(item.status||'').toLowerCase(); if(st==='success'||st==='done'||st==='completed')score=Math.max(score,idx+1); else if(st==='running')score=Math.max(score,idx+0.45); else if(st==='warning'||st==='failed')score=Math.max(score,idx+1); }); return Math.max(0,Math.min(98,Math.round((score/items.length)*100))); } function uniqueStrings(values=[]){const out=[];for(const value of values){const text=String(value||'').trim();if(text&&!out.includes(text))out.push(text)}return out} function validationEndpointNames(detail={}){ const smoke=detail.generation_smoke||detail.summary?.generation_smoke||detail.state?.generation_smoke||{}; const schema=detail.api_schema||detail.tests?.api_schema||{}; const names=[]; for(const source of [schema.api_names,schema.discovered_api_names,smoke.discovered_api_names,smoke.api_names]){ if(Array.isArray(source))names.push(...source); } if(smoke.api_name)names.push(smoke.api_name); if(schema.selected_api_name)names.push(schema.selected_api_name); const nested=schema.schema&&typeof schema.schema==='object'?schema.schema:{}; for(const source of [nested.api_names,nested.named_endpoints]){ if(Array.isArray(source))names.push(...source); } return uniqueStrings(names.map(normalizeApiName)); } function endpointSchemaEntriesFromApiSchema(schema={}){ const raw=schema.schema&&typeof schema.schema==='object'?schema.schema:schema; const named=raw.named_endpoints||raw.endpoints||raw.dependencies||[]; if(Array.isArray(named))return named; if(named&&typeof named==='object')return Object.entries(named).map(([api_name,value])=>({api_name,...(value&&typeof value==='object'?value:{})})); return []; } function endpointNameFromEntry(entry={}){ return normalizeApiName(entry.api_name||entry.api_name_for_predict||entry.name||entry.endpoint||entry.path||entry.id||''); } function validationEndpointParameters(detail={},endpointName=''){ const smoke=detail.generation_smoke||detail.summary?.generation_smoke||detail.state?.generation_smoke||{}; const schema=detail.api_schema||detail.tests?.api_schema||{}; const selected=normalizeApiName(endpointName||smoke.api_name||schema.selected_api_name||formValue('validateApi')||''); const entries=endpointSchemaEntriesFromApiSchema(schema); const match=entries.find(entry=>endpointNameFromEntry(entry)===selected); const possible=match?.parameters||match?.inputs||match?.input_components||match?.components||smoke.endpoint_parameters||schema.endpoint_parameters||schema.schema?.endpoint_parameters||[]; const params=Array.isArray(possible)?possible.map(item=>typeof item==='string'?item:(item?.parameter_name||item?.label||item?.name||item?.id||item?.component||'')):[]; return uniqueStrings(params); } function applyValidationEndpoint(endpointName,detail={}){ const name=normalizeApiName(endpointName); setInputValue('validateApi',name); const input=$('validateApi'); if(input){input.dispatchEvent(new Event('input',{bubbles:true}));input.focus({preventScroll:true})} renderValidationEndpoints(detail||state.validationDetail||{}); showMessage(`API name set to ${name}.`,'success'); } function bindValidationEndpointPicker(root){ if(!root||root.dataset.boundEndpointPicker==='true')return; root.dataset.boundEndpointPicker='true'; root.addEventListener('click',e=>{ const btn=e.target.closest('[data-endpoint-name]'); if(!btn)return; e.preventDefault(); applyValidationEndpoint(btn.dataset.endpointName,state.validationDetail||{}); }); } function endpointHumanText(value){ if(value==null)return''; if(typeof value==='string'||typeof value==='number'||typeof value==='boolean')return String(value); if(Array.isArray(value))return value.map(endpointHumanText).filter(Boolean).join(', '); if(typeof value==='object'){ return firstNonEmpty(value.label,value.name,value.type,value.component,value.component_type,value.type_name,value.class_name,value.__type__,value.datatype,value.python_type,value.api_info?.type,value.value); } return String(value||''); } function endpointChoices(item={}){ const raw=item.choices||item.options||item.api_info?.choices||item.component?.choices||item.component?.options||[]; if(!Array.isArray(raw))return []; return raw.map(choice=>endpointHumanText(choice)).filter(Boolean); } function endpointDefaultValue(item={}){ const raw=item.default ?? item.value ?? item.example_input ?? item.api_info?.default ?? item.component?.value; const text=endpointHumanText(raw); if(!text||text==='[object Object]')return''; return text; } function endpointInputItemsFromEntry(entry={}){ const raw=entry.parameters||entry.inputs||entry.input_components||entry.components||[]; if(!Array.isArray(raw))return []; return raw.map((item,index)=>{ if(typeof item==='string')return {name:item,type:'',component:'',choices:[],defaultValue:'',optional:false}; const name=endpointHumanText(item.parameter_name||item.label||item.name||item.id)||`arg${index}`; const type=endpointHumanText(item.type||item.python_type||item.datatype||item.api_info?.type); const component=endpointHumanText(item.component||item.component_type||item.type_name||item.label||item.api_info?.component); const optional=item.optional===true||item.required===false||item.parameter_has_default===true; return {name,type,component,choices:endpointChoices(item),defaultValue:endpointDefaultValue(item),optional}; }).filter(x=>x.name); } function endpointOutputItemsFromEntry(entry={}){ const raw=entry.returns||entry.outputs||entry.output_components||[]; if(!Array.isArray(raw))return []; return raw.map((item,index)=>{ if(typeof item==='string')return {name:item,type:'',component:'',choices:[],defaultValue:'',optional:false}; const name=endpointHumanText(item.label||item.name||item.id)||`output${index}`; const type=endpointHumanText(item.type||item.python_type||item.datatype||item.api_info?.type); const component=endpointHumanText(item.component||item.component_type||item.type_name||item.label); return {name,type,component,choices:endpointChoices(item),defaultValue:endpointDefaultValue(item),optional:false}; }).filter(x=>x.name); } function endpointDetails(detail={},endpointName=''){ const schema=detail.api_schema||detail.tests?.api_schema||{}; const entries=endpointSchemaEntriesFromApiSchema(schema); const selected=normalizeApiName(endpointName||formValue('validateApi')||detail.generation_smoke?.api_name||schema.selected_api_name||''); const match=entries.find(entry=>endpointNameFromEntry(entry)===selected)||{}; const inputs=endpointInputItemsFromEntry(match); const fallbackParams=validationEndpointParameters(detail,selected).map(name=>({name,type:'',component:''})); return { name:selected, description:match.description||match.documentation||match.doc||'', inputs:inputs.length?inputs:fallbackParams, outputs:endpointOutputItemsFromEntry(match), raw:match, }; } function endpointDetailText(item={}){ const component=endpointHumanText(item.component||item.component_type||item.rendered_component); const type=endpointHumanText(item.type||item.datatype); const required=item.optional?'optional':'required'; const parts=[component||type,component&&type&&component!==type?type:'',required].filter(Boolean); const choices=Array.isArray(item.choices)?item.choices.filter(Boolean):[]; if(choices.length)parts.push(`choices: ${choices.slice(0,4).join(', ')}${choices.length>4?'…':''}`); if(item.defaultValue)parts.push(`default: ${item.defaultValue}`); return parts.join(' · '); } function renderEndpointParamChips(items=[]){ if(!items.length)return 'No parameters discovered yet.'; return items.slice(0,10).map(item=>{ const name=endpointHumanText(item.name||item.label||item.id)||'param'; const detail=endpointDetailText(item); return `${escapeHtml(name)}${detail?`${escapeHtml(detail)}`:''}`; }).join('')+(items.length>10?'':''); } function renderValidationEndpoints(detail={}){ const root=$('spaceTestEndpoints'); if(!root)return; bindValidationEndpointPicker(root); const names=validationEndpointNames(detail); const selected=normalizeApiName(formValue('validateApi')||detail.generation_smoke?.api_name||detail.api_schema?.selected_api_name||names[0]||''); if(!names.length){root.innerHTML='
No Gradio endpoints discovered yet. They will appear after the live API schema step.
';return} const chips=names.slice(0,12).map(name=>``).join(''); const details=endpointDetails(detail,selected); const signature=JSON.stringify({names:names.slice(0,12),selected,inputs:details.inputs,outputs:details.outputs,description:details.description||''}); if(root.dataset.signature===signature)return; root.dataset.signature=signature; const inputLine=`
Inputs${renderEndpointParamChips(details.inputs)}
`; const outputLine=details.outputs.length?`
Outputs${renderEndpointParamChips(details.outputs)}
`:''; const meta=`
${escapeHtml(selected)}${details.inputs.length} input${details.inputs.length===1?'':'s'}${details.outputs.length} output${details.outputs.length===1?'':'s'}
`; root.innerHTML=`
${chips}
${meta}${inputLine}${outputLine}${details.description?`

${escapeHtml(details.description)}

`:''}
`; } function setGeneratedSpaceLinksEnabled(links={},enabled=false){ const space=enabled?links.target_space_url:''; const settings=enabled?(links.target_space_settings_url||links.target_space_url&&links.target_space_url+'/settings'):''; for(const id of ['activeOpenSpace','openSpace','launchOpenSpace'])setLink(id,space); for(const id of ['activeOpenSettings','openSettings','manualOpenSettings','launchOpenSettings'])setLink(id,settings); } function setQuickLinks(links={},context={}){links=normalizeLinks(links||{});state.activeLinks=links;for(const id of ['activeOpenJob','openJob','launchOpenJob'])setLink(id,links.job_url);const runForLinks=links.run_id||context.run_id||context.summary?.run_id||state.runId;let spaceReady=runPassedSpaceCreation(context);if(spaceReady&&links.target_space_url)state.spaceLinksUnlockedFor=runForLinks;if(!spaceReady&&state.spaceLinksUnlockedFor&&state.spaceLinksUnlockedFor===runForLinks&&links.target_space_url)spaceReady=true;setGeneratedSpaceLinksEnabled(links,spaceReady);for(const id of ['activeOpenArtifacts','openArtifacts','launchOpenArtifacts'])setLink(id,links.artifacts_url);renderManualAction({links:{...links,target_space_url:spaceReady?links.target_space_url:'',target_space_settings_url:spaceReady?links.target_space_settings_url:''}})} let operationTimer=null;function toastDuration(type='info'){if(type==='loading')return 12000;if(type==='error')return 7000;if(type==='warning'||type==='warn')return 6000;return 3500} function setOperation(message,type='info',opts={}){const el=$('operationStatus');if(!el)return;if(operationTimer){clearTimeout(operationTimer);operationTimer=null}if(!message){el.hidden=true;el.textContent='';el.className='operation-status floating-toast';return}el.hidden=false;el.className='operation-status floating-toast '+type;el.textContent=message;const duration=opts.duration??toastDuration(type);if(duration>0)operationTimer=setTimeout(()=>{setOperation('')},duration)} function showMessage(msg,isError=false){const type=isError===true?'error':(typeof isError==='string'?isError:'info');setOperation(msg,type);const el=$('eventsPanel');if(el&&!state.runId)el.textContent=(isError?'Error: ':'')+msg} function setBusy(isBusy,label='Working…'){state.busy=Boolean(isBusy);if(!state.busy&&$('operationStatus')?.className.includes('loading'))setOperation('');document.querySelectorAll('[data-action-button]').forEach(btn=>{btn.disabled=state.busy||btn.dataset.requiresBucket==='true'&&!state.bucketReady});if($('launchBuild'))setBuildLaunchEnabled();if($('launchValidate'))setValidationLaunchEnabled();if(state.busy)setOperation(label,'loading')} function setButtonBusy(id,isBusy,busyLabel){const btn=$(id);if(!btn)return;if(isBusy){if(!btn.classList.contains('is-busy')&&!btn.dataset.oldText)btn.dataset.oldText=btn.textContent;btn.textContent=busyLabel||'Working…';btn.disabled=true;btn.classList.add('is-busy')}else{if(btn.dataset.oldText){btn.textContent=btn.dataset.oldText;delete btn.dataset.oldText}if(id==='launchBuild')setBuildLaunchEnabled();else btn.disabled=state.busy||btn.dataset.requiresBucket==='true'&&!state.bucketReady;btn.classList.remove('is-busy')}} function bucketFeedbackSummary(message=''){ const text=String(message||'').trim(); if(!text)return'Create your private run bucket before launching builds.'; if(/Bucket Not Found|404 Client Error|Repository not found/i.test(text))return'Bucket not found. Create it to store runs and artifacts.'; if(/permission|authenticated|token|401|403/i.test(text))return'Bucket is private or inaccessible with this token.'; if(text.length>150)return text.slice(0,147)+'…'; return text; } function setBucketFeedback(mode='checking',message='Checking private bucket access…'){ const orb=$('bucketInlineOrb'); const text=$('bucketFeedbackText'); if(orb)orb.className='bucket-status-orb '+mode; if(text){ text.textContent=bucketFeedbackSummary(message); text.title=String(message||''); } } function renderAnonymousEvalStatus(me){ const card=$('evalArchiveCard'); const title=$('evalArchiveTitle'); const text=$('anonymousEvalText'); const enable=$('enableEvalArchive'); const disable=$('disableEvalArchive'); const verify=$('verifyEvalArchive'); const stateBadge=$('evalArchiveStateBadge'); const cfg=me?.anonymous_eval||{}; const enabled=Boolean(cfg.enabled); const canManage=Boolean(cfg.can_manage)&&cfg.env_override!==true; const readonly=Boolean(cfg.readonly)||Boolean(enabled&&!canManage); const bucket=cfg.bucket_source||cfg.proposed_bucket_source||'configured bucket'; const path=cfg.bucket_path?'/'+cfg.bucket_path:(cfg.default_bucket_path?'/'+cfg.default_bucket_path:''); const mount=cfg.job_mount_path||cfg.default_mount_path||'/evals'; if(card){ card.hidden=false; card.className='eval-archive-panel '+(enabled?'on':'off')+(readonly?' readonly':'')+(canManage?' manageable':''); } if(title){ title.textContent=enabled?'Anonymous eval archive':'Anonymous eval archive'; } if(stateBadge){ const unavailable=String(cfg.reason||'')==='status_unavailable'; stateBadge.textContent=enabled?'On':(unavailable?'Unknown':'Off'); stateBadge.className='badge '+(enabled?'success':unavailable?'warn':'neutral'); } if(text){ text.className='eval-feedback '+(enabled?'on':'off'); if(enabled){ const manager=cfg.managed_by==='you'?'You manage this instance setting.':`Managed by ${cfg.managed_by||'instance owner'}.`; text.textContent=`On · ${bucket}${path} → ${mount}`; text.title=`Anonymous project eval archive enabled from ${cfg.source||'config'}: ${bucket}${path} mounted at ${mount}. ${manager} ASF backend publishes anonymized eval records after user Jobs write local run evals.`; }else if(String(cfg.reason||'')==='status_unavailable'){ text.textContent='Status unavailable · could not verify eval archive configuration.'; text.title='Refresh to retry the public eval archive status check. Unknown is not treated as Off.'; }else if(me?.username){ text.textContent='Mount an operator eval bucket at /evals, then enable publishing.'; text.title='Recommended: private operator bucket, bucket path evals, mounted read-write at /evals on this ASF Space. Env vars still work as an admin override.'; }else{ text.textContent='Sign in as the instance owner to enable it.'; text.title='Anonymous eval archive can be enabled by the instance owner or configured eval admins.'; } } if(enable){ enable.hidden=enabled||!me?.username||cfg.env_override===true||cfg.can_manage===false; enable.disabled=!me?.username||state.busy; enable.title=`Enable anonymous eval archive using ${cfg.proposed_bucket_source||'your namespace bucket'} mounted at ${cfg.default_mount_path||'/evals'}.`; } if(disable){ disable.hidden=!enabled||!canManage; disable.disabled=state.busy; disable.title='Disable anonymous eval publishing for this ASF instance. Existing archived eval records are not deleted.'; } if(verify){ verify.hidden=!enabled||!canManage; verify.disabled=state.busy; verify.title='Refresh and verify the eval archive configuration.'; } } function setBucketReady(ok,message){state.bucketReady=Boolean(ok);setBuildLaunchEnabled();const feedback=state.bucketReady?'Ready for builds, validations and artifacts.':(message||'Create your private run bucket before launching builds.');setText('buildGateText',state.bucketReady?'Bucket ready. You can launch builds.':bucketFeedbackSummary(feedback));setText('bucketInlineStatus',state.bucketReady?'Ready':'Setup needed');setBucketFeedback(state.bucketReady?'ready':'error',feedback);for(const id of ['bucketInlineDot','sidebarBucketDot']){const dot=$(id);if(dot)dot.className='status-dot '+(state.bucketReady?'green':'amber-dot')}const inline=$('bucketInlineStatus');if(inline)inline.className='badge '+(state.bucketReady?'success':'warn');document.querySelectorAll('[data-requires-bucket="true"]').forEach(btn=>btn.disabled=state.busy||!state.bucketReady);setBuildLaunchEnabled()} function effectivePreferredHardware(){const preferred=formValue('preferredHardware')||'zero-a10g';const fallback=formValue('fallbackHardware')||'a10g-large';const tryZero=$('tryZeroGpu')?.checked??true;if(tryZero)return preferred;if(preferred==='zero-a10g'||preferred.startsWith('zero'))return fallback;return preferred} function hardwarePlanLabel(){const tryZero=$('tryZeroGpu')?.checked??true;const preferred=effectivePreferredHardware();const fallback=formValue('fallbackHardware')||'a10g-large';const allow=$('allowFallback')?.checked??true;if(tryZero)return `ZeroGPU → ${allow?fallback:'no fixed fallback'}`;return `${preferred}${allow&&fallback!==preferred?' → '+fallback+' fallback':''}`} function normalizeModelInput(value){return String(value||'').trim().replace('https://huggingface.co/','').split('?')[0].split('#')[0].replace(/^\/+|\/+$/g,'')} function modelScanMatchesCurrent(){return state.modelScan?.ok&&normalizeModelInput(state.modelScan.model_id)===normalizeModelInput(formValue('modelId'))} function scanVerdictClass(verdict){verdict=String(verdict||'').toLowerCase();if(verdict==='safe')return'success';if(verdict==='caution')return'warn';if(verdict==='risky'||verdict==='unsupported')return'error';if(verdict==='scanning')return'running';return'neutral'} function outputTypeFromModelScan(scan={}){ const value=String(scan.expected_output_type||scan.metadata?.expected_output_type||'').toLowerCase(); return ['text','image','video','audio','any'].includes(value)?value:''; } function syncExpectedOutputFromModelScan(scan={}){ const inferred=outputTypeFromModelScan(scan); const select=$('buildExpectedOutput'); if(!inferred||!select)return false; const previous=select.value; select.value=inferred; select.dataset.prescanOutput=inferred; select.dataset.prescanPreviousOutput=previous||''; select.dispatchEvent(new Event('change',{bubbles:true})); return previous!==inferred; } function renderModelPreScan(scan=null){ const card=$('modelPreScanCard'),badge=$('modelPreScanBadge'),signals=$('modelPreScanSignals'),ackWrap=$('modelRiskAckWrap'); if(!card)return; const current=normalizeModelInput(formValue('modelId')); const isTransient=scan&&scan.transient===true; const matches=scan&&((scan.ok&&normalizeModelInput(scan.model_id)===current)||isTransient); if(!scan||!matches){ card.className='model-prescan-card required'; setText('modelPreScanTitle','Pre-scan required'); setText('modelPreScanSummary','Run a fast metadata scan before launching a paid Job. It checks model card guidance, runnable examples, Diffusers signals, files, safetensors, gated access and custom-code risk without downloading weights.'); if(badge){badge.textContent='Required';badge.className='badge neutral'} if(signals){signals.hidden=false;signals.innerHTML='
Metadata onlyNo weight downloadRequired before Job
'} if(ackWrap)ackWrap.hidden=true; return; } const verdict=String(scan.verdict||'caution').toLowerCase(); const cls=scanVerdictClass(verdict); const labelMap={safe:'Safe',caution:'Needs review',risky:'Risky',unsupported:'Unsupported',scanning:'Scanning',error:'Scan failed'}; card.className='model-prescan-card '+cls; const scoreText=(scan.score===undefined||scan.score===null||verdict==='scanning'||verdict==='error')?'':` · score ${scan.score}/100`; setText('modelPreScanTitle',`${labelMap[verdict]||labelMap.caution}${scoreText}`); setText('modelPreScanSummary',scan.summary||'Model metadata scan completed.'); if(badge){badge.textContent=labelMap[verdict]||verdict;badge.className='badge '+cls} const allGood=(scan.good_signals||[]).filter(Boolean); const good=allGood.slice(0,2); const allRisk=(scan.risk_signals||[]).filter(Boolean); const risk=allRisk.slice(0,3); const outputType=outputTypeFromModelScan(scan); const recommendations=(scan.recommendations||[]).filter(Boolean); const primaryRecommendation=recommendations.find(x=>!String(x).toLowerCase().startsWith('expected output'))||recommendations[0]||''; if(signals){ const metaCards=[ outputType?['↳','Output',outputType,verdict==='safe']:null, scan.pipeline_tag?['◈','Pipeline',scan.pipeline_tag,false]:null, scan.library_name?['◎','Library',scan.library_name,false]:null, ].filter(Boolean).slice(0,3); const compactMeta=metaCards.length?`
${metaCards.map(([icon,k,v,isGood])=>`${escapeHtml(icon)}${escapeHtml(k)}${escapeHtml(String(v))}`).join('')}
`:''; const signalSummaryParts=[]; if(allGood.length)signalSummaryParts.push(`${allGood.length} check${allGood.length>1?'s':''} passed`); if(allRisk.length)signalSummaryParts.push(`${allRisk.length} risk signal${allRisk.length>1?'s':''}`); else if(verdict!=='scanning'&&verdict!=='error')signalSummaryParts.push('No risk signals'); if(primaryRecommendation)signalSummaryParts.push(primaryRecommendation); const summaryTitle=[...allGood,...allRisk,...recommendations].filter(Boolean).join('\n'); const signalSummary=signalSummaryParts.length?`
${verdict==='safe'?'Ready':verdict==='caution'?'Review':verdict==='risky'?'Risk':verdict==='unsupported'?'Unsupported':verdict==='scanning'?'Scanning':'Issue'}${escapeHtml(signalSummaryParts.join(' · '))}
`:''; const goodPreview=(verdict!=='safe'&&good.length)?`
${good.map(x=>`${escapeHtml(x)}`).join('')}
`:''; const riskPills=risk.length?`
${risk.map(x=>`!${escapeHtml(x)}`).join('')}
`:''; const runningPills=verdict==='scanning'?'
Reading model cardChecking metadata
':''; const errorPill=verdict==='error'?`
!${escapeHtml(scan.error||'The scan could not complete. Try again.')}
`:''; const emptyHint=(!compactMeta&&!signalSummary&&!goodPreview&&!riskPills&&!runningPills&&!errorPill)?'
No extra metadata found.
':''; signals.hidden=false; signals.innerHTML=`${compactMeta}${runningPills}${signalSummary}${goodPreview}${riskPills}${errorPill}${emptyHint}`; } if(ackWrap)ackWrap.hidden=!(verdict==='risky'); } function resetModelPreScan(){state.modelScan=null;const ack=$('modelRiskAck');if(ack)ack.checked=false;renderModelPreScan(null);setBuildLaunchEnabled()} function setBuildLaunchEnabled(){const btn=$('launchBuild');const err=validateBuildForm();if(btn)btn.disabled=state.busy||Boolean(err);if($('buildGateText'))setText('buildGateText',err||'Bucket and model pre-scan ready. You can launch builds.')} async function scanModel(){ const model=formValue('modelId'); if(!model){showMessage('Enter a model card URL or model ID before scanning.',true);return} setButtonBusy('scanModel',true,'Scanning…'); renderModelPreScan({ok:true,transient:true,model_id:model,verdict:'scanning',summary:'Reading the model card, Hub metadata and small config files. We do not download model weights.'}); try{ const result=await apiPost('/api/models/pre-scan',{model_id:model}); state.modelScan=result; syncExpectedOutputFromModelScan(result); const ack=$('modelRiskAck');if(ack)ack.checked=false; renderModelPreScan(result); setBuildLaunchEnabled(); showMessage(`Model pre-scan: ${result.verdict} (${result.score}/100)`,result.verdict==='safe'?'success':(result.verdict==='unsupported'||result.verdict==='risky'?true:'warning')); }catch(e){state.modelScan=null;renderModelPreScan({ok:true,transient:true,model_id:model,verdict:'error',summary:'The model pre-scan could not complete. Fix the issue or try again before launching a Job.',error:e.message});showMessage(e.message,true)} finally{setButtonBusy('scanModel',false);setBuildLaunchEnabled()} } function validateBuildForm(){if(!state.bucketReady)return'Create or check your private run bucket before launching a build.';if(!formValue('modelId'))return'Enter a model card URL or model ID.';if(!formValue('piModel'))return'Enter the Pi model to use.';if(!modelScanMatchesCurrent())return'Run the model pre-scan before launching this build.';const verdict=String(state.modelScan?.verdict||'').toLowerCase();if(verdict==='unsupported')return'This model pre-scan marked the repo as unsupported for automatic build.';if(verdict==='risky'&&!$('modelRiskAck')?.checked)return'Review the model pre-scan risk signals and confirm before launching.';return''} function parseJsonField(id,fallback){const raw=formValue(id);if(!raw)return fallback;return JSON.parse(raw)} function prettyJson(value){return JSON.stringify(value,null,2)} function validationTimeoutValue(){const raw=formValue('validateTimeout');if(!raw)return 60;const value=Number(raw);if(!Number.isFinite(value))return NaN;return Math.max(30,Math.min(3600,Math.round(value)))} function validationPayloadSizeError(){const enc=typeof TextEncoder!=='undefined'?new TextEncoder():null;for(const [id,label] of [['testArgs','Test args'],['testKwargs','Test kwargs']]){const text=$(id)?.value||'';const bytes=enc?enc.encode(text).length:text.length;if(bytes>16000)return`${label} JSON is too large for this version (${bytes} bytes). Keep validation payloads under 16 KB and avoid pasted base64/files.`}return''} function validateValidationForm(){if(!formValue('validateSpace'))return'Enter the target Space ID to validate.';const target=formValue('validateSpace');if(state.user?.username&&target.includes('/')&&target.split('/')[0]!==state.user.username)return`For now, Space Test can only validate Spaces in your own namespace (${state.user.username}/...).`;const timeout=validationTimeoutValue();if(!Number.isFinite(timeout))return'Timeout must be a number of seconds.';const sizeError=validationPayloadSizeError();if(sizeError)return sizeError;try{const args=parseJsonField('testArgs',[]);const kwargs=parseJsonField('testKwargs',{});if(!Array.isArray(args))return'Test args must be a JSON array because they are passed as positional arguments to gradio_client.predict(...).';if(!kwargs||Array.isArray(kwargs)||typeof kwargs!=='object')return'Test kwargs must be a JSON object because they are passed as keyword arguments.'}catch(e){return`Invalid JSON payload: ${e.message}`}return''} function setValidationLaunchEnabled(){const btn=$('launchValidate');if(!btn)return;const running=state.validationMode==='running'||Boolean(state.validationRunId&&state.validationDetail&&validationCanonicalStatus(state.validationDetail)==='running');const error=validateValidationForm();btn.disabled=Boolean(state.busy||running||error);btn.title=error||''} function validationIsTerminalStatus(status){const canonical=String(status||'').toLowerCase();return ['full_inference_success','partial_validation','manual_hardware_required','failed','stale','stopped'].includes(canonical)} function validationIsNonTerminalStatus(status){const canonical=String(status||'').toLowerCase();return !canonical||['running','pending','waiting','started','queued','building','unknown'].includes(canonical)} function validationDetailRunId(detail={}){return detail.run_id||detail.summary?.run_id||detail.state?.run_id||detail.launch?.run_id||''} function rememberTerminalValidation(detail={}){const runId=validationDetailRunId(detail)||state.validationRunId;const canonical=validationCanonicalStatus(detail);if(runId&&validationIsTerminalStatus(canonical)){state.validationTerminalByRun=state.validationTerminalByRun||{};state.validationTerminalByRun[runId]={canonical,detail:{...detail,_terminalLocked:true}};}return canonical} function terminalValidationForRun(runId=state.validationRunId){return runId&&state.validationTerminalByRun?state.validationTerminalByRun[runId]||null:null} function mergeValidationWithTerminalLock(incoming={},runId=state.validationRunId){const terminal=terminalValidationForRun(runId);if(!terminal)return incoming;const incomingCanonical=validationCanonicalStatus(incoming);if(validationIsNonTerminalStatus(incomingCanonical)){return {...(terminal.detail||{}),_refreshing:true,_ignoredIncomingStatus:incomingCanonical};}return incoming;} function shouldIgnoreValidationUpdate(incoming={},runId=state.validationRunId){const incomingCanonical=validationCanonicalStatus(incoming);const terminal=terminalValidationForRun(runId);if(terminal&&incomingCanonical==='running')return true;return Boolean(terminal&&validationIsNonTerminalStatus(incomingCanonical));} function extractEffectiveValidationPayload(detail={}){const smoke=detail.generation_smoke||detail.summary?.generation_smoke||detail.state?.generation_smoke||{};const payload=detail.validation_payload||detail.tests?.validation_payload||detail.summary?.validation_payload||{};const args=firstArrayPath(detail.effective_args,smoke.effective_args,payload.effective_args,smoke.test_args,payload.test_args);const kwargs=firstObjectPath(detail.effective_kwargs,smoke.effective_kwargs,payload.effective_kwargs,smoke.test_kwargs,payload.test_kwargs);const source=detail.args_source||smoke.args_source||payload.args_source||'';return {args,kwargs,source,argsWereAutofilled:Boolean(detail.args_were_autofilled||smoke.args_were_autofilled||payload.args_were_autofilled||source==='gradio_schema_auto_fill')};} function applyEffectiveValidationArgs(detail={}){const payload=extractEffectiveValidationPayload(detail);if(!payload.argsWereAutofilled||!Array.isArray(payload.args))return;if(state.validationArgsDirty)return;setInputValue('testArgs',prettyJson(payload.args));if(payload.kwargs&&typeof payload.kwargs==='object'&&!Array.isArray(payload.kwargs))setInputValue('testKwargs',prettyJson(payload.kwargs));const note=$('spaceTestArgsNote');if(note){note.hidden=false;note.textContent='Arguments filled from discovered Gradio schema.';} } function setBuildModeNew(){const panel=$('buildModePanel');if(panel){panel.classList.remove('inspecting');panel.innerHTML='Preparing a new build

This form launches new builds. Existing runs can be inspected in the Runs Explorer on the right.

'}const launch=$('launchResultPanel');if(launch)launch.hidden=true;const status=$('progressStatus');if(status){status.textContent='Idle';status.className='badge neutral'}setText('progressTitle','No run selected')} function setBuildModeInspecting(runId){const panel=$('buildModePanel');if(panel){panel.classList.add('inspecting');panel.innerHTML=`Inspecting selected run

You are viewing run ${escapeHtml(runId||'')}. The build form is unchanged and the active run panel is now tracking it.

`}} function renderActiveRunEmptyState(){ const timeline=$('timeline'); if(timeline){timeline.dataset.signature='empty';timeline.className='timeline empty-timeline';timeline.innerHTML='
No active run selectedLaunch a build or select a run from Runs Explorer. The timeline will appear once a run starts.
';if(timeline.style?.removeProperty)timeline.style.removeProperty('--timeline-phase-count');} const note=$('timelineTraceNote');if(note){note.hidden=true;note.innerHTML='';note.className='timeline-trace-note';} const details=$('timelinePhaseDetails');if(details){details.hidden=true;details.innerHTML='';details.className='timeline-phase-details';} } function resetRunDetails(){ const cancel=$('cancelRun');if(cancel)cancel.disabled=true; if(typeof elapsedClock!=='undefined')elapsedClock.isRunning=false;if(typeof resetProgressStability==='function')resetProgressStability(null); if(typeof activityFeedState!=='undefined'){activityFeedState.lastItems=[];activityFeedState.runId=null} for(const [id,value] of [ ['detailRunId','—'],['detailJobStatus','—'],['detailGateStatus','—'],['detailSpace','—'],['detailHardware','—'],['detailTargetGpu','—'],['detailFallbackGpu','—'],['detailExpectedOutput','—'],['detailPiAssistant','—'],['detailTraces','—'], ['homeRunDetailStatus','No run'],['selectedModelId','—'],['progressTitle','No run selected'],['progressStatus','Idle'], ['currentStep','—'],['lastEvent','Select a run from the explorer or launch a new build.'],['elapsed','—'],['lastPolled','—'], ['progressPercent','0%'] ])setText(id,value); setText('activeLatencyValue','—');setText('activeZeroGpuDuration','—');setText('activeLatencySource','waiting for live smoke test');const latencyCard=$('activeLatencyCard');if(latencyCard){latencyCard.classList.remove('has-latency');latencyCard.classList.add('is-loading')} const status=$('progressStatus');if(status)status.className='badge neutral'; const fill=$('progressFill');if(fill){fill.style.width='0%';fill.classList.remove('is-running','progress-bump','is-success','is-warn','is-error','is-running-state','is-stopped','is-neutral')}const cap=$('progressCaptionLabel');if(cap)cap.textContent='Overall progress';const sem=$('progressSemantics');if(sem){sem.hidden=true;sem.innerHTML=''}const bar=$('progressBar');if(bar)bar.setAttribute('aria-valuenow','0') setQuickLinks({}); const full=$('reportPreview');if(full)full.textContent='No report selected.'; const manual=$('manualActionPanel');if(manual)manual.hidden=true; const activity=$('activityFeed');if(activity){activity.dataset.signature='';activity.classList.remove('show-all');activity.innerHTML='
No activity yet.
'} const events=$('eventsPanel');if(events)events.textContent='No events yet.'; const artifacts=$('artifactList');if(artifacts)artifacts.textContent='No artifacts indexed yet.'; const recovery=$('agentRecoveryCard');if(recovery){recovery.hidden=true;const body=$('agentRecoveryBody');if(body)body.innerHTML='';const badge=$('agentRecoveryBadge');if(badge){badge.textContent='Not needed';badge.className='badge neutral'}} const docs=$('runDocumentsDock');if(docs)docs.innerHTML='
Run documents will appear as files are written to the bucket.
'; const blockers=$('selectedBlockers');if(blockers){blockers.hidden=true;blockers.innerHTML=''} for(const id of ['deleteActiveRun','activePrefillSpaceTest','deleteValidationRun']){const btn=$(id);if(btn)btn.disabled=true} // legacy anchor: renderTimeline(DEFAULT_TIMELINE,'idle') renderActiveRunEmptyState(); } function prepareNewBuild(){if(state.poll){clearInterval(state.poll);state.poll=null}state.runId=null;state.activeRunProgress=null;state.selectedRunDetail=null;state.documentCache={};state.latencyCache={};state.activeLinks={};state.pollErrors=0;clearSavedRun();document.querySelectorAll('.run-row').forEach(r=>r.classList.remove('selected'));setBuildModeNew();resetRunDetails();setText('progressPercent','0%');const cap=$('progressCaptionLabel');if(cap)cap.textContent='Overall progress';const sem=$('progressSemantics');if(sem){sem.hidden=true;sem.innerHTML=''}const fill=$('progressFill');if(fill)fill.style.width='0%';setText('currentStep','Ready');setText('lastEvent','Choose a model card and launch a build.');setText('elapsed','—');if(typeof elapsedClock!=='undefined')elapsedClock.isRunning=false;setText('lastPolled','—');setText('hardwarePlan',hardwarePlanLabel());renderMetrics({});showMessage('New build mode ready.','info')} function setActiveRun(result){if(state.poll){clearInterval(state.poll);state.poll=null}resetRunDetails();state.documentCache={};state.latencyCache={};state.runId=result.run_id;state.spaceLinksUnlockedFor=null;if(Array.isArray(state.runsCache)&&typeof sortRunsNewestFirst==='function'){state.runsCache=sortRunsNewestFirst([{...result,run_id:result.run_id,status:result.status||'running',created_at:result.created_at||new Date().toISOString()},...state.runsCache.filter(r=>r.run_id!==result.run_id)]);renderRunsFromCache();}if(result.bucket_source)state.bucketSource=result.bucket_source;setText('detailRunId',result.run_id);setText('detailJobStatus',result.status||'RUNNING');setText('detailGateStatus',result.kind||'running');setText('detailSpace',result.target_space||'—');setText('detailHardware',result.selected_hardware||result.preferred_space_hardware||'—');renderActiveRunMeta({summary:result,state:result,launch:result});renderProgress({run_id:result.run_id,status:result.status||'running',progress:1,current_step_label:'Launching build Job…',events:[{step:'launch',status:'started',message:'Build Job launched; waiting for first worker event.'}],summary:result,state:result});setText('homeRunDetailStatus',result.status||'Running');setBuildModeInspecting(result.run_id);setQuickLinks({...result.links,bucket_source:result.bucket_source,run_id:result.run_id,job_id:result.job_id,job_owner:state.user?.username,target_space_url:result.target_space_url},result);saveActiveRun();markPendingActiveFields();startPolling(result.run_id)} function startPolling(runId,options={}){ if(!runId)return; const sameRun=state.runId===runId; if(sameRun&&state.poll)return; if(!sameRun){ state.spaceLinksUnlockedFor=null; const blockers=$('selectedBlockers');if(blockers){blockers.hidden=true;blockers.innerHTML=''} } state.runId=runId; state.pollErrors=0; state.lastJobLogPoll=0; if(typeof resetProgressStability==='function')resetProgressStability(runId); if(state.poll)clearInterval(state.poll); saveActiveRun(); if(!options.deferFirstTick)refreshProgress(); else setTimeout(()=>{if(state.runId===runId)refreshProgress()},80); state.poll=setInterval(refreshProgress,2000); } async function bootstrapRunRecovery(){return restoreActiveRun()} async function restoreActiveRun(){try{const resumable=await apiGet(`/api/runs/resumable?bucket_name=${encodeURIComponent(state.bucketName)}`);if(resumable?.run?.run_id){state.runId=resumable.run.run_id;if(resumable.bucket_source)state.bucketSource=resumable.bucket_source;setBuildModeInspecting(state.runId);if(resumable.view)renderRunViewModel(resumable.view,{progress:0,events:[]});setQuickLinks(resumable.view?.links||{},resumable.view||{});startPolling(state.runId);return true}}catch(e){console.warn('resumable lookup failed',e)}try{const raw=localStorage.getItem('asf.activeRun');if(!raw)return false;const saved=JSON.parse(raw);if(saved?.bucketName)state.bucketName=saved.bucketName;if(saved?.runId){state.runId=saved.runId;setText('detailRunId',saved.runId);setQuickLinks(saved.links||{},{});setBuildModeInspecting(saved.runId);startPolling(saved.runId);return true}}catch(_){}return false} async function refreshAnonymousEvalStatus(){ try{ const anonymous_eval=await apiGet('/api/eval-archive/status'); renderAnonymousEvalStatus({anonymous_eval}); return anonymous_eval; }catch(e){ renderAnonymousEvalStatus({anonymous_eval:{enabled:false,reason:'status_unavailable',managed_by:'instance owner'}}); return null; } } async function loadAppInfo(){setOperation('Checking sign-in and run storage…','loading');setBucketFeedback('checking','Checking private bucket access…');try{const me=await apiGet('/api/me');state.user=me;renderAnonymousEvalStatus(me);setText('userChip','@'+me.username);const userChip=$('userChip');if(userChip)userChip.href=`https://huggingface.co/${me.username}`;const logout=$('logoutLink');if(logout){logout.hidden=false;logout.href=me.logout_url||'/logout'}state.bucketSource=me.username+'/'+state.bucketName;setText('bucketInlineLabel',state.bucketSource);renderAuthWarnings(me);renderBillingPanel(me);loadBillingStatus().catch(()=>{});await checkBucket(false);await loadRuns(true);clearSavedRun();if(!state.bucketReady)setOperation('Create your private run bucket before launching builds.','warning');else setOperation('')}catch(e){state.user=null;await refreshAnonymousEvalStatus();setText('userChip','Sign in');const userChip=$('userChip');if(userChip)userChip.href='/oauth/huggingface/login';const logout=$('logoutLink');if(logout)logout.hidden=true;renderSignedOut();renderBillingPanel(null);setBucketReady(false,'Sign in with Hugging Face first.');showMessage('Please sign in with Hugging Face, then refresh this page.',true)}} function renderSignedOut(){const auth=$('authPanel');if(!auth)return;auth.hidden=false;auth.className='auth-panel warning';auth.innerHTML='Sign in required

Use Hugging Face OAuth before launching Jobs or reading your Bucket.

Sign in with Hugging Face ↗'} function renderAuthWarnings(me){const auth=$('authPanel');if(!auth)return;const missing=me.missing_scopes||[];const warnings=me.warnings||[];if(!missing.length&&!warnings.length){auth.hidden=true;auth.innerHTML='';return}auth.hidden=false;auth.className='auth-panel warning';auth.innerHTML=`OAuth session warning

${escapeHtml([...warnings,missing.length?'Missing scopes: '+missing.join(', '):''].filter(Boolean).join(' • '))}

Refresh sign-in ↗`} function renderBillingPanel(info){ // Open HF Billing: Live quotas, spend and compute usage remain in the HF Billing dashboard. const badge=$('billingStatusBadge'); const canPay=info?.can_pay===true||info?.payment_ready===true; if(badge){ badge.textContent=canPay?'Billing ready':'Check billing'; badge.className='badge '+(canPay?'success':'warn'); } const billing=$('openBilling'); if(billing)billing.href=info?.links?.billing||'https://huggingface.co/settings/billing'; } async function loadBillingStatus(){ try{const data=await apiGet('/api/billing/status');renderBillingPanel({...state.user,...data});return data}catch(e){console.warn('billing status failed',e);return null} } async function enableEvalArchive(){ const me=state.user; const cfg=me?.anonymous_eval||{}; const bucketSource=cfg.proposed_bucket_source||(me?.username?`${me.username}/agentic-space-factory-evals`:null); if(!bucketSource){showMessage('Sign in before enabling the eval archive.',true);return} setButtonBusy('enableEvalArchive',true,'Enabling…'); try{ const result=await apiPost('/api/eval-archive/activate',{bucket_source:bucketSource,bucket_path:cfg.default_bucket_path||'evals',mount_path:cfg.default_mount_path||'/evals'}); state.user={...(state.user||{}),anonymous_eval:result}; renderAnonymousEvalStatus(state.user); showMessage(result.message||`Eval archive enabled: ${bucketSource}`,'success'); }catch(e){showMessage(e.message,true)} finally{setButtonBusy('enableEvalArchive',false)} } async function verifyEvalArchive(){ setButtonBusy('verifyEvalArchive',true,'Verifying…'); try{ const result=await apiGet('/api/eval-archive/status'); state.user={...(state.user||{}),anonymous_eval:result}; renderAnonymousEvalStatus(state.user); showMessage(result.enabled?'Eval archive configuration verified.':'Eval archive is not enabled.',result.enabled?'success':'warning'); }catch(e){showMessage(e.message,true)} finally{setButtonBusy('verifyEvalArchive',false)} } async function disableEvalArchive(){ const ok=window.confirm('Disable anonymous eval publishing for this ASF instance? Existing archived records will not be deleted.'); if(!ok)return; setButtonBusy('disableEvalArchive',true,'Disabling…'); try{ const result=await apiPost('/api/eval-archive/disable',{}); state.user={...(state.user||{}),anonymous_eval:result}; renderAnonymousEvalStatus(state.user); showMessage(result.message||'Eval archive disabled.','success'); }catch(e){showMessage(e.message,true)} finally{setButtonBusy('disableEvalArchive',false)} } async function checkBucket(noisy=true){setButtonBusy('checkBucket',true,'Checking…');setBucketFeedback('checking','Checking private bucket access…');try{const data=await apiGet(`/api/bucket/status?bucket_name=${encodeURIComponent(state.bucketName)}`);const source=data.bucket_source||state.bucketName;state.bucketSource=source;setText('bucketInlineLabel',source);setBucketReady(Boolean(data.ok),data.error||'Create your private run bucket before launching builds.');if(noisy)showMessage(data.ok?`Bucket ready: ${source}`:`Bucket not ready: ${data.error||'not found'}`,!data.ok);return data}catch(e){setBucketReady(false,e.message);if(noisy)showMessage(e.message,true);throw e}finally{setButtonBusy('checkBucket',false)}} async function createBucket(){setButtonBusy('createBucket',true,'Creating…');setBucketFeedback('creating','Creating private bucket…');try{const data=await apiPost('/api/bucket/create',{bucket_name:state.bucketName});const source=data.bucket_source||state.bucketName;state.bucketSource=source;setText('bucketInlineLabel',source);setBucketReady(Boolean(data.ok),data.error||'Could not create bucket.');showMessage(data.ok?`Created/ready: ${source}`:`Could not create bucket: ${data.error}`,!data.ok);if(data.ok)loadRuns(true)}catch(e){setBucketReady(false,e.message);showMessage(e.message,true)}finally{setButtonBusy('createBucket',false)}} function switchCenterTab(tab='active'){ const next=tab==='validate'?'validate':'active'; state.centerTab=next; document.querySelectorAll('[data-center-tab]').forEach(btn=>{ const active=btn.dataset.centerTab===next; btn.classList.toggle('active',active); btn.setAttribute('aria-selected',active?'true':'false'); }); document.querySelectorAll('[data-center-panel]').forEach(panel=>{ const active=panel.dataset.centerPanel===next; panel.classList.toggle('active',active); panel.hidden=!active; }); } function renderManualAction(p={}){const panel=$('manualActionPanel');if(!panel)return;const view=p.view||{};const sm=view.status_model||{};const status=String(p.status||p.state?.status||p.inference_gate?.status||sm.global_status||'');const manual=Boolean(sm.requires_manual_action||p.manual_hardware_required||p.inference_gate?.manual_hardware_required||p.hardware_strategy?.manual_action_required||status.includes('manual_hardware_required')||status.includes('generated_needs_manual_hardware')||status.includes('waiting_manual_action'));panel.hidden=!manual;if(!manual)return;setText('manualActionTitle','Manual hardware required');setText('manualActionText','Automatic hardware selection was not available. Open Space settings, choose the recommended GPU, then run Space Test.');setLink('manualOpenSettings',(p.links||view.links||state.activeLinks||{}).target_space_settings_url)} function defaultValidationArgs(expected='text'){ const kind=String(expected||'text').toLowerCase(); if(kind==='image')return ["a cinematic robot cat astronaut, detailed, studio lighting"]; if(kind==='video')return ["a short cinematic shot of a robot cat astronaut walking on the moon"]; if(kind==='audio')return ["A calm voice saying hello from Agentic Space Factory."]; return ["Explain the concept of agentic AI in one paragraph."]; } function normalizeApiName(value){ value=String(value||'').trim(); if(!value)return'/generate'; return value.startsWith('/')?value:'/'+value; } function firstPositiveNumber(...values){ for(const value of values.flat()){ const n=Number(value); if(Number.isFinite(n)&&n>0)return n; } return null; } function formatLatencySeconds(value){ const n=Number(value); if(!Number.isFinite(n)||n<=0)return'—'; if(n<10)return`${n.toFixed(2).replace(/\.00$/,'')}s`; if(n<60)return`${n.toFixed(1).replace(/\.0$/,'')}s`; return fmtSeconds(Math.round(n)); } function parsedJsonOrNull(value){ if(value==null||value==='')return null; try{return typeof value==='string'?JSON.parse(value):value}catch(_){return null} } function firstArrayPath(...values){ for(const value of values){ if(Array.isArray(value))return value; const parsed=parsedJsonOrNull(value); if(Array.isArray(parsed))return parsed; } return null; } function firstObjectPath(...values){ for(const value of values){ if(value&&typeof value==='object'&&!Array.isArray(value))return value; const parsed=parsedJsonOrNull(value); if(parsed&&typeof parsed==='object'&&!Array.isArray(parsed))return parsed; } return null; } function testPayloadFromEndpointParameters(parameters=[],expected='text'){ if(!Array.isArray(parameters)||!parameters.length)return null; const args=[]; for(const param of parameters){ const name=String(param?.name||param?.parameter_name||param?.label||'').toLowerCase(); const component=String(param?.component||param?.component_type||param?.type||'').toLowerCase(); const choices=Array.isArray(param?.choices)?param.choices:(Array.isArray(param?.options)?param.options:[]); if(name.includes('negative'))args.push(''); else if(name.includes('prompt'))args.push(defaultValidationArgs(expected)[0]); else if(name.includes('resolution')&&choices.length)args.push(String(choices[0])); else if(name.includes('height'))args.push(Number(param?.default||1024)); else if(name.includes('width'))args.push(Number(param?.default||1024)); else if(name.includes('step'))args.push(Number(param?.default||9)); else if(name.includes('guidance'))args.push(Number(param?.default||0)); else if(name.includes('seed')&&component.includes('checkbox'))args.push(Boolean(param?.default??true)); else if(name.includes('random')&&name.includes('seed'))args.push(Boolean(param?.default??true)); else if(name.includes('seed'))args.push(Number(param?.default??42)); else if(choices.length)args.push(String(choices[0])); else if(component.includes('checkbox'))args.push(Boolean(param?.default??false)); else if(component.includes('number')||component.includes('slider'))args.push(Number(param?.default??0)); else args.push(param?.default??''); } return args.length?args:null; } function validationPrefillFromDetail(detail={}){ const progress=(state.activeRunProgress&&((state.activeRunProgress.run_id||state.activeRunProgress.summary?.run_id)===(detail.run_id||detail.summary?.run_id||state.runId)))?state.activeRunProgress:{}; const summary={...(detail.summary||{}),...(progress.summary||{})}; const gate={...(detail.inference_gate||{}),...(progress.inference_gate||{})}; const gateSmoke=gate.generation_smoke&&typeof gate.generation_smoke==='object'?gate.generation_smoke:{}; const smoke={...(detail.state?.generation_smoke||{}),...(detail.tests?.generation_smoke||{}),...(detail.generation_smoke||{}),...(progress.generation_smoke||{}),...(progress.state?.generation_smoke||{}),...gateSmoke}; const launch={...(detail.launch||{}),...(progress.launch||{})}; const stateObj={...(detail.state||{}),...(progress.state||{})}; const expected=smoke.expected_output_type||gate.expected_output_type||launch.expected_output_type||summary.expected_output_type||stateObj.expected_output_type||formValue('buildExpectedOutput')||'text'; const endpointParameters=smoke.parameters||smoke.endpoint_parameters||gate.endpoint_parameters||gate.smoke_parameters||[]; let args=firstArrayPath(smoke.test_args,smoke.args,gate.test_args,gateSmoke.test_args,launch.test_args_json,summary.test_args_json); if(!Array.isArray(args))args=testPayloadFromEndpointParameters(endpointParameters,expected); let kwargs=firstObjectPath(smoke.test_kwargs,smoke.kwargs,gate.test_kwargs,gateSmoke.test_kwargs,launch.test_kwargs_json,summary.test_kwargs_json); if(!Array.isArray(args))args=defaultValidationArgs(expected); if(!kwargs||Array.isArray(kwargs)||typeof kwargs!=='object')kwargs={}; const target=summary.target_space||stateObj.target_space||launch.target_space||progress.target_space||$('detailSpace')?.textContent||''; const api=normalizeApiName(smoke.api_name||gate.api_name||launch.api_name||gateSmoke.api_name||progress.api_name||'/generate'); return {target,api,expected,args,kwargs}; } function renderValidationStatus(data={}){ const candidateRunId=validationDetailRunId(data)||state.validationRunId; data=mergeValidationWithTerminalLock(data||state.validationDetail||{},candidateRunId); state.validationDetail=data||state.validationDetail; const summary=data.summary||{}; const smoke=data.generation_smoke||data.summary?.generation_smoke||data.state?.generation_smoke||{}; const canonical=validationCanonicalStatus(data); const displayStatus={idle:'idle',full_inference_success:'full inference success',partial_validation:'partial validation',manual_hardware_required:'manual action required',failed:'failed',stale:'stale',stopped:'stopped',running:'running'}[canonical]||canonical; const klass=statusClass(displayStatus); const isRunning=canonical==='running'; const isIdle=canonical==='idle'; const runIdForState=validationDetailRunId(data)||state.validationRunId; if(runIdForState)rememberTerminalValidation(data); applyEffectiveValidationArgs(data); const badge=$('spaceTestStatus'); if(badge){badge.textContent=badgeLabel(displayStatus);badge.className='badge '+klass} const tabDot=$('spaceTestTabDot'); if(tabDot)tabDot.className='tab-status-dot '+(isRunning?'running':klass); const card=$('spaceTestPreview'); if(card)card.classList.toggle('is-validating',isRunning); const runId=data.run_id||summary.run_id||state.validationRunId||'—'; setText('spaceTestOutput',isIdle?'—':runId); setText('validationStartedAt',isIdle?'Not launched':formatTime(data.updated_at||summary.updated_at||data.state?.updated_at||data.created_at||summary.created_at||new Date().toISOString())); const latency=firstPositiveNumber(smoke.latency_seconds,smoke.observed_latency_seconds,summary.latency_seconds,summary.observed_latency_seconds,data.latency_seconds,data.observed_latency_seconds); setText('spaceTestLatency',isIdle?'—':(latency?formatLatencySeconds(latency):(canonical==='running'?'—':'Not recorded'))); setText('spaceTestVerdict',isIdle?(data.message||'No validation run selected.'):data._refreshing?`${badgeLabel(displayStatus)} · Refreshing…`:badgeLabel(displayStatus)); const launchBtn=$('launchValidate'); if(launchBtn&&!(launchBtn.classList?.contains&&launchBtn.classList.contains('is-busy')))launchBtn.textContent=runId&&runId!=='—'&&!isRunning&&!isIdle?'Run validation again':'Launch validation'; setValidationLaunchEnabled(); const deleteBtn=$('deleteValidationRun'); if(deleteBtn){deleteBtn.disabled=isIdle||!(runId&&runId!=='—')||isRunning;deleteBtn.onclick=(!deleteBtn.disabled)?()=>deleteRunById(runId,{kind:'validation',detail:data}):null;} // Legacy invariant: deleteBtn.onclick=()=>deleteRunById is still owned by renderValidationStatus, not bindActions. const percent=validationProgressPercent(data); setText('spaceTestProgressPercent',isIdle?'0%':`${Math.round(percent)}%`); const fill=$('spaceTestProgressFill'); if(fill){ fill.style.width=isIdle?'0%':`${Math.max(0,Math.min(100,percent))}%`; fill.className='validation-progress-fill '+(isRunning?'is-running':klass); } if(isIdle){const timeline=$('spaceTestTimeline');if(timeline)timeline.innerHTML='
No validation run selected.
';const endpoints=$('spaceTestEndpoints');if(endpoints)endpoints.innerHTML='
Endpoint schema will appear after a validation run.
';}else{renderValidationTimeline(data);renderValidationEndpoints(data);} } function resetValidationRunView({reason='idle'}={}){ stopValidationPolling(); state.validationMode='idle'; state.validationRunId=null; state.validationDetail=null; state.validationPrefillDraft=null; renderValidationStatus({status:'idle',run_id:'—',events:[],message:reason==='deleted'?'Validation run deleted.':'No validation run selected.'}); setValidationLaunchEnabled(); } function renderValidationLaunchResult(result={}){ state.validationRunId=result.run_id; renderValidationStatus({...result,status:result.status||'running'}); } function renderValidationTimeline(detail={}){ const root=$('spaceTestTimeline'); if(!root)return; const items=validationTimelineItems(detail); root.innerHTML=items.map((item,idx)=>{ const st=statusClass(item.status||'pending'); const label=item.label||String(item.step||`Step ${idx+1}`).replace(/_/g,' '); return `
${escapeHtml(label)}${escapeHtml(badgeLabel(item.status||'pending'))}
`; }).join('')||'
No validation events yet.
'; } function showValidationRunDetail(detail={}){ const incomingRunId=detail.run_id||detail.summary?.run_id||state.validationRunId; state.validationRunId=incomingRunId; detail=mergeValidationWithTerminalLock(detail,incomingRunId); state.validationMode='view'; state.validationDetail=detail; state.validationPrefillDraft=null; rememberTerminalValidation(detail); stopValidationPolling(); renderValidationStatus(detail); applyValidationPrefill(detail,'validation run',{preserveSelection:true}); switchCenterTab('validate'); if(state.validationRunId&&validationCanonicalStatus(detail)==='running')startValidationPolling(state.validationRunId); } function stopValidationPolling(){ if(state.validationPoll){clearInterval(state.validationPoll);state.validationPoll=null} state.validationPollToken=null; } async function refreshValidationProgress(pollToken=state.validationPollToken){ const requestedRunId=state.validationRunId; if(!requestedRunId)return; try{ const p=await apiGet(`/api/runs/${encodeURIComponent(requestedRunId)}/progress?bucket_name=${encodeURIComponent(state.bucketName)}&include_job_logs=1`); if(pollToken!==state.validationPollToken||requestedRunId!==state.validationRunId)return; if(shouldIgnoreValidationUpdate(p,requestedRunId)){const terminal=terminalValidationForRun(requestedRunId);if(terminal){renderValidationStatus({...terminal.detail,_refreshing:true});stopValidationPolling();loadRuns(false);}return;} state.validationPollErrors=0; renderValidationStatus(p); const canonical=validationCanonicalStatus(p); if(validationIsTerminalStatus(canonical)){state.validationMode='view';rememberTerminalValidation(p);stopValidationPolling();showMessage(`Validation finished: ${badgeLabel(canonical)}`,statusClass(canonical)==='success'?'success':statusClass(canonical)==='error'?'error':'warning');loadRuns(false)} }catch(e){ if(pollToken!==state.validationPollToken||requestedRunId!==state.validationRunId)return; state.validationPollErrors+=1; console.warn('validation polling failed',e); if(state.validationPollErrors<=2)showMessage(`Validation polling failed. Retrying…`,'warning'); } } function startValidationPolling(runId){ const terminal=terminalValidationForRun(runId); if(terminal){stopValidationPolling();state.validationMode='view';state.validationRunId=runId;renderValidationStatus({...terminal.detail,_refreshing:true});return;} stopValidationPolling(); state.validationMode='running'; state.validationRunId=runId; state.validationPollToken=`${runId}:${Date.now()}:${++state.validationRequestSeq}`; switchCenterTab('validate'); refreshValidationProgress(state.validationPollToken); state.validationPoll=setInterval(()=>refreshValidationProgress(state.validationPollToken),3000); } function renderValidationPrefillDraft(prefill={},sourceLabel='selected Space'){ stopValidationPolling(); state.validationMode='draft'; state.validationRunId=null; state.validationDetail=null; state.validationArgsDirty=false; state.validationPrefillDraft={...prefill,sourceLabel,sourceRunId:prefill.sourceRunId||state.runId||''}; const badge=$('spaceTestStatus'); if(badge){badge.textContent='Ready';badge.className='badge neutral'} const tabDot=$('spaceTestTabDot'); if(tabDot)tabDot.className='tab-status-dot neutral'; const card=$('spaceTestPreview'); if(card)card.classList.remove('is-validating'); setText('spaceTestOutput','New validation'); setText('validationStartedAt','Not launched'); setText('spaceTestLatency','—'); setText('spaceTestVerdict',`Prepared from ${sourceLabel}`); setText('spaceTestProgressPercent','0%'); const fill=$('spaceTestProgressFill'); if(fill){fill.style.width='0%';fill.className='validation-progress-fill neutral'} const timeline=$('spaceTestTimeline'); if(timeline){ timeline.innerHTML=VALIDATION_PHASES.map(([id,label],idx)=>`
${escapeHtml(label)}${idx===0?'Ready':'Pending'}
`).join(''); } const endpoints=$('spaceTestEndpoints'); if(endpoints)endpoints.innerHTML='
Endpoint schema will be discovered when this validation runs.
'; const launchBtn=$('launchValidate'); if(launchBtn&&!launchBtn.classList.contains('is-busy'))launchBtn.textContent='Launch validation'; setValidationLaunchEnabled(); const deleteBtn=$('deleteValidationRun'); if(deleteBtn){deleteBtn.disabled=true;deleteBtn.onclick=null;} if(typeof renderRunsFromCache==='function')renderRunsFromCache(); } function applyValidationPrefill(detail={},sourceLabel='selected Space',options={}){ const prefill=validationPrefillFromDetail(detail); if(prefill.target&&prefill.target!=='—')setInputValue('validateSpace',prefill.target); setInputValue('expectedOutput',prefill.expected); setInputValue('validateApi',prefill.api); setInputValue('testArgs',prettyJson(prefill.args)); setInputValue('testKwargs',prettyJson(prefill.kwargs)); state.validationArgsDirty=false; const note=$('spaceTestArgsNote');if(note)note.hidden=true; switchCenterTab('validate'); if(!options.preserveSelection)renderValidationPrefillDraft(prefill,sourceLabel); showMessage(`Prepared validation form for ${prefill.target||sourceLabel}.`,'info'); } function prepareValidationFromActiveRun(){ const selected=((state.selectedRunDetail?.run_id===state.runId||state.selectedRunDetail?.summary?.run_id===state.runId)?state.selectedRunDetail:{}); const activeDetail={...selected,...(state.activeRunProgress||{}),summary:{...(selected.summary||{}),...(state.activeRunProgress?.summary||{})}}; applyValidationPrefill(activeDetail,'active run',{preserveSelection:false}); } function prepareValidationFromSelectedRun(){ applyValidationPrefill(state.selectedRunDetail||{},'selected run',{preserveSelection:false}); } async function launchBuild(){const formError=validateBuildForm();if(formError){showMessage(formError,true);return}setBusy(true,'Launching build Job…');setButtonBusy('launchBuild',true,'Launching…');try{setText('hardwarePlan',hardwarePlanLabel());const payload={bucket_name:state.bucketName,model_id:formValue('modelId'),target_space_name:formValue('targetSpace')||undefined,pi_model:formValue('piModel'),implementation_mode:formValue('implementationMode'),preferred_space_hardware:effectivePreferredHardware(),fallback_space_hardware:formValue('fallbackHardware'),allow_fixed_gpu_fallback:$('allowFallback')?.checked??true,try_zero_gpu_first:$('tryZeroGpu')?.checked??true,expected_output_type:formValue('buildExpectedOutput')};const result=await apiPost('/api/build',payload);setActiveRun(result);showMessage(`Build launched: ${result.run_id}`,'success');loadRuns(true)}catch(e){showMessage(e.message,true)}finally{setBusy(false);setButtonBusy('launchBuild',false)}} async function launchValidate(){const formError=validateValidationForm();if(formError){showMessage(formError,true);return}setBusy(true,'Launching validation Job…');setButtonBusy('launchValidate',true,'Launching…');try{const args=parseJsonField('testArgs',[]);const kwargs=parseJsonField('testKwargs',{});const payload={bucket_name:state.bucketName,target_space_id:formValue('validateSpace'),api_name:normalizeApiName(formValue('validateApi')||'/generate'),expected_output_type:formValue('expectedOutput')||'any',test_args_json:prettyJson(args),test_kwargs_json:prettyJson(kwargs),live_timeout_seconds:validationTimeoutValue()};const result=await apiPost('/api/validate',payload);state.validationPrefillDraft=null;state.validationArgsDirty=false;state.validationMode='running';renderValidationLaunchResult(result);startValidationPolling(result.run_id);showMessage(`Validation launched: ${result.run_id}`,'success');loadRuns(true)}catch(e){showMessage(e.message,true)}finally{setBusy(false);setButtonBusy('launchValidate',false)}} async function refreshRunReportPreview(runId){ if(!runId)return; try{ const detail=await apiGet(`/api/runs/${encodeURIComponent(runId)}?bucket_name=${encodeURIComponent(state.bucketName)}`); if(detail.bucket_source)state.bucketSource=detail.bucket_source; state.selectedRunDetail=detail; if(typeof renderRunDetail==='function')renderRunDetail(detail); if(typeof renderActiveRunActions==='function')renderActiveRunActions(detail.summary||{},detail); if(typeof renderRunDocuments==='function')renderRunDocuments(detail); if(typeof renderMetrics==='function')renderMetrics({...detail,summary:detail.summary||{}}); if(typeof renderBlockers==='function')renderBlockers(detail);markPendingActiveFields(); if(typeof renderRunDetail!=='function'){ const reportText=(detail.report||'No report available.').slice(0,8000); const report=$('reportPreview'); if(report)report.textContent=reportText; } }catch(e){ console.warn('report refresh failed',e); } } async function refreshProgress(){if(!state.runId||state.progressPollInFlight)return;state.progressPollInFlight=true;try{const now=Date.now();const includeLogs=!state.lastJobLogPoll||now-state.lastJobLogPoll>8000;if(includeLogs)state.lastJobLogPoll=now;const requestedRunId=state.runId;const p=await apiGet(`/api/runs/${encodeURIComponent(requestedRunId)}/progress?bucket_name=${encodeURIComponent(state.bucketName)}${includeLogs?'&include_job_logs=1':''}`);if(requestedRunId!==state.runId)return;if((p.run_id||p.summary?.run_id)&&state.runId&&(p.run_id||p.summary?.run_id)!==state.runId)return;state.activeRunProgress=p;state.pollErrors=0;if(p.bucket_source)state.bucketSource=p.bucket_source;renderProgress(p);renderEvents(p.events||[]);renderMetrics(p);if(typeof upsertRunExplorerFromProgress==='function')upsertRunExplorerFromProgress(p);if(typeof renderActiveRunActions==='function')renderActiveRunActions({...p.summary,bucket_source:p.bucket_source},p);if(typeof renderRunDocuments==='function')renderRunDocuments({...p,summary:{...p.summary,bucket_source:p.bucket_source}});if(typeof renderAgentRecovery==='function')renderAgentRecovery(p);if(typeof renderBlockers==='function')renderBlockers(p);if(p.view){setText('detailRunId',p.view.run_id||p.run_id);setText('selectedModelId',p.view.header?.model||p.summary?.model_id||'—')}else{setText('detailRunId',p.run_id||state.runId)}renderActiveRunMeta(p);if(p.state){setText('detailSpace',p.state.target_space||p.summary?.target_space||'—');const mode=runImplementationMode(p.summary||{},p);setText('detailImplementationMode',mode?implementationModeLabel(mode):'—');const modeEl=$('detailImplementationMode');if(modeEl&&mode)modeEl.title=implementationModeDescription(mode);setText('detailHardware',p.state.selected_hardware||p.summary?.selected_hardware||'—')}setText('detailJobStatus',p.status||p.state?.status||p.view?.header?.raw_status||'running');setText('detailGateStatus',p.inference_gate?.status||p.summary?.gate_status||'—');setText('detailTraces',Array.isArray(p.events)?String(p.events.length)+' events':'—');setText('homeRunDetailStatus',badgeLabel(p.status||p.state?.status||p.view?.header?.status||'running'));setQuickLinks({...p.links,...p.view?.links,bucket_source:p.bucket_source,run_id:p.run_id},{...p,events:p.events||[]});saveActiveRun();const status=String(p.view?.header?.status||p.status||p.state?.status||'').toLowerCase();if(TERMINAL_STATUSES.has(status)&&state.poll){clearInterval(state.poll);state.poll=null;if(state.lastReportRefreshRunId!==state.runId){state.lastReportRefreshRunId=state.runId;setTimeout(()=>refreshRunReportPreview(state.runId),120);setTimeout(()=>loadRuns(true),160)}setOperation(`Run finished with status: ${badgeLabel(status)}`,status.includes('success')||status.includes('succeed')?'success':status.includes('failed')||status.includes('blocker')?'error':'warning')}markPendingActiveFields();if(now-(state.lastRunsRefreshFromPoll||0)>15000){state.lastRunsRefreshFromPoll=now;loadRuns(false)}}catch(e){state.pollErrors+=1;console.warn(e);setOperation(`Progress polling failed ${state.pollErrors} time${state.pollErrors===1?'':'s'}. Retrying automatically…`,'warning')}finally{state.progressPollInFlight=false}} function numberFromEvents(events=[],keys=[]){ const rows=Array.isArray(events)?events:[]; for(let i=rows.length-1;i>=0;i--){ const event=rows[i]||{}; const data=event.data||{}; for(const key of keys){ const direct=Number(event[key]); if(Number.isFinite(direct)&&direct>0)return direct; const nested=Number(data[key]); if(Number.isFinite(nested)&&nested>0)return nested; } } return null; } function readRunLatencyPayload(p={}){ const smoke=p.generation_smoke||p.tests?.generation_smoke||p.summary?.generation_smoke||p.state?.generation_smoke||{}; const gate=p.inference_gate||p.summary?.inference_gate||{}; const summary=p.summary||{}; const validation=gate.validation||summary.validation||{}; const eventLatency=numberFromEvents(p.events||[],['latency_seconds','observed_latency_seconds']); const eventDuration=numberFromEvents(p.events||[],['recommended_zerogpu_duration_seconds','recommended_zero_gpu_duration_seconds','recommended_duration_seconds','zero_gpu_duration_recommendation']); const latency=firstPositiveNumber(smoke.latency_seconds,smoke.observed_latency_seconds,summary.latency_seconds,summary.observed_latency_seconds,p.latency_seconds,p.observed_latency_seconds,eventLatency); const duration=firstPositiveNumber(smoke.recommended_zerogpu_duration_seconds,smoke.recommended_zero_gpu_duration_seconds,smoke.recommended_duration_seconds,summary.recommended_zerogpu_duration_seconds,summary.recommended_zero_gpu_duration_seconds,summary.recommended_duration_seconds,gate.recommended_zerogpu_duration_seconds,gate.recommended_zero_gpu_duration_seconds,gate.zero_gpu_duration_recommendation,eventDuration); const source=smoke.recommendation_source||summary.recommendation_source||gate.recommendation_source||(eventLatency?'generation_smoke event':''); const failureType=smoke.failure_type||validation.failure_type||gate.failure_type||''; const failureOwner=smoke.failure_owner||validation.failure_owner||gate.failure_owner||''; const missingArgument=smoke.missing_argument||validation.missing_argument||gate.missing_argument||''; const error=smoke.error||smoke.message||validation.failure_reason||gate.message||''; return {smoke,gate,latency,duration,source,failureType,failureOwner,missingArgument,error}; } function smokeFailureLatencyNote({smoke={},failureType='',failureOwner='',missingArgument='',error=''}={}){ const status=String(smoke.status||'').toLowerCase(); if(!status||status==='success')return ''; if(missingArgument){ return `Not measured because generation smoke failed before inference started. Missing required argument: ${missingArgument}.`; } if(failureType==='validator_request_error'||failureOwner==='factory_validator'){ return 'Not measured because ASF sent an invalid smoke-test request before live inference could start.'; } if(failureType==='app_runtime_error'||failureOwner==='generated_space'){ return 'Not measured because the generated Space raised an error during the live generation smoke test.'; } if(String(error||'').trim()){ return `Not measured because generation smoke failed: ${shortText(error,120)}`; } return 'Not measured because the generation smoke test did not produce a verified output.'; } function renderActiveLatency(p={}){ const card=$('activeLatencyCard'); if(!card)return; const runId=String(p.run_id||p.summary?.run_id||state.runId||''); state.latencyCache=state.latencyCache||{}; const payload=readRunLatencyPayload(p); const {latency,duration,source}=payload; const hasLatency=Number.isFinite(latency)&&latency>0; const hasDuration=Number.isFinite(duration)&&duration>0; const cached=state.latencyCache[runId]||{}; const stableLatency=hasLatency?latency:cached.latency; const stableDuration=hasDuration?duration:cached.duration; const runStatus=String(p.status||p.state?.status||p.summary?.status||p.view?.header?.status||'').toLowerCase(); const finalBlocker=p.build_error_observation?' Final blocker: build error after repair.':''; const failedWithoutSmoke=(runStatus==='failed'||runStatus==='error')&&!hasLatency; const failureNote=smokeFailureLatencyNote(payload)||(failedWithoutSmoke?`Not measured because live validation did not reach a successful generation smoke test.${finalBlocker}`:''); const stableSource=hasLatency?(source||'live smoke test'):(failureNote?'not measured: smoke failed':(cached.source||'measured when smoke test passes')); if(hasLatency||hasDuration)state.latencyCache[runId]={latency:stableLatency,duration:stableDuration,source:stableSource}; const finalHasLatency=Number.isFinite(stableLatency)&&stableLatency>0; const finalHasDuration=Number.isFinite(stableDuration)&&stableDuration>0; setText('activeLatencyValue',finalHasLatency?formatLatencySeconds(stableLatency):'—'); setText('activeZeroGpuDuration',finalHasDuration?fmtSeconds(Math.round(stableDuration)):'—'); setText('activeLatencySource',stableSource); const note=$('activeLatencyNote'); if(note){ note.textContent=finalHasDuration ? 'This measured latency is normally used to tune the `@spaces.GPU(duration=...)` decorator for ZeroGPU when the generated Space uses ZeroGPU.' : (failureNote||'When available, the live smoke-test latency is used to recommend the `@spaces.GPU(duration=...)` value for ZeroGPU apps.'); } card.classList.toggle('has-latency',finalHasLatency); card.classList.toggle('is-loading',!finalHasLatency); } function runHardwareMeta(p={}){ const summary=p.summary||{}; const stateObj=p.state||{}; const launch=p.launch||{}; const hardware=p.hardware_strategy||summary.hardware_strategy||{}; const target=summary.preferred_space_hardware||summary.target_gpu||stateObj.preferred_space_hardware||stateObj.target_gpu||launch.preferred_space_hardware||hardware.preferred||hardware.target||summary.selected_hardware||stateObj.selected_hardware||'—'; const fallback=summary.fallback_space_hardware||summary.fallback_gpu||stateObj.fallback_space_hardware||stateObj.fallback_gpu||launch.fallback_space_hardware||hardware.fallback||'—'; const output=summary.expected_output_type||stateObj.expected_output_type||launch.expected_output_type||p.generation_smoke?.expected_output_type||p.inference_gate?.expected_output_type||'—'; return {target,fallback,output}; } function shortModelLabel(value){ const raw=String(value||'').trim(); if(!raw)return '—'; return raw.length>30?raw.split('/').slice(-1)[0]||raw:raw; } function piAssistantResolution(p={}){ const summary=p.summary||{}; const stateObj=p.state||{}; const launch=p.launch||{}; const resolution=p.pi_model_resolution||stateObj.pi_model_resolution||summary.pi_model_resolution||{}; const requested=resolution.requested_model||stateObj.pi_model||launch.pi_model||summary.pi_model||''; const effective=resolution.effective_model||resolution.configured_model||requested||''; const mismatch=Boolean(resolution.mismatch&&effective&&requested&&normalizeComparableModelName(effective)!==normalizeComparableModelName(requested)); return {requested,effective,mismatch,provider:resolution.provider||'huggingface',source:resolution.source||''}; } function normalizeComparableModelName(value){ const raw=String(value||'').trim().toLowerCase(); const tail=raw.includes('/')?raw.split('/').pop():raw; return tail.replace(/[^a-z0-9]+/g,''); } function renderPiAssistantMeta(p={}){ const el=$('detailPiAssistant'); if(!el)return; const info=piAssistantResolution(p); const requested=shortModelLabel(info.requested); const effective=shortModelLabel(info.effective); el.textContent=info.mismatch?`${requested} → ${effective}`:(effective||requested||'—'); el.title=info.mismatch?`Requested ${info.requested||'—'}; effective provider model ${info.effective||'—'}`:`Requested/effective assistant: ${info.effective||info.requested||'—'}`; el.classList.toggle('warn-text',Boolean(info.mismatch)); } function renderActiveRunMeta(p={}){ const meta=runHardwareMeta(p); setText('detailTargetGpu',meta.target||'—'); setText('detailFallbackGpu',meta.fallback||'—'); setText('detailExpectedOutput',meta.output||'—'); renderPiAssistantMeta(p); } function markPendingActiveFields(){ ['detailRunId','detailSpace','selectedModelId','detailTargetGpu','detailFallbackGpu','detailExpectedOutput','detailPiAssistant','currentStep','elapsed'].forEach(id=>{ const el=$(id); if(!el)return; const pending=!String(el.textContent||'').trim()||String(el.textContent||'').trim()==='—'; el.classList.toggle('is-pending',pending); }); } function renderMetrics(p){const root=$('metricsList');const {smoke,gate,latency,duration}=readRunLatencyPayload(p);const health=(gate.implementation_signals&&gate.implementation_signals.health_passed)||smoke.health_passed;const smokeOk=smoke.ok||smoke.status==='success';renderActiveLatency(p);if(!root)return;root.innerHTML=`
  • /health${health?'passed':'pending'}
  • /generate smoke test${smokeOk?'passed':(smoke.status||'pending')}
  • Latency${Number.isFinite(latency)&&latency>0?formatLatencySeconds(latency):'—'}
  • Recommended ZeroGPU duration${Number.isFinite(duration)&&duration>0?fmtSeconds(Math.round(duration)):'—'}
  • `} function renderEvents(events){const root=$('eventsPanel');if(!root)return;try{const rows=Array.isArray(events)?events:[];root.textContent=rows.slice(-12).map(e=>`${e?.ts||''} ${e?.step||''} ${e?.status||''} ${e?.message||''}`).join('\n')||'No events yet. The run may still be scheduling.'}catch(e){console.warn('renderEvents failed',e);root.textContent='Events could not be rendered.'}} async function cancelActiveRun(){ if(!state.runId){showMessage('Select a running run before cancelling.', 'warning');return} if(!confirm(`Cancel Job for run ${state.runId}?`))return; setButtonBusy('cancelRun',true,'Cancelling…'); try{ const result=await apiPost(`/api/runs/${encodeURIComponent(state.runId)}/cancel?bucket_name=${encodeURIComponent(state.bucketName)}`,{}); showMessage(`Cancelled Job ${result.job_id||''}`,'success'); if(state.poll){clearInterval(state.poll);state.poll=null} await refreshProgress(); await loadRuns(true); }catch(e){ showMessage(e.message,true); }finally{ setButtonBusy('cancelRun',false); } } function switchView(view){state.currentView=view;document.querySelectorAll('.nav-item').forEach(b=>b.classList.toggle('active',b.dataset.view===view));document.querySelectorAll('[data-section]').forEach(s=>s.hidden=s.dataset.section!==view);setOperation('');if(view==='progress')loadRuns(false);if(view==='validate')switchCenterTab('validate');if(view==='active')switchCenterTab('active');const targetMap={build:'newBuildCard',progress:'runsExplorerPanel',validate:'spaceTestSection',active:'activeRunPanel'};const target=$(targetMap[view]||'');if(target)target.scrollIntoView({behavior:'smooth',block:'start'})} function bindNavigation(){ bindAllOnce('.nav-item','click','navItem',e=>switchView(e.currentTarget.dataset.view||'build')); bindAllOnce('[data-view-target]','click','viewTarget',e=>switchView(e.currentTarget.dataset.viewTarget||'build')); bindAllOnce('[data-center-tab]','click','centerTab',e=>switchCenterTab(e.currentTarget.dataset.centerTab||'active')); } function bindRunFilters(){ bindAllOnce('.filter[data-status]','click','runStatusFilter',e=>{ state.runStatusFilter=e.currentTarget.dataset.status||'all'; state.runPage=0; renderRunsFromCache(); }); for(const id of ['runSearch','runSearchFull'])bindOnce($(id),'input',`runSearch${id}`,e=>{ state.runSearch=e.target.value||''; state.runPage=0; for(const other of ['runSearch','runSearchFull'])if($(other)&&$(other)!==e.target)$(other).value=state.runSearch; clearTimeout(state.runSearchTimer); state.runSearchTimer=setTimeout(renderRunsFromCache,80); }); } function bindValidationDraftInputs(){ for(const id of ['testArgs','testKwargs'])bindOnce($(id),'input',`validationArgsDirty${id}`,()=>{state.validationArgsDirty=true;const note=$('spaceTestArgsNote');if(note)note.hidden=true;setValidationLaunchEnabled();}); for(const id of ['validateSpace','validateApi','expectedOutput','validateTimeout'])bindOnce($(id),'input',`validationForm${id}`,setValidationLaunchEnabled); } function bindActions(){ $('launchBuild')?.setAttribute('data-requires-bucket','true'); $('launchBuild')?.setAttribute('data-action-button','true'); $('launchValidate')?.setAttribute('data-action-button','true'); const actions={ launchBuild:launchBuild, scanModel:scanModel, launchValidate:launchValidate, prepareNewBuild:prepareNewBuild, manualGoValidate:prepareValidationFromActiveRun, activePrefillSpaceTest:prepareValidationFromActiveRun, checkBucket:()=>checkBucket(true), createBucket:createBucket, enableEvalArchive:enableEvalArchive, verifyEvalArchive:verifyEvalArchive, disableEvalArchive:disableEvalArchive, refreshRuns:()=>loadRuns(true), refreshRunsHome:()=>loadRuns(true), cancelRun:cancelActiveRun, }; Object.entries(actions).forEach(([id,handler])=>bindOnce($(id),'click',`action${id}`,handler)); bindOnce($('modelId'),'input','modelPreScanReset',resetModelPreScan); bindOnce($('modelRiskAck'),'change','modelRiskAck',setBuildLaunchEnabled); ['tryZeroGpu','preferredHardware','fallbackHardware','allowFallback'].forEach(id=>bindOnce($(id),'change',`hardware${id}`,()=>setText('hardwarePlan',hardwarePlanLabel()))); bindOnce($('implementationMode'),'change','implementationModeHelp',updateImplementationModeHelp); } bindNavigation();bindActions();bindRunFilters();bindValidationDraftInputs();setText('hardwarePlan',hardwarePlanLabel());updateImplementationModeHelp();setBuildModeNew();renderActiveRunEmptyState();resetValidationRunView();loadAppInfo(); // Pass 47 intentionally removed automatic switchView('progress') after launch and run selection. // Compatibility note for v108 regression: implementationMode')?.addEventListener('change',updateImplementationModeHelp is now bound through bindOnce(). // Live quotas, spend and compute usage remain in the HF Billing dashboard; Open HF Billing for numeric values. // Legacy endpoint picker wording kept for tests: API name used for validation / Set API name. // Legacy status copy kept for regression tests only, not displayed: // 'Eval archive off · set env vars' // Anonymous project eval archive enabled: // Env override remains supported for backend publishing: ASF_EVAL_ENABLED=true, ASF_EVAL_BUCKET_SOURCE=/, ASF_EVAL_BUCKET_PATH=evals, ASF_EVAL_BUCKET_MOUNT=/evals.