Mike0021's picture
Enable browser HTTP commands with CORS-aware errors and bounded requests
39371ea verified
Raw History Blame Contribute Delete
6.55 kB
import {chromium} from 'playwright';
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
import { CONTEXT_LIMIT } from '../src/context-usage.mjs';
const root=new URL('../..',import.meta.url).pathname.replace(/\/$/,'');const url=process.argv[2]??'http://127.0.0.1:4173/?source=local';const label=process.argv[3]??'agent-context-usage';
const profile=process.argv[4]??`${root}/validation/agent-browser-profile`;
const result={date:new Date().toISOString(),url,checks:[],errors:[]};
const context=await chromium.launchPersistentContext(profile,{executablePath:'/usr/bin/chromium',headless:true,viewport:{width:1440,height:1000},args:['--enable-unsafe-webgpu','--use-angle=vulkan','--enable-features=Vulkan','--disable-vulkan-surface']});
context.setDefaultTimeout(180000);const page=await context.newPage();page.on('pageerror',e=>result.errors.push(e.stack));
try {
await page.goto(url);await page.waitForFunction(()=>window.browserPi?.terminal);await page.evaluate(()=>window.browserPi.ready);
assert(await page.locator('.xterm-helper-textarea').evaluate(el=>el===document.activeElement));
await page.keyboard.type('/new');await page.keyboard.press('Enter');await page.waitForFunction(()=>!window.browserPi.busy&&window.browserPi.terminal.text===''&&window.browserPi.diagnostics.contextUsage.inputTokens===0);
assert.deepEqual(await page.evaluate(()=>window.browserPi.diagnostics.contextUsage),{inputTokens:0,outputTokens:0});
result.checks.push('Input focused on page load; keyboard command works without clicking');
const nonce='CONTEXT-'+crypto.randomUUID().slice(0,8);
await page.evaluate(nonce=>window.browserPi.rpc('write',{path:'/workspace/context-check.txt',content:nonce}),nonce);
const prompt='Read context-check.txt using the read tool and tell me its exact contents.';
await page.keyboard.type(prompt);await page.keyboard.press('Enter');await page.waitForFunction(()=>document.querySelector('#model-dialog').open);
assert(await page.locator('#model-confirm').evaluate(el=>el===document.activeElement));assert.equal(await page.locator('#model-cancel').textContent(),'Cancel');
await page.locator('#model-cancel').click();await page.waitForFunction(()=>window.browserPi.terminal.text.includes('context-check.txt'));
assert(await page.locator('.xterm-helper-textarea').evaluate(el=>el===document.activeElement));
result.checks.push('Modal takes focus and Cancel restores Pi input and draft');
await page.evaluate(()=>{window.usageSamples=[];window.usageTimer=setInterval(()=>{const u=window.browserPi.diagnostics.contextUsage;if(JSON.stringify(u)!==JSON.stringify(window.usageSamples.at(-1)))window.usageSamples.push({...u});},40)});
await page.keyboard.press('Enter');await page.locator('#model-confirm').click();
await page.waitForFunction(()=>window.browserPi.loaded&&window.browserPi.diagnostics.events.includes('agent_end')&&!window.browserPi.busy);
await page.evaluate(()=>clearInterval(window.usageTimer));
const snapshot=await page.evaluate(()=>window.browserPi.rpc('snapshot'));const diagnostics=await page.evaluate(()=>window.browserPi.diagnostics);
const final=snapshot.messages.filter(m=>m.role==='assistant').at(-1);const gen=diagnostics.generations.at(-1);
assert(final.content.some(c=>c.text?.includes(nonce)));assert(snapshot.messages.some(m=>m.role==='toolResult'&&m.toolName==='read'&&!m.isError));
assert.deepEqual(diagnostics.contextUsage,{inputTokens:gen.inputTokens,outputTokens:gen.outputTokens});assert.equal(final.usage.totalTokens,gen.inputTokens+gen.outputTokens);
const samples=await page.evaluate(()=>window.usageSamples);assert(samples.some(u=>u.inputTokens===gen.inputTokens&&u.outputTokens>0&&u.outputTokens<gen.outputTokens));
result.samples=samples;result.completed=diagnostics.contextUsage;result.checks.push('Actual model/tool workflow: live token increments and final counts equal generation usage');
for(const width of [1440,320]) {
await page.setViewportSize({width,height:844});
const text=`${(gen.inputTokens+gen.outputTokens).toLocaleString('en-US')}/${CONTEXT_LIMIT.toLocaleString('en-US')} context · ${(CONTEXT_LIMIT-gen.inputTokens-gen.outputTokens).toLocaleString('en-US')} free`;
await page.waitForFunction(text=>window.browserPi.terminal.readScreen().includes(text),text);
await page.screenshot({path:`${root}/validation/${label}-${width}.png`,fullPage:true});
}
result.checks.push('Used/limit and remaining tokens fully visible at desktop and 320px widths');
await page.setViewportSize({width:1440,height:1000});await page.locator('.xterm-helper-textarea').focus();await page.keyboard.type('Write a numbered list of 100 different animals, with a sentence about each.');await page.keyboard.press('Enter');
await page.waitForFunction(input=>window.browserPi.busy&&window.browserPi.diagnostics.contextUsage.inputTokens!==input&&window.browserPi.diagnostics.contextUsage.outputTokens>=5,gen.inputTokens);
await page.locator('#stop').click();await page.waitForFunction(()=>!window.browserPi.busy);
const stopped=await page.evaluate(()=>window.browserPi.rpc('snapshot'));const stopUsage=stopped.messages.filter(m=>m.role==='assistant').at(-1).usage;
const beforeReload=await page.evaluate(()=>window.browserPi.diagnostics.contextUsage);
assert.deepEqual(beforeReload,{inputTokens:stopUsage.input,outputTokens:stopUsage.output});assert(stopUsage.output>=5);
await page.reload();await page.waitForFunction(()=>window.browserPi?.terminal);await page.evaluate(()=>window.browserPi.ready);
assert.deepEqual(await page.evaluate(()=>window.browserPi.diagnostics.contextUsage),beforeReload);
assert(await page.locator('.xterm-helper-textarea').evaluate(el=>el===document.activeElement));
result.stopped=beforeReload;result.checks.push('Stopped generation retains exact counts; reload restores them and focuses input');
await page.keyboard.type('/new');await page.keyboard.press('Enter');await page.waitForFunction(()=>!window.browserPi.busy&&window.browserPi.diagnostics.contextUsage.inputTokens===0);
assert.deepEqual(await page.evaluate(()=>window.browserPi.diagnostics.contextUsage),{inputTokens:0,outputTokens:0});
result.checks.push('New chat resets context usage');assert.deepEqual(result.errors,[]);result.passed=true;
console.log(JSON.stringify({passed:true,checks:result.checks,completed:result.completed,stopped:result.stopped}));
} catch(e){result.failure=e.stack;await page.screenshot({path:`${root}/validation/${label}-failure.png`});throw e;}
finally {await fs.writeFile(`${root}/validation/${label}.json`,JSON.stringify(result,null,2));await context.close();}