@workglow/eval 0.3.48 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/evals/EvalSweepTask.d.ts +47 -0
- package/dist/evals/EvalSweepTask.d.ts.map +1 -0
- package/dist/evals/runner.d.ts +7 -1
- package/dist/evals/runner.d.ts.map +1 -1
- package/dist/evals/streamSubscribe.d.ts +2 -1
- package/dist/evals/streamSubscribe.d.ts.map +1 -1
- package/dist/evals/types.d.ts +16 -2
- package/dist/evals/types.d.ts.map +1 -1
- package/dist/test/evalSweepTask.test.d.ts +7 -0
- package/dist/test/evalSweepTask.test.d.ts.map +1 -0
- package/dist/workglow-eval.js +82 -10
- package/package.json +14 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA2C7C,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,EACrC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACnC,IAAI,CA2CN"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import type { IExecuteContext } from "@workglow/task-graph";
|
|
7
|
+
import { Task } from "@workglow/task-graph";
|
|
8
|
+
import type { DataPortSchema } from "@workglow/util/schema";
|
|
9
|
+
import type { DatasetRowRecord, EvalStores } from "../storage";
|
|
10
|
+
import { type SweepOptions } from "./runner";
|
|
11
|
+
export interface EvalSweepTaskOutput {
|
|
12
|
+
readonly run_id: string;
|
|
13
|
+
readonly rows: number;
|
|
14
|
+
readonly models: number;
|
|
15
|
+
}
|
|
16
|
+
/** An `interface` carries no index signature; the mapped form is what `DataPorts` accepts. */
|
|
17
|
+
type Ports<T> = {
|
|
18
|
+
[K in keyof T]: T[K];
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Runs one sweep as a task, so the run has a graph.
|
|
22
|
+
*
|
|
23
|
+
* The sweep is a nested loop over models and rows, and each row is its own
|
|
24
|
+
* small workflow — so putting every row through the CLI seam would report one
|
|
25
|
+
* RUN per row: fifteen hundred of them for a 500-row sweep of three models,
|
|
26
|
+
* which is not a graph anyone can read. One task for the sweep is the honest
|
|
27
|
+
* unit: it is what the operator started, and its progress is what they want to
|
|
28
|
+
* watch.
|
|
29
|
+
*
|
|
30
|
+
* The stores, rows and options are passed as construction state rather than as
|
|
31
|
+
* ports. They are live handles and parsed dataset records, not values a form
|
|
32
|
+
* could supply or a cache could serialize.
|
|
33
|
+
*/
|
|
34
|
+
export declare class EvalSweepTask extends Task<Record<string, never>, Ports<EvalSweepTaskOutput>> {
|
|
35
|
+
#private;
|
|
36
|
+
static readonly type = "EvalSweepTask";
|
|
37
|
+
static readonly category = "Eval";
|
|
38
|
+
static readonly title = "Run eval sweep";
|
|
39
|
+
static readonly cacheable = false;
|
|
40
|
+
static inputSchema(): DataPortSchema;
|
|
41
|
+
static outputSchema(): DataPortSchema;
|
|
42
|
+
/** Hands the task the live handles a port cannot carry. */
|
|
43
|
+
withSweep(stores: EvalStores, rows: readonly DatasetRowRecord[], options: SweepOptions): this;
|
|
44
|
+
execute(_input: Record<string, never>, context: IExecuteContext): Promise<Ports<EvalSweepTaskOutput>>;
|
|
45
|
+
}
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=EvalSweepTask.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EvalSweepTask.d.ts","sourceRoot":"","sources":["../../src/evals/EvalSweepTask.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAmBvD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,8FAA8F;AAC9F,KAAK,KAAK,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC;AAEzC;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAc,SAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;;IACxF,gBAAyB,IAAI,mBAAmB;IAChD,gBAAyB,QAAQ,UAAU;IAC3C,gBAAyB,KAAK,oBAAoB;IAClD,gBAAyB,SAAS,SAAS;IAE3C,OAAgB,WAAW,IAAI,cAAc,CAE5C;IACD,OAAgB,YAAY,IAAI,cAAc,CAE7C;IAMD,2DAA2D;IAC3D,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,gBAAgB,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAK5F;IAEc,OAAO,CACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CA2BrC;CACF"}
|
package/dist/evals/runner.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import type { ModelPricing } from "@workglow/ai";
|
|
7
|
-
import type { StreamEvent, Usage } from "@workglow/task-graph";
|
|
7
|
+
import type { IExecuteContext, StreamEvent, Usage } from "@workglow/task-graph";
|
|
8
8
|
import type { EvalKind } from "../models";
|
|
9
9
|
import type { DatasetRowRecord, EvalStores } from "../storage";
|
|
10
10
|
import type { ColumnOptions, DatasetContext } from "./types";
|
|
@@ -22,6 +22,12 @@ export interface SweepOptions {
|
|
|
22
22
|
* pays nothing for it.
|
|
23
23
|
*/
|
|
24
24
|
readonly onStreamChunk?: ((event: StreamEvent) => void) | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* The sweep task's own context. Given one, each row's workflow is owned for
|
|
27
|
+
* its duration, so the run is a single task graph the progress surfaces can
|
|
28
|
+
* see into rather than a loop of invisible standalone runs.
|
|
29
|
+
*/
|
|
30
|
+
readonly owner?: IExecuteContext | undefined;
|
|
25
31
|
}
|
|
26
32
|
/**
|
|
27
33
|
* Map one run's token accounting onto the result row's columns.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/evals/runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,cAAc,CAAC;AAE9D,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/evals/runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,cAAc,CAAC;AAE9D,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI/D,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAe,MAAM,SAAS,CAAC;AAE1E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAChB,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,KAAK,IAAI,CAAC,GAC7F,SAAS,CAAC;IACd;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpE;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,OAAO,EAAE,YAAY,GAAG,SAAS,GAChC;IACD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAWA;AAoBD;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,SAAS,gBAAgB,EAAE,EACjC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,MAAM,CAAC,CAmFjB"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import type { StreamEvent, Workflow } from "@workglow/task-graph";
|
|
7
|
+
import type { RowOwner } from "./types";
|
|
7
8
|
/**
|
|
8
9
|
* Run a workflow, forwarding its `stream_chunk` events to `onStreamChunk` for
|
|
9
10
|
* the duration of the run only.
|
|
@@ -11,5 +12,5 @@ import type { StreamEvent, Workflow } from "@workglow/task-graph";
|
|
|
11
12
|
* When no listener is given, nothing is subscribed at all — a 500-row sweep
|
|
12
13
|
* without `--stream` pays nothing for it.
|
|
13
14
|
*/
|
|
14
|
-
export declare function runWithStreamChunks<Output>(workflow: Workflow, onStreamChunk: ((event: StreamEvent) => void) | undefined): Promise<Output>;
|
|
15
|
+
export declare function runWithStreamChunks<Output>(workflow: Workflow, onStreamChunk: ((event: StreamEvent) => void) | undefined, owner?: RowOwner | undefined): Promise<Output>;
|
|
15
16
|
//# sourceMappingURL=streamSubscribe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamSubscribe.d.ts","sourceRoot":"","sources":["../../src/evals/streamSubscribe.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAc,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"streamSubscribe.d.ts","sourceRoot":"","sources":["../../src/evals/streamSubscribe.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAc,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAC9C,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,SAAS,EACzD,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,GAC3B,OAAO,CAAC,MAAM,CAAC,CAgBjB"}
|
package/dist/evals/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2026 Steven Roussey <sroussey@gmail.com>
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import type { StreamEvent, Usage } from "@workglow/task-graph";
|
|
6
|
+
import type { IExecuteContext, StreamEvent, Usage } from "@workglow/task-graph";
|
|
7
7
|
import type { DatasetRow, LabelNames } from "../hf/types";
|
|
8
8
|
/** What one workflow execution produced for one dataset row. */
|
|
9
9
|
export interface RowPrediction {
|
|
@@ -20,7 +20,21 @@ export interface RowPrediction {
|
|
|
20
20
|
* the life of the call only — `--stream` is the only caller that passes it, so
|
|
21
21
|
* an ordinary sweep never pays for the subscription.
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* How a row's work joins the run's single task graph.
|
|
25
|
+
*
|
|
26
|
+
* Each row builds its own small workflow. Run standalone those are invisible:
|
|
27
|
+
* the run is one graph, and anything executed outside it is work no progress
|
|
28
|
+
* surface can see. Handing the executor the sweep task's context lets it OWN
|
|
29
|
+
* that workflow for the row's duration, so the row appears as a live child and
|
|
30
|
+
* leaves when it finishes.
|
|
31
|
+
*/
|
|
32
|
+
export interface RowOwner {
|
|
33
|
+
readonly context: IExecuteContext;
|
|
34
|
+
/** Row label, e.g. `claude-haiku-4-5 · row 12`. */
|
|
35
|
+
readonly title: string;
|
|
36
|
+
}
|
|
37
|
+
export type RowExecutor = (row: DatasetRow, onStreamChunk?: (event: StreamEvent) => void, owner?: RowOwner) => Promise<RowPrediction>;
|
|
24
38
|
export interface ColumnOptions {
|
|
25
39
|
readonly textColumn: string;
|
|
26
40
|
/** classify: gold label column. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/evals/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/evals/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,gEAAgE;AAChE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;CACpC;AAED;;;;;;GAMG;AACH;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,WAAW,GAAG,CACxB,GAAG,EAAE,UAAU,EACf,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,EAC5C,KAAK,CAAC,EAAE,QAAQ,KACb,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,mCAAmC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAChD,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gDAAgD;IAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAChD,uDAAuD;IACvD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evalSweepTask.test.d.ts","sourceRoot":"","sources":["../../src/test/evalSweepTask.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/dist/workglow-eval.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/workglow-eval.ts
|
|
5
|
+
import { registerWebCommand } from "@workglow/cli";
|
|
5
6
|
import { program } from "commander";
|
|
6
7
|
|
|
7
8
|
// src/hf/auth.ts
|
|
@@ -698,6 +699,13 @@ function registerReportCommand(program, openStores) {
|
|
|
698
699
|
});
|
|
699
700
|
}
|
|
700
701
|
|
|
702
|
+
// src/commands/run.ts
|
|
703
|
+
import { withCli } from "@workglow/cli";
|
|
704
|
+
import { Workflow as Workflow4 } from "@workglow/task-graph";
|
|
705
|
+
|
|
706
|
+
// src/evals/EvalSweepTask.ts
|
|
707
|
+
import { Task } from "@workglow/task-graph";
|
|
708
|
+
|
|
701
709
|
// src/evals/runner.ts
|
|
702
710
|
import { estimateCost } from "@workglow/ai";
|
|
703
711
|
|
|
@@ -974,13 +982,17 @@ ${fence}`;
|
|
|
974
982
|
}
|
|
975
983
|
|
|
976
984
|
// src/evals/streamSubscribe.ts
|
|
977
|
-
async function runWithStreamChunks(workflow, onStreamChunk) {
|
|
985
|
+
async function runWithStreamChunks(workflow, onStreamChunk, owner) {
|
|
978
986
|
const listener = onStreamChunk ? (_taskId, event) => onStreamChunk(event) : undefined;
|
|
979
987
|
if (listener)
|
|
980
988
|
workflow.on("stream_chunk", listener);
|
|
989
|
+
if (owner)
|
|
990
|
+
owner.context.own(workflow, { title: owner.title });
|
|
981
991
|
try {
|
|
982
992
|
return await workflow.run();
|
|
983
993
|
} finally {
|
|
994
|
+
if (owner)
|
|
995
|
+
owner.context.disown(workflow);
|
|
984
996
|
if (listener)
|
|
985
997
|
workflow.off("stream_chunk", listener);
|
|
986
998
|
}
|
|
@@ -1025,7 +1037,7 @@ function makeClassifyExecutor(model, options, context) {
|
|
|
1025
1037
|
required: ["label"],
|
|
1026
1038
|
additionalProperties: false
|
|
1027
1039
|
};
|
|
1028
|
-
return async (row, onStreamChunk) => {
|
|
1040
|
+
return async (row, onStreamChunk, owner) => {
|
|
1029
1041
|
const text = String(row[options.textColumn] ?? "");
|
|
1030
1042
|
const workflow = new Workflow;
|
|
1031
1043
|
workflow.structuredGeneration({
|
|
@@ -1035,7 +1047,7 @@ function makeClassifyExecutor(model, options, context) {
|
|
|
1035
1047
|
temperature: 0,
|
|
1036
1048
|
maxTokens: 256
|
|
1037
1049
|
});
|
|
1038
|
-
const output = await runWithStreamChunks(workflow, onStreamChunk);
|
|
1050
|
+
const output = await runWithStreamChunks(workflow, onStreamChunk, owner);
|
|
1039
1051
|
return {
|
|
1040
1052
|
expected: expectedLabel(row, options.labelColumn, context.labelNames, labels),
|
|
1041
1053
|
predicted: String(output.object?.label ?? ""),
|
|
@@ -1112,7 +1124,7 @@ function makeExtractExecutor(model, options, context) {
|
|
|
1112
1124
|
const instruction = options.instruction ?? DEFAULT_INSTRUCTION;
|
|
1113
1125
|
const explicitFields = options.fields && options.fields.length > 0 ? resolveExtractionFields([], options.keyField, options.fields) : undefined;
|
|
1114
1126
|
const explicitSchema = explicitFields ? buildItemsSchema(explicitFields, options.keyField) : undefined;
|
|
1115
|
-
return async (row, onStreamChunk) => {
|
|
1127
|
+
return async (row, onStreamChunk, owner) => {
|
|
1116
1128
|
const text = String(row[options.textColumn] ?? "");
|
|
1117
1129
|
const expectedRows = parseExpectedRows(row[options.expectedColumn], options.expectedColumn);
|
|
1118
1130
|
const fields = explicitFields ?? resolveExtractionFields(expectedRows, options.keyField, undefined);
|
|
@@ -1125,7 +1137,7 @@ function makeExtractExecutor(model, options, context) {
|
|
|
1125
1137
|
temperature: 0,
|
|
1126
1138
|
maxTokens: 2048
|
|
1127
1139
|
});
|
|
1128
|
-
const output = await runWithStreamChunks(workflow, onStreamChunk);
|
|
1140
|
+
const output = await runWithStreamChunks(workflow, onStreamChunk, owner);
|
|
1129
1141
|
const items = Array.isArray(output.object?.items) ? output.object.items : [];
|
|
1130
1142
|
return {
|
|
1131
1143
|
expected: JSON.stringify(expectedRows),
|
|
@@ -1144,12 +1156,12 @@ function makeSimilarityExecutor(model, options, context) {
|
|
|
1144
1156
|
throw new Error(`dataset has no column "${column}" (columns: ${context.columns.join(", ")}) \u2014 ` + `set --text-column/--pair-column/--score-column`);
|
|
1145
1157
|
}
|
|
1146
1158
|
}
|
|
1147
|
-
return async (row, onStreamChunk) => {
|
|
1159
|
+
return async (row, onStreamChunk, owner) => {
|
|
1148
1160
|
const a = String(row[options.textColumn] ?? "");
|
|
1149
1161
|
const b = String(row[options.pairColumn] ?? "");
|
|
1150
1162
|
const workflow = new Workflow3;
|
|
1151
1163
|
workflow.textEmbedding({ model, text: [a, b] });
|
|
1152
|
-
const output = await runWithStreamChunks(workflow, onStreamChunk);
|
|
1164
|
+
const output = await runWithStreamChunks(workflow, onStreamChunk, owner);
|
|
1153
1165
|
const vectors = Array.isArray(output.vector) ? output.vector : [output.vector];
|
|
1154
1166
|
if (vectors.length < 2) {
|
|
1155
1167
|
throw new Error(`expected 2 embeddings, got ${vectors.length}`);
|
|
@@ -1230,7 +1242,7 @@ async function runSweep(stores, rows, options) {
|
|
|
1230
1242
|
outcome = failedOutcome(parseError ?? "invalid stored row");
|
|
1231
1243
|
} else {
|
|
1232
1244
|
try {
|
|
1233
|
-
const prediction = await executor(row, options.onStreamChunk);
|
|
1245
|
+
const prediction = await executor(row, options.onStreamChunk, options.owner ? { context: options.owner, title: `${modelId} \xB7 row ${record.row_index}` } : undefined);
|
|
1234
1246
|
outcomeUsage = prediction.usage;
|
|
1235
1247
|
outcome = {
|
|
1236
1248
|
ok: 1,
|
|
@@ -1270,6 +1282,61 @@ function failedOutcome(error) {
|
|
|
1270
1282
|
};
|
|
1271
1283
|
}
|
|
1272
1284
|
|
|
1285
|
+
// src/evals/EvalSweepTask.ts
|
|
1286
|
+
var INPUT = {
|
|
1287
|
+
type: "object",
|
|
1288
|
+
properties: {},
|
|
1289
|
+
additionalProperties: false
|
|
1290
|
+
};
|
|
1291
|
+
var OUTPUT = {
|
|
1292
|
+
type: "object",
|
|
1293
|
+
properties: {
|
|
1294
|
+
run_id: { type: "string", title: "Run id" },
|
|
1295
|
+
rows: { type: "number", title: "Dataset rows" },
|
|
1296
|
+
models: { type: "number", title: "Models swept" }
|
|
1297
|
+
},
|
|
1298
|
+
required: ["run_id"],
|
|
1299
|
+
additionalProperties: false
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1302
|
+
class EvalSweepTask extends Task {
|
|
1303
|
+
static type = "EvalSweepTask";
|
|
1304
|
+
static category = "Eval";
|
|
1305
|
+
static title = "Run eval sweep";
|
|
1306
|
+
static cacheable = false;
|
|
1307
|
+
static inputSchema() {
|
|
1308
|
+
return INPUT;
|
|
1309
|
+
}
|
|
1310
|
+
static outputSchema() {
|
|
1311
|
+
return OUTPUT;
|
|
1312
|
+
}
|
|
1313
|
+
#stores;
|
|
1314
|
+
#rows = [];
|
|
1315
|
+
#options;
|
|
1316
|
+
withSweep(stores, rows, options) {
|
|
1317
|
+
this.#stores = stores;
|
|
1318
|
+
this.#rows = rows;
|
|
1319
|
+
this.#options = options;
|
|
1320
|
+
return this;
|
|
1321
|
+
}
|
|
1322
|
+
async execute(_input, context) {
|
|
1323
|
+
const stores = this.#stores;
|
|
1324
|
+
const options = this.#options;
|
|
1325
|
+
if (!stores || !options)
|
|
1326
|
+
throw new Error("EvalSweepTask.withSweep was never called");
|
|
1327
|
+
await context.updateProgress(0, `${this.#rows.length} rows \xD7 ${options.models.length} model(s)`);
|
|
1328
|
+
const run_id = await runSweep(stores, this.#rows, {
|
|
1329
|
+
...options,
|
|
1330
|
+
owner: context,
|
|
1331
|
+
onProgress: (done, total, model, ok, usage) => {
|
|
1332
|
+
options.onProgress?.(done, total, model, ok, usage);
|
|
1333
|
+
context.updateProgress(total > 0 ? done / total * 100 : 0, `${model} \xB7 ${done}/${total}`);
|
|
1334
|
+
}
|
|
1335
|
+
});
|
|
1336
|
+
return { run_id, rows: this.#rows.length, models: options.models.length };
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1273
1340
|
// src/report/liveTally.ts
|
|
1274
1341
|
import { estimateCost as estimateCost2, formatCost, formatUsage } from "@workglow/ai";
|
|
1275
1342
|
import { mergeUsage } from "@workglow/task-graph";
|
|
@@ -1386,7 +1453,7 @@ async function runEval(kind, flags, stores) {
|
|
|
1386
1453
|
if (event.type === "text-delta")
|
|
1387
1454
|
process.stderr.write(event.textDelta);
|
|
1388
1455
|
} : undefined;
|
|
1389
|
-
const
|
|
1456
|
+
const sweep = new EvalSweepTask({ title: `${kind} \xB7 ${flags.dataset}` }).withSweep(stores, limited, {
|
|
1390
1457
|
kind,
|
|
1391
1458
|
dataset: flags.dataset,
|
|
1392
1459
|
split: flags.split,
|
|
@@ -1400,6 +1467,10 @@ async function runEval(kind, flags, stores) {
|
|
|
1400
1467
|
},
|
|
1401
1468
|
onStreamChunk
|
|
1402
1469
|
});
|
|
1470
|
+
const workflow = new Workflow4;
|
|
1471
|
+
workflow.pipe(sweep);
|
|
1472
|
+
const output = await withCli(workflow, { interactive: false }).run();
|
|
1473
|
+
const runId = output.run_id;
|
|
1403
1474
|
console.error(`run ${runId} complete
|
|
1404
1475
|
`);
|
|
1405
1476
|
await printReport(stores, runId, flags.format);
|
|
@@ -1546,9 +1617,10 @@ var stores;
|
|
|
1546
1617
|
var openStores = () => stores ??= createSqliteStores(config);
|
|
1547
1618
|
var providers;
|
|
1548
1619
|
var ensureProviders = () => providers ??= registerEvalProviders(config);
|
|
1549
|
-
program.version("2.0.0").description("Workglow eval example \u2014 pull HuggingFace datasets into storage, run task workflows " + "across models, and score the stored results");
|
|
1620
|
+
program.name("workglow-eval").version("2.0.0").description("Workglow eval example \u2014 pull HuggingFace datasets into storage, run task workflows " + "across models, and score the stored results");
|
|
1550
1621
|
registerDatasetCommand(program, openStores);
|
|
1551
1622
|
registerRunCommand(program, openStores, ensureProviders);
|
|
1552
1623
|
registerReportCommand(program, openStores);
|
|
1624
|
+
registerWebCommand(program);
|
|
1553
1625
|
await program.parseAsync(process.argv);
|
|
1554
1626
|
process.exit(process.exitCode ?? 0);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workglow/eval",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/workglow-dev/libs.git",
|
|
@@ -33,18 +33,19 @@
|
|
|
33
33
|
"src/**/*.md"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@workglow/ai": "0.
|
|
37
|
-
"@workglow/anthropic": "0.
|
|
38
|
-
"@workglow/
|
|
39
|
-
"@workglow/
|
|
40
|
-
"@workglow/
|
|
41
|
-
"@workglow/
|
|
42
|
-
"@workglow/
|
|
43
|
-
"@workglow/
|
|
44
|
-
"@workglow/
|
|
45
|
-
"@workglow/
|
|
46
|
-
"@workglow/
|
|
47
|
-
"@workglow/
|
|
36
|
+
"@workglow/ai": "0.4.0",
|
|
37
|
+
"@workglow/anthropic": "0.4.0",
|
|
38
|
+
"@workglow/cli": "0.4.0",
|
|
39
|
+
"@workglow/deepseek": "0.4.0",
|
|
40
|
+
"@workglow/google-gemini": "0.4.0",
|
|
41
|
+
"@workglow/huggingface-transformers": "0.4.0",
|
|
42
|
+
"@workglow/node-llama-cpp": "0.4.0",
|
|
43
|
+
"@workglow/openai": "0.4.0",
|
|
44
|
+
"@workglow/sqlite": "0.4.0",
|
|
45
|
+
"@workglow/storage": "0.4.0",
|
|
46
|
+
"@workglow/task-graph": "0.4.0",
|
|
47
|
+
"@workglow/util": "0.4.0",
|
|
48
|
+
"@workglow/xai": "0.4.0",
|
|
48
49
|
"@huggingface/transformers": "^4.2.0",
|
|
49
50
|
"commander": "^15.0.0",
|
|
50
51
|
"hyparquet": "^1.28.2",
|