@arizeai/phoenix-client 7.1.0 → 7.2.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 (73) hide show
  1. package/README.md +25 -0
  2. package/dist/esm/__generated__/api/v1.d.ts +315 -9
  3. package/dist/esm/__generated__/api/v1.d.ts.map +1 -1
  4. package/dist/esm/experiments/getExperiment.d.ts.map +1 -1
  5. package/dist/esm/experiments/getExperiment.js.map +1 -1
  6. package/dist/esm/projects/getProjects.d.ts +31 -0
  7. package/dist/esm/projects/getProjects.d.ts.map +1 -0
  8. package/dist/esm/projects/getProjects.js +45 -0
  9. package/dist/esm/projects/getProjects.js.map +1 -0
  10. package/dist/esm/projects/index.d.ts +2 -0
  11. package/dist/esm/projects/index.d.ts.map +1 -0
  12. package/dist/esm/projects/index.js +2 -0
  13. package/dist/esm/projects/index.js.map +1 -0
  14. package/dist/esm/prompts/createPrompt.js +1 -1
  15. package/dist/esm/prompts/createPrompt.js.map +1 -1
  16. package/dist/esm/prompts/sdks/toSDK.js +1 -1
  17. package/dist/esm/prompts/sdks/toSDK.js.map +1 -1
  18. package/dist/esm/schemas/llm/converters.js +5 -5
  19. package/dist/esm/schemas/llm/converters.js.map +1 -1
  20. package/dist/esm/schemas/llm/openai/converters.js +3 -3
  21. package/dist/esm/schemas/llm/openai/converters.js.map +1 -1
  22. package/dist/esm/schemas/llm/phoenixPrompt/converters.d.ts.map +1 -1
  23. package/dist/esm/schemas/llm/phoenixPrompt/converters.js +2 -0
  24. package/dist/esm/schemas/llm/phoenixPrompt/converters.js.map +1 -1
  25. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  26. package/dist/esm/types/projects.d.ts +5 -0
  27. package/dist/esm/types/projects.d.ts.map +1 -1
  28. package/dist/esm/types/projects.js.map +1 -1
  29. package/dist/esm/utils/serverVersionUtils.d.ts.map +1 -1
  30. package/dist/esm/utils/serverVersionUtils.js +3 -0
  31. package/dist/esm/utils/serverVersionUtils.js.map +1 -1
  32. package/dist/src/__generated__/api/v1.d.ts +315 -9
  33. package/dist/src/__generated__/api/v1.d.ts.map +1 -1
  34. package/dist/src/experiments/getExperiment.d.ts.map +1 -1
  35. package/dist/src/experiments/getExperiment.js.map +1 -1
  36. package/dist/src/projects/getProjects.d.ts +31 -0
  37. package/dist/src/projects/getProjects.d.ts.map +1 -0
  38. package/dist/src/projects/getProjects.js +53 -0
  39. package/dist/src/projects/getProjects.js.map +1 -0
  40. package/dist/src/projects/index.d.ts +2 -0
  41. package/dist/src/projects/index.d.ts.map +1 -0
  42. package/dist/src/projects/index.js +18 -0
  43. package/dist/src/projects/index.js.map +1 -0
  44. package/dist/src/prompts/createPrompt.js +1 -1
  45. package/dist/src/prompts/createPrompt.js.map +1 -1
  46. package/dist/src/prompts/sdks/toSDK.js +1 -1
  47. package/dist/src/prompts/sdks/toSDK.js.map +1 -1
  48. package/dist/src/schemas/llm/converters.js +5 -5
  49. package/dist/src/schemas/llm/converters.js.map +1 -1
  50. package/dist/src/schemas/llm/openai/converters.js +3 -3
  51. package/dist/src/schemas/llm/openai/converters.js.map +1 -1
  52. package/dist/src/schemas/llm/phoenixPrompt/converters.d.ts.map +1 -1
  53. package/dist/src/schemas/llm/phoenixPrompt/converters.js +2 -0
  54. package/dist/src/schemas/llm/phoenixPrompt/converters.js.map +1 -1
  55. package/dist/src/types/projects.d.ts +5 -0
  56. package/dist/src/types/projects.d.ts.map +1 -1
  57. package/dist/src/types/projects.js.map +1 -1
  58. package/dist/src/utils/serverVersionUtils.d.ts.map +1 -1
  59. package/dist/src/utils/serverVersionUtils.js +3 -0
  60. package/dist/src/utils/serverVersionUtils.js.map +1 -1
  61. package/dist/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +16 -12
  63. package/src/__generated__/api/v1.ts +315 -9
  64. package/src/experiments/getExperiment.ts +4 -7
  65. package/src/projects/getProjects.ts +69 -0
  66. package/src/projects/index.ts +1 -0
  67. package/src/prompts/createPrompt.ts +1 -1
  68. package/src/prompts/sdks/toSDK.ts +1 -1
  69. package/src/schemas/llm/converters.ts +5 -5
  70. package/src/schemas/llm/openai/converters.ts +3 -3
  71. package/src/schemas/llm/phoenixPrompt/converters.ts +2 -0
  72. package/src/types/projects.ts +7 -0
  73. package/src/utils/serverVersionUtils.ts +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arizeai/phoenix-client",
