@openbkn/bkn-sdk 0.1.2 → 0.1.3
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/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/{chunk-LH3ONZGQ.js → chunk-PC2F54XD.js} +1204 -917
- package/dist/cli.js +335 -74
- package/dist/index.d.ts +1287 -452
- package/dist/index.js +9 -3
- package/package.json +4 -4
|
@@ -20,6 +20,14 @@ var HttpError = class extends Error {
|
|
|
20
20
|
this.hint = hint;
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
|
+
var ToolError = class extends Error {
|
|
24
|
+
code;
|
|
25
|
+
constructor(message, code) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "ToolError";
|
|
28
|
+
if (code) this.code = code;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
23
31
|
var InputError = class extends Error {
|
|
24
32
|
constructor(message) {
|
|
25
33
|
super(message);
|
|
@@ -38,14 +46,15 @@ function formatError(err2) {
|
|
|
38
46
|
if (err2 instanceof HttpError) {
|
|
39
47
|
const serverMsg = serverError(err2.body);
|
|
40
48
|
if (err2.status === 401) {
|
|
41
|
-
const
|
|
42
|
-
return `Not authorized (HTTP 401)${serverMsg ? `: ${serverMsg}` : ""}. ${
|
|
49
|
+
const next2 = err2.hint ?? "Run `openbkn auth login` and retry.";
|
|
50
|
+
return `Not authorized (HTTP 401)${serverMsg ? `: ${serverMsg}` : ""}. ${next2}`;
|
|
43
51
|
}
|
|
44
52
|
if (err2.status === 403) {
|
|
45
53
|
return `Forbidden (HTTP 403)${serverMsg ? `: ${serverMsg}` : " \u2014 admin privileges required"}.`;
|
|
46
54
|
}
|
|
47
55
|
const detail = err2.body ? `: ${truncate(err2.body, 500)}` : "";
|
|
48
|
-
|
|
56
|
+
const next = err2.hint ? ` ${err2.hint}` : "";
|
|
57
|
+
return `Request failed (HTTP ${err2.status} ${err2.statusText})${detail}${next}`;
|
|
49
58
|
}
|
|
50
59
|
if (err2 instanceof Error) {
|
|
51
60
|
const cause = err2.cause;
|
|
@@ -81,10 +90,23 @@ import { spawn } from "child_process";
|
|
|
81
90
|
|
|
82
91
|
// src/api/tls.ts
|
|
83
92
|
import { Agent, FormData as UndiciFormData, fetch as undiciFetch } from "undici";
|
|
84
|
-
var
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
var UNDICI_HEADERS_TIMEOUT_MS = 3e5;
|
|
94
|
+
var agents = /* @__PURE__ */ new Map();
|
|
95
|
+
function dispatcherFor(insecure, headersTimeoutMs) {
|
|
96
|
+
const key = `${insecure}|${headersTimeoutMs ?? ""}`;
|
|
97
|
+
let agent = agents.get(key);
|
|
98
|
+
if (!agent) {
|
|
99
|
+
agent = new Agent({
|
|
100
|
+
...insecure ? { connect: { rejectUnauthorized: false } } : {},
|
|
101
|
+
...headersTimeoutMs === void 0 ? {} : (
|
|
102
|
+
// undici also enforces a body deadline; a request that waits this
|
|
103
|
+
// long for headers is not going to stream its body any faster.
|
|
104
|
+
{ headersTimeout: headersTimeoutMs, bodyTimeout: headersTimeoutMs }
|
|
105
|
+
)
|
|
106
|
+
});
|
|
107
|
+
agents.set(key, agent);
|
|
108
|
+
}
|
|
109
|
+
return agent;
|
|
88
110
|
}
|
|
89
111
|
function isFormData(body) {
|
|
90
112
|
return typeof body === "object" && body !== null && body[Symbol.toStringTag] === "FormData";
|
|
@@ -98,12 +120,13 @@ function toUndiciBody(body) {
|
|
|
98
120
|
}
|
|
99
121
|
return form2;
|
|
100
122
|
}
|
|
101
|
-
function tlsFetch(insecure, url, init) {
|
|
102
|
-
|
|
123
|
+
function tlsFetch(insecure, url, init, headersTimeoutMs) {
|
|
124
|
+
const needsAgent = headersTimeoutMs !== void 0 && headersTimeoutMs > UNDICI_HEADERS_TIMEOUT_MS;
|
|
125
|
+
if (!insecure && !needsAgent) return fetch(url, init);
|
|
103
126
|
return undiciFetch(url, {
|
|
104
127
|
...init,
|
|
105
128
|
...init?.body === void 0 || init?.body === null ? {} : { body: toUndiciBody(init.body) },
|
|
106
|
-
dispatcher:
|
|
129
|
+
dispatcher: dispatcherFor(insecure === true, needsAgent ? headersTimeoutMs : void 0)
|
|
107
130
|
});
|
|
108
131
|
}
|
|
109
132
|
|
|
@@ -426,33 +449,59 @@ async function request(ctx, path, init = {}) {
|
|
|
426
449
|
const hasBody = init.body !== void 0;
|
|
427
450
|
const controller = new AbortController();
|
|
428
451
|
const timer = setTimeout(() => controller.abort(), init.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
429
|
-
const send = () => tlsFetch(
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
452
|
+
const send = () => tlsFetch(
|
|
453
|
+
ctx.insecure,
|
|
454
|
+
url,
|
|
455
|
+
{
|
|
456
|
+
method: init.method ?? (hasBody ? "POST" : "GET"),
|
|
457
|
+
headers: buildHeaders(ctx, {
|
|
458
|
+
...hasBody ? { "content-type": "application/json" } : {},
|
|
459
|
+
...init.headers
|
|
460
|
+
}),
|
|
461
|
+
body: hasBody ? JSON.stringify(init.body) : void 0,
|
|
462
|
+
redirect: init.redirect,
|
|
463
|
+
signal: controller.signal
|
|
464
|
+
},
|
|
465
|
+
init.headersTimeoutMs
|
|
466
|
+
);
|
|
439
467
|
try {
|
|
440
468
|
let res = await send();
|
|
441
469
|
if (res.status === 401 && ctx.refresh && await tryRefresh(ctx)) {
|
|
442
470
|
res = await send();
|
|
443
471
|
}
|
|
444
472
|
const text = await res.text();
|
|
445
|
-
if (!res.ok)
|
|
473
|
+
if (!res.ok) {
|
|
474
|
+
throw new HttpError(res.status, res.statusText, text, hintFor(ctx, res.status, text));
|
|
475
|
+
}
|
|
446
476
|
return text ? JSON.parse(text) : void 0;
|
|
447
477
|
} finally {
|
|
448
478
|
clearTimeout(timer);
|
|
449
479
|
}
|
|
450
480
|
}
|
|
451
|
-
function hintFor(ctx, status2) {
|
|
481
|
+
function hintFor(ctx, status2, body) {
|
|
452
482
|
if (status2 === 401 && ctx.token.startsWith("bak_")) {
|
|
453
483
|
return "AppKey invalid / expired / revoked / owner disabled \u2014 re-issue with `openbkn appkey create` (or `appkey regenerate <id>`). Do not auto-retry.";
|
|
454
484
|
}
|
|
455
|
-
return
|
|
485
|
+
return lifecycleHint(body);
|
|
486
|
+
}
|
|
487
|
+
var LIFECYCLE_ACTIONS = /* @__PURE__ */ new Set([
|
|
488
|
+
"create_conversation",
|
|
489
|
+
"start_interaction",
|
|
490
|
+
"ensure_operation",
|
|
491
|
+
"bkn_start_interaction"
|
|
492
|
+
]);
|
|
493
|
+
function lifecycleHint(body) {
|
|
494
|
+
if (!LIFECYCLE_ACTIONS.has(requiredAction(body) ?? "")) return void 0;
|
|
495
|
+
return "This deploy requires a managed lifecycle session: the request needs a `bkn_context` with conversation_id and interaction_id. Easiest fix: use the `openbkn bkn` / `openbkn context` commands, which open and release one for you. To do it by hand, check `openbkn context info` for the deploy's lifecycle tools \u2014 where it lists `bkn_create_conversation`, call that first and pass the conversation_id it returns to `bkn_start_interaction`; where it does not, `bkn_start_interaction` alone returns both ids. Either way: `openbkn context tool-call <kn-id> <tool> --args '{...}'`.";
|
|
496
|
+
}
|
|
497
|
+
function requiredAction(body) {
|
|
498
|
+
try {
|
|
499
|
+
const parsed = JSON.parse(body);
|
|
500
|
+
const action = parsed.error?.required_action;
|
|
501
|
+
return typeof action === "string" ? action : void 0;
|
|
502
|
+
} catch {
|
|
503
|
+
return void 0;
|
|
504
|
+
}
|
|
456
505
|
}
|
|
457
506
|
async function tryRefresh(ctx) {
|
|
458
507
|
if (!ctx.refresh) return false;
|
|
@@ -1194,7 +1243,7 @@ function setSkillMembers(agent, members) {
|
|
|
1194
1243
|
if (!config.skills || typeof config.skills !== "object") config.skills = {};
|
|
1195
1244
|
config.skills.skills = members;
|
|
1196
1245
|
}
|
|
1197
|
-
function
|
|
1246
|
+
function agents2(ctx) {
|
|
1198
1247
|
return {
|
|
1199
1248
|
list: (opts) => listAgents(ctx, opts),
|
|
1200
1249
|
get: (agentId) => getAgent(ctx, agentId),
|
|
@@ -1243,6 +1292,9 @@ function agents(ctx) {
|
|
|
1243
1292
|
};
|
|
1244
1293
|
}
|
|
1245
1294
|
|
|
1295
|
+
// src/api/lifecycle.ts
|
|
1296
|
+
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
1297
|
+
|
|
1246
1298
|
// src/api/context-loader.ts
|
|
1247
1299
|
var MCP_PATH = "/api/agent-retrieval/v1/mcp";
|
|
1248
1300
|
var PROTOCOL = "2024-11-05";
|
|
@@ -1280,18 +1332,25 @@ function parseBody(text) {
|
|
|
1280
1332
|
throw new Error(`Context-loader returned invalid JSON: ${text.slice(0, 200)}`);
|
|
1281
1333
|
}
|
|
1282
1334
|
}
|
|
1283
|
-
async function post(ctx, knId, sessionId, body) {
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1335
|
+
async function post(ctx, knId, sessionId, body, timeoutMs) {
|
|
1336
|
+
const controller = timeoutMs === void 0 ? void 0 : new AbortController();
|
|
1337
|
+
const timer = controller === void 0 ? void 0 : setTimeout(() => controller.abort(), timeoutMs);
|
|
1338
|
+
try {
|
|
1339
|
+
const res = await authFetch(
|
|
1340
|
+
ctx,
|
|
1341
|
+
() => tlsFetch(ctx.insecure, mcpUrl(ctx), {
|
|
1342
|
+
method: "POST",
|
|
1343
|
+
headers: headers(ctx, knId, sessionId),
|
|
1344
|
+
body: JSON.stringify(body),
|
|
1345
|
+
...controller ? { signal: controller.signal } : {}
|
|
1346
|
+
})
|
|
1347
|
+
);
|
|
1348
|
+
const text = await res.text();
|
|
1349
|
+
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
1350
|
+
return { res, text };
|
|
1351
|
+
} finally {
|
|
1352
|
+
if (timer) clearTimeout(timer);
|
|
1353
|
+
}
|
|
1295
1354
|
}
|
|
1296
1355
|
async function ensureSession(ctx, knId) {
|
|
1297
1356
|
const key = `${mcpUrl(ctx)}:${knId}`;
|
|
@@ -1314,31 +1373,103 @@ async function ensureSession(ctx, knId) {
|
|
|
1314
1373
|
sessions.set(key, { id: sessionId, at: Date.now() });
|
|
1315
1374
|
return sessionId;
|
|
1316
1375
|
}
|
|
1317
|
-
function
|
|
1376
|
+
function toolErrorCode(structuredContent) {
|
|
1377
|
+
const code = structuredContent?.error?.code;
|
|
1378
|
+
return typeof code === "string" ? code : void 0;
|
|
1379
|
+
}
|
|
1380
|
+
function unwrapToolResult(parsed) {
|
|
1318
1381
|
const rpc = parsed;
|
|
1319
1382
|
if (rpc.error) throw new Error(`Context-loader error: ${rpc.error.message}`);
|
|
1320
1383
|
const result = rpc.result;
|
|
1321
|
-
if (result === void 0) return parsed;
|
|
1384
|
+
if (result === void 0) return { value: parsed };
|
|
1385
|
+
const structuredContent = result.structuredContent;
|
|
1386
|
+
const receipt = structuredContent?.bkn_receipt;
|
|
1322
1387
|
const content = result.content;
|
|
1388
|
+
if (result.isError === true) {
|
|
1389
|
+
const message = Array.isArray(content) && content[0] && typeof content[0].text === "string" ? content[0].text : "tool call failed";
|
|
1390
|
+
throw new ToolError(`Context-loader error: ${message}`, toolErrorCode(structuredContent));
|
|
1391
|
+
}
|
|
1323
1392
|
if (Array.isArray(content) && content[0] && typeof content[0].text === "string") {
|
|
1324
1393
|
try {
|
|
1325
|
-
return JSON.parse(content[0].text);
|
|
1394
|
+
return { value: JSON.parse(content[0].text), receipt };
|
|
1326
1395
|
} catch {
|
|
1327
|
-
|
|
1396
|
+
if (structuredContent !== void 0) {
|
|
1397
|
+
return { value: structuredContent, receipt };
|
|
1398
|
+
}
|
|
1399
|
+
return { value: { raw: content[0].text }, receipt };
|
|
1328
1400
|
}
|
|
1329
1401
|
}
|
|
1330
|
-
return result;
|
|
1402
|
+
return { value: result, receipt };
|
|
1403
|
+
}
|
|
1404
|
+
function toolCallParams(name, args, options) {
|
|
1405
|
+
const meta = {
|
|
1406
|
+
...options?.hostConversationKey ? { "openbkn.ai/host-conversation-key": options.hostConversationKey } : {},
|
|
1407
|
+
...options?.clientInvocationId ? { "openbkn.ai/client-invocation-id": options.clientInvocationId } : {}
|
|
1408
|
+
};
|
|
1409
|
+
return {
|
|
1410
|
+
name,
|
|
1411
|
+
arguments: args,
|
|
1412
|
+
...Object.keys(meta).length > 0 ? { _meta: meta } : {}
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
async function callToolRaw(ctx, knId, name, args, options, timeoutMs) {
|
|
1416
|
+
const operationCtx = operationContext(ctx);
|
|
1417
|
+
const sessionId = await ensureSession(operationCtx, knId);
|
|
1418
|
+
const { text } = await post(
|
|
1419
|
+
operationCtx,
|
|
1420
|
+
knId,
|
|
1421
|
+
sessionId,
|
|
1422
|
+
{
|
|
1423
|
+
jsonrpc: "2.0",
|
|
1424
|
+
method: "tools/call",
|
|
1425
|
+
params: toolCallParams(name, args, options),
|
|
1426
|
+
id: nextId()
|
|
1427
|
+
},
|
|
1428
|
+
timeoutMs
|
|
1429
|
+
);
|
|
1430
|
+
return unwrapToolResult(parseBody(text)).value;
|
|
1431
|
+
}
|
|
1432
|
+
var LIFECYCLE_TOOLS = /* @__PURE__ */ new Set([
|
|
1433
|
+
"bkn_create_conversation",
|
|
1434
|
+
"bkn_resume_conversation",
|
|
1435
|
+
"bkn_start_interaction",
|
|
1436
|
+
"bkn_complete_interaction",
|
|
1437
|
+
"bkn_finish_interaction",
|
|
1438
|
+
"bkn_fail_interaction",
|
|
1439
|
+
"bkn_cancel_interaction",
|
|
1440
|
+
"bkn_handoff_interaction",
|
|
1441
|
+
"bkn_close_conversation",
|
|
1442
|
+
"bkn_get_operation",
|
|
1443
|
+
"bkn_retry_operation",
|
|
1444
|
+
"bkn_get_receipt"
|
|
1445
|
+
]);
|
|
1446
|
+
function callTool(ctx, knId, name, args, options) {
|
|
1447
|
+
if (LIFECYCLE_TOOLS.has(name)) return callToolRaw(ctx, knId, name, args, options);
|
|
1448
|
+
if (args.bkn_context !== void 0) return callToolRaw(ctx, knId, name, args, options);
|
|
1449
|
+
return withManagedLifecycle(
|
|
1450
|
+
ctx,
|
|
1451
|
+
knId,
|
|
1452
|
+
questionFor(name, args),
|
|
1453
|
+
(bknContext) => callToolRaw(ctx, knId, name, bknContext ? { ...args, bkn_context: bknContext } : args, options)
|
|
1454
|
+
);
|
|
1455
|
+
}
|
|
1456
|
+
function questionFor(name, args) {
|
|
1457
|
+
return typeof args.query === "string" && args.query ? args.query : name;
|
|
1331
1458
|
}
|
|
1332
|
-
async function
|
|
1459
|
+
async function callManagedTool(ctx, knId, name, args, options) {
|
|
1333
1460
|
const operationCtx = operationContext(ctx);
|
|
1334
1461
|
const sessionId = await ensureSession(operationCtx, knId);
|
|
1335
1462
|
const { text } = await post(operationCtx, knId, sessionId, {
|
|
1336
1463
|
jsonrpc: "2.0",
|
|
1337
1464
|
method: "tools/call",
|
|
1338
|
-
params:
|
|
1465
|
+
params: toolCallParams(name, args, options),
|
|
1339
1466
|
id: nextId()
|
|
1340
1467
|
});
|
|
1341
|
-
|
|
1468
|
+
const result = unwrapToolResult(parseBody(text));
|
|
1469
|
+
if (!result.receipt) {
|
|
1470
|
+
throw new Error("Context-loader managed tool response did not include bkn_receipt");
|
|
1471
|
+
}
|
|
1472
|
+
return { value: result.value, receipt: result.receipt };
|
|
1342
1473
|
}
|
|
1343
1474
|
async function callMethod(ctx, knId, method, params = {}) {
|
|
1344
1475
|
const operationCtx = operationContext(ctx);
|
|
@@ -1406,6 +1537,225 @@ function getPrompt(ctx, knId, name, args = {}) {
|
|
|
1406
1537
|
return callMethod(ctx, knId, "prompts/get", { name, arguments: args });
|
|
1407
1538
|
}
|
|
1408
1539
|
|
|
1540
|
+
// src/api/lifecycle.ts
|
|
1541
|
+
var V1_MARKER = "bkn_create_conversation";
|
|
1542
|
+
var V2_MARKER = "bkn_start_interaction";
|
|
1543
|
+
var STALE_SESSION_CODES = /* @__PURE__ */ new Set([
|
|
1544
|
+
"conversation_required",
|
|
1545
|
+
"interaction_required",
|
|
1546
|
+
"interaction_terminal",
|
|
1547
|
+
"interaction_in_progress",
|
|
1548
|
+
"lease_expired",
|
|
1549
|
+
"lease_invalid",
|
|
1550
|
+
"lease_superseded"
|
|
1551
|
+
]);
|
|
1552
|
+
var PROCESS_ID = randomUUID2();
|
|
1553
|
+
var generation = 0;
|
|
1554
|
+
var AGENT_NAME = "openbkn-sdk";
|
|
1555
|
+
var RELEASE_TIMEOUT_MS = 3e3;
|
|
1556
|
+
var contracts = /* @__PURE__ */ new Map();
|
|
1557
|
+
var PROBE_FAILURE_TTL_MS = 3e4;
|
|
1558
|
+
var probeFailures = /* @__PURE__ */ new Map();
|
|
1559
|
+
var sessions2 = /* @__PURE__ */ new Map();
|
|
1560
|
+
function lifecycleContract(ctx) {
|
|
1561
|
+
const failureKey = `${ctx.baseUrl}\0${identityOf(ctx)}`;
|
|
1562
|
+
const failedAt = probeFailures.get(failureKey);
|
|
1563
|
+
if (failedAt !== void 0) {
|
|
1564
|
+
if (Date.now() - failedAt < PROBE_FAILURE_TTL_MS) return Promise.resolve("none");
|
|
1565
|
+
probeFailures.delete(failureKey);
|
|
1566
|
+
}
|
|
1567
|
+
let pending = contracts.get(ctx.baseUrl);
|
|
1568
|
+
if (!pending) {
|
|
1569
|
+
pending = mcpInfo(ctx).then((info) => {
|
|
1570
|
+
const names = toolNames(info);
|
|
1571
|
+
if (names.includes(V1_MARKER)) return "managed-v1";
|
|
1572
|
+
return names.includes(V2_MARKER) ? "managed-v2" : "none";
|
|
1573
|
+
});
|
|
1574
|
+
contracts.set(ctx.baseUrl, pending);
|
|
1575
|
+
pending.catch((err2) => {
|
|
1576
|
+
contracts.delete(ctx.baseUrl);
|
|
1577
|
+
if (!isAuthFailure(err2)) probeFailures.set(failureKey, Date.now());
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
return pending.catch(() => "none");
|
|
1581
|
+
}
|
|
1582
|
+
function isAuthFailure(err2) {
|
|
1583
|
+
return err2 instanceof HttpError && (err2.status === 401 || err2.status === 403);
|
|
1584
|
+
}
|
|
1585
|
+
function toolNames(info) {
|
|
1586
|
+
const tools = info?.tools;
|
|
1587
|
+
if (!Array.isArray(tools)) return [];
|
|
1588
|
+
return tools.flatMap((tool) => typeof tool?.name === "string" ? [tool.name] : []);
|
|
1589
|
+
}
|
|
1590
|
+
function callerOwnedSession(ctx) {
|
|
1591
|
+
const conversationId = ctx.trace?.conversationId;
|
|
1592
|
+
const interactionId = ctx.trace?.interactionId;
|
|
1593
|
+
return conversationId && interactionId ? { conversationId, interactionId } : void 0;
|
|
1594
|
+
}
|
|
1595
|
+
function readId(result, field, tool) {
|
|
1596
|
+
const value = result?.[field];
|
|
1597
|
+
if (typeof value !== "string" || !value) {
|
|
1598
|
+
throw new Error(`Managed lifecycle: ${tool} returned no ${field}.`);
|
|
1599
|
+
}
|
|
1600
|
+
return value;
|
|
1601
|
+
}
|
|
1602
|
+
function callerNamedConversation(ctx) {
|
|
1603
|
+
return ctx.trace?.interactionId ? void 0 : ctx.trace?.conversationId;
|
|
1604
|
+
}
|
|
1605
|
+
async function openSession(ctx, knId, contract, question) {
|
|
1606
|
+
generation += 1;
|
|
1607
|
+
const named = callerNamedConversation(ctx);
|
|
1608
|
+
if (contract === "managed-v2") {
|
|
1609
|
+
const started2 = await callToolRaw(ctx, knId, V2_MARKER, {
|
|
1610
|
+
question,
|
|
1611
|
+
// The name is fixed when the conversation is created, so it belongs only
|
|
1612
|
+
// on the call that creates one. Joining a conversation the caller named
|
|
1613
|
+
// and relabelling it `openbkn-sdk` would rewrite their attribution — the
|
|
1614
|
+
// v1 join below has always omitted it, and this is the same decision.
|
|
1615
|
+
...named ? { conversation_id: named } : (
|
|
1616
|
+
// Display-only, but the only thing separating a session the SDK
|
|
1617
|
+
// opened from a real agent's in a Trace listing.
|
|
1618
|
+
{ agent_name: AGENT_NAME }
|
|
1619
|
+
)
|
|
1620
|
+
});
|
|
1621
|
+
return {
|
|
1622
|
+
contract,
|
|
1623
|
+
ctx,
|
|
1624
|
+
knId,
|
|
1625
|
+
conversationId: readId(started2, "conversation_id", V2_MARKER),
|
|
1626
|
+
interactionId: readId(started2, "interaction_id", V2_MARKER)
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
if (named) {
|
|
1630
|
+
const started2 = await callToolRaw(ctx, knId, V2_MARKER, {
|
|
1631
|
+
conversation_id: named,
|
|
1632
|
+
idempotency_key: `start:${PROCESS_ID}:${generation}`,
|
|
1633
|
+
question
|
|
1634
|
+
});
|
|
1635
|
+
return {
|
|
1636
|
+
contract,
|
|
1637
|
+
ctx,
|
|
1638
|
+
knId,
|
|
1639
|
+
conversationId: named,
|
|
1640
|
+
interactionId: readId(started2, "interaction_id", V2_MARKER)
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
const conversation = await callToolRaw(ctx, knId, V1_MARKER, {
|
|
1644
|
+
external_conversation_key: `cli:${PROCESS_ID}:${generation}`,
|
|
1645
|
+
// Nothing closes this conversation: a CLI invocation has no answer to close
|
|
1646
|
+
// over, and v1's closure manifest must enumerate every operation it
|
|
1647
|
+
// produced. one_shot hands it to the server's idle sweeper instead.
|
|
1648
|
+
one_shot: true
|
|
1649
|
+
});
|
|
1650
|
+
const conversationId = readId(conversation, "conversation_id", V1_MARKER);
|
|
1651
|
+
const started = await callToolRaw(ctx, knId, V2_MARKER, {
|
|
1652
|
+
conversation_id: conversationId,
|
|
1653
|
+
idempotency_key: `start:${PROCESS_ID}:${generation}`,
|
|
1654
|
+
question
|
|
1655
|
+
});
|
|
1656
|
+
return {
|
|
1657
|
+
contract,
|
|
1658
|
+
ctx,
|
|
1659
|
+
knId,
|
|
1660
|
+
conversationId,
|
|
1661
|
+
interactionId: readId(started, "interaction_id", V2_MARKER)
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
function identityOf(ctx) {
|
|
1665
|
+
return createHash("sha256").update(`${ctx.token}\0${ctx.businessDomain}`).digest("hex").slice(0, 16);
|
|
1666
|
+
}
|
|
1667
|
+
function sessionKey(ctx, knId) {
|
|
1668
|
+
return `${ctx.baseUrl}\0${knId}\0${identityOf(ctx)}\0${ctx.trace?.conversationId ?? ""}`;
|
|
1669
|
+
}
|
|
1670
|
+
function ensureSession2(ctx, knId, contract, question) {
|
|
1671
|
+
const key = sessionKey(ctx, knId);
|
|
1672
|
+
const cached = sessions2.get(key);
|
|
1673
|
+
if (cached) return cached;
|
|
1674
|
+
const opening = openSession(ctx, knId, contract, question);
|
|
1675
|
+
sessions2.set(key, opening);
|
|
1676
|
+
opening.catch(() => sessions2.delete(key));
|
|
1677
|
+
return opening;
|
|
1678
|
+
}
|
|
1679
|
+
function newOperationKey() {
|
|
1680
|
+
return `op:${randomUUID2()}`;
|
|
1681
|
+
}
|
|
1682
|
+
function contextFor(session, contract) {
|
|
1683
|
+
return {
|
|
1684
|
+
conversation_id: session.conversationId,
|
|
1685
|
+
interaction_id: session.interactionId,
|
|
1686
|
+
// v2 validates bkn_context strictly and rejects the field.
|
|
1687
|
+
...contract === "managed-v1" ? { operation_key: newOperationKey() } : {}
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
async function bknContextFor(ctx, knId, question) {
|
|
1691
|
+
const contract = await lifecycleContract(ctx);
|
|
1692
|
+
if (contract === "none") return void 0;
|
|
1693
|
+
const owned = callerOwnedSession(ctx);
|
|
1694
|
+
if (owned) return contextFor(owned, contract);
|
|
1695
|
+
try {
|
|
1696
|
+
return contextFor(await ensureSession2(ctx, knId, contract, question), contract);
|
|
1697
|
+
} catch {
|
|
1698
|
+
return void 0;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
function serverErrorCode(err2) {
|
|
1702
|
+
if (err2 instanceof ToolError) return err2.code;
|
|
1703
|
+
if (!(err2 instanceof HttpError)) return void 0;
|
|
1704
|
+
try {
|
|
1705
|
+
const parsed = JSON.parse(err2.body);
|
|
1706
|
+
return typeof parsed.error?.code === "string" ? parsed.error.code : void 0;
|
|
1707
|
+
} catch {
|
|
1708
|
+
return void 0;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
async function withManagedLifecycle(ctx, knId, question, send) {
|
|
1712
|
+
const first = await bknContextFor(ctx, knId, question);
|
|
1713
|
+
try {
|
|
1714
|
+
return await send(first);
|
|
1715
|
+
} catch (err2) {
|
|
1716
|
+
const code = serverErrorCode(err2);
|
|
1717
|
+
if (!first || callerOwnedSession(ctx) || !code || !STALE_SESSION_CODES.has(code)) throw err2;
|
|
1718
|
+
sessions2.delete(sessionKey(ctx, knId));
|
|
1719
|
+
const reopened = await bknContextFor(ctx, knId, question);
|
|
1720
|
+
if (!reopened) throw err2;
|
|
1721
|
+
return await send(reopened);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
async function releaseLifecycleSessions() {
|
|
1725
|
+
const pending = [...sessions2.values()];
|
|
1726
|
+
sessions2.clear();
|
|
1727
|
+
await Promise.all(pending.map((opening) => withDeadline(releaseOne(opening))));
|
|
1728
|
+
}
|
|
1729
|
+
function withDeadline(work) {
|
|
1730
|
+
return new Promise((resolve7) => {
|
|
1731
|
+
const timer = setTimeout(resolve7, RELEASE_TIMEOUT_MS);
|
|
1732
|
+
timer.unref?.();
|
|
1733
|
+
work.finally(() => {
|
|
1734
|
+
clearTimeout(timer);
|
|
1735
|
+
resolve7();
|
|
1736
|
+
});
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
async function releaseOne(opening) {
|
|
1740
|
+
try {
|
|
1741
|
+
const session = await opening;
|
|
1742
|
+
if (session.contract !== "managed-v2") return;
|
|
1743
|
+
await callToolRaw(
|
|
1744
|
+
session.ctx,
|
|
1745
|
+
session.knId,
|
|
1746
|
+
"bkn_finish_interaction",
|
|
1747
|
+
{
|
|
1748
|
+
interaction_id: session.interactionId,
|
|
1749
|
+
outcome: "cancelled",
|
|
1750
|
+
reason: "client session ended"
|
|
1751
|
+
},
|
|
1752
|
+
void 0,
|
|
1753
|
+
RELEASE_TIMEOUT_MS
|
|
1754
|
+
);
|
|
1755
|
+
} catch {
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1409
1759
|
// src/resources/context-loader.ts
|
|
1410
1760
|
function context(ctx) {
|
|
1411
1761
|
return {
|
|
@@ -1418,7 +1768,8 @@ function context(ctx) {
|
|
|
1418
1768
|
relationTypes: (knId, ids) => getRelationTypes(ctx, knId, ids),
|
|
1419
1769
|
info: () => mcpInfo(ctx),
|
|
1420
1770
|
tools: (knId) => listTools(ctx, knId),
|
|
1421
|
-
toolCall: (knId, name, args) => callTool(ctx, knId, name, args),
|
|
1771
|
+
toolCall: (knId, name, args, options) => callTool(ctx, knId, name, args, options),
|
|
1772
|
+
managedToolCall: (knId, name, args, options) => callManagedTool(ctx, knId, name, args, options),
|
|
1422
1773
|
// Generic MCP method passthrough — covers methods not yet wrapped, so the
|
|
1423
1774
|
// surface doesn't have to grow every time the server adds one.
|
|
1424
1775
|
callMethod: (knId, method, params) => callMethod(ctx, knId, method, params),
|
|
@@ -1715,22 +2066,39 @@ function searchMetrics(ctx, knId, body) {
|
|
|
1715
2066
|
});
|
|
1716
2067
|
}
|
|
1717
2068
|
function validateMetric(ctx, knId, body) {
|
|
1718
|
-
return request(ctx, `${ONTOLOGY_BASE}/${encodeURIComponent(knId)}/metrics/
|
|
2069
|
+
return request(ctx, `${ONTOLOGY_BASE}/${encodeURIComponent(knId)}/metrics/validation`, {
|
|
1719
2070
|
method: "POST",
|
|
1720
2071
|
body
|
|
1721
2072
|
});
|
|
1722
2073
|
}
|
|
2074
|
+
function searchBody(knId, query, opts) {
|
|
2075
|
+
return {
|
|
2076
|
+
kn_id: knId,
|
|
2077
|
+
query,
|
|
2078
|
+
mode: opts.mode ?? "keyword_vector_retrieval",
|
|
2079
|
+
max_concepts: opts.maxConcepts ?? 10,
|
|
2080
|
+
return_query_understanding: opts.returnQueryUnderstanding ?? false
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
1723
2083
|
function semanticSearch(ctx, knId, query, opts = {}) {
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
2084
|
+
if (opts.bknContext) {
|
|
2085
|
+
return request(ctx, `${RETRIEVAL_BASE}/semantic-search`, {
|
|
2086
|
+
method: "POST",
|
|
2087
|
+
body: { ...searchBody(knId, query, opts), bkn_context: opts.bknContext }
|
|
2088
|
+
});
|
|
2089
|
+
}
|
|
2090
|
+
return withManagedLifecycle(
|
|
2091
|
+
ctx,
|
|
2092
|
+
knId,
|
|
2093
|
+
query,
|
|
2094
|
+
(bknContext) => request(ctx, `${RETRIEVAL_BASE}/semantic-search`, {
|
|
2095
|
+
method: "POST",
|
|
2096
|
+
body: {
|
|
2097
|
+
...searchBody(knId, query, opts),
|
|
2098
|
+
...bknContext ? { bkn_context: bknContext } : {}
|
|
2099
|
+
}
|
|
2100
|
+
})
|
|
2101
|
+
);
|
|
1734
2102
|
}
|
|
1735
2103
|
|
|
1736
2104
|
// src/api/resources.ts
|
|
@@ -3194,28 +3562,102 @@ function deleteActionSchedules(ctx, knId, ids) {
|
|
|
3194
3562
|
import { z } from "zod";
|
|
3195
3563
|
var VEGA_BASE = "/api/vega-backend/v1";
|
|
3196
3564
|
var BuildMode = z.enum(["batch", "streaming"]);
|
|
3197
|
-
var
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3565
|
+
var BuildTaskExecuteType = z.enum(["incremental", "full"]);
|
|
3566
|
+
var BuildTaskStatus = z.enum([
|
|
3567
|
+
"init",
|
|
3568
|
+
"running",
|
|
3569
|
+
"stopping",
|
|
3570
|
+
"stopped",
|
|
3571
|
+
"completed",
|
|
3572
|
+
"failed"
|
|
3573
|
+
]);
|
|
3574
|
+
var CatalogHealthCheckScheduleMode = z.enum(["inherit", "enabled", "disabled"]);
|
|
3575
|
+
var CatalogHealthCheckStatus = z.enum([
|
|
3576
|
+
"healthy",
|
|
3577
|
+
"degraded",
|
|
3578
|
+
"unhealthy",
|
|
3579
|
+
"offline",
|
|
3580
|
+
"unchecked"
|
|
3581
|
+
]);
|
|
3582
|
+
var CatalogHealthStatus = z.object({
|
|
3583
|
+
id: z.string(),
|
|
3584
|
+
health_check_status: CatalogHealthCheckStatus,
|
|
3585
|
+
last_check_time: z.number().optional(),
|
|
3586
|
+
health_check_result: z.string().optional()
|
|
3587
|
+
}).passthrough();
|
|
3588
|
+
var CatalogHealthCheckSchedule = z.object({
|
|
3589
|
+
catalog_id: z.string(),
|
|
3590
|
+
mode: CatalogHealthCheckScheduleMode,
|
|
3591
|
+
cron_expr: z.string().optional(),
|
|
3592
|
+
last_run: z.number(),
|
|
3593
|
+
next_run: z.number()
|
|
3594
|
+
}).passthrough();
|
|
3595
|
+
var CatalogConnectionTestResult = z.object({
|
|
3596
|
+
success: z.boolean(),
|
|
3597
|
+
message: z.string().optional()
|
|
3598
|
+
}).passthrough();
|
|
3599
|
+
var CreateBuildTaskRequest = z.discriminatedUnion("mode", [
|
|
3600
|
+
z.object({
|
|
3601
|
+
resource_id: z.string().min(1),
|
|
3602
|
+
mode: z.literal("batch"),
|
|
3603
|
+
execute_type: BuildTaskExecuteType.optional()
|
|
3604
|
+
}),
|
|
3605
|
+
z.object({
|
|
3606
|
+
resource_id: z.string().min(1),
|
|
3607
|
+
mode: z.literal("streaming"),
|
|
3608
|
+
// Streaming tasks do not have an execution type.
|
|
3609
|
+
execute_type: z.never().optional()
|
|
3610
|
+
})
|
|
3611
|
+
]);
|
|
3202
3612
|
var BuildTask = z.object({
|
|
3203
3613
|
id: z.string(),
|
|
3204
3614
|
resource_id: z.string().optional(),
|
|
3205
3615
|
mode: BuildMode.optional(),
|
|
3206
|
-
status:
|
|
3616
|
+
status: BuildTaskStatus.optional(),
|
|
3207
3617
|
state: z.string().optional(),
|
|
3208
3618
|
total_count: z.number().optional(),
|
|
3209
3619
|
synced_count: z.number().optional(),
|
|
3210
3620
|
vectorized_count: z.number().optional(),
|
|
3211
3621
|
index_config: z.unknown().optional(),
|
|
3212
3622
|
catalog_id: z.string().optional(),
|
|
3623
|
+
execute_type: BuildTaskExecuteType.optional(),
|
|
3624
|
+
index_health: z.object({
|
|
3625
|
+
embedding: z.string(),
|
|
3626
|
+
fulltext: z.string(),
|
|
3627
|
+
usable: z.boolean()
|
|
3628
|
+
}).passthrough().optional()
|
|
3629
|
+
}).passthrough();
|
|
3630
|
+
var BuildTaskSummary = z.object({
|
|
3631
|
+
id: z.string(),
|
|
3632
|
+
resource_id: z.string(),
|
|
3633
|
+
resource_name: z.string().optional(),
|
|
3634
|
+
catalog_id: z.string(),
|
|
3635
|
+
catalog_name: z.string().optional(),
|
|
3636
|
+
status: BuildTaskStatus,
|
|
3637
|
+
mode: BuildMode,
|
|
3638
|
+
execute_type: BuildTaskExecuteType.optional(),
|
|
3639
|
+
total_count: z.number(),
|
|
3640
|
+
synced_count: z.number(),
|
|
3641
|
+
vectorized_count: z.number(),
|
|
3642
|
+
synced_mark: z.string(),
|
|
3643
|
+
error_msg: z.string().optional(),
|
|
3644
|
+
creator: z.object({
|
|
3645
|
+
id: z.string(),
|
|
3646
|
+
name: z.string().optional(),
|
|
3647
|
+
type: z.string()
|
|
3648
|
+
}),
|
|
3649
|
+
create_time: z.number(),
|
|
3650
|
+
update_time: z.number(),
|
|
3213
3651
|
index_health: z.object({
|
|
3214
3652
|
embedding: z.string(),
|
|
3215
3653
|
fulltext: z.string(),
|
|
3216
3654
|
usable: z.boolean()
|
|
3217
3655
|
}).passthrough().optional()
|
|
3218
3656
|
}).passthrough();
|
|
3657
|
+
var ListBuildTasksResponse = z.object({
|
|
3658
|
+
entries: z.array(BuildTaskSummary),
|
|
3659
|
+
total_count: z.number()
|
|
3660
|
+
}).passthrough();
|
|
3219
3661
|
async function createBuildTask(ctx, req) {
|
|
3220
3662
|
const p = CreateBuildTaskRequest.parse(req);
|
|
3221
3663
|
const body = {
|
|
@@ -3226,8 +3668,13 @@ async function createBuildTask(ctx, req) {
|
|
|
3226
3668
|
const res = await request(ctx, `${VEGA_BASE}/build-tasks`, { method: "POST", body });
|
|
3227
3669
|
return BuildTask.parse(res);
|
|
3228
3670
|
}
|
|
3229
|
-
function listBuildTasks(ctx, opts = {}) {
|
|
3230
|
-
|
|
3671
|
+
async function listBuildTasks(ctx, opts = {}) {
|
|
3672
|
+
if (opts.orderBy === "default") {
|
|
3673
|
+
throw new InputError(
|
|
3674
|
+
'orderBy "default" is no longer supported; use "created_at" or "updated_at"'
|
|
3675
|
+
);
|
|
3676
|
+
}
|
|
3677
|
+
const res = await request(ctx, `${VEGA_BASE}/build-tasks`, {
|
|
3231
3678
|
query: {
|
|
3232
3679
|
limit: opts.limit,
|
|
3233
3680
|
offset: opts.offset,
|
|
@@ -3240,6 +3687,7 @@ function listBuildTasks(ctx, opts = {}) {
|
|
|
3240
3687
|
order: opts.order
|
|
3241
3688
|
}
|
|
3242
3689
|
});
|
|
3690
|
+
return ListBuildTasksResponse.parse(res);
|
|
3243
3691
|
}
|
|
3244
3692
|
async function getBuildTask(ctx, taskId) {
|
|
3245
3693
|
const res = await request(ctx, `${VEGA_BASE}/build-tasks/${encodeURIComponent(taskId)}`);
|
|
@@ -3290,35 +3738,46 @@ async function listCatalogs(ctx, opts = {}) {
|
|
|
3290
3738
|
function getCatalog(ctx, id) {
|
|
3291
3739
|
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}`);
|
|
3292
3740
|
}
|
|
3293
|
-
function createCatalog(ctx, req) {
|
|
3741
|
+
function createCatalog(ctx, req, opts = {}) {
|
|
3294
3742
|
return request(ctx, `${VEGA_BASE}/catalogs`, {
|
|
3295
3743
|
method: "POST",
|
|
3744
|
+
query: {
|
|
3745
|
+
allow_unhealthy: opts.allowUnhealthy === void 0 ? void 0 : String(opts.allowUnhealthy)
|
|
3746
|
+
},
|
|
3296
3747
|
body: {
|
|
3297
3748
|
...req.id ? { id: req.id } : {},
|
|
3298
3749
|
name: req.name,
|
|
3299
3750
|
connector_type: req.connectorType,
|
|
3300
3751
|
connector_config: req.connectorConfig,
|
|
3301
|
-
...req.tags ? { tags: req.tags } : {},
|
|
3302
|
-
...req.description ? { description: req.description } : {},
|
|
3752
|
+
...req.tags !== void 0 ? { tags: req.tags } : {},
|
|
3753
|
+
...req.description !== void 0 ? { description: req.description } : {},
|
|
3303
3754
|
...req.enabled !== void 0 ? { enabled: req.enabled } : {},
|
|
3304
3755
|
...req.internal !== void 0 ? { internal: req.internal } : {},
|
|
3305
|
-
...req.extensions ? { extensions: req.extensions } : {}
|
|
3306
|
-
|
|
3756
|
+
...req.extensions !== void 0 ? { extensions: req.extensions } : {},
|
|
3757
|
+
...req.healthCheckSchedule !== void 0 ? {
|
|
3758
|
+
health_check_schedule: req.healthCheckSchedule === null ? null : mapCatalogHealthCheckScheduleRequest(req.healthCheckSchedule)
|
|
3759
|
+
} : {}
|
|
3760
|
+
},
|
|
3761
|
+
timeoutMs: 6e4
|
|
3307
3762
|
});
|
|
3308
3763
|
}
|
|
3309
|
-
function updateCatalog(ctx, id, req) {
|
|
3764
|
+
function updateCatalog(ctx, id, req, opts = {}) {
|
|
3310
3765
|
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}`, {
|
|
3311
3766
|
method: "PUT",
|
|
3767
|
+
query: {
|
|
3768
|
+
allow_unhealthy: opts.allowUnhealthy === void 0 ? void 0 : String(opts.allowUnhealthy)
|
|
3769
|
+
},
|
|
3312
3770
|
body: {
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3771
|
+
id,
|
|
3772
|
+
name: req.name,
|
|
3773
|
+
connector_type: req.connectorType,
|
|
3774
|
+
enabled: req.enabled,
|
|
3316
3775
|
...req.connectorConfig !== void 0 ? { connector_config: req.connectorConfig } : {},
|
|
3317
|
-
...req.tags ? { tags: req.tags } : {},
|
|
3776
|
+
...req.tags !== void 0 ? { tags: req.tags } : {},
|
|
3318
3777
|
...req.description !== void 0 ? { description: req.description } : {},
|
|
3319
|
-
...req.
|
|
3320
|
-
|
|
3321
|
-
|
|
3778
|
+
...req.extensions !== void 0 ? { extensions: req.extensions } : {}
|
|
3779
|
+
},
|
|
3780
|
+
timeoutMs: 6e4
|
|
3322
3781
|
});
|
|
3323
3782
|
}
|
|
3324
3783
|
function enableCatalog(ctx, id) {
|
|
@@ -3332,10 +3791,51 @@ function disableCatalog(ctx, id) {
|
|
|
3332
3791
|
function deleteCatalog(ctx, id) {
|
|
3333
3792
|
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
3334
3793
|
}
|
|
3335
|
-
function
|
|
3336
|
-
|
|
3337
|
-
method: "POST"
|
|
3794
|
+
async function testCatalogConnectionConfig(ctx, req) {
|
|
3795
|
+
const result = await request(ctx, `${VEGA_BASE}/catalogs/test-connection`, {
|
|
3796
|
+
method: "POST",
|
|
3797
|
+
body: {
|
|
3798
|
+
connector_type: req.connectorType,
|
|
3799
|
+
connector_config: req.connectorConfig
|
|
3800
|
+
},
|
|
3801
|
+
timeoutMs: 6e4
|
|
3338
3802
|
});
|
|
3803
|
+
return CatalogConnectionTestResult.parse(result);
|
|
3804
|
+
}
|
|
3805
|
+
async function testCatalogConnection(ctx, id) {
|
|
3806
|
+
const result = await request(
|
|
3807
|
+
ctx,
|
|
3808
|
+
`${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/test-connection`,
|
|
3809
|
+
{
|
|
3810
|
+
method: "POST",
|
|
3811
|
+
timeoutMs: 6e4
|
|
3812
|
+
}
|
|
3813
|
+
);
|
|
3814
|
+
return CatalogConnectionTestResult.parse(result);
|
|
3815
|
+
}
|
|
3816
|
+
async function getCatalogHealthCheckSchedule(ctx, id) {
|
|
3817
|
+
const result = await request(
|
|
3818
|
+
ctx,
|
|
3819
|
+
`${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/health-check-schedule`
|
|
3820
|
+
);
|
|
3821
|
+
return CatalogHealthCheckSchedule.parse(result);
|
|
3822
|
+
}
|
|
3823
|
+
async function updateCatalogHealthCheckSchedule(ctx, id, req) {
|
|
3824
|
+
const result = await request(
|
|
3825
|
+
ctx,
|
|
3826
|
+
`${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/health-check-schedule`,
|
|
3827
|
+
{
|
|
3828
|
+
method: "PUT",
|
|
3829
|
+
body: mapCatalogHealthCheckScheduleRequest(req)
|
|
3830
|
+
}
|
|
3831
|
+
);
|
|
3832
|
+
return CatalogHealthCheckSchedule.parse(result);
|
|
3833
|
+
}
|
|
3834
|
+
function mapCatalogHealthCheckScheduleRequest(req) {
|
|
3835
|
+
return {
|
|
3836
|
+
mode: req.mode,
|
|
3837
|
+
...req.mode === "enabled" ? { cron_expr: req.cronExpr } : {}
|
|
3838
|
+
};
|
|
3339
3839
|
}
|
|
3340
3840
|
function discoverCatalog(ctx, id, wait = true) {
|
|
3341
3841
|
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/discover`, {
|
|
@@ -3355,11 +3855,12 @@ function listCatalogResources(ctx, id, category, limit, offset) {
|
|
|
3355
3855
|
}
|
|
3356
3856
|
});
|
|
3357
3857
|
}
|
|
3358
|
-
function catalogHealthStatus(ctx,
|
|
3359
|
-
|
|
3858
|
+
async function catalogHealthStatus(ctx, id) {
|
|
3859
|
+
const result = await request(
|
|
3360
3860
|
ctx,
|
|
3361
|
-
`${VEGA_BASE}/catalogs/${
|
|
3861
|
+
`${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/health-status`
|
|
3362
3862
|
);
|
|
3863
|
+
return CatalogHealthStatus.parse(result);
|
|
3363
3864
|
}
|
|
3364
3865
|
function listConnectorTypes(ctx) {
|
|
3365
3866
|
return request(ctx, `${VEGA_BASE}/connector-types`, { query: { sort: "name", order: "asc" } });
|
|
@@ -4273,16 +4774,45 @@ async function updateSkillPackageZip(ctx, skillId, bytes, filename = "skill.zip"
|
|
|
4273
4774
|
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
4274
4775
|
return text ? JSON.parse(text) : void 0;
|
|
4275
4776
|
}
|
|
4276
|
-
|
|
4777
|
+
function skillPath(skillId, view, path) {
|
|
4778
|
+
const seg = view === "draft" ? "management/" : "";
|
|
4779
|
+
return `${BASE5}/skills/${encodeURIComponent(skillId)}/${seg}${path}`;
|
|
4780
|
+
}
|
|
4781
|
+
async function downloadSkill(ctx, skillId, view = "published") {
|
|
4277
4782
|
const res = await authFetch(
|
|
4278
4783
|
ctx,
|
|
4279
|
-
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${
|
|
4784
|
+
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${skillPath(skillId, view, "download")}`, {
|
|
4280
4785
|
headers: buildHeaders(ctx)
|
|
4281
4786
|
})
|
|
4282
4787
|
);
|
|
4283
4788
|
if (!res.ok) throw new HttpError(res.status, res.statusText, await res.text());
|
|
4284
4789
|
return new Uint8Array(await res.arrayBuffer());
|
|
4285
4790
|
}
|
|
4791
|
+
function executeSkill(ctx, skillId, opts) {
|
|
4792
|
+
return request(ctx, `${BASE5}/skills/${encodeURIComponent(skillId)}/execute`, {
|
|
4793
|
+
method: "POST",
|
|
4794
|
+
body: {
|
|
4795
|
+
entry_shell: opts.entryShell,
|
|
4796
|
+
...opts.timeout === void 0 ? {} : { timeout: opts.timeout }
|
|
4797
|
+
},
|
|
4798
|
+
// Outlast the sandbox: the default client timeout is shorter than the run
|
|
4799
|
+
// budget, so without this a long run aborts locally mid-execution and the
|
|
4800
|
+
// caller never learns the exit code. With no stated limit the sandbox
|
|
4801
|
+
// applies its own — 300s by default, 3600s at most — so the budget has to
|
|
4802
|
+
// cover that rather than a number of ours.
|
|
4803
|
+
timeoutMs: executeBudgetMs(opts.timeout),
|
|
4804
|
+
// The abort deadline alone tops out at undici's 300s header deadline,
|
|
4805
|
+
// because `execute-sync` blocks and sends no headers until the run is over.
|
|
4806
|
+
headersTimeoutMs: executeBudgetMs(opts.timeout)
|
|
4807
|
+
});
|
|
4808
|
+
}
|
|
4809
|
+
var SANDBOX_MAX_TIMEOUT_SEC = 3600;
|
|
4810
|
+
function executeBudgetMs(timeoutSec) {
|
|
4811
|
+
return (timeoutSec ?? SANDBOX_MAX_TIMEOUT_SEC) * 1e3 + 15e3;
|
|
4812
|
+
}
|
|
4813
|
+
function getSkillNames(ctx, ids) {
|
|
4814
|
+
return request(ctx, `${BASE5}/skills/names`, { method: "POST", body: { ids } });
|
|
4815
|
+
}
|
|
4286
4816
|
function updateSkillMetadata(ctx, skillId, body) {
|
|
4287
4817
|
return request(ctx, `${BASE5}/skills/${encodeURIComponent(skillId)}`, { method: "PUT", body });
|
|
4288
4818
|
}
|
|
@@ -4323,12 +4853,15 @@ function getSkillMarket(ctx, skillId) {
|
|
|
4323
4853
|
function deleteSkill(ctx, skillId) {
|
|
4324
4854
|
return request(ctx, `${BASE5}/skills/${encodeURIComponent(skillId)}`, { method: "DELETE" });
|
|
4325
4855
|
}
|
|
4326
|
-
function getSkillContent(ctx, skillId) {
|
|
4327
|
-
return request(ctx,
|
|
4856
|
+
function getSkillContent(ctx, skillId, opts = {}) {
|
|
4857
|
+
return request(ctx, skillPath(skillId, opts.view ?? "published", "content"), {
|
|
4858
|
+
query: { response_mode: opts.responseMode }
|
|
4859
|
+
});
|
|
4328
4860
|
}
|
|
4329
|
-
function readSkillFile(ctx, skillId, relPath) {
|
|
4330
|
-
return request(ctx,
|
|
4861
|
+
function readSkillFile(ctx, skillId, relPath, opts = {}) {
|
|
4862
|
+
return request(ctx, skillPath(skillId, opts.view ?? "published", "files/read"), {
|
|
4331
4863
|
method: "POST",
|
|
4864
|
+
query: { response_mode: opts.responseMode },
|
|
4332
4865
|
body: { rel_path: relPath }
|
|
4333
4866
|
});
|
|
4334
4867
|
}
|
|
@@ -4366,6 +4899,15 @@ async function zipDirectory(dir) {
|
|
|
4366
4899
|
}
|
|
4367
4900
|
return new Uint8Array(await zip.generateAsync({ type: "uint8array", compression: "DEFLATE" }));
|
|
4368
4901
|
}
|
|
4902
|
+
async function unzipToMap(bytes) {
|
|
4903
|
+
const zip = await JSZip.loadAsync(bytes);
|
|
4904
|
+
const out = /* @__PURE__ */ new Map();
|
|
4905
|
+
for (const entry of Object.values(zip.files)) {
|
|
4906
|
+
if (entry.dir) continue;
|
|
4907
|
+
out.set(entry.name, new Uint8Array(await entry.async("uint8array")));
|
|
4908
|
+
}
|
|
4909
|
+
return out;
|
|
4910
|
+
}
|
|
4369
4911
|
async function unzipToDirectory(bytes, dir) {
|
|
4370
4912
|
const abs = resolve4(dir);
|
|
4371
4913
|
mkdirSync3(abs, { recursive: true });
|
|
@@ -4382,16 +4924,202 @@ async function unzipToDirectory(bytes, dir) {
|
|
|
4382
4924
|
return written;
|
|
4383
4925
|
}
|
|
4384
4926
|
|
|
4927
|
+
// src/utils/skill-tree.ts
|
|
4928
|
+
function normalize(path) {
|
|
4929
|
+
return (path ?? "").replace(/^\/+|\/+$/g, "");
|
|
4930
|
+
}
|
|
4931
|
+
function segments(relPath) {
|
|
4932
|
+
return relPath.split("/").filter(Boolean);
|
|
4933
|
+
}
|
|
4934
|
+
function classifyPath(files, path) {
|
|
4935
|
+
const target = normalize(path);
|
|
4936
|
+
if (!target) return "root";
|
|
4937
|
+
if (files.some((f) => normalize(f.rel_path) === target)) return "file";
|
|
4938
|
+
const prefix = `${target}/`;
|
|
4939
|
+
return files.some((f) => normalize(f.rel_path).startsWith(prefix)) ? "dir" : "missing";
|
|
4940
|
+
}
|
|
4941
|
+
function listChildren(files, path) {
|
|
4942
|
+
const target = normalize(path);
|
|
4943
|
+
const prefix = target ? `${target}/` : "";
|
|
4944
|
+
const dirs = /* @__PURE__ */ new Map();
|
|
4945
|
+
const leaves = [];
|
|
4946
|
+
for (const file of files) {
|
|
4947
|
+
const rel = normalize(file.rel_path);
|
|
4948
|
+
if (prefix && !rel.startsWith(prefix)) continue;
|
|
4949
|
+
const rest = segments(rel.slice(prefix.length));
|
|
4950
|
+
if (rest.length === 0) continue;
|
|
4951
|
+
const [head] = rest;
|
|
4952
|
+
if (!head) continue;
|
|
4953
|
+
if (rest.length === 1) {
|
|
4954
|
+
leaves.push({
|
|
4955
|
+
name: head,
|
|
4956
|
+
type: "file",
|
|
4957
|
+
relPath: rel,
|
|
4958
|
+
fileType: file.file_type,
|
|
4959
|
+
size: file.size,
|
|
4960
|
+
mime: file.mime_type
|
|
4961
|
+
});
|
|
4962
|
+
continue;
|
|
4963
|
+
}
|
|
4964
|
+
const dir = dirs.get(head) ?? { name: head, type: "dir", files: 0, size: 0 };
|
|
4965
|
+
dir.files += 1;
|
|
4966
|
+
dir.size += file.size ?? 0;
|
|
4967
|
+
dirs.set(head, dir);
|
|
4968
|
+
}
|
|
4969
|
+
const byName = (a, b) => a.name.localeCompare(b.name);
|
|
4970
|
+
return [...[...dirs.values()].sort(byName), ...leaves.sort(byName)];
|
|
4971
|
+
}
|
|
4972
|
+
function filesUnder(files, path) {
|
|
4973
|
+
const target = normalize(path);
|
|
4974
|
+
if (!target) return files;
|
|
4975
|
+
const prefix = `${target}/`;
|
|
4976
|
+
return files.filter((f) => normalize(f.rel_path).startsWith(prefix));
|
|
4977
|
+
}
|
|
4978
|
+
function emptyNode() {
|
|
4979
|
+
return { dirs: /* @__PURE__ */ new Map(), files: [] };
|
|
4980
|
+
}
|
|
4981
|
+
function buildTree(files) {
|
|
4982
|
+
const root = emptyNode();
|
|
4983
|
+
for (const file of files) {
|
|
4984
|
+
const parts = segments(normalize(file.rel_path));
|
|
4985
|
+
const name = parts.pop();
|
|
4986
|
+
if (!name) continue;
|
|
4987
|
+
let node = root;
|
|
4988
|
+
for (const part of parts) {
|
|
4989
|
+
const next = node.dirs.get(part) ?? emptyNode();
|
|
4990
|
+
node.dirs.set(part, next);
|
|
4991
|
+
node = next;
|
|
4992
|
+
}
|
|
4993
|
+
node.files.push({
|
|
4994
|
+
name,
|
|
4995
|
+
type: "file",
|
|
4996
|
+
relPath: normalize(file.rel_path),
|
|
4997
|
+
fileType: file.file_type,
|
|
4998
|
+
size: file.size,
|
|
4999
|
+
mime: file.mime_type
|
|
5000
|
+
});
|
|
5001
|
+
}
|
|
5002
|
+
return root;
|
|
5003
|
+
}
|
|
5004
|
+
function renderNode(node, indent, out) {
|
|
5005
|
+
const dirs = [...node.dirs.entries()].sort(([a], [b]) => a.localeCompare(b));
|
|
5006
|
+
const files = [...node.files].sort((a, b) => a.name.localeCompare(b.name));
|
|
5007
|
+
const total = dirs.length + files.length;
|
|
5008
|
+
let index = 0;
|
|
5009
|
+
for (const [name, child] of dirs) {
|
|
5010
|
+
index += 1;
|
|
5011
|
+
const last = index === total;
|
|
5012
|
+
out.push(`${indent}${last ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 "}${name}/`);
|
|
5013
|
+
renderNode(child, `${indent}${last ? " " : "\u2502 "}`, out);
|
|
5014
|
+
}
|
|
5015
|
+
for (const file of files) {
|
|
5016
|
+
index += 1;
|
|
5017
|
+
const last = index === total;
|
|
5018
|
+
const meta = [file.fileType, file.size === void 0 ? void 0 : `${file.size} B`].filter(Boolean).join(", ");
|
|
5019
|
+
out.push(`${indent}${last ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 "}${file.name}${meta ? ` (${meta})` : ""}`);
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
function renderTree(files) {
|
|
5023
|
+
const out = [];
|
|
5024
|
+
renderNode(buildTree(files), "", out);
|
|
5025
|
+
return out.join("\n");
|
|
5026
|
+
}
|
|
5027
|
+
|
|
4385
5028
|
// src/resources/skills.ts
|
|
5029
|
+
function viewOf(opts) {
|
|
5030
|
+
return opts?.draft ? "draft" : "published";
|
|
5031
|
+
}
|
|
5032
|
+
function cachedArchive(cache, ctx, skillId, view) {
|
|
5033
|
+
const key = `${skillId}|${view}`;
|
|
5034
|
+
const hit = cache.get(key);
|
|
5035
|
+
if (hit) return hit;
|
|
5036
|
+
const pending = downloadSkill(ctx, skillId, view).then(unzipToMap);
|
|
5037
|
+
cache.set(key, pending);
|
|
5038
|
+
pending.catch(() => cache.delete(key));
|
|
5039
|
+
return pending;
|
|
5040
|
+
}
|
|
5041
|
+
function binaryError(relPath) {
|
|
5042
|
+
return new InputError(
|
|
5043
|
+
`'${relPath}' is a binary file \u2014 use \`openbkn skill install\` or \`skill download\` to fetch it.`
|
|
5044
|
+
);
|
|
5045
|
+
}
|
|
5046
|
+
function decodeStrict(bytes, relPath) {
|
|
5047
|
+
let text;
|
|
5048
|
+
try {
|
|
5049
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
5050
|
+
} catch {
|
|
5051
|
+
throw binaryError(relPath);
|
|
5052
|
+
}
|
|
5053
|
+
if (text.includes("\0")) throw binaryError(relPath);
|
|
5054
|
+
return text;
|
|
5055
|
+
}
|
|
5056
|
+
function looksLossy(text) {
|
|
5057
|
+
return text.includes("\0") || text.includes("\uFFFD");
|
|
5058
|
+
}
|
|
5059
|
+
async function readFileText(cache, ctx, skillId, relPath, view) {
|
|
5060
|
+
const res = await readSkillFile(ctx, skillId, normalize(relPath), {
|
|
5061
|
+
view,
|
|
5062
|
+
responseMode: "content"
|
|
5063
|
+
});
|
|
5064
|
+
if (typeof res?.content === "string" && res.content.length > 0) {
|
|
5065
|
+
if (looksLossy(res.content)) throw binaryError(relPath);
|
|
5066
|
+
return res.content;
|
|
5067
|
+
}
|
|
5068
|
+
const archive = await cachedArchive(cache, ctx, skillId, view);
|
|
5069
|
+
const bytes = archive.get(normalize(relPath));
|
|
5070
|
+
if (!bytes) {
|
|
5071
|
+
throw new InputError(`'${relPath}' not found in skill ${skillId}.`);
|
|
5072
|
+
}
|
|
5073
|
+
return decodeStrict(bytes, relPath);
|
|
5074
|
+
}
|
|
4386
5075
|
function skills(ctx) {
|
|
5076
|
+
const archives = /* @__PURE__ */ new Map();
|
|
5077
|
+
const manifest = async (skillId, opts) => {
|
|
5078
|
+
const res = await getSkillContent(ctx, skillId, { view: viewOf(opts) });
|
|
5079
|
+
return res?.files ?? [];
|
|
5080
|
+
};
|
|
4387
5081
|
return {
|
|
4388
5082
|
list: (opts) => listSkills(ctx, opts),
|
|
4389
5083
|
get: (skillId) => getSkill(ctx, skillId),
|
|
4390
5084
|
market: (opts) => listSkillMarket(ctx, opts),
|
|
4391
5085
|
marketGet: (skillId) => getSkillMarket(ctx, skillId),
|
|
4392
5086
|
delete: (skillId) => deleteSkill(ctx, skillId),
|
|
4393
|
-
content: (skillId) => getSkillContent(ctx, skillId),
|
|
4394
|
-
|
|
5087
|
+
content: (skillId, opts) => getSkillContent(ctx, skillId, { view: viewOf(opts) }),
|
|
5088
|
+
// Normalized like every other path entry point, so `/a/b.md` addresses the
|
|
5089
|
+
// same file here as it does under `--raw` and in `skill files`.
|
|
5090
|
+
readFile: (skillId, relPath, opts) => readSkillFile(ctx, skillId, normalize(relPath), { view: viewOf(opts) }),
|
|
5091
|
+
/** SKILL.md's own text, for callers that want the document rather than a link. */
|
|
5092
|
+
contentRaw: (skillId, opts) => readFileText(archives, ctx, skillId, "SKILL.md", viewOf(opts)),
|
|
5093
|
+
/** A bundled file's text. */
|
|
5094
|
+
readFileRaw: (skillId, relPath, opts) => readFileText(archives, ctx, skillId, relPath, viewOf(opts)),
|
|
5095
|
+
/** Run the skill in the platform sandbox. */
|
|
5096
|
+
execute: (skillId, opts) => executeSkill(ctx, skillId, opts),
|
|
5097
|
+
/** Resolve skill ids to names; unknown ids are simply absent from the result. */
|
|
5098
|
+
names: (ids) => getSkillNames(ctx, ids),
|
|
5099
|
+
/**
|
|
5100
|
+
* One level of the skill's file tree. Directories are inferred from the
|
|
5101
|
+
* manifest's paths — see utils/skill-tree.
|
|
5102
|
+
*/
|
|
5103
|
+
files: async (skillId, path, opts) => {
|
|
5104
|
+
const files = await manifest(skillId, opts);
|
|
5105
|
+
const kind = classifyPath(files, path);
|
|
5106
|
+
if (kind === "file") {
|
|
5107
|
+
throw new InputError(`'${path}' is a file, not a directory \u2014 use \`skill read-file\`.`);
|
|
5108
|
+
}
|
|
5109
|
+
if (kind === "missing") {
|
|
5110
|
+
throw new InputError(`'${path}' not found in skill ${skillId}.`);
|
|
5111
|
+
}
|
|
5112
|
+
const subtree = filesUnder(files, path);
|
|
5113
|
+
return {
|
|
5114
|
+
skillId,
|
|
5115
|
+
path: path ?? "",
|
|
5116
|
+
entries: listChildren(files, path),
|
|
5117
|
+
totalFiles: subtree.length,
|
|
5118
|
+
totalSize: subtree.reduce((sum, f) => sum + (f.size ?? 0), 0)
|
|
5119
|
+
};
|
|
5120
|
+
},
|
|
5121
|
+
/** The manifest itself, for callers that want to render the whole tree. */
|
|
5122
|
+
fileManifest: manifest,
|
|
4395
5123
|
history: (skillId) => getSkillHistory(ctx, skillId),
|
|
4396
5124
|
setStatus: (skillId, status2) => setSkillStatus(ctx, skillId, status2),
|
|
4397
5125
|
updateMetadata: (skillId, body) => updateSkillMetadata(ctx, skillId, body),
|
|
@@ -4405,16 +5133,16 @@ function skills(ctx) {
|
|
|
4405
5133
|
/** Replace a skill's package from a local directory. */
|
|
4406
5134
|
updatePackage: async (skillId, dir) => updateSkillPackageZip(ctx, skillId, await zipDirectory(dir), `${basename2(resolve5(dir))}.zip`),
|
|
4407
5135
|
/** Download a skill archive to a local .zip file. */
|
|
4408
|
-
download: async (skillId, outPath) => {
|
|
4409
|
-
const bytes = await downloadSkill(ctx, skillId);
|
|
5136
|
+
download: async (skillId, outPath, opts) => {
|
|
5137
|
+
const bytes = await downloadSkill(ctx, skillId, viewOf(opts));
|
|
4410
5138
|
const dest = resolve5(outPath ?? `${skillId}.zip`);
|
|
4411
5139
|
mkdirSync4(dirname3(dest), { recursive: true });
|
|
4412
5140
|
writeFileSync3(dest, bytes);
|
|
4413
5141
|
return { skillId, path: dest, bytes: bytes.length };
|
|
4414
5142
|
},
|
|
4415
5143
|
/** Download a skill archive and extract it into a directory. */
|
|
4416
|
-
install: async (skillId, dir) => {
|
|
4417
|
-
const bytes = await downloadSkill(ctx, skillId);
|
|
5144
|
+
install: async (skillId, dir, opts) => {
|
|
5145
|
+
const bytes = await downloadSkill(ctx, skillId, viewOf(opts));
|
|
4418
5146
|
const target = resolve5(dir ?? skillId);
|
|
4419
5147
|
const files = await unzipToDirectory(bytes, target);
|
|
4420
5148
|
return { skillId, dir: target, files: files.length };
|
|
@@ -4576,727 +5304,384 @@ function toolboxes(ctx) {
|
|
|
4576
5304
|
};
|
|
4577
5305
|
}
|
|
4578
5306
|
|
|
4579
|
-
// src/trace-
|
|
4580
|
-
|
|
4581
|
-
var
|
|
4582
|
-
"
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
"
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
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"
|
|
5307
|
+
// src/api/trace-lifecycle.ts
|
|
5308
|
+
var LIFECYCLE = "/api/agent-observability/v1";
|
|
5309
|
+
var FORBIDDEN_INPUT_FIELDS = /* @__PURE__ */ new Set([
|
|
5310
|
+
"generation",
|
|
5311
|
+
"on_behalf_of",
|
|
5312
|
+
"onBehalfOf",
|
|
5313
|
+
"owner",
|
|
5314
|
+
"tenant_id",
|
|
5315
|
+
"application_principal_id",
|
|
5316
|
+
"actor_subject",
|
|
5317
|
+
"actor_subject_type",
|
|
5318
|
+
"actor_subject_id",
|
|
5319
|
+
"effective_subject",
|
|
5320
|
+
"effective_subject_type",
|
|
5321
|
+
"effective_subject_id",
|
|
5322
|
+
"delegation_id"
|
|
4734
5323
|
]);
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
"
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
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"
|
|
5324
|
+
function traceLifecycleApi(ctx) {
|
|
5325
|
+
const post2 = async (path, input) => {
|
|
5326
|
+
assertNoForbiddenInputFields(input);
|
|
5327
|
+
return await request(ctx, `${LIFECYCLE}${path}`, { method: "POST", body: input });
|
|
5328
|
+
};
|
|
5329
|
+
const get = (path) => request(ctx, `${LIFECYCLE}${path}`, { method: "GET" });
|
|
5330
|
+
const interactionTerminal = (interactionId, action, input) => post2(`/interactions/${encodeURIComponent(interactionId)}/${action}`, input);
|
|
5331
|
+
const finishAttempt = (operationId, attempt, action, input) => post2(
|
|
5332
|
+
`/operations/${encodeURIComponent(operationId)}/attempts/${encodeURIComponent(String(attempt))}:${action}`,
|
|
5333
|
+
input
|
|
5334
|
+
);
|
|
5335
|
+
return {
|
|
5336
|
+
listConversations: (query = {}) => {
|
|
5337
|
+
const params = new URLSearchParams();
|
|
5338
|
+
if (query.limit !== void 0 && Number.isFinite(query.limit)) {
|
|
5339
|
+
params.set("limit", String(query.limit));
|
|
5340
|
+
}
|
|
5341
|
+
const suffix = params.size > 0 ? `?${params.toString()}` : "";
|
|
5342
|
+
return get(`/conversations${suffix}`);
|
|
5343
|
+
},
|
|
5344
|
+
ensureConversation: (input) => post2("/conversations:ensure-current", input),
|
|
5345
|
+
createNewConversationGeneration: (input) => post2("/conversations:create-new-generation", input),
|
|
5346
|
+
resumeConversation: (input) => post2("/conversations:resume-by-id", input),
|
|
5347
|
+
getConversation: (conversationId) => get(`/conversations/${encodeURIComponent(conversationId)}`),
|
|
5348
|
+
closeConversation: (conversationId, input) => post2(`/conversations/${encodeURIComponent(conversationId)}/close`, input),
|
|
5349
|
+
startInteraction: (conversationId, input) => post2(`/conversations/${encodeURIComponent(conversationId)}/interactions`, input),
|
|
5350
|
+
getInteraction: (interactionId) => get(`/interactions/${encodeURIComponent(interactionId)}`),
|
|
5351
|
+
completeInteraction: (interactionId, input) => interactionTerminal(interactionId, "complete", input),
|
|
5352
|
+
failInteraction: (interactionId, input) => interactionTerminal(interactionId, "fail", input),
|
|
5353
|
+
cancelInteraction: (interactionId, input) => interactionTerminal(interactionId, "cancel", input),
|
|
5354
|
+
handoffInteraction: (interactionId, input) => interactionTerminal(interactionId, "handoff", input),
|
|
5355
|
+
ensureOperation: (conversationId, interactionId, input) => post2(
|
|
5356
|
+
`/conversations/${encodeURIComponent(conversationId)}/interactions/${encodeURIComponent(interactionId)}/operations:ensure`,
|
|
5357
|
+
input
|
|
5358
|
+
),
|
|
5359
|
+
getOperation: (operationId) => get(`/operations/${encodeURIComponent(operationId)}`),
|
|
5360
|
+
retryOperationAttempt: (operationId, input) => post2(`/operations/${encodeURIComponent(operationId)}/attempts`, input),
|
|
5361
|
+
completeOperationAttempt: (operationId, attempt, input) => finishAttempt(operationId, attempt, "complete", input),
|
|
5362
|
+
failOperationAttempt: (operationId, attempt, input) => finishAttempt(operationId, attempt, "fail", input),
|
|
5363
|
+
getReceipt: (receiptId) => get(`/receipts/${encodeURIComponent(receiptId)}`)
|
|
4859
5364
|
};
|
|
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
5365
|
}
|
|
4918
|
-
function
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
if (
|
|
4927
|
-
throw new
|
|
5366
|
+
function assertNoForbiddenInputFields(input) {
|
|
5367
|
+
const pending = [input];
|
|
5368
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5369
|
+
while (pending.length > 0) {
|
|
5370
|
+
const value = pending.pop();
|
|
5371
|
+
if (typeof value !== "object" || value === null || seen.has(value)) continue;
|
|
5372
|
+
seen.add(value);
|
|
5373
|
+
for (const [field, nested] of Object.entries(value)) {
|
|
5374
|
+
if (FORBIDDEN_INPUT_FIELDS.has(field)) {
|
|
5375
|
+
throw new InputError(`Lifecycle input field "${field}" is not allowed`);
|
|
4928
5376
|
}
|
|
4929
|
-
|
|
5377
|
+
pending.push(nested);
|
|
4930
5378
|
}
|
|
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
5379
|
}
|
|
4936
5380
|
}
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
5381
|
+
|
|
5382
|
+
// src/managed-trace.ts
|
|
5383
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
5384
|
+
var FORBIDDEN_INPUT_FIELDS2 = ["generation", "on_behalf_of", "onBehalfOf"];
|
|
5385
|
+
var CompletionMissingError = class extends InputError {
|
|
5386
|
+
};
|
|
5387
|
+
var OperationFailedError = class extends InputError {
|
|
5388
|
+
};
|
|
5389
|
+
var ManagedTrace = class {
|
|
5390
|
+
constructor(api, options = {}) {
|
|
5391
|
+
this.api = api;
|
|
5392
|
+
this.idFactory = options.idFactory ?? randomUUID3;
|
|
5393
|
+
}
|
|
5394
|
+
api;
|
|
4944
5395
|
idFactory;
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
5396
|
+
pendingConversations = /* @__PURE__ */ new Map();
|
|
5397
|
+
activeConversationIds = /* @__PURE__ */ new Set();
|
|
5398
|
+
async withInteraction(strategy, callback) {
|
|
5399
|
+
assertSafeStrategy(strategy);
|
|
5400
|
+
const conversation = await this.resolveConversation(strategy);
|
|
5401
|
+
if (this.activeConversationIds.has(conversation.conversation_id)) {
|
|
5402
|
+
throw new InputError(
|
|
5403
|
+
`Conversation "${conversation.conversation_id}" already has an active interaction`
|
|
5404
|
+
);
|
|
5405
|
+
}
|
|
5406
|
+
this.activeConversationIds.add(conversation.conversation_id);
|
|
5407
|
+
try {
|
|
5408
|
+
const interaction = await this.api.startInteraction(conversation.conversation_id, {
|
|
5409
|
+
idempotency_key: this.idFactory()
|
|
5410
|
+
});
|
|
5411
|
+
const receipts = /* @__PURE__ */ new Map();
|
|
5412
|
+
let terminal;
|
|
5413
|
+
let terminalAction;
|
|
5414
|
+
const terminalInput = (reason) => ({
|
|
5415
|
+
terminal_idempotency_key: this.idFactory(),
|
|
5416
|
+
lease_token: interaction.lease_token,
|
|
5417
|
+
lease_epoch: interaction.lease_epoch,
|
|
5418
|
+
completion_manifest_version: "3.0.0",
|
|
5419
|
+
completion_reason: reason,
|
|
5420
|
+
claims: [],
|
|
5421
|
+
expected_operations: expectedOperations(receipts.values()),
|
|
5422
|
+
expected_receipts: expectedReceipts(receipts.values())
|
|
5423
|
+
});
|
|
5424
|
+
const scope = {
|
|
5425
|
+
conversation,
|
|
5426
|
+
interaction,
|
|
5427
|
+
bknContext: (operationKey, parentOperationId, causationEventIds) => ({
|
|
5428
|
+
bkn_context: {
|
|
5429
|
+
conversation_id: conversation.conversation_id,
|
|
5430
|
+
interaction_id: interaction.interaction_id,
|
|
5431
|
+
operation_key: operationKey,
|
|
5432
|
+
...parentOperationId ? { parent_operation_id: parentOperationId } : {},
|
|
5433
|
+
...causationEventIds?.length ? { causation_event_ids: causationEventIds } : {}
|
|
5434
|
+
}
|
|
5435
|
+
}),
|
|
5436
|
+
recordReceipt: (receipt) => {
|
|
5437
|
+
if (receipt.conversation_id !== conversation.conversation_id || receipt.interaction_id !== interaction.interaction_id) {
|
|
5438
|
+
throw new InputError("Receipt does not belong to the active managed interaction");
|
|
5439
|
+
}
|
|
5440
|
+
receipts.set(receipt.receipt_id, receipt);
|
|
5441
|
+
},
|
|
5442
|
+
supportCandidates: () => [...receipts.values()].flatMap(
|
|
5443
|
+
(receipt) => receipt.observed_evidence_refs.map((ref) => ({
|
|
5444
|
+
ref,
|
|
5445
|
+
state: "observed",
|
|
5446
|
+
adopted: false
|
|
5447
|
+
}))
|
|
5448
|
+
),
|
|
5449
|
+
runOperation: async (input, execute) => this.runOperation(
|
|
5450
|
+
conversation,
|
|
5451
|
+
interaction,
|
|
5452
|
+
input,
|
|
5453
|
+
execute,
|
|
5454
|
+
scope.bknContext,
|
|
5455
|
+
scope.recordReceipt
|
|
5456
|
+
),
|
|
5457
|
+
cancel: async (reason) => {
|
|
5458
|
+
terminalAction ??= this.api.cancelInteraction(
|
|
5459
|
+
interaction.interaction_id,
|
|
5460
|
+
terminalInput(reason)
|
|
5461
|
+
);
|
|
5462
|
+
terminal = await terminalAction;
|
|
5463
|
+
return terminal;
|
|
5464
|
+
},
|
|
5465
|
+
handoff: async (reason) => {
|
|
5466
|
+
terminalAction ??= this.api.handoffInteraction(
|
|
5467
|
+
interaction.interaction_id,
|
|
5468
|
+
terminalInput(reason)
|
|
5469
|
+
);
|
|
5470
|
+
terminal = await terminalAction;
|
|
5471
|
+
return terminal;
|
|
5472
|
+
}
|
|
5473
|
+
};
|
|
5474
|
+
let completion;
|
|
5475
|
+
try {
|
|
5476
|
+
completion = await callback(scope);
|
|
5477
|
+
if (terminalAction) return await terminalAction;
|
|
5478
|
+
if (terminal) return terminal;
|
|
5479
|
+
if (!completion || typeof completion !== "object") {
|
|
5480
|
+
throw new CompletionMissingError(
|
|
5481
|
+
"Interaction callback must return a completion manifest"
|
|
5482
|
+
);
|
|
5483
|
+
}
|
|
5484
|
+
} catch (error) {
|
|
5485
|
+
if (!terminalAction && !terminal) {
|
|
5486
|
+
try {
|
|
5487
|
+
terminal = await this.api.failInteraction(
|
|
5488
|
+
interaction.interaction_id,
|
|
5489
|
+
terminalInput(
|
|
5490
|
+
error instanceof CompletionMissingError ? "completion_missing" : "callback_failed"
|
|
5491
|
+
)
|
|
5492
|
+
);
|
|
5493
|
+
} catch {
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
throw error;
|
|
4975
5497
|
}
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
version_status: input.versionStatus ?? "unversioned",
|
|
5001
|
-
...input.resultArtifactRef ? { result_artifact_ref: input.resultArtifactRef } : {}
|
|
5498
|
+
const completionInput = {
|
|
5499
|
+
...completion,
|
|
5500
|
+
terminal_idempotency_key: this.idFactory(),
|
|
5501
|
+
lease_token: interaction.lease_token,
|
|
5502
|
+
lease_epoch: interaction.lease_epoch,
|
|
5503
|
+
expected_operations: completion.expected_operations ?? expectedOperations(receipts.values()),
|
|
5504
|
+
expected_receipts: completion.expected_receipts ?? expectedReceipts(receipts.values())
|
|
5505
|
+
};
|
|
5506
|
+
try {
|
|
5507
|
+
return await this.api.completeInteraction(interaction.interaction_id, completionInput);
|
|
5508
|
+
} catch (completeError) {
|
|
5509
|
+
let current;
|
|
5510
|
+
try {
|
|
5511
|
+
current = await this.api.getInteraction(interaction.interaction_id);
|
|
5512
|
+
} catch {
|
|
5513
|
+
throw completeError;
|
|
5514
|
+
}
|
|
5515
|
+
if (current.execution_status === "completed") return current;
|
|
5516
|
+
if (current.execution_status !== "active") {
|
|
5517
|
+
throw new InputError(
|
|
5518
|
+
`Interaction terminal state "${current.execution_status}" conflicts with complete`
|
|
5519
|
+
);
|
|
5520
|
+
}
|
|
5521
|
+
return await this.api.completeInteraction(interaction.interaction_id, completionInput);
|
|
5002
5522
|
}
|
|
5523
|
+
} finally {
|
|
5524
|
+
this.activeConversationIds.delete(conversation.conversation_id);
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5527
|
+
async resolveConversation(strategy) {
|
|
5528
|
+
switch (strategy.mode) {
|
|
5529
|
+
case "resume_by_id":
|
|
5530
|
+
return await this.api.resumeConversation({ conversation_id: strategy.conversationId });
|
|
5531
|
+
case "create_new_generation":
|
|
5532
|
+
return await this.api.createNewConversationGeneration({
|
|
5533
|
+
external_conversation_key: strategy.externalConversationKey,
|
|
5534
|
+
idempotency_key: this.idFactory()
|
|
5535
|
+
});
|
|
5536
|
+
case "one_shot":
|
|
5537
|
+
return await this.api.ensureConversation({
|
|
5538
|
+
external_conversation_key: strategy.externalConversationKey ?? `one-shot-${this.idFactory()}`,
|
|
5539
|
+
idempotency_key: this.idFactory(),
|
|
5540
|
+
one_shot: true
|
|
5541
|
+
});
|
|
5542
|
+
case "ensure_current":
|
|
5543
|
+
return await this.ensureCurrent(strategy.externalConversationKey);
|
|
5544
|
+
}
|
|
5545
|
+
}
|
|
5546
|
+
async ensureCurrent(externalConversationKey) {
|
|
5547
|
+
const pending = this.pendingConversations.get(externalConversationKey);
|
|
5548
|
+
if (pending) return await pending;
|
|
5549
|
+
const request2 = this.api.ensureConversation({
|
|
5550
|
+
external_conversation_key: externalConversationKey,
|
|
5551
|
+
idempotency_key: this.idFactory()
|
|
5003
5552
|
});
|
|
5004
|
-
this.
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
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
|
-
}))
|
|
5553
|
+
this.pendingConversations.set(externalConversationKey, request2);
|
|
5554
|
+
try {
|
|
5555
|
+
return await request2;
|
|
5556
|
+
} finally {
|
|
5557
|
+
if (this.pendingConversations.get(externalConversationKey) === request2) {
|
|
5558
|
+
this.pendingConversations.delete(externalConversationKey);
|
|
5028
5559
|
}
|
|
5029
|
-
}
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
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
|
-
}))
|
|
5560
|
+
}
|
|
5561
|
+
}
|
|
5562
|
+
async runOperation(conversation, interaction, input, execute, bknContext, recordReceipt) {
|
|
5563
|
+
const operationKey = input.operationKey ?? this.idFactory();
|
|
5564
|
+
let current = await this.api.ensureOperation(
|
|
5565
|
+
conversation.conversation_id,
|
|
5566
|
+
interaction.interaction_id,
|
|
5567
|
+
{
|
|
5568
|
+
operation_key: operationKey,
|
|
5569
|
+
tool_name: input.toolName,
|
|
5570
|
+
normalized_input_hash: input.normalizedInputHash,
|
|
5571
|
+
parent_operation_id: input.parentOperationId,
|
|
5572
|
+
causation_event_ids: input.causationEventIds,
|
|
5573
|
+
required: input.required ?? true,
|
|
5574
|
+
lease_token: interaction.lease_token,
|
|
5575
|
+
lease_epoch: interaction.lease_epoch
|
|
5056
5576
|
}
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
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"
|
|
5577
|
+
);
|
|
5578
|
+
const maxAttempts = input.maxAttempts ?? 2;
|
|
5579
|
+
if (!Number.isInteger(maxAttempts) || maxAttempts < 1 || maxAttempts > 10) {
|
|
5580
|
+
throw new InputError("maxAttempts must be an integer between 1 and 10");
|
|
5581
|
+
}
|
|
5582
|
+
while (true) {
|
|
5583
|
+
if (isCompletedReceipt(current.receipt)) {
|
|
5584
|
+
recordReceipt(current.receipt);
|
|
5585
|
+
return { value: void 0, receipt: current.receipt, recovered: true };
|
|
5080
5586
|
}
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
},
|
|
5099
|
-
get lastEventId() {
|
|
5100
|
-
return internal.lastEventId;
|
|
5101
|
-
},
|
|
5102
|
-
get state() {
|
|
5103
|
-
return internal.state;
|
|
5587
|
+
if (isFailedReceipt(current.receipt)) {
|
|
5588
|
+
recordReceipt(current.receipt);
|
|
5589
|
+
if (!current.operation.retryable) {
|
|
5590
|
+
throw new OperationFailedError(
|
|
5591
|
+
`Operation "${current.operation.operation_id}" failed and is not retryable`
|
|
5592
|
+
);
|
|
5593
|
+
}
|
|
5594
|
+
if (current.operation.attempt >= maxAttempts) {
|
|
5595
|
+
throw new OperationFailedError(
|
|
5596
|
+
`Operation "${current.operation.operation_id}" reached maximum attempt count ${maxAttempts}`
|
|
5597
|
+
);
|
|
5598
|
+
}
|
|
5599
|
+
current = await this.api.retryOperationAttempt(current.operation.operation_id, {
|
|
5600
|
+
lease_token: interaction.lease_token,
|
|
5601
|
+
lease_epoch: interaction.lease_epoch
|
|
5602
|
+
});
|
|
5603
|
+
continue;
|
|
5104
5604
|
}
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
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}`);
|
|
5605
|
+
let result;
|
|
5606
|
+
try {
|
|
5607
|
+
result = await execute({
|
|
5608
|
+
context: bknContext(operationKey, input.parentOperationId, input.causationEventIds),
|
|
5609
|
+
operation: current.operation,
|
|
5610
|
+
receipt: current.receipt
|
|
5611
|
+
});
|
|
5612
|
+
} catch (executeError) {
|
|
5613
|
+
const recovered = await this.api.getReceipt(current.receipt.receipt_id);
|
|
5614
|
+
if (!isTerminalReceipt(recovered)) throw executeError;
|
|
5615
|
+
assertSameReceipt(current.receipt, recovered);
|
|
5616
|
+
current = {
|
|
5617
|
+
...current,
|
|
5618
|
+
operation: isFailedReceipt(recovered) ? await this.api.getOperation(current.operation.operation_id) : current.operation,
|
|
5619
|
+
receipt: recovered
|
|
5620
|
+
};
|
|
5621
|
+
continue;
|
|
5202
5622
|
}
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
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}`);
|
|
5623
|
+
assertSameReceipt(current.receipt, result.receipt);
|
|
5624
|
+
recordReceipt(result.receipt);
|
|
5625
|
+
if (isCompletedReceipt(result.receipt)) {
|
|
5626
|
+
return { ...result, recovered: false };
|
|
5258
5627
|
}
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5628
|
+
current = {
|
|
5629
|
+
...current,
|
|
5630
|
+
operation: isFailedReceipt(result.receipt) ? await this.api.getOperation(current.operation.operation_id) : current.operation,
|
|
5631
|
+
receipt: result.receipt
|
|
5632
|
+
};
|
|
5633
|
+
if (!isTerminalReceipt(result.receipt)) {
|
|
5634
|
+
throw new InputError(
|
|
5635
|
+
`Operation "${current.operation.operation_id}" returned a pending receipt`
|
|
5636
|
+
);
|
|
5265
5637
|
}
|
|
5266
5638
|
}
|
|
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
5639
|
}
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5640
|
+
};
|
|
5641
|
+
function assertSafeStrategy(strategy) {
|
|
5642
|
+
if (!strategy || typeof strategy !== "object") {
|
|
5643
|
+
throw new InputError("A conversation strategy is required");
|
|
5275
5644
|
}
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
if (!eventID) throw new Error(`unknown claim reference: ${claimID}`);
|
|
5279
|
-
return eventID;
|
|
5645
|
+
for (const field of FORBIDDEN_INPUT_FIELDS2) {
|
|
5646
|
+
if (field in strategy) throw new InputError(`Lifecycle input field "${field}" is not allowed`);
|
|
5280
5647
|
}
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
}
|
|
5290
|
-
return internal;
|
|
5648
|
+
}
|
|
5649
|
+
function expectedOperations(receipts) {
|
|
5650
|
+
const operations = /* @__PURE__ */ new Map();
|
|
5651
|
+
for (const receipt of receipts) {
|
|
5652
|
+
operations.set(
|
|
5653
|
+
receipt.operation_id,
|
|
5654
|
+
(operations.get(receipt.operation_id) ?? false) || receipt.required
|
|
5655
|
+
);
|
|
5291
5656
|
}
|
|
5292
|
-
};
|
|
5657
|
+
return [...operations].map(([operation_id, required]) => ({ operation_id, required }));
|
|
5658
|
+
}
|
|
5659
|
+
function expectedReceipts(receipts) {
|
|
5660
|
+
return [...receipts].map((receipt) => ({
|
|
5661
|
+
receipt_id: receipt.receipt_id,
|
|
5662
|
+
required: receipt.required
|
|
5663
|
+
}));
|
|
5664
|
+
}
|
|
5665
|
+
function isTerminalReceipt(receipt) {
|
|
5666
|
+
return receipt.receipt_status !== "pending";
|
|
5667
|
+
}
|
|
5668
|
+
function isCompletedReceipt(receipt) {
|
|
5669
|
+
return receipt.receipt_status === "completed";
|
|
5670
|
+
}
|
|
5671
|
+
function isFailedReceipt(receipt) {
|
|
5672
|
+
return receipt.receipt_status === "failed";
|
|
5673
|
+
}
|
|
5674
|
+
function assertSameReceipt(expected, actual) {
|
|
5675
|
+
if (actual.receipt_id !== expected.receipt_id || actual.operation_id !== expected.operation_id || actual.attempt !== expected.attempt || actual.operation_key !== expected.operation_key || actual.normalized_input_hash !== expected.normalized_input_hash) {
|
|
5676
|
+
throw new InputError("Recovered receipt does not match the registered operation attempt");
|
|
5677
|
+
}
|
|
5678
|
+
}
|
|
5293
5679
|
|
|
5294
5680
|
// src/api/trace.ts
|
|
5295
5681
|
var SEARCH = "/api/agent-observability/v1/traces/_search";
|
|
5296
|
-
var
|
|
5297
|
-
var
|
|
5298
|
-
var
|
|
5299
|
-
var INTERACTIONS = "/api/agent-observability/v1/interactions";
|
|
5682
|
+
var BUSINESS_PROVENANCE = "/api/agent-observability/v1/business-provenance";
|
|
5683
|
+
var REQUESTS = `${BUSINESS_PROVENANCE}/requests`;
|
|
5684
|
+
var INTERACTIONS = `${BUSINESS_PROVENANCE}/interactions`;
|
|
5300
5685
|
var TRACES = "/api/agent-observability/v1/traces";
|
|
5301
5686
|
function isoToNanos(iso) {
|
|
5302
5687
|
const ms = Date.parse(iso);
|
|
@@ -5339,67 +5724,9 @@ async function getRawSpansByConversation(ctx, conversationId, opts = {}) {
|
|
|
5339
5724
|
function traceSearch(ctx, body) {
|
|
5340
5725
|
return request(ctx, SEARCH, { method: "POST", body });
|
|
5341
5726
|
}
|
|
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
5727
|
function getTraceGraph(ctx, traceId) {
|
|
5383
5728
|
return request(ctx, `${TRACES}/${encodeURIComponent(traceId)}/trace-graph`);
|
|
5384
5729
|
}
|
|
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
|
-
}
|
|
5403
5730
|
async function getSpansByConversation(ctx, conversationId, opts = {}) {
|
|
5404
5731
|
const agg = await request(ctx, SEARCH, {
|
|
5405
5732
|
method: "POST",
|
|
@@ -5424,38 +5751,6 @@ async function getSpansByConversation(ctx, conversationId, opts = {}) {
|
|
|
5424
5751
|
}) ?? {};
|
|
5425
5752
|
return (spans.hits?.hits ?? []).map((h) => h._source ?? {});
|
|
5426
5753
|
}
|
|
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
|
-
}
|
|
5459
5754
|
|
|
5460
5755
|
// src/bkn-trace/claude-judge.ts
|
|
5461
5756
|
import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
|
|
@@ -6838,6 +7133,8 @@ async function semanticJudge(question, answer, reference) {
|
|
|
6838
7133
|
};
|
|
6839
7134
|
}
|
|
6840
7135
|
function trace(ctx) {
|
|
7136
|
+
const lifecycle = traceLifecycleApi(ctx);
|
|
7137
|
+
const managed = new ManagedTrace(lifecycle);
|
|
6841
7138
|
const diagnoseOne = async (conversationId, opts = {}) => {
|
|
6842
7139
|
const { spans, traceIds } = await getRawSpansByConversation(ctx, conversationId);
|
|
6843
7140
|
if (spans.length === 0) throw new Error(`No spans found for conversation: ${conversationId}`);
|
|
@@ -6866,34 +7163,14 @@ function trace(ctx) {
|
|
|
6866
7163
|
};
|
|
6867
7164
|
};
|
|
6868
7165
|
return {
|
|
7166
|
+
/** Low-level BKN Trace 3.0 lifecycle and durable receipt API. */
|
|
7167
|
+
lifecycle,
|
|
7168
|
+
/** Own one complete interaction lifecycle around an application callback. */
|
|
7169
|
+
withInteraction: managed.withInteraction.bind(managed),
|
|
6869
7170
|
/** Raw trace search (OpenSearch-style body). */
|
|
6870
7171
|
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
7172
|
/** Normalized trace tree/status graph by trace id. */
|
|
6890
7173
|
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),
|
|
6897
7174
|
/** All span source docs for a conversation. */
|
|
6898
7175
|
spans: (conversationId, opts) => getSpansByConversation(ctx, conversationId, opts),
|
|
6899
7176
|
diagnose: diagnoseOne,
|
|
@@ -6965,15 +7242,18 @@ function vega(ctx) {
|
|
|
6965
7242
|
return {
|
|
6966
7243
|
catalogs: (opts) => listCatalogs(ctx, opts),
|
|
6967
7244
|
getCatalog: (id) => getCatalog(ctx, id),
|
|
6968
|
-
createCatalog: (req) => createCatalog(ctx, req),
|
|
6969
|
-
updateCatalog: (id, req) => updateCatalog(ctx, id, req),
|
|
7245
|
+
createCatalog: (req, opts) => createCatalog(ctx, req, opts),
|
|
7246
|
+
updateCatalog: (id, req, opts) => updateCatalog(ctx, id, req, opts),
|
|
6970
7247
|
enableCatalog: (id) => enableCatalog(ctx, id),
|
|
6971
7248
|
disableCatalog: (id) => disableCatalog(ctx, id),
|
|
6972
7249
|
deleteCatalog: (id) => deleteCatalog(ctx, id),
|
|
7250
|
+
testCatalogConnectionConfig: (req) => testCatalogConnectionConfig(ctx, req),
|
|
6973
7251
|
testCatalogConnection: (id) => testCatalogConnection(ctx, id),
|
|
7252
|
+
catalogHealthCheckSchedule: (id) => getCatalogHealthCheckSchedule(ctx, id),
|
|
7253
|
+
updateCatalogHealthCheckSchedule: (id, req) => updateCatalogHealthCheckSchedule(ctx, id, req),
|
|
6974
7254
|
discoverCatalog: (id, wait = false) => discoverCatalog(ctx, id, wait),
|
|
6975
7255
|
catalogResources: (id, category, limit, offset) => listCatalogResources(ctx, id, category, limit, offset),
|
|
6976
|
-
catalogHealth: (
|
|
7256
|
+
catalogHealth: (id) => catalogHealthStatus(ctx, id),
|
|
6977
7257
|
connectorTypes: () => listConnectorTypes(ctx),
|
|
6978
7258
|
connectorType: (type) => getConnectorType(ctx, type),
|
|
6979
7259
|
/** Run SQL / OpenSearch DSL directly against a data source. */
|
|
@@ -7120,7 +7400,7 @@ function createClient(opts = {}) {
|
|
|
7120
7400
|
kn: kn(ctx),
|
|
7121
7401
|
resource: resources(ctx),
|
|
7122
7402
|
dataflows: dataflows(ctx),
|
|
7123
|
-
agents:
|
|
7403
|
+
agents: agents2(ctx),
|
|
7124
7404
|
context: context(ctx),
|
|
7125
7405
|
models: models(ctx),
|
|
7126
7406
|
skills: skills(ctx),
|
|
@@ -7158,7 +7438,7 @@ function hostOf(baseUrl) {
|
|
|
7158
7438
|
return baseUrl;
|
|
7159
7439
|
}
|
|
7160
7440
|
}
|
|
7161
|
-
function
|
|
7441
|
+
function normalize2(baseUrl) {
|
|
7162
7442
|
return baseUrl.replace(/\/+$/, "");
|
|
7163
7443
|
}
|
|
7164
7444
|
function usernameOf(token) {
|
|
@@ -7167,7 +7447,7 @@ function usernameOf(token) {
|
|
|
7167
7447
|
return token.username ?? token.displayName ?? claims?.preferred_username ?? claims?.name ?? claims?.sub;
|
|
7168
7448
|
}
|
|
7169
7449
|
function attachToken(baseUrl, accessToken, opts = {}) {
|
|
7170
|
-
const url =
|
|
7450
|
+
const url = normalize2(baseUrl);
|
|
7171
7451
|
const token = {
|
|
7172
7452
|
baseUrl: url,
|
|
7173
7453
|
accessToken,
|
|
@@ -7270,7 +7550,7 @@ function listPlatforms2() {
|
|
|
7270
7550
|
);
|
|
7271
7551
|
}
|
|
7272
7552
|
function use(baseUrl) {
|
|
7273
|
-
const url =
|
|
7553
|
+
const url = normalize2(baseUrl);
|
|
7274
7554
|
if (!readToken(url)) {
|
|
7275
7555
|
throw new InputError(`No saved credentials for ${url}. Run \`openbkn auth login\` first.`);
|
|
7276
7556
|
}
|
|
@@ -7281,10 +7561,10 @@ function logout() {
|
|
|
7281
7561
|
return baseUrl ? deleteToken(baseUrl) : false;
|
|
7282
7562
|
}
|
|
7283
7563
|
function deletePlatform(baseUrl, userId) {
|
|
7284
|
-
return deleteToken(
|
|
7564
|
+
return deleteToken(normalize2(baseUrl), userId);
|
|
7285
7565
|
}
|
|
7286
7566
|
function switchUser(baseUrl, userOrName) {
|
|
7287
|
-
const url =
|
|
7567
|
+
const url = normalize2(baseUrl);
|
|
7288
7568
|
const users = usersOf(url);
|
|
7289
7569
|
const match = users.find((u) => u.userId === userOrName) ?? users.find((u) => (u.username ?? u.displayName) === userOrName);
|
|
7290
7570
|
if (!match) {
|
|
@@ -7295,7 +7575,7 @@ function switchUser(baseUrl, userOrName) {
|
|
|
7295
7575
|
return { baseUrl: url, userId: match.userId, username: match.username ?? match.displayName };
|
|
7296
7576
|
}
|
|
7297
7577
|
function usersOf(baseUrl) {
|
|
7298
|
-
const url =
|
|
7578
|
+
const url = normalize2(baseUrl);
|
|
7299
7579
|
return listPlatforms().find((p) => p.baseUrl === url)?.users ?? [];
|
|
7300
7580
|
}
|
|
7301
7581
|
function exportCreds() {
|
|
@@ -7313,6 +7593,7 @@ function exportCreds() {
|
|
|
7313
7593
|
|
|
7314
7594
|
export {
|
|
7315
7595
|
HttpError,
|
|
7596
|
+
ToolError,
|
|
7316
7597
|
InputError,
|
|
7317
7598
|
toExitCode,
|
|
7318
7599
|
formatError,
|
|
@@ -7321,6 +7602,7 @@ export {
|
|
|
7321
7602
|
deviceLogin,
|
|
7322
7603
|
credentialDeviceLogin,
|
|
7323
7604
|
request,
|
|
7605
|
+
lifecycleHint,
|
|
7324
7606
|
rawCall,
|
|
7325
7607
|
DEFAULT_BUSINESS_DOMAIN,
|
|
7326
7608
|
DEFAULT_LIST_LIMIT,
|
|
@@ -7334,7 +7616,8 @@ export {
|
|
|
7334
7616
|
getUserSafe,
|
|
7335
7617
|
changePasswordSafe,
|
|
7336
7618
|
admin,
|
|
7337
|
-
agents,
|
|
7619
|
+
agents2 as agents,
|
|
7620
|
+
releaseLifecycleSessions,
|
|
7338
7621
|
context,
|
|
7339
7622
|
dataflows,
|
|
7340
7623
|
parsePkMap,
|
|
@@ -7342,11 +7625,15 @@ export {
|
|
|
7342
7625
|
kn,
|
|
7343
7626
|
models,
|
|
7344
7627
|
resources,
|
|
7628
|
+
classifyPath,
|
|
7629
|
+
filesUnder,
|
|
7630
|
+
renderTree,
|
|
7345
7631
|
skills,
|
|
7346
7632
|
toolboxes,
|
|
7633
|
+
traceLifecycleApi,
|
|
7347
7634
|
renderReportMarkdown,
|
|
7348
7635
|
validateFixturePath,
|
|
7349
|
-
|
|
7636
|
+
ManagedTrace,
|
|
7350
7637
|
trace,
|
|
7351
7638
|
vega,
|
|
7352
7639
|
createClient,
|
|
@@ -7363,4 +7650,4 @@ export {
|
|
|
7363
7650
|
exportCreds,
|
|
7364
7651
|
auth_exports
|
|
7365
7652
|
};
|
|
7366
|
-
//# sourceMappingURL=chunk-
|
|
7653
|
+
//# sourceMappingURL=chunk-PC2F54XD.js.map
|