@arizeai/phoenix-client 7.9.0 → 7.11.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +21 -11
  3. package/dist/esm/__generated__/api/v1.d.ts +14 -0
  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 +9 -0
  8. package/dist/esm/constants/serverRequirements.js.map +1 -1
  9. package/dist/esm/prompts/createPrompt.d.ts +5 -0
  10. package/dist/esm/prompts/createPrompt.d.ts.map +1 -1
  11. package/dist/esm/prompts/createPrompt.js +27 -121
  12. package/dist/esm/prompts/createPrompt.js.map +1 -1
  13. package/dist/esm/schemas/llm/converters.d.ts +4 -4
  14. package/dist/esm/traces/getTraces.d.ts +29 -1
  15. package/dist/esm/traces/getTraces.d.ts.map +1 -1
  16. package/dist/esm/traces/getTraces.js +78 -30
  17. package/dist/esm/traces/getTraces.js.map +1 -1
  18. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  19. package/dist/esm/utils/getPromptBySelector.d.ts +3 -0
  20. package/dist/esm/utils/getPromptBySelector.d.ts.map +1 -1
  21. package/dist/src/__generated__/api/v1.d.ts +14 -0
  22. package/dist/src/__generated__/api/v1.d.ts.map +1 -1
  23. package/dist/src/constants/serverRequirements.d.ts +1 -0
  24. package/dist/src/constants/serverRequirements.d.ts.map +1 -1
  25. package/dist/src/constants/serverRequirements.js +10 -1
  26. package/dist/src/constants/serverRequirements.js.map +1 -1
  27. package/dist/src/prompts/createPrompt.d.ts +5 -0
  28. package/dist/src/prompts/createPrompt.d.ts.map +1 -1
  29. package/dist/src/prompts/createPrompt.js +20 -121
  30. package/dist/src/prompts/createPrompt.js.map +1 -1
  31. package/dist/src/schemas/llm/converters.d.ts +4 -4
  32. package/dist/src/traces/getTraces.d.ts +29 -1
  33. package/dist/src/traces/getTraces.d.ts.map +1 -1
  34. package/dist/src/traces/getTraces.js +92 -32
  35. package/dist/src/traces/getTraces.js.map +1 -1
  36. package/dist/src/utils/getPromptBySelector.d.ts +3 -0
  37. package/dist/src/utils/getPromptBySelector.d.ts.map +1 -1
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/docs/traces.mdx +14 -1
  40. package/package.json +11 -11
  41. package/src/__generated__/api/v1.ts +14 -0
  42. package/src/constants/serverRequirements.ts +11 -0
  43. package/src/prompts/createPrompt.ts +35 -121
  44. package/src/traces/getTraces.ts +126 -47
package/docs/traces.mdx CHANGED
@@ -29,7 +29,7 @@ The traces module provides trace retrieval, project transfer, and trace-level an
29
29
 
30
30
  ## Retrieve Traces
31
31
 
32
- Use `getTraces` when you want trace-centric pagination by project, optional inline spans, or filtering by session.
32
+ Use `getTraces` when you want trace-centric pagination by project, optional inline spans, or filtering by session, error status, or latency.
33
33
 
