@arizeai/phoenix-client 7.2.0 → 7.3.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/README.md +3 -2
- package/dist/esm/client.d.ts +10 -2
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +6 -0
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/config.d.ts +10 -0
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +13 -9
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/experiments/resumeEvaluation.d.ts.map +1 -1
- package/dist/esm/experiments/resumeEvaluation.js +5 -5
- package/dist/esm/experiments/resumeEvaluation.js.map +1 -1
- package/dist/esm/experiments/resumeExperiment.d.ts.map +1 -1
- package/dist/esm/experiments/resumeExperiment.js +5 -5
- package/dist/esm/experiments/resumeExperiment.js.map +1 -1
- package/dist/esm/experiments/runExperiment.d.ts.map +1 -1
- package/dist/esm/experiments/runExperiment.js +5 -5
- package/dist/esm/experiments/runExperiment.js.map +1 -1
- package/dist/esm/experiments/tracing.d.ts +27 -0
- package/dist/esm/experiments/tracing.d.ts.map +1 -1
- package/dist/esm/experiments/tracing.js +27 -0
- package/dist/esm/experiments/tracing.js.map +1 -1
- package/dist/esm/testing/phoenix-test-tracking.d.ts.map +1 -1
- package/dist/esm/testing/phoenix-test-tracking.js +9 -9
- package/dist/esm/testing/phoenix-test-tracking.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/src/client.d.ts +10 -2
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +6 -1
- package/dist/src/client.js.map +1 -1
- package/dist/src/config.d.ts +10 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +11 -7
- package/dist/src/config.js.map +1 -1
- package/dist/src/experiments/resumeEvaluation.d.ts.map +1 -1
- package/dist/src/experiments/resumeEvaluation.js +4 -4
- package/dist/src/experiments/resumeEvaluation.js.map +1 -1
- package/dist/src/experiments/resumeExperiment.d.ts.map +1 -1
- package/dist/src/experiments/resumeExperiment.js +4 -4
- package/dist/src/experiments/resumeExperiment.js.map +1 -1
- package/dist/src/experiments/runExperiment.d.ts.map +1 -1
- package/dist/src/experiments/runExperiment.js +4 -4
- package/dist/src/experiments/runExperiment.js.map +1 -1
- package/dist/src/experiments/tracing.d.ts +27 -0
- package/dist/src/experiments/tracing.d.ts.map +1 -1
- package/dist/src/experiments/tracing.js +30 -0
- package/dist/src/experiments/tracing.js.map +1 -1
- package/dist/src/testing/phoenix-test-tracking.d.ts.map +1 -1
- package/dist/src/testing/phoenix-test-tracking.js +8 -8
- package/dist/src/testing/phoenix-test-tracking.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/ci-evals-jest.mdx +1 -1
- package/docs/ci-evals-vitest.mdx +1 -1
- package/docs/ci-evals.mdx +1 -1
- package/docs/overview.mdx +5 -5
- package/package.json +5 -5
- package/src/client.ts +17 -1
- package/src/config.ts +28 -11
- package/src/experiments/resumeEvaluation.ts +11 -9
- package/src/experiments/resumeExperiment.ts +11 -9
- package/src/experiments/runExperiment.ts +9 -11
- package/src/experiments/tracing.ts +35 -0
- package/src/testing/phoenix-test-tracking.ts +12 -9
package/docs/ci-evals-jest.mdx
CHANGED
|
@@ -23,7 +23,7 @@ module.exports = {
|
|
|
23
23
|
- `testMatch` keeps eval suites separate from regular tests.
|
|
24
24
|
- `reporters` keeps Jest's default reporter and adds the Phoenix
|
|
25
25
|
summary block at the end of the run.
|
|
26
|
-
- `setupFiles: ["dotenv/config"]` loads `
|
|
26
|
+
- `setupFiles: ["dotenv/config"]` loads `PHOENIX_ENDPOINT`, `PHOENIX_API_KEY`,
|
|
27
27
|
and other env vars from `.env`.
|
|
28
28
|
- `testTimeout` is bumped because LLM calls can be slow.
|
|
29
29
|
|
package/docs/ci-evals-vitest.mdx
CHANGED
|
@@ -28,7 +28,7 @@ export default defineConfig({
|
|
|
28
28
|
`*.eval.ts` convention.
|
|
29
29
|
- `reporters` keeps Vitest's default diagnostics and enables the Phoenix
|
|
30
30
|
summary block.
|
|
31
|
-
- `setupFiles: ["dotenv/config"]` loads `
|
|
31
|
+
- `setupFiles: ["dotenv/config"]` loads `PHOENIX_ENDPOINT`, `PHOENIX_API_KEY`,
|
|
32
32
|
and any other env vars from `.env`.
|
|
33
33
|
- `testTimeout` is bumped because LLM calls can be slow.
|
|
34
34
|
|
package/docs/ci-evals.mdx
CHANGED
|
@@ -94,7 +94,7 @@ standard Phoenix env vars.
|
|
|
94
94
|
|
|
95
95
|
| Variable | Purpose |
|
|
96
96
|
| --- | --- |
|
|
97
|
-
| `
|
|
97
|
+
| `PHOENIX_ENDPOINT` | Phoenix base URL |
|
|
98
98
|
| `PHOENIX_API_KEY` | Bearer token for Phoenix |
|
|
99
99
|
| `PHOENIX_CLIENT_HEADERS` | Optional JSON headers forwarded to the Phoenix client and tracer |
|
|
100
100
|
| `PHOENIX_TEST_TRACKING=false` | Disable sync to Phoenix for the current run (tracking is on by default) |
|
package/docs/overview.mdx
CHANGED
|
@@ -50,18 +50,18 @@ That gives the agent version-matched docs plus the exact implementation and gene
|
|
|
50
50
|
|
|
51
51
|
## Configuration
|
|
52
52
|
|
|
53
|
-
`createClient()` resolves Phoenix client options in this order: library defaults, environment variables, then explicit options. In most applications, the normal setup is to set `
|
|
53
|
+
`createClient()` resolves Phoenix client options in this order: library defaults, environment variables, then explicit options. In most applications, the normal setup is to set `PHOENIX_ENDPOINT` and `PHOENIX_API_KEY` in the environment and call `createClient()` with no overrides.
|
|
54
54
|
|
|
55
55
|
### Recommended Setup
|
|
56
56
|
|
|
57
57
|
Use the environment-driven path unless you have a specific reason to override client options in code.
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
export
|
|
60
|
+
export PHOENIX_ENDPOINT=http://localhost:6006
|
|
61
61
|
export PHOENIX_API_KEY=<your-api-key>
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
For a remote deployment, `
|
|
64
|
+
For a remote deployment, `PHOENIX_ENDPOINT` is that instance's base URL, e.g. `https://your-phoenix.example.com`.
|
|
65
65
|
|
|
66
66
|
```ts
|
|
67
67
|
import { createClient } from "@arizeai/phoenix-client";
|
|
@@ -103,7 +103,7 @@ These are the Phoenix-specific options this package resolves before creating the
|
|
|
103
103
|
|
|
104
104
|
| Option | Type | Description |
|
|
105
105
|
|--------|------|-------------|
|
|
106
|
-
| `baseUrl` | `string` | Base Phoenix URL. Defaults to `http://localhost:6006`, or `
|
|
106
|
+
| `baseUrl` | `string` | Base Phoenix URL. Defaults to `http://localhost:6006`, or `PHOENIX_ENDPOINT` when that environment variable is set. |
|
|
107
107
|
| `headers` | `ClientOptions["headers"]` | Headers sent on every request. `PHOENIX_API_KEY` populates `Authorization` automatically. Explicit `headers` replace environment-derived headers. |
|
|
108
108
|
|
|
109
109
|
### Header Override Rule
|
|
@@ -124,7 +124,7 @@ const client = createClient({
|
|
|
124
124
|
|
|
125
125
|
| Variable | Maps to | Description |
|
|
126
126
|
|--------|---------|-------------|
|
|
127
|
-
| `
|
|
127
|
+
| `PHOENIX_ENDPOINT` | `options.baseUrl` | Base Phoenix URL, for example `http://localhost:6006`. |
|
|
128
128
|
| `PHOENIX_API_KEY` | `options.headers.Authorization` | Bearer token for authenticated environments. |
|
|
129
129
|
| `PHOENIX_CLIENT_HEADERS` | `options.headers` | Optional JSON-encoded object of additional headers to send on every request. Most setups do not need this. |
|
|
130
130
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arizeai/phoenix-client",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"description": "A client for the Phoenix API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arize",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"openapi-fetch": "^0.17.0",
|
|
105
105
|
"tiny-invariant": "^1.3.3",
|
|
106
106
|
"zod": "^4.4.3",
|
|
107
|
-
"@arizeai/phoenix-
|
|
108
|
-
"@arizeai/phoenix-
|
|
107
|
+
"@arizeai/phoenix-config": "0.5.0",
|
|
108
|
+
"@arizeai/phoenix-otel": "2.2.0"
|
|
109
109
|
},
|
|
110
110
|
"devDependencies": {
|
|
111
111
|
"@ai-sdk/openai": "^4.0.27",
|
|
@@ -122,8 +122,8 @@
|
|
|
122
122
|
"openapi-typescript": "^7.13.0",
|
|
123
123
|
"tsx": "^4.23.1",
|
|
124
124
|
"vitest": "^4.1.10",
|
|
125
|
-
"@arizeai/phoenix-
|
|
126
|
-
"@arizeai/phoenix-
|
|
125
|
+
"@arizeai/phoenix-testing": "0.0.0",
|
|
126
|
+
"@arizeai/phoenix-evals": "2.2.0"
|
|
127
127
|
},
|
|
128
128
|
"peerDependencies": {
|
|
129
129
|
"@anthropic-ai/sdk": "^0.35.0",
|
package/src/client.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
paths as oapiPathsV1,
|
|
10
10
|
} from "./__generated__/api/v1.d.ts";
|
|
11
11
|
import {
|
|
12
|
+
type BaseUrlSource,
|
|
12
13
|
defaultGetEnvironmentOptions,
|
|
13
14
|
makeDefaultClientOptions,
|
|
14
15
|
} from "./config";
|
|
@@ -36,6 +37,14 @@ export type Types = {
|
|
|
36
37
|
};
|
|
37
38
|
};
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* The client's resolved options, tagged with where the base URL came from so
|
|
42
|
+
* consumers can tell deliberate configuration from an ambient environment.
|
|
43
|
+
*/
|
|
44
|
+
export type PhoenixClientOptions = ClientOptions & {
|
|
45
|
+
baseUrlSource: BaseUrlSource;
|
|
46
|
+
};
|
|
47
|
+
|
|
39
48
|
/**
|
|
40
49
|
* Merge all configuration options according to priority:
|
|
41
50
|
* defaults < environment < explicit options
|
|
@@ -51,13 +60,20 @@ export const getMergedOptions = ({
|
|
|
51
60
|
}: {
|
|
52
61
|
options?: Partial<ClientOptions>;
|
|
53
62
|
getEnvironmentOptions?: () => Partial<ClientOptions>;
|
|
54
|
-
} = {}):
|
|
63
|
+
} = {}): PhoenixClientOptions => {
|
|
55
64
|
const defaultOptions = makeDefaultClientOptions();
|
|
56
65
|
const environmentOptions = getEnvironmentOptions();
|
|
66
|
+
const baseUrlSource: BaseUrlSource =
|
|
67
|
+
options.baseUrl !== undefined
|
|
68
|
+
? "explicit"
|
|
69
|
+
: environmentOptions.baseUrl !== undefined
|
|
70
|
+
? "environment"
|
|
71
|
+
: "default";
|
|
57
72
|
return {
|
|
58
73
|
...defaultOptions,
|
|
59
74
|
...environmentOptions,
|
|
60
75
|
...options,
|
|
76
|
+
baseUrlSource,
|
|
61
77
|
};
|
|
62
78
|
};
|
|
63
79
|
|
package/src/config.ts
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import type { EnvironmentConfig } from "@arizeai/phoenix-config";
|
|
2
1
|
import {
|
|
3
2
|
DEFAULT_PHOENIX_BASE_URL,
|
|
4
|
-
|
|
3
|
+
getBaseUrlFromEnvironment,
|
|
4
|
+
getCredentialsFromEnvironment,
|
|
5
5
|
} from "@arizeai/phoenix-config";
|
|
6
6
|
import type { ClientOptions } from "openapi-fetch";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Convert
|
|
9
|
+
* Convert resolved Phoenix credentials into a ClientOptions object.
|
|
10
10
|
*
|
|
11
|
-
* @param
|
|
11
|
+
* @param credentials - The API key and headers resolved from the environment.
|
|
12
12
|
* @returns The converted ClientOptions object.
|
|
13
13
|
*/
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const phoenixCredentialsToClientOptions = (
|
|
15
|
+
credentials: ReturnType<typeof getCredentialsFromEnvironment>
|
|
16
16
|
): Partial<ClientOptions> => {
|
|
17
17
|
const options: Partial<ClientOptions> = {
|
|
18
|
-
baseUrl: environment.PHOENIX_HOST,
|
|
19
18
|
headers: {
|
|
20
|
-
...(
|
|
21
|
-
...(
|
|
22
|
-
? { Authorization: `Bearer ${
|
|
19
|
+
...(credentials.headers ?? {}),
|
|
20
|
+
...(credentials.apiKey
|
|
21
|
+
? { Authorization: `Bearer ${credentials.apiKey}` }
|
|
23
22
|
: {}),
|
|
24
23
|
},
|
|
25
24
|
};
|
|
@@ -36,6 +35,17 @@ const phoenixEnvironmentToClientOptions = (
|
|
|
36
35
|
);
|
|
37
36
|
};
|
|
38
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Where a client's base URL came from: an explicit `baseUrl` option
|
|
40
|
+
* (`"explicit"`), a Phoenix environment variable (`"environment"`), or the
|
|
41
|
+
* built-in localhost default (`"default"`).
|
|
42
|
+
*
|
|
43
|
+
* Explicit configuration outranks the ambient environment, so this is what
|
|
44
|
+
* decides whether an environment variable may retarget the client's trace
|
|
45
|
+
* export.
|
|
46
|
+
*/
|
|
47
|
+
export type BaseUrlSource = "default" | "environment" | "explicit";
|
|
48
|
+
|
|
39
49
|
/**
|
|
40
50
|
* Get the environment options from the environment.
|
|
41
51
|
*
|
|
@@ -46,7 +56,14 @@ export const defaultGetEnvironmentOptions = (): Partial<ClientOptions> => {
|
|
|
46
56
|
if (typeof process !== "object" || typeof process.env !== "object") {
|
|
47
57
|
return {};
|
|
48
58
|
}
|
|
49
|
-
|
|
59
|
+
const options = phoenixCredentialsToClientOptions(
|
|
60
|
+
getCredentialsFromEnvironment()
|
|
61
|
+
);
|
|
62
|
+
// The base URL resolves as a tier group (PHOENIX_ENDPOINT first, inferring
|
|
63
|
+
// from the trace-export variables, then legacy PHOENIX_HOST) rather than
|
|
64
|
+
// variable by variable.
|
|
65
|
+
const baseUrl = getBaseUrlFromEnvironment();
|
|
66
|
+
return baseUrl !== undefined ? { ...options, baseUrl } : options;
|
|
50
67
|
};
|
|
51
68
|
|
|
52
69
|
/**
|
|
@@ -31,7 +31,11 @@ import { getExperimentInfo } from "./getExperimentInfo.js";
|
|
|
31
31
|
import { getExperimentEvaluators } from "./helpers";
|
|
32
32
|
import { getExampleGlobalId } from "./helpers/getExampleGlobalId";
|
|
33
33
|
import { logEvalResumeSummary, PROGRESS_PREFIX } from "./logging";
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
cleanupOwnedTracerProvider,
|
|
36
|
+
getTraceExportUrl,
|
|
37
|
+
MISSING_BASE_URL_MESSAGE,
|
|
38
|
+
} from "./tracing";
|
|
35
39
|
|
|
36
40
|
/**
|
|
37
41
|
* Error thrown when evaluation is aborted due to a failure in stopOnFirstError mode.
|
|
@@ -199,14 +203,15 @@ async function handleEvaluationFetchError(
|
|
|
199
203
|
*/
|
|
200
204
|
function setupEvaluationTracer({
|
|
201
205
|
projectName,
|
|
202
|
-
|
|
206
|
+
traceExportUrl,
|
|
203
207
|
headers,
|
|
204
208
|
useBatchSpanProcessor,
|
|
205
209
|
diagLogLevel,
|
|
206
210
|
setGlobalTracerProvider,
|
|
207
211
|
}: {
|
|
208
212
|
projectName: string | null;
|
|
209
|
-
|
|
213
|
+
/** Where spans are exported; omit to let `register()` read the environment. */
|
|
214
|
+
traceExportUrl?: string;
|
|
210
215
|
headers?: Record<string, string>;
|
|
211
216
|
useBatchSpanProcessor: boolean;
|
|
212
217
|
diagLogLevel?: DiagLogLevel;
|
|
@@ -222,7 +227,7 @@ function setupEvaluationTracer({
|
|
|
222
227
|
|
|
223
228
|
const provider = register({
|
|
224
229
|
projectName,
|
|
225
|
-
url:
|
|
230
|
+
url: traceExportUrl,
|
|
226
231
|
headers,
|
|
227
232
|
batch: useBatchSpanProcessor,
|
|
228
233
|
diagLogLevel,
|
|
@@ -323,14 +328,11 @@ export async function resumeEvaluation({
|
|
|
323
328
|
|
|
324
329
|
// Initialize tracer (only if experiment has a project_name)
|
|
325
330
|
const baseUrl = client.config.baseUrl;
|
|
326
|
-
invariant(
|
|
327
|
-
baseUrl,
|
|
328
|
-
"Phoenix base URL not found. Please set PHOENIX_HOST or set baseUrl on the client."
|
|
329
|
-
);
|
|
331
|
+
invariant(baseUrl, MISSING_BASE_URL_MESSAGE);
|
|
330
332
|
|
|
331
333
|
const tracerSetup = setupEvaluationTracer({
|
|
332
334
|
projectName: experiment.projectName,
|
|
333
|
-
|
|
335
|
+
traceExportUrl: getTraceExportUrl(client.config),
|
|
334
336
|
headers: client.config.headers
|
|
335
337
|
? toObjectHeaders(client.config.headers)
|
|
336
338
|
: undefined,
|
|
@@ -35,7 +35,11 @@ import {
|
|
|
35
35
|
PROGRESS_PREFIX,
|
|
36
36
|
} from "./logging";
|
|
37
37
|
import { resumeEvaluation } from "./resumeEvaluation";
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
cleanupOwnedTracerProvider,
|
|
40
|
+
getTraceExportUrl,
|
|
41
|
+
MISSING_BASE_URL_MESSAGE,
|
|
42
|
+
} from "./tracing";
|
|
39
43
|
|
|
40
44
|
/**
|
|
41
45
|
* Error thrown when task is aborted due to a failure in stopOnFirstError mode.
|
|
@@ -182,14 +186,15 @@ async function handleFetchError(
|
|
|
182
186
|
*/
|
|
183
187
|
function setupTracer({
|
|
184
188
|
projectName,
|
|
185
|
-
|
|
189
|
+
traceExportUrl,
|
|
186
190
|
headers,
|
|
187
191
|
useBatchSpanProcessor,
|
|
188
192
|
diagLogLevel,
|
|
189
193
|
setGlobalTracerProvider,
|
|
190
194
|
}: {
|
|
191
195
|
projectName: string | null;
|
|
192
|
-
|
|
196
|
+
/** Where spans are exported; omit to let `register()` read the environment. */
|
|
197
|
+
traceExportUrl?: string;
|
|
193
198
|
headers?: Record<string, string>;
|
|
194
199
|
useBatchSpanProcessor: boolean;
|
|
195
200
|
diagLogLevel?: DiagLogLevel;
|
|
@@ -205,7 +210,7 @@ function setupTracer({
|
|
|
205
210
|
|
|
206
211
|
const provider = register({
|
|
207
212
|
projectName,
|
|
208
|
-
url:
|
|
213
|
+
url: traceExportUrl,
|
|
209
214
|
headers,
|
|
210
215
|
batch: useBatchSpanProcessor,
|
|
211
216
|
diagLogLevel,
|
|
@@ -307,15 +312,12 @@ export async function resumeExperiment({
|
|
|
307
312
|
|
|
308
313
|
// Get base URL for tracing and URL generation
|
|
309
314
|
const baseUrl = client.config.baseUrl;
|
|
310
|
-
invariant(
|
|
311
|
-
baseUrl,
|
|
312
|
-
"Phoenix base URL not found. Please set PHOENIX_HOST or set baseUrl on the client."
|
|
313
|
-
);
|
|
315
|
+
invariant(baseUrl, MISSING_BASE_URL_MESSAGE);
|
|
314
316
|
|
|
315
317
|
// Initialize tracer (only if experiment has a project_name)
|
|
316
318
|
const tracerSetup = setupTracer({
|
|
317
319
|
projectName: experiment.projectName,
|
|
318
|
-
|
|
320
|
+
traceExportUrl: getTraceExportUrl(client.config),
|
|
319
321
|
headers: client.config.headers
|
|
320
322
|
? toObjectHeaders(client.config.headers)
|
|
321
323
|
: undefined,
|
|
@@ -54,7 +54,11 @@ import {
|
|
|
54
54
|
logTaskSummary,
|
|
55
55
|
PROGRESS_PREFIX,
|
|
56
56
|
} from "./logging";
|
|
57
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
cleanupOwnedTracerProvider,
|
|
59
|
+
getTraceExportUrl,
|
|
60
|
+
MISSING_BASE_URL_MESSAGE,
|
|
61
|
+
} from "./tracing";
|
|
58
62
|
|
|
59
63
|
/**
|
|
60
64
|
* Validate that a repetition is valid
|
|
@@ -270,14 +274,11 @@ export async function runExperiment({
|
|
|
270
274
|
};
|
|
271
275
|
// Initialize the tracer, now that we have a project name
|
|
272
276
|
const baseUrl = client.config.baseUrl;
|
|
273
|
-
invariant(
|
|
274
|
-
baseUrl,
|
|
275
|
-
"Phoenix base URL not found. Please set PHOENIX_HOST or set baseUrl on the client."
|
|
276
|
-
);
|
|
277
|
+
invariant(baseUrl, MISSING_BASE_URL_MESSAGE);
|
|
277
278
|
|
|
278
279
|
taskProvider = register({
|
|
279
280
|
projectName,
|
|
280
|
-
url:
|
|
281
|
+
url: getTraceExportUrl(client.config),
|
|
281
282
|
headers: client.config.headers
|
|
282
283
|
? toObjectHeaders(client.config.headers)
|
|
283
284
|
: undefined,
|
|
@@ -621,10 +622,7 @@ export async function evaluateExperiment({
|
|
|
621
622
|
const isDryRun = typeof dryRun === "number" || dryRun === true;
|
|
622
623
|
const client = _client ?? createClient();
|
|
623
624
|
const baseUrl = client.config.baseUrl;
|
|
624
|
-
invariant(
|
|
625
|
-
baseUrl,
|
|
626
|
-
"Phoenix base URL not found. Please set PHOENIX_HOST or set baseUrl on the client."
|
|
627
|
-
);
|
|
625
|
+
invariant(baseUrl, MISSING_BASE_URL_MESSAGE);
|
|
628
626
|
let provider: NodeTracerProvider;
|
|
629
627
|
let globalRegistration: GlobalTracerProviderRegistration | null = null;
|
|
630
628
|
const ownsProvider = !paramsTracerProvider;
|
|
@@ -635,7 +633,7 @@ export async function evaluateExperiment({
|
|
|
635
633
|
} else if (!isDryRun) {
|
|
636
634
|
provider = register({
|
|
637
635
|
projectName: "evaluators",
|
|
638
|
-
url:
|
|
636
|
+
url: getTraceExportUrl(client.config),
|
|
639
637
|
headers: client.config.headers
|
|
640
638
|
? toObjectHeaders(client.config.headers)
|
|
641
639
|
: undefined,
|
|
@@ -3,6 +3,41 @@ import type {
|
|
|
3
3
|
NodeTracerProvider,
|
|
4
4
|
} from "@arizeai/phoenix-otel";
|
|
5
5
|
|
|
6
|
+
import type { BaseUrlSource } from "../config";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Message for the invariant shared by every experiment entry point: a base URL
|
|
10
|
+
* must be resolvable before a tracer can be registered.
|
|
11
|
+
*/
|
|
12
|
+
export const MISSING_BASE_URL_MESSAGE =
|
|
13
|
+
"Phoenix base URL not found. Please set PHOENIX_ENDPOINT (or PHOENIX_COLLECTOR_ENDPOINT) or set baseUrl on the client.";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the URL experiment spans are exported to, as the `url` argument to
|
|
17
|
+
* `register()`.
|
|
18
|
+
*
|
|
19
|
+
* Explicit code-level configuration outranks the ambient environment: a client
|
|
20
|
+
* created with an explicit `baseUrl` exports its spans to that server, so a
|
|
21
|
+
* `PHOENIX_COLLECTOR_ENDPOINT` left in the shell cannot silently retarget it.
|
|
22
|
+
* When the base URL itself came from the environment, so does trace export:
|
|
23
|
+
* returning `undefined` hands resolution to `register()`, which reads the
|
|
24
|
+
* trace-export chain (`PHOENIX_COLLECTOR_ENDPOINT`, the OTel-standard
|
|
25
|
+
* variables, then `PHOENIX_ENDPOINT`) exactly as a standalone `register()`
|
|
26
|
+
* call would.
|
|
27
|
+
*
|
|
28
|
+
* A base URL of unknown provenance — a hand-built client rather than one from
|
|
29
|
+
* `createClient()` — counts as explicit, since only deliberate configuration
|
|
30
|
+
* puts a URL there.
|
|
31
|
+
*/
|
|
32
|
+
export function getTraceExportUrl(config: {
|
|
33
|
+
baseUrl?: string;
|
|
34
|
+
baseUrlSource?: BaseUrlSource;
|
|
35
|
+
}): string | undefined {
|
|
36
|
+
return (config.baseUrlSource ?? "explicit") === "explicit"
|
|
37
|
+
? config.baseUrl
|
|
38
|
+
: undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
6
41
|
/**
|
|
7
42
|
* Flushes and shuts down a tracer provider that this package created, then
|
|
8
43
|
* detaches any global OTEL registration it owns so another provider can be mounted.
|
|
@@ -16,7 +16,10 @@ import {
|
|
|
16
16
|
import type { Span } from "@opentelemetry/api";
|
|
17
17
|
|
|
18
18
|
import { createDataset } from "../datasets";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
cleanupOwnedTracerProvider,
|
|
21
|
+
getTraceExportUrl,
|
|
22
|
+
} from "../experiments/tracing";
|
|
20
23
|
import { createClient, type PhoenixClient } from "../index";
|
|
21
24
|
import { ensureString } from "../utils/ensureString";
|
|
22
25
|
import { toObjectHeaders } from "../utils/toObjectHeaders";
|
|
@@ -163,9 +166,9 @@ interface TaskSpanLifecycle {
|
|
|
163
166
|
const taskSpansByRun = new WeakMap<RunState, TaskSpanLifecycle>();
|
|
164
167
|
|
|
165
168
|
/**
|
|
166
|
-
* Warn once when
|
|
167
|
-
* header is being forwarded to the OTLP exporter — that
|
|
168
|
-
* exfiltrates the bearer token in cleartext.
|
|
169
|
+
* Warn once when the resolved base URL is plain `http:` while an
|
|
170
|
+
* `Authorization` header is being forwarded to the OTLP exporter — that
|
|
171
|
+
* combination exfiltrates the bearer token in cleartext.
|
|
169
172
|
*/
|
|
170
173
|
let warnedAboutHttpScheme = false;
|
|
171
174
|
function maybeWarnHttpScheme(
|
|
@@ -191,9 +194,9 @@ function maybeWarnHttpScheme(
|
|
|
191
194
|
warnedAboutHttpScheme = true;
|
|
192
195
|
// eslint-disable-next-line no-console
|
|
193
196
|
console.warn(
|
|
194
|
-
`[@arizeai/phoenix-client]
|
|
195
|
-
`an Authorization header set; the bearer token will travel in
|
|
196
|
-
`Use https:// for non-localhost Phoenix endpoints.`
|
|
197
|
+
`[@arizeai/phoenix-client] The Phoenix base URL "${baseUrl}" uses http:// ` +
|
|
198
|
+
`with an Authorization header set; the bearer token will travel in ` +
|
|
199
|
+
`cleartext. Use https:// for non-localhost Phoenix endpoints.`
|
|
197
200
|
);
|
|
198
201
|
}
|
|
199
202
|
|
|
@@ -349,7 +352,7 @@ export async function initializeSuite(suite: SuiteState): Promise<void> {
|
|
|
349
352
|
if (!baseUrl) {
|
|
350
353
|
suite.trackingDisabled = true;
|
|
351
354
|
suite.setupError = new Error(
|
|
352
|
-
"Phoenix base URL not found. Set
|
|
355
|
+
"Phoenix base URL not found. Set PHOENIX_ENDPOINT (or PHOENIX_COLLECTOR_ENDPOINT) or pass baseUrl on the client."
|
|
353
356
|
);
|
|
354
357
|
suite.tracer = createNoOpProvider().getTracer("no-op");
|
|
355
358
|
suite.evaluatorTracer = suite.tracer;
|
|
@@ -362,7 +365,7 @@ export async function initializeSuite(suite: SuiteState): Promise<void> {
|
|
|
362
365
|
try {
|
|
363
366
|
provider = register({
|
|
364
367
|
projectName: suite.projectName,
|
|
365
|
-
url:
|
|
368
|
+
url: getTraceExportUrl(client.config),
|
|
366
369
|
headers: client.config.headers
|
|
367
370
|
? toObjectHeaders(client.config.headers)
|
|
368
371
|
: undefined,
|