@bongos/core 1.19.706 → 1.19.707

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,111 @@
1
+ // tests/agent_invoke_live.mjs — the end-to-end proof, reproducible (task 1002491).
2
+ //
3
+ // tests/agent_invoke.mjs proves the DECISIONS with a fake pool, a fake runner and
4
+ // a fake tree. It cannot prove the one thing criterion `agents-historian-exemplar`
5
+ // actually claims: that the real historian, given the real corpus, comes back with
6
+ // an answer whose citations are real. Only a real model call can say that, and a
7
+ // real model call costs real money (~$0.90 a question at the time of writing) and
8
+ // needs an authenticated `claude` CLI — so it must never run in CI or in the unit
9
+ // gate, and it is OPT-IN.
10
+ //
11
+ // AGENT_INVOKE_LIVE=1 node tests/agent_invoke_live.mjs ["<question>"]
12
+ //
13
+ // Skipped and exit 0 otherwise, so `run-unit-tests.js` sweeps it up harmlessly.
14
+ //
15
+ // The POOL is still faked — a builder box has no database, which is also why the
16
+ // script's every edge is injectable. What is real here is the definition (parsed
17
+ // from the committed .claude/agents/historian.md exactly as agents-sync would land
18
+ // it), the corpus (this checkout), the model, and the citation check.
19
+
20
+ import { strict as assert } from 'node:assert';
21
+ import fs from 'node:fs';
22
+ import path from 'node:path';
23
+ import { fileURLToPath } from 'node:url';
24
+ import { createRequire } from 'node:module';
25
+
26
+ const require = createRequire(import.meta.url);
27
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
28
+
29
+ if (process.env.AGENT_INVOKE_LIVE !== '1') {
30
+ console.log(' skip agent_invoke_live — set AGENT_INVOKE_LIVE=1 to spend ~$1 proving the chain for real');
31
+ process.exit(0);
32
+ }
33
+
34
+ const invoke = require('../scripts/gds/agent-invoke.js');
35
+ const agentsSync = require('../scripts/gds/agents-sync.js');
36
+ const grader = require('../modules/grading/grader.js');
37
+
38
+ // The definition exactly as the deploy-time reconcile would land it, so what runs
39
+ // is the committed file and not a fixture that drifted from it.
40
+ const candidate = agentsSync.parseAgentFile(
41
+ fs.readFileSync(path.join(ROOT, '.claude/agents/historian.md'), 'utf8'),
42
+ { name: 'historian' },
43
+ );
44
+ const definition = {
45
+ id: 1,
46
+ ...candidate,
47
+ trigger_spec: {},
48
+ scope_modules: [],
49
+ scope_paths: [],
50
+ scope_violation: null,
51
+ source: 'file',
52
+ provenance: 'built-in',
53
+ // Armed for the duration of this check. Note that a real deploy does NOT land
54
+ // it armed — see the header of scripts/gds/agent-invoke.js.
55
+ author_rank: 'archon',
56
+ enabled: true,
57
+ };
58
+
59
+ const ledger = [];
60
+ const pool = {
61
+ async query(sql, params) {
62
+ if (/FROM agents_definitions/.test(sql)) return { rows: [definition] };
63
+ // No database on a builder box; the degrade path is exercised for free.
64
+ if (/FROM learnings/.test(sql)) throw new Error('no database on this box');
65
+ if (/^INSERT INTO agents_runs/.test(sql)) { ledger.push(['insert', params]); return { rows: [{ id: 1 }] }; }
66
+ ledger.push(['update', params]);
67
+ return { rows: [] };
68
+ },
69
+ };
70
+
71
+ const question = process.argv.slice(2).join(' ')
72
+ || 'Why does this project enforce permissions server-side rather than in the client, and what is the rule about editing local files to grant yourself authority?';
73
+
74
+ console.log(` Q: ${question}`);
75
+ const started = Date.now();
76
+ const result = await invoke.invokeAgent(
77
+ { name: 'historian', question, requestedByBuilderId: 1, requestedByLogin: 'live-check' },
78
+ {
79
+ pool,
80
+ runSubagentCached: (a) => grader.runSubagentCached({ ...a, opts: { ...a.opts, timeoutMs: 600000 } }),
81
+ spawnDeps: { brandingModels: { subagentDefault: 'claude-opus-5', subagentRoutine: 'claude-haiku-4-5-20251001' } },
82
+ warn: (m) => console.log(` warn: ${m}`),
83
+ },
84
+ );
85
+ const secs = Math.round((Date.now() - started) / 1000);
86
+
87
+ if (!result.ok) {
88
+ console.error(` FAIL ${result.code} — ${result.reason || ''} (${secs}s)`);
89
+ process.exit(1);
90
+ }
91
+
92
+ console.log(`\n${result.answer.answer}\n`);
93
+ console.log(' Citations, every one resolved against this checkout:');
94
+ for (const c of result.answer.citations) console.log(` - ${c.ref}`);
95
+ console.log(`\n ${secs}s · ${result.model} · $${result.cost_usd} · confidence ${result.answer.confidence}`);
96
+
97
+ // The claim the criterion makes, asserted rather than eyeballed.
98
+ assert.ok(result.answer.citations.length > 0, 'a cited result');
99
+ for (const c of result.answer.citations) {
100
+ const p = invoke.citationPath(c.ref);
101
+ if (/^learning:/.test(c.ref)) continue;
102
+ assert.ok(fs.existsSync(path.join(ROOT, p)), `${p} exists in the tree`);
103
+ }
104
+ // ...and the ledger said so: one go row, finished ok, with a real cost on it.
105
+ const [insert] = ledger.filter(([k]) => k === 'insert');
106
+ const [update] = ledger.filter(([k]) => k === 'update');
107
+ assert.ok(insert && insert[1].includes('go'), 'the gate said go');
108
+ assert.ok(update && update[1].includes('ok'), 'the run finished ok');
109
+ assert.ok(Number(result.cost_usd) > 0, 'a real fire costs real money and the ledger carries it');
110
+
111
+ console.log('\n ok the historian returned a cited result end-to-end, and the ledger agrees');