@cef-ai/eval 0.0.0-stage → 0.2.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.
Files changed (54) hide show
  1. package/README.md +195 -2
  2. package/dist/capture.d.ts +37 -0
  3. package/dist/capture.d.ts.map +1 -0
  4. package/dist/capture.js +70 -0
  5. package/dist/capture.js.map +1 -0
  6. package/dist/conformance.d.ts +6 -0
  7. package/dist/conformance.d.ts.map +1 -0
  8. package/dist/conformance.js +256 -0
  9. package/dist/conformance.js.map +1 -0
  10. package/dist/contract.d.ts +18 -0
  11. package/dist/contract.d.ts.map +1 -0
  12. package/dist/contract.js +176 -0
  13. package/dist/contract.js.map +1 -0
  14. package/dist/index.d.ts +18 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +11 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/layout.d.ts +105 -0
  19. package/dist/layout.d.ts.map +1 -0
  20. package/dist/layout.js +215 -0
  21. package/dist/layout.js.map +1 -0
  22. package/dist/pool.d.ts +13 -0
  23. package/dist/pool.d.ts.map +1 -0
  24. package/dist/pool.js +34 -0
  25. package/dist/pool.js.map +1 -0
  26. package/dist/result.d.ts +11 -0
  27. package/dist/result.d.ts.map +1 -0
  28. package/dist/result.js +72 -0
  29. package/dist/result.js.map +1 -0
  30. package/dist/run.d.ts +86 -0
  31. package/dist/run.d.ts.map +1 -0
  32. package/dist/run.js +240 -0
  33. package/dist/run.js.map +1 -0
  34. package/dist/score.d.ts +102 -0
  35. package/dist/score.d.ts.map +1 -0
  36. package/dist/score.js +433 -0
  37. package/dist/score.js.map +1 -0
  38. package/dist/storage.d.ts +218 -0
  39. package/dist/storage.d.ts.map +1 -0
  40. package/dist/storage.js +577 -0
  41. package/dist/storage.js.map +1 -0
  42. package/dist/summary.d.ts +105 -0
  43. package/dist/summary.d.ts.map +1 -0
  44. package/dist/summary.js +219 -0
  45. package/dist/summary.js.map +1 -0
  46. package/dist/types.d.ts +265 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +14 -0
  49. package/dist/types.js.map +1 -0
  50. package/dist/vault-store.d.ts +46 -0
  51. package/dist/vault-store.d.ts.map +1 -0
  52. package/dist/vault-store.js +127 -0
  53. package/dist/vault-store.js.map +1 -0
  54. package/package.json +27 -3
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `EvalStore` over a vault scope's object storage.
3
+ *
4
+ * Evaluations live in the vault the workflow runs in, in the workflow's scope:
5
+ * `/api/v1/vaults/<vault>/scopes/<scope>/objects/evals/workflows/<wf>/…`. So
6
+ * the vault decides who may read and write them, the same way it decides who
7
+ * may run the workflow: a read grant on the scope reads datasets and
8
+ * experiments, a write grant manages datasets and runs experiments.
9
+ *
10
+ * Takes the objects client STRUCTURALLY — vault-sdk's `vault.scope(s).objects`
11
+ * fits, and so does an in-memory fake — so this package keeps no dependency on
12
+ * the vault SDK and stays browser-safe.
13
+ */
14
+ import type { EvalStore } from "./storage.js";
15
+ /** What the store needs of a vault scope's objects client. */
16
+ export interface VaultObjects {
17
+ upload(path: string, data: Uint8Array, opts: {
18
+ contentType?: string;
19
+ ifNoneMatch?: "*";
20
+ }): Promise<unknown>;
21
+ get(path: string): Promise<Uint8Array>;
22
+ list(opts: {
23
+ prefix?: string;
24
+ }): Promise<{
25
+ items: Array<{
26
+ path: string;
27
+ }>;
28
+ }>;
29
+ }
30
+ export interface VaultObjectStoreOptions {
31
+ /** Path prefix inside the scope's objects. Default `"evals/"`. */
32
+ root?: string;
33
+ }
34
+ /**
35
+ * The server or the client dropped `If-None-Match: *`: a create-only upload of
36
+ * a path that exists was accepted. Writing on would turn every write-once key
37
+ * (case revisions, dataset versions) into an overwrite that still answers
38
+ * "won", so the store refuses instead.
39
+ */
40
+ export declare class ConditionalWriteUnsupportedError extends Error {
41
+ constructor();
42
+ }
43
+ /** The one key the write-once probe uses, so repeated sessions do not pile up keys nobody can delete. */
44
+ export declare const CONDITIONAL_WRITE_PROBE_KEY = ".probe/conditional-write";
45
+ export declare function vaultObjectStore(objects: VaultObjects, opts?: VaultObjectStoreOptions): EvalStore;
46
+ //# sourceMappingURL=vault-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault-store.d.ts","sourceRoot":"","sources":["../src/vault-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IAC3B,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,GAAG,CAAA;KAAE,GAChD,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC9E;AAED,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAwBD;;;;;GAKG;AACH,qBAAa,gCAAiC,SAAQ,KAAK;;CAS1D;AAED,yGAAyG;AACzG,eAAO,MAAM,2BAA2B,6BAA6B,CAAC;AAEtE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,GAAE,uBAA4B,GAAG,SAAS,CA+FrG"}
@@ -0,0 +1,127 @@
1
+ const errorField = (err, field) => err && typeof err === "object" ? err[field] : undefined;
2
+ /**
3
+ * The object is not there: vault-api's `OBJECT_NOT_FOUND`, by its code. A bare
4
+ * 404 is not enough — a wrong vault-api URL, an unmounted route or a proxy
5
+ * answers one too, and reading that as "absent" would let `putCase`'s
6
+ * write-once check pass on a read that never happened.
7
+ */
8
+ const isNotFound = (err) => errorField(err, "code") === "OBJECT_NOT_FOUND";
9
+ /**
10
+ * A create-only upload lost: vault-api answers `If-None-Match: *` on a taken
11
+ * path with 409 `OBJECT_EXISTS`. Nothing else counts — any other refusal is a
12
+ * failure, not someone else having won.
13
+ */
14
+ const isTaken = (err) => errorField(err, "status") === 409 && errorField(err, "code") === "OBJECT_EXISTS";
15
+ const encoder = new TextEncoder();
16
+ const decoder = new TextDecoder();
17
+ /**
18
+ * The server or the client dropped `If-None-Match: *`: a create-only upload of
19
+ * a path that exists was accepted. Writing on would turn every write-once key
20
+ * (case revisions, dataset versions) into an overwrite that still answers
21
+ * "won", so the store refuses instead.
22
+ */
23
+ export class ConditionalWriteUnsupportedError extends Error {
24
+ constructor() {
25
+ super("This vault does not honour create-only uploads (If-None-Match: *): an upload of a path that already " +
26
+ "exists was accepted. Evaluations need vault-api with Cerebellum-Network/ddc-node#1375 and " +
27
+ "@cef-ai/vault-sdk >= 5.8.0; nothing was written.");
28
+ this.name = "ConditionalWriteUnsupportedError";
29
+ }
30
+ }
31
+ /** The one key the write-once probe uses, so repeated sessions do not pile up keys nobody can delete. */
32
+ export const CONDITIONAL_WRITE_PROBE_KEY = ".probe/conditional-write";
33
+ export function vaultObjectStore(objects, opts = {}) {
34
+ const root = (opts.root ?? "evals/").replace(/\/*$/, "/").replace(/^\/+/, "");
35
+ const full = (key) => `${root}${key}`;
36
+ const createOnly = async (path, body) => {
37
+ try {
38
+ await objects.upload(path, encoder.encode(body), { contentType: "application/json", ifNoneMatch: "*" });
39
+ return true;
40
+ }
41
+ catch (err) {
42
+ if (isTaken(err))
43
+ return false;
44
+ throw err;
45
+ }
46
+ };
47
+ /*
48
+ * ONCE PER STORE, BEFORE THE FIRST WRITE-ONCE WRITE: prove the create-only
49
+ * upload is real. Two create-only uploads of the same fixed key; the second
50
+ * must lose. An old vault-sdk (which drops the option) or a vault-api that
51
+ * ignores the header accepts it, and then `putIfAbsent` would overwrite
52
+ * silently while answering `true`. Two round trips per store; a reader never
53
+ * pays them. A probe that failed for any other reason (network, no grant) is
54
+ * not remembered, so the next write asks again.
55
+ */
56
+ let probe = null;
57
+ const proveCreateOnly = () => {
58
+ probe ??= (async () => {
59
+ const key = full(CONDITIONAL_WRITE_PROBE_KEY);
60
+ await createOnly(key, "{}");
61
+ if (await createOnly(key, "{}"))
62
+ throw new ConditionalWriteUnsupportedError();
63
+ })().catch((err) => {
64
+ if (!(err instanceof ConditionalWriteUnsupportedError))
65
+ probe = null;
66
+ throw err;
67
+ });
68
+ return probe;
69
+ };
70
+ const list = async (prefix) => {
71
+ // vault-api lists every page server-side and answers once, so there is
72
+ // no continuation to follow and nothing to be silently cut short. If its
73
+ // List handler ever starts paging (a cursor in the response), this must
74
+ // follow it in the same change, or listings truncate without a word.
75
+ const res = await objects.list({ prefix: full(prefix) });
76
+ return res.items
77
+ .map((i) => i.path)
78
+ .filter((p) => p.startsWith(root))
79
+ .map((p) => p.slice(root.length))
80
+ // The probe's key is the store's own, not eval data.
81
+ .filter((k) => k.startsWith(prefix) && k !== CONDITIONAL_WRITE_PROBE_KEY)
82
+ .sort();
83
+ };
84
+ return {
85
+ list,
86
+ /** Derived from the flat listing: the object API has no delimiter. */
87
+ async listPrefixes(prefix) {
88
+ const out = new Set();
89
+ for (const key of await list(prefix)) {
90
+ const slash = key.indexOf("/", prefix.length);
91
+ if (slash > prefix.length)
92
+ out.add(key.slice(0, slash + 1));
93
+ }
94
+ return [...out].sort();
95
+ },
96
+ async get(key) {
97
+ try {
98
+ return decoder.decode(await objects.get(full(key)));
99
+ }
100
+ catch (err) {
101
+ // Only a missing object is `null`. Anything else (no grant, vault-api
102
+ // down) must throw, or `putCase`'s write-once check would pass on a
103
+ // failed read and overwrite a real case.
104
+ if (isNotFound(err))
105
+ return null;
106
+ throw err;
107
+ }
108
+ },
109
+ async put(key, body) {
110
+ await objects.upload(full(key), encoder.encode(body), { contentType: "application/json" });
111
+ },
112
+ /**
113
+ * The server decides: `If-None-Match: *` on the upload, and a taken path
114
+ * answers `false`. No read first and no unconditional fallback: either
115
+ * could let two writers both believe they cut the same version. The first
116
+ * call proves the mechanism works (see `proveCreateOnly`) and refuses with
117
+ * `ConditionalWriteUnsupportedError` when it does not.
118
+ */
119
+ async putIfAbsent(key, body) {
120
+ await proveCreateOnly();
121
+ return createOnly(full(key), body);
122
+ },
123
+ /** Pinned by `vault-store.test.ts`, which reads `ifNoneMatch` off the upload this store sent. */
124
+ atomicity: "conditional-write",
125
+ };
126
+ }
127
+ //# sourceMappingURL=vault-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault-store.js","sourceRoot":"","sources":["../src/vault-store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,30 @@
1
1
  {
2
2
  "name": "@cef-ai/eval",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "Workflow evaluations for CEF: datasets, experiments, scoring and comparison over an injected store and workflow target.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^20.11.0",
22
+ "typescript": "^5.4.0",
23
+ "vitest": "^1.5.0"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -b",
27
+ "test": "tsc -p tsconfig.test.json && vitest run",
28
+ "lint": "eslint src"
29
+ }
6
30
  }