@arizeai/phoenix-client 1.3.0 โ†’ 2.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 (156) hide show
  1. package/README.md +118 -0
  2. package/dist/esm/datasets/appendDatasetExamples.d.ts +21 -0
  3. package/dist/esm/datasets/appendDatasetExamples.d.ts.map +1 -0
  4. package/dist/esm/datasets/appendDatasetExamples.js +32 -0
  5. package/dist/esm/datasets/appendDatasetExamples.js.map +1 -0
  6. package/dist/esm/datasets/createDataset.d.ts +25 -0
  7. package/dist/esm/datasets/createDataset.d.ts.map +1 -0
  8. package/dist/esm/datasets/createDataset.js +34 -0
  9. package/dist/esm/datasets/createDataset.js.map +1 -0
  10. package/dist/esm/datasets/getDataset.d.ts +10 -0
  11. package/dist/esm/datasets/getDataset.d.ts.map +1 -0
  12. package/dist/esm/datasets/getDataset.js +18 -0
  13. package/dist/esm/datasets/getDataset.js.map +1 -0
  14. package/dist/esm/datasets/getDatasetExamples.d.ts +10 -0
  15. package/dist/esm/datasets/getDatasetExamples.d.ts.map +1 -0
  16. package/dist/esm/datasets/getDatasetExamples.js +25 -0
  17. package/dist/esm/datasets/getDatasetExamples.js.map +1 -0
  18. package/dist/esm/datasets/getDatasetInfo.d.ts +11 -0
  19. package/dist/esm/datasets/getDatasetInfo.d.ts.map +1 -0
  20. package/dist/esm/datasets/getDatasetInfo.js +25 -0
  21. package/dist/esm/datasets/getDatasetInfo.js.map +1 -0
  22. package/dist/esm/datasets/index.d.ts +7 -0
  23. package/dist/esm/datasets/index.d.ts.map +1 -0
  24. package/dist/esm/datasets/index.js +7 -0
  25. package/dist/esm/datasets/index.js.map +1 -0
  26. package/dist/esm/datasets/listDatasets.d.ts +23 -0
  27. package/dist/esm/datasets/listDatasets.d.ts.map +1 -0
  28. package/dist/esm/datasets/listDatasets.js +26 -0
  29. package/dist/esm/datasets/listDatasets.js.map +1 -0
  30. package/dist/esm/experiments/getExperiment.d.ts +14 -0
  31. package/dist/esm/experiments/getExperiment.d.ts.map +1 -0
  32. package/dist/esm/experiments/getExperiment.js +25 -0
  33. package/dist/esm/experiments/getExperiment.js.map +1 -0
  34. package/dist/esm/experiments/getExperimentInfo.d.ts +13 -0
  35. package/dist/esm/experiments/getExperimentInfo.d.ts.map +1 -0
  36. package/dist/esm/experiments/getExperimentInfo.js +24 -0
  37. package/dist/esm/experiments/getExperimentInfo.js.map +1 -0
  38. package/dist/esm/experiments/getExperimentRuns.d.ts +15 -0
  39. package/dist/esm/experiments/getExperimentRuns.d.ts.map +1 -0
  40. package/dist/esm/experiments/getExperimentRuns.js +33 -0
  41. package/dist/esm/experiments/getExperimentRuns.js.map +1 -0
  42. package/dist/esm/experiments/index.d.ts +3 -0
  43. package/dist/esm/experiments/index.d.ts.map +1 -1
  44. package/dist/esm/experiments/index.js +3 -0
  45. package/dist/esm/experiments/index.js.map +1 -1
  46. package/dist/esm/experiments/runExperiment.d.ts +6 -6
  47. package/dist/esm/experiments/runExperiment.d.ts.map +1 -1
  48. package/dist/esm/experiments/runExperiment.js +49 -12
  49. package/dist/esm/experiments/runExperiment.js.map +1 -1
  50. package/dist/esm/schemas/llm/anthropic/converters.d.ts +28 -28
  51. package/dist/esm/schemas/llm/anthropic/messagePartSchemas.d.ts +8 -8
  52. package/dist/esm/schemas/llm/anthropic/messageSchemas.d.ts +24 -24
  53. package/dist/esm/schemas/llm/anthropic/toolCallSchemas.d.ts +8 -8
  54. package/dist/esm/schemas/llm/constants.d.ts +6 -6
  55. package/dist/esm/schemas/llm/converters.d.ts +24 -24
  56. package/dist/esm/schemas/llm/openai/converters.d.ts +6 -6
  57. package/dist/esm/schemas/llm/schemas.d.ts +22 -22
  58. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  59. package/dist/esm/types/datasets.d.ts +33 -8
  60. package/dist/esm/types/datasets.d.ts.map +1 -1
  61. package/dist/esm/types/experiments.d.ts +17 -3
  62. package/dist/esm/types/experiments.d.ts.map +1 -1
  63. package/dist/esm/utils/urlUtils.d.ts +36 -0
  64. package/dist/esm/utils/urlUtils.d.ts.map +1 -0
  65. package/dist/esm/utils/urlUtils.js +40 -0
  66. package/dist/esm/utils/urlUtils.js.map +1 -0
  67. package/dist/src/datasets/appendDatasetExamples.d.ts +21 -0
  68. package/dist/src/datasets/appendDatasetExamples.d.ts.map +1 -0
  69. package/dist/src/datasets/appendDatasetExamples.js +50 -0
  70. package/dist/src/datasets/appendDatasetExamples.js.map +1 -0
  71. package/dist/src/datasets/createDataset.d.ts +25 -0
  72. package/dist/src/datasets/createDataset.d.ts.map +1 -0
  73. package/dist/src/datasets/createDataset.js +52 -0
  74. package/dist/src/datasets/createDataset.js.map +1 -0
  75. package/dist/src/datasets/getDataset.d.ts +10 -0
  76. package/dist/src/datasets/getDataset.d.ts.map +1 -0
  77. package/dist/src/datasets/getDataset.js +29 -0
  78. package/dist/src/datasets/getDataset.js.map +1 -0
  79. package/dist/src/datasets/getDatasetExamples.d.ts +10 -0
  80. package/dist/src/datasets/getDatasetExamples.d.ts.map +1 -0
  81. package/dist/src/datasets/getDatasetExamples.js +40 -0
  82. package/dist/src/datasets/getDatasetExamples.js.map +1 -0
  83. package/dist/src/datasets/getDatasetInfo.d.ts +11 -0
  84. package/dist/src/datasets/getDatasetInfo.d.ts.map +1 -0
  85. package/dist/src/datasets/getDatasetInfo.js +43 -0
  86. package/dist/src/datasets/getDatasetInfo.js.map +1 -0
  87. package/dist/src/datasets/index.d.ts +7 -0
  88. package/dist/src/datasets/index.d.ts.map +1 -0
  89. package/dist/src/datasets/index.js +23 -0
  90. package/dist/src/datasets/index.js.map +1 -0
  91. package/dist/src/datasets/listDatasets.d.ts +23 -0
  92. package/dist/src/datasets/listDatasets.d.ts.map +1 -0
  93. package/dist/src/datasets/listDatasets.js +40 -0
  94. package/dist/src/datasets/listDatasets.js.map +1 -0
  95. package/dist/src/experiments/getExperiment.d.ts +14 -0
  96. package/dist/src/experiments/getExperiment.d.ts.map +1 -0
  97. package/dist/src/experiments/getExperiment.js +36 -0
  98. package/dist/src/experiments/getExperiment.js.map +1 -0
  99. package/dist/src/experiments/getExperimentInfo.d.ts +13 -0
  100. package/dist/src/experiments/getExperimentInfo.d.ts.map +1 -0
  101. package/dist/src/experiments/getExperimentInfo.js +41 -0
  102. package/dist/src/experiments/getExperimentInfo.js.map +1 -0
  103. package/dist/src/experiments/getExperimentRuns.d.ts +15 -0
  104. package/dist/src/experiments/getExperimentRuns.d.ts.map +1 -0
  105. package/dist/src/experiments/getExperimentRuns.js +50 -0
  106. package/dist/src/experiments/getExperimentRuns.js.map +1 -0
  107. package/dist/src/experiments/index.d.ts +3 -0
  108. package/dist/src/experiments/index.d.ts.map +1 -1
  109. package/dist/src/experiments/index.js +3 -0
  110. package/dist/src/experiments/index.js.map +1 -1
  111. package/dist/src/experiments/runExperiment.d.ts +6 -6
  112. package/dist/src/experiments/runExperiment.d.ts.map +1 -1
  113. package/dist/src/experiments/runExperiment.js +49 -12
  114. package/dist/src/experiments/runExperiment.js.map +1 -1
  115. package/dist/src/schemas/llm/anthropic/converters.d.ts +28 -28
  116. package/dist/src/schemas/llm/anthropic/messagePartSchemas.d.ts +8 -8
  117. package/dist/src/schemas/llm/anthropic/messageSchemas.d.ts +24 -24
  118. package/dist/src/schemas/llm/anthropic/toolCallSchemas.d.ts +8 -8
  119. package/dist/src/schemas/llm/constants.d.ts +6 -6
  120. package/dist/src/schemas/llm/converters.d.ts +24 -24
  121. package/dist/src/schemas/llm/openai/converters.d.ts +6 -6
  122. package/dist/src/schemas/llm/schemas.d.ts +22 -22
  123. package/dist/src/types/datasets.d.ts +33 -8
  124. package/dist/src/types/datasets.d.ts.map +1 -1
  125. package/dist/src/types/experiments.d.ts +17 -3
  126. package/dist/src/types/experiments.d.ts.map +1 -1
  127. package/dist/src/utils/urlUtils.d.ts +36 -0
  128. package/dist/src/utils/urlUtils.d.ts.map +1 -0
  129. package/dist/src/utils/urlUtils.js +45 -0
  130. package/dist/src/utils/urlUtils.js.map +1 -0
  131. package/dist/tsconfig.tsbuildinfo +1 -1
  132. package/package.json +5 -1
  133. package/src/datasets/appendDatasetExamples.ts +55 -0
  134. package/src/datasets/createDataset.ts +60 -0
  135. package/src/datasets/getDataset.ts +27 -0
  136. package/src/datasets/getDatasetExamples.ts +34 -0
  137. package/src/datasets/getDatasetInfo.ts +34 -0
  138. package/src/datasets/index.ts +6 -0
  139. package/src/datasets/listDatasets.ts +37 -0
  140. package/src/experiments/getExperiment.ts +40 -0
  141. package/src/experiments/getExperimentInfo.ts +39 -0
  142. package/src/experiments/getExperimentRuns.ts +45 -0
  143. package/src/experiments/index.ts +3 -0
  144. package/src/experiments/runExperiment.ts +74 -25
  145. package/src/types/datasets.ts +35 -9
  146. package/src/types/experiments.ts +19 -3
  147. package/src/utils/urlUtils.ts +63 -0
  148. package/dist/esm/utils/getDatasetBySelector.d.ts +0 -25
  149. package/dist/esm/utils/getDatasetBySelector.d.ts.map +0 -1
  150. package/dist/esm/utils/getDatasetBySelector.js +0 -37
  151. package/dist/esm/utils/getDatasetBySelector.js.map +0 -1
  152. package/dist/src/utils/getDatasetBySelector.d.ts +0 -25
  153. package/dist/src/utils/getDatasetBySelector.d.ts.map +0 -1
  154. package/dist/src/utils/getDatasetBySelector.js +0 -47
  155. package/dist/src/utils/getDatasetBySelector.js.map +0 -1
  156. package/src/utils/getDatasetBySelector.ts +0 -55
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arizeai/phoenix-client",
3
- "version": "1.3.0",
3
+ "version": "2.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",
@@ -22,6 +22,10 @@
22
22
  "import": "./dist/esm/experiments/index.js",
