@arizeai/phoenix-client 6.6.2 → 6.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arizeai/phoenix-client",
3
- "version": "6.6.2",
3
+ "version": "6.7.0",
4
4
  "description": "A client for the Phoenix API",
5
5
  "keywords": [
6
6
  "arize",
@@ -5149,6 +5149,8 @@ export interface operations {
5149
5149
  name?: string[] | null;
5150
5150
  /** @description Filter by status code(s). Values: OK, ERROR, UNSET */
5151
5151
  status_code?: string[] | null;
5152
+ /** @description Filter spans by `key:value`. Key is a dot-path (e.g. `user.id`, `metadata.tier`). Value is JSON-parsed: `k:12345` is int, `k:true` is bool, otherwise string (`k:user-42`). To match a numeric- or boolean-looking STRING, JSON-quote it: `user.id:"12345"` (URL-encoded `%2212345%22`). Split is on the first `:` only, so values may contain colons (`session.id:sess:abc:123`, ISO timestamps). Repeat the param to AND filters. List-valued attributes (e.g. `tag.tags`) cannot be matched here. Returns 422 on malformed input (missing colon, empty key/value, or list/dict/null value). */
5153
+ attribute?: string[] | null;
5152
5154
  };
5153
5155
  header?: never;
5154
5156
  path: {
@@ -5218,6 +5220,8 @@ export interface operations {
5218
5220
  span_kind?: string[] | null;
5219
5221
  /** @description Filter by status code(s). Values: OK, ERROR, UNSET */
5220
5222
  status_code?: string[] | null;
5223
+ /** @description Filter spans by `key:value`. Key is a dot-path (e.g. `user.id`, `metadata.tier`). Value is JSON-parsed: `k:12345` is int, `k:true` is bool, otherwise string (`k:user-42`). To match a numeric- or boolean-looking STRING, JSON-quote it: `user.id:"12345"` (URL-encoded `%2212345%22`). Split is on the first `:` only, so values may contain colons (`session.id:sess:abc:123`, ISO timestamps). Repeat the param to AND filters. List-valued attributes (e.g. `tag.tags`) cannot be matched here. Returns 422 on malformed input (missing colon, empty key/value, or list/dict/null value). */
5224
+ attribute?: string[] | null;
5221
5225
  };
5222
5226
  header?: never;
5223
5227
  path: {
@@ -76,6 +76,14 @@ export const LIST_PROJECT_TRACES: RouteRequirement = {
76
76
  minServerVersion: [13, 15, 0],
77
77
  };
78
78
 
79
+ export const GET_SPANS_BY_ATTRIBUTE: ParameterRequirement = {
80
+ kind: "parameter",
81
+ parameterName: "attribute",
82
+ parameterLocation: "query",
83
+ route: "GET /v1/projects/{id}/spans",
84
+ minServerVersion: [14, 9, 0],
85
+ };
86
+
79
87
  /**
80
88
  * Aggregate list of every known capability requirement.
81
89
  *
@@ -90,5 +98,6 @@ export const ALL_REQUIREMENTS: readonly CapabilityRequirement[] = [
90
98
  ANNOTATE_SESSIONS,
91
99
  GET_SPANS_TRACE_IDS,
92
100
  GET_SPANS_FILTERS,
101
+ GET_SPANS_BY_ATTRIBUTE,
93
102
  LIST_PROJECT_TRACES,
94
103
  ] as const;
@@ -1,6 +1,7 @@
1
1
  import type { operations } from "../__generated__/api/v1";
2
2
  import { createClient } from "../client";
3
3
  import {
4
+ GET_SPANS_BY_ATTRIBUTE,
4
5
  GET_SPANS_FILTERS,
5
6
  GET_SPANS_TRACE_IDS,
6
7
  } from "../constants/serverRequirements";
@@ -10,6 +11,38 @@ import { resolveProjectIdentifier } from "../types/projects";
10
11
  import type { SpanKindFilter, SpanStatusCode } from "../types/spans";
11
12
  import { ensureServerCapability } from "../utils/serverVersionUtils";
12
13
 
14
+ export type SpanAttributeValue = string | number | boolean;
15
+ export type SpanAttributes = Record<string, SpanAttributeValue>;
16
+
17
+ function serializeAttributeValue(value: SpanAttributeValue): string {
18
+ if (typeof value === "boolean") {
19
+ return JSON.stringify(value);
20
+ }
21
+ if (typeof value === "number") {
22
+ if (!Number.isFinite(value)) {
23
+ throw new RangeError(
24
+ `Non-finite attribute filter values are not supported: ${value}`
25
+ );
26
+ }
27
+ return String(value);
28
+ }
29
+ if (value === "") {
30
+ return JSON.stringify(value);
31
+ }
32
+ try {
33
+ const parsed = JSON.parse(value);
34
+ return typeof parsed === "string" ? value : JSON.stringify(value);
35
+ } catch {
36
+ return value;
37
+ }
38
+ }
39
+
40
+ function serializeAttributes(attributes: SpanAttributes): string[] {
41
+ return Object.entries(attributes).map(
42
+ ([key, value]) => `${key}:${serializeAttributeValue(value)}`
43
+ );
44
+ }
45
+
13
46
  /**
14
47
  * Parameters to get spans from a project using auto-generated types
15
48
  */
@@ -34,6 +67,12 @@ export interface GetSpansParams extends ClientFn {
34
67
  spanKind?: SpanKindFilter | SpanKindFilter[] | null;
35
68
  /** Filter by status code(s) (OK, ERROR, UNSET) */
36
69
  statusCode?: SpanStatusCode | SpanStatusCode[] | null;
70
+ /**
71
+ * Filter by attribute key/value pairs with AND semantics. The value's JS type
72
+ * selects how the stored attribute is matched: `{ "user.id": 12345 }` matches
73
+ * a stored integer, while `{ "user.id": "12345" }` matches a stored string.
74
+ */
75
+ attributes?: SpanAttributes | null;
37
76
  }
38
77
 
39
78
  export type GetSpansResponse = operations["getSpans"]["responses"]["200"];
@@ -57,6 +96,7 @@ export type GetSpansResult = {
57
96
  * @returns A paginated response containing spans and optional next cursor
58
97
  *
59
98
  * @requires Phoenix server >= 13.9.0 when filtering by `traceIds`
99
+ * @requires Phoenix server >= 14.9.0 when filtering by `attributes`
60
100
  *
61
101
  * @example
62
102
  * ```ts
@@ -116,14 +156,27 @@ export async function getSpans({
116
156
  name,
117
157
  spanKind,
118
158
  statusCode,
159
+ attributes,
119
160
  }: GetSpansParams): Promise<GetSpansResult> {
120
161
  const client = _client ?? createClient();
162
+ const serializedAttributes =
163
+ attributes != null ? serializeAttributes(attributes) : undefined;
164
+ const attributeFilters =
165
+ serializedAttributes != null && serializedAttributes.length > 0
166
+ ? serializedAttributes
167
+ : undefined;
121
168
  if (traceIds) {
122
169
  await ensureServerCapability({ client, requirement: GET_SPANS_TRACE_IDS });
123
170
  }
124
171
  if (name != null || spanKind != null || statusCode != null) {
125
172
  await ensureServerCapability({ client, requirement: GET_SPANS_FILTERS });
126
173
  }
174
+ if (attributeFilters != null) {
175
+ await ensureServerCapability({
176
+ client,
177
+ requirement: GET_SPANS_BY_ATTRIBUTE,
178
+ });
179
+ }
127
180
  const projectIdentifier = resolveProjectIdentifier(project);
128
181
 
129
182
  const params: NonNullable<operations["getSpans"]["parameters"]["query"]> = {
@@ -163,6 +216,10 @@ export async function getSpans({
163
216
  params.status_code = Array.isArray(statusCode) ? statusCode : [statusCode];
164
217
  }
165
218
 
219
+ if (attributeFilters != null) {
220
+ params.attribute = attributeFilters;
221
+ }
222
+
166
223
  const { data, error } = await client.GET(
167
224
  "/v1/projects/{project_identifier}/spans",
168
225
  {