fffiloni commited on
Commit
ebd0eab
·
verified ·
1 Parent(s): bc9b7c6

Upload 8 files

Browse files
Files changed (2) hide show
  1. web/static/components.js +1 -1
  2. web/static/progress.js +52 -9
web/static/components.js CHANGED
@@ -17,6 +17,6 @@ function firstNonEmpty(...values){for(const value of values){if(value!==undefine
17
  function fmtSeconds(s){if(s==null||s==='')return'—';s=Math.max(0,Number(s)||0);const h=Math.floor(s/3600),m=Math.floor((s%3600)/60),r=s%60;if(h)return`${h}h ${m}m`;return m?`${m}m ${r}s`:`${r}s`}
18
  function shortText(value,max=42){value=String(value||'—');return value.length>max?value.slice(0,max-1)+'…':value}
19
  function formatTime(ts){if(!ts)return'—';try{return new Date(ts).toLocaleTimeString([], {hour:'2-digit',minute:'2-digit',second:'2-digit'})}catch(_){return String(ts).slice(11,19)||'—'}}
20
- function statusClass(status){status=String(status||'').toLowerCase();if(status==='success_with_expert_intervention'||status==='expert_intervention_validation_passed'||status==='validated_after_space_test'||status==='validated_after_manual_space_test'||status==='manual_validation_passed'||status==='validated'||status==='manual_validated'||status==='recovered_by_space_test'||status==='recovered_by_manual_validation')return'success';if(status==='selected'||status==='uploaded'||status==='ready'||status==='verified')return'success';if(status==='fallback')return'warn';if(status==='full_inference_candidate_health_passed'||status==='health_only'||status==='partial'||status==='partial_validation'||status==='completed_with_warnings'||status==='demo_usable_full_promise_not_verified'||status==='interactive_app_available_smoke_failed'||status==='manual_test_required_smoke_failed')return'warn';if(status.includes('succeed')||status.includes('success')||status.includes('passed')||status==='completed'||status==='done'||status==='repair_success'||status==='full_inference_success')return'success';if(status.includes('failed')||status.includes('error')||status.includes('technical'))return'error';if(status.includes('auth_refresh_required')||status.includes('oauth_expired')||status.includes('manual')||status.includes('stale')||status.includes('blocked')||status.includes('cancelled')||status.includes('canceled')||status.includes('stopped'))return'warn';if(status.includes('running')||status.includes('queued')||status.includes('pending')||status.includes('building'))return'running';return'neutral'}
21
  function setLink(id,url){const el=$(id);if(!el)return;if(url){el.href=url;el.classList.remove('disabled');el.setAttribute('aria-disabled','false')}else{el.removeAttribute('href');el.classList.add('disabled');el.setAttribute('aria-disabled','true')}}
22
  function badgeLabel(status){return String(status||'unknown').replaceAll('_',' ')}
 
17
  function fmtSeconds(s){if(s==null||s==='')return'—';s=Math.max(0,Number(s)||0);const h=Math.floor(s/3600),m=Math.floor((s%3600)/60),r=s%60;if(h)return`${h}h ${m}m`;return m?`${m}m ${r}s`:`${r}s`}
18
  function shortText(value,max=42){value=String(value||'—');return value.length>max?value.slice(0,max-1)+'…':value}
19
  function formatTime(ts){if(!ts)return'—';try{return new Date(ts).toLocaleTimeString([], {hour:'2-digit',minute:'2-digit',second:'2-digit'})}catch(_){return String(ts).slice(11,19)||'—'}}
20
+ function statusClass(status){status=String(status||'').toLowerCase();if(status==='provider_quota_blocked')return'warn';if(status==='success_with_expert_intervention'||status==='expert_intervention_validation_passed'||status==='validated_after_space_test'||status==='validated_after_manual_space_test'||status==='manual_validation_passed'||status==='validated'||status==='manual_validated'||status==='recovered_by_space_test'||status==='recovered_by_manual_validation')return'success';if(status==='selected'||status==='uploaded'||status==='ready'||status==='verified')return'success';if(status==='fallback')return'warn';if(status==='full_inference_candidate_health_passed'||status==='health_only'||status==='partial'||status==='partial_validation'||status==='completed_with_warnings'||status==='demo_usable_full_promise_not_verified'||status==='interactive_app_available_smoke_failed'||status==='manual_test_required_smoke_failed')return'warn';if(status.includes('succeed')||status.includes('success')||status.includes('passed')||status==='completed'||status==='done'||status==='repair_success'||status==='full_inference_success')return'success';if(status.includes('failed')||status.includes('error')||status.includes('technical'))return'error';if(status.includes('auth_refresh_required')||status.includes('oauth_expired')||status.includes('manual')||status.includes('stale')||status.includes('blocked')||status.includes('cancelled')||status.includes('canceled')||status.includes('stopped'))return'warn';if(status.includes('running')||status.includes('queued')||status.includes('pending')||status.includes('building'))return'running';return'neutral'}
21
  function setLink(id,url){const el=$(id);if(!el)return;if(url){el.href=url;el.classList.remove('disabled');el.setAttribute('aria-disabled','false')}else{el.removeAttribute('href');el.classList.add('disabled');el.setAttribute('aria-disabled','true')}}
22
  function badgeLabel(status){return String(status||'unknown').replaceAll('_',' ')}
web/static/progress.js CHANGED
@@ -1,6 +1,6 @@
1
  const timelineRenderState={};
2
  const activityFeedState={lastItems:[],runId:null};
3
- const PROGRESS_TERMINAL_STATUSES=new Set(['done','success','failed','full_inference_success','full_inference_candidate_health_passed','manual_hardware_required','generated_needs_manual_hardware','technical_blocker','technical_blocker_boot_only','health_only','partial','partial_validation','completed_with_warnings','demo_usable_full_promise_not_verified','interactive_app_available_smoke_failed','manual_test_required_smoke_failed','validated','validated_after_space_test','validated_after_manual_space_test','manual_validation_passed','manual_validated','recovered_by_space_test','recovered_by_manual_validation','success_with_expert_intervention','expert_intervention_validation_passed','repair_success','repair_failed','succeeded','waiting_manual_action','blocked','stale','cancelled','canceled','stopped','auth_refresh_required']);
4
  const PROGRESS_SUCCESS_TERMINAL_STATUSES=new Set(['done','success','succeeded','completed','passed','full_inference_success','validated','validated_after_space_test','validated_after_manual_space_test','manual_validation_passed','manual_validated','recovered_by_space_test','recovered_by_manual_validation','success_with_expert_intervention','expert_intervention_validation_passed','repair_success']);
5
  const PROGRESS_POST_BUILD_SUCCESS_STATUSES=new Set(['validated_after_space_test','validated_after_manual_space_test','manual_validation_passed','manual_validated','recovered_by_space_test','recovered_by_manual_validation','success_with_expert_intervention','expert_intervention_validation_passed']);
6
  const PROGRESS_BLOCKING_TERMINAL_STATUSES=new Set(['failed','failure','error','technical_blocker','technical_blocker_boot_only','blocked','manual_hardware_required','generated_needs_manual_hardware','waiting_manual_action','auth_refresh_required','stale','stopped','cancelled','canceled']);
@@ -18,7 +18,7 @@ const COMPACT_TIMELINE_GROUPS=[
18
  {id:'auth_model',label:'Auth + model',display_label:'Model access',steps:['auth','model_analysis']},
19
  {id:'workspace_node',label:'Workspace/node',display_label:'Workspace',steps:['workspace','node']},
20
  {id:'pi_setup',label:'Pi setup',display_label:'Agent setup',steps:['pi_install','pi_config']},
21
- {id:'pi_run',label:'Pi run',display_label:'Agent build',steps:['pi_run']},
22
  {id:'pi_verify',label:'Pi verify',display_label:'Agent review',steps:['pi_model_resolution','pi_verification','metadata_sanitize','requirements_sanitize']},
23
  {id:'hardware',label:'Hardware',display_label:'Hardware',steps:['hardware_strategy','create_space_hardware']},
24
  {id:'create_space',label:'Create Space',display_label:'Space',steps:['create_space']},
@@ -33,7 +33,7 @@ const progressMotionState={lastProgress:null,lastStatus:null,lastStep:null};
33
 
34
  const WORKER_STEP_DISPLAY_LABELS={
35
  bootstrap:'start',dependencies:'dependencies',auth:'auth',model_analysis:'model card',workspace:'workspace',node:'node setup',
36
- pi_install:'agent install',pi_config:'agent config',pi_run:'agent building',pi_model_resolution:'model routing',pi_verification:'agent check',
37
  metadata_sanitize:'metadata check',requirements_sanitize:'requirements check',hardware_strategy:'hardware plan',create_space_hardware:'hardware request',
38
  create_space:'space created',upload_files:'files uploaded',space_runtime:'runtime check',space_logs:'logs checked',live_wait:'space live',
39
  api_validation:'API check',generation_smoke:'live generation',inference_gate:'inference verdict',failure_detected:'failure detected',
@@ -44,11 +44,12 @@ const WORKER_STEP_DISPLAY_LABELS={
44
  };
45
  function workerStepDisplayLabel(step){return WORKER_STEP_DISPLAY_LABELS[String(step||'')]||String(step||'').replace(/_/g,' ')}
46
 
47
- const progressStability={runId:null,progress:0,timeline:null,furthestIndex:-1,status:'',currentStep:null};
48
  const elapsedClock={baseSeconds:0,baseAt:0,isRunning:false};
49
 
50
  function isFailureStatus(status){
51
  const s=String(status||'').toLowerCase();
 
52
  return s.includes('failed')||s.includes('error')||s==='failure'||s==='technical_blocker'||s==='technical_blocker_boot_only'||s==='blocked';
53
  }
54
  function isSuccessStatus(status){
@@ -62,7 +63,7 @@ function isPartialStatus(status){
62
  }
63
  function isStoppedStatus(status){
64
  const s=String(status||'').toLowerCase();
65
- return s==='cancelled'||s==='canceled'||s==='stopped'||s==='blocked'||s==='stale';
66
  }
67
  function visualStatusClass(status){
68
  if(isFailureStatus(status))return'error';
@@ -980,6 +981,7 @@ function eventIconFor(item={},klass=''){
980
  if(klass.includes('hardware-fallback')||step.includes('hardware'))return'chip';
981
  if(step.includes('repair_decision')||step.includes('pi_diagnosis')||step.includes('failure_diagnosis'))return'search';
982
  if(step.includes('factory_rebuild'))return'rocket';
 
983
  if(step.includes('repair')||step.includes('blocker'))return'wand';
984
  if(step.includes('upload'))return'upload';
985
  if(step.includes('trace'))return'files';
@@ -1022,7 +1024,7 @@ function eventOriginFor(item={}){
1022
  if(['create_space','create_space_hardware','hardware_strategy','upload_files'].some(s=>step.includes(s)))return'hub';
1023
  if(['space_runtime','space_logs','live_wait'].some(s=>step.includes(s))||message.includes('runtime_error')||message.includes('app_starting'))return'space';
1024
  if(['api_validation','generation_smoke','inference_gate','repair_validation'].some(s=>step.includes(s))||message.includes('gradio'))return'gradio';
1025
- if(['failure_diagnosis','repair_decision','technical_blocker','failure','done','report_write'].some(s=>step.includes(s)))return'factory';
1026
  return'factory';
1027
  }
1028
  function renderActivityFeed(items){
@@ -1185,6 +1187,40 @@ function timelineFurthestIndex(items){
1185
  function cloneTimeline(items){
1186
  return (items||[]).map(x=>({...x}));
1187
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1188
  function resetProgressStability(runId=null){
1189
  progressStability.runId=runId;
1190
  progressStability.progress=0;
@@ -1192,6 +1228,9 @@ function resetProgressStability(runId=null){
1192
  progressStability.furthestIndex=-1;
1193
  progressStability.status='';
1194
  progressStability.currentStep=null;
 
 
 
1195
  progressMotionState.lastProgress=null;
1196
  progressMotionState.lastStatus=null;
1197
  progressMotionState.lastStep=null;
@@ -1248,11 +1287,14 @@ function renderRunViewModel(view,p={}){
1248
  const header=view.header||{};
1249
  const sm=view.status_model||{};
1250
  const stableEvents=mergeStableEvents(String(p.run_id||view.run_id||state.runId||''),p.events||[]);
1251
- const timelineModel=view.timeline_model||p.timeline_model||null;
1252
- const modelProgress=hasCanonicalTimelineModel(timelineModel)?(timelineModel.progress||{}):null;
1253
  const stable=stabilizeProgressPayload(p,view);
 
 
 
1254
  const canonical=canonicalRunUiState({view,...p});
1255
- const progress=Number(modelProgress?.percent??stable.progress??(canonical.isTerminal?100:(header.status==='succeeded'?100:0)));
 
 
1256
  const runStatus=canonical.status;
1257
  const visualRunStatus=canonical.visual_status||runStatus;
1258
  const semanticProgress=PROGRESS_POST_BUILD_SUCCESS_STATUSES.has(String(runStatus||'').toLowerCase())
@@ -1288,6 +1330,7 @@ function renderRunViewModel(view,p={}){
1288
  cancel.disabled=!(state.runId&&view.links?.job_url&&!terminal);
1289
  }
1290
  if(!renderTimelineModel(timelineModel,runStatus))renderTimelinePlaceholder('Waiting for canonical run timeline…');
 
1291
  renderActivityFeed(Array.isArray(view.activity)&&view.activity.length?view.activity:stableEvents);
1292
  renderDiagnostics(view.diagnostics||{},header);
1293
  renderSpaceTestPreview(view.space_test||{});
 
1
  const timelineRenderState={};
2
  const activityFeedState={lastItems:[],runId:null};
3
+ const PROGRESS_TERMINAL_STATUSES=new Set(['done','success','failed','full_inference_success','full_inference_candidate_health_passed','manual_hardware_required','generated_needs_manual_hardware','technical_blocker','technical_blocker_boot_only','health_only','partial','partial_validation','completed_with_warnings','demo_usable_full_promise_not_verified','interactive_app_available_smoke_failed','manual_test_required_smoke_failed','validated','validated_after_space_test','validated_after_manual_space_test','manual_validation_passed','manual_validated','recovered_by_space_test','recovered_by_manual_validation','success_with_expert_intervention','expert_intervention_validation_passed','repair_success','repair_failed','succeeded','waiting_manual_action','blocked','stale','cancelled','canceled','stopped','auth_refresh_required','provider_quota_blocked']);
4
  const PROGRESS_SUCCESS_TERMINAL_STATUSES=new Set(['done','success','succeeded','completed','passed','full_inference_success','validated','validated_after_space_test','validated_after_manual_space_test','manual_validation_passed','manual_validated','recovered_by_space_test','recovered_by_manual_validation','success_with_expert_intervention','expert_intervention_validation_passed','repair_success']);
5
  const PROGRESS_POST_BUILD_SUCCESS_STATUSES=new Set(['validated_after_space_test','validated_after_manual_space_test','manual_validation_passed','manual_validated','recovered_by_space_test','recovered_by_manual_validation','success_with_expert_intervention','expert_intervention_validation_passed']);
6
  const PROGRESS_BLOCKING_TERMINAL_STATUSES=new Set(['failed','failure','error','technical_blocker','technical_blocker_boot_only','blocked','manual_hardware_required','generated_needs_manual_hardware','waiting_manual_action','auth_refresh_required','stale','stopped','cancelled','canceled']);
 
18
  {id:'auth_model',label:'Auth + model',display_label:'Model access',steps:['auth','model_analysis']},
19
  {id:'workspace_node',label:'Workspace/node',display_label:'Workspace',steps:['workspace','node']},
20
  {id:'pi_setup',label:'Pi setup',display_label:'Agent setup',steps:['pi_install','pi_config']},
21
+ {id:'pi_run',label:'Pi run',display_label:'Agent build',steps:['pi_run','provider_quota']},
22
  {id:'pi_verify',label:'Pi verify',display_label:'Agent review',steps:['pi_model_resolution','pi_verification','metadata_sanitize','requirements_sanitize']},
23
  {id:'hardware',label:'Hardware',display_label:'Hardware',steps:['hardware_strategy','create_space_hardware']},
24
  {id:'create_space',label:'Create Space',display_label:'Space',steps:['create_space']},
 
33
 
34
  const WORKER_STEP_DISPLAY_LABELS={
35
  bootstrap:'start',dependencies:'dependencies',auth:'auth',model_analysis:'model card',workspace:'workspace',node:'node setup',
36
+ pi_install:'agent install',pi_config:'agent config',pi_run:'agent building',provider_quota:'quota blocked',pi_model_resolution:'model routing',pi_verification:'agent check',
37
  metadata_sanitize:'metadata check',requirements_sanitize:'requirements check',hardware_strategy:'hardware plan',create_space_hardware:'hardware request',
38
  create_space:'space created',upload_files:'files uploaded',space_runtime:'runtime check',space_logs:'logs checked',live_wait:'space live',
39
  api_validation:'API check',generation_smoke:'live generation',inference_gate:'inference verdict',failure_detected:'failure detected',
 
44
  };
45
  function workerStepDisplayLabel(step){return WORKER_STEP_DISPLAY_LABELS[String(step||'')]||String(step||'').replace(/_/g,' ')}
46
 
47
+ const progressStability={runId:null,progress:0,timeline:null,furthestIndex:-1,status:'',currentStep:null,timelineModel:null,timelineModelPercent:0,timelineModelFurthestIndex:-1};
48
  const elapsedClock={baseSeconds:0,baseAt:0,isRunning:false};
49
 
50
  function isFailureStatus(status){
51
  const s=String(status||'').toLowerCase();
52
+ if(s==='provider_quota_blocked')return false;
53
  return s.includes('failed')||s.includes('error')||s==='failure'||s==='technical_blocker'||s==='technical_blocker_boot_only'||s==='blocked';
54
  }
55
  function isSuccessStatus(status){
 
63
  }
64
  function isStoppedStatus(status){
65
  const s=String(status||'').toLowerCase();
66
+ return s==='provider_quota_blocked'||s==='cancelled'||s==='canceled'||s==='stopped'||s==='blocked'||s==='stale';
67
  }
68
  function visualStatusClass(status){
69
  if(isFailureStatus(status))return'error';
 
981
  if(klass.includes('hardware-fallback')||step.includes('hardware'))return'chip';
982
  if(step.includes('repair_decision')||step.includes('pi_diagnosis')||step.includes('failure_diagnosis'))return'search';
983
  if(step.includes('factory_rebuild'))return'rocket';
984
+ if(step.includes('provider_quota'))return'alert';
985
  if(step.includes('repair')||step.includes('blocker'))return'wand';
986
  if(step.includes('upload'))return'upload';
987
  if(step.includes('trace'))return'files';
 
1024
  if(['create_space','create_space_hardware','hardware_strategy','upload_files'].some(s=>step.includes(s)))return'hub';
1025
  if(['space_runtime','space_logs','live_wait'].some(s=>step.includes(s))||message.includes('runtime_error')||message.includes('app_starting'))return'space';
1026
  if(['api_validation','generation_smoke','inference_gate','repair_validation'].some(s=>step.includes(s))||message.includes('gradio'))return'gradio';
1027
+ if(['provider_quota','failure_diagnosis','repair_decision','technical_blocker','failure','done','report_write'].some(s=>step.includes(s)))return'factory';
1028
  return'factory';
1029
  }
1030
  function renderActivityFeed(items){
 
1187
  function cloneTimeline(items){
1188
  return (items||[]).map(x=>({...x}));
1189
  }
1190
+ function cloneTimelineModel(model){
1191
+ if(!model||typeof model!=='object')return model;
1192
+ try{return JSON.parse(JSON.stringify(model));}catch(_){return model;}
1193
+ }
1194
+ function canonicalTimelineFurthestIndex(model){
1195
+ if(!hasCanonicalTimelineModel(model))return -1;
1196
+ const phases=visibleCanonicalTimelinePhases(model);
1197
+ let max=-1;
1198
+ phases.forEach((phase,i)=>{
1199
+ const st=String(phase.status||'pending').toLowerCase();
1200
+ if(!['pending','status-pending','muted','status-muted'].includes(st))max=i;
1201
+ });
1202
+ return max;
1203
+ }
1204
+ function stabilizeCanonicalTimelineModel(model){
1205
+ if(!hasCanonicalTimelineModel(model))return model;
1206
+ const progress=model.progress||{};
1207
+ const terminal=progress.terminal===true||progressIsTerminalStatus(progress.verdict);
1208
+ const percent=Math.max(0,Math.min(100,Number(progress.percent||0)));
1209
+ const furthest=canonicalTimelineFurthestIndex(model);
1210
+ if(terminal){
1211
+ progressStability.timelineModel=cloneTimelineModel(model);
1212
+ progressStability.timelineModelPercent=percent;
1213
+ progressStability.timelineModelFurthestIndex=Math.max(progressStability.timelineModelFurthestIndex,furthest);
1214
+ return model;
1215
+ }
1216
+ if(!progressStability.timelineModel||percent>=progressStability.timelineModelPercent||furthest>=progressStability.timelineModelFurthestIndex){
1217
+ progressStability.timelineModel=cloneTimelineModel(model);
1218
+ progressStability.timelineModelPercent=Math.max(progressStability.timelineModelPercent,percent);
1219
+ progressStability.timelineModelFurthestIndex=Math.max(progressStability.timelineModelFurthestIndex,furthest);
1220
+ return model;
1221
+ }
1222
+ return cloneTimelineModel(progressStability.timelineModel);
1223
+ }
1224
  function resetProgressStability(runId=null){
1225
  progressStability.runId=runId;
1226
  progressStability.progress=0;
 
1228
  progressStability.furthestIndex=-1;
1229
  progressStability.status='';
1230
  progressStability.currentStep=null;
1231
+ progressStability.timelineModel=null;
1232
+ progressStability.timelineModelPercent=0;
1233
+ progressStability.timelineModelFurthestIndex=-1;
1234
  progressMotionState.lastProgress=null;
1235
  progressMotionState.lastStatus=null;
1236
  progressMotionState.lastStep=null;
 
1287
  const header=view.header||{};
1288
  const sm=view.status_model||{};
1289
  const stableEvents=mergeStableEvents(String(p.run_id||view.run_id||state.runId||''),p.events||[]);
 
 
1290
  const stable=stabilizeProgressPayload(p,view);
1291
+ // Compatibility anchor: const timelineModel=view.timeline_model||p.timeline_model||null;
1292
+ const timelineModel=stabilizeCanonicalTimelineModel(view.timeline_model||p.timeline_model||null);
1293
+ const modelProgress=hasCanonicalTimelineModel(timelineModel)?(timelineModel.progress||{}):null;
1294
  const canonical=canonicalRunUiState({view,...p});
1295
+ // Compatibility anchor: const progress=Number(modelProgress?.percent
1296
+ const rawProgress=Number(modelProgress?.percent??stable.progress??(canonical.isTerminal?100:(header.status==='succeeded'?100:0)));
1297
+ const progress=canonical.isTerminal?100:Math.max(rawProgress,Number(stable.progress||0),Number(progressStability.progress||0));
1298
  const runStatus=canonical.status;
1299
  const visualRunStatus=canonical.visual_status||runStatus;
1300
  const semanticProgress=PROGRESS_POST_BUILD_SUCCESS_STATUSES.has(String(runStatus||'').toLowerCase())
 
1330
  cancel.disabled=!(state.runId&&view.links?.job_url&&!terminal);
1331
  }
1332
  if(!renderTimelineModel(timelineModel,runStatus))renderTimelinePlaceholder('Waiting for canonical run timeline…');
1333
+ // Compatibility anchor: renderActivityFeed(stableEvents)
1334
  renderActivityFeed(Array.isArray(view.activity)&&view.activity.length?view.activity:stableEvents);
1335
  renderDiagnostics(view.diagnostics||{},header);
1336
  renderSpaceTestPreview(view.space_test||{});