@arizeai/phoenix-client 3.2.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 (93) 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/prompts/sdks/toAI.d.ts +13 -3
  14. package/dist/esm/prompts/sdks/toAI.d.ts.map +1 -1
  15. package/dist/esm/prompts/sdks/toAI.js +23 -15
  16. package/dist/esm/prompts/sdks/toAI.js.map +1 -1
  17. package/dist/esm/prompts/sdks/toSDK.d.ts +1 -1
  18. package/dist/esm/schemas/llm/constants.d.ts +30 -12
  19. package/dist/esm/schemas/llm/constants.d.ts.map +1 -1
  20. package/dist/esm/schemas/llm/converters.d.ts +120 -48
  21. package/dist/esm/schemas/llm/converters.d.ts.map +1 -1
  22. package/dist/esm/schemas/llm/openai/converters.d.ts +6 -3
  23. package/dist/esm/schemas/llm/openai/converters.d.ts.map +1 -1
  24. package/dist/esm/schemas/llm/openai/converters.js +7 -4
  25. package/dist/esm/schemas/llm/openai/converters.js.map +1 -1
  26. package/dist/esm/schemas/llm/schemas.d.ts +37 -16
  27. package/dist/esm/schemas/llm/schemas.d.ts.map +1 -1
  28. package/dist/esm/schemas/llm/vercel/messagePartSchemas.d.ts +42 -12
  29. package/dist/esm/schemas/llm/vercel/messagePartSchemas.d.ts.map +1 -1
  30. package/dist/esm/schemas/llm/vercel/messagePartSchemas.js +5 -2
  31. package/dist/esm/schemas/llm/vercel/messagePartSchemas.js.map +1 -1
  32. package/dist/esm/schemas/llm/vercel/messageSchemas.d.ts +31 -10
  33. package/dist/esm/schemas/llm/vercel/messageSchemas.d.ts.map +1 -1
  34. package/dist/esm/schemas/llm/vercel/toolSchemas.d.ts +3 -3
  35. package/dist/esm/schemas/llm/vercel/toolSchemas.js +1 -1
  36. package/dist/esm/schemas/llm/vercel/toolSchemas.js.map +1 -1
  37. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  38. package/dist/esm/types/datasets.d.ts +2 -2
  39. package/dist/esm/types/datasets.d.ts.map +1 -1
  40. package/dist/esm/types/experiments.d.ts +1 -1
  41. package/dist/esm/types/experiments.d.ts.map +1 -1
  42. package/dist/src/client.d.ts +3 -3
  43. package/dist/src/client.d.ts.map +1 -1
  44. package/dist/src/client.js +14 -1
  45. package/dist/src/client.js.map +1 -1
  46. package/dist/src/datasets/appendDatasetExamples.js +1 -1
  47. package/dist/src/datasets/appendDatasetExamples.js.map +1 -1
  48. package/dist/src/datasets/createDataset.js +2 -2
  49. package/dist/src/datasets/createDataset.js.map +1 -1
  50. package/dist/src/experiments/runExperiment.d.ts +4 -3
  51. package/dist/src/experiments/runExperiment.d.ts.map +1 -1
  52. package/dist/src/experiments/runExperiment.js +14 -7
  53. package/dist/src/experiments/runExperiment.js.map +1 -1
  54. package/dist/src/prompts/sdks/toAI.d.ts +13 -3
  55. package/dist/src/prompts/sdks/toAI.d.ts.map +1 -1
  56. package/dist/src/prompts/sdks/toAI.js +24 -16
  57. package/dist/src/prompts/sdks/toAI.js.map +1 -1
  58. package/dist/src/prompts/sdks/toSDK.d.ts +1 -1
  59. package/dist/src/schemas/llm/constants.d.ts +30 -12
  60. package/dist/src/schemas/llm/constants.d.ts.map +1 -1
  61. package/dist/src/schemas/llm/converters.d.ts +120 -48
  62. package/dist/src/schemas/llm/converters.d.ts.map +1 -1
  63. package/dist/src/schemas/llm/openai/converters.d.ts +6 -3
  64. package/dist/src/schemas/llm/openai/converters.d.ts.map +1 -1
  65. package/dist/src/schemas/llm/openai/converters.js +7 -4
  66. package/dist/src/schemas/llm/openai/converters.js.map +1 -1
  67. package/dist/src/schemas/llm/schemas.d.ts +37 -16
  68. package/dist/src/schemas/llm/schemas.d.ts.map +1 -1
  69. package/dist/src/schemas/llm/vercel/messagePartSchemas.d.ts +42 -12
  70. package/dist/src/schemas/llm/vercel/messagePartSchemas.d.ts.map +1 -1
  71. package/dist/src/schemas/llm/vercel/messagePartSchemas.js +5 -2
  72. package/dist/src/schemas/llm/vercel/messagePartSchemas.js.map +1 -1
  73. package/dist/src/schemas/llm/vercel/messageSchemas.d.ts +31 -10
  74. package/dist/src/schemas/llm/vercel/messageSchemas.d.ts.map +1 -1
  75. package/dist/src/schemas/llm/vercel/toolSchemas.d.ts +3 -3
  76. package/dist/src/schemas/llm/vercel/toolSchemas.js +1 -1
  77. package/dist/src/schemas/llm/vercel/toolSchemas.js.map +1 -1
  78. package/dist/src/types/datasets.d.ts +2 -2
  79. package/dist/src/types/datasets.d.ts.map +1 -1
  80. package/dist/src/types/experiments.d.ts +1 -1
  81. package/dist/src/types/experiments.d.ts.map +1 -1
  82. package/dist/tsconfig.tsbuildinfo +1 -1
  83. package/package.json +4 -4
  84. package/src/client.ts +21 -2
  85. package/src/datasets/appendDatasetExamples.ts +1 -1
  86. package/src/datasets/createDataset.ts +2 -2
  87. package/src/experiments/runExperiment.ts +37 -12
  88. package/src/prompts/sdks/toAI.ts +42 -32
  89. package/src/schemas/llm/openai/converters.ts +7 -4
  90. package/src/schemas/llm/vercel/messagePartSchemas.ts +5 -2
  91. package/src/schemas/llm/vercel/toolSchemas.ts +1 -1
  92. package/src/types/datasets.ts +2 -2
  93. 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": "3.2.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",
