@arizeai/phoenix-client 4.0.0 → 4.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.
Files changed (41) hide show
  1. package/dist/esm/client.d.ts +3 -3
  2. package/dist/esm/client.d.ts.map +1 -1
  3. package/dist/esm/client.js +14 -1
  4. package/dist/esm/client.js.map +1 -1
  5. package/dist/esm/datasets/appendDatasetExamples.js +1 -1
  6. package/dist/esm/datasets/appendDatasetExamples.js.map +1 -1
  7. package/dist/esm/datasets/createDataset.js +2 -2
  8. package/dist/esm/datasets/createDataset.js.map +1 -1
  9. package/dist/esm/experiments/runExperiment.d.ts +4 -3
  10. package/dist/esm/experiments/runExperiment.d.ts.map +1 -1
  11. package/dist/esm/experiments/runExperiment.js +14 -7
  12. package/dist/esm/experiments/runExperiment.js.map +1 -1
  13. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  14. package/dist/esm/types/datasets.d.ts +2 -2
  15. package/dist/esm/types/datasets.d.ts.map +1 -1
  16. package/dist/esm/types/experiments.d.ts +1 -1
  17. package/dist/esm/types/experiments.d.ts.map +1 -1
  18. package/dist/src/client.d.ts +3 -3
  19. package/dist/src/client.d.ts.map +1 -1
  20. package/dist/src/client.js +14 -1
  21. package/dist/src/client.js.map +1 -1
  22. package/dist/src/datasets/appendDatasetExamples.js +1 -1
  23. package/dist/src/datasets/appendDatasetExamples.js.map +1 -1
  24. package/dist/src/datasets/createDataset.js +2 -2
  25. package/dist/src/datasets/createDataset.js.map +1 -1
  26. package/dist/src/experiments/runExperiment.d.ts +4 -3
  27. package/dist/src/experiments/runExperiment.d.ts.map +1 -1
  28. package/dist/src/experiments/runExperiment.js +14 -7
  29. package/dist/src/experiments/runExperiment.js.map +1 -1
  30. package/dist/src/types/datasets.d.ts +2 -2
  31. package/dist/src/types/datasets.d.ts.map +1 -1
  32. package/dist/src/types/experiments.d.ts +1 -1
  33. package/dist/src/types/experiments.d.ts.map +1 -1
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +1 -1
  36. package/src/client.ts +21 -2
  37. package/src/datasets/appendDatasetExamples.ts +1 -1
  38. package/src/datasets/createDataset.ts +2 -2
  39. package/src/experiments/runExperiment.ts +37 -12
  40. package/src/types/datasets.ts +2 -2
  41. package/src/types/experiments.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arizeai/phoenix-client",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "description": "A client for the Phoenix API",
5
5
  "main": "dist/src/index.js",
6
6
  "module": "dist/esm/index.js",
