@arizeai/phoenix-client 4.0.3 → 4.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.
- package/dist/esm/__generated__/api/v1.d.ts +529 -4
- package/dist/esm/__generated__/api/v1.d.ts.map +1 -1
- package/dist/esm/datasets/createOrGetDataset.d.ts +18 -0
- package/dist/esm/datasets/createOrGetDataset.d.ts.map +1 -0
- package/dist/esm/datasets/createOrGetDataset.js +29 -0
- package/dist/esm/datasets/createOrGetDataset.js.map +1 -0
- package/dist/esm/datasets/index.d.ts +1 -0
- package/dist/esm/datasets/index.d.ts.map +1 -1
- package/dist/esm/datasets/index.js +1 -0
- package/dist/esm/datasets/index.js.map +1 -1
- package/dist/esm/experiments/getExperimentRuns.d.ts +8 -2
- package/dist/esm/experiments/getExperimentRuns.d.ts.map +1 -1
- package/dist/esm/experiments/getExperimentRuns.js +34 -23
- package/dist/esm/experiments/getExperimentRuns.js.map +1 -1
- package/dist/esm/experiments/instrumentation.d.ts +7 -1
- package/dist/esm/experiments/instrumentation.d.ts.map +1 -1
- package/dist/esm/experiments/instrumentation.js +5 -3
- package/dist/esm/experiments/instrumentation.js.map +1 -1
- package/dist/esm/experiments/runExperiment.d.ts +13 -2
- package/dist/esm/experiments/runExperiment.d.ts.map +1 -1
- package/dist/esm/experiments/runExperiment.js +7 -3
- package/dist/esm/experiments/runExperiment.js.map +1 -1
- package/dist/esm/sessions/addSessionAnnotation.d.ts +44 -0
- package/dist/esm/sessions/addSessionAnnotation.d.ts.map +1 -0
- package/dist/esm/sessions/addSessionAnnotation.js +44 -0
- package/dist/esm/sessions/addSessionAnnotation.js.map +1 -0
- package/dist/esm/sessions/index.d.ts +3 -0
- package/dist/esm/sessions/index.d.ts.map +1 -0
- package/dist/esm/sessions/index.js +3 -0
- package/dist/esm/sessions/index.js.map +1 -0
- package/dist/esm/sessions/logSessionAnnotations.d.ts +56 -0
- package/dist/esm/sessions/logSessionAnnotations.d.ts.map +1 -0
- package/dist/esm/sessions/logSessionAnnotations.js +53 -0
- package/dist/esm/sessions/logSessionAnnotations.js.map +1 -0
- package/dist/esm/sessions/types.d.ts +19 -0
- package/dist/esm/sessions/types.d.ts.map +1 -0
- package/dist/esm/sessions/types.js +37 -0
- package/dist/esm/sessions/types.js.map +1 -0
- package/dist/esm/spans/types.d.ts +3 -50
- package/dist/esm/spans/types.d.ts.map +1 -1
- package/dist/esm/spans/types.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/types/annotations.d.ts +37 -0
- package/dist/esm/types/annotations.d.ts.map +1 -1
- package/dist/esm/utils/formatPromptMessages.d.ts.map +1 -1
- package/dist/esm/utils/getPromptBySelector.d.ts.map +1 -1
- package/dist/src/__generated__/api/v1.d.ts +529 -4
- package/dist/src/__generated__/api/v1.d.ts.map +1 -1
- package/dist/src/datasets/createOrGetDataset.d.ts +18 -0
- package/dist/src/datasets/createOrGetDataset.d.ts.map +1 -0
- package/dist/src/datasets/createOrGetDataset.js +32 -0
- package/dist/src/datasets/createOrGetDataset.js.map +1 -0
- package/dist/src/datasets/index.d.ts +1 -0
- package/dist/src/datasets/index.d.ts.map +1 -1
- package/dist/src/datasets/index.js +1 -0
- package/dist/src/datasets/index.js.map +1 -1
- package/dist/src/experiments/getExperimentRuns.d.ts +8 -2
- package/dist/src/experiments/getExperimentRuns.d.ts.map +1 -1
- package/dist/src/experiments/getExperimentRuns.js +35 -23
- package/dist/src/experiments/getExperimentRuns.js.map +1 -1
- package/dist/src/experiments/instrumentation.d.ts +7 -1
- package/dist/src/experiments/instrumentation.d.ts.map +1 -1
- package/dist/src/experiments/instrumentation.js +4 -2
- package/dist/src/experiments/instrumentation.js.map +1 -1
- package/dist/src/experiments/runExperiment.d.ts +13 -2
- package/dist/src/experiments/runExperiment.d.ts.map +1 -1
- package/dist/src/experiments/runExperiment.js +6 -2
- package/dist/src/experiments/runExperiment.js.map +1 -1
- package/dist/src/prompts/sdks/toSDK.d.ts +2 -2
- package/dist/src/sessions/addSessionAnnotation.d.ts +44 -0
- package/dist/src/sessions/addSessionAnnotation.d.ts.map +1 -0
- package/dist/src/sessions/addSessionAnnotation.js +48 -0
- package/dist/src/sessions/addSessionAnnotation.js.map +1 -0
- package/dist/src/sessions/index.d.ts +3 -0
- package/dist/src/sessions/index.d.ts.map +1 -0
- package/dist/src/sessions/index.js +19 -0
- package/dist/src/sessions/index.js.map +1 -0
- package/dist/src/sessions/logSessionAnnotations.d.ts +56 -0
- package/dist/src/sessions/logSessionAnnotations.d.ts.map +1 -0
- package/dist/src/sessions/logSessionAnnotations.js +56 -0
- package/dist/src/sessions/logSessionAnnotations.js.map +1 -0
- package/dist/src/sessions/types.d.ts +19 -0
- package/dist/src/sessions/types.d.ts.map +1 -0
- package/dist/src/sessions/types.js +41 -0
- package/dist/src/sessions/types.js.map +1 -0
- package/dist/src/spans/types.d.ts +3 -50
- package/dist/src/spans/types.d.ts.map +1 -1
- package/dist/src/spans/types.js.map +1 -1
- package/dist/src/types/annotations.d.ts +37 -0
- package/dist/src/types/annotations.d.ts.map +1 -1
- package/dist/src/utils/formatPromptMessages.d.ts.map +1 -1
- package/dist/src/utils/getPromptBySelector.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -3
- package/src/__generated__/api/v1.ts +529 -4
- package/src/datasets/createOrGetDataset.ts +39 -0
- package/src/datasets/index.ts +1 -0
- package/src/experiments/getExperimentRuns.ts +44 -15
- package/src/experiments/instrumentation.ts +9 -1
- package/src/experiments/runExperiment.ts +22 -1
- package/src/sessions/addSessionAnnotation.ts +65 -0
- package/src/sessions/index.ts +2 -0
- package/src/sessions/logSessionAnnotations.ts +77 -0
- package/src/sessions/types.ts +67 -0
- package/src/spans/types.ts +3 -50
- package/src/types/annotations.ts +39 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createClient } from "../client";
|
|
2
|
+
import { CreateDatasetParams, createDataset } from "./createDataset";
|
|
3
|
+
import { getDatasetInfoByName } from "./getDatasetInfoByName";
|
|
4
|
+
|
|
5
|
+
export type CreateOrGetDatasetParams = CreateDatasetParams;
|
|
6
|
+
|
|
7
|
+
export type CreateOrGetDatasetResponse = {
|
|
8
|
+
datasetId: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Given the parameters to create a dataset, this function will either
|
|
13
|
+
* retrieve an existing dataset by name or create a new one with the provided parameters.
|
|
14
|
+
*
|
|
15
|
+
* This is useful in cases where you would like to re-run a pipeline like:
|
|
16
|
+
* - ensure dataset exists
|
|
17
|
+
* - create a task
|
|
18
|
+
* - run experiment
|
|
19
|
+
* - evaluate experiment
|
|
20
|
+
* without having to create a new dataset each time.
|
|
21
|
+
*/
|
|
22
|
+
export async function createOrGetDataset({
|
|
23
|
+
name,
|
|
24
|
+
description,
|
|
25
|
+
examples,
|
|
26
|
+
client: _client,
|
|
27
|
+
}: CreateOrGetDatasetParams): Promise<CreateOrGetDatasetResponse> {
|
|
28
|
+
const client = _client || createClient();
|
|
29
|
+
// start by fetching an existing dataset by name, catching any errors that occur
|
|
30
|
+
try {
|
|
31
|
+
const dataset = await getDatasetInfoByName({ datasetName: name, client });
|
|
32
|
+
return {
|
|
33
|
+
datasetId: dataset.id,
|
|
34
|
+
};
|
|
35
|
+
} catch {
|
|
36
|
+
// If the dataset doesn't exist, create it, falling back to the error handling inside createDataset
|
|
37
|
+
return await createDataset({ name, description, examples, client });
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/datasets/index.ts
CHANGED
|
@@ -2,35 +2,60 @@ import { createClient } from "../client";
|
|
|
2
2
|
import invariant from "tiny-invariant";
|
|
3
3
|
import { ClientFn } from "../types/core";
|
|
4
4
|
import { ExperimentRun } from "../types/experiments";
|
|
5
|
+
import { components } from "../__generated__/api/v1";
|
|
5
6
|
|
|
6
7
|
export type GetExperimentRunsParams = ClientFn & {
|
|
7
8
|
/**
|
|
8
9
|
* The experiment ID.
|
|
9
10
|
*/
|
|
10
11
|
experimentId: string;
|
|
12
|
+
/**
|
|
13
|
+
* The pagination size by which to pull runs
|
|
14
|
+
* Exposed for controlling the rate at which runs are pulled
|
|
15
|
+
* @default 100
|
|
16
|
+
*/
|
|
17
|
+
pageSize?: number;
|
|
11
18
|
};
|
|
12
19
|
|
|
20
|
+
const DEFAULT_PAGE_SIZE = 100;
|
|
21
|
+
|
|
13
22
|
/**
|
|
14
|
-
* A function that gets the runs (e.g. the results) of a experiment
|
|
23
|
+
* A function that gets all the runs (e.g. the results) of a experiment
|
|
15
24
|
*/
|
|
16
25
|
export async function getExperimentRuns({
|
|
17
26
|
client: _client,
|
|
18
27
|
experimentId,
|
|
28
|
+
pageSize = DEFAULT_PAGE_SIZE,
|
|
19
29
|
}: GetExperimentRunsParams): Promise<{ runs: ExperimentRun[] }> {
|
|
20
30
|
const client = _client || createClient();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
|
|
32
|
+
// Validate that the parameter is an integer and exit early
|
|
33
|
+
invariant(
|
|
34
|
+
Number.isInteger(pageSize) && pageSize > 0,
|
|
35
|
+
"pageSize must be a positive integer greater than 0"
|
|
36
|
+
);
|
|
37
|
+
const runs: ExperimentRun[] = [];
|
|
38
|
+
let cursor: string | null = null;
|
|
39
|
+
do {
|
|
40
|
+
const res: {
|
|
41
|
+
data?: components["schemas"]["ListExperimentRunsResponseBody"];
|
|
42
|
+
} = await client.GET("/v1/experiments/{experiment_id}/runs", {
|
|
43
|
+
params: {
|
|
44
|
+
path: {
|
|
45
|
+
experiment_id: experimentId,
|
|
46
|
+
},
|
|
47
|
+
query: {
|
|
48
|
+
cursor,
|
|
49
|
+
limit: pageSize,
|
|
50
|
+
},
|
|
25
51
|
},
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return {
|
|
52
|
+
});
|
|
53
|
+
// NB: older versions of phoenix simply don't respond with a cursor and fetch all
|
|
54
|
+
cursor = res.data?.next_cursor || null;
|
|
55
|
+
const data = res.data?.data;
|
|
56
|
+
invariant(data, "Failed to fetch runs");
|
|
57
|
+
runs.push(
|
|
58
|
+
...data.map((run) => ({
|
|
34
59
|
id: run.id,
|
|
35
60
|
traceId: run.trace_id || null,
|
|
36
61
|
experimentId: run.experiment_id,
|
|
@@ -39,7 +64,11 @@ export async function getExperimentRuns({
|
|
|
39
64
|
endTime: new Date(run.end_time),
|
|
40
65
|
output: run.output as ExperimentRun["output"],
|
|
41
66
|
error: run.error || null,
|
|
42
|
-
}
|
|
43
|
-
|
|
67
|
+
}))
|
|
68
|
+
);
|
|
69
|
+
} while (cursor != null);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
runs,
|
|
44
73
|
};
|
|
45
74
|
}
|
|
@@ -20,6 +20,7 @@ export function createProvider({
|
|
|
20
20
|
baseUrl,
|
|
21
21
|
headers,
|
|
22
22
|
useBatchSpanProcessor = true,
|
|
23
|
+
diagLogLevel,
|
|
23
24
|
}: {
|
|
24
25
|
projectName: string;
|
|
25
26
|
headers: HeadersOptions;
|
|
@@ -32,8 +33,15 @@ export function createProvider({
|
|
|
32
33
|
* The base URL of the Phoenix. Doesn't include the /v1/traces path.
|
|
33
34
|
*/
|
|
34
35
|
baseUrl: string;
|
|
36
|
+
/**
|
|
37
|
+
* The diag log level to set for the built in DiagConsoleLogger instance.
|
|
38
|
+
* Omit to disable built in logging.
|
|
39
|
+
*/
|
|
40
|
+
diagLogLevel?: DiagLogLevel;
|
|
35
41
|
}) {
|
|
36
|
-
|
|
42
|
+
if (diagLogLevel) {
|
|
43
|
+
diag.setLogger(new DiagConsoleLogger(), diagLogLevel);
|
|
44
|
+
}
|
|
37
45
|
|
|
38
46
|
const exporter = new OTLPTraceExporter({
|
|
39
47
|
url: `${baseUrl}/v1/traces`,
|
|
@@ -23,7 +23,12 @@ import { pluralize } from "../utils/pluralize";
|
|
|
23
23
|
import { promisifyResult } from "../utils/promisifyResult";
|
|
24
24
|
import { AnnotatorKind } from "../types/annotations";
|
|
25
25
|
import { createProvider, createNoOpProvider } from "./instrumentation";
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
type DiagLogLevel,
|
|
28
|
+
SpanStatusCode,
|
|
29
|
+
Tracer,
|
|
30
|
+
trace,
|
|
31
|
+
} from "@opentelemetry/api";
|
|
27
32
|
import {
|
|
28
33
|
MimeType,
|
|
29
34
|
OpenInferenceSpanKind,
|
|
@@ -111,6 +116,11 @@ export type RunExperimentParams = ClientFn & {
|
|
|
111
116
|
* @default true
|
|
112
117
|
*/
|
|
113
118
|
useBatchSpanProcessor?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Log level to set for the default DiagConsoleLogger when tracing.
|
|
121
|
+
* Omit to disable default diag logging, or to bring your own.
|
|
122
|
+
*/
|
|
123
|
+
diagLogLevel?: DiagLogLevel;
|
|
114
124
|
};
|
|
115
125
|
|
|
116
126
|
/**
|
|
@@ -160,6 +170,7 @@ export async function runExperiment({
|
|
|
160
170
|
setGlobalTracerProvider = true,
|
|
161
171
|
repetitions = 1,
|
|
162
172
|
useBatchSpanProcessor = true,
|
|
173
|
+
diagLogLevel,
|
|
163
174
|
}: RunExperimentParams): Promise<RanExperiment> {
|
|
164
175
|
// Validation
|
|
165
176
|
assert(
|
|
@@ -227,6 +238,7 @@ export async function runExperiment({
|
|
|
227
238
|
baseUrl,
|
|
228
239
|
headers: client.config.headers ?? {},
|
|
229
240
|
useBatchSpanProcessor,
|
|
241
|
+
diagLogLevel,
|
|
230
242
|
});
|
|
231
243
|
// Register the provider
|
|
232
244
|
if (setGlobalTracerProvider) {
|
|
@@ -298,6 +310,8 @@ export async function runExperiment({
|
|
|
298
310
|
concurrency,
|
|
299
311
|
dryRun,
|
|
300
312
|
tracerProvider: provider,
|
|
313
|
+
diagLogLevel,
|
|
314
|
+
useBatchSpanProcessor,
|
|
301
315
|
});
|
|
302
316
|
ranExperiment.evaluationRuns = evaluationRuns;
|
|
303
317
|
|
|
@@ -468,6 +482,7 @@ export async function evaluateExperiment({
|
|
|
468
482
|
setGlobalTracerProvider = true,
|
|
469
483
|
useBatchSpanProcessor = true,
|
|
470
484
|
tracerProvider: paramsTracerProvider,
|
|
485
|
+
diagLogLevel,
|
|
471
486
|
}: {
|
|
472
487
|
/**
|
|
473
488
|
* The experiment to evaluate
|
|
@@ -502,6 +517,11 @@ export async function evaluateExperiment({
|
|
|
502
517
|
* Intended as a pass-through from runExperiment
|
|
503
518
|
*/
|
|
504
519
|
tracerProvider?: NodeTracerProvider | null;
|
|
520
|
+
/**
|
|
521
|
+
* Log level to set for the default DiagConsoleLogger when tracing.
|
|
522
|
+
* Omit to disable default diag logging, or to bring your own.
|
|
523
|
+
*/
|
|
524
|
+
diagLogLevel?: DiagLogLevel;
|
|
505
525
|
}): Promise<RanExperiment> {
|
|
506
526
|
const isDryRun = typeof dryRun === "number" || dryRun === true;
|
|
507
527
|
const client = _client ?? createClient();
|
|
@@ -521,6 +541,7 @@ export async function evaluateExperiment({
|
|
|
521
541
|
baseUrl,
|
|
522
542
|
headers: client.config.headers ?? {},
|
|
523
543
|
useBatchSpanProcessor,
|
|
544
|
+
diagLogLevel,
|
|
524
545
|
});
|
|
525
546
|
if (setGlobalTracerProvider) {
|
|
526
547
|
provider.register();
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createClient } from "../client";
|
|
2
|
+
import { ClientFn } from "../types/core";
|
|
3
|
+
import { SessionAnnotation, toSessionAnnotationData } from "./types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parameters to add a span annotation
|
|
7
|
+
*/
|
|
8
|
+
export interface AddSessionAnnotationParams extends ClientFn {
|
|
9
|
+
sessionAnnotation: SessionAnnotation;
|
|
10
|
+
/**
|
|
11
|
+
* If true, the request will be fulfilled synchronously and return the annotation ID.
|
|
12
|
+
* If false, the request will be processed asynchronously and return null.
|
|
13
|
+
* @default false
|
|
14
|
+
*/
|
|
15
|
+
sync?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Add an annotation to a session.
|
|
20
|
+
*
|
|
21
|
+
* The annotation can be of type "LLM", "CODE", or "HUMAN" and can include a label, score, and metadata.
|
|
22
|
+
* If an identifier is provided and an annotation with that identifier already exists, it will be updated.
|
|
23
|
+
*
|
|
24
|
+
* @param params - The parameters to add a span annotation
|
|
25
|
+
* @returns The ID of the created or updated annotation
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const result = await addSessionAnnotation({
|
|
30
|
+
* sessionAnnotation: {
|
|
31
|
+
* sessionId: "123abc",
|
|
32
|
+
* name: "quality_score",
|
|
33
|
+
* label: "good",
|
|
34
|
+
* score: 0.95,
|
|
35
|
+
* annotatorKind: "LLM",
|
|
36
|
+
* identifier: "custom_id_123",
|
|
37
|
+
* metadata: {
|
|
38
|
+
* model: "gpt-4"
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export async function addSessionAnnotation({
|
|
45
|
+
client: _client,
|
|
46
|
+
sessionAnnotation,
|
|
47
|
+
sync = false,
|
|
48
|
+
}: AddSessionAnnotationParams): Promise<{ id: string } | null> {
|
|
49
|
+
const client = _client ?? createClient();
|
|
50
|
+
|
|
51
|
+
const { data, error } = await client.POST("/v1/session_annotations", {
|
|
52
|
+
params: {
|
|
53
|
+
query: { sync },
|
|
54
|
+
},
|
|
55
|
+
body: {
|
|
56
|
+
data: [toSessionAnnotationData(sessionAnnotation)],
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (error) {
|
|
61
|
+
throw new Error(`Failed to add session annotation: ${error}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return data?.data?.[0] || null;
|
|
65
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createClient } from "../client";
|
|
2
|
+
import { ClientFn } from "../types/core";
|
|
3
|
+
import { SessionAnnotation, toSessionAnnotationData } from "./types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parameters to log multiple session annotations
|
|
7
|
+
*/
|
|
8
|
+
export interface LogSessionAnnotationsParams extends ClientFn {
|
|
9
|
+
/**
|
|
10
|
+
* The session annotations to log
|
|
11
|
+
*/
|
|
12
|
+
sessionAnnotations: SessionAnnotation[];
|
|
13
|
+
/**
|
|
14
|
+
* If true, the request will be fulfilled synchronously and return the annotation IDs.
|
|
15
|
+
* If false, the request will be processed asynchronously and return null.
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
sync?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Log multiple session annotations in a single request.
|
|
23
|
+
*
|
|
24
|
+
* Each annotation can be of type "LLM", "CODE", or "HUMAN" and can include a label, score, and metadata.
|
|
25
|
+
* If an identifier is provided and an annotation with that identifier already exists, it will be updated.
|
|
26
|
+
*
|
|
27
|
+
* @param params - The parameters to log session annotations
|
|
28
|
+
* @returns The IDs of the created or updated annotations
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const results = await logSessionAnnotations({
|
|
33
|
+
* sessionAnnotations: [
|
|
34
|
+
* {
|
|
35
|
+
* sessionId: "123abc",
|
|
36
|
+
* name: "quality_score",
|
|
37
|
+
* label: "good",
|
|
38
|
+
* score: 0.95,
|
|
39
|
+
* annotatorKind: "LLM",
|
|
40
|
+
* identifier: "custom_id_123",
|
|
41
|
+
* metadata: {
|
|
42
|
+
* model: "gpt-4"
|
|
43
|
+
* }
|
|
44
|
+
* },
|
|
45
|
+
* {
|
|
46
|
+
* sessionId: "456def",
|
|
47
|
+
* name: "sentiment",
|
|
48
|
+
* label: "positive",
|
|
49
|
+
* score: 0.8,
|
|
50
|
+
* annotatorKind: "CODE"
|
|
51
|
+
* }
|
|
52
|
+
* ]
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export async function logSessionAnnotations({
|
|
57
|
+
client: _client,
|
|
58
|
+
sessionAnnotations,
|
|
59
|
+
sync = false,
|
|
60
|
+
}: LogSessionAnnotationsParams): Promise<{ id: string }[]> {
|
|
61
|
+
const client = _client ?? createClient();
|
|
62
|
+
|
|
63
|
+
const { data, error } = await client.POST("/v1/session_annotations", {
|
|
64
|
+
params: {
|
|
65
|
+
query: { sync },
|
|
66
|
+
},
|
|
67
|
+
body: {
|
|
68
|
+
data: sessionAnnotations.map(toSessionAnnotationData),
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (error) {
|
|
73
|
+
throw new Error(`Failed to log session annotations: ${error}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return data?.data || [];
|
|
77
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { paths } from "../__generated__/api/v1";
|
|
2
|
+
import { Annotation, AnnotationResult } from "../types/annotations";
|
|
3
|
+
|
|
4
|
+
type SessionAnnotationData =
|
|
5
|
+
paths["/v1/session_annotations"]["post"]["requestBody"]["content"]["application/json"]["data"][0];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Parameters for a single session annotation
|
|
9
|
+
*/
|
|
10
|
+
export interface SessionAnnotation extends Annotation {
|
|
11
|
+
/*
|
|
12
|
+
* The session ID used to track a conversation, thread, or session
|
|
13
|
+
*/
|
|
14
|
+
sessionId: string;
|
|
15
|
+
/**
|
|
16
|
+
* The entity that performed the annotation
|
|
17
|
+
*/
|
|
18
|
+
annotatorKind?: SessionAnnotationData["annotator_kind"];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Build and validate annotation result fields
|
|
23
|
+
*/
|
|
24
|
+
function buildSessionAnnotationResult(
|
|
25
|
+
annotation: Pick<SessionAnnotation, "label" | "score" | "explanation">
|
|
26
|
+
): AnnotationResult {
|
|
27
|
+
const result: AnnotationResult = {};
|
|
28
|
+
|
|
29
|
+
// Build result with trimming for string fields
|
|
30
|
+
if (annotation.label !== undefined) {
|
|
31
|
+
result.label = annotation.label.trim() || null;
|
|
32
|
+
}
|
|
33
|
+
if (annotation.score !== undefined) {
|
|
34
|
+
result.score = annotation.score;
|
|
35
|
+
}
|
|
36
|
+
if (annotation.explanation !== undefined) {
|
|
37
|
+
result.explanation = annotation.explanation.trim() || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Validate that at least one result field is provided
|
|
41
|
+
const hasValidResult =
|
|
42
|
+
result.label || result.score !== undefined || result.explanation;
|
|
43
|
+
if (!hasValidResult) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`At least one of label, score, or explanation must be provided for session annotation`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Convert a SessionAnnotation to the API format
|
|
53
|
+
*/
|
|
54
|
+
export function toSessionAnnotationData(
|
|
55
|
+
annotation: SessionAnnotation
|
|
56
|
+
): SessionAnnotationData {
|
|
57
|
+
const result = buildSessionAnnotationResult(annotation);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
session_id: annotation.sessionId.trim(),
|
|
61
|
+
name: annotation.name.trim(),
|
|
62
|
+
annotator_kind: annotation.annotatorKind ?? "HUMAN",
|
|
63
|
+
result,
|
|
64
|
+
metadata: annotation.metadata ?? null,
|
|
65
|
+
identifier: annotation.identifier?.trim() ?? "",
|
|
66
|
+
};
|
|
67
|
+
}
|
package/src/spans/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { paths } from "../__generated__/api/v1";
|
|
2
|
+
import { Annotation } from "../types/annotations";
|
|
2
3
|
|
|
3
4
|
type SpanAnnotationData =
|
|
4
5
|
paths["/v1/span_annotations"]["post"]["requestBody"]["content"]["application/json"]["data"][0];
|
|
@@ -9,35 +10,11 @@ type SpanDocumentAnnotationData =
|
|
|
9
10
|
/**
|
|
10
11
|
* Parameters for a single span annotation
|
|
11
12
|
*/
|
|
12
|
-
export interface SpanAnnotation {
|
|
13
|
+
export interface SpanAnnotation extends Annotation {
|
|
13
14
|
/**
|
|
14
15
|
* The OpenTelemetry Span ID (hex format without 0x prefix)
|
|
15
16
|
*/
|
|
16
17
|
spanId: string;
|
|
17
|
-
/**
|
|
18
|
-
* The name of the annotation
|
|
19
|
-
*/
|
|
20
|
-
name: string;
|
|
21
|
-
/**
|
|
22
|
-
* The label assigned by the annotation
|
|
23
|
-
*/
|
|
24
|
-
label?: string;
|
|
25
|
-
/**
|
|
26
|
-
* The score assigned by the annotation
|
|
27
|
-
*/
|
|
28
|
-
score?: number;
|
|
29
|
-
/**
|
|
30
|
-
* Explanation of the annotation result
|
|
31
|
-
*/
|
|
32
|
-
explanation?: string;
|
|
33
|
-
/**
|
|
34
|
-
* The identifier of the annotation. If provided, the annotation will be updated if it already exists.
|
|
35
|
-
*/
|
|
36
|
-
identifier?: string;
|
|
37
|
-
/**
|
|
38
|
-
* Metadata for the annotation
|
|
39
|
-
*/
|
|
40
|
-
metadata?: Record<string, unknown>;
|
|
41
18
|
/**
|
|
42
19
|
* The kind of annotator used for the annotation
|
|
43
20
|
* Can be "HUMAN", "LLM", or "CODE"
|
|
@@ -49,35 +26,11 @@ export interface SpanAnnotation {
|
|
|
49
26
|
/**
|
|
50
27
|
* Parameters for a single document annotation
|
|
51
28
|
*/
|
|
52
|
-
export interface DocumentAnnotation {
|
|
53
|
-
/**
|
|
54
|
-
* The OpenTelemetry Span ID (hex format without 0x prefix)
|
|
55
|
-
*/
|
|
56
|
-
spanId: string;
|
|
29
|
+
export interface DocumentAnnotation extends SpanAnnotation {
|
|
57
30
|
/**
|
|
58
31
|
* The 0-based index of the document within the span
|
|
59
32
|
*/
|
|
60
33
|
documentPosition: number;
|
|
61
|
-
/**
|
|
62
|
-
* The name of the annotation
|
|
63
|
-
*/
|
|
64
|
-
name: string;
|
|
65
|
-
/**
|
|
66
|
-
* The label assigned by the annotation
|
|
67
|
-
*/
|
|
68
|
-
label?: string;
|
|
69
|
-
/**
|
|
70
|
-
* The score assigned by the annotation
|
|
71
|
-
*/
|
|
72
|
-
score?: number;
|
|
73
|
-
/**
|
|
74
|
-
* Explanation of the annotation result
|
|
75
|
-
*/
|
|
76
|
-
explanation?: string;
|
|
77
|
-
/**
|
|
78
|
-
* Metadata for the annotation
|
|
79
|
-
*/
|
|
80
|
-
metadata?: Record<string, unknown>;
|
|
81
34
|
/**
|
|
82
35
|
* The kind of annotator used for the annotation
|
|
83
36
|
* Can be "HUMAN", "LLM", or "CODE"
|
package/src/types/annotations.ts
CHANGED
|
@@ -2,3 +2,42 @@ import { components } from "../__generated__/api/v1";
|
|
|
2
2
|
|
|
3
3
|
export type AnnotatorKind =
|
|
4
4
|
components["schemas"]["SpanAnnotationData"]["annotator_kind"];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The result of an annotation from an author (e.x. an LLM or human)
|
|
8
|
+
*/
|
|
9
|
+
export type AnnotationResult = {
|
|
10
|
+
label?: string | null;
|
|
11
|
+
score?: number | null;
|
|
12
|
+
explanation?: string | null;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The base interface for all kinds of annotations (span, trace, session)
|
|
17
|
+
*/
|
|
18
|
+
export interface Annotation {
|
|
19
|
+
/**
|
|
20
|
+
* The name of the annotation
|
|
21
|
+
*/
|
|
22
|
+
name: string;
|
|
23
|
+
/**
|
|
24
|
+
* The label assigned by the annotation
|
|
25
|
+
*/
|
|
26
|
+
label?: string;
|
|
27
|
+
/**
|
|
28
|
+
* The score assigned by the annotation
|
|
29
|
+
*/
|
|
30
|
+
score?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Explanation of the annotation result
|
|
33
|
+
*/
|
|
34
|
+
explanation?: string;
|
|
35
|
+
/**
|
|
36
|
+
* The identifier of the annotation. If provided, the annotation will be updated if it already exists.
|
|
37
|
+
*/
|
|
38
|
+
identifier?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Metadata for the annotation
|
|
41
|
+
*/
|
|
42
|
+
metadata?: Record<string, unknown>;
|
|
43
|
+
}
|