agent-tool-forge 0.3.0
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.
- package/LICENSE +21 -0
- package/README.md +209 -0
- package/lib/agent-registry.js +170 -0
- package/lib/api-client.js +792 -0
- package/lib/api-loader.js +260 -0
- package/lib/auth.d.ts +25 -0
- package/lib/auth.js +158 -0
- package/lib/checks/check-adapter.js +172 -0
- package/lib/checks/compose.js +42 -0
- package/lib/checks/content-match.js +14 -0
- package/lib/checks/cost-budget.js +11 -0
- package/lib/checks/index.js +18 -0
- package/lib/checks/json-valid.js +15 -0
- package/lib/checks/latency.js +11 -0
- package/lib/checks/length-bounds.js +17 -0
- package/lib/checks/negative-match.js +14 -0
- package/lib/checks/no-hallucinated-numbers.js +63 -0
- package/lib/checks/non-empty.js +34 -0
- package/lib/checks/regex-match.js +12 -0
- package/lib/checks/run-checks.js +84 -0
- package/lib/checks/schema-match.js +26 -0
- package/lib/checks/tool-call-count.js +16 -0
- package/lib/checks/tool-selection.js +34 -0
- package/lib/checks/types.js +45 -0
- package/lib/comparison/compare.js +86 -0
- package/lib/comparison/format.js +104 -0
- package/lib/comparison/index.js +6 -0
- package/lib/comparison/statistics.js +59 -0
- package/lib/comparison/types.js +41 -0
- package/lib/config-schema.js +200 -0
- package/lib/config.d.ts +66 -0
- package/lib/conversation-store.d.ts +77 -0
- package/lib/conversation-store.js +443 -0
- package/lib/db.d.ts +6 -0
- package/lib/db.js +1112 -0
- package/lib/dep-check.js +99 -0
- package/lib/drift-background.js +61 -0
- package/lib/drift-monitor.js +187 -0
- package/lib/eval-runner.js +566 -0
- package/lib/fixtures/fixture-store.js +161 -0
- package/lib/fixtures/index.js +11 -0
- package/lib/forge-engine.js +982 -0
- package/lib/forge-eval-generator.js +417 -0
- package/lib/forge-file-writer.js +386 -0
- package/lib/forge-service-client.js +190 -0
- package/lib/forge-service.d.ts +4 -0
- package/lib/forge-service.js +655 -0
- package/lib/forge-verifier-generator.js +271 -0
- package/lib/handlers/admin.js +151 -0
- package/lib/handlers/agents.js +229 -0
- package/lib/handlers/chat-resume.js +334 -0
- package/lib/handlers/chat-sync.js +320 -0
- package/lib/handlers/chat.js +320 -0
- package/lib/handlers/conversations.js +92 -0
- package/lib/handlers/preferences.js +88 -0
- package/lib/handlers/tools-list.js +58 -0
- package/lib/hitl-engine.d.ts +60 -0
- package/lib/hitl-engine.js +261 -0
- package/lib/http-utils.js +92 -0
- package/lib/index.d.ts +20 -0
- package/lib/index.js +141 -0
- package/lib/init.js +636 -0
- package/lib/manual-entry.js +59 -0
- package/lib/mcp-server.js +252 -0
- package/lib/output-groups.js +54 -0
- package/lib/postgres-store.d.ts +31 -0
- package/lib/postgres-store.js +465 -0
- package/lib/preference-store.d.ts +47 -0
- package/lib/preference-store.js +79 -0
- package/lib/prompt-store.d.ts +42 -0
- package/lib/prompt-store.js +60 -0
- package/lib/rate-limiter.d.ts +30 -0
- package/lib/rate-limiter.js +104 -0
- package/lib/react-engine.d.ts +110 -0
- package/lib/react-engine.js +337 -0
- package/lib/runner/cli.js +156 -0
- package/lib/runner/cost-estimator.js +71 -0
- package/lib/runner/gate.js +46 -0
- package/lib/runner/index.js +165 -0
- package/lib/sidecar.d.ts +83 -0
- package/lib/sidecar.js +161 -0
- package/lib/sse.d.ts +15 -0
- package/lib/sse.js +30 -0
- package/lib/tools-scanner.js +91 -0
- package/lib/tui.js +253 -0
- package/lib/verifier-report.js +78 -0
- package/lib/verifier-runner.js +338 -0
- package/lib/verifier-scanner.js +70 -0
- package/lib/verifier-worker-pool.js +196 -0
- package/lib/views/chat.js +340 -0
- package/lib/views/endpoints.js +203 -0
- package/lib/views/eval-run.js +206 -0
- package/lib/views/forge-agent.js +538 -0
- package/lib/views/forge.js +410 -0
- package/lib/views/main-menu.js +275 -0
- package/lib/views/mediation.js +381 -0
- package/lib/views/model-compare.js +430 -0
- package/lib/views/model-comparison.js +333 -0
- package/lib/views/onboarding.js +470 -0
- package/lib/views/performance.js +237 -0
- package/lib/views/run-evals.js +205 -0
- package/lib/views/settings.js +829 -0
- package/lib/views/tools-evals.js +514 -0
- package/lib/views/verifier-coverage.js +617 -0
- package/lib/workers/verifier-worker.js +52 -0
- package/package.json +123 -0
- package/widget/forge-chat.js +789 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Adapted from agent-eval-kit by FlanaganSe (https://github.com/FlanaganSe/agent-eval-kit)
|
|
2
|
+
// MIT License — see LICENSE
|
|
3
|
+
|
|
4
|
+
import { readFile, writeFile, mkdir, readdir, unlink, stat } from 'node:fs/promises';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
const VERSION = '1.0.0';
|
|
8
|
+
const DEFAULT_TTL_DAYS = 30;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Deep-sort all keys in an object (for stable hashing).
|
|
12
|
+
* @param {unknown} obj
|
|
13
|
+
* @returns {unknown}
|
|
14
|
+
*/
|
|
15
|
+
export function sortKeysDeep(obj) {
|
|
16
|
+
if (Array.isArray(obj)) return obj.map(sortKeysDeep);
|
|
17
|
+
if (obj !== null && typeof obj === 'object') {
|
|
18
|
+
return Object.fromEntries(
|
|
19
|
+
Object.keys(obj).sort().map(k => [k, sortKeysDeep(obj[k])])
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return obj;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Slugify a case ID for use as a filename.
|
|
27
|
+
* @param {string} caseId
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
function slugify(caseId) {
|
|
31
|
+
return caseId.replace(/[^a-zA-Z0-9]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get the fixture file path for a case.
|
|
36
|
+
* @param {string} fixturesDir
|
|
37
|
+
* @param {string} caseId
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
function fixturePath(fixturesDir, caseId) {
|
|
41
|
+
return join(fixturesDir, `${slugify(caseId)}.jsonl`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Write a fixture to disk.
|
|
46
|
+
* @param {string} fixturesDir
|
|
47
|
+
* @param {string} caseId
|
|
48
|
+
* @param {string} configHash
|
|
49
|
+
* @param {unknown} output
|
|
50
|
+
* @returns {Promise<void>}
|
|
51
|
+
*/
|
|
52
|
+
export async function writeFixture(fixturesDir, caseId, configHash, output) {
|
|
53
|
+
await mkdir(fixturesDir, { recursive: true });
|
|
54
|
+
const meta = { _meta: { configHash, version: VERSION, timestamp: new Date().toISOString() } };
|
|
55
|
+
const data = { output };
|
|
56
|
+
const content = JSON.stringify(meta) + '\n' + JSON.stringify(data) + '\n';
|
|
57
|
+
await writeFile(fixturePath(fixturesDir, caseId), content, 'utf8');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Read a fixture from disk.
|
|
62
|
+
* @param {string} fixturesDir
|
|
63
|
+
* @param {string} caseId
|
|
64
|
+
* @param {string} configHash
|
|
65
|
+
* @param {{ttlDays?: number}} [opts]
|
|
66
|
+
* @returns {Promise<{status: 'hit', output: unknown} | {status: 'miss', reason: string, storedHash?: string, age?: number}>}
|
|
67
|
+
*/
|
|
68
|
+
export async function readFixture(fixturesDir, caseId, configHash, opts = {}) {
|
|
69
|
+
const ttlDays = opts.ttlDays ?? DEFAULT_TTL_DAYS;
|
|
70
|
+
const path = fixturePath(fixturesDir, caseId);
|
|
71
|
+
|
|
72
|
+
let content;
|
|
73
|
+
try {
|
|
74
|
+
content = await readFile(path, 'utf8');
|
|
75
|
+
} catch {
|
|
76
|
+
return { status: 'miss', reason: 'not-found' };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const lines = content.trim().split('\n');
|
|
80
|
+
if (lines.length < 2) return { status: 'miss', reason: 'not-found' };
|
|
81
|
+
|
|
82
|
+
let metaLine, dataLine;
|
|
83
|
+
try {
|
|
84
|
+
metaLine = JSON.parse(lines[0]);
|
|
85
|
+
dataLine = JSON.parse(lines[1]);
|
|
86
|
+
} catch {
|
|
87
|
+
return { status: 'miss', reason: 'not-found' };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const stored = metaLine._meta;
|
|
91
|
+
if (!stored) return { status: 'miss', reason: 'not-found' };
|
|
92
|
+
|
|
93
|
+
if (stored.configHash !== configHash) {
|
|
94
|
+
return { status: 'miss', reason: 'config-hash-mismatch', storedHash: stored.configHash };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const ageMs = Date.now() - new Date(stored.timestamp).getTime();
|
|
98
|
+
const ageDays = ageMs / (1000 * 60 * 60 * 24);
|
|
99
|
+
if (ageDays > ttlDays) {
|
|
100
|
+
return { status: 'miss', reason: 'stale', age: Math.floor(ageDays) };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { status: 'hit', output: dataLine.output };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* List all fixture files in a directory.
|
|
108
|
+
* @param {string} fixturesDir
|
|
109
|
+
* @returns {Promise<string[]>} - array of caseId slugs
|
|
110
|
+
*/
|
|
111
|
+
export async function listFixtures(fixturesDir) {
|
|
112
|
+
try {
|
|
113
|
+
const files = await readdir(fixturesDir);
|
|
114
|
+
return files.filter(f => f.endsWith('.jsonl')).map(f => f.slice(0, -6));
|
|
115
|
+
} catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Delete all fixture files in a directory.
|
|
122
|
+
* @param {string} fixturesDir
|
|
123
|
+
* @returns {Promise<number>} - number of files deleted
|
|
124
|
+
*/
|
|
125
|
+
export async function clearFixtures(fixturesDir) {
|
|
126
|
+
try {
|
|
127
|
+
const files = await readdir(fixturesDir);
|
|
128
|
+
const jsonlFiles = files.filter(f => f.endsWith('.jsonl'));
|
|
129
|
+
await Promise.all(jsonlFiles.map(f => unlink(join(fixturesDir, f))));
|
|
130
|
+
return jsonlFiles.length;
|
|
131
|
+
} catch {
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get statistics about fixtures in a directory.
|
|
138
|
+
* @param {string} fixturesDir
|
|
139
|
+
* @returns {Promise<{count: number, totalBytes: number, oldestDays: number, newestDays: number}>}
|
|
140
|
+
*/
|
|
141
|
+
export async function fixtureStats(fixturesDir) {
|
|
142
|
+
try {
|
|
143
|
+
const files = await readdir(fixturesDir);
|
|
144
|
+
const jsonlFiles = files.filter(f => f.endsWith('.jsonl'));
|
|
145
|
+
if (jsonlFiles.length === 0) return { count: 0, totalBytes: 0, oldestDays: 0, newestDays: 0 };
|
|
146
|
+
|
|
147
|
+
const stats = await Promise.all(jsonlFiles.map(f => stat(join(fixturesDir, f))));
|
|
148
|
+
const totalBytes = stats.reduce((sum, s) => sum + s.size, 0);
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
const ages = stats.map(s => (now - s.mtimeMs) / (1000 * 60 * 60 * 24));
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
count: jsonlFiles.length,
|
|
154
|
+
totalBytes,
|
|
155
|
+
oldestDays: Math.floor(Math.max(...ages)),
|
|
156
|
+
newestDays: Math.floor(Math.min(...ages)),
|
|
157
|
+
};
|
|
158
|
+
} catch {
|
|
159
|
+
return { count: 0, totalBytes: 0, oldestDays: 0, newestDays: 0 };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Adapted from agent-eval-kit by FlanaganSe (https://github.com/FlanaganSe/agent-eval-kit)
|
|
2
|
+
// MIT License — see LICENSE
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
writeFixture,
|
|
6
|
+
readFixture,
|
|
7
|
+
listFixtures,
|
|
8
|
+
clearFixtures,
|
|
9
|
+
fixtureStats,
|
|
10
|
+
sortKeysDeep,
|
|
11
|
+
} from './fixture-store.js';
|