3
- "version": "7.1.0",
3
+ "version": "7.2.0",
4
4
  "description": "A client for the Phoenix API",
5
5
  "keywords": [
6
6
  "arize",
@@ -53,6 +53,10 @@
53
53
  "import": "./dist/esm/sessions/index.js",
54
54
  "require": "./dist/src/sessions/index.js"
55
55
  },
56
+ "./projects": {
57
+ "import": "./dist/esm/projects/index.js",
58
+ "require": "./dist/src/projects/index.js"
59
+ },
56
60
  "./traces": {
57
61
  "import": "./dist/esm/traces/index.js",
58
62
  "require": "./dist/src/traces/index.js"
@@ -95,31 +99,31 @@
95
99
  }
96
100
  },
97
101
  "dependencies": {
98
- "@arizeai/openinference-semantic-conventions": "^2.5.0",
102
+ "@arizeai/openinference-semantic-conventions": "^2.6.0",
99
103
  "async": "^3.2.6",
100
104
  "openapi-fetch": "^0.17.0",
101
105
  "tiny-invariant": "^1.3.3",
102
106
  "zod": "^4.4.3",
103
- "@arizeai/phoenix-config": "0.4.0",
104
- "@arizeai/phoenix-otel": "2.1.0"
107
+ "@arizeai/phoenix-otel": "2.1.0",
108
+ "@arizeai/phoenix-config": "0.4.0"
105
109
  },
106
110
  "devDependencies": {
107
- "@ai-sdk/openai": "^4.0.0",
108
- "@ai-sdk/otel": "^1.0.0",
111
+ "@ai-sdk/openai": "^4.0.27",
112
+ "@ai-sdk/otel": "^1.0.47",
109
113
  "@anthropic-ai/sdk": "^0.111.0",
110
114
  "@opentelemetry/api": "^1.9.1",
111
- "@opentelemetry/sdk-trace-node": "^2.9.0",
115
+ "@opentelemetry/sdk-trace-node": "^2.10.0",
112
116
  "@types/async": "^3.2.25",
113
- "@types/node": "^26.1.1",
114
- "ai": "^7.0.0",
117
+ "@types/node": "^26.1.2",
118
+ "ai": "^7.0.47",
115
119
  "dotenv": "^17.4.2",
116
120
  "jest": "^30.4.2",
117
- "openai": "^6.48.0",
121
+ "openai": "^6.49.0",
118
122
  "openapi-typescript": "^7.13.0",
119
123
  "tsx": "^4.23.1",
120
124
  "vitest": "^4.1.10",
121
- "@arizeai/phoenix-testing": "0.0.0",
122
- "@arizeai/phoenix-evals": "2.1.0"
125
+ "@arizeai/phoenix-evals": "2.2.0",
126
+ "@arizeai/phoenix-testing": "0.0.0"
123
127
  },
