@hawkeyexl/inference 0.0.1

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/index.js ADDED
@@ -0,0 +1,722 @@
1
+ // src/types.ts
2
+ var InferenceError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "InferenceError";
6
+ }
7
+ };
8
+
9
+ // src/providers/anthropic.ts
10
+ import Anthropic from "@anthropic-ai/sdk";
11
+ var DEFAULT_TOOL_NAME = "record_result";
12
+ var AnthropicProvider = class {
13
+ constructor(model, apiKeyEnv, options = {}) {
14
+ this.model = model;
15
+ const apiKey = process.env[apiKeyEnv];
16
+ if (!apiKey) {
17
+ throw new InferenceError(
18
+ `Anthropic provider needs ${apiKeyEnv} set (or choose another provider)`
19
+ );
20
+ }
21
+ this.client = new Anthropic({ apiKey });
22
+ this.toolName = options.toolName ?? DEFAULT_TOOL_NAME;
23
+ this.toolDescription = options.toolDescription ?? "Record the structured result.";
24
+ this.maxTokens = options.maxTokens ?? 1024;
25
+ }
26
+ model;
27
+ client;
28
+ toolName;
29
+ toolDescription;
30
+ maxTokens;
31
+ provider() {
32
+ return "anthropic";
33
+ }
34
+ modelName() {
35
+ return this.model;
36
+ }
37
+ async completeJSON(req) {
38
+ const response = await this.client.messages.create({
39
+ model: this.model,
40
+ max_tokens: this.maxTokens,
41
+ temperature: req.temperature,
42
+ system: req.system,
43
+ messages: [{ role: "user", content: req.user }],
44
+ tools: [
45
+ {
46
+ name: this.toolName,
47
+ description: this.toolDescription,
48
+ input_schema: req.schema
49
+ }
50
+ ],
51
+ tool_choice: { type: "tool", name: this.toolName }
52
+ });
53
+ if (response.stop_reason === "max_tokens") {
54
+ throw new Error(
55
+ `Anthropic response hit max_tokens (${this.maxTokens}) before completing the tool call \u2014 raise the anthropic.maxTokens option.`
56
+ );
57
+ }
58
+ const toolUse = response.content.find(
59
+ (block) => block.type === "tool_use"
60
+ );
61
+ if (!toolUse) {
62
+ throw new Error("Anthropic response contained no tool_use block");
63
+ }
64
+ return {
65
+ json: toolUse.input,
66
+ usage: {
67
+ inputTokens: response.usage.input_tokens,
68
+ outputTokens: response.usage.output_tokens
69
+ }
70
+ };
71
+ }
72
+ };
73
+
74
+ // src/providers/openai-compat.ts
75
+ function extractJson(content) {
76
+ const trimmed = content.replace(/^\s*```(?:json)?\s*/i, "").replace(/\s*```\s*$/, "").trim();
77
+ try {
78
+ return JSON.parse(trimmed);
79
+ } catch {
80
+ const start = trimmed.indexOf("{");
81
+ const end = trimmed.lastIndexOf("}");
82
+ if (start >= 0 && end > start) {
83
+ return JSON.parse(trimmed.slice(start, end + 1));
84
+ }
85
+ throw new Error("Response contained no parseable JSON object");
86
+ }
87
+ }
88
+ function toStrictSchema(schema) {
89
+ const clone = structuredClone(schema);
90
+ const walk = (node) => {
91
+ if (node === null || typeof node !== "object") return;
92
+ if (Array.isArray(node)) {
93
+ for (const item of node) walk(item);
94
+ return;
95
+ }
96
+ const obj = node;
97
+ delete obj["minLength"];
98
+ delete obj["uniqueItems"];
99
+ const properties = obj["properties"];
100
+ if (properties && typeof properties === "object") {
101
+ obj["required"] = Object.keys(properties);
102
+ obj["additionalProperties"] = false;
103
+ for (const prop of Object.values(properties)) {
104
+ walk(prop);
105
+ if (prop && typeof prop === "object" && !Array.isArray(prop)) {
106
+ const p = prop;
107
+ if (typeof p["type"] === "string" && p["type"] !== "null") {
108
+ p["type"] = [p["type"], "null"];
109
+ }
110
+ }
111
+ }
112
+ }
113
+ walk(obj["items"]);
114
+ };
115
+ walk(clone);
116
+ return clone;
117
+ }
118
+ function stripNulls(value) {
119
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
120
+ return value;
121
+ }
122
+ return Object.fromEntries(
123
+ Object.entries(value).filter(
124
+ ([, v]) => v !== null
125
+ )
126
+ );
127
+ }
128
+ var OpenAICompatProvider = class {
129
+ constructor(baseUrl, model, apiKeyEnv, apiKey = process.env[apiKeyEnv], options = {}) {
130
+ this.baseUrl = baseUrl;
131
+ this.model = model;
132
+ this.apiKey = apiKey;
133
+ if (!this.apiKey && baseUrl.includes("api.openai.com")) {
134
+ throw new InferenceError(
135
+ `OpenAI provider needs ${apiKeyEnv} set (or point baseUrl at a local server)`
136
+ );
137
+ }
138
+ this.schemaName = options.schemaName ?? "result";
139
+ }
140
+ baseUrl;
141
+ model;
142
+ apiKey;
143
+ supportsJsonSchema = true;
144
+ schemaName;
145
+ provider() {
146
+ return "openai";
147
+ }
148
+ modelName() {
149
+ return this.model;
150
+ }
151
+ async chat(body) {
152
+ const response = await fetch(
153
+ `${this.baseUrl.replace(/\/$/, "")}/chat/completions`,
154
+ {
155
+ method: "POST",
156
+ headers: {
157
+ "content-type": "application/json",
158
+ ...this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {}
159
+ },
160
+ body: JSON.stringify(body)
161
+ }
162
+ );
163
+ const json = await response.json().catch(() => ({}));
164
+ if (!response.ok) {
165
+ const message = json.error?.message ?? `HTTP ${response.status}`;
166
+ throw new Error(`${message}`);
167
+ }
168
+ return json;
169
+ }
170
+ async completeJSON(req) {
171
+ const base = {
172
+ model: this.model,
173
+ temperature: req.temperature,
174
+ messages: [
175
+ { role: "system", content: req.system },
176
+ { role: "user", content: req.user }
177
+ ]
178
+ };
179
+ let response;
180
+ if (this.supportsJsonSchema) {
181
+ try {
182
+ response = await this.chat({
183
+ ...base,
184
+ response_format: {
185
+ type: "json_schema",
186
+ json_schema: {
187
+ name: this.schemaName,
188
+ strict: true,
189
+ schema: toStrictSchema(req.schema)
190
+ }
191
+ }
192
+ });
193
+ } catch (e) {
194
+ const message = e instanceof Error ? e.message : String(e);
195
+ if (!/response_format|json_schema|schema/i.test(message) && message !== "HTTP 400") {
196
+ throw e;
197
+ }
198
+ this.supportsJsonSchema = false;
199
+ response = await this.jsonObjectFallback(base, req);
200
+ }
201
+ } else {
202
+ response = await this.jsonObjectFallback(base, req);
203
+ }
204
+ const content = response.choices?.[0]?.message?.content;
205
+ if (!content) throw new Error("Empty completion response");
206
+ return {
207
+ json: stripNulls(extractJson(content)),
208
+ usage: response.usage?.prompt_tokens != null ? {
209
+ inputTokens: response.usage.prompt_tokens ?? 0,
210
+ outputTokens: response.usage.completion_tokens ?? 0
211
+ } : void 0
212
+ };
213
+ }
214
+ jsonObjectFallback(base, req) {
215
+ return this.chat({
216
+ ...base,
217
+ messages: [
218
+ {
219
+ role: "system",
220
+ content: `${req.system}
221
+
222
+ Respond with ONLY a JSON object conforming to this JSON Schema:
223
+ ${JSON.stringify(req.schema)}`
224
+ },
225
+ { role: "user", content: req.user }
226
+ ],
227
+ response_format: { type: "json_object" }
228
+ });
229
+ }
230
+ };
231
+
232
+ // src/exec.ts
233
+ import spawn from "cross-spawn";
234
+ var realExec = (cmd, opts = {}) => {
235
+ const [bin, ...args] = cmd;
236
+ if (!bin) {
237
+ return Promise.resolve({
238
+ code: null,
239
+ stdout: "",
240
+ stderr: "",
241
+ timedOut: false,
242
+ spawnError: "Empty command"
243
+ });
244
+ }
245
+ return new Promise((resolvePromise) => {
246
+ const child = spawn(bin, args, {
247
+ cwd: opts.cwd,
248
+ env: { ...process.env, ...opts.env ?? {} },
249
+ stdio: [opts.input != null ? "pipe" : "ignore", "pipe", "pipe"]
250
+ });
251
+ let stdout = "";
252
+ let stderr = "";
253
+ let timedOut = false;
254
+ let settled = false;
255
+ const timeoutMs = opts.timeoutMs ?? 6e4;
256
+ const timer = setTimeout(() => {
257
+ timedOut = true;
258
+ child.kill();
259
+ settle({ code: null, stdout, stderr, timedOut: true });
260
+ }, timeoutMs);
261
+ const settle = (result) => {
262
+ if (settled) return;
263
+ settled = true;
264
+ clearTimeout(timer);
265
+ resolvePromise(result);
266
+ };
267
+ if (opts.input != null && child.stdin) {
268
+ child.stdin.on("error", () => {
269
+ });
270
+ child.stdin.end(opts.input);
271
+ }
272
+ child.stdout?.setEncoding("utf8");
273
+ child.stderr?.setEncoding("utf8");
274
+ child.stdout?.on("data", (d) => stdout += d);
275
+ child.stderr?.on("data", (d) => stderr += d);
276
+ child.on(
277
+ "error",
278
+ (e) => settle({ code: null, stdout, stderr, timedOut, spawnError: e.message })
279
+ );
280
+ child.on("close", (code) => settle({ code, stdout, stderr, timedOut }));
281
+ });
282
+ };
283
+
284
+ // src/providers/claude-cli.ts
285
+ var ClaudeCliProvider = class {
286
+ constructor(model, command = "claude", exec = realExec, timeoutMs = 18e4) {
287
+ this.model = model;
288
+ this.command = command;
289
+ this.exec = exec;
290
+ this.timeoutMs = timeoutMs;
291
+ }
292
+ model;
293
+ command;
294
+ exec;
295
+ timeoutMs;
296
+ provider() {
297
+ return "claude-cli";
298
+ }
299
+ modelName() {
300
+ return this.model;
301
+ }
302
+ async completeJSON(req) {
303
+ const prompt = [
304
+ req.user,
305
+ "",
306
+ "Respond with ONLY a JSON object conforming to this JSON Schema \u2014 no",
307
+ "prose, no markdown fences:",
308
+ JSON.stringify(req.schema)
309
+ ].join("\n");
310
+ const result = await this.exec(
311
+ [
312
+ this.command,
313
+ "-p",
314
+ "--append-system-prompt",
315
+ req.system,
316
+ "--output-format",
317
+ "json",
318
+ "--model",
319
+ this.model
320
+ ],
321
+ { timeoutMs: this.timeoutMs, input: prompt }
322
+ );
323
+ if (result.spawnError) {
324
+ throw new Error(
325
+ `Failed to run ${this.command}: ${result.spawnError} (is the Claude CLI installed?)`
326
+ );
327
+ }
328
+ if (result.timedOut) throw new Error("Claude CLI timed out");
329
+ if (result.code !== 0) {
330
+ throw new Error(
331
+ `Claude CLI exited ${result.code}: ${result.stderr.trim().slice(-300)}`
332
+ );
333
+ }
334
+ const wrapper = JSON.parse(result.stdout);
335
+ if (typeof wrapper.result !== "string") {
336
+ throw new Error("Claude CLI returned no result field");
337
+ }
338
+ return { json: extractJson(wrapper.result) };
339
+ }
340
+ };
341
+
342
+ // src/providers/mock.ts
343
+ var MockProvider = class {
344
+ constructor(responses, model = "mock-model") {
345
+ this.responses = responses;
346
+ this.model = model;
347
+ if (responses.length === 0) {
348
+ throw new Error("MockProvider needs at least one scripted response");
349
+ }
350
+ }
351
+ responses;
352
+ model;
353
+ calls = 0;
354
+ /** Every request seen, in order — assert against this in tests. */
355
+ requests = [];
356
+ provider() {
357
+ return "mock";
358
+ }
359
+ modelName() {
360
+ return this.model;
361
+ }
362
+ completeJSON(req) {
363
+ this.requests.push(req);
364
+ const response = this.responses[this.calls % this.responses.length];
365
+ this.calls += 1;
366
+ if ("error" in response) {
367
+ return Promise.reject(new Error(response.error));
368
+ }
369
+ return Promise.resolve({
370
+ json: response.json,
371
+ usage: response.usage ?? { inputTokens: 500, outputTokens: 100 }
372
+ });
373
+ }
374
+ };
375
+ function mockVerdict(match, confidence, overrides = {}) {
376
+ return {
377
+ json: {
378
+ claim: overrides.claim ?? "The assertion under test",
379
+ observed: overrides.observed ?? "Observed content",
380
+ match,
381
+ confidence,
382
+ reasoning: overrides.reasoning ?? "Scripted mock reasoning"
383
+ }
384
+ };
385
+ }
386
+
387
+ // src/providers/index.ts
388
+ var DEFAULT_MODELS = {
389
+ anthropic: "claude-sonnet-4-5",
390
+ openai: "gpt-4o-mini",
391
+ "claude-cli": "claude-sonnet-4-5",
392
+ mock: "mock-model"
393
+ };
394
+ var DEFAULT_API_KEY_ENV = {
395
+ anthropic: "ANTHROPIC_API_KEY",
396
+ openai: "OPENAI_API_KEY"
397
+ };
398
+ var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
399
+ function resolveProviderIdentity(spec) {
400
+ return {
401
+ provider: spec.provider,
402
+ model: spec.model ?? DEFAULT_MODELS[spec.provider] ?? "unknown"
403
+ };
404
+ }
405
+ function makeProvider(spec) {
406
+ const { model } = resolveProviderIdentity(spec);
407
+ switch (spec.provider) {
408
+ case "anthropic":
409
+ return new AnthropicProvider(
410
+ model,
411
+ spec.apiKeyEnv ?? DEFAULT_API_KEY_ENV["anthropic"],
412
+ spec.anthropic ?? {}
413
+ );
414
+ case "openai":
415
+ return new OpenAICompatProvider(
416
+ spec.baseUrl ?? DEFAULT_OPENAI_BASE_URL,
417
+ model,
418
+ spec.apiKeyEnv ?? DEFAULT_API_KEY_ENV["openai"],
419
+ void 0,
420
+ spec.openai ?? {}
421
+ );
422
+ case "claude-cli":
423
+ return new ClaudeCliProvider(
424
+ model,
425
+ spec.command ?? "claude",
426
+ spec.exec,
427
+ spec.timeoutMs
428
+ );
429
+ case "mock":
430
+ return new MockProvider(spec.mockResponses ?? [{ json: {} }], model);
431
+ default:
432
+ throw new InferenceError(
433
+ `Unknown provider "${String(spec.provider)}". Available: ${Object.keys(
434
+ DEFAULT_MODELS
435
+ ).join(", ")}.`
436
+ );
437
+ }
438
+ }
439
+
440
+ // src/complete.ts
441
+ import { Ajv2020 } from "ajv/dist/2020.js";
442
+ var validatorCache = /* @__PURE__ */ new WeakMap();
443
+ function validatorFor(schema) {
444
+ const cached = validatorCache.get(schema);
445
+ if (cached) return cached;
446
+ const compiled = new Ajv2020({ allErrors: true }).compile(schema);
447
+ validatorCache.set(schema, compiled);
448
+ return compiled;
449
+ }
450
+ async function completeValidatedJSON(options) {
451
+ const {
452
+ provider,
453
+ system,
454
+ user,
455
+ schema,
456
+ temperature = 0,
457
+ attempts = 2
458
+ } = options;
459
+ const validate = options.validate ?? validatorFor(schema);
460
+ const start = Date.now();
461
+ const base = {
462
+ provider: provider.provider(),
463
+ model: provider.modelName(),
464
+ cached: false
465
+ };
466
+ let lastError = "unknown error";
467
+ for (let attempt = 0; attempt < attempts; attempt++) {
468
+ try {
469
+ const response = await provider.completeJSON({
470
+ system,
471
+ user,
472
+ schema,
473
+ temperature
474
+ });
475
+ if (validate(response.json)) {
476
+ return {
477
+ ...base,
478
+ result: response.json,
479
+ usage: response.usage,
480
+ durationMs: Date.now() - start
481
+ };
482
+ }
483
+ lastError = `Response failed schema validation: ${(validate.errors ?? []).map((e) => `${e.instancePath} ${e.message}`).join("; ")}`;
484
+ } catch (e) {
485
+ lastError = e instanceof Error ? e.message : String(e);
486
+ }
487
+ }
488
+ return { ...base, error: lastError, durationMs: Date.now() - start };
489
+ }
490
+
491
+ // src/cache.ts
492
+ import { createHash } from "crypto";
493
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
494
+ import { join } from "path";
495
+ function sha256(text) {
496
+ return createHash("sha256").update(text, "utf8").digest("hex");
497
+ }
498
+ function buildCacheKey(parts) {
499
+ return sha256(parts.map((p) => `${p.length}:${p}`).join("|"));
500
+ }
501
+ var JsonCache = class {
502
+ constructor(dir, enabled = true, label = "inference") {
503
+ this.dir = dir;
504
+ this.enabled = enabled;
505
+ this.label = label;
506
+ }
507
+ dir;
508
+ enabled;
509
+ label;
510
+ /** Cache-write failures warn once per process, not once per entry. */
511
+ warned = false;
512
+ get(key) {
513
+ if (!this.enabled) return void 0;
514
+ const path = join(this.dir, `${key}.json`);
515
+ if (!existsSync(path)) return void 0;
516
+ try {
517
+ return JSON.parse(readFileSync(path, "utf8"));
518
+ } catch {
519
+ return void 0;
520
+ }
521
+ }
522
+ set(key, value) {
523
+ if (!this.enabled) return;
524
+ try {
525
+ mkdirSync(this.dir, { recursive: true });
526
+ writeFileSync(
527
+ join(this.dir, `${key}.json`),
528
+ JSON.stringify(value, null, 2)
529
+ );
530
+ } catch (e) {
531
+ if (!this.warned) {
532
+ this.warned = true;
533
+ console.warn(
534
+ `${this.label}: could not write the cache at ${this.dir} (${e instanceof Error ? e.message : String(e)}). Continuing without caching.`
535
+ );
536
+ }
537
+ }
538
+ }
539
+ };
540
+
541
+ // src/cost.ts
542
+ var PRICE_TABLE = {
543
+ "claude-sonnet-4-5": { inputPerMTok: 3, outputPerMTok: 15 },
544
+ "claude-sonnet-4-6": { inputPerMTok: 3, outputPerMTok: 15 },
545
+ "claude-haiku-4-5": { inputPerMTok: 1, outputPerMTok: 5 },
546
+ "claude-opus-4-8": { inputPerMTok: 15, outputPerMTok: 75 },
547
+ "gpt-4o-mini": { inputPerMTok: 0.15, outputPerMTok: 0.6 },
548
+ "gpt-4o": { inputPerMTok: 2.5, outputPerMTok: 10 }
549
+ };
550
+ function pricingFor(model, override) {
551
+ if (override) return override;
552
+ if (PRICE_TABLE[model]) return PRICE_TABLE[model];
553
+ const base = Object.keys(PRICE_TABLE).filter((k) => model.startsWith(k)).sort((a, b) => b.length - a.length)[0];
554
+ return base ? PRICE_TABLE[base] : void 0;
555
+ }
556
+ function costOfUsage(usage, pricing) {
557
+ if (!usage || !pricing) return 0;
558
+ return usage.inputTokens / 1e6 * pricing.inputPerMTok + usage.outputTokens / 1e6 * pricing.outputPerMTok;
559
+ }
560
+ function costOfRuns(runs, pricing) {
561
+ if (!pricing) return 0;
562
+ let usd = 0;
563
+ for (const run of runs) {
564
+ if (!run.usage || run.cached) continue;
565
+ usd += costOfUsage(run.usage, pricing);
566
+ }
567
+ return usd;
568
+ }
569
+
570
+ // src/judge/verdict-schema.json
571
+ var verdict_schema_default = {
572
+ $schema: "https://json-schema.org/draft/2020-12/schema",
573
+ $id: "inference:verdict:0.1",
574
+ title: "LLM-as-judge verdict",
575
+ type: "object",
576
+ required: ["claim", "observed", "match", "confidence", "reasoning"],
577
+ properties: {
578
+ claim: {
579
+ type: "string",
580
+ description: "The specific assertion under evaluation."
581
+ },
582
+ observed: {
583
+ type: "string",
584
+ description: "What was actually observed in the subject under evaluation, quoting evidence where possible."
585
+ },
586
+ match: {
587
+ enum: ["pass", "fail", "partial"],
588
+ description: "pass only if the assertion is fully satisfied; partial for partial compliance."
589
+ },
590
+ confidence: {
591
+ type: "number",
592
+ minimum: 0,
593
+ maximum: 1,
594
+ description: "Self-reported confidence in this verdict."
595
+ },
596
+ reasoning: {
597
+ type: "string",
598
+ description: "Why this conclusion was reached."
599
+ }
600
+ },
601
+ additionalProperties: false
602
+ };
603
+
604
+ // src/judge/types.ts
605
+ var VERDICT_SCHEMA = verdict_schema_default;
606
+
607
+ // src/judge/consensus.ts
608
+ function computeConsensus(runs) {
609
+ const votes = { pass: 0, fail: 0, partial: 0, error: 0 };
610
+ let confidenceSum = 0;
611
+ let confidenceCount = 0;
612
+ for (const run of runs) {
613
+ if (!run.verdict) {
614
+ votes.error += 1;
615
+ continue;
616
+ }
617
+ votes[run.verdict.match] += 1;
618
+ confidenceSum += run.verdict.confidence;
619
+ confidenceCount += 1;
620
+ }
621
+ const passVotes = votes.pass;
622
+ const failVotes = votes.fail + votes.partial;
623
+ const verdict = passVotes > failVotes ? "pass" : "fail";
624
+ const graded = passVotes + failVotes;
625
+ const agreement = graded > 0 ? Math.max(passVotes, failVotes) / graded : 0;
626
+ const meanConfidence = confidenceCount > 0 ? confidenceSum / confidenceCount : 0;
627
+ return { runs, votes, verdict, agreement, meanConfidence };
628
+ }
629
+
630
+ // src/judge/zones.ts
631
+ var DEFAULT_ZONES = { autoPass: 0.8, autoFail: 0.8 };
632
+ function zoneFor(consensus, thresholds = DEFAULT_ZONES) {
633
+ const { votes, meanConfidence } = consensus;
634
+ const unanimousPass = votes.pass > 0 && votes.fail === 0 && votes.partial === 0 && votes.error === 0;
635
+ const unanimousFail = votes.pass === 0 && votes.error === 0 && votes.fail + votes.partial > 0;
636
+ if (unanimousPass && meanConfidence >= thresholds.autoPass) return "auto-pass";
637
+ if (unanimousFail && meanConfidence >= thresholds.autoFail) return "auto-fail";
638
+ return "human-review";
639
+ }
640
+
641
+ // src/judge/ensemble.ts
642
+ var warnedTemperature = false;
643
+ async function runEnsemble(options) {
644
+ const {
645
+ provider,
646
+ system,
647
+ user,
648
+ runs: runCount = 3,
649
+ temperature = 0,
650
+ schema = VERDICT_SCHEMA,
651
+ cache,
652
+ cacheKey,
653
+ label = "inference"
654
+ } = options;
655
+ if (temperature > 0 && !warnedTemperature) {
656
+ warnedTemperature = true;
657
+ console.warn(
658
+ `${label}: judge temperature is ${temperature} \u2014 nonzero temperature adds noise to verdicts; 0 is strongly recommended.`
659
+ );
660
+ }
661
+ if (cache && cacheKey) {
662
+ const hit = cache.get(cacheKey);
663
+ if (Array.isArray(hit)) return hit.map((r) => ({ ...r, cached: true }));
664
+ }
665
+ const validate = validatorFor(schema);
666
+ const results = [];
667
+ for (let i = 0; i < runCount; i++) {
668
+ const run = await completeValidatedJSON({
669
+ provider,
670
+ system,
671
+ user,
672
+ schema,
673
+ temperature,
674
+ validate
675
+ });
676
+ const { result, ...rest } = run;
677
+ results.push(result === void 0 ? rest : { ...rest, verdict: result });
678
+ }
679
+ if (cache && cacheKey) cache.set(cacheKey, results);
680
+ return results;
681
+ }
682
+ async function judge(options) {
683
+ const runs = await runEnsemble(options);
684
+ const base = computeConsensus(runs);
685
+ return { ...base, zone: zoneFor(base, options.zones ?? DEFAULT_ZONES) };
686
+ }
687
+ function resetTemperatureWarning() {
688
+ warnedTemperature = false;
689
+ }
690
+ export {
691
+ AnthropicProvider,
692
+ ClaudeCliProvider,
693
+ DEFAULT_MODELS,
694
+ DEFAULT_OPENAI_BASE_URL,
695
+ DEFAULT_ZONES,
696
+ InferenceError,
697
+ JsonCache,
698
+ MockProvider,
699
+ OpenAICompatProvider,
700
+ PRICE_TABLE,
701
+ VERDICT_SCHEMA,
702
+ buildCacheKey,
703
+ completeValidatedJSON,
704
+ computeConsensus,
705
+ costOfRuns,
706
+ costOfUsage,
707
+ extractJson,
708
+ judge,
709
+ makeProvider,
710
+ mockVerdict,
711
+ pricingFor,
712
+ realExec,
713
+ resetTemperatureWarning,
714
+ resolveProviderIdentity,
715
+ runEnsemble,
716
+ sha256,
717
+ stripNulls,
718
+ toStrictSchema,
719
+ validatorFor,
720
+ zoneFor
721
+ };
722
+ //# sourceMappingURL=index.js.map