aboutsummaryrefslogtreecommitdiff
path: root/modules/test/test-agent-registry.js
blob: 0bfc573ee157ce66b4c58cac0e5be62771c0c57b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// modules/test/test-agent-registry.js — run: node
// MAINT-007/008/009: registration must not depend on the cwd, must keep every capability it is
// given, and a bare directory in /agents must not count as a registered agent.
const fsMod = require('fs'), path = require('path');
const ROOT = path.join(__dirname, '..');
const store = {};
global.localStorage = { getItem: k => (k in store ? store[k] : null), setItem: (k, v) => { store[k] = String(v); }, removeItem: k => { delete store[k]; } };
global.indexedDB = { open() { throw new Error('no idb'); }, deleteDatabase() { throw new Error('no idb'); } };
global.window = global;

const load = (rel, cls) => new Function(fsMod.readFileSync(path.join(ROOT, rel), 'utf8') + '\nreturn ' + cls + ';')();
const VFS = load('core/virtual-fs.js', 'VirtualFileSystem');
const Registry = load('core/module-agent-registry.js', 'AgentRegistryModule');

let fails = 0, passes = 0;
function ok(name, cond, detail) {
    if (cond) { passes++; return; }
    fails++;
    console.log('FAIL ' + name + (detail ? ' — ' + detail : ''));
}

function mk() {
    const out = [];
    const vfs = new VFS();
    vfs.saveToStorage = () => true;
    const reg = Object.create(Registry.prototype);
    reg.terminal = { print: (m, t) => out.push({ text: String(m), type: t || '' }), log: () => {}, fs: vfs };
    reg._contracts = {};
    reg._a2aMessages = [];
    reg._a2a = { post: () => 'msg-1', unregister: () => {} };
    // the real A2A helpers touch VFS paths; keep them inert for this test
    reg.a2aRegister = () => {};
    reg.a2aUnregister = () => {};
    return { reg, vfs, out };
}
const text = out => out.map(o => o.text).join(' | ');

// A. the command word is not the agent id, and every capability is kept
{
    const { reg, out } = mk();
    reg.registerAgent(['register', 'orchestrator-0', 'delegate', 'spawn', 'monitor', 'purge']);
    const s = JSON.parse(reg.terminal.fs.readFile('/agents/orchestrator-0/status.json') || 'null');
    ok('A1 the agent is named orchestrator-0', !!s && s.id === 'orchestrator-0', text(out));
    ok('A2 all four capabilities are stored', !!s && s.capabilities.length === 4, s ? JSON.stringify(s.capabilities) : 'no status');
    ok('A3 no agent literally named "register"', !reg.terminal.fs.readDir('/agents/register'));
    ok('A4 the boot message reports 4, not 1', /registered with 4 capabilities/.test(text(out)), text(out));
}

// B. comma-separated capabilities still work
{
    const { reg } = mk();
    reg.registerAgent(['worker', 'read_file,write_file,list_files']);
    const s = JSON.parse(reg.terminal.fs.readFile('/agents/worker/status.json'));
    ok('B1 comma list parsed', s.capabilities.length === 3 && s.capabilities[1] === 'write_file', JSON.stringify(s.capabilities));
}

// C. registering from a subdirectory still writes /agents, never <cwd>/agents
{
    const { reg, vfs } = mk();
    vfs.mkdirRecursive('/docs');
    vfs.currentPath = ['docs'];
    reg.registerAgent(['nested', 'a,b']);
    ok('C1 the agent dir is at /agents/nested', !!vfs.readDir('/agents/nested'), JSON.stringify(vfs.readDir('/') || []));
    ok('C2 nothing was created under /docs', !vfs.readDir('/docs/agents'));
}

// D. unregister removes the directory even when the cwd is elsewhere
{
    const { reg, vfs } = mk();
    reg.registerAgent(['temp-agent', 'a']);
    vfs.currentPath = ['docs'];
    reg.unregisterAgent('temp-agent');
    ok('D1 the directory is gone after unregister', !vfs.readDir('/agents/temp-agent'));
}

// E. a bare directory is not a registered agent
{
    const { reg, vfs, out } = mk();
    reg.registerAgent(['real-agent', 'a,b']);
    vfs.mkdirRecursive('/agents/hand-made');
    reg.listAgents();
    const t = text(out);
    ok('E1 the registered agent is listed', /real-agent/.test(t), t);
    ok('E2 the bare directory is not listed as an agent', !/hand-made — /.test(t), t);
    ok('E3 it is reported as unregistered instead', /no status\.json/.test(t) && /hand-made/.test(t), t);
}

if (fails === 0) {
    console.log('test-agent-registry: ' + passes + ' passed, 0 failed');
} else {
    console.log('test-agent-registry: ' + passes + ' passed, ' + fails + ' FAILED');
    process.exit(1);
}