pareta 2.0.0 → 3.0.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/README.md +1 -1
- package/dist/index.cjs +80 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -38
- package/dist/index.d.ts +55 -38
- package/dist/index.mjs +80 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ contender honestly:
|
|
|
41
41
|
|
|
42
42
|
```ts
|
|
43
43
|
const set = await pa.evals.sets.create({
|
|
44
|
-
items: [...],
|
|
44
|
+
items: [...], prompt: "extract vendor, total and date from each invoice",
|
|
45
45
|
});
|
|
46
46
|
const run = await pa.evals.runs.create({
|
|
47
47
|
evalSet: set.id, models: ["auto"], frontier: ["claude-opus-4-7"], wait: true,
|
package/dist/index.cjs
CHANGED
|
@@ -174,7 +174,7 @@ function parseSSE(reader, opts) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
// src/version.ts
|
|
177
|
-
var VERSION = "
|
|
177
|
+
var VERSION = "3.0.0";
|
|
178
178
|
|
|
179
179
|
// src/money.ts
|
|
180
180
|
var MICRO_PER_CENT = 10000n;
|
|
@@ -255,6 +255,36 @@ var ChatCompletion = class extends BaseModel {
|
|
|
255
255
|
get usage() {
|
|
256
256
|
return new Usage(this.raw.usage ?? {});
|
|
257
257
|
}
|
|
258
|
+
/** #164 receipt, held OFF `.raw` so `toDict()` stays the raw server JSON. */
|
|
259
|
+
_cost;
|
|
260
|
+
/** #164: attach the per-call receipt from the response headers (billed +
|
|
261
|
+
* the frontier counterfactual, micro-USD ints). Chainable. */
|
|
262
|
+
withCost(headers) {
|
|
263
|
+
const int = (name) => {
|
|
264
|
+
const v = headers?.get(name);
|
|
265
|
+
if (v == null) return null;
|
|
266
|
+
const n = parseInt(v, 10);
|
|
267
|
+
return Number.isNaN(n) ? null : n;
|
|
268
|
+
};
|
|
269
|
+
this._cost = {
|
|
270
|
+
billed: int("X-Pareta-Billed"),
|
|
271
|
+
frontier: int("X-Pareta-Frontier-Would-Have-Cost")
|
|
272
|
+
};
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
/** What Pareta charged, micro-USD (0 on an idempotent replay); null if absent. */
|
|
276
|
+
get billedMicroUsd() {
|
|
277
|
+
return this._cost?.billed ?? null;
|
|
278
|
+
}
|
|
279
|
+
/** What one list-priced frontier call would have cost, micro-USD. */
|
|
280
|
+
get frontierWouldHaveCostMicroUsd() {
|
|
281
|
+
return this._cost?.frontier ?? null;
|
|
282
|
+
}
|
|
283
|
+
/** frontier / billed — e.g. 17 = 17× cheaper; null if either is missing or billed is 0. */
|
|
284
|
+
get savingsFactor() {
|
|
285
|
+
const b = this.billedMicroUsd, f = this.frontierWouldHaveCostMicroUsd;
|
|
286
|
+
return b && f && b > 0 ? Math.round(f / b * 10) / 10 : null;
|
|
287
|
+
}
|
|
258
288
|
};
|
|
259
289
|
var ChatCompletionChunk = class extends ChatCompletion {
|
|
260
290
|
};
|
|
@@ -342,9 +372,9 @@ var EvalSet = class extends BaseModel {
|
|
|
342
372
|
return this.raw.scoring_strategy ?? null;
|
|
343
373
|
}
|
|
344
374
|
/** The one-sentence success criterion this set was created with (CB1:
|
|
345
|
-
* DATA +
|
|
346
|
-
get
|
|
347
|
-
return this.raw.
|
|
375
|
+
* DATA + PROMPT). Required at create. */
|
|
376
|
+
get prompt() {
|
|
377
|
+
return this.raw.prompt ?? null;
|
|
348
378
|
}
|
|
349
379
|
};
|
|
350
380
|
function evalSetFromCreate(raw) {
|
|
@@ -383,23 +413,24 @@ var ProposalResult = class extends BaseModel {
|
|
|
383
413
|
get closestTask() {
|
|
384
414
|
return this.raw.closest_task ?? null;
|
|
385
415
|
}
|
|
386
|
-
get
|
|
387
|
-
return this.raw.
|
|
416
|
+
get prompt() {
|
|
417
|
+
return this.raw.prompt ?? null;
|
|
388
418
|
}
|
|
389
419
|
get message() {
|
|
390
420
|
return this.raw.message ?? null;
|
|
391
421
|
}
|
|
392
|
-
/** True when
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
* `task: "custom-eval"`, never
|
|
422
|
+
/** True when exactly ONE homogeneous SPECIFIC task matched at high/medium
|
|
423
|
+
* confidence with no conflict/split — the case a task-less `create`
|
|
424
|
+
* proceeds with, no human confirming. `custom-eval` (a judge panel grading
|
|
425
|
+
* each answer against your prompt) is EXCLUDED: it is offered only when
|
|
426
|
+
* nothing specific fits, and using it is the user's CHOICE — opt in with
|
|
427
|
+
* `task: "custom-eval"`, never silently. */
|
|
398
428
|
get isClean() {
|
|
399
429
|
const props = this.proposals;
|
|
400
430
|
return this.homogeneous && this.conflict == null && this.split == null && props.length === 1 && (props[0].confidence === "high" || props[0].confidence === "medium") && Boolean(props[0].taskId) && props[0].taskId !== "custom-eval";
|
|
401
431
|
}
|
|
402
|
-
/**
|
|
432
|
+
/** How a task-less `create` would score this set, or null if the result
|
|
433
|
+
* isn't clean (pass `task` yourself). */
|
|
403
434
|
get boundTask() {
|
|
404
435
|
return this.isClean ? this.proposals[0].taskId : null;
|
|
405
436
|
}
|
|
@@ -644,10 +675,14 @@ var Completions = class {
|
|
|
644
675
|
cast: (raw) => new ChatCompletionChunk(raw)
|
|
645
676
|
});
|
|
646
677
|
}
|
|
678
|
+
let headers;
|
|
647
679
|
return this.client.request("POST", PATH, {
|
|
648
680
|
body,
|
|
649
|
-
cast: (raw) => new ChatCompletion(raw)
|
|
650
|
-
|
|
681
|
+
cast: (raw) => new ChatCompletion(raw),
|
|
682
|
+
onHeaders: (h) => {
|
|
683
|
+
headers = h;
|
|
684
|
+
}
|
|
685
|
+
}).then((completion) => completion.withCost(headers));
|
|
651
686
|
}
|
|
652
687
|
};
|
|
653
688
|
var Chat = class {
|
|
@@ -744,37 +779,37 @@ async function toBlob(file, mimeOverride) {
|
|
|
744
779
|
const mime = mimeOverride || "application/octet-stream";
|
|
745
780
|
return { blob: new Blob([bytes], { type: mime }), filename: "upload", size: bytes.byteLength, mime };
|
|
746
781
|
}
|
|
747
|
-
function
|
|
748
|
-
const s = (
|
|
782
|
+
function requirePrompt(prompt) {
|
|
783
|
+
const s = (prompt ?? "").trim();
|
|
749
784
|
if (!s) {
|
|
750
785
|
throw new ParetaError(
|
|
751
|
-
'
|
|
786
|
+
'prompt is required: one sentence describing what the model should do with each item (e.g. "extract vendor, total and date from each invoice"). Pass prompt to evals.create / proposeContract.'
|
|
752
787
|
);
|
|
753
788
|
}
|
|
754
789
|
return s.slice(0, 500);
|
|
755
790
|
}
|
|
756
|
-
function itemsJsonl(task, items,
|
|
791
|
+
function itemsJsonl(task, items, prompt, name) {
|
|
757
792
|
if (!items || items.length === 0) throw new ParetaError("items is required and must be non-empty");
|
|
758
793
|
const jsonl = items.map((it) => JSON.stringify(it)).join("\n");
|
|
759
794
|
return {
|
|
760
795
|
files: { items: { filename: `items.${task}.jsonl`, content: jsonl, contentType: "application/jsonl" } },
|
|
761
|
-
data: { task_id: task,
|
|
796
|
+
data: { task_id: task, prompt, name: name || `sdk eval set (${items.length} items)` }
|
|
762
797
|
};
|
|
763
798
|
}
|
|
764
|
-
function proposeMultipart(items,
|
|
799
|
+
function proposeMultipart(items, prompt) {
|
|
765
800
|
if (!items || items.length === 0) throw new ParetaError("items is required and must be non-empty");
|
|
766
801
|
const jsonl = items.map((it) => JSON.stringify(it)).join("\n");
|
|
767
802
|
return {
|
|
768
803
|
files: { items: { filename: "items.jsonl", content: jsonl, contentType: "application/jsonl" } },
|
|
769
|
-
data: {
|
|
804
|
+
data: { prompt }
|
|
770
805
|
};
|
|
771
806
|
}
|
|
772
807
|
function bindError(result) {
|
|
773
|
-
const
|
|
808
|
+
const prompt = result.prompt ?? "";
|
|
774
809
|
if (result.conflict) {
|
|
775
810
|
const c = result.conflict;
|
|
776
811
|
return new ParetaError(
|
|
777
|
-
`
|
|
812
|
+
`prompt '${prompt}' describes a different job than the data's shape supports (reads as '${c.intended_task}': ${c.reasoning}). Pass a task to pin the task, or revise the prompt.`
|
|
778
813
|
);
|
|
779
814
|
}
|
|
780
815
|
if (result.split) {
|
|
@@ -787,14 +822,14 @@ function bindError(result) {
|
|
|
787
822
|
if (props.length === 1 && props[0].taskId === "custom-eval") {
|
|
788
823
|
const warn = props[0].warning ? ` (${props[0].warning})` : "";
|
|
789
824
|
return new ParetaError(
|
|
790
|
-
`no
|
|
825
|
+
`no ready-made scorer fits this data for prompt '${prompt}'. A judge panel can grade each answer against what you asked for (win rate vs gpt-5.5) \u2014 pass task: "custom-eval" to use it.${warn} Or revise the data/prompt so a specific task fits.`
|
|
791
826
|
);
|
|
792
827
|
}
|
|
793
828
|
const options = props.map((p) => p.taskId).filter(Boolean);
|
|
794
829
|
if (options.length === 0 && result.closestTask) options.push(result.closestTask);
|
|
795
830
|
const hint = options.length ? ` Candidates: ${options.join(", ")}.` : "";
|
|
796
831
|
return new ParetaError(
|
|
797
|
-
`
|
|
832
|
+
`couldn't work out how to score this for prompt '${prompt}'.${hint} Pass a task to choose yourself, or inspect evals.proposeContract({ items, prompt }).`
|
|
798
833
|
);
|
|
799
834
|
}
|
|
800
835
|
function mergeCandidates(models, frontierIds) {
|
|
@@ -818,27 +853,27 @@ var EvalSets = class {
|
|
|
818
853
|
}
|
|
819
854
|
client;
|
|
820
855
|
/**
|
|
821
|
-
* Persist an eval set from your rows. `
|
|
822
|
-
* on what the model should do with each item. `task` is OPTIONAL — omit it
|
|
823
|
-
*
|
|
824
|
-
* (
|
|
825
|
-
* `task` to pin one explicitly.
|
|
856
|
+
* Persist an eval set from your rows. `prompt` is REQUIRED (v3): one sentence
|
|
857
|
+
* on what the model should do with each item. `task` is OPTIONAL — omit it
|
|
858
|
+
* and Pareta works out how to score the results from your prompt + the
|
|
859
|
+
* data's shape (a clean single match is used; anything ambiguous throws with
|
|
860
|
+
* the proposals). Pass `task` to pin one explicitly.
|
|
826
861
|
*/
|
|
827
862
|
async create(params) {
|
|
828
|
-
const
|
|
863
|
+
const prompt = requirePrompt(params.prompt);
|
|
829
864
|
let task = params.task;
|
|
830
865
|
if (task == null) {
|
|
831
|
-
const proposal = await this.proposeContract(params.items,
|
|
866
|
+
const proposal = await this.proposeContract(params.items, prompt);
|
|
832
867
|
task = proposal.boundTask ?? void 0;
|
|
833
868
|
if (task == null) throw bindError(proposal);
|
|
834
869
|
}
|
|
835
|
-
const { files, data } = itemsJsonl(task, params.items,
|
|
870
|
+
const { files, data } = itemsJsonl(task, params.items, prompt, params.name);
|
|
836
871
|
return this.client.request("POST", BASE2, { files, data, cast: evalSetFromCreate });
|
|
837
872
|
}
|
|
838
|
-
/** Internal: the
|
|
873
|
+
/** Internal: the propose call `create` uses when no task is pinned. Public on
|
|
839
874
|
* `Evals` as `proposeContract`; kept here so `sets.create` can reach it. */
|
|
840
|
-
proposeContract(items,
|
|
841
|
-
const { files, data } = proposeMultipart(items,
|
|
875
|
+
proposeContract(items, prompt) {
|
|
876
|
+
const { files, data } = proposeMultipart(items, requirePrompt(prompt));
|
|
842
877
|
return this.client.request("POST", PROPOSE, { files, data, cast: proposalResult });
|
|
843
878
|
}
|
|
844
879
|
list() {
|
|
@@ -909,11 +944,11 @@ var EvalRuns = class {
|
|
|
909
944
|
let evalSet = params.evalSet;
|
|
910
945
|
if (evalSet == null) {
|
|
911
946
|
if (!params.items) {
|
|
912
|
-
throw new ParetaError("pass evalSet: <id>, or items (+
|
|
947
|
+
throw new ParetaError("pass evalSet: <id>, or items (+ prompt) to create one");
|
|
913
948
|
}
|
|
914
949
|
evalSet = (await this.sets.create({
|
|
915
950
|
items: params.items,
|
|
916
|
-
|
|
951
|
+
prompt: params.prompt,
|
|
917
952
|
task: params.task,
|
|
918
953
|
name: params.name
|
|
919
954
|
})).id ?? void 0;
|
|
@@ -957,13 +992,14 @@ var Evals = class {
|
|
|
957
992
|
}
|
|
958
993
|
client;
|
|
959
994
|
/**
|
|
960
|
-
*
|
|
995
|
+
* How would your data be scored under your stated `prompt`? Stateless
|
|
961
996
|
* discovery — nothing is persisted. Returns a ProposalResult (ranked
|
|
962
|
-
* proposals, the
|
|
963
|
-
* calls this under the hood; use it directly to
|
|
997
|
+
* proposals, the task a task-less create would use, conflict/split
|
|
998
|
+
* reporting). `sets.create` calls this under the hood; use it directly to
|
|
999
|
+
* preview the scoring first.
|
|
964
1000
|
*/
|
|
965
1001
|
proposeContract(params) {
|
|
966
|
-
return this.sets.proposeContract(params.items, params.
|
|
1002
|
+
return this.sets.proposeContract(params.items, params.prompt);
|
|
967
1003
|
}
|
|
968
1004
|
/**
|
|
969
1005
|
* The frontier (vendor) roster you can evaluate against. With `task`, each is
|
|
@@ -1310,6 +1346,7 @@ var Pareta = class _Pareta {
|
|
|
1310
1346
|
break;
|
|
1311
1347
|
}
|
|
1312
1348
|
if (res.ok) {
|
|
1349
|
+
if (opts.onHeaders) opts.onHeaders(res.headers);
|
|
1313
1350
|
const text = await res.text();
|
|
1314
1351
|
const raw = text ? JSON.parse(text) : {};
|
|
1315
1352
|
return cast ? cast(raw) : raw;
|