@arizeai/phoenix-client 7.9.0 → 7.10.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.
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.10.0",
4
4
  "description": "A client for the Phoenix API",
5
5
  "keywords": [
6
6
  "arize",
@@ -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,
@@ -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
  );