localarena 0.1.0 → 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.
@@ -88,3 +88,548 @@ export class Arena {
88
88
  static fromSnapshot(snapshot: ArenaSnapshot): Arena;
89
89
  static fromJSON(value: string): Arena;
90
90
  }
91
+
92
+ export const RUN_SCHEMA_VERSION: 1;
93
+
94
+ export type ChatRole = "system" | "user" | "assistant";
95
+
96
+ export interface ChatMessageOptions {
97
+ role: ChatRole;
98
+ content: string;
99
+ }
100
+
101
+ export class ChatMessage {
102
+ constructor(role: ChatRole, content: string);
103
+ constructor(options: ChatMessageOptions);
104
+ readonly role: ChatRole;
105
+ readonly content: string;
106
+ }
107
+
108
+ export interface GenerationRequestOptions {
109
+ model: string;
110
+ messages?: readonly (ChatMessage | ChatMessageOptions)[];
111
+ input?: string | readonly (ChatMessage | ChatMessageOptions)[];
112
+ prompt?: string | readonly (ChatMessage | ChatMessageOptions)[];
113
+ system?: string;
114
+ maxTokens?: number | null;
115
+ maxOutputTokens?: number | null;
116
+ max_tokens?: number | null;
117
+ temperature?: number;
118
+ seed?: number;
119
+ stop?: readonly string[];
120
+ extraBody?: Metadata;
121
+ extra_body?: Metadata;
122
+ }
123
+
124
+ export class GenerationRequest {
125
+ constructor(options: GenerationRequestOptions);
126
+ readonly model: string;
127
+ readonly messages: readonly ChatMessage[];
128
+ readonly maxTokens: number | null;
129
+ readonly temperature?: number;
130
+ readonly seed?: number;
131
+ readonly stop: readonly string[];
132
+ readonly extraBody: Readonly<Metadata>;
133
+ }
134
+
135
+ export interface TokenUsageOptions {
136
+ inputTokens?: number | null;
137
+ outputTokens?: number | null;
138
+ totalTokens?: number | null;
139
+ cachedInputTokens?: number | null;
140
+ reasoningTokens?: number | null;
141
+ }
142
+
143
+ export class TokenUsage {
144
+ constructor(options?: TokenUsageOptions);
145
+ readonly inputTokens?: number;
146
+ readonly outputTokens?: number;
147
+ readonly totalTokens?: number;
148
+ readonly cachedInputTokens?: number;
149
+ readonly reasoningTokens?: number;
150
+ }
151
+
152
+ export interface GenerationResultOptions {
153
+ text: string;
154
+ provider: string;
155
+ model: string;
156
+ responseModel?: string;
157
+ finishReason?: string;
158
+ usage?: TokenUsage | TokenUsageOptions;
159
+ latencySeconds: number;
160
+ attempts: number;
161
+ responseId?: string;
162
+ requestId?: string;
163
+ metadata?: Metadata;
164
+ }
165
+
166
+ export class GenerationResult {
167
+ constructor(options: GenerationResultOptions);
168
+ readonly text: string;
169
+ readonly provider: string;
170
+ readonly model: string;
171
+ readonly responseModel?: string;
172
+ readonly finishReason?: string;
173
+ readonly usage: TokenUsage;
174
+ readonly latencySeconds: number;
175
+ readonly attempts: number;
176
+ readonly responseId?: string;
177
+ readonly requestId?: string;
178
+ readonly metadata: Readonly<Metadata>;
179
+ }
180
+
181
+ export interface ModelInfoOptions {
182
+ id: string;
183
+ provider: string;
184
+ displayName?: string;
185
+ metadata?: Metadata;
186
+ }
187
+
188
+ export class ModelInfo {
189
+ constructor(options: ModelInfoOptions);
190
+ readonly id: string;
191
+ readonly provider: string;
192
+ readonly displayName?: string;
193
+ readonly metadata: Readonly<Metadata>;
194
+ }
195
+
196
+ export interface RequestPolicyOptions {
197
+ timeoutMs?: number;
198
+ maxRetries?: number;
199
+ retryBaseMs?: number;
200
+ retryMaxMs?: number;
201
+ maxResponseBytes?: number;
202
+ retryStatuses?: readonly number[];
203
+ }
204
+
205
+ export class RequestPolicy {
206
+ constructor(options?: RequestPolicyOptions);
207
+ readonly timeoutMs: number;
208
+ readonly maxRetries: number;
209
+ readonly retryBaseMs: number;
210
+ readonly retryMaxMs: number;
211
+ readonly maxResponseBytes: number;
212
+ readonly retryStatuses: readonly number[];
213
+ }
214
+
215
+ export interface ProviderCallOptions {
216
+ signal?: AbortSignal;
217
+ requestPolicy?: RequestPolicy | RequestPolicyOptions;
218
+ }
219
+
220
+ export interface GenerationProviderMethods {
221
+ generate(
222
+ request: GenerationRequest | GenerationRequestOptions,
223
+ options?: ProviderCallOptions,
224
+ ): Promise<GenerationResult>;
225
+ listModels?(options?: ProviderCallOptions): Promise<readonly ModelInfo[]>;
226
+ }
227
+
228
+ export type GenerationProvider = GenerationProviderMethods &
229
+ (
230
+ | { readonly id: string; readonly name?: string }
231
+ | { readonly id?: string; readonly name: string }
232
+ );
233
+
234
+ export interface ProviderErrorDetails {
235
+ code?: string;
236
+ provider?: string;
237
+ status?: number;
238
+ retryable?: boolean;
239
+ requestId?: string;
240
+ attempts?: number;
241
+ }
242
+
243
+ export class ProviderError extends Error {
244
+ constructor(message: string, details?: ProviderErrorDetails);
245
+ readonly code: string;
246
+ readonly provider?: string;
247
+ readonly status?: number;
248
+ readonly retryable: boolean;
249
+ readonly requestId?: string;
250
+ readonly attempts: number;
251
+ toJSON(): Record<string, JsonValue | undefined>;
252
+ }
253
+
254
+ export class ProviderConfigurationError extends ProviderError {}
255
+ export class ProviderRequestError extends ProviderError {}
256
+ export class ProviderResponseError extends ProviderError {}
257
+ export class ProviderTimeoutError extends ProviderError {}
258
+ export class ProviderAbortError extends ProviderError {}
259
+
260
+ export interface OpenAICompatibleProviderOptions {
261
+ id?: string;
262
+ baseURL: string;
263
+ apiKey?: string | null;
264
+ headers?: Record<string, string>;
265
+ defaultHeaders?: Record<string, string>;
266
+ requestPolicy?: RequestPolicy | RequestPolicyOptions;
267
+ maxTokensField?: "max_tokens" | "max_completion_tokens";
268
+ fetch?: (...args: any[]) => Promise<any>;
269
+ sleep?: (delayMs: number, signal?: AbortSignal) => Promise<void>;
270
+ random?: () => number;
271
+ now?: () => number;
272
+ }
273
+
274
+ export class OpenAICompatibleProvider {
275
+ constructor(options: OpenAICompatibleProviderOptions);
276
+ readonly id: string;
277
+ readonly kind: "openai-compatible";
278
+ readonly requestPolicy: RequestPolicy;
279
+ generate(
280
+ request: GenerationRequest | GenerationRequestOptions,
281
+ options?: ProviderCallOptions,
282
+ ): Promise<GenerationResult>;
283
+ listModels(options?: ProviderCallOptions): Promise<readonly ModelInfo[]>;
284
+ toJSON(): { id: string; kind: "openai-compatible" };
285
+ }
286
+
287
+ export type ProviderPreset =
288
+ | "llamacpp"
289
+ | "llama.cpp"
290
+ | "llama-cpp"
291
+ | "ollama"
292
+ | "lmstudio"
293
+ | "lm-studio"
294
+ | "LM Studio"
295
+ | "openrouter"
296
+ | "openai"
297
+ | "custom"
298
+ | "generic";
299
+
300
+ export function createProvider(
301
+ name: ProviderPreset,
302
+ options?: Partial<OpenAICompatibleProviderOptions>,
303
+ ): OpenAICompatibleProvider;
304
+
305
+ export interface ModelTargetOptions {
306
+ name: string;
307
+ provider: GenerationProvider;
308
+ model: string;
309
+ requestOverrides?: {
310
+ maxTokens?: number | null;
311
+ maxOutputTokens?: number | null;
312
+ max_tokens?: number | null;
313
+ temperature?: number;
314
+ seed?: number;
315
+ stop?: readonly string[];
316
+ extraBody?: Metadata;
317
+ extra_body?: Metadata;
318
+ };
319
+ }
320
+
321
+ export class ModelTarget {
322
+ constructor(options: ModelTargetOptions);
323
+ readonly name: string;
324
+ readonly provider: GenerationProvider;
325
+ readonly providerName: string;
326
+ readonly model: string;
327
+ readonly requestOverrides: Readonly<Metadata>;
328
+ generate(
329
+ request: Omit<GenerationRequestOptions, "model">,
330
+ options?: ProviderCallOptions,
331
+ ): Promise<GenerationResult>;
332
+ toJSON(): {
333
+ name: string;
334
+ provider: string;
335
+ model: string;
336
+ parameters: {
337
+ max_tokens: number | null;
338
+ temperature: number | null;
339
+ seed: number | null;
340
+ stop: string[];
341
+ };
342
+ };
343
+ }
344
+
345
+ export interface ScoreOptions {
346
+ value: number;
347
+ passed?: boolean | null;
348
+ reason?: string;
349
+ metadata?: Metadata;
350
+ }
351
+
352
+ export class Score {
353
+ constructor(value: number, options?: Omit<ScoreOptions, "value">);
354
+ constructor(options: ScoreOptions);
355
+ readonly value: number;
356
+ readonly passed: boolean | null;
357
+ readonly reason: string;
358
+ readonly metadata: Readonly<Metadata>;
359
+ snapshot(): ScoreSnapshot;
360
+ toJSON(): ScoreSnapshot;
361
+ static fromSnapshot(value: ScoreOptions): Score;
362
+ }
363
+
364
+ export interface ScoreSnapshot {
365
+ value: number;
366
+ passed: boolean | null;
367
+ reason: string | null;
368
+ metadata: Metadata;
369
+ }
370
+
371
+ export interface Evaluator {
372
+ readonly name: string;
373
+ evaluate(
374
+ task: PromptTask,
375
+ generation: GenerationResult,
376
+ options?: { signal?: AbortSignal },
377
+ ): Score | Promise<Score>;
378
+ toConfig(): Metadata & { type: string };
379
+ }
380
+
381
+ export interface PromptTaskOptions {
382
+ id: string;
383
+ messages: readonly ChatMessage[];
384
+ evaluator?: Evaluator | null;
385
+ metadata?: Metadata;
386
+ }
387
+
388
+ export class PromptTask {
389
+ constructor(options: PromptTaskOptions);
390
+ constructor(
391
+ id: string,
392
+ messages: readonly ChatMessage[],
393
+ options?: Omit<PromptTaskOptions, "id" | "messages">,
394
+ );
395
+ readonly id: string;
396
+ readonly messages: readonly ChatMessage[];
397
+ readonly evaluator: Evaluator | null;
398
+ readonly metadata: Readonly<Metadata>;
399
+ snapshot(): TaskSnapshot;
400
+ toJSON(): TaskSnapshot;
401
+ static fromText(
402
+ id: string,
403
+ prompt: string,
404
+ options?: {
405
+ system?: string | null;
406
+ evaluator?: Evaluator | null;
407
+ metadata?: Metadata;
408
+ },
409
+ ): PromptTask;
410
+ }
411
+
412
+ export interface TaskSnapshot {
413
+ id: string;
414
+ messages: Array<{ role: ChatRole; content: string | null }>;
415
+ evaluator: (Metadata & { type: string }) | null;
416
+ metadata: Metadata;
417
+ }
418
+
419
+ export class ExactMatch implements Evaluator {
420
+ constructor(expected: string, options?: {
421
+ strip?: boolean;
422
+ ignoreCase?: boolean;
423
+ ignore_case?: boolean;
424
+ });
425
+ readonly name: "exact";
426
+ readonly expected: string;
427
+ readonly strip: boolean;
428
+ readonly ignoreCase: boolean;
429
+ evaluate(task: PromptTask, generation: GenerationResult): Score;
430
+ toConfig(): Metadata & { type: "exact" };
431
+ }
432
+
433
+ export class Contains implements Evaluator {
434
+ constructor(expected: string | readonly string[], options?: {
435
+ mode?: "all" | "any";
436
+ ignoreCase?: boolean;
437
+ ignore_case?: boolean;
438
+ });
439
+ readonly name: "contains";
440
+ evaluate(task: PromptTask, generation: GenerationResult): Score;
441
+ toConfig(): Metadata & { type: "contains" };
442
+ }
443
+
444
+ export class RegexMatch implements Evaluator {
445
+ constructor(pattern: string, options?: {
446
+ ignoreCase?: boolean;
447
+ ignore_case?: boolean;
448
+ fullMatch?: boolean;
449
+ full_match?: boolean;
450
+ });
451
+ readonly name: "regex";
452
+ evaluate(task: PromptTask, generation: GenerationResult): Score;
453
+ toConfig(): Metadata & { type: "regex" };
454
+ }
455
+
456
+ export class JSONMatch implements Evaluator {
457
+ constructor(expected?: JsonValue, options?: { compare?: boolean });
458
+ readonly name: "json";
459
+ evaluate(task: PromptTask, generation: GenerationResult): Score;
460
+ toConfig(): Metadata & { type: "json" };
461
+ }
462
+
463
+ export const JsonMatch: typeof JSONMatch;
464
+
465
+ export class NumericMatch implements Evaluator {
466
+ constructor(expected: number, options?: { tolerance?: number });
467
+ readonly name: "numeric";
468
+ evaluate(task: PromptTask, generation: GenerationResult): Score;
469
+ toConfig(): Metadata & { type: "numeric" };
470
+ }
471
+
472
+ export function evaluatorFromConfig(config?: Metadata | null): Evaluator | null;
473
+
474
+ export interface ModelJudgeOptions {
475
+ target: ModelTarget;
476
+ rubric?: string;
477
+ referenceAnswer?: string | null;
478
+ reference_answer?: string | null;
479
+ passThreshold?: number | null;
480
+ pass_threshold?: number | null;
481
+ }
482
+
483
+ export class JudgeParseError extends Error {}
484
+
485
+ export class ModelJudge implements Evaluator {
486
+ constructor(target: ModelTarget, options?: Omit<ModelJudgeOptions, "target">);
487
+ constructor(options: ModelJudgeOptions);
488
+ readonly name: "model_judge";
489
+ readonly target: ModelTarget;
490
+ readonly rubric: string;
491
+ readonly referenceAnswer: string | null;
492
+ readonly passThreshold: number | null;
493
+ evaluate(
494
+ task: PromptTask,
495
+ generation: GenerationResult,
496
+ options?: { signal?: AbortSignal },
497
+ ): Promise<Score>;
498
+ toConfig(): Metadata & { type: "model_judge" };
499
+ }
500
+
501
+ export interface ErrorMetadata {
502
+ status_code?: number | null;
503
+ retryable?: boolean;
504
+ attempts?: number;
505
+ }
506
+
507
+ export interface EvaluationRecordOptions {
508
+ id: number;
509
+ target: string;
510
+ provider: string;
511
+ model: string;
512
+ taskId: string;
513
+ repetition: number;
514
+ startedAt: string;
515
+ finishedAt: string;
516
+ durationSeconds: number;
517
+ generation?: GenerationResult | null;
518
+ score?: Score | null;
519
+ error?: string | null;
520
+ errorMetadata?: ErrorMetadata;
521
+ }
522
+
523
+ export class EvaluationRecord {
524
+ constructor(options: EvaluationRecordOptions);
525
+ readonly id: number;
526
+ readonly target: string;
527
+ readonly provider: string;
528
+ readonly model: string;
529
+ readonly taskId: string;
530
+ readonly repetition: number;
531
+ readonly startedAt: string;
532
+ readonly finishedAt: string;
533
+ readonly durationSeconds: number;
534
+ readonly generation: GenerationResult | null;
535
+ readonly score: Score | null;
536
+ readonly error: string | null;
537
+ readonly errorMetadata: Readonly<ErrorMetadata>;
538
+ readonly status: "ok" | "score_error" | "generation_error";
539
+ snapshot(options?: { includeContent?: boolean }): Metadata;
540
+ }
541
+
542
+ export interface EvaluationSummaryRow {
543
+ rank: number;
544
+ name: string;
545
+ provider: string;
546
+ model: string;
547
+ runs: number;
548
+ generated: number;
549
+ successful: number;
550
+ errors: number;
551
+ scored: number;
552
+ average_score: number | null;
553
+ pass_rate: number | null;
554
+ average_latency_seconds: number | null;
555
+ input_tokens: number;
556
+ output_tokens: number;
557
+ judge_input_tokens: number;
558
+ judge_output_tokens: number;
559
+ judge_latency_seconds: number;
560
+ elo: number;
561
+ }
562
+
563
+ export interface EvaluationRunOptions {
564
+ id: string;
565
+ name: string;
566
+ startedAt: string;
567
+ finishedAt: string;
568
+ models: readonly Metadata[];
569
+ tasks: readonly Metadata[];
570
+ records: readonly EvaluationRecord[];
571
+ includeContent?: boolean;
572
+ }
573
+
574
+ export class EvaluationRun {
575
+ constructor(options: EvaluationRunOptions);
576
+ readonly id: string;
577
+ readonly name: string;
578
+ readonly startedAt: string;
579
+ readonly finishedAt: string;
580
+ readonly models: readonly Metadata[];
581
+ readonly tasks: readonly Metadata[];
582
+ readonly records: readonly EvaluationRecord[];
583
+ readonly includeContent: boolean;
584
+ arena(): Arena;
585
+ summary(): EvaluationSummaryRow[];
586
+ snapshot(): Metadata;
587
+ toJSON(): Metadata;
588
+ toJSONString(indent?: number | null): string;
589
+ }
590
+
591
+ export interface EvaluationRunnerOptions {
592
+ maxConcurrency?: number;
593
+ repetitions?: number;
594
+ includeContent?: boolean;
595
+ now?: () => string;
596
+ clock?: () => number;
597
+ }
598
+
599
+ export class EvaluationRunner {
600
+ constructor(
601
+ models: readonly ModelTarget[],
602
+ tasks: readonly PromptTask[],
603
+ options?: EvaluationRunnerOptions,
604
+ );
605
+ readonly models: readonly ModelTarget[];
606
+ readonly tasks: readonly PromptTask[];
607
+ readonly maxConcurrency: number;
608
+ readonly repetitions: number;
609
+ readonly includeContent: boolean;
610
+ run(options?: {
611
+ name?: string;
612
+ signal?: AbortSignal;
613
+ progress?: (
614
+ completed: number,
615
+ total: number,
616
+ record: EvaluationRecord,
617
+ ) => void | Promise<void>;
618
+ }): Promise<EvaluationRun>;
619
+ }
620
+
621
+ export function runFromSnapshot(value: Metadata): EvaluationRun;
622
+ export function runFromObject(value: Metadata): EvaluationRun;
623
+ export function runFromJSON(value: string): EvaluationRun;
624
+
625
+ export function renderHTMLReport(
626
+ run: EvaluationRun,
627
+ options?: { title?: string },
628
+ ): string;
629
+ export const renderHtmlReport: typeof renderHTMLReport;
630
+ export function writeHTMLReport(
631
+ run: EvaluationRun,
632
+ path: string | URL | Uint8Array,
633
+ options?: { title?: string },
634
+ ): Promise<string | URL | Uint8Array>;
635
+ export const writeHtmlReport: typeof writeHTMLReport;
@@ -520,3 +520,52 @@ export class Arena {
520
520
  return Arena.fromSnapshot(snapshot);
521
521
  }
