pareta 0.1.0 → 1.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 CHANGED
@@ -1,13 +1,13 @@
1
1
  # pareta
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/pareta)](https://www.npmjs.com/package/pareta)
4
- [![types](https://img.shields.io/npm/types/pareta)](https://www.npmjs.com/package/pareta)
5
- [![license](https://img.shields.io/npm/l/pareta)](https://github.com/Pareta-AI/pareta-js/blob/main/LICENSE)
4
+ [![License](https://img.shields.io/npm/l/pareta)](https://github.com/Pareta-AI/pareta-js/blob/main/LICENSE)
6
5
 
7
- TypeScript/JavaScript client for [Pareta](https://pareta.ai) — deploy
8
- open-weights endpoints, run metered inference, browse the benchmark catalog, and
9
- evaluate models on your own data. The mirror of the Python [`pareta`](https://pypi.org/project/pareta/)
10
- package, re-expressed as one Promise-only client.
6
+ TypeScript/JavaScript client for [Pareta](https://pareta.ai). One model id
7
+ `"auto"` and Pareta plans each request, routes it to benchmark-proven open
8
+ specialists, verifies the result, and falls back to a frontier model when
9
+ that's the right call. One request, one bill; you never pay for Pareta's
10
+ orchestration or cold starts.
11
11
 
12
12
  ```bash
13
13
  npm install pareta # or: pnpm add pareta / yarn add pareta / bun add pareta
@@ -16,93 +16,82 @@ npm install pareta # or: pnpm add pareta / yarn add pareta / bun add pare
16
16
  ```ts
17
17
  import { Pareta } from "pareta";
18
18
 
19
- const pa = Pareta.fromEnv(); // reads PARETA_API_KEY (+ optional PARETA_BASE_URL)
19
+ const pa = Pareta.fromEnv(); // reads PARETA_API_KEY
20
+ // or: new Pareta({ apiKey: "pareta_sk_…", baseURL: "https://api.pareta.ai" })
20
21
 
21
22
  const res = await pa.chat.completions.create({
22
- model: "ep_…", // an endpoint id from endpoints.deploy(...)
23
- messages: [{ role: "user", content: "Extract the totals from this invoice." }],
23
+ model: "auto", // the routing brain the product
24
+ messages: [{ role: "user", content: "Extract the total from this invoice: …" }],
24
25
  });
25
26
  console.log(res.choices[0].message.content);
26
- ```
27
27
 
28
- Inference is OpenAI-compatible, so you can equally point the `openai` SDK at
29
- `baseURL` + your `pareta_sk_` key. The SDK's unique value is the control plane —
30
- **deploy**, **eval**, and **discovery**.
28
+ // Streaming (progress while Pareta plans + executes, then tokens)
29
+ for await (const chunk of await pa.chat.completions.create({
30
+ model: "auto", messages: [...], stream: true,
31
+ })) {
32
+ process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
33
+ }
34
+ ```
31
35
 
32
- ## Authenticate
36
+ ## Is it actually good? Measure it on YOUR data
33
37
 
34
- Every request uses a `pareta_sk_` secret key (mint one in the
35
- [dashboard](https://pareta.ai) key management is browser-only). Put it in the
36
- environment and use `fromEnv()`, or pass it explicitly:
38
+ Don't take the routing brain on faith benchmark it. `pa.evals` runs `"auto"`
39
+ head-to-head against frontier models on your own ground truth and prices every
40
+ contender honestly:
37
41
 
38
42
  ```ts
39
- const pa = new Pareta({ apiKey: "pareta_sk_…" });
43
+ const set = await pa.evals.sets.create({ task: "invoice-extraction", items: [...] });
44
+ const run = await pa.evals.runs.create({
45
+ evalSet: set.id, models: ["auto"], frontier: ["claude-opus-4-7"], wait: true,
46
+ });
40
47
  ```
41
48
 
42
- ## Deploy infer
49
+ And watch what your live traffic is doing — spend, success rate, and the
50
+ projected savings vs calling a frontier directly:
43
51
 
44
52
  ```ts
45
- // Pareta picks the GPU/serving class; model defaults to the task's best pick.
46
- const ep = await pa.endpoints.deploy({ task: "invoice-extraction", wait: true });
47
-
48
- const res = await pa.chat.completions.create({
49
- model: ep.id!,
53
+ await pa.auto.metrics(); // requests, success, spend, savings
54
+ await pa.auto.compareFrontier({ // one prompt, metered, side-by-side
55
+ model: "gpt-5.5",
50
56
  messages: [{ role: "user", content: "…" }],
51
57
  });
52
58
  ```
53
59
 
54
- Stream tokens:
55
-
56
- ```ts
57
- for await (const chunk of pa.chat.completions.create({ model: ep.id!, messages, stream: true })) {
58
- process.stdout.write(chunk.choices[0]?.delta.content ?? "");
59
- }
60
- ```
60
+ ## Inference is OpenAI-compatible
61
61
 
62
- ## Discover the best model for a task
62
+ You don't even need this SDK to call Pareta — point the `openai` package at
63
+ `baseURL` + your key and set `model: "auto"`:
63
64
 
64
65
  ```ts
65
- const lb = await pa.tasks.leaderboard("invoice-extraction");
66
- console.log(lb.recommended, lb.frontier?.name); // open pick + frontier baseline
66
+ import OpenAI from "openai";
67
+ const client = new OpenAI({ apiKey: "pareta_sk_…", baseURL: "https://api.pareta.ai/v1" });
68
+ const res = await client.chat.completions.create({ model: "auto", messages: [...] });
67
69
  ```
68
70
 
69
- ## Evaluate on your own data
71
+ This SDK's unique value is everything AROUND that call — evals on your data,
72
+ auto metrics, and the benchmark catalog.
70
73
 
71
- ```ts
72
- const run = await pa.evals.runs.create({
73
- task: "intent-classification",
74
- items: [{ input: { text: "cancel my plan" }, expected: "cancellation" }],
75
- models: ["qwen-1"],
76
- frontier: "benchmarked", // also race the benchmarked frontier models
77
- wait: true,
78
- });
79
- console.log(run.cost, run.results.map((r) => [r.modelId, r.qualityMean]));
80
- ```
74
+ Discovery (`pa.tasks.match`) tells you whether Pareta has a benchmark-proven
75
+ specialist lane for your workload — describe the task in free text and get
76
+ ranked matching tasks back.
81
77
 
82
- Eval runs are metered against your org balance; `run.cost` is the billed total
83
- in dollars (floored to cents).
78
+ ## Auth
84
79
 
85
- ## Errors
86
-
87
- Status codes map to typed errors you can branch on:
80
+ Mint a `pareta_sk_` key in the dashboard (key management is browser-only) and
81
+ pass it as `apiKey` or via `PARETA_API_KEY`. The SDK only ever *consumes* a
82
+ key; it never creates, lists, or revokes them.
88
83
 
89
- ```ts
90
- import { InsufficientCreditsError, EndpointNotReadyError } from "pareta";
91
-
92
- try {
93
- await pa.chat.completions.create({ model, messages });
94
- } catch (e) {
95
- if (e instanceof InsufficientCreditsError) { /* top up in the dashboard */ }
96
- if (e instanceof EndpointNotReadyError) { /* endpoint is cold/stopped */ }
97
- }
98
- ```
99
-
100
- ## Runtime
84
+ ## Errors
101
85
 
102
- Node 18+, modern browsers, and edge runtimes (Workers / Vercel Edge) — built on
103
- native `fetch` / `ReadableStream` / `FormData`, **zero runtime dependencies**.
104
- Ships ESM + CommonJS + `.d.ts`.
86
+ All errors subclass `ParetaError` `AuthenticationError` (401),
87
+ `InsufficientCreditsError` (402), `NotFoundError` (404),
88
+ `EndpointNotReadyError` (503), `RateLimitError` (429, auto-retried),
89
+ `BadRequestError` (400/422), and `APIConnectionError` / `APITimeoutError`
90
+ (transport, auto-retried). Idempotent GETs and 429/5xx/timeouts are retried
91
+ with exponential backoff (`maxRetries`, default 2).
105
92
 
106
- ## Docs
93
+ ## Python
107
94
 
108
- Full guide, reference, and examples: **[docs.pareta.ai](https://docs.pareta.ai)**.
95
+ The same surface ships as a Python package: [`pip install pareta`](https://pypi.org/project/pareta/),
96
+ plus a CLI (`pareta[cli]`) and an MCP server (`pareta[mcp]`). Docs for both:
97
+ [docs.pareta.ai](https://docs.pareta.ai).
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 = "0.1.0";
177
+ var VERSION = "1.0.0";
178
178
 
179
179
  // src/money.ts
180
180
  var MICRO_PER_CENT = 10000n;
@@ -280,33 +280,6 @@ var ModelList = class extends BaseModel {
280
280
  return this.data[Symbol.iterator]();
281
281
  }
282
282
  };
283
- var Endpoint = class extends BaseModel {
284
- get id() {
285
- return this.raw.id ?? this.raw.name ?? null;
286
- }
287
- get name() {
288
- return this.raw.name ?? null;
289
- }
290
- get model() {
291
- return this.raw.model ?? null;
292
- }
293
- get status() {
294
- return this.raw.status ?? null;
295
- }
296
- // Live list sends camelCase `taskName`; the detail record sends `task`.
297
- get task() {
298
- return this.raw.taskName ?? this.raw.task ?? null;
299
- }
300
- get url() {
301
- return this.raw.url ?? null;
302
- }
303
- get isLive() {
304
- return this.raw.status === "live";
305
- }
306
- };
307
- function endpointList(raw) {
308
- return (raw ?? []).map((e) => new Endpoint(e));
309
- }
310
283
  var Task = class extends BaseModel {
311
284
  get id() {
312
285
  return this.raw.id ?? null;
@@ -375,6 +348,20 @@ function evalSetFromCreate(raw) {
375
348
  function evalSetList(raw) {
376
349
  return (raw?.eval_sets ?? []).map((e) => new EvalSet(e));
377
350
  }
351
+ var EvalItemResult = class extends BaseModel {
352
+ get idx() {
353
+ return this.raw.idx ?? null;
354
+ }
355
+ get score() {
356
+ return this.raw.score ?? null;
357
+ }
358
+ get prediction() {
359
+ return this.raw.prediction ?? null;
360
+ }
361
+ get error() {
362
+ return this.raw.error ?? null;
363
+ }
364
+ };
378
365
  var EvalResult = class extends BaseModel {
379
366
  get modelId() {
380
367
  return this.raw.model_id ?? null;
@@ -401,46 +388,9 @@ var EvalResult = class extends BaseModel {
401
388
  get errorCount() {
402
389
  return this.raw.error_count ?? null;
403
390
  }
404
- };
405
- var LeaderboardEntry = class extends BaseModel {
406
- get name() {
407
- return this.raw.name ?? null;
408
- }
409
- get kind() {
410
- return this.raw.kind ?? null;
411
- }
412
- get quality() {
413
- return this.raw.quality ?? null;
414
- }
415
- // Raw integer — sub-cent unit rate, NOT floored (see money.ts).
416
- get costPerRequestMicroUsd() {
417
- return this.raw.cost_per_request_micro_usd ?? null;
418
- }
419
- get contextK() {
420
- return this.raw.context_k ?? null;
421
- }
422
- get runMode() {
423
- return this.raw.run_mode ?? null;
424
- }
425
- };
426
- var Leaderboard = class extends BaseModel {
427
- get taskId() {
428
- return this.raw.task_id ?? null;
429
- }
430
- get metric() {
431
- return this.raw.metric ?? null;
432
- }
433
- get costUnit() {
434
- return this.raw.cost_unit ?? null;
435
- }
436
- get recommended() {
437
- return this.raw.recommended ?? null;
438
- }
439
- get models() {
440
- return (this.raw.models ?? []).map((m) => new LeaderboardEntry(m));
441
- }
442
- get frontier() {
443
- return this.raw.frontier ? new LeaderboardEntry(this.raw.frontier) : null;
391
+ /** Per-item rows (idx/score/prediction/error); empty when not persisted. */
392
+ get perItem() {
393
+ return (this.raw.per_item ?? []).map((it) => new EvalItemResult(it));
444
394
  }
445
395
  };
446
396
  var FrontierModel = class extends BaseModel {
@@ -453,14 +403,11 @@ var FrontierModel = class extends BaseModel {
453
403
  get vision() {
454
404
  return Boolean(this.raw.vision);
455
405
  }
456
- /** Only meaningful when a task was given: it's on that task's leaderboard. */
406
+ /** Only meaningful when a task was given: it has benchmark results on that task. */
457
407
  get benchmarked() {
458
408
  return Boolean(this.raw.benchmarked);
459
409
  }
460
410
  };
461
- function leaderboardFrom(raw) {
462
- return new Leaderboard(raw ?? {});
463
- }
464
411
  function frontierModels(raw) {
465
412
  return (raw?.frontier_models ?? []).map((m) => new FrontierModel(m));
466
413
  }
@@ -503,7 +450,7 @@ var EvalRun = class extends BaseModel {
503
450
  var PATH = "/v1/chat/completions";
504
451
  function buildBody(params) {
505
452
  const { model, messages, stream, ...extra } = params;
506
- if (!model) throw new ParetaError("model is required (an endpoint id from endpoints.deploy)");
453
+ if (!model) throw new ParetaError('model is required (use "auto")');
507
454
  if (!messages || messages.length === 0) {
508
455
  throw new ParetaError("messages is required and must be non-empty");
509
456
  }
@@ -551,99 +498,19 @@ var Models = class {
551
498
  }
552
499
  };
553
500
 
554
- // src/resources/endpoints.ts
555
- var BASE = "/v1/endpoints";
556
- function buildDeployBody(params) {
557
- const { task, model, name, wait: _wait, ...extra } = params;
558
- if (!task) throw new ParetaError("task is required");
559
- const body = { task, model: model || "recommended", ...extra };
560
- if (name !== void 0) body.name = name;
561
- return body;
562
- }
563
- function endpointFromComplete(data) {
564
- const ep = data && typeof data === "object" ? data.endpoint : null;
565
- return new Endpoint(ep ?? {});
566
- }
567
- function deployError(data) {
568
- const msg = data && typeof data === "object" ? data.message : String(data);
569
- return new ParetaError(`deploy failed: ${msg || "unknown error"}`);
570
- }
571
- var EndpointMetrics = class {
572
- constructor(client, id) {
573
- this.client = client;
574
- this.id = id;
575
- }
576
- client;
577
- id;
578
- performance(params) {
579
- return this.client.request("GET", `${BASE}/${this.id}/performance`, { params });
580
- }
581
- uptime(params) {
582
- return this.client.request("GET", `${BASE}/${this.id}/uptime`, { params });
583
- }
584
- cost(params) {
585
- return this.client.request("GET", `${BASE}/${this.id}/cost`, { params });
586
- }
587
- quality(params) {
588
- return this.client.request("GET", `${BASE}/${this.id}/quality`, { params });
589
- }
590
- activity(params) {
591
- return this.client.request("GET", `${BASE}/${this.id}/activity`, { params });
592
- }
593
- };
594
- var Endpoints = class {
595
- constructor(client) {
596
- this.client = client;
597
- }
598
- client;
599
- deploy(params) {
600
- const body = buildDeployBody(params);
601
- const stream = this.client.stream("POST", BASE, { body, events: true });
602
- if (!params.wait) return stream;
603
- return this.waitForDeploy(stream);
604
- }
605
- async waitForDeploy(stream) {
606
- for await (const ev of stream) {
607
- if (ev.event === "complete") return endpointFromComplete(ev.data);
608
- if (ev.event === "error") throw deployError(ev.data);
609
- }
610
- throw new ParetaError("deploy stream ended without a 'complete' event");
611
- }
612
- list() {
613
- return this.client.request("GET", BASE, { cast: endpointList });
614
- }
615
- retrieve(endpointId) {
616
- return this.client.request("GET", `${BASE}/${endpointId}`, {
617
- cast: (raw) => new Endpoint(raw)
618
- });
619
- }
620
- start(endpointId) {
621
- return this.client.request("POST", `${BASE}/${endpointId}/start`);
622
- }
623
- stop(endpointId) {
624
- return this.client.request("POST", `${BASE}/${endpointId}/stop`);
625
- }
626
- async delete(endpointId) {
627
- await this.client.request("DELETE", `${BASE}/${endpointId}`);
628
- }
629
- metrics(endpointId) {
630
- return new EndpointMetrics(this.client, endpointId);
631
- }
632
- };
633
-
634
501
  // src/resources/tasks.ts
635
- var BASE2 = "/v1/tasks";
502
+ var BASE = "/v1/tasks";
636
503
  var Tasks = class {
637
504
  constructor(client) {
638
505
  this.client = client;
639
506
  }
640
507
  client;
641
508
  list() {
642
- return this.client.request("GET", BASE2, { cast: taskList });
509
+ return this.client.request("GET", BASE, { cast: taskList });
643
510
  }
644
511
  retrieve(taskId, opts = {}) {
645
512
  const params = opts.examplesN !== void 0 ? { examples_n: opts.examplesN } : void 0;
646
- return this.client.request("GET", `${BASE2}/${taskId}`, {
513
+ return this.client.request("GET", `${BASE}/${taskId}`, {
647
514
  params,
648
515
  cast: (raw) => new Task(raw)
649
516
  });
@@ -651,25 +518,15 @@ var Tasks = class {
651
518
  /** Free-text intent → ranked candidate tasks (the Step-0 backend matcher). */
652
519
  match(query, opts = {}) {
653
520
  if (!query || !query.trim()) throw new ParetaError("query is required");
654
- return this.client.request("POST", `${BASE2}/match`, {
521
+ return this.client.request("POST", `${BASE}/match`, {
655
522
  body: { query, top_k: opts.topK ?? 5 },
656
523
  cast: (raw) => new TaskMatch(raw)
657
524
  });
658
525
  }
659
- /** Models ranked by quality/cost for a task (+ recommended + frontier baseline). */
660
- leaderboard(taskId) {
661
- return this.client.request("GET", `${BASE2}/${taskId}/leaderboard`, {
662
- cast: leaderboardFrom
663
- });
664
- }
665
- /** The task's recommended deployable model — what deploy(model:"recommended") resolves to. */
666
- async recommended(taskId) {
667
- return (await this.leaderboard(taskId)).recommended;
668
- }
669
526
  };
670
527
 
671
528
  // src/resources/evals.ts
672
- var BASE3 = "/v1/eval-sets";
529
+ var BASE2 = "/v1/eval-sets";
673
530
  var RUNS = "/v1/eval-runs";
674
531
  var FRONTIER = "/v1/eval/frontier-models";
675
532
  var INLINE_MAX = 5 * 1024 * 1024;
@@ -743,17 +600,17 @@ var EvalSets = class {
743
600
  client;
744
601
  create(params) {
745
602
  const { files, data } = itemsJsonl(params.task, params.items, params.name);
746
- return this.client.request("POST", BASE3, { files, data, cast: evalSetFromCreate });
603
+ return this.client.request("POST", BASE2, { files, data, cast: evalSetFromCreate });
747
604
  }
748
605
  list() {
749
- return this.client.request("GET", BASE3, { cast: evalSetList });
606
+ return this.client.request("GET", BASE2, { cast: evalSetList });
750
607
  }
751
608
  async retrieve(evalSetId) {
752
- const raw = await this.client.request("GET", `${BASE3}/${evalSetId}`);
609
+ const raw = await this.client.request("GET", `${BASE2}/${evalSetId}`);
753
610
  return new EvalSet((raw ?? {}).eval_set ?? {});
754
611
  }
755
612
  async delete(evalSetId) {
756
- await this.client.request("DELETE", `${BASE3}/${evalSetId}`);
613
+ await this.client.request("DELETE", `${BASE2}/${evalSetId}`);
757
614
  }
758
615
  /**
759
616
  * Attach a binary doc (PDF/image) to one row's blob field. Collapses the
@@ -763,14 +620,14 @@ var EvalSets = class {
763
620
  async uploadDocument(evalSetId, file, opts) {
764
621
  const { blob, filename, size, mime } = await toBlob(file, opts.mime);
765
622
  if (size < INLINE_MAX) {
766
- return this.client.request("POST", `${BASE3}/${evalSetId}/attach-blob`, {
623
+ return this.client.request("POST", `${BASE2}/${evalSetId}/attach-blob`, {
767
624
  files: { file: { filename, content: blob, contentType: mime } },
768
625
  data: { idx: String(opts.idx), field_name: opts.fieldName, mime }
769
626
  });
770
627
  }
771
628
  const minted = await this.client.request(
772
629
  "POST",
773
- `${BASE3}/${evalSetId}/blob-upload-url`,
630
+ `${BASE2}/${evalSetId}/blob-upload-url`,
774
631
  { body: { idx: opts.idx, field_name: opts.fieldName, mime, file_size: size } }
775
632
  );
776
633
  const put = await globalThis.fetch(minted.upload_url, {
@@ -782,7 +639,7 @@ var EvalSets = class {
782
639
  if (put.status !== 200 && put.status !== 201) {
783
640
  throw new ParetaError(`blob upload PUT failed: ${put.status}`);
784
641
  }
785
- return this.client.request("POST", `${BASE3}/${evalSetId}/blob-upload-complete`, {
642
+ return this.client.request("POST", `${BASE2}/${evalSetId}/blob-upload-complete`, {
786
643
  body: { idx: opts.idx, field_name: opts.fieldName, storage_uri: minted.storage_uri, mime }
787
644
  });
788
645
  }
@@ -865,9 +722,41 @@ var Evals = class {
865
722
  }
866
723
  };
867
724
 
725
+ // src/resources/auto.ts
726
+ var Auto = class {
727
+ constructor(client) {
728
+ this.client = client;
729
+ }
730
+ client;
731
+ /** Your org's `model: "auto"` traffic, rolled up. Read-only, free. */
732
+ metrics() {
733
+ return this.client.request("GET", "/v1/auto/metrics");
734
+ }
735
+ /**
736
+ * One prompt against a frontier vendor for a side-by-side with
737
+ * `model: "auto"` — METERED at the vendor's actual token cost (a failed
738
+ * vendor call bills $0). Allowed models: gpt-5.5, gemini-3-5-flash,
739
+ * gemini-3-1-pro, claude-sonnet-4-6.
740
+ */
741
+ compareFrontier(params) {
742
+ return this.client.request(
743
+ "POST",
744
+ "/v1/playground/frontier",
745
+ { body: params }
746
+ );
747
+ }
748
+ };
749
+
868
750
  // src/client.ts
869
751
  var DEFAULT_BASE_URL = "https://api.pareta.ai";
870
- var DEFAULT_TIMEOUT_MS = 6e4;
752
+ function randomKey() {
753
+ try {
754
+ return globalThis.crypto?.randomUUID?.().replace(/-/g, "") ?? Math.random().toString(36).slice(2) + Date.now().toString(36);
755
+ } catch {
756
+ return Math.random().toString(36).slice(2) + Date.now().toString(36);
757
+ }
758
+ }
759
+ var DEFAULT_TIMEOUT_MS = 6e5;
871
760
  var DEFAULT_MAX_RETRIES = 2;
872
761
  var RETRY_STATUSES = /* @__PURE__ */ new Set([408, 409, 429, 500, 502, 503, 504]);
873
762
  function normalizeBaseURL(url) {
@@ -882,9 +771,9 @@ var Pareta = class _Pareta {
882
771
  // Resource namespaces (assigned in the constructor; filled in slice by slice).
883
772
  chat;
884
773
  models;
885
- endpoints;
886
774
  tasks;
887
775
  evals;
776
+ auto;
888
777
  constructor(options = {}) {
889
778
  if (!options.apiKey) {
890
779
  throw new ParetaError(
@@ -902,9 +791,9 @@ var Pareta = class _Pareta {
902
791
  this.fetchImpl = options.fetch ? f : f.bind(globalThis);
903
792
  this.chat = new Chat(this);
904
793
  this.models = new Models(this);
905
- this.endpoints = new Endpoints(this);
906
794
  this.tasks = new Tasks(this);
907
795
  this.evals = new Evals(this);
796
+ this.auto = new Auto(this);
908
797
  }
909
798
  /** Build from PARETA_API_KEY (+ optional PARETA_BASE_URL); explicit opts win. */
910
799
  static fromEnv(options = {}) {
@@ -991,6 +880,9 @@ var Pareta = class _Pareta {
991
880
  const url = this.buildURL(path, params);
992
881
  const isMultipart = files != null || data != null;
993
882
  const headers = this.headers({ jsonBody: body != null && !isMultipart });
883
+ if (method.toUpperCase() === "POST" && !headers["Idempotency-Key"]) {
884
+ headers["Idempotency-Key"] = `pareta-js-${randomKey()}`;
885
+ }
994
886
  let payload;
995
887
  if (isMultipart) {
996
888
  payload = this.buildFormData(files, data);
@@ -1032,12 +924,15 @@ var Pareta = class _Pareta {
1032
924
  /**
1033
925
  * Yield parsed SSE objects. Retries ONLY the initial connect/handshake — once
1034
926
  * bytes are flowing a mid-stream drop raises (re-issuing would re-run a
1035
- * metered generation / re-trigger a deploy). `events:true` → `{event,data}`.
927
+ * metered generation). `events:true` → `{event,data}`.
1036
928
  */
1037
929
  async *stream(method, path, opts = {}) {
1038
930
  const { body, params, cast, events } = opts;
1039
931
  const url = this.buildURL(path, params);
1040
932
  const headers = this.headers({ stream: true, jsonBody: body != null });
933
+ if (method.toUpperCase() === "POST" && !headers["Idempotency-Key"]) {
934
+ headers["Idempotency-Key"] = `pareta-js-${randomKey()}`;
935
+ }
1041
936
  const payload = body != null ? JSON.stringify(body) : void 0;
1042
937
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
1043
938
  let started = false;
@@ -1089,9 +984,8 @@ exports.ChatCompletion = ChatCompletion;
1089
984
  exports.ChatCompletionChunk = ChatCompletionChunk;
1090
985
  exports.Choice = Choice;
1091
986
  exports.ConflictError = ConflictError;
1092
- exports.Endpoint = Endpoint;
1093
- exports.EndpointMetrics = EndpointMetrics;
1094
987
  exports.EndpointNotReadyError = EndpointNotReadyError;
988
+ exports.EvalItemResult = EvalItemResult;
1095
989
  exports.EvalResult = EvalResult;
1096
990
  exports.EvalRun = EvalRun;
1097
991
  exports.EvalRuns = EvalRuns;
@@ -1099,8 +993,6 @@ exports.EvalSet = EvalSet;
1099
993
  exports.EvalSets = EvalSets;
1100
994
  exports.FrontierModel = FrontierModel;
1101
995
  exports.InsufficientCreditsError = InsufficientCreditsError;
1102
- exports.Leaderboard = Leaderboard;
1103
- exports.LeaderboardEntry = LeaderboardEntry;
1104
996
  exports.Message = Message;
1105
997
  exports.Model = Model;
1106
998
  exports.ModelList = ModelList;