@botpress/evals 2.0.1-beta.0 → 2.0.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/runner.d.ts +14 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +55 -3
- package/dist/runner.js.map +4 -4
- package/dist/spans/index.js +34 -1
- package/dist/spans/index.js.map +2 -2
- package/dist/spans/local-span-source.js +34 -1
- package/dist/spans/local-span-source.js.map +2 -2
- package/dist/spans/span-source.d.ts +5 -0
- package/dist/spans/span-source.d.ts.map +1 -1
- package/dist/spans/sse-collector.d.ts +10 -0
- package/dist/spans/sse-collector.d.ts.map +1 -1
- package/dist/spans/sse-collector.js +34 -1
- package/dist/spans/sse-collector.js.map +2 -2
- package/package.json +1 -1
package/dist/runner.d.ts
CHANGED
|
@@ -12,6 +12,20 @@ export declare function runEval(evalDef: EvalDefinition, connection: BotConnecti
|
|
|
12
12
|
devServerUrl?: string;
|
|
13
13
|
idleTimeout?: number;
|
|
14
14
|
judgePassThreshold?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Configure the LLM judge inside the runner's OWN graders module. A bundled embedder can hold a
|
|
17
|
+
* different copy of that module, so initializing it here guarantees the instance grading consults.
|
|
18
|
+
*/
|
|
19
|
+
judge?: {
|
|
20
|
+
credentials: {
|
|
21
|
+
token: string;
|
|
22
|
+
apiUrl: string;
|
|
23
|
+
botId: string;
|
|
24
|
+
workspaceId?: string;
|
|
25
|
+
};
|
|
26
|
+
model?: string;
|
|
27
|
+
failClosed?: boolean;
|
|
28
|
+
};
|
|
15
29
|
onProgress?: (event: EvalProgressEvent) => void | Promise<void>;
|
|
16
30
|
evalIndex?: number;
|
|
17
31
|
/** Forwarded from EvalRunnerConfig — lets per-turn workflow waits unblock immediately on Stop instead of burning the full idleTimeout each. */
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,UAAU,EAGV,aAAa,EAEd,MAAM,SAAS,CAAA;AAGhB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,UAAU,EAGV,aAAa,EAEd,MAAM,SAAS,CAAA;AAGhB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AA0HrD,wBAAsB,OAAO,CAC3B,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,aAAa,EACzB,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE;QACN,WAAW,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QACnF,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,UAAU,CAAC,EAAE,OAAO,CAAA;KACrB,CAAA;IACD,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+IAA+I;IAC/I,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,UAAU,CAAC,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IAC3C,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IACnC,WAAW,CAAC,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAA;IAC7C,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;CAChB,GACL,OAAO,CAAC,UAAU,CAAC,CAgWrB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CA2GxG"}
|
package/dist/runner.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// src/runner.ts
|
|
2
|
+
import { Client as BpClientCtor } from "@botpress/client";
|
|
3
|
+
|
|
1
4
|
// src/definition.ts
|
|
2
5
|
var Eval = class {
|
|
3
6
|
name;
|
|
@@ -392,10 +395,11 @@ var SSECollector = class _SSECollector {
|
|
|
392
395
|
throw new Error("waitForTurnComplete aborted");
|
|
393
396
|
}
|
|
394
397
|
return new Promise((resolve2, reject) => {
|
|
398
|
+
const expected = accept ? [...accept].join(" or ") : "handler.conversation or handler.event";
|
|
395
399
|
const timer = setTimeout(() => {
|
|
400
|
+
clearStartTimer();
|
|
396
401
|
this._removeWaiter(waiter);
|
|
397
402
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
398
|
-
const expected = accept ? [...accept].join(" or ") : "handler.conversation or handler.event";
|
|
399
403
|
const reason = this.streamError ? `SSE stream died: ${this.streamError.message}` : `no ${expected} span completed`;
|
|
400
404
|
reject(
|
|
401
405
|
new Error(
|
|
@@ -403,8 +407,27 @@ var SSECollector = class _SSECollector {
|
|
|
403
407
|
)
|
|
404
408
|
);
|
|
405
409
|
}, opts.timeout);
|
|
410
|
+
let startTimer;
|
|
411
|
+
const clearStartTimer = () => {
|
|
412
|
+
if (startTimer !== void 0) clearTimeout(startTimer);
|
|
413
|
+
startTimer = void 0;
|
|
414
|
+
};
|
|
415
|
+
if (opts.handlerStartTimeoutMs !== void 0 && opts.handlerStartTimeoutMs < opts.timeout) {
|
|
416
|
+
startTimer = setTimeout(() => {
|
|
417
|
+
if (this._hasNewHandlerSpan(accept)) return;
|
|
418
|
+
clearTimeout(timer);
|
|
419
|
+
this._removeWaiter(waiter);
|
|
420
|
+
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
421
|
+
reject(
|
|
422
|
+
new Error(
|
|
423
|
+
`no ${expected} span started within ${opts.handlerStartTimeoutMs}ms \u2014 no handler is subscribed to this turn's trigger, so the turn can never complete; diagnostics: ${this._formatTurnDiagnostics()}`
|
|
424
|
+
)
|
|
425
|
+
);
|
|
426
|
+
}, opts.handlerStartTimeoutMs);
|
|
427
|
+
}
|
|
406
428
|
const onAbort = () => {
|
|
407
429
|
clearTimeout(timer);
|
|
430
|
+
clearStartTimer();
|
|
408
431
|
this._removeWaiter(waiter);
|
|
409
432
|
reject(new Error("waitForTurnComplete aborted"));
|
|
410
433
|
};
|
|
@@ -412,6 +435,7 @@ var SSECollector = class _SSECollector {
|
|
|
412
435
|
const waiter = (_span) => {
|
|
413
436
|
if (this._hasNewCompletedHandler(accept)) {
|
|
414
437
|
clearTimeout(timer);
|
|
438
|
+
clearStartTimer();
|
|
415
439
|
this._removeWaiter(waiter);
|
|
416
440
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
417
441
|
this._settleAfterHandler(settle).then(resolve2, reject);
|
|
@@ -713,6 +737,18 @@ ${value}` : value;
|
|
|
713
737
|
}
|
|
714
738
|
return false;
|
|
715
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* Whether a turn-handler span has appeared since startTurn() — any status. Proves a handler was
|
|
742
|
+
* dispatched. Never consumes keys (unlike {@link _hasNewCompletedHandler}).
|
|
743
|
+
*/
|
|
744
|
+
_hasNewHandlerSpan(acceptSpanNames) {
|
|
745
|
+
for (const [key, span] of this.spanMap) {
|
|
746
|
+
if (isTurnHandlerSpan(span) && (!acceptSpanNames || acceptSpanNames.has(span.name)) && !this.seenHandlerKeys.has(key)) {
|
|
747
|
+
return true;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
716
752
|
/**
|
|
717
753
|
* Check if a handler.workflow span matches the given condition.
|
|
718
754
|
*/
|
|
@@ -1356,6 +1392,7 @@ import { randomUUID } from "crypto";
|
|
|
1356
1392
|
var DEFAULT_IDLE_TIMEOUT = 3e4;
|
|
1357
1393
|
var DEFAULT_DEV_SERVER_URL = "http://localhost:3001";
|
|
1358
1394
|
var WORKFLOW_TRIGGER_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1395
|
+
var EVENT_HANDLER_START_TIMEOUT_MS = 3e4;
|
|
1359
1396
|
var BUILT_IN_STATES = {
|
|
1360
1397
|
conversation: "state",
|
|
1361
1398
|
user: "userState",
|
|
@@ -1435,6 +1472,14 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
1435
1472
|
const logger = options.logger ?? defaultLogger;
|
|
1436
1473
|
const idleTimeout = evalDef.options?.idleTimeout ?? options.idleTimeout ?? DEFAULT_IDLE_TIMEOUT;
|
|
1437
1474
|
const judgePassThreshold = evalDef.options?.judgePassThreshold ?? options.judgePassThreshold;
|
|
1475
|
+
if (options.judge) {
|
|
1476
|
+
const judgeClient = new BpClientCtor(options.judge.credentials);
|
|
1477
|
+
await initLLMJudge(judgeClient, {
|
|
1478
|
+
...options.judge.model !== void 0 ? { model: options.judge.model } : {},
|
|
1479
|
+
...options.judge.failClosed !== void 0 ? { failClosed: options.judge.failClosed } : {},
|
|
1480
|
+
logger
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1438
1483
|
const start = Date.now();
|
|
1439
1484
|
const turns = [];
|
|
1440
1485
|
let outcomeAssertions = [];
|
|
@@ -1526,6 +1571,8 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
1526
1571
|
// can get it absorbed by their transcript saves and silently skipped.
|
|
1527
1572
|
settleQuietMs: 1500,
|
|
1528
1573
|
settleMaxMs: 15e3,
|
|
1574
|
+
// Event turns fail fast when nothing is subscribed (see the constant).
|
|
1575
|
+
...turn.event ? { handlerStartTimeoutMs: EVENT_HANDLER_START_TIMEOUT_MS } : {},
|
|
1529
1576
|
...options.signal !== void 0 ? { abortSignal: options.signal } : {}
|
|
1530
1577
|
});
|
|
1531
1578
|
} catch (err) {
|
|
@@ -1545,8 +1592,13 @@ async function runEval(evalDef, connection, options = {}) {
|
|
|
1545
1592
|
});
|
|
1546
1593
|
}
|
|
1547
1594
|
}
|
|
1548
|
-
|
|
1549
|
-
|
|
1595
|
+
let turnData = transformSpans(collector.getTurnSpans());
|
|
1596
|
+
if (turn.event && !turn.expectSilence && turnData.messages.length === 0 && turnData.handlerDuration > 0) {
|
|
1597
|
+
for (let waited = 0; waited < 600 && turnData.messages.length === 0; waited += 150) {
|
|
1598
|
+
await new Promise((resolve2) => setTimeout(resolve2, 150));
|
|
1599
|
+
turnData = transformSpans(collector.getTurnSpans());
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1550
1602
|
const botResponse = turnData.messages.join("\n");
|
|
1551
1603
|
const botDuration = turnData.handlerDuration;
|
|
1552
1604
|
const evalStart = Date.now();
|