mona-agent / apps /desktop /test /docker-control.test.mjs
mo
feat: desktop app packaging + engine/protocol/gateway packages, HTTP metrics pipeline
e720a94
Raw History Blame Contribute Delete
3.68 kB
// Docker-platform protocol tests: flat register, chat mapping, llm:request RPC.
// Run: node --test test/docker-control.test.mjs
import { describe, it, before, after } from 'node:test';
import assert from 'node:assert/strict';
import { WebSocketServer } from 'ws';
// Start the fake platform first, then import ControlChannel with the env pointing at it.
const server = new WebSocketServer({ port: 0 });
const port = server.address().port;
process.env.MONA_CLOUD = `http://127.0.0.1:${port}`;
process.env.MONA_CLOUD_WS = `ws://127.0.0.1:${port}/ws`;
const { ControlChannel } = await import('../src/control.js');
const received = [];
const connections = [];
server.on('connection', (ws) => {
connections.push(ws);
ws.on('message', (raw) => {
const msg = JSON.parse(raw.toString());
received.push(msg);
if (msg.type === 'llm:request') {
if (msg.messages?.[0]?.content === 'boom') {
ws.send(JSON.stringify({ type: 'llm:error', requestId: msg.requestId, error: 'no key for provider' }));
} else {
ws.send(JSON.stringify({
type: 'llm:response', requestId: msg.requestId,
content: 'hello from fake platform', usage: { inputTokens: 5, outputTokens: 3 },
}));
}
}
});
});
const waitFor = (pred, ms = 3000) => new Promise((resolve, reject) => {
const t0 = Date.now();
const iv = setInterval(() => {
const hit = pred();
if (hit) { clearInterval(iv); resolve(hit); }
else if (Date.now() - t0 > ms) { clearInterval(iv); reject(new Error('timeout waiting for condition')); }
}, 20);
});
describe('docker platform protocol', () => {
before(() => {});
after(() => server.close());
it('connects and sends a flat register message', async () => {
const ch = new ControlChannel('key', 'agent-1');
ch.on('error', () => {});
ch.connect();
const reg = await waitFor(() => received.find(m => m.type === 'register'));
assert.ok(reg);
assert.equal(reg.type, 'register');
assert.ok(reg.name);
assert.ok(reg.model.includes('mona-agent'));
ch.close();
});
it('proxies llm:request and resolves llm:response', async () => {
const ch = new ControlChannel('key', 'agent-1');
ch.on('error', () => {});
ch.connect();
const p = ch.llmRequest({ messages: [{ role: 'user', content: 'hi' }] });
const res = await Promise.race([
p,
new Promise((_, reject) => setTimeout(() => reject(new Error('no llm response')), 3000)),
]);
assert.equal(res.content, 'hello from fake platform');
assert.deepEqual(res.usage, { inputTokens: 5, outputTokens: 3 });
ch.close();
});
it('rejects when the platform answers llm:error', async () => {
const ch = new ControlChannel('key', 'agent-1');
ch.on('error', () => {});
ch.connect();
await assert.rejects(
ch.llmRequest({ messages: [{ role: 'user', content: 'boom' }] }),
/no key for provider/
);
ch.close();
});
it('maps inbound chat messages to run commands', async () => {
const ch = new ControlChannel('key', 'agent-1');
ch.on('error', () => {});
const cmd = new Promise((resolve) => ch.on('command', resolve));
ch.connect();
// Wait for the connection to be open before pushing a chat message.
await waitFor(() => ch.connected);
connections.at(-1).send(JSON.stringify({ type: 'chat', requestId: 'req_42', message: 'do the thing' }));
const m = await Promise.race([cmd, new Promise((_, reject) => setTimeout(() => reject(new Error('no command')), 3000))]);
assert.equal(m.action, 'run');
assert.equal(m.runId, 'req_42');
assert.equal(m.payload.task, 'do the thing');
ch.close();
});
});