@openbkn/bkn-sdk 0.1.1 → 0.1.2

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.
@@ -26,38 +26,38 @@ var InputError = class extends Error {
26
26
  this.name = "InputError";
27
27
  }
28
28
  };
29
- function toExitCode(err) {
30
- if (err instanceof InputError) return 2;
31
- if (err instanceof HttpError) {
32
- if (err.status === 401 || err.status === 403) return 3;
29
+ function toExitCode(err2) {
30
+ if (err2 instanceof InputError) return 2;
31
+ if (err2 instanceof HttpError) {
32
+ if (err2.status === 401 || err2.status === 403) return 3;
33
33
  return 1;
34
34
  }
35
35
  return 1;
36
36
  }
37
- function formatError(err) {
38
- if (err instanceof HttpError) {
39
- const serverMsg = serverError(err.body);
40
- if (err.status === 401) {
41
- const next = err.hint ?? "Run `openbkn auth login` and retry.";
37
+ function formatError(err2) {
38
+ if (err2 instanceof HttpError) {
39
+ const serverMsg = serverError(err2.body);
40
+ if (err2.status === 401) {
41
+ const next = err2.hint ?? "Run `openbkn auth login` and retry.";
42
42
  return `Not authorized (HTTP 401)${serverMsg ? `: ${serverMsg}` : ""}. ${next}`;
43
43
  }
44
- if (err.status === 403) {
44
+ if (err2.status === 403) {
45
45
  return `Forbidden (HTTP 403)${serverMsg ? `: ${serverMsg}` : " \u2014 admin privileges required"}.`;
46
46
  }
47
- const detail = err.body ? `: ${truncate(err.body, 500)}` : "";
48
- return `Request failed (HTTP ${err.status} ${err.statusText})${detail}`;
47
+ const detail = err2.body ? `: ${truncate(err2.body, 500)}` : "";
48
+ return `Request failed (HTTP ${err2.status} ${err2.statusText})${detail}`;
49
49
  }
50
- if (err instanceof Error) {
51
- const cause = err.cause;
50
+ if (err2 instanceof Error) {
51
+ const cause = err2.cause;
52
52
  if (cause?.code && isTlsCertError(cause.code)) {
53
53
  return `TLS certificate rejected (${cause.code}). The platform is likely self-signed \u2014 retry with \`-k\`/\`--insecure\`.`;
54
54
  }
55
- if (err.message === "fetch failed" && cause?.message) {
55
+ if (err2.message === "fetch failed" && cause?.message) {
56
56
  return `Request failed: ${cause.message}${cause.code ? ` (${cause.code})` : ""}`;
57
57
  }
58
- return err.message;
58
+ return err2.message;
59
59
  }
60
- return String(err);
60
+ return String(err2);
61
61
  }
62
62
  function serverError(body) {
63
63
  if (!body) return "";
@@ -80,16 +80,29 @@ function truncate(s, n) {
80
80
  import { spawn } from "child_process";
81
81
 
82
82
  // src/api/tls.ts
83
- import { Agent, fetch as undiciFetch } from "undici";
83
+ import { Agent, FormData as UndiciFormData, fetch as undiciFetch } from "undici";
84
84
  var insecureAgent;
85
85
  function insecureDispatcher() {
86
86
  insecureAgent ??= new Agent({ connect: { rejectUnauthorized: false } });
87
87
  return insecureAgent;
88
88
  }
89
+ function isFormData(body) {
90
+ return typeof body === "object" && body !== null && body[Symbol.toStringTag] === "FormData";
91
+ }
92
+ function toUndiciBody(body) {
93
+ if (body instanceof UndiciFormData || !isFormData(body)) return body;
94
+ const form2 = new UndiciFormData();
95
+ for (const [name, value] of body.entries()) {
96
+ if (typeof value === "string") form2.append(name, value);
97
+ else form2.append(name, value, value.name);
98
+ }
99
+ return form2;
100
+ }
89
101
  function tlsFetch(insecure, url, init) {
90
102
  if (!insecure) return fetch(url, init);
91
103
  return undiciFetch(url, {
92
104
  ...init,
105
+ ...init?.body === void 0 || init?.body === null ? {} : { body: toUndiciBody(init.body) },
93
106
  dispatcher: insecureDispatcher()
94
107
  });
95
108
  }
@@ -305,11 +318,96 @@ async function credentialDeviceLogin(baseUrl, username, password, opts = {}) {
305
318
  );
306
319
  }
307
320
 
321
+ // src/trace-context.ts
322
+ import { randomBytes, randomUUID } from "crypto";
323
+ var TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
324
+ var REQUEST_ID_RE = /^req_[0-9A-Za-z_.-]+$/;
325
+ var CORRELATION_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
326
+ var RFC3339_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
327
+ var ALLOWED_BAGGAGE = /* @__PURE__ */ new Set(["bkn.account.type", "bkn.runtime.env"]);
328
+ function isValidRequestId(value) {
329
+ return typeof value === "string" && REQUEST_ID_RE.test(value);
330
+ }
331
+ function isValidCorrelationId(value) {
332
+ return typeof value === "string" && CORRELATION_ID_RE.test(value.trim());
333
+ }
334
+ function isValidTraceparent(value) {
335
+ if (typeof value !== "string") return false;
336
+ const match = TRACEPARENT_RE.exec(value);
337
+ if (!match) return false;
338
+ const [, traceId, spanId] = match;
339
+ return traceId !== "0".repeat(32) && spanId !== "0".repeat(16);
340
+ }
341
+ function createTraceContext(opts = {}) {
342
+ const requestId = isValidRequestId(opts.requestId) ? opts.requestId : `req_${randomUUID()}`;
343
+ const traceparent = isValidTraceparent(opts.traceparent) ? opts.traceparent : newTraceparent();
344
+ const baggage = filterBaggage(opts.baggage);
345
+ const conversationId = isValidCorrelationId(opts.conversationId) ? opts.conversationId.trim() : void 0;
346
+ const interactionId = isValidCorrelationId(opts.interactionId) ? opts.interactionId.trim() : void 0;
347
+ const operationId = isValidCorrelationId(opts.operationId) ? opts.operationId.trim() : void 0;
348
+ const attempt = Number.isInteger(opts.attempt) && (opts.attempt ?? 0) >= 1 && (opts.attempt ?? 0) <= 1e3 ? opts.attempt : void 0;
349
+ const observedAt = isValidObservedAt(opts.observedAt) ? opts.observedAt : void 0;
350
+ return {
351
+ requestId,
352
+ traceparent,
353
+ ...conversationId ? { conversationId } : {},
354
+ ...interactionId ? { interactionId } : {},
355
+ ...operationId ? { operationId } : {},
356
+ ...attempt ? { attempt } : {},
357
+ ...observedAt ? { observedAt } : {},
358
+ ...Object.keys(baggage).length > 0 ? { baggage } : {}
359
+ };
360
+ }
361
+ function createOperationTraceContext(trace2) {
362
+ return {
363
+ ...trace2,
364
+ operationId: trace2.operationId ?? `op_${randomUUID()}`,
365
+ attempt: trace2.attempt ?? 1,
366
+ observedAt: isValidObservedAt(trace2.observedAt) ? trace2.observedAt : (/* @__PURE__ */ new Date()).toISOString()
367
+ };
368
+ }
369
+ function isValidObservedAt(value) {
370
+ return typeof value === "string" && RFC3339_RE.test(value) && !Number.isNaN(Date.parse(value));
371
+ }
372
+ function filterBaggage(baggage) {
373
+ const filtered = {};
374
+ for (const [key, value] of Object.entries(baggage ?? {})) {
375
+ if (ALLOWED_BAGGAGE.has(key) && value !== "") filtered[key] = value;
376
+ }
377
+ return filtered;
378
+ }
379
+ function serializeBaggage(baggage) {
380
+ const filtered = filterBaggage(baggage);
381
+ const entries = Object.entries(filtered);
382
+ if (entries.length === 0) return void 0;
383
+ return entries.map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join(",");
384
+ }
385
+ function newTraceparent() {
386
+ return `00-${randomHex(16)}-${randomHex(8)}-01`;
387
+ }
388
+ function randomHex(bytes) {
389
+ let value = randomBytes(bytes).toString("hex");
390
+ while (/^0+$/.test(value)) value = randomBytes(bytes).toString("hex");
391
+ return value;
392
+ }
393
+
308
394
  // src/api/headers.ts
309
395
  function buildHeaders(ctx, extra) {
396
+ const baggage = serializeBaggage(ctx.trace?.baggage);
310
397
  return {
311
398
  authorization: `Bearer ${ctx.token}`,
312
399
  "x-business-domain": ctx.businessDomain,
400
+ ...ctx.trace ? {
401
+ "bkn-request-id": ctx.trace.requestId,
402
+ "x-request-id": ctx.trace.requestId,
403
+ traceparent: ctx.trace.traceparent,
404
+ ...ctx.trace.conversationId ? { "bkn-conversation-id": ctx.trace.conversationId } : {},
405
+ ...ctx.trace.interactionId ? { "bkn-interaction-id": ctx.trace.interactionId } : {},
406
+ ...ctx.trace.operationId ? { "bkn-operation-id": ctx.trace.operationId } : {},
407
+ ...ctx.trace.attempt ? { "bkn-attempt": String(ctx.trace.attempt) } : {},
408
+ ...ctx.trace.observedAt ? { "bkn-event-observed-at": ctx.trace.observedAt } : {}
409
+ } : {},
410
+ ...baggage ? { baggage } : {},
313
411
  ...extra
314
412
  };
315
413
  }
@@ -335,6 +433,7 @@ async function request(ctx, path, init = {}) {
335
433
  ...init.headers
336
434
  }),
337
435
  body: hasBody ? JSON.stringify(init.body) : void 0,
436
+ redirect: init.redirect,
338
437
  signal: controller.signal
339
438
  });
340
439
  try {
@@ -588,6 +687,13 @@ function resolveContext(opts = {}) {
588
687
  token,
589
688
  businessDomain: opts.businessDomain ?? readPlatformConfig(normalized).businessDomain ?? DEFAULT_BUSINESS_DOMAIN,
590
689
  insecure,
690
+ ...opts.evidenceIngestToken ?? process.env.BKN_TRACE_EVIDENCE_INGEST_TOKEN ? {
691
+ evidenceIngestToken: opts.evidenceIngestToken ?? process.env.BKN_TRACE_EVIDENCE_INGEST_TOKEN
692
+ } : {},
693
+ // Correlation ids come from `opts.trace` only. The CLI reads its flags and
694
+ // env vars in `commands/_shared.ts`; a library client must not inherit an
695
+ // ambient interaction id it would then freeze for its whole lifetime.
696
+ trace: createTraceContext(opts.trace),
591
697
  ...refresh ? { refresh } : {}
592
698
  };
593
699
  }
@@ -774,12 +880,12 @@ async function importLicenseSafe(ctx, licenseText, opts = {}) {
774
880
  method: "POST",
775
881
  body: { license: text }
776
882
  });
777
- } catch (err) {
778
- if (err instanceof HttpError) {
779
- const stored = storedImport(err.body);
883
+ } catch (err2) {
884
+ if (err2 instanceof HttpError) {
885
+ const stored = storedImport(err2.body);
780
886
  if (stored) return stored;
781
887
  }
782
- throw err;
888
+ throw err2;
783
889
  }
784
890
  }
785
891
  function storedImport(body) {
@@ -1150,19 +1256,20 @@ function nextId() {
1150
1256
  function mcpUrl(ctx) {
1151
1257
  return `${ctx.baseUrl}${MCP_PATH}`;
1152
1258
  }
1259
+ function operationContext(ctx) {
1260
+ return ctx.trace ? { ...ctx, trace: createOperationTraceContext(ctx.trace) } : ctx;
1261
+ }
1153
1262
  function mcpInfo(ctx) {
1154
1263
  return request(ctx, `${MCP_PATH}/info`);
1155
1264
  }
1156
1265
  function headers(ctx, knId, sessionId) {
1157
- const h = {
1266
+ return buildHeaders(ctx, {
1158
1267
  "content-type": "application/json",
1159
1268
  accept: "application/json, text/event-stream",
1160
1269
  "x-kn-id": knId,
1161
1270
  "mcp-protocol-version": PROTOCOL,
1162
- authorization: `Bearer ${ctx.token}`
1163
- };
1164
- if (sessionId) h["mcp-session-id"] = sessionId;
1165
- return h;
1271
+ ...sessionId ? { "mcp-session-id": sessionId } : {}
1272
+ });
1166
1273
  }
1167
1274
  function parseBody(text) {
1168
1275
  try {
@@ -1223,8 +1330,9 @@ function unwrap(parsed) {
1223
1330
  return result;
1224
1331
  }
1225
1332
  async function callTool(ctx, knId, name, args) {
1226
- const sessionId = await ensureSession(ctx, knId);
1227
- const { text } = await post(ctx, knId, sessionId, {
1333
+ const operationCtx = operationContext(ctx);
1334
+ const sessionId = await ensureSession(operationCtx, knId);
1335
+ const { text } = await post(operationCtx, knId, sessionId, {
1228
1336
  jsonrpc: "2.0",
1229
1337
  method: "tools/call",
1230
1338
  params: { name, arguments: args },
@@ -1233,8 +1341,9 @@ async function callTool(ctx, knId, name, args) {
1233
1341
  return unwrap(parseBody(text));
1234
1342
  }
1235
1343
  async function callMethod(ctx, knId, method, params = {}) {
1236
- const sessionId = await ensureSession(ctx, knId);
1237
- const { text } = await post(ctx, knId, sessionId, {
1344
+ const operationCtx = operationContext(ctx);
1345
+ const sessionId = await ensureSession(operationCtx, knId);
1346
+ const { text } = await post(operationCtx, knId, sessionId, {
1238
1347
  jsonrpc: "2.0",
1239
1348
  method,
1240
1349
  params: Object.keys(params).length > 0 ? params : void 0,
@@ -1369,7 +1478,11 @@ async function executeDataflow(ctx, body, opts = {}) {
1369
1478
  }
1370
1479
  function listDataflowRuns(ctx, dagId, opts = {}) {
1371
1480
  return request(ctx, `${BASE2}/dag/${encodeURIComponent(dagId)}/results`, {
1372
- query: { since: opts.since || void 0 }
1481
+ query: {
1482
+ since: opts.since || void 0,
1483
+ page: opts.page,
1484
+ limit: opts.limit && opts.limit > 0 ? opts.limit : void 0
1485
+ }
1373
1486
  });
1374
1487
  }
1375
1488
  function runDataflowRemote(ctx, dagId, url, name) {
@@ -1425,9 +1538,11 @@ function deleteKnowledgeNetwork(ctx, knId) {
1425
1538
  function updateKnowledgeNetwork(ctx, knId, body) {
1426
1539
  return request(ctx, `${ONTOLOGY_BASE}/${encodeURIComponent(knId)}`, { method: "PUT", body });
1427
1540
  }
1541
+ var QUERY_OVER_POST = { "X-HTTP-Method-Override": "GET" };
1428
1542
  function querySubgraph(ctx, knId, body) {
1429
1543
  return request(ctx, `${ONTOLOGY_QUERY_BASE}/${encodeURIComponent(knId)}/subgraph`, {
1430
1544
  method: "POST",
1545
+ headers: QUERY_OVER_POST,
1431
1546
  body
1432
1547
  });
1433
1548
  }
@@ -1459,13 +1574,7 @@ function queryObjectTypeInstances(ctx, knId, otId, body) {
1459
1574
  return request(
1460
1575
  ctx,
1461
1576
  `${ONTOLOGY_QUERY_BASE}/${encodeURIComponent(knId)}/object-types/${encodeURIComponent(otId)}`,
1462
- { method: "POST", body }
1463
- );
1464
- }
1465
- function getObjectTypeProperties(ctx, knId, otId) {
1466
- return request(
1467
- ctx,
1468
- `${ONTOLOGY_QUERY_BASE}/${encodeURIComponent(knId)}/object-types/${encodeURIComponent(otId)}/properties`
1577
+ { method: "POST", headers: QUERY_OVER_POST, body }
1469
1578
  );
1470
1579
  }
1471
1580
  function queryActionType(ctx, knId, atId, body) {
@@ -1634,7 +1743,10 @@ function listResources2(ctx, opts = {}) {
1634
1743
  category: opts.category || void 0,
1635
1744
  status: opts.status || void 0,
1636
1745
  database: opts.database || void 0,
1637
- limit: opts.limit && opts.limit > 0 ? opts.limit : void 0,
1746
+ // Same `/resources` endpoint as `catalogResources`: limit=-1 (NO_LIMIT)
1747
+ // fetches every row; any other non-positive/invalid value falls back to
1748
+ // the backend default.
1749
+ limit: Number.isFinite(opts.limit) && (opts.limit > 0 || opts.limit === -1) ? opts.limit : void 0,
1638
1750
  offset: opts.offset,
1639
1751
  sort: opts.sort,
1640
1752
  direction: opts.direction,
@@ -1750,18 +1862,31 @@ function deleteResource(ctx, id, opts = {}) {
1750
1862
  });
1751
1863
  }
1752
1864
  async function findResource(ctx, name, opts = {}) {
1753
- const result = await listResources2(ctx, { name, datasourceId: opts.datasourceId });
1865
+ const result = await listResources2(ctx, {
1866
+ name,
1867
+ datasourceId: opts.datasourceId,
1868
+ limit: opts.limit
1869
+ });
1754
1870
  const list = Array.isArray(result) ? result : result.entries ?? [];
1755
1871
  return opts.exact ? list.filter((r) => r.name === name) : list;
1756
1872
  }
1757
1873
  function queryResource(ctx, id, opts = {}) {
1758
- return request(ctx, `${BASE3}/${encodeURIComponent(id)}/data`, {
1759
- method: "POST",
1760
- body: {
1874
+ const body = opts.cursor ? {
1875
+ paging: { cursor: opts.cursor },
1876
+ need_total: opts.needTotal ?? false
1877
+ } : {
1878
+ paging: {
1879
+ mode: opts.pagingMode ?? "single",
1761
1880
  limit: opts.limit ?? 50,
1762
1881
  offset: opts.offset ?? 0,
1763
- need_total: opts.needTotal ?? false
1764
- }
1882
+ ...opts.keepAliveSec !== void 0 ? { keep_alive_sec: opts.keepAliveSec } : {}
1883
+ },
1884
+ need_total: opts.needTotal ?? false
1885
+ };
1886
+ return request(ctx, `${BASE3}/${encodeURIComponent(id)}/data`, {
1887
+ method: "POST",
1888
+ headers: { "X-HTTP-Method-Override": "GET" },
1889
+ body
1765
1890
  });
1766
1891
  }
1767
1892
 
@@ -2999,7 +3124,11 @@ function listBknResources(ctx) {
2999
3124
  return request(ctx, "/api/bkn-backend/v1/resources");
3000
3125
  }
3001
3126
  function relationTypePaths(ctx, knId, body) {
3002
- return request(ctx, knPath(knId, "relation-type-paths"), { method: "POST", body });
3127
+ return request(ctx, knPath(knId, "relation-type-paths"), {
3128
+ method: "POST",
3129
+ headers: { "X-HTTP-Method-Override": "GET" },
3130
+ body
3131
+ });
3003
3132
  }
3004
3133
  function listConceptGroups(ctx, knId) {
3005
3134
  return request(ctx, knPath(knId, "concept-groups"));
@@ -3060,18 +3189,6 @@ function setActionScheduleStatus(ctx, knId, scheduleId, body) {
3060
3189
  function deleteActionSchedules(ctx, knId, ids) {
3061
3190
  return request(ctx, knPath(knId, `action-schedules/${ids}`), { method: "DELETE" });
3062
3191
  }
3063
- function listJobs(ctx, knId) {
3064
- return request(ctx, knPath(knId, "jobs"));
3065
- }
3066
- function getJob(ctx, knId, jobId) {
3067
- return request(ctx, knPath(knId, `jobs/${encodeURIComponent(jobId)}`));
3068
- }
3069
- function getJobTasks(ctx, knId, jobId) {
3070
- return request(ctx, knPath(knId, `jobs/${encodeURIComponent(jobId)}/tasks`));
3071
- }
3072
- function deleteJobs(ctx, knId, ids) {
3073
- return request(ctx, knPath(knId, `jobs/${ids}`), { method: "DELETE" });
3074
- }
3075
3192
 
3076
3193
  // src/api/vega.ts
3077
3194
  import { z } from "zod";
@@ -3227,9 +3344,15 @@ function discoverCatalog(ctx, id, wait = true) {
3227
3344
  timeoutMs: 12e4
3228
3345
  });
3229
3346
  }
3230
- function listCatalogResources(ctx, id, category) {
3347
+ function listCatalogResources(ctx, id, category, limit, offset) {
3231
3348
  return request(ctx, `${VEGA_BASE}/resources`, {
3232
- query: { catalog_id: id, category: category || void 0 }
3349
+ query: {
3350
+ catalog_id: id,
3351
+ category: category || void 0,
3352
+ // limit=-1 (NO_LIMIT) fetches all; NaN / 0 fall back to the backend default.
3353
+ limit: Number.isFinite(limit) && (limit > 0 || limit === -1) ? limit : void 0,
3354
+ offset: offset || void 0
3355
+ }
3233
3356
  });
3234
3357
  }
3235
3358
  function catalogHealthStatus(ctx, ids) {
@@ -3871,7 +3994,6 @@ function kn(ctx) {
3871
3994
  metricValidate: (knId, body) => validateMetric(ctx, knId, body),
3872
3995
  objectTypes: (knId, opts) => listObjectTypes(ctx, knId, opts),
3873
3996
  objectTypeQuery: (knId, otId, body) => queryObjectTypeInstances(ctx, knId, otId, body),
3874
- objectTypeProperties: (knId, otId) => getObjectTypeProperties(ctx, knId, otId),
3875
3997
  objectTypeGet: (knId, id) => getSchemaItem(ctx, knId, "object-types", id),
3876
3998
  objectTypeCreate: (knId, body) => createSchemaItem(ctx, knId, "object-types", body),
3877
3999
  objectTypeUpdate: (knId, id, body) => updateSchemaItem(ctx, knId, "object-types", id, body),
@@ -3899,10 +4021,6 @@ function kn(ctx) {
3899
4021
  actionScheduleUpdate: (knId, scheduleId, body) => updateActionSchedule(ctx, knId, scheduleId, body),
3900
4022
  actionScheduleSetStatus: (knId, scheduleId, body) => setActionScheduleStatus(ctx, knId, scheduleId, body),
3901
4023
  actionScheduleDelete: (knId, ids) => deleteActionSchedules(ctx, knId, ids),
3902
- jobs: (knId) => listJobs(ctx, knId),
3903
- job: (knId, jobId) => getJob(ctx, knId, jobId),
3904
- jobTasks: (knId, jobId) => getJobTasks(ctx, knId, jobId),
3905
- jobDelete: (knId, ids) => deleteJobs(ctx, knId, ids),
3906
4024
  relationTypePaths: (knId, body) => relationTypePaths(ctx, knId, body),
3907
4025
  bknResources: () => listBknResources(ctx),
3908
4026
  createFromCatalog: (opts) => createFromCatalog(ctx, opts),
@@ -4366,8 +4484,14 @@ function listToolboxes(ctx, opts = {}) {
4366
4484
  query: { keyword: opts.keyword || void 0, limit: opts.limit, offset: opts.offset ?? 0 }
4367
4485
  });
4368
4486
  }
4369
- function listTools2(ctx, boxId) {
4370
- return request(ctx, `${PATH}/${encodeURIComponent(boxId)}/tools/list`);
4487
+ function listTools2(ctx, boxId, opts = {}) {
4488
+ return request(ctx, `${PATH}/${encodeURIComponent(boxId)}/tools/list`, {
4489
+ query: {
4490
+ page: opts.page,
4491
+ page_size: Number.isFinite(opts.pageSize) && opts.pageSize > 0 ? opts.pageSize : void 0,
4492
+ all: opts.all ? "true" : void 0
4493
+ }
4494
+ });
4371
4495
  }
4372
4496
  function createToolbox(ctx, opts) {
4373
4497
  return request(ctx, PATH, {
@@ -4426,7 +4550,7 @@ function setToolStatuses(ctx, boxId, updates) {
4426
4550
  function toolboxes(ctx) {
4427
4551
  return {
4428
4552
  list: (opts) => listToolboxes(ctx, opts),
4429
- tools: (boxId) => listTools2(ctx, boxId),
4553
+ tools: (boxId, opts) => listTools2(ctx, boxId, opts),
4430
4554
  create: (opts) => createToolbox(ctx, opts),
4431
4555
  delete: (boxId) => deleteToolbox(ctx, boxId),
4432
4556
  publish: (boxId) => setToolboxStatus(ctx, boxId, "published"),
@@ -4452,8 +4576,728 @@ function toolboxes(ctx) {
4452
4576
  };
4453
4577
  }
4454
4578
 
4579
+ // src/trace-session.ts
4580
+ import { randomUUID as randomUUID2 } from "crypto";
4581
+ var PAYLOAD_FIELDS = {
4582
+ "agent.interaction.started": /* @__PURE__ */ new Set([
4583
+ "intent_hash",
4584
+ "mode",
4585
+ "agent_id",
4586
+ "app_ref",
4587
+ "question_artifact_ref"
4588
+ ]),
4589
+ "retrieval.completed": /* @__PURE__ */ new Set([
4590
+ "query_hash",
4591
+ "candidate_count",
4592
+ "truncated",
4593
+ "version_status",
4594
+ "source_refs"
4595
+ ]),
4596
+ "knowledge.read.observed": /* @__PURE__ */ new Set([
4597
+ "kn_id",
4598
+ "read_kind",
4599
+ "version_status",
4600
+ "schema_version",
4601
+ "business_refs"
4602
+ ]),
4603
+ "data.query.observed": /* @__PURE__ */ new Set([
4604
+ "query_hash",
4605
+ "query_type",
4606
+ "row_count",
4607
+ "truncated",
4608
+ "as_of",
4609
+ "version_status",
4610
+ "resource_refs",
4611
+ "field_refs",
4612
+ "query_artifact_ref",
4613
+ "result_artifact_ref"
4614
+ ]),
4615
+ "logic.execution.observed": /* @__PURE__ */ new Set([
4616
+ "logic_ref",
4617
+ "input_artifact_ref",
4618
+ "result_artifact_ref",
4619
+ "status"
4620
+ ]),
4621
+ "model.call.observed": /* @__PURE__ */ new Set([
4622
+ "model_name",
4623
+ "model_provider",
4624
+ "status",
4625
+ "input_token_count",
4626
+ "output_token_count",
4627
+ "prompt_hash",
4628
+ "output_hash",
4629
+ "error_category",
4630
+ "error_hash"
4631
+ ]),
4632
+ "tool.called": /* @__PURE__ */ new Set(["tool_id", "tool_name", "args_hash", "visibility", "version_status"]),
4633
+ "tool.result.observed": /* @__PURE__ */ new Set([
4634
+ "tool_id",
4635
+ "tool_name",
4636
+ "status",
4637
+ "result_hash",
4638
+ "result_length",
4639
+ "result_count",
4640
+ "error_hash",
4641
+ "error_category",
4642
+ "visibility",
4643
+ "version_status"
4644
+ ]),
4645
+ "claim.created": /* @__PURE__ */ new Set([
4646
+ "claim_id",
4647
+ "claim_type",
4648
+ "claim_hash",
4649
+ "source_event_ids",
4650
+ "operation_ids",
4651
+ "visibility",
4652
+ "version_status",
4653
+ "result_artifact_ref"
4654
+ ]),
4655
+ "evidence.refs.created": /* @__PURE__ */ new Set(["claim_id", "evidence_refs"]),
4656
+ "business.refs.resolved": /* @__PURE__ */ new Set(["claim_id", "resolver_status", "business_refs"]),
4657
+ "action.recommended": /* @__PURE__ */ new Set([
4658
+ "action_instance_id",
4659
+ "action_type",
4660
+ "target_refs",
4661
+ "reason_hash",
4662
+ "status",
4663
+ "reason_artifact_ref",
4664
+ "input_artifact_ref"
4665
+ ]),
4666
+ "action.approval_requested": /* @__PURE__ */ new Set(["action_instance_id", "policy_ref", "status"]),
4667
+ "action.approved": /* @__PURE__ */ new Set(["action_instance_id", "actor_ref", "policy_decision_ref", "status"]),
4668
+ "action.rejected": /* @__PURE__ */ new Set(["action_instance_id", "actor_ref", "policy_decision_ref", "status"]),
4669
+ "action.executed": /* @__PURE__ */ new Set([
4670
+ "action_instance_id",
4671
+ "status",
4672
+ "invocation_ref",
4673
+ "error_category",
4674
+ "error_hash"
4675
+ ]),
4676
+ "action.result_recorded": /* @__PURE__ */ new Set([
4677
+ "action_instance_id",
4678
+ "status",
4679
+ "result_hash",
4680
+ "task_ref",
4681
+ "artifact_ref",
4682
+ "result_artifact_ref"
4683
+ ])
4684
+ };
4685
+ var REQUIRED_PAYLOAD_FIELDS = {
4686
+ "agent.interaction.started": ["intent_hash", "mode"],
4687
+ "retrieval.completed": ["query_hash", "candidate_count", "truncated"],
4688
+ "knowledge.read.observed": ["kn_id", "read_kind", "version_status"],
4689
+ "data.query.observed": ["query_hash", "query_type", "row_count"],
4690
+ "logic.execution.observed": ["logic_ref", "input_artifact_ref", "result_artifact_ref", "status"],
4691
+ "model.call.observed": [
4692
+ "model_name",
4693
+ "model_provider",
4694
+ "status",
4695
+ "input_token_count",
4696
+ "output_token_count",
4697
+ "prompt_hash",
4698
+ "output_hash"
4699
+ ],
4700
+ "tool.called": ["tool_id", "tool_name", "args_hash", "visibility", "version_status"],
4701
+ "tool.result.observed": ["tool_id", "tool_name", "status", "visibility", "version_status"],
4702
+ "claim.created": [
4703
+ "claim_id",
4704
+ "claim_type",
4705
+ "claim_hash",
4706
+ "source_event_ids",
4707
+ "operation_ids",
4708
+ "visibility",
4709
+ "version_status"
4710
+ ],
4711
+ "evidence.refs.created": ["claim_id", "evidence_refs"],
4712
+ "business.refs.resolved": ["claim_id", "resolver_status", "business_refs"],
4713
+ "action.recommended": [
4714
+ "action_instance_id",
4715
+ "action_type",
4716
+ "target_refs",
4717
+ "reason_hash",
4718
+ "status"
4719
+ ],
4720
+ "action.approval_requested": ["action_instance_id", "policy_ref", "status"],
4721
+ "action.approved": ["action_instance_id", "actor_ref", "policy_decision_ref", "status"],
4722
+ "action.rejected": ["action_instance_id", "actor_ref", "policy_decision_ref", "status"],
4723
+ "action.executed": ["action_instance_id", "status", "invocation_ref"],
4724
+ "action.result_recorded": ["action_instance_id", "status", "result_hash"]
4725
+ };
4726
+ var REF_FIELDS = /* @__PURE__ */ new Set([
4727
+ "ref_id",
4728
+ "ref_type",
4729
+ "source_system",
4730
+ "validity",
4731
+ "version_status",
4732
+ "visibility",
4733
+ "summary_hash"
4734
+ ]);
4735
+ var RAW_KEYS = /* @__PURE__ */ new Set([
4736
+ "authorization",
4737
+ "cookie",
4738
+ "access_token",
4739
+ "refresh_token",
4740
+ "id_token",
4741
+ "api_key",
4742
+ "password",
4743
+ "private_key",
4744
+ "prompt",
4745
+ "user_question",
4746
+ "approval_comment",
4747
+ "sql",
4748
+ "query_params",
4749
+ "rows"
4750
+ ]);
4751
+ var HASH_RE = /^sha256:[0-9a-f]{64}$/;
4752
+ var RAW_VALUE_PATTERNS = [
4753
+ /bearer\s+[A-Za-z0-9._-]+/i,
4754
+ /\bselect\s+.+\s+from\b/is,
4755
+ /\binsert\s+into\b/i,
4756
+ /\bupdate\s+\S+\s+set\b/i,
4757
+ /\bdelete\s+from\b/i,
4758
+ /[\w.+-]+@[\w.-]+\.[A-Za-z]{2,}/,
4759
+ /https?:\/\/[^\s"']+/i
4760
+ ];
4761
+ function defaultNow() {
4762
+ return (/* @__PURE__ */ new Date()).toISOString();
4763
+ }
4764
+ function assertSessionOptions(options) {
4765
+ const trace2 = options.trace;
4766
+ if (!/^[0-9a-f]{32}$/.test(trace2.trace_id)) throw new Error("trace_id must be 32 hex characters");
4767
+ const traceparent = /^00-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/.exec(trace2.traceparent);
4768
+ if (!traceparent || traceparent[1] !== trace2.trace_id) {
4769
+ throw new Error("traceparent must be valid and match trace_id");
4770
+ }
4771
+ if (!/^req_[0-9A-Za-z_.-]+$/.test(trace2["bkn.request.id"])) {
4772
+ throw new Error("bkn.request.id must start with req_");
4773
+ }
4774
+ const conversationId = options.conversationId ?? trace2["bkn.conversation.id"];
4775
+ if (conversationId && !/^[0-9A-Za-z_.:-]{1,128}$/.test(conversationId)) {
4776
+ throw new Error("conversationId must be an opaque correlation identifier");
4777
+ }
4778
+ if (options.conversationId && trace2["bkn.conversation.id"] && options.conversationId !== trace2["bkn.conversation.id"]) {
4779
+ throw new Error("conversationId conflicts with trace bkn.conversation.id");
4780
+ }
4781
+ if (!trace2["bkn.tenant.id"] && !trace2.business_domain) {
4782
+ throw new Error("trace requires bkn.tenant.id or business_domain");
4783
+ }
4784
+ if (!trace2["bkn.account.id"] || !trace2["bkn.account.type"]) {
4785
+ throw new Error("trace requires account id and type");
4786
+ }
4787
+ if (!/^[0-9a-f]{16}$/.test(options.spanId)) throw new Error("spanId must be 16 hex characters");
4788
+ if (!options.producerModule.trim()) throw new Error("producerModule is required");
4789
+ }
4790
+ function clone(value) {
4791
+ return JSON.parse(JSON.stringify(value));
4792
+ }
4793
+ function assertSafePayload(eventType, payload) {
4794
+ const allowed = PAYLOAD_FIELDS[eventType];
4795
+ for (const key of Object.keys(payload)) {
4796
+ if (!allowed.has(key)) throw new Error(`${eventType} payload field is not registered: ${key}`);
4797
+ }
4798
+ for (const key of REQUIRED_PAYLOAD_FIELDS[eventType] ?? []) {
4799
+ if (payload[key] === void 0 || payload[key] === "") {
4800
+ throw new Error(`${eventType} payload requires ${key}`);
4801
+ }
4802
+ }
4803
+ if (eventType === "agent.interaction.started" && !payload.agent_id && !payload.app_ref) {
4804
+ throw new Error("agent.interaction.started requires agent_id or app_ref");
4805
+ }
4806
+ if (eventType === "agent.interaction.started") {
4807
+ assertEnum(payload, "mode", ["chat", "task", "background"]);
4808
+ }
4809
+ if (eventType === "model.call.observed" || eventType === "action.executed") {
4810
+ assertEnum(payload, "status", ["ok", "error"]);
4811
+ }
4812
+ if (eventType === "model.call.observed" && payload.status === "error") {
4813
+ for (const key of ["error_category", "error_hash"]) {
4814
+ if (!payload[key]) throw new Error(`model.call.observed error requires ${key}`);
4815
+ }
4816
+ }
4817
+ if (eventType === "tool.result.observed") {
4818
+ assertEnum(payload, "status", ["success", "error"]);
4819
+ if (payload.status === "success" && !payload.result_hash) {
4820
+ throw new Error("tool.result.observed success requires result_hash");
4821
+ }
4822
+ if (payload.status === "error" && !payload.error_hash) {
4823
+ throw new Error("tool.result.observed error requires error_hash");
4824
+ }
4825
+ }
4826
+ if (eventType === "business.refs.resolved") {
4827
+ assertEnum(payload, "resolver_status", ["resolved", "partial", "unresolved"]);
4828
+ }
4829
+ for (const key of ["source_event_ids", "operation_ids", "target_refs"]) {
4830
+ if (key in payload && (!Array.isArray(payload[key]) || payload[key].length === 0)) {
4831
+ throw new Error(`${eventType} payload requires non-empty ${key}`);
4832
+ }
4833
+ }
4834
+ if (eventType === "action.recommended") {
4835
+ for (const ref of payload.target_refs) assertQualifiedReference(ref);
4836
+ }
4837
+ if (eventType === "evidence.refs.created") {
4838
+ assertRefs(payload.evidence_refs, false);
4839
+ }
4840
+ if (eventType === "business.refs.resolved") {
4841
+ const unresolved = payload.resolver_status === "unresolved";
4842
+ assertRefs(payload.business_refs, unresolved);
4843
+ }
4844
+ if (eventType === "action.result_recorded" && !payload.task_ref && !payload.artifact_ref && !payload.result_artifact_ref) {
4845
+ throw new Error(
4846
+ "action.result_recorded requires task_ref, artifact_ref, or result_artifact_ref"
4847
+ );
4848
+ }
4849
+ if (eventType === "action.executed" && payload.status === "error") {
4850
+ for (const key of ["error_category", "error_hash"]) {
4851
+ if (!payload[key]) throw new Error(`action.executed error requires ${key}`);
4852
+ }
4853
+ }
4854
+ const fixedStatus = {
4855
+ "action.recommended": "recommended",
4856
+ "action.approval_requested": "approval_requested",
4857
+ "action.approved": "approved",
4858
+ "action.rejected": "rejected"
4859
+ };
4860
+ if (fixedStatus[eventType] && payload.status !== fixedStatus[eventType]) {
4861
+ throw new Error(`${eventType} requires status=${fixedStatus[eventType]}`);
4862
+ }
4863
+ scanSafeValue(payload, "payload");
4864
+ }
4865
+ function assertRefs(value, allowEmpty) {
4866
+ if (!Array.isArray(value) || !allowEmpty && value.length === 0) {
4867
+ throw new Error("reference list must be a non-empty array");
4868
+ }
4869
+ for (const item of value) {
4870
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
4871
+ throw new Error("reference must be an object");
4872
+ }
4873
+ const ref = item;
4874
+ for (const key of Object.keys(ref)) {
4875
+ if (!REF_FIELDS.has(key)) throw new Error(`reference field is not registered: ${key}`);
4876
+ }
4877
+ for (const key of [
4878
+ "ref_id",
4879
+ "ref_type",
4880
+ "source_system",
4881
+ "validity",
4882
+ "version_status",
4883
+ "visibility"
4884
+ ]) {
4885
+ if (!ref[key]) throw new Error(`reference requires ${key}`);
4886
+ }
4887
+ assertQualifiedReference(String(ref.ref_id));
4888
+ assertEnum(ref, "validity", ["observed", "available", "unavailable", "expired", "partial"]);
4889
+ assertEnum(ref, "version_status", ["versioned", "unversioned", "not_auditable"]);
4890
+ assertEnum(ref, "visibility", [
4891
+ "visible",
4892
+ "redacted",
4893
+ "hidden",
4894
+ "omitted",
4895
+ "unresolved",
4896
+ "unauthorized"
4897
+ ]);
4898
+ }
4899
+ }
4900
+ function assertQualifiedReference(value) {
4901
+ const parts = value.trim().split(":");
4902
+ const namespace = parts[0] ?? "";
4903
+ let valid = parts.every((part) => part.length > 0);
4904
+ if (["kn", "resource"].includes(namespace)) valid = valid && parts.length === 2;
4905
+ if (["object", "relation", "action_type", "metric", "field"].includes(namespace)) {
4906
+ valid = valid && parts.length === 3;
4907
+ }
4908
+ if (namespace === "property") valid = valid && parts.length === 4;
4909
+ if (!valid) {
4910
+ throw new Error("business reference id must include its knowledge-network or resource scope");
4911
+ }
4912
+ }
4913
+ function assertEnum(value, key, allowed) {
4914
+ if (!allowed.includes(String(value[key]))) {
4915
+ throw new Error(`${key} must be one of ${allowed.join(", ")}`);
4916
+ }
4917
+ }
4918
+ function scanSafeValue(value, path) {
4919
+ if (Array.isArray(value)) {
4920
+ value.forEach((child, index) => scanSafeValue(child, `${path}[${index}]`));
4921
+ return;
4922
+ }
4923
+ if (value && typeof value === "object") {
4924
+ for (const [key, child] of Object.entries(value)) {
4925
+ if (RAW_KEYS.has(key.toLowerCase())) throw new Error(`raw sensitive payload field: ${key}`);
4926
+ if (key.endsWith("_hash") && child !== "" && !HASH_RE.test(String(child))) {
4927
+ throw new Error(`${path}.${key} must be a sha256 hash`);
4928
+ }
4929
+ scanSafeValue(child, `${path}.${key}`);
4930
+ }
4931
+ return;
4932
+ }
4933
+ if (typeof value === "string" && RAW_VALUE_PATTERNS.some((pattern) => pattern.test(value))) {
4934
+ throw new Error(`raw sensitive payload value at ${path}`);
4935
+ }
4936
+ }
4937
+ var TraceSession = class {
4938
+ interactionId;
4939
+ trace;
4940
+ producerModule;
4941
+ spanId;
4942
+ emit;
4943
+ contractVersion;
4944
+ idFactory;
4945
+ now;
4946
+ events = [];
4947
+ eventIDs = /* @__PURE__ */ new Set();
4948
+ operationIDs = /* @__PURE__ */ new Set();
4949
+ claimEventIDs = /* @__PURE__ */ new Map();
4950
+ actions = /* @__PURE__ */ new WeakMap();
4951
+ flushTail = Promise.resolve();
4952
+ constructor(options) {
4953
+ assertSessionOptions(options);
4954
+ this.trace = clone(options.trace);
4955
+ if (options.conversationId) {
4956
+ this.trace["bkn.conversation.id"] = options.conversationId;
4957
+ }
4958
+ this.producerModule = options.producerModule;
4959
+ this.spanId = options.spanId;
4960
+ this.emit = options.emit;
4961
+ this.contractVersion = options.contractVersion ?? "2.1.0";
4962
+ this.idFactory = options.idFactory ?? randomUUID2;
4963
+ this.now = options.now ?? defaultNow;
4964
+ this.interactionId = options.interactionId ?? this.idFactory();
4965
+ }
4966
+ startInteraction(input) {
4967
+ return this.append("agent.interaction.started", {
4968
+ operationName: input.operationName,
4969
+ payload: {
4970
+ intent_hash: input.intentHash,
4971
+ mode: input.mode,
4972
+ ...input.agentId ? { agent_id: input.agentId } : {},
4973
+ ...input.appRef ? { app_ref: input.appRef } : {},
4974
+ ...input.questionArtifactRef ? { question_artifact_ref: input.questionArtifactRef } : {}
4975
+ }
4976
+ });
4977
+ }
4978
+ observeOperation(eventType, input) {
4979
+ const operationId = input.operationId ?? this.idFactory();
4980
+ this.operationIDs.add(operationId);
4981
+ return this.append(eventType, { ...input, operationId });
4982
+ }
4983
+ createClaim(input) {
4984
+ if (input.sourceEventIds.length === 0 || input.operationIds.length === 0) {
4985
+ throw new Error("claim requires at least one source event and operation");
4986
+ }
4987
+ this.assertKnownRefs(input.sourceEventIds, this.eventIDs, "event");
4988
+ this.assertKnownRefs(input.operationIds, this.operationIDs, "operation");
4989
+ const event = this.append("claim.created", {
4990
+ operationName: input.operationName,
4991
+ causationEventId: input.causationEventId,
4992
+ claimId: input.claimId,
4993
+ payload: {
4994
+ claim_id: input.claimId,
4995
+ claim_type: input.claimType,
4996
+ claim_hash: input.claimHash,
4997
+ source_event_ids: input.sourceEventIds,
4998
+ operation_ids: input.operationIds,
4999
+ visibility: input.visibility ?? "visible",
5000
+ version_status: input.versionStatus ?? "unversioned",
5001
+ ...input.resultArtifactRef ? { result_artifact_ref: input.resultArtifactRef } : {}
5002
+ }
5003
+ });
5004
+ this.claimEventIDs.set(input.claimId, event.event_id);
5005
+ return event;
5006
+ }
5007
+ createEvidenceRefs(input) {
5008
+ const claimEventID = this.requireClaim(input.claimId);
5009
+ if (input.refs.length === 0) throw new Error("evidence refs must not be empty");
5010
+ const operationId = this.idFactory();
5011
+ this.operationIDs.add(operationId);
5012
+ const event = this.append("evidence.refs.created", {
5013
+ operationName: input.operationName,
5014
+ operationId,
5015
+ causationEventId: input.causationEventId ?? claimEventID,
5016
+ claimId: input.claimId,
5017
+ payload: {
5018
+ claim_id: input.claimId,
5019
+ evidence_refs: input.refs.map((ref) => ({
5020
+ ref_id: ref.refId,
5021
+ ref_type: ref.refType,
5022
+ source_system: ref.sourceSystem,
5023
+ validity: ref.validity,
5024
+ version_status: ref.versionStatus,
5025
+ visibility: ref.visibility,
5026
+ ...ref.summaryHash ? { summary_hash: ref.summaryHash } : {}
5027
+ }))
5028
+ }
5029
+ });
5030
+ this.claimEventIDs.set(input.claimId, event.event_id);
5031
+ return event;
5032
+ }
5033
+ resolveBusinessRefs(input) {
5034
+ const claimEventID = this.requireClaim(input.claimId);
5035
+ if (input.resolverStatus === "resolved" && input.refs.length === 0) {
5036
+ throw new Error("resolved business refs must not be empty");
5037
+ }
5038
+ const operationId = this.idFactory();
5039
+ this.operationIDs.add(operationId);
5040
+ const event = this.append("business.refs.resolved", {
5041
+ operationName: input.operationName,
5042
+ operationId,
5043
+ causationEventId: input.causationEventId ?? claimEventID,
5044
+ claimId: input.claimId,
5045
+ payload: {
5046
+ claim_id: input.claimId,
5047
+ resolver_status: input.resolverStatus,
5048
+ business_refs: input.refs.map((ref) => ({
5049
+ ref_id: ref.refId,
5050
+ ref_type: ref.refType,
5051
+ source_system: ref.sourceSystem,
5052
+ validity: ref.validity,
5053
+ version_status: ref.versionStatus,
5054
+ visibility: ref.visibility
5055
+ }))
5056
+ }
5057
+ });
5058
+ this.claimEventIDs.set(input.claimId, event.event_id);
5059
+ return event;
5060
+ }
5061
+ recommendAction(input) {
5062
+ const claimEventID = this.requireClaim(input.claimId);
5063
+ if (input.targetRefs.length === 0) throw new Error("action target refs must not be empty");
5064
+ const operationId = this.idFactory();
5065
+ const actionInstanceId = this.idFactory();
5066
+ this.operationIDs.add(operationId);
5067
+ const event = this.append("action.recommended", {
5068
+ operationName: input.operationName,
5069
+ operationId,
5070
+ causationEventId: input.causationEventId ?? claimEventID,
5071
+ claimId: input.claimId,
5072
+ payload: {
5073
+ action_instance_id: actionInstanceId,
5074
+ action_type: input.actionType,
5075
+ target_refs: input.targetRefs,
5076
+ reason_hash: input.reasonHash,
5077
+ ...input.reasonArtifactRef ? { reason_artifact_ref: input.reasonArtifactRef } : {},
5078
+ ...input.inputArtifactRef ? { input_artifact_ref: input.inputArtifactRef } : {},
5079
+ status: "recommended"
5080
+ }
5081
+ });
5082
+ const internal = {
5083
+ actionInstanceId,
5084
+ claimId: input.claimId,
5085
+ operationId,
5086
+ lastEventId: event.event_id,
5087
+ state: "recommended"
5088
+ };
5089
+ const handle = Object.freeze({
5090
+ get actionInstanceId() {
5091
+ return internal.actionInstanceId;
5092
+ },
5093
+ get claimId() {
5094
+ return internal.claimId;
5095
+ },
5096
+ get operationId() {
5097
+ return internal.operationId;
5098
+ },
5099
+ get lastEventId() {
5100
+ return internal.lastEventId;
5101
+ },
5102
+ get state() {
5103
+ return internal.state;
5104
+ }
5105
+ });
5106
+ this.actions.set(handle, internal);
5107
+ return handle;
5108
+ }
5109
+ requestActionApproval(action, input) {
5110
+ const internal = this.expectActionState(action, "recommended");
5111
+ const event = this.appendAction(internal, "action.approval_requested", {
5112
+ action_instance_id: internal.actionInstanceId,
5113
+ policy_ref: input.policyRef,
5114
+ status: "approval_requested"
5115
+ });
5116
+ internal.state = "approval_requested";
5117
+ internal.lastEventId = event.event_id;
5118
+ return event;
5119
+ }
5120
+ approveAction(action, input) {
5121
+ const internal = this.expectActionState(action, "approval_requested");
5122
+ const event = this.appendAction(internal, "action.approved", {
5123
+ action_instance_id: internal.actionInstanceId,
5124
+ actor_ref: input.actorRef,
5125
+ policy_decision_ref: input.policyDecisionRef,
5126
+ status: "approved"
5127
+ });
5128
+ internal.state = "approved";
5129
+ internal.lastEventId = event.event_id;
5130
+ return event;
5131
+ }
5132
+ rejectAction(action, input) {
5133
+ const internal = this.expectActionState(action, "approval_requested");
5134
+ const event = this.appendAction(internal, "action.rejected", {
5135
+ action_instance_id: internal.actionInstanceId,
5136
+ actor_ref: input.actorRef,
5137
+ policy_decision_ref: input.policyDecisionRef,
5138
+ status: "rejected"
5139
+ });
5140
+ internal.state = "rejected";
5141
+ internal.lastEventId = event.event_id;
5142
+ return event;
5143
+ }
5144
+ executeAction(action, input) {
5145
+ const internal = this.expectActionState(
5146
+ action,
5147
+ "approved",
5148
+ "requires approval before execution"
5149
+ );
5150
+ const event = this.appendAction(internal, "action.executed", {
5151
+ action_instance_id: internal.actionInstanceId,
5152
+ status: input.status,
5153
+ invocation_ref: input.invocationRef,
5154
+ ...input.status === "error" ? { error_category: input.errorCategory, error_hash: input.errorHash } : {}
5155
+ });
5156
+ internal.state = "executed";
5157
+ internal.lastEventId = event.event_id;
5158
+ return event;
5159
+ }
5160
+ recordActionResult(action, input) {
5161
+ const internal = this.expectActionState(action, "executed");
5162
+ const event = this.appendAction(internal, "action.result_recorded", {
5163
+ action_instance_id: internal.actionInstanceId,
5164
+ result_hash: input.resultHash,
5165
+ status: input.status,
5166
+ ...input.taskRef ? { task_ref: input.taskRef } : {},
5167
+ ...input.artifactRef ? { artifact_ref: input.artifactRef } : {},
5168
+ ...input.resultArtifactRef ? { result_artifact_ref: input.resultArtifactRef } : {}
5169
+ });
5170
+ internal.state = "result_recorded";
5171
+ internal.lastEventId = event.event_id;
5172
+ return event;
5173
+ }
5174
+ pendingEvents() {
5175
+ return clone(this.events);
5176
+ }
5177
+ flush() {
5178
+ const requestedIDs = new Set(this.events.map((event) => event.event_id));
5179
+ const operation = this.flushTail.then(() => this.flushEvents(requestedIDs));
5180
+ this.flushTail = operation.then(
5181
+ () => void 0,
5182
+ () => void 0
5183
+ );
5184
+ return operation;
5185
+ }
5186
+ appendAction(action, eventType, payload) {
5187
+ return this.append(eventType, {
5188
+ operationName: eventType,
5189
+ operationId: action.operationId,
5190
+ causationEventId: action.lastEventId,
5191
+ claimId: action.claimId,
5192
+ payload
5193
+ });
5194
+ }
5195
+ append(eventType, input) {
5196
+ assertSafePayload(eventType, input.payload);
5197
+ this.assertContractPayload(eventType, input.payload);
5198
+ if (eventType !== "agent.interaction.started") {
5199
+ if (!input.causationEventId) throw new Error(`${eventType} requires causation_event_id`);
5200
+ if (!this.eventIDs.has(input.causationEventId)) {
5201
+ throw new Error(`unknown event reference: ${input.causationEventId}`);
5202
+ }
5203
+ }
5204
+ if (eventType !== "agent.interaction.started" && eventType !== "claim.created" && !input.operationId) {
5205
+ throw new Error(`${eventType} requires operation_id`);
5206
+ }
5207
+ const eventID = this.idFactory();
5208
+ if (this.eventIDs.has(eventID)) throw new Error(`duplicate event id: ${eventID}`);
5209
+ const timestamp = this.now();
5210
+ const event = {
5211
+ event_id: eventID,
5212
+ event_type: eventType,
5213
+ "bkn.trace.schema.version": this.contractVersion,
5214
+ observed_at: timestamp,
5215
+ emitted_at: timestamp,
5216
+ producer_module: this.producerModule,
5217
+ trace_id: this.trace.trace_id,
5218
+ span_id: this.spanId,
5219
+ "bkn.request.id": this.trace["bkn.request.id"],
5220
+ "bkn.operation.name": input.operationName,
5221
+ interaction_id: this.interactionId,
5222
+ ...input.operationId ? { operation_id: input.operationId } : {},
5223
+ ...input.causationEventId ? { causation_event_id: input.causationEventId } : {},
5224
+ ...input.claimId ? { claim_id: input.claimId } : {},
5225
+ ...input.attempt ? { attempt: input.attempt } : {},
5226
+ payload: clone(input.payload)
5227
+ };
5228
+ this.events.push(clone(event));
5229
+ this.eventIDs.add(eventID);
5230
+ return clone(event);
5231
+ }
5232
+ async flushEvents(requestedIDs) {
5233
+ const batch = this.events.filter((event) => requestedIDs.has(event.event_id));
5234
+ if (batch.length === 0) return void 0;
5235
+ const response = await this.emit({
5236
+ "bkn.trace.schema.version": this.contractVersion,
5237
+ trace: clone(this.trace),
5238
+ events: clone(batch)
5239
+ });
5240
+ const remaining = this.events.filter((event) => !requestedIDs.has(event.event_id));
5241
+ this.events.splice(0, this.events.length, ...remaining);
5242
+ return response;
5243
+ }
5244
+ assertContractPayload(eventType, payload) {
5245
+ if (this.contractVersion !== "2.2.0") return;
5246
+ const requiredArtifactFields = {
5247
+ "agent.interaction.started": ["question_artifact_ref"],
5248
+ "data.query.observed": ["query_artifact_ref", "result_artifact_ref"],
5249
+ "logic.execution.observed": ["input_artifact_ref", "result_artifact_ref"],
5250
+ "claim.created": ["result_artifact_ref"],
5251
+ "action.recommended": ["input_artifact_ref"],
5252
+ "action.result_recorded": ["result_artifact_ref"]
5253
+ };
5254
+ for (const field of requiredArtifactFields[eventType] ?? []) {
5255
+ const value = payload[field];
5256
+ if (typeof value !== "string" || !/^artifact:[0-9A-Za-z][0-9A-Za-z_.:-]{0,127}$/.test(value)) {
5257
+ throw new Error(`${eventType} payload requires valid ${field}`);
5258
+ }
5259
+ }
5260
+ for (const [field, value] of Object.entries(payload)) {
5261
+ if (field.endsWith("_artifact_ref") && value !== void 0) {
5262
+ if (typeof value !== "string" || !/^artifact:[0-9A-Za-z][0-9A-Za-z_.:-]{0,127}$/.test(value)) {
5263
+ throw new Error(`${eventType} payload requires valid ${field}`);
5264
+ }
5265
+ }
5266
+ }
5267
+ if (eventType === "action.result_recorded" && payload.artifact_ref !== void 0) {
5268
+ throw new Error("action.result_recorded 2.2 does not accept legacy artifact_ref");
5269
+ }
5270
+ }
5271
+ assertKnownRefs(values, known, kind) {
5272
+ for (const value of values) {
5273
+ if (!known.has(value)) throw new Error(`unknown ${kind} reference: ${value}`);
5274
+ }
5275
+ }
5276
+ requireClaim(claimID) {
5277
+ const eventID = this.claimEventIDs.get(claimID);
5278
+ if (!eventID) throw new Error(`unknown claim reference: ${claimID}`);
5279
+ return eventID;
5280
+ }
5281
+ expectActionState(action, expected, message) {
5282
+ const internal = this.actions.get(action);
5283
+ if (!internal) throw new Error("action handle does not belong to this trace session");
5284
+ if (internal.state !== expected) {
5285
+ if (message) throw new Error(`action ${internal.actionInstanceId} ${message}`);
5286
+ throw new Error(
5287
+ `action ${internal.actionInstanceId} must be ${expected}, got ${internal.state}`
5288
+ );
5289
+ }
5290
+ return internal;
5291
+ }
5292
+ };
5293
+
4455
5294
  // src/api/trace.ts
4456
5295
  var SEARCH = "/api/agent-observability/v1/traces/_search";
5296
+ var EVIDENCE_EVENTS = "/api/agent-observability/v1/evidence/events";
5297
+ var EVIDENCE_ARTIFACTS = "/api/agent-observability/v1/evidence/artifacts";
5298
+ var REQUESTS = "/api/agent-observability/v1/requests";
5299
+ var INTERACTIONS = "/api/agent-observability/v1/interactions";
5300
+ var TRACES = "/api/agent-observability/v1/traces";
4457
5301
  function isoToNanos(iso) {
4458
5302
  const ms = Date.parse(iso);
4459
5303
  if (Number.isNaN(ms)) return void 0;
@@ -4495,6 +5339,67 @@ async function getRawSpansByConversation(ctx, conversationId, opts = {}) {
4495
5339
  function traceSearch(ctx, body) {
4496
5340
  return request(ctx, SEARCH, { method: "POST", body });
4497
5341
  }
5342
+ function emitEvidenceEvents(ctx, body) {
5343
+ return request(ctx, EVIDENCE_EVENTS, {
5344
+ method: "POST",
5345
+ body,
5346
+ headers: evidenceWriteHeaders(ctx),
5347
+ redirect: "manual"
5348
+ });
5349
+ }
5350
+ function emitEvidenceArtifact(ctx, body) {
5351
+ return request(ctx, EVIDENCE_ARTIFACTS, {
5352
+ method: "POST",
5353
+ body,
5354
+ headers: evidenceWriteHeaders(ctx),
5355
+ redirect: "manual"
5356
+ });
5357
+ }
5358
+ function evidenceWriteHeaders(ctx) {
5359
+ return ctx.evidenceIngestToken ? { "x-bkn-trace-ingest-token": ctx.evidenceIngestToken } : void 0;
5360
+ }
5361
+ function getEvidenceArtifact(ctx, artifactId) {
5362
+ return request(ctx, `${EVIDENCE_ARTIFACTS}/${encodeURIComponent(artifactId)}`);
5363
+ }
5364
+ function listRequestSummaries(ctx, query = {}) {
5365
+ return request(ctx, REQUESTS, {
5366
+ query: summaryQuery(query)
5367
+ });
5368
+ }
5369
+ function getRequestSummary(ctx, requestId) {
5370
+ return request(ctx, `${REQUESTS}/${encodeURIComponent(requestId)}`);
5371
+ }
5372
+ function getInteractionSummary(ctx, interactionId) {
5373
+ return request(ctx, `${INTERACTIONS}/${encodeURIComponent(interactionId)}`);
5374
+ }
5375
+ function getRequestTraces(ctx, requestId, query = {}) {
5376
+ return request(
5377
+ ctx,
5378
+ `${REQUESTS}/${encodeURIComponent(requestId)}/traces`,
5379
+ { query: summaryQuery(query) }
5380
+ );
5381
+ }
5382
+ function getTraceGraph(ctx, traceId) {
5383
+ return request(ctx, `${TRACES}/${encodeURIComponent(traceId)}/trace-graph`);
5384
+ }
5385
+ function getEvidenceChain(ctx, scope, opts = {}) {
5386
+ const target = traceTarget(scope, "evidence-chain");
5387
+ return request(ctx, target.path, {
5388
+ query: queryWithLimit(target.query, opts)
5389
+ });
5390
+ }
5391
+ function getBusinessGraph(ctx, scope, opts = {}) {
5392
+ const target = traceTarget(scope, "business-graph");
5393
+ return request(ctx, target.path, {
5394
+ query: queryWithLimit(target.query, opts)
5395
+ });
5396
+ }
5397
+ function getSnapshotPreview(ctx, scope, opts = {}) {
5398
+ const target = traceTarget(scope, "snapshot-preview");
5399
+ return request(ctx, target.path, {
5400
+ query: queryWithLimit(target.query, opts)
5401
+ });
5402
+ }
4498
5403
  async function getSpansByConversation(ctx, conversationId, opts = {}) {
4499
5404
  const agg = await request(ctx, SEARCH, {
4500
5405
  method: "POST",
@@ -4519,6 +5424,38 @@ async function getSpansByConversation(ctx, conversationId, opts = {}) {
4519
5424
  }) ?? {};
4520
5425
  return (spans.hits?.hits ?? []).map((h) => h._source ?? {});
4521
5426
  }
5427
+ function traceTarget(scope, subresource) {
5428
+ if (typeof scope === "string") {
5429
+ return { path: `${TRACES}/${encodeURIComponent(scope)}/${subresource}` };
5430
+ }
5431
+ if ("traceId" in scope) {
5432
+ return { path: `${TRACES}/${encodeURIComponent(scope.traceId)}/${subresource}` };
5433
+ }
5434
+ const requestPath = subresource === "evidence-chain" ? `${TRACES}/by-request` : `${TRACES}/by-request/${subresource}`;
5435
+ return { path: requestPath, query: { request_id: scope.requestId } };
5436
+ }
5437
+ function queryWithLimit(query, opts) {
5438
+ if (opts.limit === void 0 || !Number.isFinite(opts.limit)) return query;
5439
+ return { ...query ?? {}, limit: opts.limit };
5440
+ }
5441
+ function summaryQuery(query) {
5442
+ const result = {};
5443
+ if (query.limit !== void 0 && Number.isFinite(query.limit)) result.limit = query.limit;
5444
+ if (query.cursor) result.cursor = query.cursor;
5445
+ if (query.from) result.from = query.from;
5446
+ if (query.to) result.to = query.to;
5447
+ if (query.status) result.status = query.status;
5448
+ if (query.agentOrApp) result.agent_or_app = query.agentOrApp;
5449
+ if (query.businessDomain) result.business_domain = query.businessDomain;
5450
+ if (query.conversationId) result.conversation_id = query.conversationId;
5451
+ if (query.interactionId) result.interaction_id = query.interactionId;
5452
+ if (query.knowledgeNetwork) result.knowledge_network = query.knowledgeNetwork;
5453
+ if (query.evidenceCompleteness) {
5454
+ result.evidence_completeness = query.evidenceCompleteness;
5455
+ }
5456
+ if (query.keyword) result.keyword = query.keyword;
5457
+ return Object.keys(result).length ? result : void 0;
5458
+ }
4522
5459
 
4523
5460
  // src/bkn-trace/claude-judge.ts
4524
5461
  import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
@@ -4580,10 +5517,10 @@ async function judgeJson(prompt, opts = {}) {
4580
5517
  child.stdout.on("data", (d) => {
4581
5518
  out += d;
4582
5519
  });
4583
- child.on("error", (err) => {
5520
+ child.on("error", (err2) => {
4584
5521
  clearTimeout(killer);
4585
5522
  reject(
4586
- err.code === "ENOENT" ? new ClaudeJudgeError("`claude` not found on PATH", "not_available") : err
5523
+ err2.code === "ENOENT" ? new ClaudeJudgeError("`claude` not found on PATH", "not_available") : err2
4587
5524
  );
4588
5525
  });
4589
5526
  child.on("close", (code) => {
@@ -4593,8 +5530,8 @@ async function judgeJson(prompt, opts = {}) {
4593
5530
  if (code !== 0) return reject(new ClaudeJudgeError(`claude exited ${code}`, "exit"));
4594
5531
  resolve7(out);
4595
5532
  });
4596
- child.stdin.on("error", (err) => {
4597
- if (err.code !== "EPIPE") reject(err);
5533
+ child.stdin.on("error", (err2) => {
5534
+ if (err2.code !== "EPIPE") reject(err2);
4598
5535
  });
4599
5536
  child.stdin.end(prompt);
4600
5537
  });
@@ -5144,6 +6081,747 @@ async function runEvalSet(agentId, cases, deps) {
5144
6081
  };
5145
6082
  }
5146
6083
 
6084
+ // src/bkn-trace/fixture-validate.ts
6085
+ import { readFileSync as readFileSync4, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
6086
+ import { join as join4 } from "path";
6087
+ var CONTRACT_VERSIONS = /* @__PURE__ */ new Set(["1.0.0", "2.0.0", "2.1.0"]);
6088
+ var BUSINESS_CONTRACT_VERSION = "2.1.0";
6089
+ var TRACEPARENT_RE2 = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
6090
+ var REQUEST_ID_RE2 = /^req_[0-9A-Za-z_.-]+$/;
6091
+ var RFC3339_NANO_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/;
6092
+ var ALLOWED_BAGGAGE2 = /* @__PURE__ */ new Set(["bkn.account.type", "bkn.runtime.env"]);
6093
+ var REQUIRED_LOG_FIELDS = [
6094
+ "trace_id",
6095
+ "span_id",
6096
+ "bkn.request.id",
6097
+ "bkn.module.name",
6098
+ "bkn.operation.name",
6099
+ "bkn.status",
6100
+ "bkn.timestamp",
6101
+ "bkn.trace.schema.version"
6102
+ ];
6103
+ var REQUIRED_SPAN_FIELDS = [
6104
+ "span_id",
6105
+ "name",
6106
+ "bkn.module.name",
6107
+ "bkn.operation.name",
6108
+ "bkn.status",
6109
+ "bkn.timestamp"
6110
+ ];
6111
+ var REQUIRED_EVENT_FIELDS = [
6112
+ "trace_id",
6113
+ "span_id",
6114
+ "bkn.request.id",
6115
+ "bkn.operation.name",
6116
+ "event_id",
6117
+ "event_type",
6118
+ "bkn.trace.schema.version",
6119
+ "observed_at",
6120
+ "emitted_at",
6121
+ "producer_module",
6122
+ "payload"
6123
+ ];
6124
+ var SENSITIVE_PATTERNS = [
6125
+ /authorization/i,
6126
+ /bearer\s+[A-Za-z0-9._-]+/i,
6127
+ /access[_-]?token/i,
6128
+ /api[_-]?key/i,
6129
+ /cookie/i,
6130
+ /\bselect\s+.+\s+from\b/is,
6131
+ /prompt\s*[:=]/i,
6132
+ /https?:\/\/[^\s"']+/i,
6133
+ /[\w.+-]+@[\w.-]+\.[A-Za-z]{2,}/
6134
+ ];
6135
+ var BUSINESS_EVENT_TYPES = /* @__PURE__ */ new Set([
6136
+ "agent.interaction.started",
6137
+ "retrieval.completed",
6138
+ "knowledge.read.observed",
6139
+ "data.query.observed",
6140
+ "model.call.observed",
6141
+ "tool.called",
6142
+ "tool.result.observed",
6143
+ "claim.created",
6144
+ "evidence.refs.created",
6145
+ "business.refs.resolved",
6146
+ "action.recommended",
6147
+ "action.approval_requested",
6148
+ "action.approved",
6149
+ "action.rejected",
6150
+ "action.executed",
6151
+ "action.result_recorded"
6152
+ ]);
6153
+ var CLAIM_EVENT_TYPES = /* @__PURE__ */ new Set([
6154
+ "claim.created",
6155
+ "evidence.refs.created",
6156
+ "business.refs.resolved",
6157
+ "action.recommended",
6158
+ "action.approval_requested",
6159
+ "action.approved",
6160
+ "action.rejected",
6161
+ "action.executed",
6162
+ "action.result_recorded"
6163
+ ]);
6164
+ var ACTION_TRANSITIONS = {
6165
+ recommended: /* @__PURE__ */ new Set(["approval_requested"]),
6166
+ approval_requested: /* @__PURE__ */ new Set(["approved", "rejected"]),
6167
+ approved: /* @__PURE__ */ new Set(["executed"]),
6168
+ executed: /* @__PURE__ */ new Set(["result_recorded"]),
6169
+ rejected: /* @__PURE__ */ new Set(),
6170
+ result_recorded: /* @__PURE__ */ new Set()
6171
+ };
6172
+ var ACTION_STATE_BY_EVENT = {
6173
+ "action.recommended": "recommended",
6174
+ "action.approval_requested": "approval_requested",
6175
+ "action.approved": "approved",
6176
+ "action.rejected": "rejected",
6177
+ "action.executed": "executed",
6178
+ "action.result_recorded": "result_recorded"
6179
+ };
6180
+ var EVENT_PAYLOAD_FIELDS = {
6181
+ "agent.interaction.started": /* @__PURE__ */ new Set(["intent_hash", "mode", "agent_id", "app_ref"]),
6182
+ "retrieval.completed": /* @__PURE__ */ new Set([
6183
+ "query_hash",
6184
+ "candidate_count",
6185
+ "truncated",
6186
+ "version_status",
6187
+ "source_refs"
6188
+ ]),
6189
+ "knowledge.read.observed": /* @__PURE__ */ new Set([
6190
+ "kn_id",
6191
+ "read_kind",
6192
+ "version_status",
6193
+ "schema_version",
6194
+ "business_refs"
6195
+ ]),
6196
+ "data.query.observed": /* @__PURE__ */ new Set([
6197
+ "query_hash",
6198
+ "query_type",
6199
+ "row_count",
6200
+ "truncated",
6201
+ "as_of",
6202
+ "version_status",
6203
+ "resource_refs",
6204
+ "field_refs"
6205
+ ]),
6206
+ "model.call.observed": /* @__PURE__ */ new Set([
6207
+ "model_name",
6208
+ "model_provider",
6209
+ "status",
6210
+ "input_token_count",
6211
+ "output_token_count",
6212
+ "prompt_hash",
6213
+ "output_hash",
6214
+ "error_category",
6215
+ "error_hash"
6216
+ ]),
6217
+ "tool.called": /* @__PURE__ */ new Set(["tool_id", "tool_name", "args_hash", "visibility", "version_status"]),
6218
+ "tool.result.observed": /* @__PURE__ */ new Set([
6219
+ "tool_id",
6220
+ "tool_name",
6221
+ "status",
6222
+ "result_hash",
6223
+ "result_length",
6224
+ "result_count",
6225
+ "error_hash",
6226
+ "error_category",
6227
+ "visibility",
6228
+ "version_status"
6229
+ ]),
6230
+ "claim.created": /* @__PURE__ */ new Set([
6231
+ "claim_id",
6232
+ "claim_type",
6233
+ "claim_hash",
6234
+ "source_event_ids",
6235
+ "operation_ids",
6236
+ "visibility",
6237
+ "version_status"
6238
+ ]),
6239
+ "evidence.refs.created": /* @__PURE__ */ new Set(["claim_id", "evidence_refs"]),
6240
+ "business.refs.resolved": /* @__PURE__ */ new Set(["claim_id", "resolver_status", "business_refs"]),
6241
+ "action.recommended": /* @__PURE__ */ new Set([
6242
+ "action_instance_id",
6243
+ "action_type",
6244
+ "target_refs",
6245
+ "reason_hash",
6246
+ "status"
6247
+ ]),
6248
+ "action.approval_requested": /* @__PURE__ */ new Set(["action_instance_id", "policy_ref", "status"]),
6249
+ "action.approved": /* @__PURE__ */ new Set(["action_instance_id", "actor_ref", "policy_decision_ref", "status"]),
6250
+ "action.rejected": /* @__PURE__ */ new Set(["action_instance_id", "actor_ref", "policy_decision_ref", "status"]),
6251
+ "action.executed": /* @__PURE__ */ new Set([
6252
+ "action_instance_id",
6253
+ "invocation_ref",
6254
+ "tool_ref",
6255
+ "status",
6256
+ "error_category",
6257
+ "error_hash"
6258
+ ]),
6259
+ "action.result_recorded": /* @__PURE__ */ new Set([
6260
+ "action_instance_id",
6261
+ "result_hash",
6262
+ "artifact_ref",
6263
+ "task_ref",
6264
+ "status"
6265
+ ])
6266
+ };
6267
+ var REFERENCE_FIELDS = /* @__PURE__ */ new Set([
6268
+ "ref_id",
6269
+ "ref_type",
6270
+ "source_system",
6271
+ "validity",
6272
+ "version_status",
6273
+ "visibility",
6274
+ "summary_hash"
6275
+ ]);
6276
+ var FORBIDDEN_RAW_KEYS = /* @__PURE__ */ new Set([
6277
+ "authorization",
6278
+ "cookie",
6279
+ "access_token",
6280
+ "refresh_token",
6281
+ "id_token",
6282
+ "api_key",
6283
+ "password",
6284
+ "private_key",
6285
+ "prompt",
6286
+ "user_question",
6287
+ "approval_comment",
6288
+ "sql",
6289
+ "query_params",
6290
+ "rows"
6291
+ ]);
6292
+ function err(code, path, message) {
6293
+ return { code, path, message };
6294
+ }
6295
+ function asRecord(value) {
6296
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
6297
+ }
6298
+ function jsonFiles(path) {
6299
+ const stat = statSync4(path);
6300
+ if (stat.isFile()) return [path];
6301
+ return readdirSync5(path).filter((name) => name.endsWith(".json")).sort().map((name) => join4(path, name));
6302
+ }
6303
+ function validTraceparent(value) {
6304
+ if (typeof value !== "string") return false;
6305
+ const match = TRACEPARENT_RE2.exec(value);
6306
+ if (!match) return false;
6307
+ const [, traceId, spanId] = match;
6308
+ return traceId !== "0".repeat(32) && spanId !== "0".repeat(16);
6309
+ }
6310
+ function checkRequired(item, fields, basePath, errors) {
6311
+ for (const field of fields) {
6312
+ if (item[field] === void 0 || item[field] === "") {
6313
+ errors.push(
6314
+ err(
6315
+ "BKN_TRACE_REQUIRED_FIELD_MISSING",
6316
+ `${basePath}.${field}`,
6317
+ `missing required field ${field}`
6318
+ )
6319
+ );
6320
+ }
6321
+ }
6322
+ }
6323
+ function checkTimestamp(value, path, errors) {
6324
+ if (typeof value !== "string" || !RFC3339_NANO_RE.test(value)) {
6325
+ errors.push(err("BKN_TRACE_INVALID_TIMESTAMP", path, "timestamp must be UTC RFC3339Nano"));
6326
+ }
6327
+ }
6328
+ function checkSensitive(value, path, errors) {
6329
+ if (Array.isArray(value)) {
6330
+ value.forEach((child, index) => checkSensitive(child, `${path}[${index}]`, errors));
6331
+ return;
6332
+ }
6333
+ if (value && typeof value === "object") {
6334
+ for (const [key, child] of Object.entries(value)) {
6335
+ if (FORBIDDEN_RAW_KEYS.has(key.toLowerCase())) {
6336
+ errors.push(
6337
+ err(
6338
+ "BKN_TRACE_SENSITIVE_VALUE_LEAKED",
6339
+ `${path}.${key}`,
6340
+ "raw sensitive field is forbidden"
6341
+ )
6342
+ );
6343
+ }
6344
+ if (key.endsWith("_hash") && child !== "" && (typeof child !== "string" || !/^sha256:[0-9a-f]{64}$/.test(child))) {
6345
+ errors.push(
6346
+ err("BKN_TRACE_REQUIRED_FIELD_MISSING", `${path}.${key}`, `${key} must be a sha256 hash`)
6347
+ );
6348
+ }
6349
+ checkSensitive(child, `${path}.${key}`, errors);
6350
+ }
6351
+ return;
6352
+ }
6353
+ if (typeof value !== "string") return;
6354
+ if (SENSITIVE_PATTERNS.some((pattern) => pattern.test(value))) {
6355
+ errors.push(
6356
+ err(
6357
+ "BKN_TRACE_SENSITIVE_VALUE_LEAKED",
6358
+ path,
6359
+ "sensitive value must be redacted, hashed, or referenced"
6360
+ )
6361
+ );
6362
+ }
6363
+ }
6364
+ function validateFixture(data) {
6365
+ const root = asRecord(data);
6366
+ const errors = [];
6367
+ const fixtureId = typeof root.fixture_id === "string" ? root.fixture_id : "<unknown>";
6368
+ const contractVersion = typeof root["bkn.trace.schema.version"] === "string" ? root["bkn.trace.schema.version"] : null;
6369
+ if (!contractVersion) {
6370
+ errors.push(
6371
+ err(
6372
+ "BKN_TRACE_SCHEMA_VERSION_MISSING",
6373
+ "$.bkn.trace.schema.version",
6374
+ "missing contract version"
6375
+ )
6376
+ );
6377
+ } else if (!CONTRACT_VERSIONS.has(contractVersion)) {
6378
+ errors.push(
6379
+ err(
6380
+ "BKN_TRACE_SCHEMA_VERSION_UNSUPPORTED",
6381
+ "$.bkn.trace.schema.version",
6382
+ `unsupported contract version ${contractVersion}`
6383
+ )
6384
+ );
6385
+ }
6386
+ const trace2 = asRecord(root.trace);
6387
+ const traceId = trace2.trace_id;
6388
+ const requestId = trace2["bkn.request.id"];
6389
+ if (typeof traceId !== "string" || !/^[0-9a-f]{32}$/.test(traceId)) {
6390
+ errors.push(
6391
+ err("BKN_TRACE_REQUIRED_FIELD_MISSING", "$.trace.trace_id", "missing valid trace id")
6392
+ );
6393
+ }
6394
+ if (typeof requestId !== "string" || !REQUEST_ID_RE2.test(requestId)) {
6395
+ errors.push(
6396
+ err(
6397
+ "BKN_TRACE_REQUIRED_FIELD_MISSING",
6398
+ "$.trace.bkn.request.id",
6399
+ "missing valid bkn.request.id"
6400
+ )
6401
+ );
6402
+ }
6403
+ if (!validTraceparent(trace2.traceparent)) {
6404
+ errors.push(err("BKN_TRACE_INVALID_TRACEPARENT", "$.trace.traceparent", "invalid traceparent"));
6405
+ }
6406
+ const spans = Array.isArray(root.spans) ? root.spans : [];
6407
+ const spanIds = /* @__PURE__ */ new Set();
6408
+ spans.forEach((item, index) => {
6409
+ const span = asRecord(item);
6410
+ checkRequired(span, REQUIRED_SPAN_FIELDS, `$.spans[${index}]`, errors);
6411
+ checkTimestamp(span["bkn.timestamp"], `$.spans[${index}].bkn.timestamp`, errors);
6412
+ if (typeof span.span_id === "string") spanIds.add(span.span_id);
6413
+ const parent = span.parent_span_id;
6414
+ if (parent !== null && parent !== void 0 && !spanIds.has(String(parent))) {
6415
+ errors.push(
6416
+ err(
6417
+ "BKN_TRACE_ORPHAN_SPAN",
6418
+ `$.spans[${index}].parent_span_id`,
6419
+ "parent span must appear before child span or be represented as a link"
6420
+ )
6421
+ );
6422
+ }
6423
+ });
6424
+ if (spans.length === 0) {
6425
+ errors.push(err("BKN_TRACE_REQUIRED_FIELD_MISSING", "$.spans", "at least one span required"));
6426
+ }
6427
+ const logs = Array.isArray(root.logs) ? root.logs : [];
6428
+ logs.forEach((item, index) => {
6429
+ const log = asRecord(item);
6430
+ checkRequired(log, REQUIRED_LOG_FIELDS, `$.logs[${index}]`, errors);
6431
+ checkTimestamp(log["bkn.timestamp"], `$.logs[${index}].bkn.timestamp`, errors);
6432
+ if (log.trace_id !== traceId || log["bkn.request.id"] !== requestId) {
6433
+ errors.push(
6434
+ err("BKN_TRACE_JOIN_FAILED", `$.logs[${index}]`, "log cannot join trace/request")
6435
+ );
6436
+ }
6437
+ if (!spanIds.has(String(log.span_id))) {
6438
+ errors.push(
6439
+ err("BKN_TRACE_JOIN_FAILED", `$.logs[${index}].span_id`, "log span_id not found")
6440
+ );
6441
+ }
6442
+ });
6443
+ const events = Array.isArray(root.events) ? root.events : [];
6444
+ const eventIds = /* @__PURE__ */ new Set();
6445
+ const knownEventIds = /* @__PURE__ */ new Set();
6446
+ const knownOperationIds = /* @__PURE__ */ new Set();
6447
+ const knownClaimIds = /* @__PURE__ */ new Set();
6448
+ const actionStates = /* @__PURE__ */ new Map();
6449
+ events.forEach((item, index) => {
6450
+ const event = asRecord(item);
6451
+ const eventPath = `$.events[${index}]`;
6452
+ checkRequired(event, REQUIRED_EVENT_FIELDS, `$.events[${index}]`, errors);
6453
+ checkTimestamp(event.observed_at, `$.events[${index}].observed_at`, errors);
6454
+ checkTimestamp(event.emitted_at, `$.events[${index}].emitted_at`, errors);
6455
+ if (event.trace_id !== traceId || event["bkn.request.id"] !== requestId) {
6456
+ errors.push(
6457
+ err("BKN_TRACE_JOIN_FAILED", `$.events[${index}]`, "event cannot join trace/request")
6458
+ );
6459
+ }
6460
+ if (!spanIds.has(String(event.span_id))) {
6461
+ errors.push(
6462
+ err("BKN_TRACE_JOIN_FAILED", `$.events[${index}].span_id`, "event span_id not found")
6463
+ );
6464
+ }
6465
+ if (typeof event.event_id === "string") {
6466
+ if (eventIds.has(event.event_id)) {
6467
+ errors.push(
6468
+ err("BKN_TRACE_EVENT_ID_CONFLICT", `${eventPath}.event_id`, "duplicate event_id")
6469
+ );
6470
+ }
6471
+ eventIds.add(event.event_id);
6472
+ }
6473
+ if (contractVersion !== BUSINESS_CONTRACT_VERSION) return;
6474
+ if (event["bkn.trace.schema.version"] !== contractVersion) {
6475
+ errors.push(
6476
+ err(
6477
+ "BKN_TRACE_SCHEMA_VERSION_UNSUPPORTED",
6478
+ `${eventPath}.bkn.trace.schema.version`,
6479
+ "event contract version must match the fixture envelope"
6480
+ )
6481
+ );
6482
+ }
6483
+ validateBusinessEvent(
6484
+ event,
6485
+ eventPath,
6486
+ knownEventIds,
6487
+ knownOperationIds,
6488
+ knownClaimIds,
6489
+ actionStates,
6490
+ errors
6491
+ );
6492
+ if (typeof event.event_id === "string") knownEventIds.add(event.event_id);
6493
+ if (typeof event.operation_id === "string") knownOperationIds.add(event.operation_id);
6494
+ if (event.event_type === "claim.created" && typeof event.claim_id === "string") {
6495
+ knownClaimIds.add(event.claim_id);
6496
+ }
6497
+ });
6498
+ if (contractVersion !== "1.0.0" && events.length === 0) {
6499
+ errors.push(err("BKN_TRACE_REQUIRED_FIELD_MISSING", "$.events", "at least one event required"));
6500
+ }
6501
+ const baggage = asRecord(root.baggage);
6502
+ for (const key of Object.keys(baggage)) {
6503
+ if (!ALLOWED_BAGGAGE2.has(key)) {
6504
+ errors.push(
6505
+ err(
6506
+ "BKN_TRACE_BAGGAGE_FORBIDDEN_FIELD",
6507
+ `$.baggage.${key}`,
6508
+ `baggage field ${key} is forbidden`
6509
+ )
6510
+ );
6511
+ }
6512
+ }
6513
+ checkSensitive(root, "$", errors);
6514
+ const result = errors.length > 0 ? "fail" : "pass";
6515
+ const expectedResult = root.expected_result === "pass" || root.expected_result === "fail" ? root.expected_result : null;
6516
+ return {
6517
+ fixtureId,
6518
+ result,
6519
+ contractVersion,
6520
+ errors,
6521
+ warnings: [],
6522
+ expectedResult,
6523
+ expectationMatched: expectedResult === null ? result === "pass" : expectedResult === result
6524
+ };
6525
+ }
6526
+ function validateBusinessEvent(event, path, knownEventIds, knownOperationIds, knownClaimIds, actionStates, errors) {
6527
+ const eventType = typeof event.event_type === "string" ? event.event_type : "";
6528
+ if (!BUSINESS_EVENT_TYPES.has(eventType)) {
6529
+ errors.push(
6530
+ err(
6531
+ "BKN_TRACE_EVENT_TYPE_UNSUPPORTED",
6532
+ `${path}.event_type`,
6533
+ `unsupported event ${eventType}`
6534
+ )
6535
+ );
6536
+ return;
6537
+ }
6538
+ checkRequired(event, ["interaction_id"], path, errors);
6539
+ if (eventType !== "agent.interaction.started" && eventType !== "claim.created") {
6540
+ checkRequired(event, ["operation_id"], path, errors);
6541
+ }
6542
+ if (eventType !== "agent.interaction.started") {
6543
+ checkRequired(event, ["causation_event_id"], path, errors);
6544
+ if (typeof event.causation_event_id === "string" && !knownEventIds.has(event.causation_event_id)) {
6545
+ errors.push(
6546
+ err(
6547
+ "BKN_TRACE_CAUSATION_INVALID",
6548
+ `${path}.causation_event_id`,
6549
+ "causation_event_id must reference an earlier event"
6550
+ )
6551
+ );
6552
+ }
6553
+ }
6554
+ if (CLAIM_EVENT_TYPES.has(eventType)) {
6555
+ checkRequired(event, ["claim_id"], path, errors);
6556
+ if (eventType !== "claim.created" && typeof event.claim_id === "string" && !knownClaimIds.has(event.claim_id)) {
6557
+ errors.push(
6558
+ err(
6559
+ "BKN_TRACE_UNKNOWN_CLAIM_ID",
6560
+ `${path}.claim_id`,
6561
+ "event must reference an earlier claim"
6562
+ )
6563
+ );
6564
+ }
6565
+ }
6566
+ const payload = asRecord(event.payload);
6567
+ checkAllowedKeys(
6568
+ payload,
6569
+ EVENT_PAYLOAD_FIELDS[eventType] ?? /* @__PURE__ */ new Set(),
6570
+ `${path}.payload`,
6571
+ errors
6572
+ );
6573
+ if (eventType === "agent.interaction.started") {
6574
+ checkRequired(payload, ["intent_hash", "mode"], `${path}.payload`, errors);
6575
+ checkOneOf(payload, ["agent_id", "app_ref"], `${path}.payload`, errors);
6576
+ }
6577
+ if (eventType === "retrieval.completed") {
6578
+ checkRequired(
6579
+ payload,
6580
+ ["query_hash", "candidate_count", "truncated"],
6581
+ `${path}.payload`,
6582
+ errors
6583
+ );
6584
+ }
6585
+ if (eventType === "knowledge.read.observed") {
6586
+ checkRequired(payload, ["kn_id", "read_kind", "version_status"], `${path}.payload`, errors);
6587
+ }
6588
+ if (eventType === "data.query.observed") {
6589
+ checkRequired(payload, ["query_hash", "query_type", "row_count"], `${path}.payload`, errors);
6590
+ }
6591
+ if (eventType === "model.call.observed") {
6592
+ checkRequired(
6593
+ payload,
6594
+ [
6595
+ "model_name",
6596
+ "model_provider",
6597
+ "status",
6598
+ "input_token_count",
6599
+ "output_token_count",
6600
+ "prompt_hash",
6601
+ "output_hash"
6602
+ ],
6603
+ `${path}.payload`,
6604
+ errors
6605
+ );
6606
+ if (payload.status === "error") {
6607
+ checkRequired(payload, ["error_category", "error_hash"], `${path}.payload`, errors);
6608
+ }
6609
+ }
6610
+ if (eventType === "claim.created") {
6611
+ checkRequired(
6612
+ payload,
6613
+ [
6614
+ "claim_id",
6615
+ "claim_type",
6616
+ "claim_hash",
6617
+ "source_event_ids",
6618
+ "operation_ids",
6619
+ "visibility",
6620
+ "version_status"
6621
+ ],
6622
+ `${path}.payload`,
6623
+ errors
6624
+ );
6625
+ checkNonEmptyArray(payload, "source_event_ids", `${path}.payload`, errors);
6626
+ checkNonEmptyArray(payload, "operation_ids", `${path}.payload`, errors);
6627
+ checkKnownArray(payload, "source_event_ids", knownEventIds, `${path}.payload`, errors);
6628
+ checkKnownArray(payload, "operation_ids", knownOperationIds, `${path}.payload`, errors);
6629
+ }
6630
+ if (eventType === "evidence.refs.created") {
6631
+ checkReferenceList(payload, "evidence_refs", `${path}.payload`, errors);
6632
+ }
6633
+ if (eventType === "business.refs.resolved") {
6634
+ checkRequired(payload, ["resolver_status"], `${path}.payload`, errors);
6635
+ checkReferenceList(
6636
+ payload,
6637
+ "business_refs",
6638
+ `${path}.payload`,
6639
+ errors,
6640
+ payload.resolver_status === "unresolved"
6641
+ );
6642
+ }
6643
+ const actionState = ACTION_STATE_BY_EVENT[eventType];
6644
+ if (!actionState) return;
6645
+ checkRequired(payload, ["action_instance_id", "status"], `${path}.payload`, errors);
6646
+ const fixedStatus = {
6647
+ "action.recommended": "recommended",
6648
+ "action.approval_requested": "approval_requested",
6649
+ "action.approved": "approved",
6650
+ "action.rejected": "rejected"
6651
+ };
6652
+ if (fixedStatus[eventType] && payload.status !== fixedStatus[eventType]) {
6653
+ errors.push(
6654
+ err(
6655
+ "BKN_TRACE_ACTION_TRANSITION_INVALID",
6656
+ `${path}.payload.status`,
6657
+ `${eventType} requires status=${fixedStatus[eventType]}`
6658
+ )
6659
+ );
6660
+ }
6661
+ if (eventType === "action.recommended") {
6662
+ checkRequired(
6663
+ payload,
6664
+ ["action_type", "target_refs", "reason_hash"],
6665
+ `${path}.payload`,
6666
+ errors
6667
+ );
6668
+ checkNonEmptyArray(payload, "target_refs", `${path}.payload`, errors);
6669
+ checkQualifiedStringRefs(payload, "target_refs", `${path}.payload`, errors);
6670
+ }
6671
+ if (eventType === "action.approval_requested") {
6672
+ checkRequired(payload, ["policy_ref"], `${path}.payload`, errors);
6673
+ }
6674
+ if (eventType === "action.approved" || eventType === "action.rejected") {
6675
+ checkRequired(payload, ["actor_ref", "policy_decision_ref"], `${path}.payload`, errors);
6676
+ }
6677
+ if (eventType === "action.executed") {
6678
+ checkOneOf(payload, ["invocation_ref", "tool_ref"], `${path}.payload`, errors);
6679
+ if (payload.status === "error") {
6680
+ checkRequired(payload, ["error_category", "error_hash"], `${path}.payload`, errors);
6681
+ }
6682
+ }
6683
+ if (eventType === "action.result_recorded") {
6684
+ checkRequired(payload, ["result_hash"], `${path}.payload`, errors);
6685
+ checkOneOf(payload, ["artifact_ref", "task_ref"], `${path}.payload`, errors);
6686
+ }
6687
+ const actionID = typeof payload.action_instance_id === "string" ? payload.action_instance_id : "";
6688
+ if (!actionID) return;
6689
+ const claimID = typeof event.claim_id === "string" ? event.claim_id : "";
6690
+ const operationID = typeof event.operation_id === "string" ? event.operation_id : "";
6691
+ const previous = actionStates.get(actionID);
6692
+ if (!previous && actionState !== "recommended" || previous && (!ACTION_TRANSITIONS[previous.state]?.has(actionState) || event.causation_event_id !== previous.lastEventID || claimID !== previous.claimID || operationID !== previous.operationID)) {
6693
+ errors.push(
6694
+ err(
6695
+ "BKN_TRACE_ACTION_TRANSITION_INVALID",
6696
+ `${path}.event_type`,
6697
+ `invalid action transition ${previous?.state ?? "<none>"} -> ${actionState}`
6698
+ )
6699
+ );
6700
+ return;
6701
+ }
6702
+ actionStates.set(actionID, {
6703
+ state: actionState,
6704
+ claimID,
6705
+ operationID,
6706
+ lastEventID: String(event.event_id ?? "")
6707
+ });
6708
+ }
6709
+ function checkOneOf(payload, fields, path, errors) {
6710
+ if (fields.some((field) => typeof payload[field] === "string" && payload[field] !== "")) return;
6711
+ errors.push(
6712
+ err(
6713
+ "BKN_TRACE_REQUIRED_FIELD_MISSING",
6714
+ `${path}.${fields[0]}`,
6715
+ `one of ${fields.join(" or ")} is required`
6716
+ )
6717
+ );
6718
+ }
6719
+ function checkNonEmptyArray(payload, field, path, errors) {
6720
+ if (Array.isArray(payload[field]) && payload[field].length > 0) return;
6721
+ errors.push(
6722
+ err(
6723
+ "BKN_TRACE_REQUIRED_FIELD_MISSING",
6724
+ `${path}.${field}`,
6725
+ `${field} must be a non-empty array`
6726
+ )
6727
+ );
6728
+ }
6729
+ function checkReferenceList(payload, field, path, errors, allowEmpty = false) {
6730
+ if (!allowEmpty) checkNonEmptyArray(payload, field, path, errors);
6731
+ const refs = Array.isArray(payload[field]) ? payload[field] : [];
6732
+ refs.forEach((value, index) => {
6733
+ const ref = asRecord(value);
6734
+ checkRequired(
6735
+ ref,
6736
+ ["ref_id", "ref_type", "source_system", "validity", "version_status", "visibility"],
6737
+ `${path}.${field}[${index}]`,
6738
+ errors
6739
+ );
6740
+ checkAllowedKeys(ref, REFERENCE_FIELDS, `${path}.${field}[${index}]`, errors);
6741
+ if (typeof ref.ref_id === "string" && !isQualifiedReference(ref.ref_id)) {
6742
+ errors.push(
6743
+ err(
6744
+ "BKN_TRACE_REFERENCE_ID_INVALID",
6745
+ `${path}.${field}[${index}].ref_id`,
6746
+ "business reference id must include its knowledge-network or resource scope"
6747
+ )
6748
+ );
6749
+ }
6750
+ });
6751
+ }
6752
+ function checkQualifiedStringRefs(payload, field, path, errors) {
6753
+ const refs = Array.isArray(payload[field]) ? payload[field] : [];
6754
+ refs.forEach((value, index) => {
6755
+ if (typeof value !== "string" || isQualifiedReference(value)) return;
6756
+ errors.push(
6757
+ err(
6758
+ "BKN_TRACE_REFERENCE_ID_INVALID",
6759
+ `${path}.${field}[${index}]`,
6760
+ "business reference id must include its knowledge-network or resource scope"
6761
+ )
6762
+ );
6763
+ });
6764
+ }
6765
+ function isQualifiedReference(value) {
6766
+ const parts = value.trim().split(":");
6767
+ if (parts.some((part) => part.length === 0)) return false;
6768
+ if (["kn", "resource"].includes(parts[0] ?? "")) return parts.length === 2;
6769
+ if (["object", "relation", "action_type", "metric", "field"].includes(parts[0] ?? "")) {
6770
+ return parts.length === 3;
6771
+ }
6772
+ if (parts[0] === "property") return parts.length === 4;
6773
+ return true;
6774
+ }
6775
+ function checkKnownArray(payload, field, known, path, errors) {
6776
+ if (!Array.isArray(payload[field])) return;
6777
+ for (const value of payload[field]) {
6778
+ if (typeof value === "string" && known.has(value)) continue;
6779
+ errors.push(
6780
+ err(
6781
+ "BKN_TRACE_CAUSATION_INVALID",
6782
+ `${path}.${field}`,
6783
+ `${field} must reference earlier events or operations`
6784
+ )
6785
+ );
6786
+ }
6787
+ }
6788
+ function checkAllowedKeys(value, allowed, path, errors) {
6789
+ for (const key of Object.keys(value)) {
6790
+ if (allowed.has(key)) continue;
6791
+ errors.push(
6792
+ err(
6793
+ "BKN_TRACE_EVENT_PAYLOAD_FIELD_UNSUPPORTED",
6794
+ `${path}.${key}`,
6795
+ `payload field ${key} is not registered for this event`
6796
+ )
6797
+ );
6798
+ }
6799
+ }
6800
+ function validateFixturePath(path) {
6801
+ const results = jsonFiles(path).map((file) => {
6802
+ try {
6803
+ return validateFixture(JSON.parse(readFileSync4(file, "utf8")));
6804
+ } catch (e) {
6805
+ return {
6806
+ fixtureId: file,
6807
+ result: "fail",
6808
+ contractVersion: null,
6809
+ errors: [
6810
+ err(
6811
+ "BKN_TRACE_FIXTURE_PARSE_FAILED",
6812
+ "$",
6813
+ `failed to parse JSON: ${e instanceof Error ? e.message : String(e)}`
6814
+ )
6815
+ ],
6816
+ warnings: [],
6817
+ expectedResult: null,
6818
+ expectationMatched: false
6819
+ };
6820
+ }
6821
+ });
6822
+ return { ok: results.every((r) => r.expectationMatched), results };
6823
+ }
6824
+
5147
6825
  // src/resources/trace.ts
5148
6826
  async function semanticJudge(question, answer, reference) {
5149
6827
  const prompt = [
@@ -5190,6 +6868,32 @@ function trace(ctx) {
5190
6868
  return {
5191
6869
  /** Raw trace search (OpenSearch-style body). */
5192
6870
  search: (body) => traceSearch(ctx, body),
6871
+ /** Submit BKN Trace phase-two claim/evidence/business events. */
6872
+ emitEvidenceEvents: (body) => emitEvidenceEvents(ctx, body),
6873
+ /** Store one authorized BKN Trace 2.2 business-content artifact. */
6874
+ emitArtifact: (body) => emitEvidenceArtifact(ctx, body),
6875
+ /** Read one authorized BKN Trace 2.2 business-content artifact. */
6876
+ artifact: (artifactId) => getEvidenceArtifact(ctx, artifactId),
6877
+ /** Product-facing business request list and request-to-trace drilldown. */
6878
+ requests: {
6879
+ get: (requestId) => getRequestSummary(ctx, requestId),
6880
+ list: (query) => listRequestSummaries(ctx, query),
6881
+ traces: (requestId, query) => getRequestTraces(ctx, requestId, query)
6882
+ },
6883
+ /** Aggregate all OpenBKN requests and traces for one caller-owned interaction. */
6884
+ interactions: {
6885
+ get: (interactionId) => getInteractionSummary(ctx, interactionId)
6886
+ },
6887
+ /** Create a typed BKN Trace 2.1 session for an Agent or AI application. */
6888
+ createSession: (options) => new TraceSession({ ...options, emit: (body) => emitEvidenceEvents(ctx, body) }),
6889
+ /** Normalized trace tree/status graph by trace id. */
6890
+ graph: (traceId) => getTraceGraph(ctx, traceId),
6891
+ /** Claim -> evidence/business refs graph by trace id or BKN request id. */
6892
+ evidenceChain: (scope, opts) => getEvidenceChain(ctx, scope, opts),
6893
+ /** Business semantic graph by trace id or BKN request id. */
6894
+ businessGraph: (scope, opts) => getBusinessGraph(ctx, scope, opts),
6895
+ /** Metadata-only evidence snapshot preview by trace id or BKN request id. */
6896
+ snapshotPreview: (scope, opts) => getSnapshotPreview(ctx, scope, opts),
5193
6897
  /** All span source docs for a conversation. */
5194
6898
  spans: (conversationId, opts) => getSpansByConversation(ctx, conversationId, opts),
5195
6899
  diagnose: diagnoseOne,
@@ -5227,6 +6931,8 @@ function trace(ctx) {
5227
6931
  },
5228
6932
  /** Build eval cases from a loosely-shaped queries object/array. */
5229
6933
  evalSetBuild: (raw) => buildCasesFromQueries(raw),
6934
+ /** Validate BKN Trace phase-one fixture files or directories. */
6935
+ validateFixture: (path) => validateFixturePath(path),
5230
6936
  /**
5231
6937
  * Run an eval set against an agent: each case's query is sent to the agent,
5232
6938
  * the resulting trace is fetched, and assertions are checked. `llm` enables
@@ -5266,7 +6972,7 @@ function vega(ctx) {
5266
6972
  deleteCatalog: (id) => deleteCatalog(ctx, id),
5267
6973
  testCatalogConnection: (id) => testCatalogConnection(ctx, id),
5268
6974
  discoverCatalog: (id, wait = false) => discoverCatalog(ctx, id, wait),
5269
- catalogResources: (id, category) => listCatalogResources(ctx, id, category),
6975
+ catalogResources: (id, category, limit, offset) => listCatalogResources(ctx, id, category, limit, offset),
5270
6976
  catalogHealth: (ids) => catalogHealthStatus(ctx, ids),
5271
6977
  connectorTypes: () => listConnectorTypes(ctx),
5272
6978
  connectorType: (type) => getConnectorType(ctx, type),
@@ -5300,7 +7006,7 @@ function sleep(ms) {
5300
7006
  }
5301
7007
 
5302
7008
  // src/api/call.ts
5303
- import { readFileSync as readFileSync4 } from "fs";
7009
+ import { readFileSync as readFileSync5 } from "fs";
5304
7010
  function parseHeader(raw) {
5305
7011
  const idx = raw.indexOf(":");
5306
7012
  if (idx <= 0) return null;
@@ -5329,7 +7035,7 @@ async function rawCall(ctx, path, opts = {}) {
5329
7035
  const fd = new FormData();
5330
7036
  for (const field of opts.form) {
5331
7037
  const [key, value, isFile] = parseFormField(field);
5332
- if (isFile) fd.append(key, new Blob([readFileSync4(value)]), value.split("/").pop());
7038
+ if (isFile) fd.append(key, new Blob([readFileSync5(value)]), value.split("/").pop());
5333
7039
  else fd.append(key, value);
5334
7040
  }
5335
7041
  body = fd;
@@ -5639,6 +7345,8 @@ export {
5639
7345
  skills,
5640
7346
  toolboxes,
5641
7347
  renderReportMarkdown,
7348
+ validateFixturePath,
7349
+ TraceSession,
5642
7350
  trace,
5643
7351
  vega,
5644
7352
  createClient,
@@ -5655,4 +7363,4 @@ export {
5655
7363
  exportCreds,
5656
7364
  auth_exports
5657
7365
  };
5658
- //# sourceMappingURL=chunk-NC6DZ2AU.js.map
7366
+ //# sourceMappingURL=chunk-LH3ONZGQ.js.map