Download app/tests/protocol.test.mjs from Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP: direct link, hf CLI and curl.
- Browser
- Download file 9.1 kB
-
https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/protocol.test.mjs
- Command line
-
hf download hf://spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/app/tests/protocol.test.mjs
-
curl -L -o protocol.test.mjs https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/protocol.test.mjs
9.1 kB
| import test from 'node:test'; | |
| import assert from 'node:assert/strict'; | |
| import { parseCompletion, splitThinking, toMiniMessages, fitContext } from '../src/protocol.mjs'; | |
| import { createWorkspace } from '../src/workspace.mjs'; | |
| import { renderMarkdown } from '../src/markdown.mjs'; | |
| const { tools } = createWorkspace(); | |
| test('read results identify the real file through relative paths and symlinks', async () => { | |
| const workspace = createWorkspace(); | |
| await workspace.write('nested/name%20#é.txt', ''); | |
| await workspace.bash.exec("ln -s 'nested/name%20#é.txt' link.txt"); | |
| const read = workspace.tools.find(tool => tool.name === 'read'); | |
| const result = await read.execute('read-path', { path: './link.txt' }); | |
| assert.equal(result.details.path, '/workspace/nested/name%20#é.txt'); | |
| assert.equal(result.content[0].text, ''); | |
| await assert.rejects(read.execute('missing', { path: 'missing.txt' })); | |
| }); | |
| test('model Markdown cannot execute HTML or request remote images', () => { | |
| const html = renderMarkdown('<script>alert(1)</script>\n\n[x](javascript:alert(1))'); | |
| assert(!html.includes('<script>')); assert(!html.includes('<img')); assert(!html.includes('href="javascript:')); | |
| assert.match(renderMarkdown('```bash\necho ok\n```'), /<pre><code class="language-bash">/); | |
| }); | |
| test('MiniCPM XML retains shell characters, CDATA, split CDATA, and multiple calls', () => { | |
| const text = 'Inspecting.\n<function name="bash"><param name="command"><![CDATA[printf "<x>&</function>"\necho ]]]]><![CDATA[>]]></param></function>\n<function name="read"><param name="path">a&b.txt</param></function><|im_end|>'; | |
| const blocks = parseCompletion(text, tools); | |
| assert.equal(blocks[0].text, 'Inspecting.'); | |
| assert.equal(blocks[1].arguments.command, 'printf "<x>&</function>"\necho ]]>'); | |
| assert.equal(blocks[2].arguments.path, 'a&b.txt'); | |
| }); | |
| test('XML examples in fenced or inline code remain text', () => { | |
| const call = '<function name="bash"><param name="command">ls</param></function>'; | |
| for (const example of ['```xml\n' + call + '\n```', '`' + call + '`', '~~~xml\n' + call + '\n~~~']) { | |
| const blocks = parseCompletion(example, tools); | |
| assert.deepEqual(blocks, [{ type: 'text', text: example }]); | |
| } | |
| const blocks = parseCompletion('```xml\n' + call + '\n```\n' + call, tools); | |
| assert.equal(blocks[1].type, 'toolCall'); | |
| }); | |
| test('incomplete, unknown, nested, duplicate and malformed calls cannot execute', () => { | |
| for (const text of [ | |
| '<function name="bash"><param name="command">ls', | |
| '<function name="missing"></function>', | |
| '<function name="bash"><param name="command"><x/></param></function>', | |
| '<function name="bash"><param name="command">ls</param><param name="command">pwd</param></function>', | |
| '<function name="bash"><param name="__proto__">x</param></function>', | |
| '<function name="bash"><param name="command">ls</function>', | |
| ]) assert.throws(() => parseCompletion(text, tools), text); | |
| }); | |
| test('thinking never becomes executable and tool history is serialized with names', () => { | |
| const blocks = parseCompletion('<think><function name="bash"><param name="command">rm -r /</param></function></think>Done<|im_end|>', tools); | |
| assert.equal(blocks[0].type, 'thinking'); | |
| assert.deepEqual(blocks.slice(1), [{ type: 'text', text: 'Done' }]); | |
| const messages = toMiniMessages({ systemPrompt: 'Pi', messages: [ | |
| { role: 'assistant', content: [{ type: 'toolCall', name: 'read', arguments: { path: 'x' } }] }, | |
| { role: 'toolResult', toolName: 'read', content: [{ type: 'text', text: 'abc' }], isError: false }, | |
| ] }); | |
| assert.equal(messages[1].tool_calls[0].function.arguments.path, 'x'); | |
| assert.deepEqual(JSON.parse(messages[2].content), { name: 'read', isError: false, output: 'abc' }); | |
| }); | |
| test('prefilled thinking is separated, retained across user turns, and never executed', () => { | |
| const reasoning = '<function name="bash"><param name="command">rm -r /</param></function>'; | |
| const content = parseCompletion(reasoning + '\n</think>\n\nDone<|im_end|>', tools, { thinkingPrefilled: true }); | |
| assert.deepEqual(content, [{ type: 'thinking', thinking: reasoning }, { type: 'text', text: 'Done' }]); | |
| assert.throws(() => parseCompletion(reasoning, tools, { thinkingPrefilled: true }), /before finishing/); | |
| assert.equal(splitThinking('Let me inspect</thi', { thinkingPrefilled: true }).complete, false); | |
| const messages = toMiniMessages({ systemPrompt: 'Pi', messages: [ | |
| { role: 'user', content: 'old' }, { role: 'assistant', content }, { role: 'user', content: 'new' }, | |
| ] }); | |
| assert.equal(messages[2].reasoning_content, reasoning); | |
| assert.equal(messages[2].content, 'Done'); | |
| assert.equal(messages[2].tool_calls.length, 0); | |
| }); | |
| test('literal thinking tags in code and tool data are preserved', () => { | |
| const literal = '<think>example</think>'; | |
| const raw = 'Ready\n</think>\n<function name="write"><param name="path">x</param><param name="content"><![CDATA[' + literal + ']]></param></function>'; | |
| const blocks = parseCompletion(raw, tools, { thinkingPrefilled: true }); | |
| assert.equal(blocks[1].arguments.content, literal); | |
| assert.deepEqual(parseCompletion('```html\n' + literal + '\n```', tools), [{ type: 'text', text: '```html\n' + literal + '\n```' }]); | |
| }); | |
| test('assistant history keeps text/tool order and excludes interrupted thoughts', () => { | |
| const content = [{ type: 'thinking', thinking: 'Inspect both.' }, { type: 'text', text: 'First.\n' }, | |
| { type: 'toolCall', name: 'read', arguments: { path: 'a' } }, { type: 'text', text: '\nSecond.\n' }, | |
| { type: 'toolCall', name: 'read', arguments: { path: 'b' } }]; | |
| const messages = toMiniMessages({ systemPrompt: 'Pi', messages: [ | |
| { role: 'assistant', content }, { role: 'assistant', content, stopReason: 'aborted' }, | |
| { role: 'assistant', content, stopReason: 'error' }, | |
| ] }); | |
| assert.equal(messages.length, 2); | |
| assert.equal(messages[1].content, 'First.\n<tool_sep>\nSecond.\n<tool_sep>'); | |
| assert.deepEqual(messages[1].tool_calls.map(c => c.function.arguments.path), ['a', 'b']); | |
| }); | |
| test('context trimming drops complete older user turns and rejects oversized current turn', () => { | |
| const context = { systemPrompt: '', messages: [ | |
| { role: 'user', content: 'old' }, { role: 'assistant', content: [] }, | |
| { role: 'toolResult', content: [], toolName: 'read' }, { role: 'user', content: 'new' }, | |
| ] }; | |
| const result = fitContext(context, messages => ({ input_ids: { dims: [1, messages.length] } }), 2); | |
| assert.equal(result.dropped, 3); | |
| assert.throws(() => fitContext(context, () => ({ input_ids: { dims: [1, 99] } }), 2), /exceeds/); | |
| }); | |
| test('real just-bash executes pipelines and scripts; filesystem survives reload snapshot', async () => { | |
| const workspace = createWorkspace(); | |
| const total = "awk 'NR==FNR {price[$1]=$2; next} FNR>1 {split($0,row,\",\"); if (!(row[1] in price)) exit 1; sum += row[2]*price[row[1]]} END {print sum}' <(jq -r '.[] | [.product, .price] | @tsv' products.json) sales.csv"; | |
| let result = await workspace.bash.exec(total + ' > total.txt; cat total.txt'); | |
| assert.equal(result.stdout.trim(), '144'); assert.equal(result.exitCode, 0); | |
| const products = JSON.parse(await workspace.read('products.json')); products[0].price = 6; | |
| await workspace.write('products.json', JSON.stringify(products)); | |
| assert.equal((await workspace.bash.exec(total)).stdout.trim(), '156'); | |
| await workspace.write('sales.csv', (await workspace.read('sales.csv')).replace('Notebook,12', 'Notebook,13')); | |
| assert.equal((await workspace.bash.exec(total)).stdout.trim(), '162'); | |
| await workspace.tools.find(t => t.name === 'write').execute('1', { path: 'hello.sh', content: 'printf "Hello from the browser\\n"' }); | |
| result = await workspace.bash.exec('bash hello.sh'); assert.equal(result.stdout.trim(), 'Hello from the browser'); | |
| await workspace.tools.find(t => t.name === 'edit').execute('2', { path: 'hello.sh', oldText: 'Hello', newText: '$& literal' }); | |
| assert.match(await workspace.read('hello.sh'), /\$& literal/); | |
| const restored = createWorkspace(await workspace.snapshot()); assert.equal(await restored.read('total.txt'), '144\n'); | |
| const denied = await workspace.bash.exec('curl http://example.com'); | |
| assert.notEqual(denied.exitCode, 0); assert.match(denied.stderr, /Only HTTPS/); | |
| assert.equal((await workspace.bash.exec('node -v')).exitCode, 127); | |
| }); | |
| test('workspace persistence preserves executable modes, empty directories, symlinks and bytes', async () => { | |
| const w = createWorkspace(); | |
| await w.bash.exec('mkdir empty; printf "echo ok\\n" > run.sh; chmod +x run.sh; ln -s run.sh link.sh'); | |
| await w.bash.fs.writeFile('/workspace/bytes', new Uint8Array([0, 255, 128, 65])); | |
| const restored = createWorkspace(undefined, await w.serialize()); | |
| await restored.ready; | |
| assert.equal((await restored.bash.exec('./link.sh')).stdout, 'ok\n'); | |
| assert.equal((await restored.bash.fs.stat('/workspace/empty')).isDirectory, true); | |
| assert.deepEqual(await restored.bash.fs.readFileBuffer('/workspace/bytes'), new Uint8Array([0, 255, 128, 65])); | |
| }); | |