package/src/client.ts CHANGED
@@ -1,4 +1,7 @@
1
- import createOpenApiClient, { type ClientOptions } from "openapi-fetch";
1
+ import createOpenApiClient, {
2
+ type Middleware,
3
+ type ClientOptions,
4
+ } from "openapi-fetch";
2
5
  import type {
3
6
  paths as oapiPathsV1,
4
7
  components as oapiComponentsV1,
@@ -49,6 +52,20 @@ export const getMergedOptions = ({
49
52
  };
50
53
  };
51
54
 
55
+ /**
56
+ * Middleware to take non-successful API calls throw instead of being swallowed
57
+ */
58
+ const middleware: Middleware = {
59
+ onResponse({ response }) {
60
+ if (!response.ok) {
61
+ // Will produce error messages like "https://example.org/api/v1/example: 404 Not Found".
62
+ throw new Error(
63
+ `${response.url}: ${response.status} ${response.statusText}`
64
+ );
65
+ }
66
+ },
67
+ };
68
+
52
69
  /**
53
70
  * Create a Phoenix client.
54
71
  *
@@ -79,8 +96,10 @@ export const createClient = (
79
96
  } = {}
80
97
  ) => {
81
98
  const mergedOptions = getMergedOptions(config);
99
+ const openApiClient = createOpenApiClient<pathsV1>(mergedOptions);
100
+ openApiClient.use(middleware);
82
101
  return {
83
- ...createOpenApiClient<pathsV1>(mergedOptions),
102
+ ...openApiClient,
84
103
  config: mergedOptions,
85
104
  };
86
105
  };
@@ -33,7 +33,7 @@ export async function appendDatasetExamples({
33
33
  const client = _client || createClient();
34
34
  const inputs = examples.map((example) => example.input);
35
35
  const outputs = examples.map((example) => example.output ?? {}); // Treat null as an empty object
36
- const metadata = examples.map((example) => example.metadata);
36
+ const metadata = examples.map((example) => example.metadata ?? {});
37
37
  let datasetName: string;
38
38
  if ("datasetName" in dataset) {
39
39
  datasetName = dataset.datasetName;
@@ -34,8 +34,8 @@ export async function createDataset({
34
34
  }: CreateDatasetParams): Promise<CreateDatasetResponse> {
35
35
  const client = _client || createClient();
36
36
  const inputs = examples.map((example) => example.input);
37
- const outputs = examples.map((example) => example.output ?? {}); // Treat null as an empty object
38
- const metadata = examples.map((example) => example.metadata);
37
+ const outputs = examples.map((example) => example?.output ?? {}); // Treat null as an empty object
38
+ const metadata = examples.map((example) => example?.metadata ?? {});
39
39
  const createDatasetResponse = await client.POST("/v1/datasets/upload", {
40
40
  params: {
41
41
  query: {
@@ -95,6 +95,11 @@ export type RunExperimentParams = ClientFn & {
95
95
  */
96
96
  setGlobalTracerProvider?: boolean;
97
97
  /**
98
+ * Number of times to repeat each dataset example
99
+ * @default 1
100
+ */
101
+ repetitions?: number;
102
+ /*
98
103
  * Whether to use batching for the span processor.
99
104
  * @default true
100
105
  */
@@ -146,6 +151,7 @@ export async function runExperiment({
146
151
  concurrency = 5,
147
152
  dryRun = false,
148
153
  setGlobalTracerProvider = true,
154
+ repetitions = 1,
149
155
  useBatchSpanProcessor = true,
150
156
  }: RunExperimentParams): Promise<RanExperiment> {
151
157
  let provider: NodeTracerProvider | undefined;
@@ -185,6 +191,7 @@ export async function runExperiment({
185
191
  description: experimentDescription,
186
192
  metadata: experimentMetadata,
187
193
  project_name: projectName,
194
+ repetitions,
188
195
  },
189
196
  })
190
197
  .then((res) => res.data?.data);
@@ -262,6 +269,7 @@ export async function runExperiment({
262
269
  isDryRun,
263
270
  nExamples,
264
271
  tracer: taskTracer,
272
+ repetitions,
265
273
  });
266
274
  logger.info(`✅ Task runs completed`);
267
275
 
@@ -315,6 +323,7 @@ function runTaskWithExamples({
315
323
  isDryRun,
316
324
  nExamples,
317
325
  tracer,
326
+ repetitions = 1,
318
327
  }: {
319
328
  /** The client to use */
320
329
  client: PhoenixClient;
@@ -336,9 +345,17 @@ function runTaskWithExamples({
336
345
  nExamples: number;
337
346
  /** TraceProvider instance that will be used to create spans from task calls */
338
347
  tracer: Tracer;
348
+ /** Number of repetitions per example */
349
+ repetitions?: number;
339
350
  }): Promise<void> {
340
351
  logger.info(`🔧 Running task "${task.name}" on dataset "${dataset.id}"`);
341
- const run = async (example: ExampleWithId) => {
352
+ const run = async ({
353
+ example,
354
+ repetitionNumber,
355
+ }: {
356
+ example: ExampleWithId;
357
+ repetitionNumber: number;
358
+ }) => {
342
359
  return tracer.startActiveSpan(`Task: ${task.name}`, async (span) => {
343
360
  logger.info(
344
361
  `🔧 Running task "${task.name}" on example "${example.id} of dataset "${dataset.id}"`
@@ -374,7 +391,7 @@ function runTaskWithExamples({
374
391
  body: {
375
392
  dataset_example_id: example.id,
376
393
  output: thisRun.output,
377
- repetition_number: 0,
394
+ repetition_number: repetitionNumber,
378
395
  start_time: thisRun.startTime.toISOString(),
379
396
  end_time: thisRun.endTime.toISOString(),
380
397
  trace_id: thisRun.traceId,
@@ -404,15 +421,23 @@ function runTaskWithExamples({
404
421
  };
405
422
  const q = queue(run, concurrency);
406
423
  const examplesToUse = dataset.examples.slice(0, nExamples);
407
- examplesToUse.forEach((example) =>
408
- q.push(example, (err) => {
409
- if (err) {
410
- logger.error(
411
- `Error running task "${task.name}" on example "${example.id}": ${err}`
412
- );
413
- }
414
- })
415
- );
424
+
425
+ examplesToUse
426
+ .flatMap((example) =>
427
+ Array.from({ length: repetitions }, (_, index) => ({
428
+ example,
429
+ repetitionNumber: index,
430
+ }))
431
+ )
432
+ .forEach((exampleWithRepetition) =>
433
+ q.push(exampleWithRepetition, (err) => {
434
+ if (err) {
435
+ logger.error(
436
+ `Error running task "${task.name}" on example "${exampleWithRepetition.example.id}" repetition ${exampleWithRepetition.repetitionNumber}: ${err}`
437
+ );
438
+ }
439
+ })
440
+ );
416
441
  return q.drain();
417
442
  }
418
443
 
@@ -674,7 +699,7 @@ async function runEvaluator({
674
699
  input: example.input,
675
700
  output: run.output ?? null,
676
701
  expected: example.output,
677
- metadata: example.metadata,
702
+ metadata: example?.metadata,
678
703
  });
679
704
  thisEval.result = result;
680
705
  logger.info(
@@ -47,8 +47,8 @@ export interface DatasetExamples {
47
47
  */
48
48
  export interface Example {
49
49
  input: Record<string, unknown>;
50
- output: Record<string, unknown> | null;
51
- metadata: Record<string, unknown>;
50
+ output?: Record<string, unknown> | null;
51
+ metadata?: Record<string, unknown> | null;
52
52
  }
53
53
 
54
54
  /**
@@ -67,7 +67,7 @@ export type EvaluatorParams = {
67
67
  /**
68
68
  * Metadata associated with the Dataset Example
69
69
  */
70
- metadata?: Record<string, unknown>;
70
+ metadata?: Example["metadata"];
71
71
  };
72
72
 
73
73
  export type Evaluator = {