34
34
  ```ts
35
35
  import { getTraces } from "@arizeai/phoenix-client/traces";
@@ -60,6 +60,18 @@ console.log(result.nextCursor);
60
60
  - `cursor`
61
61
  - `includeSpans`
62
62
  - `sessionId`
63
+ - `error`
64
+ - `minLatencyMs`
65
+ - `maxLatencyMs`
66
+
67
+ ```ts
68
+ // Slow traces that contain at least one errored span
69
+ const slowFailures = await getTraces({
70
+ project: { projectName: "support-bot" },
71
+ error: true,
72
+ minLatencyMs: 1000,
73
+ });
74
+ ```
63
75
 
64
76
  ### Notes
65
77
 
@@ -67,6 +79,7 @@ console.log(result.nextCursor);
67
79
  - Use the returned `nextCursor` to continue pagination
68
80
  - Set `includeSpans` when you need a trace-centric fetch that also contains span details
69
81
  - `project` accepts `{ project }`, `{ projectId }`, or `{ projectName }`
82
+ - `error`, `minLatencyMs`, and `maxLatencyMs` require Phoenix server >= 20.8.0; `error: false` selects traces with no errored spans
70
83
 
71
84
  ## Move Traces To Another Project
72
85
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arizeai/phoenix-client",
3
- "version": "7.9.0",
3
+ "version": "7.11.0",
4
4
  "description": "A client for the Phoenix API",
5
5
  "keywords": [
6
6
  "arize",
@@ -103,30 +103,30 @@
103
103
  }
104
104
  },
105
105
  "dependencies": {
106
- "@arizeai/openinference-semantic-conventions": "^2.7.0",
106
+ "@arizeai/openinference-semantic-conventions": "^2.9.0",
107
107
  "@arizeai/phoenix-config": "0.5.0",
108
108
  "@arizeai/phoenix-otel": "2.2.0",
109
109
  "async": "^3.2.6",
110
110
  "openapi-fetch": "^0.17.0",
111
111
  "tiny-invariant": "^1.3.3",
112
- "zod": "^4.4.3"
112
+ "zod": "^4.5.4"
113
113
  },
114
114
  "devDependencies": {
115
- "@ai-sdk/openai": "^4.0.46",
116
- "@ai-sdk/otel": "^1.0.77",
115
+ "@ai-sdk/openai": "^4.0.60",
116
+ "@ai-sdk/otel": "^1.0.93",
117
117
  "@anthropic-ai/sdk": "^0.111.0",
118
- "@arizeai/phoenix-evals": "2.4.0",
118
+ "@arizeai/phoenix-evals": "2.5.0",
119
119
  "@arizeai/phoenix-testing": "0.0.0",
120
120
  "@opentelemetry/api": "^1.9.1",
121
- "@opentelemetry/sdk-trace-node": "^2.10.0",
121
+ "@opentelemetry/sdk-trace-node": "^2.11.0",
122
122
  "@types/async": "^3.2.25",
123
- "@types/node": "^26.2.0",
124
- "ai": "^7.0.77",
123
+ "@types/node": "^26.4.1",
124
+ "ai": "^7.0.93",
125
125
  "dotenv": "^17.4.2",
126
- "jest": "^30.4.2",
126
+ "jest": "^30.5.1",
127
127
  "openai": "^6.49.0",
128
128
  "openapi-typescript": "^7.13.0",
129
- "tsx": "^4.23.12",
129
+ "tsx": "^4.23.13",
130
130
  "vitest": "^5.0.0"
131
131
  },
132
132
  "peerDependencies": {
@@ -5296,6 +5296,13 @@ export interface components {
5296
5296
  PromptVersion: {
5297
5297
  /** Description */
5298
5298
  description?: string | null;
5299
+ /**
5300
+ * Metadata
5301
+ * @description Arbitrary JSON metadata for the prompt version.
5302
+ */
5303
+ metadata?: {
5304
+ [key: string]: unknown;
5305
+ };
5299
5306
  model_provider: components["schemas"]["ModelProvider"];
5300
5307
  /** Model Name */
5301
5308
  model_name: string;
@@ -5315,6 +5322,13 @@ export interface components {
5315
5322
  PromptVersionData: {
5316
5323
  /** Description */
5317
5324
  description?: string | null;
5325
+ /**
5326
+ * Metadata
5327
+ * @description Arbitrary JSON metadata for the prompt version.
5328
+ */
5329
+ metadata?: {
5330
+ [key: string]: unknown;
5331
+ };
5318
5332
  model_provider: components["schemas"]["ModelProvider"];
5319
5333
  /** Model Name */
5320
5334
  model_name: string;
@@ -98,6 +98,16 @@ export const LIST_PROJECT_TRACES: RouteRequirement = {
98
98
  minServerVersion: [13, 15, 0],
99
99
  };
100
100
 
101
+ export const GET_TRACES_FILTERS: ParameterRequirement = {
102
+ kind: "parameter",
103
+ parameterName: "error",
104
+ parameterLocation: "query",
105
+ route: "GET /v1/projects/{id}/traces",
106
+ minServerVersion: [20, 8, 0],
107
+ description:
108
+ "The 'error', 'min_latency_ms', and 'max_latency_ms' query parameters on GET /v1/projects/{id}/traces",
109
+ };
110
+
101
111
  export const TRANSFER_TRACES: RouteRequirement = {
102
112
  kind: "route",
103
113
  method: "POST",
@@ -234,6 +244,7 @@ export const ALL_REQUIREMENTS: readonly CapabilityRequirement[] = [
234
244
  GET_SPANS_FILTERS,
235
245
  GET_SPANS_BY_ATTRIBUTE,
236
246
  LIST_PROJECT_TRACES,
247
+ GET_TRACES_FILTERS,
237
248
  TRANSFER_TRACES,
238
249
  DATASET_UPLOAD_EXAMPLE_IDS,
239
250
  ADD_TRACE_NOTE_IDENTIFIER,
@@ -84,6 +84,11 @@ interface PromptVersionInputBase {
84
84
  * The description of the prompt version.
85
85
  */
86
86
  description?: string;
87
+ /**
88
+ * Optional metadata for the prompt version as a JSON object.
89
+ * @example { "agent": "support", "dependencies": ["retriever"] }
90
+ */
91
+ metadata?: PromptVersionData["metadata"];
87
92
  /**
88
93
  * The name of the model to use for the prompt version.
89
94
  */
@@ -165,142 +170,51 @@ export type PromptVersionInput =
165
170
  export function promptVersion(params: PromptVersionInput): PromptVersionData {
166
171
  const {
167
172
  description = "",
173
+ metadata,
168
174
  modelProvider: model_provider,
169
175
  modelName: model_name,
170
176
  template: templateMessages,
171
177
  templateFormat: template_format = "MUSTACHE",
172
- invocationParameters: invocation_parameters,
173
178
  } = params;
174
- switch (model_provider) {
179
+ return {
180
+ description,
181
+ ...(metadata ? { metadata } : {}),
182
+ model_provider,
183
+ model_name,
184
+ template_type: "CHAT",
185
+ template_format,
186
+ template: {
187
+ type: "chat",
188
+ messages: templateMessages,
189
+ },
190
+ invocation_parameters: toInvocationParameters(params),
191
+ };
192
+ }
193
+
194
+ function toInvocationParameters(
195
+ params: PromptVersionInput
196
+ ): PromptVersionData["invocation_parameters"] {
197
+ switch (params.modelProvider) {
175
198
  case "OPENAI":
176
- return {
177
- description,
178
- model_provider,
179
- model_name,
180
- template_type: "CHAT",
181
- template_format,
182
- template: {
183
- type: "chat",
184
- messages: templateMessages,
185
- },
186
- invocation_parameters: {
187
- type: "openai",
188
- openai: invocation_parameters ?? {},
189
- },
190
- };
199
+ return { type: "openai", openai: params.invocationParameters ?? {} };
191
200
  case "AZURE_OPENAI":
192
201
  return {
193
- description,
194
- model_provider,
195
- model_name,
196
- template_type: "CHAT",
197
- template_format,
198
- template: {
199
- type: "chat",
200
- messages: templateMessages,
201
- },
202
- invocation_parameters: {
203
- type: "azure_openai",
204
- azure_openai: invocation_parameters ?? {},
205
- },
202
+ type: "azure_openai",
203
+ azure_openai: params.invocationParameters ?? {},
206
204
  };
207
205
  case "ANTHROPIC":
208
- return {
209
- description,
210
- model_provider,
211
- model_name,
212
- template_type: "CHAT",
213
- template_format,
214
- template: {
215
- type: "chat",
216
- messages: templateMessages,
217
- },
218
- invocation_parameters: {
219
- type: "anthropic",
220
- anthropic: invocation_parameters,
221
- },
222
- };
206
+ return { type: "anthropic", anthropic: params.invocationParameters };
223
207
  case "GOOGLE":
224
- return {
225
- description,
226
- model_provider,
227
- model_name,
228
- template_type: "CHAT",
229
- template_format,
230
- template: {
231
- type: "chat",
232
- messages: templateMessages,
233
- },
234
- invocation_parameters: {
235
- type: "google",
236
- google: invocation_parameters ?? {},
237
- },
238
- };
208
+ return { type: "google", google: params.invocationParameters ?? {} };
239
209
  case "DEEPSEEK":
240
- return {
241
- description,
242
- model_provider,
243
- model_name,
244
- template_type: "CHAT",
245
- template_format,
246
- template: {
247
- type: "chat",
248
- messages: templateMessages,
249
- },
250
- invocation_parameters: {
251
- type: "deepseek",
252
- deepseek: invocation_parameters ?? {},
253
- },
254
- };
210
+ return { type: "deepseek", deepseek: params.invocationParameters ?? {} };
255
211
  case "XAI":
256
- return {
257
- description,
258
- model_provider,
259
- model_name,
260
- template_type: "CHAT",
261
- template_format,
262
- template: {
263
- type: "chat",
264
- messages: templateMessages,
265
- },
266
- invocation_parameters: {
267
- type: "xai",
268
- xai: invocation_parameters ?? {},
269
- },
270
- };
212
+ return { type: "xai", xai: params.invocationParameters ?? {} };
271
213
  case "OLLAMA":
272
- return {
273
- description,
274
- model_provider,
275
- model_name,
276
- template_type: "CHAT",
277
- template_format,
278
- template: {
279
- type: "chat",
280
- messages: templateMessages,
281
- },
282
- invocation_parameters: {
283
- type: "ollama",
284
- ollama: invocation_parameters ?? {},
285
- },
286
- };
214
+ return { type: "ollama", ollama: params.invocationParameters ?? {} };
287
215
  case "AWS":
288
- return {
289
- description,
290
- model_provider,
291
- model_name,
292
- template_type: "CHAT",
293
- template_format,
294
- template: {
295
- type: "chat",
296
- messages: templateMessages,
297
- },
298
- invocation_parameters: {
299
- type: "aws",
300
- aws: invocation_parameters ?? {},
301
- },
302
- };
216
+ return { type: "aws", aws: params.invocationParameters ?? {} };
303
217
  default:
304
- return assertUnreachable(model_provider);
218
+ return assertUnreachable(params);
305
219
  }
306
220
  }
@@ -1,6 +1,9 @@
1
1
  import type { operations } from "../__generated__/api/v1";
2
2
  import { createClient } from "../client";
3
- import { LIST_PROJECT_TRACES } from "../constants/serverRequirements";
3
+ import {
4
+ GET_TRACES_FILTERS,
5
+ LIST_PROJECT_TRACES,
6
+ } from "../constants/serverRequirements";
4
7
  import type { ClientFn } from "../types/core";
5
8
  import type { ProjectIdentifier } from "../types/projects";
6
9
  import { resolveProjectIdentifier } from "../types/projects";
@@ -28,6 +31,112 @@ export interface GetTracesParams extends ClientFn {
28
31
  includeSpans?: boolean;
29
32
  /** Filter traces by session identifier(s) (session_id strings or GlobalIDs) */
30
33
  sessionId?: string | string[] | null;
34
+ /**
35
+ * Filter by trace error status. `true` returns only traces containing at
36
+ * least one errored span, `false` only traces with no errored spans.
37
+ * Omit to leave traces unfiltered by error status.
38
+ *
39
+ * @requires Phoenix server >= 20.8.0
40
+ */
41
+ error?: boolean | null;
42
+ /**
43
+ * Inclusive lower bound on trace latency in milliseconds.
44
+ *
45
+ * @requires Phoenix server >= 20.8.0
46
+ */
47
+ minLatencyMs?: number | null;
48
+ /**
49
+ * Inclusive upper bound on trace latency in milliseconds.
50
+ *
51
+ * @requires Phoenix server >= 20.8.0
52
+ */
53
+ maxLatencyMs?: number | null;
54
+ }
55
+
56
+ /**
57
+ * Reject latency bounds the server would reject (negatives) or that can never
58
+ * match a trace (an inverted range), so callers get a clear error instead of a
59
+ * 422 or a silently empty page.
60
+ */
61
+ function validateLatencyBounds({
62
+ minLatencyMs,
63
+ maxLatencyMs,
64
+ }: Pick<GetTracesParams, "minLatencyMs" | "maxLatencyMs">): void {
65
+ if (minLatencyMs != null && minLatencyMs < 0) {
66
+ throw new Error(`minLatencyMs must be non-negative, got ${minLatencyMs}`);
67
+ }
68
+ if (maxLatencyMs != null && maxLatencyMs < 0) {
69
+ throw new Error(`maxLatencyMs must be non-negative, got ${maxLatencyMs}`);
70
+ }
71
+ if (
72
+ minLatencyMs != null &&
73
+ maxLatencyMs != null &&
74
+ minLatencyMs > maxLatencyMs
75
+ ) {
76
+ throw new Error(
77
+ `minLatencyMs (${minLatencyMs}) must not exceed maxLatencyMs (${maxLatencyMs})`
78
+ );
79
+ }
80
+ }
81
+
82
+ type ListProjectTracesQuery = NonNullable<
83
+ operations["listProjectTraces"]["parameters"]["query"]
84
+ >;
85
+
86
+ /**
87
+ * Translate the camelCase parameters into the endpoint's snake_case query,
88
+ * omitting anything the caller left unset so the server applies its defaults.
89
+ */
90
+ function buildQuery({
91
+ cursor,
92
+ limit = 100,
93
+ startTime,
94
+ endTime,
95
+ sort,
96
+ order,
97
+ includeSpans,
98
+ sessionId,
99
+ error,
100
+ minLatencyMs,
101
+ maxLatencyMs,
102
+ }: Omit<GetTracesParams, "client" | "project">): ListProjectTracesQuery {
103
+ const query: ListProjectTracesQuery = { limit };
104
+ if (cursor) {
105
+ query.cursor = cursor;
106
+ }
107
+ if (startTime) {
108
+ query.start_time =
109
+ startTime instanceof Date ? startTime.toISOString() : startTime;
110
+ }
111
+ if (endTime) {
112
+ query.end_time = endTime instanceof Date ? endTime.toISOString() : endTime;
113
+ }
114
+ if (sort) {
115
+ query.sort = sort;
116
+ }
117
+ if (order) {
118
+ query.order = order;
119
+ }
120
+ if (includeSpans) {
121
+ query.include_spans = true;
122
+ }
123
+ if (sessionId) {
124
+ query.session_identifier = Array.isArray(sessionId)
125
+ ? sessionId
126
+ : [sessionId];
127
+ }
128
+ // `error: false` is a meaningful filter (traces with no errored spans), so
129
+ // send the parameter whenever it was set rather than only when truthy.
130
+ if (error != null) {
131
+ query.error = error;
132
+ }
133
+ if (minLatencyMs != null) {
134
+ query.min_latency_ms = minLatencyMs;
135
+ }
136
+ if (maxLatencyMs != null) {
137
+ query.max_latency_ms = maxLatencyMs;
138
+ }
139
+ return query;
31
140
  }
32
141
 
33
142
  export type GetTracesResponse =
@@ -81,60 +190,30 @@ export type GetTracesResult = {
81
190
  * });
82
191
  * cursor = result.nextCursor || undefined;
83
192
  * } while (cursor);
193
+ *
194
+ * // Only slow traces that errored
195
+ * const slowFailures = await getTraces({
196
+ * client,
197
+ * project: { projectName: "my-project" },
198
+ * error: true,
199
+ * minLatencyMs: 1000,
200
+ * });
84
201
  * ```
