@arizeai/phoenix-client 7.6.0 → 7.7.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 (143) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +27 -3
  3. package/dist/esm/__generated__/api/v1.d.ts +1 -1
  4. package/dist/esm/__generated__/api/v1.d.ts.map +1 -1
  5. package/dist/esm/constants/serverRequirements.d.ts +1 -0
  6. package/dist/esm/constants/serverRequirements.d.ts.map +1 -1
  7. package/dist/esm/constants/serverRequirements.js +7 -0
  8. package/dist/esm/constants/serverRequirements.js.map +1 -1
  9. package/dist/esm/experiments/resumeEvaluation.d.ts +0 -60
  10. package/dist/esm/experiments/resumeEvaluation.d.ts.map +1 -1
  11. package/dist/esm/experiments/resumeEvaluation.js +44 -37
  12. package/dist/esm/experiments/resumeEvaluation.js.map +1 -1
  13. package/dist/esm/experiments/resumeExperiment.d.ts +0 -52
  14. package/dist/esm/experiments/resumeExperiment.d.ts.map +1 -1
  15. package/dist/esm/experiments/resumeExperiment.js +42 -35
  16. package/dist/esm/experiments/resumeExperiment.js.map +1 -1
  17. package/dist/esm/experiments/runExperiment.d.ts.map +1 -1
  18. package/dist/esm/experiments/runExperiment.js +152 -123
  19. package/dist/esm/experiments/runExperiment.js.map +1 -1
  20. package/dist/esm/projects/index.d.ts +1 -0
  21. package/dist/esm/projects/index.d.ts.map +1 -1
  22. package/dist/esm/projects/index.js +1 -0
  23. package/dist/esm/projects/index.js.map +1 -1
  24. package/dist/esm/projects/setProjectRetentionPolicy.d.ts +49 -0
  25. package/dist/esm/projects/setProjectRetentionPolicy.d.ts.map +1 -0
  26. package/dist/esm/projects/setProjectRetentionPolicy.js +52 -0
  27. package/dist/esm/projects/setProjectRetentionPolicy.js.map +1 -0
  28. package/dist/esm/prompts/sdks/toOpenAI.d.ts.map +1 -1
  29. package/dist/esm/prompts/sdks/toOpenAI.js +49 -58
  30. package/dist/esm/prompts/sdks/toOpenAI.js.map +1 -1
  31. package/dist/esm/sessions/sessionUtils.d.ts.map +1 -1
  32. package/dist/esm/sessions/sessionUtils.js +3 -0
  33. package/dist/esm/sessions/sessionUtils.js.map +1 -1
  34. package/dist/esm/spans/getSpans.d.ts +0 -70
  35. package/dist/esm/spans/getSpans.d.ts.map +1 -1
  36. package/dist/esm/spans/getSpans.js +42 -93
  37. package/dist/esm/spans/getSpans.js.map +1 -1
  38. package/dist/esm/testing/phoenix-test-tracking.d.ts.map +1 -1
  39. package/dist/esm/testing/phoenix-test-tracking.js +109 -78
  40. package/dist/esm/testing/phoenix-test-tracking.js.map +1 -1
  41. package/dist/esm/traces/getTraces.d.ts +1 -1
  42. package/dist/esm/traces/getTraces.d.ts.map +1 -1
  43. package/dist/esm/traces/index.d.ts +1 -0
  44. package/dist/esm/traces/index.d.ts.map +1 -1
  45. package/dist/esm/traces/index.js +1 -0
  46. package/dist/esm/traces/index.js.map +1 -1
  47. package/dist/esm/traces/transferTraces.d.ts +56 -0
  48. package/dist/esm/traces/transferTraces.d.ts.map +1 -0
  49. package/dist/esm/traces/transferTraces.js +56 -0
  50. package/dist/esm/traces/transferTraces.js.map +1 -0
  51. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  52. package/dist/esm/types/sessions.d.ts +6 -0
  53. package/dist/esm/types/sessions.d.ts.map +1 -1
  54. package/dist/esm/users/getCurrentUser.d.ts +25 -0
  55. package/dist/esm/users/getCurrentUser.d.ts.map +1 -0
  56. package/dist/esm/users/getCurrentUser.js +30 -0
  57. package/dist/esm/users/getCurrentUser.js.map +1 -0
  58. package/dist/esm/users/index.d.ts +2 -0
  59. package/dist/esm/users/index.d.ts.map +1 -0
  60. package/dist/esm/users/index.js +2 -0
  61. package/dist/esm/users/index.js.map +1 -0
  62. package/dist/src/__generated__/api/v1.d.ts +1 -1
  63. package/dist/src/__generated__/api/v1.d.ts.map +1 -1
  64. package/dist/src/constants/serverRequirements.d.ts +1 -0
  65. package/dist/src/constants/serverRequirements.d.ts.map +1 -1
  66. package/dist/src/constants/serverRequirements.js +8 -1
  67. package/dist/src/constants/serverRequirements.js.map +1 -1
  68. package/dist/src/experiments/resumeEvaluation.d.ts +0 -60
  69. package/dist/src/experiments/resumeEvaluation.d.ts.map +1 -1
  70. package/dist/src/experiments/resumeEvaluation.js +44 -37
  71. package/dist/src/experiments/resumeEvaluation.js.map +1 -1
  72. package/dist/src/experiments/resumeExperiment.d.ts +0 -52
  73. package/dist/src/experiments/resumeExperiment.d.ts.map +1 -1
  74. package/dist/src/experiments/resumeExperiment.js +42 -35
  75. package/dist/src/experiments/resumeExperiment.js.map +1 -1
  76. package/dist/src/experiments/runExperiment.d.ts.map +1 -1
  77. package/dist/src/experiments/runExperiment.js +148 -116
  78. package/dist/src/experiments/runExperiment.js.map +1 -1
  79. package/dist/src/projects/index.d.ts +1 -0
  80. package/dist/src/projects/index.d.ts.map +1 -1
  81. package/dist/src/projects/index.js +1 -0
  82. package/dist/src/projects/index.js.map +1 -1
  83. package/dist/src/projects/setProjectRetentionPolicy.d.ts +49 -0
  84. package/dist/src/projects/setProjectRetentionPolicy.d.ts.map +1 -0
  85. package/dist/src/projects/setProjectRetentionPolicy.js +59 -0
  86. package/dist/src/projects/setProjectRetentionPolicy.js.map +1 -0
  87. package/dist/src/prompts/sdks/toOpenAI.d.ts.map +1 -1
  88. package/dist/src/prompts/sdks/toOpenAI.js +56 -63
  89. package/dist/src/prompts/sdks/toOpenAI.js.map +1 -1
  90. package/dist/src/sessions/sessionUtils.d.ts.map +1 -1
  91. package/dist/src/sessions/sessionUtils.js +3 -0
  92. package/dist/src/sessions/sessionUtils.js.map +1 -1
  93. package/dist/src/spans/getSpans.d.ts +0 -70
  94. package/dist/src/spans/getSpans.d.ts.map +1 -1
  95. package/dist/src/spans/getSpans.js +43 -94
  96. package/dist/src/spans/getSpans.js.map +1 -1
  97. package/dist/src/testing/phoenix-test-tracking.d.ts.map +1 -1
  98. package/dist/src/testing/phoenix-test-tracking.js +117 -84
  99. package/dist/src/testing/phoenix-test-tracking.js.map +1 -1
  100. package/dist/src/traces/getTraces.d.ts +1 -1
  101. package/dist/src/traces/getTraces.d.ts.map +1 -1
  102. package/dist/src/traces/index.d.ts +1 -0
  103. package/dist/src/traces/index.d.ts.map +1 -1
  104. package/dist/src/traces/index.js +1 -0
  105. package/dist/src/traces/index.js.map +1 -1
  106. package/dist/src/traces/transferTraces.d.ts +56 -0
  107. package/dist/src/traces/transferTraces.d.ts.map +1 -0
  108. package/dist/src/traces/transferTraces.js +59 -0
  109. package/dist/src/traces/transferTraces.js.map +1 -0
  110. package/dist/src/types/sessions.d.ts +6 -0
  111. package/dist/src/types/sessions.d.ts.map +1 -1
  112. package/dist/src/users/getCurrentUser.d.ts +25 -0
  113. package/dist/src/users/getCurrentUser.d.ts.map +1 -0
  114. package/dist/src/users/getCurrentUser.js +36 -0
  115. package/dist/src/users/getCurrentUser.js.map +1 -0
  116. package/dist/src/users/index.d.ts +2 -0
  117. package/dist/src/users/index.d.ts.map +1 -0
  118. package/dist/src/users/index.js +18 -0
  119. package/dist/src/users/index.js.map +1 -0
  120. package/dist/tsconfig.tsbuildinfo +1 -1
  121. package/docs/overview.mdx +8 -4
  122. package/docs/projects.mdx +71 -0
  123. package/docs/sessions.mdx +10 -1
  124. package/docs/traces.mdx +28 -2
  125. package/docs/users.mdx +44 -0
  126. package/package.json +6 -2
  127. package/src/__generated__/api/v1.ts +1 -1
  128. package/src/constants/serverRequirements.ts +8 -0
  129. package/src/experiments/resumeEvaluation.ts +78 -48
  130. package/src/experiments/resumeExperiment.ts +73 -46
  131. package/src/experiments/runExperiment.ts +235 -129
  132. package/src/projects/index.ts +1 -0
  133. package/src/projects/setProjectRetentionPolicy.ts +80 -0
  134. package/src/prompts/sdks/toOpenAI.ts +58 -61
  135. package/src/sessions/sessionUtils.ts +3 -0
  136. package/src/spans/getSpans.ts +84 -48
  137. package/src/testing/phoenix-test-tracking.ts +154 -90
  138. package/src/traces/getTraces.ts +1 -1
  139. package/src/traces/index.ts +1 -0
  140. package/src/traces/transferTraces.ts +89 -0
  141. package/src/types/sessions.ts +6 -0
  142. package/src/users/getCurrentUser.ts +39 -0
  143. package/src/users/index.ts +1 -0
