pareta 1.4.0 → 2.1.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 +3 -1
- package/dist/index.cjs +186 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -5
- package/dist/index.d.ts +87 -5
- package/dist/index.mjs +185 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,9 @@ head-to-head against frontier models on your own ground truth and prices every
|
|
|
40
40
|
contender honestly:
|
|
41
41
|
|
|
42
42
|
```ts
|
|
43
|
-
const set = await pa.evals.sets.create({
|
|
43
|
+
const set = await pa.evals.sets.create({
|
|
44
|
+
items: [...], intent: "extract vendor, total and date from each invoice",
|
|
45
|
+
});
|
|
44
46
|
const run = await pa.evals.runs.create({
|
|
45
47
|
evalSet: set.id, models: ["auto"], frontier: ["claude-opus-4-7"], wait: true,
|
|
46
48
|
});
|
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 = "1.
|
|
177
|
+
var VERSION = "2.1.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
|
};
|
|
@@ -341,6 +371,11 @@ var EvalSet = class extends BaseModel {
|
|
|
341
371
|
get scoringStrategy() {
|
|
342
372
|
return this.raw.scoring_strategy ?? null;
|
|
343
373
|
}
|
|
374
|
+
/** The one-sentence success criterion this set was created with (CB1:
|
|
375
|
+
* DATA + INTENT). Required at create. */
|
|
376
|
+
get intent() {
|
|
377
|
+
return this.raw.intent ?? null;
|
|
378
|
+
}
|
|
344
379
|
};
|
|
345
380
|
function evalSetFromCreate(raw) {
|
|
346
381
|
return new EvalSet(raw?.eval_set ?? {});
|
|
@@ -348,6 +383,60 @@ function evalSetFromCreate(raw) {
|
|
|
348
383
|
function evalSetList(raw) {
|
|
349
384
|
return (raw?.eval_sets ?? []).map((e) => new EvalSet(e));
|
|
350
385
|
}
|
|
386
|
+
var ContractProposal = class extends BaseModel {
|
|
387
|
+
get taskId() {
|
|
388
|
+
return this.raw.task_id ?? null;
|
|
389
|
+
}
|
|
390
|
+
get confidence() {
|
|
391
|
+
return this.raw.confidence ?? null;
|
|
392
|
+
}
|
|
393
|
+
get evidence() {
|
|
394
|
+
return this.raw.evidence ?? {};
|
|
395
|
+
}
|
|
396
|
+
get warning() {
|
|
397
|
+
return this.raw.warning ?? null;
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
var ProposalResult = class extends BaseModel {
|
|
401
|
+
get proposals() {
|
|
402
|
+
return (this.raw.proposals ?? []).map((p) => new ContractProposal(p));
|
|
403
|
+
}
|
|
404
|
+
get homogeneous() {
|
|
405
|
+
return Boolean(this.raw.homogeneous);
|
|
406
|
+
}
|
|
407
|
+
get split() {
|
|
408
|
+
return this.raw.split ?? null;
|
|
409
|
+
}
|
|
410
|
+
get conflict() {
|
|
411
|
+
return this.raw.conflict ?? null;
|
|
412
|
+
}
|
|
413
|
+
get closestTask() {
|
|
414
|
+
return this.raw.closest_task ?? null;
|
|
415
|
+
}
|
|
416
|
+
get intent() {
|
|
417
|
+
return this.raw.intent ?? null;
|
|
418
|
+
}
|
|
419
|
+
get message() {
|
|
420
|
+
return this.raw.message ?? null;
|
|
421
|
+
}
|
|
422
|
+
/** True when the binder matched exactly ONE homogeneous SPECIFIC contract at
|
|
423
|
+
* high/medium confidence and no conflict/split — the case `create` auto-binds
|
|
424
|
+
* without a human confirming. The `custom-eval` universal FLOOR is EXCLUDED:
|
|
425
|
+
* the binder offers it only when no specific contract fits, and per the
|
|
426
|
+
* precision ladder the floor is a CHOICE — the user opts in with
|
|
427
|
+
* `task: "custom-eval"`, never a silent auto-bind. */
|
|
428
|
+
get isClean() {
|
|
429
|
+
const props = this.proposals;
|
|
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";
|
|
431
|
+
}
|
|
432
|
+
/** The task `create` would auto-bind, or null if the result isn't clean. */
|
|
433
|
+
get boundTask() {
|
|
434
|
+
return this.isClean ? this.proposals[0].taskId : null;
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
function proposalResult(raw) {
|
|
438
|
+
return new ProposalResult(raw ?? {});
|
|
439
|
+
}
|
|
351
440
|
var EvalItemResult = class extends BaseModel {
|
|
352
441
|
get idx() {
|
|
353
442
|
return this.raw.idx ?? null;
|
|
@@ -585,10 +674,14 @@ var Completions = class {
|
|
|
585
674
|
cast: (raw) => new ChatCompletionChunk(raw)
|
|
586
675
|
});
|
|
587
676
|
}
|
|
677
|
+
let headers;
|
|
588
678
|
return this.client.request("POST", PATH, {
|
|
589
679
|
body,
|
|
590
|
-
cast: (raw) => new ChatCompletion(raw)
|
|
591
|
-
|
|
680
|
+
cast: (raw) => new ChatCompletion(raw),
|
|
681
|
+
onHeaders: (h) => {
|
|
682
|
+
headers = h;
|
|
683
|
+
}
|
|
684
|
+
}).then((completion) => completion.withCost(headers));
|
|
592
685
|
}
|
|
593
686
|
};
|
|
594
687
|
var Chat = class {
|
|
@@ -641,6 +734,7 @@ var Tasks = class {
|
|
|
641
734
|
|
|
642
735
|
// src/resources/evals.ts
|
|
643
736
|
var BASE2 = "/v1/eval-sets";
|
|
737
|
+
var PROPOSE = "/v1/eval-sets/propose-contract";
|
|
644
738
|
var RUNS = "/v1/eval-runs";
|
|
645
739
|
var FRONTIER = "/v1/eval/frontier-models";
|
|
646
740
|
var INLINE_MAX = 5 * 1024 * 1024;
|
|
@@ -684,14 +778,59 @@ async function toBlob(file, mimeOverride) {
|
|
|
684
778
|
const mime = mimeOverride || "application/octet-stream";
|
|
685
779
|
return { blob: new Blob([bytes], { type: mime }), filename: "upload", size: bytes.byteLength, mime };
|
|
686
780
|
}
|
|
687
|
-
function
|
|
781
|
+
function requireIntent(intent) {
|
|
782
|
+
const s = (intent ?? "").trim();
|
|
783
|
+
if (!s) {
|
|
784
|
+
throw new ParetaError(
|
|
785
|
+
'intent is required: one sentence describing what the model should do with each item (e.g. "extract vendor, total and date from each invoice"). Pass intent to evals.create / proposeContract.'
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
return s.slice(0, 500);
|
|
789
|
+
}
|
|
790
|
+
function itemsJsonl(task, items, intent, name) {
|
|
688
791
|
if (!items || items.length === 0) throw new ParetaError("items is required and must be non-empty");
|
|
689
792
|
const jsonl = items.map((it) => JSON.stringify(it)).join("\n");
|
|
690
793
|
return {
|
|
691
794
|
files: { items: { filename: `items.${task}.jsonl`, content: jsonl, contentType: "application/jsonl" } },
|
|
692
|
-
data: { task_id: task, name: name || `sdk eval set (${items.length} items)` }
|
|
795
|
+
data: { task_id: task, intent, name: name || `sdk eval set (${items.length} items)` }
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
function proposeMultipart(items, intent) {
|
|
799
|
+
if (!items || items.length === 0) throw new ParetaError("items is required and must be non-empty");
|
|
800
|
+
const jsonl = items.map((it) => JSON.stringify(it)).join("\n");
|
|
801
|
+
return {
|
|
802
|
+
files: { items: { filename: "items.jsonl", content: jsonl, contentType: "application/jsonl" } },
|
|
803
|
+
data: { intent }
|
|
693
804
|
};
|
|
694
805
|
}
|
|
806
|
+
function bindError(result) {
|
|
807
|
+
const intent = result.intent ?? "";
|
|
808
|
+
if (result.conflict) {
|
|
809
|
+
const c = result.conflict;
|
|
810
|
+
return new ParetaError(
|
|
811
|
+
`intent '${intent}' describes a different job than the data's shape supports (reads as '${c.intended_task}': ${c.reasoning}). Pass a task to pin a contract, or revise the intent.`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
if (result.split) {
|
|
815
|
+
const s = result.split;
|
|
816
|
+
return new ParetaError(
|
|
817
|
+
`the dataset looks MIXED \u2014 ${s.validated_n}/${s.total_n} items fit '${s.closest_task}', the rest a different shape. Split the set or pass a task.`
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
const props = result.proposals;
|
|
821
|
+
if (props.length === 1 && props[0].taskId === "custom-eval") {
|
|
822
|
+
const warn = props[0].warning ? ` (${props[0].warning})` : "";
|
|
823
|
+
return new ParetaError(
|
|
824
|
+
`no specific grading contract fits this data for intent '${intent}'. The custom-eval universal floor is available \u2014 it grades by judged win-rate vs the frontier anchor.${warn} Pass task: "custom-eval" to use it, or revise the data/intent for a specific contract.`
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
const options = props.map((p) => p.taskId).filter(Boolean);
|
|
828
|
+
if (options.length === 0 && result.closestTask) options.push(result.closestTask);
|
|
829
|
+
const hint = options.length ? ` Candidates: ${options.join(", ")}.` : "";
|
|
830
|
+
return new ParetaError(
|
|
831
|
+
`could not confidently bind a grading contract for intent '${intent}'.${hint} Pass a task to pin one, or inspect evals.proposeContract({ items, intent }).`
|
|
832
|
+
);
|
|
833
|
+
}
|
|
695
834
|
function mergeCandidates(models, frontierIds) {
|
|
696
835
|
const cands = [...models ?? [], ...frontierIds ?? []];
|
|
697
836
|
if (cands.length === 0) throw new ParetaError("models is required (the open candidates to evaluate)");
|
|
@@ -712,10 +851,30 @@ var EvalSets = class {
|
|
|
712
851
|
this.client = client;
|
|
713
852
|
}
|
|
714
853
|
client;
|
|
715
|
-
|
|
716
|
-
|
|
854
|
+
/**
|
|
855
|
+
* Persist an eval set from your rows. `intent` is REQUIRED (v2): one sentence
|
|
856
|
+
* on what the model should do with each item. `task` is OPTIONAL — omit it and
|
|
857
|
+
* the binder resolves your intent + the data's shape to a grading contract
|
|
858
|
+
* (auto-binds a clean single match; throws with the proposals otherwise). Pass
|
|
859
|
+
* `task` to pin one explicitly.
|
|
860
|
+
*/
|
|
861
|
+
async create(params) {
|
|
862
|
+
const intent = requireIntent(params.intent);
|
|
863
|
+
let task = params.task;
|
|
864
|
+
if (task == null) {
|
|
865
|
+
const proposal = await this.proposeContract(params.items, intent);
|
|
866
|
+
task = proposal.boundTask ?? void 0;
|
|
867
|
+
if (task == null) throw bindError(proposal);
|
|
868
|
+
}
|
|
869
|
+
const { files, data } = itemsJsonl(task, params.items, intent, params.name);
|
|
717
870
|
return this.client.request("POST", BASE2, { files, data, cast: evalSetFromCreate });
|
|
718
871
|
}
|
|
872
|
+
/** Internal: the binder call `create` uses when no task is pinned. Public on
|
|
873
|
+
* `Evals` as `proposeContract`; kept here so `sets.create` can reach it. */
|
|
874
|
+
proposeContract(items, intent) {
|
|
875
|
+
const { files, data } = proposeMultipart(items, requireIntent(intent));
|
|
876
|
+
return this.client.request("POST", PROPOSE, { files, data, cast: proposalResult });
|
|
877
|
+
}
|
|
719
878
|
list() {
|
|
720
879
|
return this.client.request("GET", BASE2, { cast: evalSetList });
|
|
721
880
|
}
|
|
@@ -783,10 +942,15 @@ var EvalRuns = class {
|
|
|
783
942
|
async create(params) {
|
|
784
943
|
let evalSet = params.evalSet;
|
|
785
944
|
if (evalSet == null) {
|
|
786
|
-
if (!
|
|
787
|
-
throw new ParetaError("pass evalSet: <id>, or
|
|
945
|
+
if (!params.items) {
|
|
946
|
+
throw new ParetaError("pass evalSet: <id>, or items (+ intent) to create one");
|
|
788
947
|
}
|
|
789
|
-
evalSet = (await this.sets.create({
|
|
948
|
+
evalSet = (await this.sets.create({
|
|
949
|
+
items: params.items,
|
|
950
|
+
intent: params.intent,
|
|
951
|
+
task: params.task,
|
|
952
|
+
name: params.name
|
|
953
|
+
})).id ?? void 0;
|
|
790
954
|
}
|
|
791
955
|
const frontierIds = await this.frontierIds(params.frontier, evalSet, params.task);
|
|
792
956
|
const candidateModelIds = mergeCandidates(params.models, frontierIds);
|
|
@@ -826,6 +990,15 @@ var Evals = class {
|
|
|
826
990
|
this.client = client;
|
|
827
991
|
}
|
|
828
992
|
client;
|
|
993
|
+
/**
|
|
994
|
+
* Which grading contract fits your data under your stated `intent`? Stateless
|
|
995
|
+
* discovery — nothing is persisted. Returns a ProposalResult (ranked
|
|
996
|
+
* proposals, the auto-bind decision, conflict/split reporting). `sets.create`
|
|
997
|
+
* calls this under the hood; use it directly to preview the binding first.
|
|
998
|
+
*/
|
|
999
|
+
proposeContract(params) {
|
|
1000
|
+
return this.sets.proposeContract(params.items, params.intent);
|
|
1001
|
+
}
|
|
829
1002
|
/**
|
|
830
1003
|
* The frontier (vendor) roster you can evaluate against. With `task`, each is
|
|
831
1004
|
* annotated `benchmarked` + the roster is vision-filtered for document tasks.
|
|
@@ -1171,6 +1344,7 @@ var Pareta = class _Pareta {
|
|
|
1171
1344
|
break;
|
|
1172
1345
|
}
|
|
1173
1346
|
if (res.ok) {
|
|
1347
|
+
if (opts.onHeaders) opts.onHeaders(res.headers);
|
|
1174
1348
|
const text = await res.text();
|
|
1175
1349
|
const raw = text ? JSON.parse(text) : {};
|
|
1176
1350
|
return cast ? cast(raw) : raw;
|
|
@@ -1248,6 +1422,7 @@ exports.ChatCompletion = ChatCompletion;
|
|
|
1248
1422
|
exports.ChatCompletionChunk = ChatCompletionChunk;
|
|
1249
1423
|
exports.Choice = Choice;
|
|
1250
1424
|
exports.ConflictError = ConflictError;
|
|
1425
|
+
exports.ContractProposal = ContractProposal;
|
|
1251
1426
|
exports.Embeddings = Embeddings;
|
|
1252
1427
|
exports.EndpointNotReadyError = EndpointNotReadyError;
|
|
1253
1428
|
exports.EvalItemResult = EvalItemResult;
|
|
@@ -1267,6 +1442,7 @@ exports.NotFoundError = NotFoundError;
|
|
|
1267
1442
|
exports.Pareta = Pareta;
|
|
1268
1443
|
exports.ParetaError = ParetaError;
|
|
1269
1444
|
exports.PermissionDeniedError = PermissionDeniedError;
|
|
1445
|
+
exports.ProposalResult = ProposalResult;
|
|
1270
1446
|
exports.RateLimitError = RateLimitError;
|
|
1271
1447
|
exports.Rerank = Rerank;
|
|
1272
1448
|
exports.RerankResult = RerankResult;
|