Files
agent/scripts/verify-image-video-readiness.mjs
T

53 lines
3.7 KiB
JavaScript

// Live model/Skill readiness only. Never uploads a reference or submits H3.
import assert from 'node:assert/strict';
const base='http://127.0.0.1:5173';
const abort=new AbortController();
async function api(path,method='GET',body){
const response=await fetch(base+path,{method,redirect:'error',signal:AbortSignal.timeout(20000),headers:{Origin:base,...(body?{'Content-Type':'application/json'}:{})},...(body?{body:JSON.stringify(body)}:{})});
assert(response.ok,`${method} ${path}: HTTP ${response.status}`);
return response.json();
}
let sessionId;
try {
const catalog=await api('/api/skills');
assert(catalog.skills.some(skill=>skill.name==='swads-image-to-video'),'New Skill missing from live catalog');
const history=await api('/api/image-video/tasks');
console.log(JSON.stringify({stage:'catalog-and-history',skillFound:true,historyAvailable:history!==undefined,remoteMutation:false}));
({sessionId}=await api('/api/sessions','POST',{}));
const stream=await fetch(`${base}/api/sessions/${sessionId}/events`,{signal:abort.signal});
assert(stream.ok&&stream.body,'SSE unavailable');
const reader=stream.body.getReader();
const sent=await api(`/api/sessions/${sessionId}/messages`,'POST',{text:'仅做 swads-image-to-video 接入只读检查:完整读取该 Skill 的 SKILL.md 和 references/swads.md。然后简短说明它不需要 CMS,以及必须分别批准参考图外传和 H3 生成。不要调用任何 CMS 工具,不读取图片或私人业务数据,不上传、不入库、不生成、不写文件。',attachmentIds:[]});
const timer=setTimeout(()=>abort.abort(),150000);
let buffer='';const decoder=new TextDecoder();let loaded=false;let answer=false;let referenceRead=false;let done=false;const referenceCalls=new Set();
try {
while(!done){
const chunk=await reader.read();assert(!chunk.done,'Unexpected SSE end');buffer+=decoder.decode(chunk.value,{stream:true});
let boundary;
while((boundary=buffer.indexOf('\n\n'))!==-1){
const frame=buffer.slice(0,boundary);buffer=buffer.slice(boundary+2);
const data=frame.split('\n').find(line=>line.startsWith('data: '))?.slice(6);if(!data)continue;
const event=JSON.parse(data);if(event.runId!==sent.runId)continue;
assert(event.type!=='approval.required','Unexpected external/mutating action request');
if(event.type==='tool.requested'){
assert(['read','ls','find','grep'].includes(event.payload.toolName),'Unexpected business tool requested');
if(event.payload.toolName==='read'&&JSON.stringify(event.payload.arguments).includes('references/swads.md'))referenceCalls.add(event.payload.toolCallId);
}
if(event.type==='skill.loaded')loaded=true;
if(event.type==='tool.completed'&&referenceCalls.has(event.payload.toolCallId))referenceRead=true;
if(event.type==='assistant.delta'&&event.payload.delta?.trim())answer=true;
if(['run.completed','run.failed','run.cancelled'].includes(event.type)){
console.log(JSON.stringify({stage:'model-skill',terminal:event.type,skillLoaded:loaded,referenceRead,answerReceived:answer,remoteMutation:false}));
assert(event.type==='run.completed');done=true;
}
}
}
assert(loaded&&referenceRead&&answer,'Skill/read/answer evidence incomplete');
}finally{clearTimeout(timer);abort.abort();}
console.log(JSON.stringify({result:'PASS',scope:'live Skill reading and local history only',h3GenerationVerified:false}));
}catch(error){console.error(JSON.stringify({result:'FAIL',message:String(error.message).slice(0,300)}));process.exitCode=1;}
finally{
abort.abort();
if(sessionId){await api(`/api/sessions/${sessionId}/cancel`,'POST',{}).catch(()=>{});await api(`/api/sessions/${sessionId}`,'DELETE').catch(()=>{});}
}