124
128
  "peerDependencies": {
125
129
  "@anthropic-ai/sdk": "^0.35.0",
@@ -1027,7 +1027,11 @@ export interface paths {
1027
1027
  delete: operations["deletePrompt"];
1028
1028
  options?: never;
1029
1029
  head?: never;
1030
- patch?: never;
1030
+ /**
1031
+ * Update prompt metadata
1032
+ * @description Update a prompt's description and metadata by identifier.
1033
+ */
1034
+ patch: operations["patchPrompt"];
1031
1035
  trace?: never;
1032
1036
  };
1033
1037
  "/v1/projects": {
@@ -1390,6 +1394,28 @@ export interface paths {
1390
1394
  patch?: never;
1391
1395
  trace?: never;
1392
1396
  };
1397
+ "/v1/chat/completions": {
1398
+ parameters: {
1399
+ query?: never;
1400
+ header?: never;
1401
+ path?: never;
1402
+ cookie?: never;
1403
+ };
1404
+ get?: never;
1405
+ put?: never;
1406
+ /**
1407
+ * OpenAI-compatible chat completions
1408
+ * @description Creates a chat completion using the OpenAI wire format, proxying to the selected provider with credentials resolved on the server (secret store first, environment second) — callers never handle provider API keys. Model must be '{provider}:{model_name}' for a built-in provider (one of anthropic, aws, azure_openai, cerebras, deepseek, fireworks, google, groq, moonshot, ollama, openai, perplexity, together, xai) or 'custom:{provider_id}:{model_name}' for a stored custom provider, e.g. 'openai:gpt-4o' or 'anthropic:claude-sonnet-4-5'. Set `stream: true` for server-sent events of `chat.completion.chunk` payloads terminated by `data: [DONE]`. Tool calling is not supported.
1409
+ *
1410
+ * **Phoenix is not an AI gateway.** The same server also takes on trace ingestion traffic, so routing production LLM calls through it competes with ingestion. Use this endpoint only to quickly try out different models in non-production environments.
1411
+ */
1412
+ post: operations["createChatCompletion"];
1413
+ delete?: never;
1414
+ options?: never;
1415
+ head?: never;
1416
+ patch?: never;
1417
+ trace?: never;
1418
+ };
1393
1419
  "/auth/login": {
1394
1420
  parameters: {
1395
1421
  query?: never;
@@ -1933,6 +1959,98 @@ export interface components {
1933
1959
  /** Score */
1934
1960
  score?: number | null;
1935
1961
  };
1962
+ /** ChatCompletion */
1963
+ ChatCompletion: {
1964
+ /** Id */
1965
+ id: string;
1966
+ /**
1967
+ * Object
1968
+ * @default chat.completion
1969
+ * @constant
1970
+ */
1971
+ object?: "chat.completion";
1972
+ /** Created */
1973
+ created: number;
1974
+ /** Model */
1975
+ model: string;
1976
+ /** Choices */
1977
+ choices: components["schemas"]["ChatCompletionChoice"][];
1978
+ usage: components["schemas"]["ChatCompletionUsage"];
1979
+ };
1980
+ /** ChatCompletionChoice */
1981
+ ChatCompletionChoice: {
1982
+ /**
1983
+ * Index
1984
+ * @default 0
1985
+ */
1986
+ index?: number;
1987
+ message: components["schemas"]["ChatCompletionMessage"];
1988
+ /** Finish Reason */
1989
+ finish_reason: string;
1990
+ };
1991
+ /** ChatCompletionErrorDetail */
1992
+ ChatCompletionErrorDetail: {
1993
+ /** Message */
1994
+ message: string;
1995
+ /** Type */
1996
+ type: string;
1997
+ /** Param */
1998
+ param?: string | null;
1999
+ /** Code */
2000
+ code?: string | null;
2001
+ };
2002
+ /** ChatCompletionErrorResponse */
2003
+ ChatCompletionErrorResponse: {
2004
+ error: components["schemas"]["ChatCompletionErrorDetail"];
2005
+ };
2006
+ /** ChatCompletionMessage */
2007
+ ChatCompletionMessage: {
2008
+ /**
2009
+ * Role
2010
+ * @default assistant
2011
+ * @constant
2012
+ */
2013
+ role?: "assistant";
2014
+ /** Content */
2015
+ content: string;
2016
+ };
2017
+ /** ChatCompletionRequestMessage */
2018
+ ChatCompletionRequestMessage: {
2019
+ /**
2020
+ * Role
2021
+ * @enum {string}
2022
+ */
2023
+ role: "system" | "developer" | "user" | "assistant";
2024
+ /** Content */
2025
+ content: string | components["schemas"]["ChatCompletionTextPart"][];
2026
+ };
2027
+ /** ChatCompletionStreamOptions */
2028
+ ChatCompletionStreamOptions: {
2029
+ /**
2030
+ * Include Usage
2031
+ * @default false
2032
+ */
2033
+ include_usage?: boolean;
2034
+ };
2035
+ /** ChatCompletionTextPart */
2036
+ ChatCompletionTextPart: {
2037
+ /**
2038
+ * Type
2039
+ * @constant
2040
+ */
2041
+ type: "text";
2042
+ /** Text */
2043
+ text: string;
2044
+ };
2045
+ /** ChatCompletionUsage */
2046
+ ChatCompletionUsage: {
2047
+ /** Prompt Tokens */
2048
+ prompt_tokens: number;
2049
+ /** Completion Tokens */
2050
+ completion_tokens: number;
2051
+ /** Total Tokens */
2052
+ total_tokens: number;
2053
+ };
1936
2054
  /**
1937
2055
  * ChatContext
1938
2056
  * @description Discriminated union of every UI-state context the agent understands.
@@ -2107,6 +2225,63 @@ export interface components {
2107
2225
  CreateApiKeyResponseBody: {
2108
2226
  data: components["schemas"]["CreatedApiKey"];
2109
2227
  };
2228
+ /**
2229
+ * CreateChatCompletionRequestBody
2230
+ * @example {
2231
+ * "messages": [
2232
+ * {
2233
+ * "content": "You are a helpful assistant.",
2234
+ * "role": "system"
2235
+ * },
2236
+ * {
2237
+ * "content": "Say hello.",
2238
+ * "role": "user"
2239
+ * }
2240
+ * ],
2241
+ * "model": "openai:gpt-4o"
2242
+ * }
2243
+ */
2244
+ CreateChatCompletionRequestBody: {
2245
+ /**
2246
+ * Model
2247
+ * @description Model must be '{provider}:{model_name}' for a built-in provider (one of anthropic, aws, azure_openai, cerebras, deepseek, fireworks, google, groq, moonshot, ollama, openai, perplexity, together, xai) or 'custom:{provider_id}:{model_name}' for a stored custom provider, e.g. 'openai:gpt-4o' or 'anthropic:claude-sonnet-4-5'.
2248
+ */
2249
+ model: string;
2250
+ /** Messages */
2251
+ messages: components["schemas"]["ChatCompletionRequestMessage"][];
2252
+ /**
2253
+ * Stream
2254
+ * @default false
2255
+ */
2256
+ stream?: boolean;
2257
+ /** Temperature */
2258
+ temperature?: number | null;
2259
+ /** Top P */
2260
+ top_p?: number | null;
2261
+ /** Max Tokens */
2262
+ max_tokens?: number | null;
2263
+ /** Max Completion Tokens */
2264
+ max_completion_tokens?: number | null;
2265
+ /** Stop */
2266
+ stop?: string | string[] | null;
2267
+ /** Frequency Penalty */
2268
+ frequency_penalty?: number | null;
2269
+ /** Presence Penalty */
2270
+ presence_penalty?: number | null;
2271
+ /** Seed */
2272
+ seed?: number | null;
2273
+ /** N */
2274
+ n?: number | null;
2275
+ stream_options?: components["schemas"]["ChatCompletionStreamOptions"] | null;
2276
+ /** Tools */
2277
+ tools?: unknown[] | null;
2278
+ /** Tool Choice */
2279
+ tool_choice?: unknown | null;
2280
+ /** Response Format */
2281
+ response_format?: {
2282
+ [key: string]: unknown;
2283
+ } | null;
2284
+ };
2110
2285
  /** CreateDatasetLabelRequestBody */
2111
2286
  CreateDatasetLabelRequestBody: {
2112
2287
  /**
@@ -3596,6 +3771,28 @@ export interface components {
3596
3771
  */
3597
3772
  message?: string | null;
3598
3773
  };
3774
+ /**
3775
+ * PatchPromptRequestBody
3776
+ * @description Fields to update on a prompt. Omit a field to leave it unchanged.
3777
+ */
3778
+ PatchPromptRequestBody: {
3779
+ /**
3780
+ * Description
3781
+ * @description New description for the prompt (null clears the description)
3782
+ */
3783
+ description?: string | null;
3784
+ /**
3785
+ * Metadata
3786
+ * @description New metadata object for the prompt (replaces the existing metadata as a whole)
3787
+ */
3788
+ metadata?: {
3789
+ [key: string]: unknown;
3790
+ };
3791
+ };
3792
+ /** PatchPromptResponseBody */
3793
+ PatchPromptResponseBody: {
3794
+ data: components["schemas"]["Prompt"];
3795
+ };
3599
3796
  /**
3600
3797
  * PhoenixUIMessage
3601
3798
  * @description `UIMessage` with `metadata` narrowed to the Phoenix wire shapes.
@@ -3756,12 +3953,9 @@ export interface components {
3756
3953
  *
3757
3954
  * ``span_filter`` carries the project-scoped span filter expression when the
3758
3955
  * span filter field is mounted — empty string when the field is mounted with
3759
- * no condition applied, ``None`` when the field is not present at all.
3760
- *
3761
- * ``root_spans_only`` carries the current state of the spans-table root vs.
3762
- * all toggle when that toggle is mounted — ``True`` when the table is
3763
- * restricted to root spans, ``False`` when it shows every span, ``None``
3764
- * when the toggle is not present (e.g. on the traces tab).
3956
+ * no condition applied, ``None`` when the field is not present at all. It
3957
+ * describes the view in full, root-span scoping included (which is expressed
3958
+ * within the filter DSL as ``parent_id is None``).
3765
3959
  */
3766
3960
  ProjectContext: {
3767
3961
  /**
@@ -3773,8 +3967,6 @@ export interface components {
3773
3967
  projectNodeId: string;
3774
3968
  /** Spanfilter */
3775
3969
  spanFilter?: string | null;
3776
- /** Rootspansonly */
3777
- rootSpansOnly?: boolean | null;
3778
3970
  };
3779
3971
  /** Prompt */
3780
3972
  Prompt: {
@@ -9480,6 +9672,60 @@ export interface operations {
9480
9672
  };
9481
9673
  };
9482
9674
  };
9675
+ patchPrompt: {
9676
+ parameters: {
9677
+ query?: never;
9678
+ header?: never;
9679
+ path: {
9680
+ /** @description The identifier of the prompt, i.e. name or ID. */
9681
+ prompt_identifier: string;
9682
+ };
9683
+ cookie?: never;
9684
+ };
9685
+ requestBody: {
9686
+ content: {
9687
+ "application/json": components["schemas"]["PatchPromptRequestBody"];
9688
+ };
9689
+ };
9690
+ responses: {
9691
+ /** @description The updated prompt */
9692
+ 200: {
9693
+ headers: {
9694
+ [name: string]: unknown;
9695
+ };
9696
+ content: {
9697
+ "application/json": components["schemas"]["PatchPromptResponseBody"];
9698
+ };
9699
+ };
9700
+ /** @description Forbidden */
9701
+ 403: {
9702
+ headers: {
9703
+ [name: string]: unknown;
9704
+ };
9705
+ content: {
9706
+ "text/plain": string;
9707
+ };
9708
+ };
9709
+ /** @description Not Found */
9710
+ 404: {
9711
+ headers: {
9712
+ [name: string]: unknown;
9713
+ };
9714
+ content: {
9715
+ "text/plain": string;
9716
+ };
9717
+ };
9718
+ /** @description Unprocessable Entity */
9719
+ 422: {
9720
+ headers: {
9721
+ [name: string]: unknown;
9722
+ };
9723
+ content: {
9724
+ "text/plain": string;
9725
+ };
9726
+ };
9727
+ };
9728
+ };
9483
9729
  getProjects: {
9484
9730
  parameters: {
9485
9731
  query?: {
@@ -10679,6 +10925,66 @@ export interface operations {
10679
10925
  };
10680
10926
  };
10681
10927
  };
10928
+ createChatCompletion: {
10929
+ parameters: {
10930
+ query?: never;
10931
+ header?: never;
10932
+ path?: never;
10933
+ cookie?: never;
10934
+ };
10935
+ requestBody: {
10936
+ content: {
10937
+ "application/json": components["schemas"]["CreateChatCompletionRequestBody"];
10938
+ };
10939
+ };
10940
+ responses: {
10941
+ /** @description Successful Response */
10942
+ 200: {
10943
+ headers: {
10944
+ [name: string]: unknown;
10945
+ };
10946
+ content: {
10947
+ "application/json": components["schemas"]["ChatCompletion"];
10948
+ };
10949
+ };
10950
+ /** @description Bad Request */
10951
+ 400: {
10952
+ headers: {
10953
+ [name: string]: unknown;
10954
+ };
10955
+ content: {
10956
+ "application/json": components["schemas"]["ChatCompletionErrorResponse"];
10957
+ };
10958
+ };
10959
+ /** @description Forbidden */
10960
+ 403: {
10961
+ headers: {
10962
+ [name: string]: unknown;
10963
+ };
10964
+ content: {
10965
+ "text/plain": string;
10966
+ };
10967
+ };
10968
+ /** @description Not Found */
10969
+ 404: {
10970
+ headers: {
10971
+ [name: string]: unknown;
10972
+ };
10973
+ content: {
10974
+ "application/json": components["schemas"]["ChatCompletionErrorResponse"];
10975
+ };
10976
+ };
10977
+ /** @description Unprocessable Entity */
10978
+ 422: {
10979
+ headers: {
10980
+ [name: string]: unknown;
10981
+ };
10982
+ content: {
10983
+ "application/json": components["schemas"]["ChatCompletionErrorResponse"];
10984
+ };
10985
+ };
10986
+ };
10987
+ };
10682
10988
  _login_auth_login_post: {
10683
10989
  parameters: {
10684
10990
  query?: never;
@@ -25,13 +25,10 @@ export async function getExperiment({
25
25
  getExperimentRuns({ client, experimentId }),
26
26
  ]);
27
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
- ),
28
+ runs: experimentRuns.runs.reduce<ExperimentRunsMap["runs"]>((acc, run) => {
29
+ acc[run.id] = run;
30
+ return acc;
31
+ }, {}),
35
32
  };
36
33
  return {
37
34
  ...experiment,
@@ -0,0 +1,69 @@
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 { Project } from "../types/projects";
7
+
8
+ export interface GetProjectsParams extends ClientFn {
9
+ /**
10
+ * Return only projects whose name contains this substring
11
+ * (case-insensitive). The match is performed server-side.
12
+ *
13
+ * @requires Phoenix server >= 17.16.0
14
+ */
15
+ nameContains?: string;
16
+ }
17
+
18
+ type ProjectsResponse = components["schemas"]["GetProjectsResponseBody"];
19
+
20
+ const DEFAULT_PAGE_SIZE = 100;
21
+
22
+ /**
23
+ * List projects with automatic pagination handling.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { getProjects } from "@arizeai/phoenix-client/projects";
28
+ *
29
+ * // Every project
30
+ * const projects = await getProjects();
31
+ *
32
+ * // Only projects whose name contains "agent" (requires Phoenix server >= 17.16.0)
33
+ * const agentProjects = await getProjects({ nameContains: "agent" });
34
+ *
35
+ * for (const project of agentProjects) {
36
+ * console.log(`Project: ${project.name} (${project.id})`);
37
+ * }
38
+ * ```
39
+ */
40
+ export async function getProjects(
41
+ params: GetProjectsParams = {}
42
+ ): Promise<Project[]> {
43
+ const client = params.client || createClient();
44
+ const { nameContains } = params;
45
+
46
+ const projects: Project[] = [];
47
+ let cursor: string | null | undefined = null;
48
+
49
+ do {
50
+ const response: { data?: ProjectsResponse; error?: unknown } =
51
+ await client.GET("/v1/projects", {
52
+ params: {
53
+ query: {
54
+ cursor,
55
+ limit: DEFAULT_PAGE_SIZE,
56
+ name_contains: nameContains,
57
+ },
58
+ },
59
+ });
60
+
61
+ if (response.error) throw response.error;
62
+ invariant(response.data?.data, "Failed to list projects");
63
+
64
+ cursor = response.data.next_cursor ?? null;
65
+ projects.push(...response.data.data);
66
+ } while (cursor != null);
67
+
68
+ return projects;
69
+ }
@@ -0,0 +1 @@
1
+ export * from "./getProjects";
@@ -301,6 +301,6 @@ export function promptVersion(params: PromptVersionInput): PromptVersionData {
301
301
  },
302
302
  };
303
303
  default:
304
- assertUnreachable(model_provider);
304
+ return assertUnreachable(model_provider);
305
305
  }
306
306
  }
@@ -42,7 +42,7 @@ const getTargetSDK = <SDK extends SupportedSDK>(sdk: SDK) => {
42
42
  case "ai":
43
43
  return PROVIDER_TO_SDK.ai;
44
44
  default:
45
- assertUnreachable(sdk);
45
+ return assertUnreachable(sdk);
46
46
  }
47
47
  };
48
48
 
@@ -294,7 +294,7 @@ export const fromOpenAIToolCall = <
294
294
  toolCall
295
295
  ) as ReturnType;