85
202
  */
86
203
  export async function getTraces({
87
204
  client: _client,
88
205
  project,
89
- cursor,
90
- limit = 100,
91
- startTime,
92
- endTime,
93
- sort,
94
- order,
95
- includeSpans,
96
- sessionId,
206
+ ...params
97
207
  }: GetTracesParams): Promise<GetTracesResult> {
208
+ const { error: errorFilter, minLatencyMs, maxLatencyMs } = params;
98
209
  const client = _client ?? createClient();
210
+ validateLatencyBounds({ minLatencyMs, maxLatencyMs });
99
211
  await ensureServerCapability({ client, requirement: LIST_PROJECT_TRACES });
100
- const projectIdentifier = resolveProjectIdentifier(project);
101
-
102
- const params: NonNullable<
103
- operations["listProjectTraces"]["parameters"]["query"]
104
- > = {
105
- limit,
106
- };
107
-
108
- if (cursor) {
109
- params.cursor = cursor;
110
- }
111
-
112
- if (startTime) {
113
- params.start_time =
114
- startTime instanceof Date ? startTime.toISOString() : startTime;
115
- }
116
-
117
- if (endTime) {
118
- params.end_time = endTime instanceof Date ? endTime.toISOString() : endTime;
119
- }
120
-
121
- if (sort) {
122
- params.sort = sort;
123
- }
124
-
125
- if (order) {
126
- params.order = order;
127
- }
128
-
129
- if (includeSpans) {
130
- params.include_spans = true;
131
- }
132
-
133
- if (sessionId) {
134
- params.session_identifier = Array.isArray(sessionId)
135
- ? sessionId
136
- : [sessionId];
212
+ if (errorFilter != null || minLatencyMs != null || maxLatencyMs != null) {
213
+ await ensureServerCapability({ client, requirement: GET_TRACES_FILTERS });
137
214
  }
215
+ const projectIdentifier = resolveProjectIdentifier(project);
216
+ const query = buildQuery(params);
138
217
 
139
218
  const { data, error } = await client.GET(
140
219
  "/v1/projects/{project_identifier}/traces",
@@ -143,7 +222,7 @@ export async function getTraces({
143
222
  path: {
144
223
  project_identifier: projectIdentifier,
145
224
  },
146
- query: params,
225
+ query,
147
226
  },
148
227
  }
149
228
  );