@@ -53,11 +53,11 @@
53
53
  "author": "oss@arize.com",
54
54
  "license": "ELv2",
55
55
  "devDependencies": {
56
- "@ai-sdk/openai": "^1.1.15",
56
+ "@ai-sdk/openai": "^2.0.27",
57
57
  "@anthropic-ai/sdk": "^0.35.0",
58
58
  "@types/async": "^3.2.24",
59
59
  "@types/node": "^20.17.22",
60
- "ai": "^4.1.24",
60
+ "ai": "^5.0.38",
61
61
  "openai": "^4.77.0",
62
62
  "openapi-typescript": "^7.6.1",
63
63
  "tsx": "^4.19.3",
@@ -84,7 +84,7 @@
84
84
  },
85
85
  "optionalDependencies": {
86
86
  "@anthropic-ai/sdk": "^0.35.0",
87
- "ai": "^4.1.47",
87
+ "ai": "^5.0.38",
88
88
  "openai": "^5.12.1"
89
89
  },
90
90
  "scripts": {
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(
@@ -2,22 +2,23 @@ import invariant from "tiny-invariant";
2
2
  import {
3
3
  safelyConvertMessageToProvider,
4
4
  safelyConvertToolChoiceToProvider,
5
- safelyConvertToolDefinitionToProvider,
6
5
  } from "../../schemas/llm/converters";
7
6
  import { formatPromptMessages } from "../../utils/formatPromptMessages";
8
7
  import { Variables, toSDKParamsBase } from "./types";
9
- import {
10
- type streamText,
11
- type generateText,
12
- type ToolSet,
13
- type Tool,
14
- } from "ai";
8
+ import { type ToolSet, type ModelMessage, type ToolChoice } from "ai";
15
9
  import { VercelAIToolChoice } from "../../schemas/llm/vercel/toolChoiceSchemas";
16
10
 
17
- export type PartialStreamTextParams = Omit<
18
- Parameters<typeof streamText>[0] | Parameters<typeof generateText>[0],
19
- "model"
20
- >;
11
+ export type PartialAIParams = {
12
+ messages: ModelMessage[];
13
+ /**
14
+ The tools that the model can call. The model needs to support calling tools.
15
+ */
16
+ tools?: ToolSet;
17
+ /**
18
+ The tool choice strategy. Default: 'auto'.
19
+ */
20
+ toolChoice?: ToolChoice<ToolSet>;
21
+ };
21
22
 
22
23
  export type ToAIParams<V extends Variables> = toSDKParamsBase<V>;
23
24
 
@@ -30,16 +31,16 @@ export type ToAIParams<V extends Variables> = toSDKParamsBase<V>;
30
31
  export const toAI = <V extends Variables>({
31
32
  prompt,
32
33
  variables,
33
- }: ToAIParams<V>): PartialStreamTextParams | null => {
34
+ }: ToAIParams<V>): PartialAIParams | null => {
34
35
  // eslint-disable-next-line no-console
35
36
  console.warn(
36
37
  "Prompt invocation parameters not currently supported in AI SDK, falling back to default invocation parameters"
37
38
  );
38
39
  try {
39
40
  // parts of the prompt that can be directly converted to OpenAI params
40
- const baseCompletionParams = {
41
+ const baseCompletionParams: Partial<PartialAIParams> = {
41
42
  // Invocation parameters are validated on the phoenix-side
42
- } satisfies Partial<PartialStreamTextParams>;
43
+ };
43
44
 
44
45
  if (!("messages" in prompt.template)) {
45
46
  return null;
@@ -55,7 +56,7 @@ export const toAI = <V extends Variables>({
55
56
  );
56
57
  }
57
58
 
58
- const messages = formattedMessages.map((message) => {
59
+ const messages: ModelMessage[] = formattedMessages.map((message) => {
59
60
  const vercelAIMessage = safelyConvertMessageToProvider({
60
61
  message,
61
62
  targetProvider: "VERCEL_AI",
@@ -65,21 +66,30 @@ export const toAI = <V extends Variables>({
65
66
  });
66
67
 
67
68
  // convert tools to Vercel AI tool set, which is a map of tool name to tool
68
- let tools: ToolSet | undefined = prompt.tools?.tools.reduce((acc, tool) => {
69
- if (!tool.function.parameters) {
70
- return acc;
71
- }
72
- const vercelAIToolDefinition = safelyConvertToolDefinitionToProvider({
73
- toolDefinition: tool,
74
- targetProvider: "VERCEL_AI",
75
- });
76
- invariant(vercelAIToolDefinition, "Tool definition is not valid");
77
- acc[tool.function.name] = vercelAIToolDefinition satisfies Tool;
78
- return acc;
79
- }, {} as ToolSet);
80
- const hasTools = Object.keys(tools ?? {}).length > 0;
81
- tools = hasTools ? tools : undefined;
82
-
69
+ // TODO: Vercel AI SDK 5 has complex tool schema
70
+ // let tools: ToolSet | undefined = prompt.tools?.tools.reduce((acc, tool) => {
71
+ // if (!tool.function.parameters) {
72
+ // return acc;
73
+ // }
74
+ // const vercelAIToolDefinition = safelyConvertToolDefinitionToProvider({
75
+ // toolDefinition: tool,
76
+ // targetProvider: "VERCEL_AI",
77
+ // });
78
+ // invariant(vercelAIToolDefinition, "Tool definition is not valid");
79
+ // // TODO: get the symbol working here for validators
80
+ // acc[tool.function.name] = vercelAIToolDefinition as unknown as Tool;
81
+ // return acc;
82
+ // }, {} as ToolSet);
83
+ // const hasTools = Object.keys(tools ?? {}).length > 0;
84
+ // tools = hasTools ? tools : undefined;
85
+ const hasTools = false;
86
+ const tools = undefined;
87
+ if (prompt.tools?.tools && prompt.tools?.tools.length) {
88
+ // eslint-disable-next-line no-console
89
+ console.warn(
90
+ "Prompt tools not currently supported in the AI SDK, falling back to no tools"
91
+ );
92
+ }
83
93
  let toolChoice: VercelAIToolChoice | undefined =
84
94
  safelyConvertToolChoiceToProvider({
85
95
  toolChoice: prompt.tools?.tool_choice,
@@ -88,12 +98,12 @@ export const toAI = <V extends Variables>({
88
98
  toolChoice = hasTools ? toolChoice : undefined;
89
99
 
90
100
  // combine base and computed params
91
- const completionParams = {
101
+ const completionParams: PartialAIParams = {
92
102
  ...baseCompletionParams,
93
103
  messages,
94
104
  tools,
95
105
  toolChoice,
96
- } satisfies Partial<PartialStreamTextParams>;
106
+ };
97
107
 
98
108
  return completionParams;
99
109
  } catch (error) {
@@ -272,7 +272,7 @@ export const openAIMessageToVercelAI = openAIMessageSchema.transform(
272
272
  type: "tool-call",
273
273
  toolCallId: tc.id,
274
274
  toolName: tc.function.name,
275
- args: tc.function.arguments,
275
+ input: tc.function.arguments,
276
276
  });
277
277
  });
278
278
  }
@@ -289,7 +289,7 @@ export const openAIMessageToVercelAI = openAIMessageSchema.transform(
289
289
  type: "tool-result",
290
290
  toolCallId: openai.tool_call_id,
291
291
  toolName: "", // We don't have this??
292
- result: openai.content,
292
+ output: { type: "text", value: openai.content },
293
293
  });
294
294
  } else {
295
295
  openai.content.forEach((part) => {
@@ -298,7 +298,10 @@ export const openAIMessageToVercelAI = openAIMessageSchema.transform(
298
298
  type: "tool-result",
299
299
  toolCallId: openai.tool_call_id,
300
300
  toolName: "", // We don't have this??
301
- result: part.text,
301
+ output: {
302
+ type: "text",
303
+ value: part.text,
304
+ },
302
305
  });
303
306
  return;
304
307
  }
@@ -391,7 +394,7 @@ export const openAIToolDefinitionToVercelAI =
391
394
  (openai): VercelAIToolDefinition => ({
392
395
  type: "function",
393
396
  description: openai.function.description,
394
- parameters: {
397
+ inputSchema: {
395
398
  _type: undefined,
396
399
  jsonSchema: openai.function.parameters,
397
400
  validate: undefined,
@@ -26,7 +26,7 @@ export const vercelAIChatPartToolCallSchema = z.object({
26
26
  type: z.literal("tool-call"),
27
27
  toolCallId: z.string(),
28
28
  toolName: z.string(),
29
- args: jsonLiteralSchema, // json serializable parameters
29
+ input: jsonLiteralSchema, // json serializable parameters
30
30
  });
31
31
 
32
32
  export type VercelAIChatPartToolCall = z.infer<
@@ -37,7 +37,10 @@ export const vercelAIChatPartToolResultSchema = z.object({
37
37
  type: z.literal("tool-result"),
38
38
  toolCallId: z.string(),
39
39
  toolName: z.string(),
40
- result: jsonLiteralSchema, // json serializable result
40
+ output: z.object({
41
+ type: z.literal("text"), // TODO: extend to support other output types
42
+ value: z.string(),
43
+ }),
41
44
  });
42
45
 
43
46
  export type VercelAIChatPartToolResult = z.infer<
@@ -9,7 +9,7 @@ import { z } from "zod";
9
9
  export const vercelAIToolDefinitionSchema = z.object({
10
10
  type: z.literal("function"),
11
11
  description: z.string().optional(),
12
- parameters: z.object({
12
+ inputSchema: z.object({
13
13
  _type: z.unknown().optional().default(undefined),
14
14
  validate: z.unknown().optional().default(undefined),
15
15
  jsonSchema: z.record(z.string(), z.unknown()).optional(),
@@ -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 = {