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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +209 -0
  3. package/lib/agent-registry.js +170 -0
  4. package/lib/api-client.js +792 -0
  5. package/lib/api-loader.js +260 -0
  6. package/lib/auth.d.ts +25 -0
  7. package/lib/auth.js +158 -0
  8. package/lib/checks/check-adapter.js +172 -0
  9. package/lib/checks/compose.js +42 -0
  10. package/lib/checks/content-match.js +14 -0
  11. package/lib/checks/cost-budget.js +11 -0
  12. package/lib/checks/index.js +18 -0
  13. package/lib/checks/json-valid.js +15 -0
  14. package/lib/checks/latency.js +11 -0
  15. package/lib/checks/length-bounds.js +17 -0
  16. package/lib/checks/negative-match.js +14 -0
  17. package/lib/checks/no-hallucinated-numbers.js +63 -0
  18. package/lib/checks/non-empty.js +34 -0
  19. package/lib/checks/regex-match.js +12 -0
  20. package/lib/checks/run-checks.js +84 -0
  21. package/lib/checks/schema-match.js +26 -0
  22. package/lib/checks/tool-call-count.js +16 -0
  23. package/lib/checks/tool-selection.js +34 -0
  24. package/lib/checks/types.js +45 -0
  25. package/lib/comparison/compare.js +86 -0
  26. package/lib/comparison/format.js +104 -0
  27. package/lib/comparison/index.js +6 -0
  28. package/lib/comparison/statistics.js +59 -0
  29. package/lib/comparison/types.js +41 -0
  30. package/lib/config-schema.js +200 -0
  31. package/lib/config.d.ts +66 -0
  32. package/lib/conversation-store.d.ts +77 -0
  33. package/lib/conversation-store.js +443 -0
  34. package/lib/db.d.ts +6 -0
  35. package/lib/db.js +1112 -0
  36. package/lib/dep-check.js +99 -0
  37. package/lib/drift-background.js +61 -0
  38. package/lib/drift-monitor.js +187 -0
  39. package/lib/eval-runner.js +566 -0
  40. package/lib/fixtures/fixture-store.js +161 -0
  41. package/lib/fixtures/index.js +11 -0
  42. package/lib/forge-engine.js +982 -0
  43. package/lib/forge-eval-generator.js +417 -0
  44. package/lib/forge-file-writer.js +386 -0
  45. package/lib/forge-service-client.js +190 -0
  46. package/lib/forge-service.d.ts +4 -0
  47. package/lib/forge-service.js +655 -0
  48. package/lib/forge-verifier-generator.js +271 -0
  49. package/lib/handlers/admin.js +151 -0
  50. package/lib/handlers/agents.js +229 -0
  51. package/lib/handlers/chat-resume.js +334 -0
  52. package/lib/handlers/chat-sync.js +320 -0
  53. package/lib/handlers/chat.js +320 -0
  54. package/lib/handlers/conversations.js +92 -0
  55. package/lib/handlers/preferences.js +88 -0
  56. package/lib/handlers/tools-list.js +58 -0
  57. package/lib/hitl-engine.d.ts +60 -0
  58. package/lib/hitl-engine.js +261 -0
  59. package/lib/http-utils.js +92 -0
  60. package/lib/index.d.ts +20 -0
  61. package/lib/index.js +141 -0
  62. package/lib/init.js +636 -0
  63. package/lib/manual-entry.js +59 -0
  64. package/lib/mcp-server.js +252 -0
  65. package/lib/output-groups.js +54 -0
  66. package/lib/postgres-store.d.ts +31 -0
  67. package/lib/postgres-store.js +465 -0
  68. package/lib/preference-store.d.ts +47 -0
  69. package/lib/preference-store.js +79 -0
  70. package/lib/prompt-store.d.ts +42 -0
  71. package/lib/prompt-store.js +60 -0
  72. package/lib/rate-limiter.d.ts +30 -0
  73. package/lib/rate-limiter.js +104 -0
  74. package/lib/react-engine.d.ts +110 -0
  75. package/lib/react-engine.js +337 -0
  76. package/lib/runner/cli.js +156 -0
  77. package/lib/runner/cost-estimator.js +71 -0
  78. package/lib/runner/gate.js +46 -0
  79. package/lib/runner/index.js +165 -0
  80. package/lib/sidecar.d.ts +83 -0
  81. package/lib/sidecar.js +161 -0
  82. package/lib/sse.d.ts +15 -0
  83. package/lib/sse.js +30 -0
  84. package/lib/tools-scanner.js +91 -0
  85. package/lib/tui.js +253 -0
  86. package/lib/verifier-report.js +78 -0
  87. package/lib/verifier-runner.js +338 -0
  88. package/lib/verifier-scanner.js +70 -0
  89. package/lib/verifier-worker-pool.js +196 -0
  90. package/lib/views/chat.js +340 -0
  91. package/lib/views/endpoints.js +203 -0
  92. package/lib/views/eval-run.js +206 -0
  93. package/lib/views/forge-agent.js +538 -0
  94. package/lib/views/forge.js +410 -0
  95. package/lib/views/main-menu.js +275 -0
  96. package/lib/views/mediation.js +381 -0
  97. package/lib/views/model-compare.js +430 -0
  98. package/lib/views/model-comparison.js +333 -0
  99. package/lib/views/onboarding.js +470 -0
  100. package/lib/views/performance.js +237 -0
  101. package/lib/views/run-evals.js +205 -0
  102. package/lib/views/settings.js +829 -0
  103. package/lib/views/tools-evals.js +514 -0
  104. package/lib/views/verifier-coverage.js +617 -0
  105. package/lib/workers/verifier-worker.js +52 -0
  106. package/package.json +123 -0
  107. 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';