@@ -139,6 +139,199 @@ export type RunExperimentParams = ClientFn & {
139
139
  diagLogLevel?: DiagLogLevel;
140
140
  };
141
141
 
142
+ type PreparedExperiment = {
143
+ experiment: ExperimentInfo;
144
+ projectName: string;
145
+ taskTracer: Tracer;
146
+ taskProvider?: NodeTracerProvider;
147
+ taskGlobalRegistration: GlobalTracerProviderRegistration | null;
148
+ };
149
+
150
+ function prepareDryRunExperiment({
151
+ dataset,
152
+ datasetSelector,
153
+ projectName,
154
+ experimentMetadata,
155
+ repetitions,
156
+ nExamples,
157
+ }: {
158
+ dataset: Dataset;
159
+ datasetSelector: DatasetSelector;
160
+ projectName: string;
161
+ experimentMetadata: Record<string, unknown>;
162
+ repetitions: number;
163
+ nExamples: number;
164
+ }): PreparedExperiment {
165
+ const now = new Date().toISOString();
166
+ return {
167
+ experiment: {
168
+ id: localId(),
169
+ datasetId: dataset.id,
170
+ datasetVersionId: dataset.versionId,
171
+ datasetSplits: datasetSelector.splits ?? [],
172
+ projectName,
173
+ metadata: experimentMetadata,
174
+ repetitions,
175
+ createdAt: now,
176
+ updatedAt: now,
177
+ exampleCount: nExamples,
178
+ successfulRunCount: 0,
179
+ failedRunCount: 0,
180
+ missingRunCount: nExamples * repetitions,
181
+ },
182
+ projectName,
183
+ taskTracer: createNoOpProvider().getTracer("no-op"),
184
+ taskGlobalRegistration: null,
185
+ };
186
+ }
187
+
188
+ async function prepareRecordedExperiment({
189
+ client,
190
+ dataset,
191
+ datasetSelector,
192
+ projectName: defaultProjectName,
193
+ experimentName,
194
+ experimentDescription,
195
+ experimentMetadata,
196
+ repetitions,
197
+ useBatchSpanProcessor,
198
+ diagLogLevel,
199
+ setGlobalTracerProvider,
200
+ }: {
201
+ client: PhoenixClient;
202
+ dataset: Dataset;
203
+ datasetSelector: DatasetSelector;
204
+ projectName: string;
205
+ experimentName: string | undefined;
206
+ experimentDescription: string | undefined;
207
+ experimentMetadata: Record<string, unknown>;
208
+ repetitions: number;
209
+ useBatchSpanProcessor: boolean;
210
+ diagLogLevel: DiagLogLevel | undefined;
211
+ setGlobalTracerProvider: boolean;
212
+ }): Promise<PreparedExperiment> {
213
+ const response = await client
214
+ .POST("/v1/datasets/{dataset_id}/experiments", {
215
+ params: { path: { dataset_id: dataset.id } },
216
+ body: {
217
+ name: experimentName,
218
+ description: experimentDescription,
219
+ metadata: experimentMetadata,
220
+ project_name: defaultProjectName,
221
+ repetitions,
222
+ ...(datasetSelector.splits ? { splits: datasetSelector.splits } : {}),
223
+ ...(dataset.versionId ? { version_id: dataset.versionId } : {}),
224
+ },
225
+ })
226
+ .then((result) => result.data?.data);
227
+ invariant(response, `Failed to create experiment`);
228
+ const projectName = response.project_name ?? defaultProjectName;
229
+ const experiment: ExperimentInfo = {
230
+ id: response.id,
231
+ datasetId: response.dataset_id,
232
+ datasetVersionId: response.dataset_version_id,
233
+ datasetSplits: datasetSelector.splits ?? [],
234
+ projectName,
235
+ repetitions: response.repetitions,
236
+ metadata: response.metadata || {},
237
+ createdAt: response.created_at,
238
+ updatedAt: response.updated_at,
239
+ exampleCount: response.example_count,
240
+ successfulRunCount: response.successful_run_count,
241
+ failedRunCount: response.failed_run_count,
242
+ missingRunCount: response.missing_run_count,
243
+ };
244
+ invariant(client.config.baseUrl, MISSING_BASE_URL_MESSAGE);
245
+ const taskProvider = register({
246
+ projectName,
247
+ url: getTraceExportUrl(client.config),
248
+ headers: client.config.headers
249
+ ? toObjectHeaders(client.config.headers)
250
+ : undefined,
251
+ batch: useBatchSpanProcessor,
252
+ diagLogLevel,
253
+ global: false,
254
+ });
255
+ return {
256
+ experiment,
257
+ projectName,
258
+ taskProvider,
259
+ taskGlobalRegistration: setGlobalTracerProvider
260
+ ? attachGlobalTracerProvider(taskProvider)
261
+ : null,
262
+ taskTracer: taskProvider.getTracer(projectName),
263
+ };
264
+ }
265
+
266
+ function buildExperimentLinks({
267
+ client,
268
+ datasetId,
269
+ experimentId,
270
+ isDryRun,
271
+ }: {
272
+ client: PhoenixClient;
273
+ datasetId: string;
274
+ experimentId: string;
275
+ isDryRun: boolean;
276
+ }): Array<{ label: string; url: string }> {
277
+ const baseUrl = client.config.baseUrl;
278
+ if (isDryRun || !baseUrl) return [];
279
+ return [
280
+ { label: "Dataset", url: getDatasetUrl({ baseUrl, datasetId }) },
281
+ {
282
+ label: "Experiments",
283
+ url: getDatasetExperimentsUrl({ baseUrl, datasetId }),
284
+ },
285
+ {
286
+ label: "Experiment",
287
+ url: getExperimentUrl({ baseUrl, datasetId, experimentId }),
288
+ },
289
+ ];
290
+ }
291
+
292
+ function logEvaluatorStart({
293
+ evaluators,
294
+ logger,
295
+ }: {
296
+ evaluators: ExperimentEvaluatorLike[] | undefined;
297
+ logger: Logger;
298
+ }): void {
299
+ if (!evaluators || evaluators.length === 0) return;
300
+ const names = getExperimentEvaluators(evaluators)
301
+ .map((evaluator) => evaluator.name)
302
+ .join(", ");
303
+ logger.info(`${PROGRESS_PREFIX.start}Evaluations (${names})`);
304
+ }
305
+
306
+ async function refreshRecordedExperiment({
307
+ isDryRun,
308
+ client,
309
+ experiment,
310
+ ranExperiment,
311
+ }: {
312
+ isDryRun: boolean;
313
+ client: PhoenixClient;
314
+ experiment: ExperimentInfo;
315
+ ranExperiment: RanExperiment;
316
+ }): Promise<void> {
317
+ if (isDryRun) return;
318
+ const updated = await getExperimentInfo({
319
+ client,
320
+ experimentId: experiment.id,
321
+ });
322
+ Object.assign(ranExperiment, updated);
323
+ }
324
+
325
+ function logEvaluationSummary({
326
+ logger,
327
+ evaluationRuns,
328
+ }: {
329
+ logger: Logger;
330
+ evaluationRuns: ExperimentEvaluationRun[] | undefined;
331
+ }): void {
332
+ if (evaluationRuns?.length) logEvalSummary(logger, evaluationRuns);
333
+ }
334
+
142
335
  /**
143
336
  * Runs an experiment using a given set of dataset of examples.
144
337
  *
@@ -208,90 +401,32 @@ export async function runExperiment({
208
401
  ? Math.min(dryRun, dataset.examples.length)
209
402
  : dataset.examples.length;
210
403
 
211
- let projectName = `${dataset.name}-exp-${new Date().toISOString()}`;
212
- // initialize the tracer into scope
213
- let taskTracer: Tracer;
214
- let experiment: ExperimentInfo;
215
- if (isDryRun) {
216
- const now = new Date().toISOString();
217
- const totalExamples = nExamples;
218
- experiment = {
219
- id: localId(),
220
- datasetId: dataset.id,
221
- datasetVersionId: dataset.versionId,
222
- // @todo: the dataset should return splits in response body
223
- datasetSplits: datasetSelector?.splits ?? [],
224
- projectName,
225
- metadata: experimentMetadata,
226
- repetitions,
227
- createdAt: now,
228
- updatedAt: now,
229
- exampleCount: totalExamples,
230
- successfulRunCount: 0,
231
- failedRunCount: 0,
232
- missingRunCount: totalExamples * repetitions,
233
- };
234
- taskTracer = createNoOpProvider().getTracer("no-op");
235
- } else {
236
- const experimentResponse = await client
237
- .POST("/v1/datasets/{dataset_id}/experiments", {
238
- params: {
239
- path: {
240
- dataset_id: dataset.id,
241
- },
242
- },
243
- body: {
244
- name: experimentName,
245
- description: experimentDescription,
246
- metadata: experimentMetadata,
247
- project_name: projectName,
248
- repetitions,
249
- // @todo: the dataset should return splits in response body
250
- ...(datasetSelector?.splits
251
- ? { splits: datasetSelector.splits }
252
- : {}),
253
- ...(dataset?.versionId ? { version_id: dataset.versionId } : {}),
254
- },
404
+ const defaultProjectName = `${dataset.name}-exp-${new Date().toISOString()}`;
405
+ const prepared = isDryRun
406
+ ? prepareDryRunExperiment({
407
+ dataset,
408
+ datasetSelector,
409
+ projectName: defaultProjectName,
410
+ experimentMetadata,
411
+ repetitions,
412
+ nExamples,
255
413
  })
256
- .then((res) => res.data?.data);
257
- invariant(experimentResponse, `Failed to create experiment`);
258
- projectName = experimentResponse.project_name ?? projectName;
259
- experiment = {
260
- id: experimentResponse.id,
261
- datasetId: experimentResponse.dataset_id,
262
- datasetVersionId: experimentResponse.dataset_version_id,
263
- // @todo: the dataset should return splits in response body
264
- datasetSplits: datasetSelector?.splits ?? [],
265
- projectName,
266
- repetitions: experimentResponse.repetitions,
267
- metadata: experimentResponse.metadata || {},
268
- createdAt: experimentResponse.created_at,
269
- updatedAt: experimentResponse.updated_at,
270
- exampleCount: experimentResponse.example_count,
271
- successfulRunCount: experimentResponse.successful_run_count,
272
- failedRunCount: experimentResponse.failed_run_count,
273
- missingRunCount: experimentResponse.missing_run_count,
274
- };
275
- // Initialize the tracer, now that we have a project name
276
- const baseUrl = client.config.baseUrl;
277
- invariant(baseUrl, MISSING_BASE_URL_MESSAGE);
278
-
279
- taskProvider = register({
280
- projectName,
281
- url: getTraceExportUrl(client.config),
282
- headers: client.config.headers
283
- ? toObjectHeaders(client.config.headers)
284
- : undefined,
285
- batch: useBatchSpanProcessor,
286
- diagLogLevel,
287
- global: false,
288
- });
289
- taskGlobalRegistration = setGlobalTracerProvider
290
- ? attachGlobalTracerProvider(taskProvider)
291
- : null;
292
-
293
- taskTracer = taskProvider.getTracer(projectName);
294
- }
414
+ : await prepareRecordedExperiment({
415
+ client,
416
+ dataset,
417
+ datasetSelector,
418
+ projectName: defaultProjectName,
419
+ experimentName,
420
+ experimentDescription,
421
+ experimentMetadata,
422
+ repetitions,
423
+ useBatchSpanProcessor,
424
+ diagLogLevel,
425
+ setGlobalTracerProvider,
426
+ });
427
+ const { experiment, taskTracer } = prepared;
428
+ taskProvider = prepared.taskProvider;
429
+ taskGlobalRegistration = prepared.taskGlobalRegistration;
295
430
  try {
296
431
  if (!record) {
297
432
  logger.info(
@@ -299,31 +434,12 @@ export async function runExperiment({
299
434
  );
300
435
  }
301
436
 
302
- const links: Array<{ label: string; url: string }> = [];
303
- if (!isDryRun && client.config.baseUrl) {
304
- links.push({
305
- label: "Dataset",
306
- url: getDatasetUrl({
307
- baseUrl: client.config.baseUrl,
308
- datasetId: dataset.id,
309
- }),
310
- });
311
- links.push({
312
- label: "Experiments",
313
- url: getDatasetExperimentsUrl({
314
- baseUrl: client.config.baseUrl,
315
- datasetId: dataset.id,
316
- }),
317
- });
318
- links.push({
319
- label: "Experiment",
320
- url: getExperimentUrl({
321
- baseUrl: client.config.baseUrl,
322
- datasetId: dataset.id,
323
- experimentId: experiment.id,
324
- }),
325
- });
326
- }
437
+ const links = buildExperimentLinks({
438
+ client,
439
+ datasetId: dataset.id,
440
+ experimentId: experiment.id,
441
+ isDryRun,
442
+ });
327
443
 
328
444
  const evCount = evaluators?.length ?? 0;
329
445
  logger.info(
@@ -367,12 +483,7 @@ export async function runExperiment({
367
483
  taskProvider = undefined;
368
484
  taskGlobalRegistration = null;
369
485
 
370
- if (evaluators && evaluators.length > 0) {
371
- const evNames = getExperimentEvaluators(evaluators)
372
- .map((evaluator) => evaluator.name)
373
- .join(", ");
374
- logger.info(`${PROGRESS_PREFIX.start}Evaluations (${evNames})`);
375
- }
486
+ logEvaluatorStart({ evaluators, logger });
376
487
 
377
488
  const { evaluationRuns } = await evaluateExperiment({
378
489
  experiment: ranExperiment,
@@ -387,15 +498,12 @@ export async function runExperiment({
387
498
  });
388
499
  ranExperiment.evaluationRuns = evaluationRuns;
389
500
 
390
- // Refresh experiment info from server to get updated counts (non-dry-run only)
391
- if (!isDryRun) {
392
- const updatedExperiment = await getExperimentInfo({
393
- client,
394
- experimentId: experiment.id,
395
- });
396
- // Update the experiment info with the latest from the server
397
- Object.assign(ranExperiment, updatedExperiment);
398
- }
501
+ await refreshRecordedExperiment({
502
+ isDryRun,
503
+ client,
504
+ experiment,
505
+ ranExperiment,
506
+ });
399
507
 
400
508
  logTaskSummary(logger, {
401
509
  nExamples,
@@ -404,12 +512,10 @@ export async function runExperiment({
404
512
  nErrors: taskErrors,
405
513
  });
406
514
 
407
- if (
408
- ranExperiment.evaluationRuns &&
409
- ranExperiment.evaluationRuns.length > 0
410
- ) {
411
- logEvalSummary(logger, ranExperiment.evaluationRuns);
412
- }
515
+ logEvaluationSummary({
516
+ logger,
517
+ evaluationRuns: ranExperiment.evaluationRuns,
518
+ });
413
519
 
414
520
  logLinks(logger, links);
415
521
 
@@ -1 +1,2 @@
1
1
  export * from "./getProjects";
2
+ export * from "./setProjectRetentionPolicy";
@@ -0,0 +1,80 @@
1
+ import invariant from "tiny-invariant";
2
+
3
+ import type { components } from "../__generated__/api/v1";
4
+ import { createClient } from "../client";
5
+ import type { ClientFn } from "../types/core";
6
+ import type { ProjectIdentifier } from "../types/projects";
7
+ import { resolveProjectIdentifier } from "../types/projects";
8
+
9
+ /**
10
+ * The retention-policy assignment returned for a project.
11
+ */
12
+ export type ProjectRetentionPolicyAssignment =
13
+ components["schemas"]["ProjectRetentionPolicyData"];
14
+
15
+ /**
16
+ * Parameters for assigning or resetting a project's retention policy.
17
+ */
18
+ export type SetProjectRetentionPolicyParams = ClientFn &
19
+ ProjectIdentifier & {
20
+ /**
21
+ * The GlobalID of an existing trace retention policy, or `null` to reset
22
+ * the project to the default policy.
23
+ */
24
+ policyId: string | null;
25
+ };
26
+
27
+ /**
28
+ * Assign an existing trace retention policy to a project, or reset the project
29
+ * to the default policy.
30
+ *
31
+ * This helper only changes the project's assignment. It does not create,
32
+ * retrieve, update, or delete retention policies.
33
+ *
34
+ * @param params - The project and policy assignment.
35
+ * @param params.project - A project name or GlobalID.
36
+ * @param params.projectId - A project GlobalID.
37
+ * @param params.projectName - A project name.
38
+ * @param params.policyId - An existing policy GlobalID, or `null` to reset.
39
+ * @param params.client - An optional Phoenix client instance.
40
+ * @returns The project's resulting retention-policy assignment.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { setProjectRetentionPolicy } from "@arizeai/phoenix-client/projects";
45
+ *
46
+ * await setProjectRetentionPolicy({
47
+ * projectName: "support-bot",
48
+ * policyId: "UHJvamVjdFRyYWNlUmV0ZW50aW9uUG9saWN5OjI=",
49
+ * });
50
+ *
51
+ * await setProjectRetentionPolicy({
52
+ * projectId: "UHJvamVjdDox",
53
+ * policyId: null,
54
+ * });
55
+ * ```
56
+ */
57
+ export async function setProjectRetentionPolicy(
58
+ params: SetProjectRetentionPolicyParams
59
+ ): Promise<ProjectRetentionPolicyAssignment> {
60
+ const client = params.client ?? createClient();
61
+ const projectIdentifier = resolveProjectIdentifier(params);
62
+
63
+ const { data, error } = await client.PATCH(
64
+ "/v1/projects/{project_identifier}/retention",
65
+ {
66
+ params: {
67
+ path: {
68
+ project_identifier: projectIdentifier,
69
+ },
70
+ },
71
+ body: {
72
+ policy_id: params.policyId,
73
+ },
74
+ }
75
+ );
76
+
77
+ if (error) throw error;
78
+ invariant(data?.data, "Failed to set project retention policy");
79
+ return data.data;
80
+ }
@@ -26,6 +26,61 @@ export type {
26
26
  export type ToOpenAIParams<PromptVariables extends Variables> =
27
27
  toSDKParamsBase<PromptVariables>;
28
28
 
29
+ type PhoenixPrompt = ToOpenAIParams<Variables>["prompt"];
30
+
31
+ function getInvocationParameters(
32
+ prompt: PhoenixPrompt
33
+ ): Partial<ChatCompletionCreateParams> {
34
+ const parameters = prompt.invocation_parameters;
35
+ switch (parameters.type) {
36
+ case "openai":
37
+ return parameters.openai;
38
+ case "azure_openai":
39
+ return parameters.azure_openai;
40
+ case "deepseek":
41
+ return parameters.deepseek;
42
+ case "xai":
43
+ return parameters.xai;
44
+ case "ollama":
45
+ return parameters.ollama;
46
+ case "cerebras":
47
+ return parameters.cerebras;
48
+ case "fireworks":
49
+ return parameters.fireworks;
50
+ case "groq":
51
+ return parameters.groq;
52
+ case "moonshot":
53
+ return parameters.moonshot;
54
+ case "perplexity":
55
+ return parameters.perplexity;
56
+ case "together":
57
+ return parameters.together;
58
+ default:
59
+ // eslint-disable-next-line no-console
60
+ console.warn(
61
+ "Prompt is not an OpenAI-family prompt, falling back to default OpenAI invocation parameters"
62
+ );
63
+ return {};
64
+ }
65
+ }
66
+
67
+ function getOpenAITools(
68
+ prompt: PhoenixPrompt
69
+ ): ChatCompletionCreateParams["tools"] {
70
+ const toolsList = prompt.tools?.tools ?? [];
71
+ if (toolsList.length === 0) return undefined;
72
+
73
+ return toolsList.map((tool) => {
74
+ if (isPromptToolRaw(tool)) return tool.raw;
75
+ const definition = safelyConvertToolDefinitionToProvider({
76
+ toolDefinition: tool,
77
+ targetProvider: "OPENAI",
78
+ });
79
+ invariant(definition, "Tool definition is not valid");
80
+ return definition;
81
+ }) as unknown as ChatCompletionCreateParams["tools"];
82
+ }
83
+
29
84
  /**
30
85
  * Convert a Phoenix prompt to OpenAI client sdk's chat completion parameters
31
86
  *
@@ -36,49 +91,7 @@ export const toOpenAI = <PromptVariables extends Variables = Variables>({
36
91
  variables,
37
92
  }: ToOpenAIParams<PromptVariables>): ChatCompletionCreateParams | null => {
38
93
  try {
39
- let invocationParameters: Partial<ChatCompletionCreateParams>;
40
- switch (prompt.invocation_parameters.type) {
41
- case "openai":
42
- invocationParameters = prompt.invocation_parameters.openai;
43
- break;
44
- case "azure_openai":
45
- invocationParameters = prompt.invocation_parameters.azure_openai;
46
- break;
47
- case "deepseek":
48
- invocationParameters = prompt.invocation_parameters.deepseek;
49
- break;
50
- case "xai":
51
- invocationParameters = prompt.invocation_parameters.xai;
52
- break;
53
- case "ollama":
54
- invocationParameters = prompt.invocation_parameters.ollama;
55
- break;
56
- case "cerebras":
57
- invocationParameters = prompt.invocation_parameters.cerebras;
58
- break;
59
- case "fireworks":
60
- invocationParameters = prompt.invocation_parameters.fireworks;
61
- break;
62
- case "groq":
63
- invocationParameters = prompt.invocation_parameters.groq;
64
- break;
65
- case "moonshot":
66
- invocationParameters = prompt.invocation_parameters.moonshot;
67
- break;
68
- case "perplexity":
69
- invocationParameters = prompt.invocation_parameters.perplexity;
70
- break;
71
- case "together":
72
- invocationParameters = prompt.invocation_parameters.together;
73
- break;
74
- default:
75
- // eslint-disable-next-line no-console
76
- console.warn(
77
- "Prompt is not an OpenAI-family prompt, falling back to default OpenAI invocation parameters"
78
- );
79
- invocationParameters = {};
80
- break;
81
- }
94
+ const invocationParameters = getInvocationParameters(prompt);
82
95
  // parts of the prompt that can be directly converted to OpenAI params
83
96
  const baseCompletionParams = {
84
97
  model: prompt.model_name,
@@ -109,24 +122,8 @@ export const toOpenAI = <PromptVariables extends Variables = Variables>({
109
122
  return openAIMessage;
110
123
  });
111
124
 
112
- const toolsList = prompt.tools?.tools ?? [];
113
- // Cast: raw tools are `Record<string, unknown>` straight from the prompt
114
- // store. We trust the upstream caller to have stored a shape OpenAI's
115
- // SDK accepts; no validation here.
116
- const tools =
117
- toolsList.length === 0
118
- ? undefined
119
- : (toolsList.map((tool) => {
120
- if (isPromptToolRaw(tool)) {
121
- return tool.raw;
122
- }
123
- const openAIToolDefinition = safelyConvertToolDefinitionToProvider({
124
- toolDefinition: tool,
125
- targetProvider: "OPENAI",
126
- });
127
- invariant(openAIToolDefinition, "Tool definition is not valid");
128
- return openAIToolDefinition;
129
- }) as unknown as ChatCompletionCreateParams["tools"]);
125
+ // Raw tools are trusted to already match the OpenAI SDK shape.
126
+ const tools = getOpenAITools(prompt);
130
127
 
131
128
  const tool_choice: OpenaiToolChoice | undefined = tools
132
129
  ? (safelyConvertToolChoiceToProvider({
@@ -13,6 +13,9 @@ export function toSession(data: SessionData): Session {
13
13
  projectId: data.project_id,
14
14
  startTime: data.start_time,
15
15
  endTime: data.end_time,
16
+ tokenCountPrompt: data.token_count_prompt,
17
+ tokenCountCompletion: data.token_count_completion,
18
+ tokenCountTotal: data.token_count_total,
16
19
  traces: data.traces.map((trace) => ({
17
20
  id: trace.id,
18
21
  traceId: trace.trace_id,