296
296
  default:
297
- assertUnreachable(targetProvider);
297
+ return assertUnreachable(targetProvider);
298
298
  }
299
299
  };
300
300
 
@@ -328,7 +328,7 @@ export const toOpenAIToolChoice = (
328
328
  validatedToolChoice
329
329
  );
330
330
  default:
331
- assertUnreachable(provider);
331
+ return assertUnreachable(provider);
332
332
  }
333
333
  };
334
334
 
@@ -373,7 +373,7 @@ export const fromOpenAIToolChoice = <
373
373
  toolChoice
374
374
  ) as ReturnType;
375
375
  default:
376
- assertUnreachable(targetProvider);
376
+ return assertUnreachable(targetProvider);
377
377
  }
378
378
  };
379
379
 
@@ -406,7 +406,7 @@ export const toOpenAIToolDefinition = (
406
406
  case null:
407
407
  return null;
408
408
  default:
409
- assertUnreachable(provider);
409
+ return assertUnreachable(provider);
410
410
  }
411
411
  };
412
412
 
@@ -447,7 +447,7 @@ export const fromOpenAIToolDefinition = <
447
447
  toolDefinition
448
448
  ) as ReturnType;
449
449
  default:
450
- assertUnreachable(targetProvider);
450
+ return assertUnreachable(targetProvider);
451
451
  }
