Download app/tests/conversation.mjs from Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP: direct link, hf CLI and curl.
- Browser
- Download file 5.53 kB
-
https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/conversation.mjs
- Command line
-
hf download hf://spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/app/tests/conversation.mjs
-
curl -L -o conversation.mjs https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/conversation.mjs
5.53 kB
| import { chromium } from 'playwright'; | |
| import fs from 'node:fs/promises'; | |
| import assert from 'node:assert/strict'; | |
| const url = process.argv[2] ?? 'http://127.0.0.1:4173/?source=local'; | |
| const label = process.argv[3] ?? 'agent-terminal-dark-conversation'; | |
| const profile = new URL('../../validation/agent-browser-profile', import.meta.url).pathname; | |
| const result = { date: new Date().toISOString(), url, kind: 'actual model; ten consecutive user turns, no chat resets', turns: [], 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(180_000); | |
| const page = await context.newPage(); | |
| page.on('pageerror', error => result.errors.push(error.stack)); | |
| const hasTool = (messages, name) => messages.some(m => m.role === 'toolResult' && m.toolName === name && !m.isError); | |
| try { | |
| await page.goto(url); await page.waitForFunction(() => window.browserPi?.terminal); | |
| await page.evaluate(() => window.browserPi.ready); | |
| await page.evaluate(() => window.browserPi.load()); | |
| await page.waitForFunction(() => !window.browserPi.busy); | |
| await page.evaluate(() => document.querySelector('#new-chat').onclick()); | |
| await page.evaluate(() => window.browserPi.rpc('shell', { command: 'rm -f /workspace/todo /workspace/numbers.txt /workspace/render-notes.md /workspace/render-missing.txt' })); | |
| await context.setOffline(true); | |
| const tasks = [ | |
| { prompt: 'Hi! Reply with one short sentence.' }, | |
| { prompt: 'Create a file called todo containing exactly "# todo" followed by a newline and "- Check rendering". Use the write tool.', check: (s,m) => { assert(hasTool(m,'write')); assert.match(s.files['/workspace/todo'], /Check rendering/); } }, | |
| { prompt: 'Read todo using the read tool and show its contents.', check: (s,m) => assert(hasTool(m,'read')) }, | |
| { prompt: 'Use the edit tool on todo to replace Check rendering with Check dark mode. Then read it to verify.', check: (s,m) => { assert(hasTool(m,'edit')); assert.match(s.files['/workspace/todo'], /Check dark mode/); } }, | |
| { prompt: 'Run this bash command: seq 1 40 > numbers.txt; wc -l numbers.txt', check: (s,m) => { assert(hasTool(m,'bash')); assert.equal(s.files['/workspace/numbers.txt'].trim().split('\n').length,40); } }, | |
| { prompt: 'Read numbers.txt using the read tool. Tell me only its first and last numbers.', check: (s,m) => assert(hasTool(m,'read')) }, | |
| { prompt: 'Write render-notes.md with a Markdown heading Dark mode, a two-item list about padding and contrast, and a fenced bash code block containing cat todo. Then read the file.', check: (s,m) => { assert(hasTool(m,'write')); assert.match(s.files['/workspace/render-notes.md'], /Dark mode/); } }, | |
| { prompt: 'Read render-missing.txt using the read tool. If missing, write exactly Recovered into it, then read it again.', check: (s,m) => { assert(m.some(m=>m.role==='toolResult' && m.isError)); assert.equal(s.files['/workspace/render-missing.txt'].trim(),'Recovered'); } }, | |
| { prompt: 'Run bash to print todo and render-missing.txt, then count the lines in numbers.txt.', check: (s,m) => assert(hasTool(m,'bash')) }, | |
| { prompt: 'Summarize the files we created in three short Markdown bullets. No tools needed.' }, | |
| ]; | |
| let count = 0; | |
| for (const [index, task] of tasks.entries()) { | |
| const start = Date.now(); | |
| await page.locator('.xterm-helper-textarea').focus(); await page.keyboard.type(task.prompt); | |
| await page.locator('#send').click(); await page.waitForFunction(() => window.browserPi.busy); | |
| await page.waitForFunction(() => !window.browserPi.busy); | |
| const state = await page.evaluate(() => window.browserPi.rpc('snapshot')); | |
| const messages = state.messages.slice(count); count = state.messages.length; | |
| const entry = { turn: index+1, elapsedMs: Date.now()-start, prompt: task.prompt, messages }; | |
| result.turns.push(entry); | |
| assert.equal(state.messages.filter(m=>m.role==='user').length,index+1); | |
| assert(messages.filter(m=>m.role==='assistant').at(-1)?.content.some(c=>c.type==='text' && c.text.trim())); | |
| task.check?.(state,messages); | |
| console.log('PASS turn', index+1, entry.elapsedMs); | |
| } | |
| await page.locator('.xterm-helper-textarea').focus(); await page.keyboard.press('Control+o'); await page.keyboard.press('End'); | |
| await page.screenshot({ path: `../validation/${label}-desktop.png`, fullPage:true }); | |
| await page.keyboard.press('Home'); await page.waitForFunction(()=>window.browserPi.terminal.viewportTop===0); | |
| await page.keyboard.press('End'); | |
| await page.setViewportSize({width:390,height:844}); await page.waitForTimeout(150); | |
| assert(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth)); | |
| await page.screenshot({ path: `../validation/${label}-mobile.png`, fullPage:true }); | |
| result.finalState = await page.evaluate(()=>window.browserPi.rpc('snapshot')); | |
| result.screen = await page.evaluate(()=>window.browserPi.terminal.readScreen()); | |
| result.diagnostics = await page.evaluate(()=>window.browserPi.diagnostics); | |
| assert.equal(result.errors.length,0); result.passed=true; | |
| } catch(error) { result.failure=error.stack; await page.screenshot({path:`../validation/${label}-failure.png`,fullPage:true}); throw error; } | |
| finally { await fs.writeFile(`../validation/${label}.json`,JSON.stringify(result,null,2)); await context.close(); } | |