@tangle-network/browser-agent-driver 0.29.0 → 0.30.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/dist/brain/index.d.ts +15 -1
- package/dist/brain/index.d.ts.map +1 -1
- package/dist/brain/index.js +67 -5
- package/dist/brain/index.js.map +1 -1
- package/dist/cli-design-audit.d.ts +4 -0
- package/dist/cli-design-audit.d.ts.map +1 -1
- package/dist/cli-design-audit.js +144 -7
- package/dist/cli-design-audit.js.map +1 -1
- package/dist/cli-ui.d.ts.map +1 -1
- package/dist/cli-ui.js +5 -1
- package/dist/cli-ui.js.map +1 -1
- package/dist/cli.js +23 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/design/audit/evaluate.d.ts +69 -0
- package/dist/design/audit/evaluate.d.ts.map +1 -1
- package/dist/design/audit/evaluate.js +414 -55
- package/dist/design/audit/evaluate.js.map +1 -1
- package/dist/design/audit/pipeline.d.ts +14 -0
- package/dist/design/audit/pipeline.d.ts.map +1 -1
- package/dist/design/audit/pipeline.js +67 -2
- package/dist/design/audit/pipeline.js.map +1 -1
- package/dist/design/audit/rubric/fragments/universal-product-intent.md +48 -0
- package/dist/design/audit/rubric/loader.d.ts.map +1 -1
- package/dist/design/audit/rubric/loader.js +32 -1
- package/dist/design/audit/rubric/loader.js.map +1 -1
- package/dist/provider-defaults.d.ts +1 -1
- package/dist/provider-defaults.d.ts.map +1 -1
- package/dist/provider-defaults.js +8 -0
- package/dist/provider-defaults.js.map +1 -1
- package/dist/supervisor/critic.d.ts +1 -1
- package/dist/supervisor/critic.d.ts.map +1 -1
- package/dist/supervisor/critic.js +50 -5
- package/dist/supervisor/critic.js.map +1 -1
- package/dist/telemetry/client.d.ts +42 -0
- package/dist/telemetry/client.d.ts.map +1 -0
- package/dist/telemetry/client.js +203 -0
- package/dist/telemetry/client.js.map +1 -0
- package/dist/telemetry/hash.d.ts +4 -0
- package/dist/telemetry/hash.d.ts.map +1 -0
- package/dist/telemetry/hash.js +7 -0
- package/dist/telemetry/hash.js.map +1 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +5 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/schema.d.ts +85 -0
- package/dist/telemetry/schema.d.ts.map +1 -0
- package/dist/telemetry/schema.js +13 -0
- package/dist/telemetry/schema.js.map +1 -0
- package/dist/telemetry/sink.d.ts +46 -0
- package/dist/telemetry/sink.d.ts.map +1 -0
- package/dist/telemetry/sink.js +97 -0
- package/dist/telemetry/sink.js.map +1 -0
- package/dist/types.d.ts +5 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry client — process-singleton gate over the sinks.
|
|
3
|
+
*
|
|
4
|
+
* Use `getTelemetry()` from anywhere in the codebase. The first call wires
|
|
5
|
+
* sinks based on env:
|
|
6
|
+
* - BAD_TELEMETRY=0|off|false disable everything
|
|
7
|
+
* - BAD_TELEMETRY_DIR=/path local file root (default ~/.bad/telemetry)
|
|
8
|
+
* - BAD_TELEMETRY_ENDPOINT=https://... optional remote POST
|
|
9
|
+
* - BAD_TELEMETRY_BEARER=... bearer token for the endpoint
|
|
10
|
+
*
|
|
11
|
+
* Why a singleton: every CLI invocation should see the same sink, and
|
|
12
|
+
* subscribers (audit pipeline, evolve loop, GEPA) may be on different code
|
|
13
|
+
* paths but share one runId. Globals are usually a smell; for cross-cutting
|
|
14
|
+
* observability they're the standard.
|
|
15
|
+
*/
|
|
16
|
+
import { execSync } from 'node:child_process';
|
|
17
|
+
import * as fs from 'node:fs';
|
|
18
|
+
import * as path from 'node:path';
|
|
19
|
+
import { randomUUID } from 'node:crypto';
|
|
20
|
+
import { FanoutTelemetrySink, FileTelemetrySink, HttpTelemetrySink, NullTelemetrySink, defaultTelemetryDir, } from './sink.js';
|
|
21
|
+
import { TELEMETRY_SCHEMA_VERSION } from './schema.js';
|
|
22
|
+
let singleton = null;
|
|
23
|
+
let cachedSource = null;
|
|
24
|
+
let cliVersion = '0.0.0';
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the parentRunId for a child envelope. Order:
|
|
27
|
+
* 1. explicit args.parentRunId
|
|
28
|
+
* 2. BAD_PARENT_RUN_ID env var (host-injected for sandbox runs)
|
|
29
|
+
*/
|
|
30
|
+
function resolveParentRunId(explicit) {
|
|
31
|
+
if (explicit)
|
|
32
|
+
return explicit;
|
|
33
|
+
const fromEnv = process.env.BAD_PARENT_RUN_ID?.trim();
|
|
34
|
+
return fromEnv || undefined;
|
|
35
|
+
}
|
|
36
|
+
export class TelemetryClient {
|
|
37
|
+
sink;
|
|
38
|
+
constructor(sink) {
|
|
39
|
+
this.sink = sink;
|
|
40
|
+
}
|
|
41
|
+
emit(args) {
|
|
42
|
+
const parentRunId = resolveParentRunId(args.parentRunId);
|
|
43
|
+
const envelope = {
|
|
44
|
+
schemaVersion: TELEMETRY_SCHEMA_VERSION,
|
|
45
|
+
envelopeId: randomUUID(),
|
|
46
|
+
runId: args.runId,
|
|
47
|
+
timestamp: new Date().toISOString(),
|
|
48
|
+
source: getSource(),
|
|
49
|
+
kind: args.kind,
|
|
50
|
+
ok: args.ok,
|
|
51
|
+
durationMs: args.durationMs,
|
|
52
|
+
data: args.data ?? {},
|
|
53
|
+
metrics: args.metrics ?? {},
|
|
54
|
+
...(parentRunId ? { parentRunId } : {}),
|
|
55
|
+
...(args.model ? { model: args.model } : {}),
|
|
56
|
+
...(args.tags ? { tags: args.tags } : {}),
|
|
57
|
+
...(args.error ? { error: args.error } : {}),
|
|
58
|
+
};
|
|
59
|
+
try {
|
|
60
|
+
this.sink.emit(envelope);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// swallow — telemetry never breaks the calling code path
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async close() {
|
|
67
|
+
await this.sink.close?.();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export function getTelemetry() {
|
|
71
|
+
if (singleton)
|
|
72
|
+
return singleton;
|
|
73
|
+
singleton = new TelemetryClient(buildSink());
|
|
74
|
+
return singleton;
|
|
75
|
+
}
|
|
76
|
+
/** Override for tests + benches that want their own sink. */
|
|
77
|
+
export function setTelemetryClient(client) {
|
|
78
|
+
singleton = client;
|
|
79
|
+
}
|
|
80
|
+
export function resetTelemetryClient() {
|
|
81
|
+
singleton = null;
|
|
82
|
+
cachedSource = null;
|
|
83
|
+
}
|
|
84
|
+
export function setCliVersion(v) {
|
|
85
|
+
cliVersion = v;
|
|
86
|
+
}
|
|
87
|
+
function buildSink() {
|
|
88
|
+
const flag = (process.env.BAD_TELEMETRY ?? '').toLowerCase();
|
|
89
|
+
if (flag === '0' || flag === 'off' || flag === 'false' || flag === 'no') {
|
|
90
|
+
return new NullTelemetrySink();
|
|
91
|
+
}
|
|
92
|
+
const sinks = [];
|
|
93
|
+
try {
|
|
94
|
+
sinks.push(new FileTelemetrySink(defaultTelemetryDir()));
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// dir not writable — fall through to null
|
|
98
|
+
}
|
|
99
|
+
const endpoint = process.env.BAD_TELEMETRY_ENDPOINT?.trim();
|
|
100
|
+
if (endpoint) {
|
|
101
|
+
sinks.push(new HttpTelemetrySink(endpoint, process.env.BAD_TELEMETRY_BEARER?.trim()));
|
|
102
|
+
}
|
|
103
|
+
if (sinks.length === 0)
|
|
104
|
+
return new NullTelemetrySink();
|
|
105
|
+
return new FanoutTelemetrySink(sinks);
|
|
106
|
+
}
|
|
107
|
+
function getSource() {
|
|
108
|
+
if (cachedSource) {
|
|
109
|
+
return { ...cachedSource, invocation: cachedSource.invocation };
|
|
110
|
+
}
|
|
111
|
+
const cwd = process.cwd();
|
|
112
|
+
// BAD_SOURCE_REPO override takes precedence — useful inside sandbox/container
|
|
113
|
+
// runs where cwd is something like /workspace and `git remote -v` is meaningless.
|
|
114
|
+
const repo = process.env.BAD_SOURCE_REPO?.trim() || inferRepoName(cwd);
|
|
115
|
+
// Skip the two child_process calls when the host already told us what we are.
|
|
116
|
+
const { gitSha, gitBranch } = process.env.BAD_SOURCE_REPO ? {} : inferGit(cwd);
|
|
117
|
+
const tenantId = process.env.BAD_TENANT_ID?.trim();
|
|
118
|
+
const customerId = process.env.BAD_CUSTOMER_ID?.trim();
|
|
119
|
+
const apiKeyHash = process.env.BAD_API_KEY_HASH?.trim();
|
|
120
|
+
cachedSource = {
|
|
121
|
+
repo,
|
|
122
|
+
cwd,
|
|
123
|
+
cliVersion,
|
|
124
|
+
invocation: process.env.BAD_INVOCATION || 'unknown',
|
|
125
|
+
...(gitSha ? { gitSha } : {}),
|
|
126
|
+
...(gitBranch ? { gitBranch } : {}),
|
|
127
|
+
...(tenantId ? { tenantId } : {}),
|
|
128
|
+
...(customerId ? { customerId } : {}),
|
|
129
|
+
...(apiKeyHash ? { apiKeyHash } : {}),
|
|
130
|
+
};
|
|
131
|
+
return cachedSource;
|
|
132
|
+
}
|
|
133
|
+
export function setInvocation(label, argv) {
|
|
134
|
+
// Allow the CLI to label each run accurately once it knows what it's doing.
|
|
135
|
+
if (!cachedSource)
|
|
136
|
+
getSource();
|
|
137
|
+
if (cachedSource) {
|
|
138
|
+
cachedSource.invocation = label;
|
|
139
|
+
if (argv)
|
|
140
|
+
cachedSource.argv = sanitiseArgv(argv);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function inferRepoName(cwd) {
|
|
144
|
+
// Prefer git remote basename → falls back to package.json `name` → cwd basename.
|
|
145
|
+
try {
|
|
146
|
+
const url = execSync('git config --get remote.origin.url', { cwd, stdio: ['ignore', 'pipe', 'ignore'] })
|
|
147
|
+
.toString()
|
|
148
|
+
.trim();
|
|
149
|
+
if (url) {
|
|
150
|
+
const m = url.match(/([^/:]+?)(?:\.git)?$/);
|
|
151
|
+
if (m?.[1])
|
|
152
|
+
return m[1];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
/* not a git repo */
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
160
|
+
if (fs.existsSync(pkgPath)) {
|
|
161
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
162
|
+
if (pkg.name)
|
|
163
|
+
return pkg.name.replace(/^@[^/]+\//, '');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* no package.json or unreadable */
|
|
168
|
+
}
|
|
169
|
+
return path.basename(cwd) || 'unknown';
|
|
170
|
+
}
|
|
171
|
+
function inferGit(cwd) {
|
|
172
|
+
try {
|
|
173
|
+
const sha = execSync('git rev-parse HEAD', { cwd, stdio: ['ignore', 'pipe', 'ignore'] })
|
|
174
|
+
.toString()
|
|
175
|
+
.trim();
|
|
176
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', { cwd, stdio: ['ignore', 'pipe', 'ignore'] })
|
|
177
|
+
.toString()
|
|
178
|
+
.trim();
|
|
179
|
+
return { gitSha: sha || undefined, gitBranch: branch || undefined };
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return {};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const SECRET_FLAGS = new Set(['--api-key', '--bearer', '--token', '--password']);
|
|
186
|
+
function sanitiseArgv(argv) {
|
|
187
|
+
const out = [];
|
|
188
|
+
for (let i = 0; i < argv.length; i++) {
|
|
189
|
+
const a = argv[i];
|
|
190
|
+
if (SECRET_FLAGS.has(a)) {
|
|
191
|
+
out.push(a, '<redacted>');
|
|
192
|
+
i++;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (/^(?:--api-key|--bearer|--token|--password)=/.test(a)) {
|
|
196
|
+
out.push(a.replace(/=.*$/, '=<redacted>'));
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
out.push(a);
|
|
200
|
+
}
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/telemetry/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/telemetry/hash.ts"],"names":[],"mappings":"AAEA;+EAC+E;AAC/E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/** 12-hex-char SHA-256 prefix — collision-resistant enough for prompt/rubric
|
|
3
|
+
* identity without being noisy. Mirrors agent-eval's PromptRegistry style. */
|
|
4
|
+
export function shortHash(input) {
|
|
5
|
+
return createHash('sha256').update(input).digest('hex').slice(0, 12);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/telemetry/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC;+EAC+E;AAC/E,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AACtE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { TELEMETRY_SCHEMA_VERSION } from './schema.js';
|
|
2
|
+
export type { TelemetryEnvelope, TelemetryKind, TelemetrySource, TelemetryModel, } from './schema.js';
|
|
3
|
+
export { shortHash } from './hash.js';
|
|
4
|
+
export { TelemetryClient, getTelemetry, setTelemetryClient, resetTelemetryClient, setCliVersion, setInvocation, type EmitArgs, } from './client.js';
|
|
5
|
+
export { type TelemetrySink, FileTelemetrySink, HttpTelemetrySink, FanoutTelemetrySink, NullTelemetrySink, defaultTelemetryDir, } from './sink.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AACtD,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EACL,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,KAAK,QAAQ,GACd,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,aAAa,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { TELEMETRY_SCHEMA_VERSION } from './schema.js';
|
|
2
|
+
export { shortHash } from './hash.js';
|
|
3
|
+
export { TelemetryClient, getTelemetry, setTelemetryClient, resetTelemetryClient, setCliVersion, setInvocation, } from './client.js';
|
|
4
|
+
export { FileTelemetrySink, HttpTelemetrySink, FanoutTelemetrySink, NullTelemetrySink, defaultTelemetryDir, } from './sink.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAOtD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EACL,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,aAAa,GAEd,MAAM,aAAa,CAAA;AACpB,OAAO,EAEL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet telemetry envelope.
|
|
3
|
+
*
|
|
4
|
+
* One envelope per meaningful unit of work — a page audit, an evolve round, a
|
|
5
|
+
* full bad run. Envelopes are append-only and JSONL-friendly. Schema is
|
|
6
|
+
* deliberately a superset of agent-eval's Run/Span trace shape so a future
|
|
7
|
+
* rollup script can promote these into agent-eval traces without translation.
|
|
8
|
+
*
|
|
9
|
+
* Versioning: bump `schemaVersion` only when readers must change. Adding
|
|
10
|
+
* optional fields is backwards-compatible and does not require a bump.
|
|
11
|
+
*/
|
|
12
|
+
export declare const TELEMETRY_SCHEMA_VERSION = 1;
|
|
13
|
+
/** Discriminator for the high-level invocation that produced this envelope. */
|
|
14
|
+
export type TelemetryKind = 'design-audit-page' | 'design-audit-run' | 'design-evolve-round' | 'design-evolve-run' | 'agent-run' | 'gepa-trial' | 'gepa-generation';
|
|
15
|
+
export interface TelemetryEnvelope {
|
|
16
|
+
schemaVersion: typeof TELEMETRY_SCHEMA_VERSION;
|
|
17
|
+
/** Unique id for this envelope. */
|
|
18
|
+
envelopeId: string;
|
|
19
|
+
/** Groups envelopes from a single CLI invocation. */
|
|
20
|
+
runId: string;
|
|
21
|
+
/** When this envelope was finalised. */
|
|
22
|
+
timestamp: string;
|
|
23
|
+
/** Optional: link a child envelope (e.g. one page) to a parent run envelope. */
|
|
24
|
+
parentRunId?: string;
|
|
25
|
+
source: TelemetrySource;
|
|
26
|
+
model?: TelemetryModel;
|
|
27
|
+
kind: TelemetryKind;
|
|
28
|
+
ok: boolean;
|
|
29
|
+
durationMs: number;
|
|
30
|
+
/**
|
|
31
|
+
* Kind-specific payload. Stays loose on purpose — readers query by `kind` and
|
|
32
|
+
* key into `data`. Keep shapes flat and JSON-serialisable; large blobs
|
|
33
|
+
* (screenshots, full snapshots) belong on disk in the run's sink, not here.
|
|
34
|
+
*/
|
|
35
|
+
data: Record<string, unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* Numeric metrics suitable for aggregation: scores, counts, durations, costs.
|
|
38
|
+
* Kept separate from `data` so a rollup can sum/avg without schema awareness.
|
|
39
|
+
*/
|
|
40
|
+
metrics: Record<string, number>;
|
|
41
|
+
/** Free-form labels for filtering during rollup. */
|
|
42
|
+
tags?: Record<string, string>;
|
|
43
|
+
/** Populated only when `ok === false`. */
|
|
44
|
+
error?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface TelemetrySource {
|
|
47
|
+
/** Repo identity — basename of cwd plus git remote if discoverable. */
|
|
48
|
+
repo: string;
|
|
49
|
+
cwd: string;
|
|
50
|
+
gitSha?: string;
|
|
51
|
+
gitBranch?: string;
|
|
52
|
+
cliVersion: string;
|
|
53
|
+
/** What was invoked, e.g. `design-audit`, `design-audit --evolve`, `run`. */
|
|
54
|
+
invocation: string;
|
|
55
|
+
/** Sanitised argv minus secrets. */
|
|
56
|
+
argv?: string[];
|
|
57
|
+
/**
|
|
58
|
+
* Multi-tenant identity. Set when the CLI runs inside a hosted product
|
|
59
|
+
* (bad-app, agent-platform) so a fleet rollup can group by tenant without
|
|
60
|
+
* leaking customer URLs or PII. The host populates this via
|
|
61
|
+
* `BAD_TENANT_ID` env var when it spawns the sandbox.
|
|
62
|
+
*/
|
|
63
|
+
tenantId?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Optional sub-tenant identity (project, suite, walkthrough, customer).
|
|
66
|
+
* Convention: opaque string the host can map back to its own entities.
|
|
67
|
+
*/
|
|
68
|
+
customerId?: string;
|
|
69
|
+
/**
|
|
70
|
+
* SHA-256 (12 hex) of the API key used to authenticate this run, when the
|
|
71
|
+
* host supplies one. Lets a rollup attribute usage to a key without
|
|
72
|
+
* holding the key itself. Set via `BAD_API_KEY_HASH` env var.
|
|
73
|
+
*/
|
|
74
|
+
apiKeyHash?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface TelemetryModel {
|
|
77
|
+
provider: string;
|
|
78
|
+
name: string;
|
|
79
|
+
/** SHA-256 (12 hex chars) of the prompt(s) used. Lets a rollup correlate
|
|
80
|
+
* outcome shifts to specific prompt versions. */
|
|
81
|
+
promptHash?: string;
|
|
82
|
+
/** SHA-256 (12 hex chars) of the composed rubric body if applicable. */
|
|
83
|
+
rubricHash?: string;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/telemetry/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC,+EAA+E;AAC/E,MAAM,MAAM,aAAa,GACrB,mBAAmB,GACnB,kBAAkB,GAClB,qBAAqB,GACrB,mBAAmB,GACnB,WAAW,GACX,YAAY,GACZ,iBAAiB,CAAA;AAErB,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,OAAO,wBAAwB,CAAA;IAC9C,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,MAAM,EAAE,eAAe,CAAA;IACvB,KAAK,CAAC,EAAE,cAAc,CAAA;IACtB,IAAI,EAAE,aAAa,CAAA;IACnB,EAAE,EAAE,OAAO,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAElB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE7B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE/B,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE7B,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAA;IAClB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ;sDACkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet telemetry envelope.
|
|
3
|
+
*
|
|
4
|
+
* One envelope per meaningful unit of work — a page audit, an evolve round, a
|
|
5
|
+
* full bad run. Envelopes are append-only and JSONL-friendly. Schema is
|
|
6
|
+
* deliberately a superset of agent-eval's Run/Span trace shape so a future
|
|
7
|
+
* rollup script can promote these into agent-eval traces without translation.
|
|
8
|
+
*
|
|
9
|
+
* Versioning: bump `schemaVersion` only when readers must change. Adding
|
|
10
|
+
* optional fields is backwards-compatible and does not require a bump.
|
|
11
|
+
*/
|
|
12
|
+
export const TELEMETRY_SCHEMA_VERSION = 1;
|
|
13
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/telemetry/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry sinks — destinations for envelopes.
|
|
3
|
+
*
|
|
4
|
+
* The default policy emits to two sinks:
|
|
5
|
+
* 1. Local file at `${BAD_TELEMETRY_DIR ?? ~/.bad/telemetry}/<repo>/<date>.jsonl`
|
|
6
|
+
* — always on, cheap, survives across machines via dotfiles/sync.
|
|
7
|
+
* 2. HTTP POST to `BAD_TELEMETRY_ENDPOINT` if set — for fleet rollups.
|
|
8
|
+
*
|
|
9
|
+
* Both sinks are best-effort: a failure here MUST NOT break the calling
|
|
10
|
+
* invocation. Telemetry is observability, not a feature.
|
|
11
|
+
*/
|
|
12
|
+
import type { TelemetryEnvelope } from './schema.js';
|
|
13
|
+
export interface TelemetrySink {
|
|
14
|
+
emit(envelope: TelemetryEnvelope): Promise<void> | void;
|
|
15
|
+
close?(): Promise<void> | void;
|
|
16
|
+
}
|
|
17
|
+
/** Append envelopes to a JSONL file rolling by date and repo. */
|
|
18
|
+
export declare class FileTelemetrySink implements TelemetrySink {
|
|
19
|
+
private readonly baseDir;
|
|
20
|
+
private streams;
|
|
21
|
+
constructor(baseDir: string);
|
|
22
|
+
emit(envelope: TelemetryEnvelope): void;
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/** Best-effort POST to a remote collector. Batches small payloads via fetch. */
|
|
26
|
+
export declare class HttpTelemetrySink implements TelemetrySink {
|
|
27
|
+
private readonly endpoint;
|
|
28
|
+
private readonly bearer?;
|
|
29
|
+
private inflight;
|
|
30
|
+
constructor(endpoint: string, bearer?: string | undefined);
|
|
31
|
+
emit(envelope: TelemetryEnvelope): void;
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
/** Fanout to multiple sinks — failures in one do not affect others. */
|
|
35
|
+
export declare class FanoutTelemetrySink implements TelemetrySink {
|
|
36
|
+
private readonly sinks;
|
|
37
|
+
constructor(sinks: TelemetrySink[]);
|
|
38
|
+
emit(envelope: TelemetryEnvelope): void;
|
|
39
|
+
close(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
/** No-op sink — used when telemetry is explicitly disabled. */
|
|
42
|
+
export declare class NullTelemetrySink implements TelemetrySink {
|
|
43
|
+
emit(): void;
|
|
44
|
+
}
|
|
45
|
+
export declare function defaultTelemetryDir(): string;
|
|
46
|
+
//# sourceMappingURL=sink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../../src/telemetry/sink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACvD,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAC/B;AAED,iEAAiE;AACjE,qBAAa,iBAAkB,YAAW,aAAa;IAGzC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,OAAO,CAAoC;gBAEtB,OAAO,EAAE,MAAM;IAI5C,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAcjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B;AAED,gFAAgF;AAChF,qBAAa,iBAAkB,YAAW,aAAa;IAInD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAJ1B,OAAO,CAAC,QAAQ,CAA2B;gBAGxB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,YAAA;IAGlC,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAWjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAED,uEAAuE;AACvE,qBAAa,mBAAoB,YAAW,aAAa;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,aAAa,EAAE;IAEnD,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAajC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAED,+DAA+D;AAC/D,qBAAa,iBAAkB,YAAW,aAAa;IACrD,IAAI,IAAI,IAAI;CACb;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry sinks — destinations for envelopes.
|
|
3
|
+
*
|
|
4
|
+
* The default policy emits to two sinks:
|
|
5
|
+
* 1. Local file at `${BAD_TELEMETRY_DIR ?? ~/.bad/telemetry}/<repo>/<date>.jsonl`
|
|
6
|
+
* — always on, cheap, survives across machines via dotfiles/sync.
|
|
7
|
+
* 2. HTTP POST to `BAD_TELEMETRY_ENDPOINT` if set — for fleet rollups.
|
|
8
|
+
*
|
|
9
|
+
* Both sinks are best-effort: a failure here MUST NOT break the calling
|
|
10
|
+
* invocation. Telemetry is observability, not a feature.
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as os from 'node:os';
|
|
14
|
+
import * as path from 'node:path';
|
|
15
|
+
/** Append envelopes to a JSONL file rolling by date and repo. */
|
|
16
|
+
export class FileTelemetrySink {
|
|
17
|
+
baseDir;
|
|
18
|
+
streams = new Map();
|
|
19
|
+
constructor(baseDir) {
|
|
20
|
+
this.baseDir = baseDir;
|
|
21
|
+
fs.mkdirSync(baseDir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
emit(envelope) {
|
|
24
|
+
const date = envelope.timestamp.slice(0, 10); // YYYY-MM-DD
|
|
25
|
+
const repo = envelope.source.repo || 'unknown';
|
|
26
|
+
const key = `${repo}/${date}`;
|
|
27
|
+
let stream = this.streams.get(key);
|
|
28
|
+
if (!stream) {
|
|
29
|
+
const dir = path.join(this.baseDir, repo);
|
|
30
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
31
|
+
stream = fs.createWriteStream(path.join(dir, `${date}.jsonl`), { flags: 'a', encoding: 'utf-8' });
|
|
32
|
+
this.streams.set(key, stream);
|
|
33
|
+
}
|
|
34
|
+
stream.write(`${JSON.stringify(envelope)}\n`);
|
|
35
|
+
}
|
|
36
|
+
async close() {
|
|
37
|
+
const closes = Array.from(this.streams.values()).map((s) => new Promise((resolve) => s.end(() => resolve())));
|
|
38
|
+
this.streams.clear();
|
|
39
|
+
await Promise.all(closes);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Best-effort POST to a remote collector. Batches small payloads via fetch. */
|
|
43
|
+
export class HttpTelemetrySink {
|
|
44
|
+
endpoint;
|
|
45
|
+
bearer;
|
|
46
|
+
inflight = new Set();
|
|
47
|
+
constructor(endpoint, bearer) {
|
|
48
|
+
this.endpoint = endpoint;
|
|
49
|
+
this.bearer = bearer;
|
|
50
|
+
}
|
|
51
|
+
emit(envelope) {
|
|
52
|
+
const body = JSON.stringify(envelope);
|
|
53
|
+
const headers = { 'content-type': 'application/json' };
|
|
54
|
+
if (this.bearer)
|
|
55
|
+
headers.authorization = `Bearer ${this.bearer}`;
|
|
56
|
+
const promise = fetch(this.endpoint, { method: 'POST', headers, body })
|
|
57
|
+
.then(() => undefined)
|
|
58
|
+
.catch(() => undefined);
|
|
59
|
+
this.inflight.add(promise);
|
|
60
|
+
promise.finally(() => this.inflight.delete(promise));
|
|
61
|
+
}
|
|
62
|
+
async close() {
|
|
63
|
+
await Promise.allSettled(Array.from(this.inflight));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Fanout to multiple sinks — failures in one do not affect others. */
|
|
67
|
+
export class FanoutTelemetrySink {
|
|
68
|
+
sinks;
|
|
69
|
+
constructor(sinks) {
|
|
70
|
+
this.sinks = sinks;
|
|
71
|
+
}
|
|
72
|
+
emit(envelope) {
|
|
73
|
+
for (const sink of this.sinks) {
|
|
74
|
+
try {
|
|
75
|
+
const result = sink.emit(envelope);
|
|
76
|
+
if (result && typeof result.catch === 'function') {
|
|
77
|
+
;
|
|
78
|
+
result.catch(() => undefined);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// swallow — telemetry must never break a run
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async close() {
|
|
87
|
+
await Promise.allSettled(this.sinks.map((s) => Promise.resolve(s.close?.())));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** No-op sink — used when telemetry is explicitly disabled. */
|
|
91
|
+
export class NullTelemetrySink {
|
|
92
|
+
emit() { }
|
|
93
|
+
}
|
|
94
|
+
export function defaultTelemetryDir() {
|
|
95
|
+
return process.env.BAD_TELEMETRY_DIR || path.join(os.homedir(), '.bad', 'telemetry');
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=sink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink.js","sourceRoot":"","sources":["../../src/telemetry/sink.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -324,8 +324,8 @@ export interface Scenario {
|
|
|
324
324
|
parentRunId?: string;
|
|
325
325
|
}
|
|
326
326
|
export interface AgentConfig {
|
|
327
|
-
/** LLM provider: 'openai' (default), 'anthropic', 'google', 'codex-cli', 'claude-code',
|
|
328
|
-
provider?: 'openai' | 'anthropic' | 'google' | 'codex-cli' | 'claude-code' | 'sandbox-backend';
|
|
327
|
+
/** LLM provider: 'openai' (default), 'anthropic', 'google', 'cli-bridge', 'codex-cli', 'claude-code', 'sandbox-backend', or 'zai-coding-plan' */
|
|
328
|
+
provider?: 'openai' | 'anthropic' | 'google' | 'cli-bridge' | 'codex-cli' | 'claude-code' | 'sandbox-backend' | 'zai-coding-plan';
|
|
329
329
|
/** LLM model (default: gpt-5.4) */
|
|
330
330
|
model?: string;
|
|
331
331
|
/** Enable adaptive model routing for decide() (default: false) */
|
|
@@ -333,7 +333,7 @@ export interface AgentConfig {
|
|
|
333
333
|
/** Fast navigation model used when adaptive routing is enabled */
|
|
334
334
|
navModel?: string;
|
|
335
335
|
/** Provider for navModel (defaults to provider) */
|
|
336
|
-
navProvider?: 'openai' | 'anthropic' | 'google' | 'codex-cli' | 'claude-code' | 'sandbox-backend';
|
|
336
|
+
navProvider?: 'openai' | 'anthropic' | 'google' | 'cli-bridge' | 'codex-cli' | 'claude-code' | 'sandbox-backend' | 'zai-coding-plan';
|
|
337
337
|
/** Gen 28: per-role model overrides. Each role falls back to the main model/provider. */
|
|
338
338
|
models?: {
|
|
339
339
|
/** Planner — needs best reasoning. Default: main model. */
|
|
@@ -468,7 +468,7 @@ export interface ScoutConfig {
|
|
|
468
468
|
/** Optional model override for scout reasoning */
|
|
469
469
|
model?: string;
|
|
470
470
|
/** Optional provider override for scout model */
|
|
471
|
-
provider?: 'openai' | 'anthropic' | 'google' | 'codex-cli' | 'claude-code' | 'sandbox-backend';
|
|
471
|
+
provider?: 'openai' | 'anthropic' | 'google' | 'cli-bridge' | 'codex-cli' | 'claude-code' | 'sandbox-backend' | 'zai-coding-plan';
|
|
472
472
|
/** Allow the scout to inspect the current screenshot when available */
|
|
473
473
|
useVision?: boolean;
|
|
474
474
|
/** Max ranked candidates sent to the scout */
|
|
@@ -486,7 +486,7 @@ export interface SupervisorConfig {
|
|
|
486
486
|
/** Optional model override for supervisor reasoning */
|
|
487
487
|
model?: string;
|
|
488
488
|
/** Optional provider override for supervisor model */
|
|
489
|
-
provider?: 'openai' | 'anthropic' | 'google' | 'codex-cli' | 'claude-code' | 'sandbox-backend';
|
|
489
|
+
provider?: 'openai' | 'anthropic' | 'google' | 'cli-bridge' | 'codex-cli' | 'claude-code' | 'sandbox-backend' | 'zai-coding-plan';
|
|
490
490
|
/** Allow the supervisor to inspect the current screenshot when available */
|
|
491
491
|
useVision?: boolean;
|
|
492
492
|
/** Minimum completed turns before supervisor can intervene */
|