452
452
  };
453
453
 
@@ -324,7 +324,7 @@ export const openAIMessageToVercelAI = openAIMessageSchema.transform(
324
324
  content: [],
325
325
  };
326
326
  default:
327
- assertUnreachable(role);
327
+ return assertUnreachable(role);
328
328
  }
329
329
  }
330
330
  );
@@ -354,7 +354,7 @@ export const openAIToolChoiceToAnthropic = openAIToolChoiceSchema.transform(
354
354
  case "required":
355
355
  return { type: "any" };
356
356
  default:
357
- assertUnreachable(openAI);
357
+ return assertUnreachable(openAI);
358
358
  }
359
359
  }
360
360
  );
@@ -372,7 +372,7 @@ export const openAIToolChoiceToVercelAI = openAIToolChoiceSchema.transform(
372
372
  case "required":
373
373
  return "required";
374
374
  default:
375
- assertUnreachable(openAI);
375
+ return assertUnreachable(openAI);
376
376
  }
377
377
  }
378
378
  );
@@ -172,6 +172,8 @@ export const phoenixToolChoiceToOpenAI = phoenixToolChoiceSchema.transform(
172
172
  return "required";
173
173
  case "specific_function":
174
174
  return { type: "function", function: { name: phoenix.function_name } };
175
+ default:
176
+ return assertUnreachable(phoenix);
175
177
  }
176
178
  }
177
179
  );
@@ -1,3 +1,10 @@
1
+ import type { components } from "../__generated__/api/v1";
2
+
3
+ /**
4
+ * A project as returned by the Phoenix REST API.
5
+ */
6
+ export type Project = components["schemas"]["Project"];
7
+
1
8
  /**
2
9
  * Identifies a project. Accepts any of:
3
10
  * - `project` — a project ID or name (the server accepts either)
@@ -20,6 +20,7 @@
20
20
 
21
21
  import type { PhoenixClient } from "../client";
22
22
  import type { CapabilityRequirement } from "../types/serverRequirements";
23
+ import { assertUnreachable } from "./assertUnreachable";
23
24
  import { formatVersion, satisfiesMinVersion } from "./semverUtils";
24
25
 
25
26
  // ---------------------------------------------------------------------------
@@ -37,6 +38,8 @@ export function capabilityLabel(req: CapabilityRequirement): string {
37
38
  return `The ${req.method} ${req.path} route`;
38
39
  case "parameter":
39
40
  return `The '${req.parameterName}' ${req.parameterLocation} parameter on ${req.route}`;
41
+ default:
42
+ return assertUnreachable(req);
40
43
  }
41
44
  }
42
45