23
23
  "require": "./dist/src/experiments/index.js"
24
24
  },
25
+ "./datasets": {
26
+ "import": "./dist/esm/datasets/index.js",
27
+ "require": "./dist/src/datasets/index.js"
28
+ },
25
29
  "./utils/*": {
26
30
  "import": "./dist/esm/utils/*.js",
27
31
  "require": "./dist/src/utils/*.js"
@@ -0,0 +1,55 @@
1
+ import { createClient } from "../client";
2
+ import { ClientFn } from "../types/core";
3
+ import { Example, DatasetSelector } from "../types/datasets";
4
+ import invariant from "tiny-invariant";
5
+
6
+ export type AppendDatasetExamplesParams = ClientFn & {
7
+ /**
8
+ * The dataset to append examples to
9
+ */
10
+ dataset: DatasetSelector;
11
+ /**
12
+ * The examples to append to the dataset
13
+ */
14
+ examples: Example[];
15
+ };
16
+
17
+ export type AppendDatasetExamplesResponse = {
18
+ datasetId: string;
19
+ // TODO: respond with the versionId
20
+ // versionId: string;
21
+ };
22
+
23
+ /**
24
+ * Append examples to an existing dataset
25
+ * @experimental this interface may change in the future
26
+ */
27
+ export async function appendDatasetExamples({
28
+ client: _client,
29
+ dataset,
30
+ examples,
31
+ }: AppendDatasetExamplesParams): Promise<AppendDatasetExamplesResponse> {
32
+ const client = _client || createClient();
33
+ const inputs = examples.map((example) => example.input);
34
+ const outputs = examples.map((example) => example.output ?? {}); // Treat null as an empty object
35
+ const metadata = examples.map((example) => example.metadata);
36
+ const appendResponse = await client.POST("/v1/datasets/upload", {
37
+ params: {
38
+ query: {
39
+ sync: true,
40
+ },
41
+ },
42
+ body: {
43
+ name: dataset.datasetId,
44
+ action: "append",
45
+ inputs,
46
+ outputs,
47
+ metadata,
48
+ },
49
+ });
50
+ invariant(appendResponse.data?.data, "Failed to append dataset examples");
51
+ const datasetId = appendResponse.data.data.dataset_id;
52
+ return {
53
+ datasetId,
54
+ };
55
+ }
@@ -0,0 +1,60 @@
1
+ import { createClient } from "../client";
2
+ import { ClientFn } from "../types/core";
3
+ import { Example } from "../types/datasets";
4
+ import invariant from "tiny-invariant";
5
+
6
+ export type CreateDatasetParams = ClientFn & {
7
+ /**
8
+ * The name of the dataset
9
+ */
10
+ name: string;
11
+ /**
12
+ * The description of the dataset
13
+ */
14
+ description: string;
15
+ /**
16
+ * The examples to create in the dataset
17
+ */
18
+ examples: Example[];
19
+ };
20
+
21
+ export type CreateDatasetResponse = {
22
+ datasetId: string;
23
+ };
24
+
25
+ /**
26
+ * Create a new dataset
27
+ * @experimental this interface may change in the future
28
+ */
29
+ export async function createDataset({
30
+ client: _client,
31
+ name,
32
+ description,
33
+ examples,
34
+ }: CreateDatasetParams): Promise<CreateDatasetResponse> {
35
+ const client = _client || createClient();
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);
39
+ const createDatasetResponse = await client.POST("/v1/datasets/upload", {
40
+ params: {
41
+ query: {
42
+ // TODO: parameterize this
43
+ sync: true,
44
+ },
45
+ },
46
+ body: {
47
+ name,
48
+ description,
49
+ action: "create",
50
+ inputs,
51
+ outputs,
52
+ metadata,
53
+ },
54
+ });
55
+ invariant(createDatasetResponse.data?.data, "Failed to create dataset");
56
+ const datasetId = createDatasetResponse.data.data.dataset_id;
57
+ return {
58
+ datasetId,
59
+ };
60
+ }
@@ -0,0 +1,27 @@
1
+ import { createClient } from "../client";
2
+ import { ClientFn } from "../types/core";
3
+ import { DatasetSelector, Dataset } from "../types/datasets";
4
+ import { getDatasetExamples } from "./getDatasetExamples";
5
+ import { getDatasetInfo } from "./getDatasetInfo";
6
+
7
+ export type GetDatasetParams = ClientFn & {
8
+ dataset: DatasetSelector;
9
+ };
10
+
11
+ /**
12
+ * Get dataset info and the examples from the latest version of the dataset
13
+ */
14
+ export async function getDataset({
15
+ client: _client,
16
+ dataset,
17
+ }: GetDatasetParams): Promise<Dataset> {
18
+ const client = _client || createClient();
19
+ const [datasetInfo, datasetExamples] = await Promise.all([
20
+ getDatasetInfo({ client, dataset }),
21
+ getDatasetExamples({ client, dataset }),
22
+ ]);
23
+ return {
24
+ ...datasetInfo,
25
+ ...datasetExamples,
26
+ };
27
+ }
@@ -0,0 +1,34 @@
1
+ import invariant from "tiny-invariant";
2
+ import { createClient } from "../client";
3
+ import { ClientFn } from "../types/core";
4
+ import { DatasetSelector, DatasetExamples } from "../types/datasets";
5
+
6
+ export type GetDatasetExamplesParams = ClientFn & {
7
+ dataset: DatasetSelector;
8
+ };
9
+
10
+ /**
11
+ * Get the latest examples from a dataset
12
+ */
13
+ export async function getDatasetExamples({
14
+ client: _client,
15
+ dataset,
16
+ }: GetDatasetExamplesParams): Promise<DatasetExamples> {
17
+ const client = _client || createClient();
18
+ const response = await client.GET("/v1/datasets/{id}/examples", {
19
+ params: {
20
+ path: {
21
+ id: dataset.datasetId,
22
+ },
23
+ },
24
+ });
25
+ invariant(response.data?.data, "Failed to get dataset examples");
26
+ const examplesData = response.data.data;
27
+ return {
28
+ versionId: examplesData.version_id,
29
+ examples: examplesData.examples.map((example) => ({
30
+ ...example,
31
+ updatedAt: new Date(example.updated_at),
32
+ })),
33
+ };
34
+ }
@@ -0,0 +1,34 @@
1
+ import invariant from "tiny-invariant";
2
+ import { createClient } from "../client";
3
+ import { ClientFn } from "../types/core";
4
+ import { DatasetSelector, DatasetInfo } from "../types/datasets";
5
+
6
+ export type GetDatasetInfoParams = ClientFn & {
7
+ dataset: DatasetSelector;
8
+ };
9
+
10
+ /**
11
+ * Get an overview of the information in a dataset
12
+ * Note: this does not include the examples contained in the dataset
13
+ */
14
+ export async function getDatasetInfo({
15
+ client: _client,
16
+ dataset,
17
+ }: GetDatasetInfoParams): Promise<DatasetInfo> {
18
+ const client = _client || createClient();
19
+ const datasetResponse = await client.GET("/v1/datasets/{id}", {
20
+ params: {
21
+ path: {
22
+ id: dataset.datasetId,
23
+ },
24
+ },
25
+ });
26
+ invariant(datasetResponse.data?.data, "Failed to get dataset info");
27
+ const datasetInfo = datasetResponse.data.data;
28
+ return {
29
+ id: datasetInfo.id,
30
+ name: datasetInfo.name,
31
+ description: datasetInfo.description || undefined,
32
+ metadata: datasetInfo.metadata,
33
+ };
34
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./createDataset";
2
+ export * from "./getDataset";
3
+ export * from "./getDatasetExamples";
4
+ export * from "./appendDatasetExamples";
5
+ export * from "./getDatasetExamples";
6
+ export * from "./getDatasetInfo";
@@ -0,0 +1,37 @@
1
+ import { createClient } from "../client";
2
+ import { DatasetInfo } from "../types/datasets";
3
+ import { ClientFn } from "../types/core";
4
+ import invariant from "tiny-invariant";
5
+
6
+ export type ListDatasetsParams = ClientFn;
7
+
8
+ type FullDatasetInfo = DatasetInfo & {
9
+ startDate: Date;
10
+ endDate: Date;
11
+ };
12
+
13
+ /**
14
+ * List the information about all datasets available to the client.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { listDatasets } from "@arizeai/phoenix-client/datasets";
19
+ *
20
+ * const datasets = await listDatasets({});
21
+ * console.log(datasets);
22
+ * ```
23
+ *
24
+ * @throws {Error} If the datasets cannot be listed or the response is invalid.
25
+ */
26
+ export async function listDatasets({
27
+ client: _client,
28
+ }: ListDatasetsParams): Promise<FullDatasetInfo[]> {
29
+ const client = _client || createClient();
30
+ const response = await client.GET("/v1/datasets");
31
+ invariant(response.data?.data, "Failed to list datasets");
32
+ return response.data.data.map((dataset) => ({
33
+ ...dataset,
34
+ startDate: new Date(dataset.created_at),
35
+ endDate: new Date(dataset.updated_at),
36
+ }));
37
+ }
@@ -0,0 +1,40 @@
1
+ import { createClient } from "../client";
2
+ import { ClientFn } from "../types/core";
3
+ import { ExperimentRunsMap, RanExperiment } from "../types/experiments";
4
+ import { getExperimentInfo } from "./getExperimentInfo";
5
+ import { getExperimentRuns } from "./getExperimentRuns";
6
+
7
+ export type GetExperimentResultParams = ClientFn & {
8
+ /**
9
+ * The experiment ID.
10
+ */
11
+ experimentId: string;
12
+ };
13
+
14
+ /**
15
+ * A function that gets the result of a experiment.
16
+ * Fetches the experiment data as well as the runs.
17
+ */
18
+ export async function getExperiment({
19
+ client: _client,
20
+ experimentId,
21
+ }: GetExperimentResultParams): Promise<RanExperiment> {
22
+ const client = _client || createClient();
23
+ const [experiment, experimentRuns] = await Promise.all([
24
+ getExperimentInfo({ client, experimentId }),
25
+ getExperimentRuns({ client, experimentId }),
26
+ ]);
27
+ const experimentRunsMap: ExperimentRunsMap = {
28
+ runs: experimentRuns.runs.reduce(
29
+ (acc, run) => {
30
+ acc[run.id] = run;
31
+ return acc;
32
+ },
33
+ {} as ExperimentRunsMap["runs"]
34
+ ),
35
+ };
36
+ return {
37
+ ...experiment,
38
+ ...experimentRunsMap,
39
+ };
40
+ }
@@ -0,0 +1,39 @@
1
+ import invariant from "tiny-invariant";
2
+ import { createClient } from "../client";
3
+ import { ClientFn } from "../types/core";
4
+ import { type ExperimentInfo } from "../types/experiments";
5
+
6
+ export type GetExperimentParams = ClientFn & {
7
+ /**
8
+ * The experiment ID
9
+ */
10
+ experimentId: string;
11
+ };
12
+
13
+ /**
14
+ * Returns an object containing the high-level info about an experiment
15
+ */
16
+ export async function getExperimentInfo({
17
+ client: _client,
18
+ experimentId: experiment_id,
19
+ }: GetExperimentParams): Promise<ExperimentInfo> {
20
+ const client = _client || createClient();
21
+ const { data: { data: experimentData } = {} } = await client.GET(
22
+ "/v1/experiments/{experiment_id}",
23
+ {
24
+ params: {
25
+ path: {
26
+ experiment_id,
27
+ },
28
+ },
29
+ }
30
+ );
31
+ invariant(experimentData, "Failed to get experiment");
32
+ return {
33
+ id: experimentData.id,
34
+ datasetId: experimentData.dataset_id,
35
+ datasetVersionId: experimentData.dataset_version_id,
36
+ projectName: experimentData.project_name || "", // This will never happen
37
+ metadata: experimentData.metadata,
38
+ };
39
+ }
@@ -0,0 +1,45 @@
1
+ import { createClient } from "../client";
2
+ import invariant from "tiny-invariant";
3
+ import { ClientFn } from "../types/core";
4
+ import { ExperimentRun } from "../types/experiments";
5
+
6
+ export type GetExperimentRunsParams = ClientFn & {
7
+ /**
8
+ * The experiment ID.
9
+ */
10
+ experimentId: string;
11
+ };
12
+
13
+ /**
14
+ * A function that gets the runs (e.g. the results) of a experiment
15
+ */
16
+ export async function getExperimentRuns({
17
+ client: _client,
18
+ experimentId,
19
+ }: GetExperimentRunsParams): Promise<{ runs: ExperimentRun[] }> {
20
+ const client = _client || createClient();
21
+ const getRunsPromise = client.GET("/v1/experiments/{experiment_id}/runs", {
22
+ params: {
23
+ path: {
24
+ experiment_id: experimentId,
25
+ },
26
+ },
27
+ });
28
+ const [experimentRunResponse] = await Promise.all([getRunsPromise]);
29
+ const { data: { data: experimentRunsData } = {} } = experimentRunResponse;
30
+ invariant(experimentRunsData, "Failed to retrieve experiment runs");
31
+ return {
32
+ runs: experimentRunsData.map((run) => {
33
+ return {
34
+ id: run.id,
35
+ traceId: run.trace_id || null,
36
+ experimentId: run.experiment_id,
37
+ datasetExampleId: run.dataset_example_id,
38
+ startTime: new Date(run.start_time),
39
+ endTime: new Date(run.end_time),
40
+ output: run.output as ExperimentRun["output"],
41
+ error: run.error || null,
42
+ };
43
+ }),
44
+ };
45
+ }
@@ -1 +1,4 @@
1
+ export * from "./getExperimentInfo";
2
+ export * from "./getExperiment";
3
+ export * from "./getExperimentRuns";
1
4
  export * from "./runExperiment";
@@ -2,17 +2,23 @@ import { queue } from "async";
2
2
  import invariant from "tiny-invariant";
3
3
  import { createClient, type PhoenixClient } from "../client";
4
4
  import { ClientFn } from "../types/core";
5
- import { Dataset, Example } from "../types/datasets";
5
+ import {
6
+ Dataset,
7
+ DatasetSelector,
8
+ Example,
9
+ ExampleWithId,
10
+ } from "../types/datasets";
6
11
  import type {
7
12
  Evaluator,
8
- Experiment,
13
+ ExperimentInfo,
9
14
  ExperimentEvaluationRun,
10
15
  ExperimentRun,
16
+ ExperimentRunID,
11
17
  ExperimentTask,
12
18
  RanExperiment,
13
19
  } from "../types/experiments";
14
20
  import { type Logger } from "../types/logger";
15
- import { getDatasetBySelector } from "../utils/getDatasetBySelector";
21
+ import { getDataset } from "../datasets/getDataset";
16
22
  import { pluralize } from "../utils/pluralize";
17
23
  import { promisifyResult } from "../utils/promisifyResult";
18
24
  import { AnnotatorKind } from "../types/annotations";
@@ -26,6 +32,11 @@ import {
26
32
  import { ensureString } from "../utils/ensureString";
27
33
  import type { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
28
34
  import { objectAsAttributes } from "../utils/objectAsAttributes";
35
+ import {
36
+ getDatasetUrl,
37
+ getDatasetExperimentsUrl,
38
+ getExperimentUrl,
39
+ } from "../utils/urlUtils";
29
40
 
30
41
  /**
31
42
  * Parameters for running an experiment.
@@ -44,12 +55,13 @@ export type RunExperimentParams = ClientFn & {
44
55
  experimentDescription?: string;
45
56
  /**
46
57
  * Experiment metadata
58
+ * E.x. modelName
47
59
  */
48
60
  experimentMetadata?: Record<string, unknown>;
49
61
  /**
50
62
  * The dataset to run the experiment on
51
63
  */
52
- dataset: Dataset | string | Example[];
64
+ dataset: DatasetSelector;
53
65
  /**
54
66
  * The task to run
55
67
  */
@@ -112,9 +124,9 @@ export type RunExperimentParams = ClientFn & {
112
124
  export async function runExperiment({
113
125
  experimentName,
114
126
  experimentDescription,
115
- experimentMetadata,
127
+ experimentMetadata = {},
116
128
  client: _client,
117
- dataset: _dataset,
129
+ dataset: DatasetSelector,
118
130
  task,
119
131
  evaluators,
120
132
  logger = console,
@@ -125,24 +137,25 @@ export async function runExperiment({
125
137
  let provider: NodeTracerProvider | undefined;
126
138
  const isDryRun = typeof dryRun === "number" || dryRun === true;
127
139
  const client = _client ?? createClient();
128
- const dataset = await getDatasetBySelector({ dataset: _dataset, client });
140
+ const dataset = await getDataset({ dataset: DatasetSelector, client });
129
141
  invariant(dataset, `Dataset not found`);
130
142
  invariant(dataset.examples.length > 0, `Dataset has no examples`);
131
143
  const nExamples =
132
144
  typeof dryRun === "number"
133
- ? Math.max(dryRun, dataset.examples.length)
145
+ ? Math.min(dryRun, dataset.examples.length)
134
146
  : dataset.examples.length;
135
147
 
136
148
  let projectName = `${dataset.name}-exp-${new Date().toISOString()}`;
137
149
  // initialize the tracer into scope
138
150
  let taskTracer: Tracer;
139
- let experiment: Experiment;
151
+ let experiment: ExperimentInfo;
140
152
  if (isDryRun) {
141
153
  experiment = {
142
154
  id: localId(),
143
155
  datasetId: dataset.id,
144
156
  datasetVersionId: dataset.versionId,
145
157
  projectName,
158
+ metadata: experimentMetadata,
146
159
  };
147
160
  taskTracer = createNoOpProvider().getTracer("no-op");
148
161
  } else {
@@ -165,9 +178,10 @@ export async function runExperiment({
165
178
  projectName = experimentResponse.project_name ?? projectName;
166
179
  experiment = {
167
180
  id: experimentResponse.id,
168
- datasetId: dataset.id,
169
- datasetVersionId: dataset.versionId,
181
+ datasetId: experimentResponse.dataset_id,
182
+ datasetVersionId: experimentResponse.dataset_version_id,
170
183
  projectName,
184
+ metadata: experimentResponse.metadata,
171
185
  };
172
186
  // Initialize the tracer, now that we have a project name
173
187
  const baseUrl = client.config.baseUrl;
@@ -188,17 +202,35 @@ export async function runExperiment({
188
202
  );
189
203
  }
190
204
 
205
+ if (!isDryRun && client.config.baseUrl) {
206
+ const datasetUrl = getDatasetUrl({
207
+ baseUrl: client.config.baseUrl,
208
+ datasetId: dataset.id,
209
+ });
210
+ const datasetExperimentsUrl = getDatasetExperimentsUrl({
211
+ baseUrl: client.config.baseUrl,
212
+ datasetId: dataset.id,
213
+ });
214
+ const experimentUrl = getExperimentUrl({
215
+ baseUrl: client.config.baseUrl,
216
+ datasetId: dataset.id,
217
+ experimentId: experiment.id,
218
+ });
219
+
220
+ logger.info(`๐Ÿ“Š View dataset: ${datasetUrl}`);
221
+ logger.info(`๐Ÿ“บ View dataset experiments: ${datasetExperimentsUrl}`);
222
+ logger.info(`๐Ÿ”— View this experiment: ${experimentUrl}`);
223
+ }
224
+
191
225
  logger.info(
192
- `๐Ÿงช Starting experiment "${experimentName}" on dataset "${dataset.id}" with task "${task.name}" and ${evaluators?.length ?? 0} ${pluralize(
226
+ `๐Ÿงช Starting experiment "${experimentName || `<unnamed>`}" on dataset "${dataset.id}" with task "${task.name}" and ${evaluators?.length ?? 0} ${pluralize(
193
227
  "evaluator",
194
228
  evaluators?.length ?? 0
195
229
  )} and ${concurrency} concurrent runs`
196
230
  );
197
231
 
198
- // Run task against all examples, for each repetition
199
- type ExperimentRunId = string;
200
- const runs: Record<ExperimentRunId, ExperimentRun> = {};
201
- await runTask({
232
+ const runs: Record<ExperimentRunID, ExperimentRun> = {};
233
+ await runTaskWithExamples({
202
234
  client,
203
235
  experimentId: experiment.id,
204
236
  task,
@@ -236,13 +268,22 @@ export async function runExperiment({
236
268
 
237
269
  logger.info(`โœ… Experiment ${experiment.id} completed`);
238
270
 
271
+ if (!isDryRun && client.config.baseUrl) {
272
+ const experimentUrl = getExperimentUrl({
273
+ baseUrl: client.config.baseUrl,
274
+ datasetId: dataset.id,
275
+ experimentId: experiment.id,
276
+ });
277
+ logger.info(`๐Ÿ” View results: ${experimentUrl}`);
278
+ }
279
+
239
280
  return ranExperiment;
240
281
  }
241
282
 
242
283
  /**
243
284
  * Run a task against n examples in a dataset.
244
285
  */
245
- function runTask({
286
+ function runTaskWithExamples({
246
287
  client,
247
288
  experimentId,
248
289
  task,
@@ -274,9 +315,9 @@ function runTask({
274
315
  nExamples: number;
275
316
  /** TraceProvider instance that will be used to create spans from task calls */
276
317
  tracer: Tracer;
277
- }) {
318
+ }): Promise<void> {
278
319
  logger.info(`๐Ÿ”ง Running task "${task.name}" on dataset "${dataset.id}"`);
279
- const run = async (example: Example) => {
320
+ const run = async (example: ExampleWithId) => {
280
321
  return tracer.startActiveSpan(`Task: ${task.name}`, async (span) => {
281
322
  logger.info(
282
323
  `๐Ÿ”ง Running task "${task.name}" on example "${example.id} of dataset "${dataset.id}"`
@@ -366,13 +407,12 @@ export async function evaluateExperiment({
366
407
  experiment,
367
408
  evaluators,
368
409
  client: _client,
369
- logger,
410
+ logger = console,
370
411
  concurrency = 5,
371
412
  dryRun = false,
372
413
  }: {
373
414
  /**
374
415
  * The experiment to evaluate
375
- * @todo also accept Experiment, and attempt to fetch the runs from the server
376
416
  **/
377
417
  experiment: RanExperiment;
378
418
  /** The evaluators to use */
@@ -380,9 +420,9 @@ export async function evaluateExperiment({
380
420
  /** The client to use */
381
421
  client?: PhoenixClient;
382
422
  /** The logger to use */
383
- logger: Logger;
423
+ logger?: Logger;
384
424
  /** The number of evaluators to run in parallel */
385
- concurrency: number;
425
+ concurrency?: number;
386
426
  /**
387
427
  * Whether to run the evaluation as a dry run
388
428
  * If a number is provided, the evaluation will be run for the first n runs
@@ -414,8 +454,8 @@ export async function evaluateExperiment({
414
454
  typeof dryRun === "number"
415
455
  ? Math.max(dryRun, Object.keys(experiment.runs).length)
416
456
  : Object.keys(experiment.runs).length;
417
- const dataset = await getDatasetBySelector({
418
- dataset: experiment.datasetId,
457
+ const dataset = await getDataset({
458
+ dataset: { datasetId: experiment.datasetId },
419
459
  client,
420
460
  });
421
461
  invariant(dataset, `Dataset "${experiment.datasetId}" not found`);
@@ -438,6 +478,15 @@ export async function evaluateExperiment({
438
478
  evaluators?.length ?? 0
439
479
  )}`
440
480
  );
481
+
482
+ if (!isDryRun && client.config.baseUrl) {
483
+ const experimentUrl = getExperimentUrl({
484
+ baseUrl: client.config.baseUrl,
485
+ datasetId: experiment.datasetId,
486
+ experimentId: experiment.id,
487
+ });
488
+ logger.info(`๐Ÿ”— View experiment evaluation: ${experimentUrl}`);
489
+ }
441
490
  type EvaluationId = string;
442
491
  const evaluationRuns: Record<EvaluationId, ExperimentEvaluationRun> = {};
443
492