522
522
  }
523
+
524
+ export {
525
+ ChatMessage,
526
+ GenerationRequest,
527
+ GenerationResult,
528
+ ModelInfo,
529
+ ModelTarget,
530
+ OpenAICompatibleProvider,
531
+ ProviderAbortError,
532
+ ProviderConfigurationError,
533
+ ProviderError,
534
+ ProviderRequestError,
535
+ ProviderResponseError,
536
+ ProviderTimeoutError,
537
+ RequestPolicy,
538
+ TokenUsage,
539
+ createProvider,
540
+ } from "./providers.js";
541
+
542
+ export {
543
+ Contains,
544
+ ExactMatch,
545
+ JSONMatch,
546
+ JsonMatch,
547
+ NumericMatch,
548
+ PromptTask,
549
+ RegexMatch,
550
+ Score,
551
+ evaluatorFromConfig,
552
+ } from "./tasks.js";
553
+
554
+ export {
555
+ RUN_SCHEMA_VERSION,
556
+ EvaluationRecord,
557
+ EvaluationRun,
558
+ EvaluationRunner,
559
+ JudgeParseError,
560
+ ModelJudge,
561
+ runFromJSON,
562
+ runFromObject,
563
+ runFromSnapshot,
564
+ } from "./evaluation.js";
565
+
566
+ export {
567
+ renderHTMLReport,
568
+ renderHtmlReport,
569
+ writeHTMLReport,
570
+ writeHtmlReport,
571
+ } from "./report.js";