@arizeai/phoenix-client 6.10.0 → 6.11.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 +62 -0
- package/dist/esm/__generated__/api/v1.d.ts +452 -28
- package/dist/esm/__generated__/api/v1.d.ts.map +1 -1
- package/dist/esm/experiments/helpers/getExampleGlobalId.d.ts +8 -0
- package/dist/esm/experiments/helpers/getExampleGlobalId.d.ts.map +1 -0
- package/dist/esm/experiments/helpers/getExampleGlobalId.js +9 -0
- package/dist/esm/experiments/helpers/getExampleGlobalId.js.map +1 -0
- package/dist/esm/experiments/resumeEvaluation.d.ts.map +1 -1
- package/dist/esm/experiments/resumeEvaluation.js +2 -1
- 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 +3 -2
- 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 +6 -3
- package/dist/esm/experiments/runExperiment.js.map +1 -1
- package/dist/esm/jest/index.d.ts +5 -0
- package/dist/esm/jest/index.d.ts.map +1 -0
- package/dist/esm/jest/index.js +49 -0
- package/dist/esm/jest/index.js.map +1 -0
- package/dist/esm/jest/reporter.d.ts +13 -0
- package/dist/esm/jest/reporter.d.ts.map +1 -0
- package/dist/esm/jest/reporter.js +19 -0
- package/dist/esm/jest/reporter.js.map +1 -0
- package/dist/esm/prompts/sdks/toAI.d.ts +2 -2
- package/dist/esm/prompts/sdks/toAI.d.ts.map +1 -1
- package/dist/esm/prompts/sdks/toAI.js.map +1 -1
- package/dist/esm/prompts/sdks/toAnthropic.d.ts +2 -2
- package/dist/esm/prompts/sdks/toAnthropic.d.ts.map +1 -1
- package/dist/esm/prompts/sdks/toAnthropic.js.map +1 -1
- package/dist/esm/prompts/sdks/toOpenAI.d.ts +2 -2
- package/dist/esm/prompts/sdks/toOpenAI.d.ts.map +1 -1
- package/dist/esm/prompts/sdks/toOpenAI.js.map +1 -1
- package/dist/esm/prompts/sdks/toSDK.d.ts +8 -8
- package/dist/esm/prompts/sdks/toSDK.d.ts.map +1 -1
- package/dist/esm/prompts/sdks/toSDK.js.map +1 -1
- package/dist/esm/prompts/sdks/types.d.ts +2 -2
- package/dist/esm/prompts/sdks/types.d.ts.map +1 -1
- package/dist/esm/schemas/llm/anthropic/converters.d.ts +8 -8
- package/dist/esm/schemas/llm/anthropic/messagePartSchemas.d.ts +4 -4
- package/dist/esm/schemas/llm/anthropic/messageSchemas.d.ts +6 -6
- package/dist/esm/schemas/llm/constants.d.ts +3 -3
- package/dist/esm/schemas/llm/converters.d.ts +12 -12
- package/dist/esm/schemas/llm/openai/converters.d.ts +3 -3
- package/dist/esm/schemas/llm/schemas.d.ts +2 -2
- package/dist/esm/testing/acceptance.d.ts +20 -0
- package/dist/esm/testing/acceptance.d.ts.map +1 -0
- package/dist/esm/testing/acceptance.js +129 -0
- package/dist/esm/testing/acceptance.js.map +1 -0
- package/dist/esm/testing/define-api.d.ts +157 -0
- package/dist/esm/testing/define-api.d.ts.map +1 -0
- package/dist/esm/testing/define-api.js +78 -0
- package/dist/esm/testing/define-api.js.map +1 -0
- package/dist/esm/testing/helpers.d.ts +55 -0
- package/dist/esm/testing/helpers.d.ts.map +1 -0
- package/dist/esm/testing/helpers.js +179 -0
- package/dist/esm/testing/helpers.js.map +1 -0
- package/dist/esm/testing/phoenix-test-tracking.d.ts +68 -0
- package/dist/esm/testing/phoenix-test-tracking.d.ts.map +1 -0
- package/dist/esm/testing/phoenix-test-tracking.js +521 -0
- package/dist/esm/testing/phoenix-test-tracking.js.map +1 -0
- package/dist/esm/testing/report-artifacts.d.ts +45 -0
- package/dist/esm/testing/report-artifacts.d.ts.map +1 -0
- package/dist/esm/testing/report-artifacts.js +218 -0
- package/dist/esm/testing/report-artifacts.js.map +1 -0
- package/dist/esm/testing/report-run.d.ts +22 -0
- package/dist/esm/testing/report-run.d.ts.map +1 -0
- package/dist/esm/testing/report-run.js +41 -0
- package/dist/esm/testing/report-run.js.map +1 -0
- package/dist/esm/testing/reporter-format.d.ts +83 -0
- package/dist/esm/testing/reporter-format.d.ts.map +1 -0
- package/dist/esm/testing/reporter-format.js +852 -0
- package/dist/esm/testing/reporter-format.js.map +1 -0
- package/dist/esm/testing/runner.d.ts +31 -0
- package/dist/esm/testing/runner.d.ts.map +1 -0
- package/dist/esm/testing/runner.js +238 -0
- package/dist/esm/testing/runner.js.map +1 -0
- package/dist/esm/testing/state.d.ts +138 -0
- package/dist/esm/testing/state.d.ts.map +1 -0
- package/dist/esm/testing/state.js +31 -0
- package/dist/esm/testing/state.js.map +1 -0
- package/dist/esm/testing/types.d.ts +319 -0
- package/dist/esm/testing/types.d.ts.map +1 -0
- package/dist/esm/testing/types.js +9 -0
- package/dist/esm/testing/types.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/utils/channel.d.ts +7 -7
- package/dist/esm/utils/channel.d.ts.map +1 -1
- package/dist/esm/utils/channel.js +1 -1
- package/dist/esm/utils/channel.js.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/esm/utils/promisifyResult.d.ts +1 -1
- package/dist/esm/utils/promisifyResult.d.ts.map +1 -1
- package/dist/esm/utils/promisifyResult.js.map +1 -1
- package/dist/esm/utils/schemaMatches.d.ts +5 -5
- package/dist/esm/utils/schemaMatches.d.ts.map +1 -1
- package/dist/esm/utils/schemaMatches.js.map +1 -1
- package/dist/esm/vitest/index.d.ts +5 -0
- package/dist/esm/vitest/index.d.ts.map +1 -0
- package/dist/esm/vitest/index.js +15 -0
- package/dist/esm/vitest/index.js.map +1 -0
- package/dist/esm/vitest/reporter.d.ts +19 -0
- package/dist/esm/vitest/reporter.d.ts.map +1 -0
- package/dist/esm/vitest/reporter.js +27 -0
- package/dist/esm/vitest/reporter.js.map +1 -0
- package/dist/src/__generated__/api/v1.d.ts +452 -28
- package/dist/src/__generated__/api/v1.d.ts.map +1 -1
- package/dist/src/experiments/helpers/getExampleGlobalId.d.ts +8 -0
- package/dist/src/experiments/helpers/getExampleGlobalId.d.ts.map +1 -0
- package/dist/src/experiments/helpers/getExampleGlobalId.js +13 -0
- package/dist/src/experiments/helpers/getExampleGlobalId.js.map +1 -0
- package/dist/src/experiments/resumeEvaluation.d.ts.map +1 -1
- package/dist/src/experiments/resumeEvaluation.js +2 -1
- 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 +3 -2
- 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 +6 -3
- package/dist/src/experiments/runExperiment.js.map +1 -1
- package/dist/src/jest/index.d.ts +5 -0
- package/dist/src/jest/index.d.ts.map +1 -0
- package/dist/src/jest/index.js +58 -0
- package/dist/src/jest/index.js.map +1 -0
- package/dist/src/jest/reporter.d.ts +13 -0
- package/dist/src/jest/reporter.d.ts.map +1 -0
- package/dist/src/jest/reporter.js +23 -0
- package/dist/src/jest/reporter.js.map +1 -0
- package/dist/src/prompts/sdks/toAI.d.ts +2 -2
- package/dist/src/prompts/sdks/toAI.d.ts.map +1 -1
- package/dist/src/prompts/sdks/toAI.js.map +1 -1
- package/dist/src/prompts/sdks/toAnthropic.d.ts +2 -2
- package/dist/src/prompts/sdks/toAnthropic.d.ts.map +1 -1
- package/dist/src/prompts/sdks/toAnthropic.js.map +1 -1
- package/dist/src/prompts/sdks/toOpenAI.d.ts +2 -2
- package/dist/src/prompts/sdks/toOpenAI.d.ts.map +1 -1
- package/dist/src/prompts/sdks/toOpenAI.js.map +1 -1
- package/dist/src/prompts/sdks/toSDK.d.ts +8 -8
- package/dist/src/prompts/sdks/toSDK.d.ts.map +1 -1
- package/dist/src/prompts/sdks/toSDK.js.map +1 -1
- package/dist/src/prompts/sdks/types.d.ts +2 -2
- package/dist/src/prompts/sdks/types.d.ts.map +1 -1
- package/dist/src/schemas/llm/anthropic/converters.d.ts +8 -8
- package/dist/src/schemas/llm/anthropic/messagePartSchemas.d.ts +4 -4
- package/dist/src/schemas/llm/anthropic/messageSchemas.d.ts +6 -6
- package/dist/src/schemas/llm/constants.d.ts +3 -3
- package/dist/src/schemas/llm/converters.d.ts +12 -12
- package/dist/src/schemas/llm/openai/converters.d.ts +3 -3
- package/dist/src/schemas/llm/schemas.d.ts +2 -2
- package/dist/src/testing/acceptance.d.ts +20 -0
- package/dist/src/testing/acceptance.d.ts.map +1 -0
- package/dist/src/testing/acceptance.js +114 -0
- package/dist/src/testing/acceptance.js.map +1 -0
- package/dist/src/testing/define-api.d.ts +157 -0
- package/dist/src/testing/define-api.d.ts.map +1 -0
- package/dist/src/testing/define-api.js +81 -0
- package/dist/src/testing/define-api.js.map +1 -0
- package/dist/src/testing/helpers.d.ts +55 -0
- package/dist/src/testing/helpers.d.ts.map +1 -0
- package/dist/src/testing/helpers.js +182 -0
- package/dist/src/testing/helpers.js.map +1 -0
- package/dist/src/testing/phoenix-test-tracking.d.ts +68 -0
- package/dist/src/testing/phoenix-test-tracking.d.ts.map +1 -0
- package/dist/src/testing/phoenix-test-tracking.js +530 -0
- package/dist/src/testing/phoenix-test-tracking.js.map +1 -0
- package/dist/src/testing/report-artifacts.d.ts +45 -0
- package/dist/src/testing/report-artifacts.d.ts.map +1 -0
- package/dist/src/testing/report-artifacts.js +225 -0
- package/dist/src/testing/report-artifacts.js.map +1 -0
- package/dist/src/testing/report-run.d.ts +22 -0
- package/dist/src/testing/report-run.d.ts.map +1 -0
- package/dist/src/testing/report-run.js +47 -0
- package/dist/src/testing/report-run.js.map +1 -0
- package/dist/src/testing/reporter-format.d.ts +83 -0
- package/dist/src/testing/reporter-format.d.ts.map +1 -0
- package/dist/src/testing/reporter-format.js +870 -0
- package/dist/src/testing/reporter-format.js.map +1 -0
- package/dist/src/testing/runner.d.ts +31 -0
- package/dist/src/testing/runner.d.ts.map +1 -0
- package/dist/src/testing/runner.js +258 -0
- package/dist/src/testing/runner.js.map +1 -0
- package/dist/src/testing/state.d.ts +138 -0
- package/dist/src/testing/state.d.ts.map +1 -0
- package/dist/src/testing/state.js +38 -0
- package/dist/src/testing/state.js.map +1 -0
- package/dist/src/testing/types.d.ts +319 -0
- package/dist/src/testing/types.d.ts.map +1 -0
- package/dist/src/testing/types.js +13 -0
- package/dist/src/testing/types.js.map +1 -0
- package/dist/src/utils/channel.d.ts +7 -7
- package/dist/src/utils/channel.d.ts.map +1 -1
- package/dist/src/utils/channel.js +1 -1
- package/dist/src/utils/channel.js.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/src/utils/promisifyResult.d.ts +1 -1
- package/dist/src/utils/promisifyResult.d.ts.map +1 -1
- package/dist/src/utils/promisifyResult.js.map +1 -1
- package/dist/src/utils/schemaMatches.d.ts +5 -5
- package/dist/src/utils/schemaMatches.d.ts.map +1 -1
- package/dist/src/utils/schemaMatches.js.map +1 -1
- package/dist/src/vitest/index.d.ts +5 -0
- package/dist/src/vitest/index.d.ts.map +1 -0
- package/dist/src/vitest/index.js +23 -0
- package/dist/src/vitest/index.js.map +1 -0
- package/dist/src/vitest/reporter.d.ts +19 -0
- package/dist/src/vitest/reporter.d.ts.map +1 -0
- package/dist/src/vitest/reporter.js +34 -0
- package/dist/src/vitest/reporter.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/ci-evals-annotations.mdx +190 -0
- package/docs/ci-evals-jest.mdx +78 -0
- package/docs/ci-evals-vitest.mdx +240 -0
- package/docs/ci-evals.mdx +263 -0
- package/docs/overview.mdx +9 -1
- package/package.json +49 -17
- package/src/__generated__/api/v1.ts +452 -28
- package/src/experiments/helpers/getExampleGlobalId.ts +12 -0
- package/src/experiments/resumeEvaluation.ts +2 -1
- package/src/experiments/resumeExperiment.ts +3 -2
- package/src/experiments/runExperiment.ts +6 -3
- package/src/jest/index.ts +124 -0
- package/src/jest/reporter.ts +22 -0
- package/src/prompts/sdks/toAI.ts +4 -3
- package/src/prompts/sdks/toAnthropic.ts +4 -3
- package/src/prompts/sdks/toOpenAI.ts +4 -3
- package/src/prompts/sdks/toSDK.ts +16 -11
- package/src/prompts/sdks/types.ts +2 -2
- package/src/testing/acceptance.ts +190 -0
- package/src/testing/define-api.ts +279 -0
- package/src/testing/helpers.ts +251 -0
- package/src/testing/phoenix-test-tracking.ts +637 -0
- package/src/testing/report-artifacts.ts +272 -0
- package/src/testing/report-run.ts +44 -0
- package/src/testing/reporter-format.ts +1072 -0
- package/src/testing/runner.ts +350 -0
- package/src/testing/state.ts +165 -0
- package/src/testing/types.ts +366 -0
- package/src/utils/channel.ts +17 -15
- package/src/utils/promisifyResult.ts +6 -4
- package/src/utils/schemaMatches.ts +12 -10
- package/src/vitest/index.ts +57 -0
- package/src/vitest/reporter.ts +32 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ExampleWithId } from "../../types/datasets";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The example's node GlobalID, which experiment runs record as their
|
|
5
|
+
* `dataset_example_id`. Servers that predate the `nodeId` field deliver the
|
|
6
|
+
* GlobalID in the `id` field instead.
|
|
7
|
+
*/
|
|
8
|
+
export function getExampleGlobalId(
|
|
9
|
+
example: Pick<ExampleWithId, "id"> & Partial<Pick<ExampleWithId, "nodeId">>
|
|
10
|
+
): string {
|
|
11
|
+
return example.nodeId ?? example.id;
|
|
12
|
+
}
|
|
@@ -29,6 +29,7 @@ import { ensureString } from "../utils/ensureString";
|
|
|
29
29
|
import { toObjectHeaders } from "../utils/toObjectHeaders";
|
|
30
30
|
import { getExperimentInfo } from "./getExperimentInfo.js";
|
|
31
31
|
import { getExperimentEvaluators } from "./helpers";
|
|
32
|
+
import { getExampleGlobalId } from "./helpers/getExampleGlobalId";
|
|
32
33
|
import { logEvalResumeSummary, PROGRESS_PREFIX } from "./logging";
|
|
33
34
|
import { cleanupOwnedTracerProvider } from "./tracing";
|
|
34
35
|
|
|
@@ -729,7 +730,7 @@ async function runSingleEvaluation({
|
|
|
729
730
|
...objectAsAttributes({
|
|
730
731
|
experiment_id: experimentId,
|
|
731
732
|
experiment_run_id: experimentRun.id,
|
|
732
|
-
dataset_example_id: datasetExample
|
|
733
|
+
dataset_example_id: getExampleGlobalId(datasetExample),
|
|
733
734
|
}),
|
|
734
735
|
});
|
|
735
736
|
|
|
@@ -28,6 +28,7 @@ import { isHttpErrorWithStatus } from "../utils/isHttpError";
|
|
|
28
28
|
import { toObjectHeaders } from "../utils/toObjectHeaders";
|
|
29
29
|
import { getDatasetExperimentsUrl, getExperimentUrl } from "../utils/urlUtils";
|
|
30
30
|
import { getExperimentInfo } from "./getExperimentInfo.js";
|
|
31
|
+
import { getExampleGlobalId } from "./helpers/getExampleGlobalId";
|
|
31
32
|
import {
|
|
32
33
|
logExperimentResumeSummary,
|
|
33
34
|
logLinks,
|
|
@@ -619,7 +620,7 @@ async function recordTaskResult({
|
|
|
619
620
|
},
|
|
620
621
|
},
|
|
621
622
|
body: {
|
|
622
|
-
dataset_example_id: example
|
|
623
|
+
dataset_example_id: getExampleGlobalId(example),
|
|
623
624
|
repetition_number: repetitionNumber,
|
|
624
625
|
output: output as Record<string, unknown>,
|
|
625
626
|
start_time: startTime.toISOString(),
|
|
@@ -695,7 +696,7 @@ async function runSingleTask({
|
|
|
695
696
|
[SemanticConventions.INPUT_MIME_TYPE]: MimeType.JSON,
|
|
696
697
|
...objectAsAttributes({
|
|
697
698
|
experiment_id: experimentId,
|
|
698
|
-
dataset_example_id: example
|
|
699
|
+
dataset_example_id: getExampleGlobalId(example),
|
|
699
700
|
repetition_number: repetitionNumber,
|
|
700
701
|
}),
|
|
701
702
|
});
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
} from "../utils/urlUtils";
|
|
48
48
|
import { getExperimentInfo } from "./getExperimentInfo";
|
|
49
49
|
import { getExperimentEvaluators } from "./helpers";
|
|
50
|
+
import { getExampleGlobalId } from "./helpers/getExampleGlobalId";
|
|
50
51
|
import {
|
|
51
52
|
logEvalSummary,
|
|
52
53
|
logLinks,
|
|
@@ -485,7 +486,7 @@ function runTaskWithExamples({
|
|
|
485
486
|
id: localId(), // initialized with local id, will be replaced with server-assigned id when dry run is false
|
|
486
487
|
traceId,
|
|
487
488
|
experimentId,
|
|
488
|
-
datasetExampleId: example
|
|
489
|
+
datasetExampleId: getExampleGlobalId(example),
|
|
489
490
|
startTime: new Date(),
|
|
490
491
|
endTime: new Date(), // will get replaced with actual end time
|
|
491
492
|
output: null,
|
|
@@ -509,7 +510,7 @@ function runTaskWithExamples({
|
|
|
509
510
|
},
|
|
510
511
|
},
|
|
511
512
|
body: {
|
|
512
|
-
dataset_example_id: example
|
|
513
|
+
dataset_example_id: getExampleGlobalId(example),
|
|
513
514
|
output: thisRun.output,
|
|
514
515
|
repetition_number: repetitionNumber,
|
|
515
516
|
start_time: thisRun.startTime.toISOString(),
|
|
@@ -681,9 +682,11 @@ export async function evaluateExperiment({
|
|
|
681
682
|
type EvaluationId = string;
|
|
682
683
|
const evaluationRuns: Record<EvaluationId, ExperimentEvaluationRun> = {};
|
|
683
684
|
|
|
685
|
+
// Index examples by node GlobalID, matching how runs record
|
|
686
|
+
// datasetExampleId.
|
|
684
687
|
const examplesById: Record<string, Example> = {};
|
|
685
688
|
for (const example of dataset.examples) {
|
|
686
|
-
examplesById[example
|
|
689
|
+
examplesById[getExampleGlobalId(example)] = example;
|
|
687
690
|
}
|
|
688
691
|
|
|
689
692
|
const onEvaluationComplete = (run: ExperimentEvaluationRun) => {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createTestApi } from "../testing/define-api";
|
|
2
|
+
import type { RunnerHooks } from "../testing/runner";
|
|
3
|
+
|
|
4
|
+
export type {
|
|
5
|
+
PhoenixDescribe,
|
|
6
|
+
PhoenixTest,
|
|
7
|
+
PhoenixTestApi,
|
|
8
|
+
PhoenixTestEach,
|
|
9
|
+
} from "../testing/define-api";
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
AcceptanceCriterion,
|
|
13
|
+
AcceptanceMetric,
|
|
14
|
+
AcceptanceResult,
|
|
15
|
+
Annotation,
|
|
16
|
+
AnnotatorKind,
|
|
17
|
+
EvaluationParams,
|
|
18
|
+
EvaluationResult,
|
|
19
|
+
Evaluator,
|
|
20
|
+
EvaluatorResult,
|
|
21
|
+
KVMap,
|
|
22
|
+
ReferenceOutput,
|
|
23
|
+
SuiteConfig,
|
|
24
|
+
TestArgs,
|
|
25
|
+
TestConfig,
|
|
26
|
+
TestEachRow,
|
|
27
|
+
TestFn,
|
|
28
|
+
TestParams,
|
|
29
|
+
TestParamsBase,
|
|
30
|
+
} from "../testing/types";
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
evaluate,
|
|
34
|
+
logAnnotation,
|
|
35
|
+
logOutput,
|
|
36
|
+
traceEvaluator,
|
|
37
|
+
} from "../testing/helpers";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolve jest globals lazily. Jest injects `describe`, `test`, `it`,
|
|
41
|
+
* `beforeAll`, `afterAll` onto the global object during test runs; we read
|
|
42
|
+
* them off `globalThis` so importing this module outside of a jest run
|
|
43
|
+
* doesn't error.
|
|
44
|
+
*/
|
|
45
|
+
function getJestGlobals(): {
|
|
46
|
+
describe: JestDescribe;
|
|
47
|
+
test: JestTest;
|
|
48
|
+
beforeAll: (fn: () => unknown | Promise<unknown>) => void;
|
|
49
|
+
afterAll: (fn: () => unknown | Promise<unknown>) => void;
|
|
50
|
+
} {
|
|
51
|
+
const g = globalThis as unknown as {
|
|
52
|
+
describe?: JestDescribe;
|
|
53
|
+
test?: JestTest;
|
|
54
|
+
it?: JestTest;
|
|
55
|
+
beforeAll?: (fn: () => unknown | Promise<unknown>) => void;
|
|
56
|
+
afterAll?: (fn: () => unknown | Promise<unknown>) => void;
|
|
57
|
+
};
|
|
58
|
+
if (!g.describe || !g.beforeAll || !g.afterAll) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
"@arizeai/phoenix-client/jest could not find Jest globals. Make sure this module " +
|
|
61
|
+
"is imported from inside a Jest test file."
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
const test = g.test ?? g.it;
|
|
65
|
+
if (!test) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
"@arizeai/phoenix-client/jest could not find Jest's test/it."
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
describe: g.describe,
|
|
72
|
+
test,
|
|
73
|
+
beforeAll: g.beforeAll,
|
|
74
|
+
afterAll: g.afterAll,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface JestDescribe {
|
|
79
|
+
(name: string, fn: () => void): void;
|
|
80
|
+
only: (name: string, fn: () => void) => void;
|
|
81
|
+
skip: (name: string, fn: () => void) => void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface JestTest {
|
|
85
|
+
(
|
|
86
|
+
name: string,
|
|
87
|
+
fn: (...args: unknown[]) => unknown | Promise<unknown>,
|
|
88
|
+
timeout?: number
|
|
89
|
+
): void;
|
|
90
|
+
only: (
|
|
91
|
+
name: string,
|
|
92
|
+
fn: (...args: unknown[]) => unknown | Promise<unknown>,
|
|
93
|
+
timeout?: number
|
|
94
|
+
) => void;
|
|
95
|
+
skip: (
|
|
96
|
+
name: string,
|
|
97
|
+
fn: (...args: unknown[]) => unknown | Promise<unknown>,
|
|
98
|
+
timeout?: number
|
|
99
|
+
) => void;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Build the runner hooks from the (lazily-resolved) jest globals. Memoized so
|
|
104
|
+
* repeated declarations don't re-read `globalThis` on every call; jest injects
|
|
105
|
+
* its globals once per worker before any test file is evaluated.
|
|
106
|
+
*/
|
|
107
|
+
let cachedHooks: RunnerHooks | undefined;
|
|
108
|
+
function getHooks(): RunnerHooks {
|
|
109
|
+
if (cachedHooks) return cachedHooks;
|
|
110
|
+
const g = getJestGlobals();
|
|
111
|
+
cachedHooks = {
|
|
112
|
+
describe: (name, fn) => g.describe(name, fn),
|
|
113
|
+
describeOnly: (name, fn) => g.describe.only(name, fn),
|
|
114
|
+
describeSkip: (name, fn) => g.describe.skip(name, fn),
|
|
115
|
+
test: (name, fn, timeout) => g.test(name, fn, timeout),
|
|
116
|
+
testOnly: (name, fn, timeout) => g.test.only(name, fn, timeout),
|
|
117
|
+
testSkip: (name, fn, timeout) => g.test.skip(name, fn, timeout),
|
|
118
|
+
beforeAll: (fn) => g.beforeAll(fn),
|
|
119
|
+
afterAll: (fn) => g.afterAll(fn),
|
|
120
|
+
};
|
|
121
|
+
return cachedHooks;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const { describe, test, it } = createTestApi(getHooks);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SuiteSummaryReportRun } from "../testing/report-run";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Jest reporter for `@arizeai/phoenix-client/jest`.
|
|
5
|
+
*
|
|
6
|
+
* Like the Vitest reporter, this does not replace Jest's default output. It
|
|
7
|
+
* appends a Phoenix summary block at the end of the run.
|
|
8
|
+
*/
|
|
9
|
+
export default class PhoenixJestReporter {
|
|
10
|
+
private readonly report = new SuiteSummaryReportRun();
|
|
11
|
+
|
|
12
|
+
// jest passes globalConfig + reporterOptions; we ignore both
|
|
13
|
+
constructor(_globalConfig?: unknown, _reporterOptions?: unknown) {}
|
|
14
|
+
|
|
15
|
+
onRunStart(): void {
|
|
16
|
+
this.report.begin();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
onRunComplete(): void {
|
|
20
|
+
this.report.finish();
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/prompts/sdks/toAI.ts
CHANGED
|
@@ -40,7 +40,8 @@ The tool choice strategy. Default: 'auto'.
|
|
|
40
40
|
toolChoice?: ToolChoice<ToolSet>;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
export type ToAIParams<
|
|
43
|
+
export type ToAIParams<PromptVariables extends Variables> =
|
|
44
|
+
toSDKParamsBase<PromptVariables>;
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* Converts a Phoenix prompt to Vercel AI sdk params.
|
|
@@ -48,10 +49,10 @@ export type ToAIParams<V extends Variables> = toSDKParamsBase<V>;
|
|
|
48
49
|
* - note: To use response format, you must pass `prompt.response_format.json_schema.schema` to generateObject or streamObject
|
|
49
50
|
* via `jsonSchema()`, through the `schema` argument.
|
|
50
51
|
*/
|
|
51
|
-
export const toAI = <
|
|
52
|
+
export const toAI = <PromptVariables extends Variables>({
|
|
52
53
|
prompt,
|
|
53
54
|
variables,
|
|
54
|
-
}: ToAIParams<
|
|
55
|
+
}: ToAIParams<PromptVariables>): PartialAIParams | null => {
|
|
55
56
|
// eslint-disable-next-line no-console
|
|
56
57
|
console.warn(
|
|
57
58
|
"Prompt invocation parameters not currently supported in AI SDK, falling back to default invocation parameters"
|
|
@@ -14,15 +14,16 @@ import type { toSDKParamsBase, Variables } from "./types";
|
|
|
14
14
|
// We must re-export these types so that they are included in the phoenix-client distribution
|
|
15
15
|
export type { MessageCreateParams };
|
|
16
16
|
|
|
17
|
-
export type ToAnthropicParams<
|
|
17
|
+
export type ToAnthropicParams<PromptVariables extends Variables> =
|
|
18
|
+
toSDKParamsBase<PromptVariables>;
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Convert a Phoenix prompt to Anthropic client sdk's message create parameters
|
|
21
22
|
*/
|
|
22
|
-
export const toAnthropic = <
|
|
23
|
+
export const toAnthropic = <PromptVariables extends Variables = Variables>({
|
|
23
24
|
prompt,
|
|
24
25
|
variables,
|
|
25
|
-
}: ToAnthropicParams<
|
|
26
|
+
}: ToAnthropicParams<PromptVariables>): MessageCreateParams | null => {
|
|
26
27
|
try {
|
|
27
28
|
let invocationParameters: { max_tokens: number } | undefined;
|
|
28
29
|
if (prompt.invocation_parameters.type === "anthropic") {
|
|
@@ -23,17 +23,18 @@ export type {
|
|
|
23
23
|
ResponseFormatJSONSchema,
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
export type ToOpenAIParams<
|
|
26
|
+
export type ToOpenAIParams<PromptVariables extends Variables> =
|
|
27
|
+
toSDKParamsBase<PromptVariables>;
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Convert a Phoenix prompt to OpenAI client sdk's chat completion parameters
|
|
30
31
|
*
|
|
31
32
|
* @returns The converted chat completion parameters
|
|
32
33
|
*/
|
|
33
|
-
export const toOpenAI = <
|
|
34
|
+
export const toOpenAI = <PromptVariables extends Variables = Variables>({
|
|
34
35
|
prompt,
|
|
35
36
|
variables,
|
|
36
|
-
}: ToOpenAIParams<
|
|
37
|
+
}: ToOpenAIParams<PromptVariables>): ChatCompletionCreateParams | null => {
|
|
37
38
|
try {
|
|
38
39
|
let invocationParameters: Partial<ChatCompletionCreateParams>;
|
|
39
40
|
switch (prompt.invocation_parameters.type) {
|
|
@@ -15,10 +15,10 @@ import type { SupportedSDK, toSDKParamsBase, Variables } from "./types";
|
|
|
15
15
|
* toOpenAI(params)
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
|
-
export type SDKParams<
|
|
19
|
-
(typeof PROVIDER_TO_SDK)[
|
|
18
|
+
export type SDKParams<SDK extends SupportedSDK> = Parameters<
|
|
19
|
+
(typeof PROVIDER_TO_SDK)[SDK]
|
|
20
20
|
>[number] extends toSDKParamsBase
|
|
21
|
-
? Parameters<(typeof PROVIDER_TO_SDK)[
|
|
21
|
+
? Parameters<(typeof PROVIDER_TO_SDK)[SDK]>[number]
|
|
22
22
|
: never;
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -33,7 +33,7 @@ export const PROVIDER_TO_SDK = {
|
|
|
33
33
|
/**
|
|
34
34
|
* Get the conversion function for a specific SDK name
|
|
35
35
|
*/
|
|
36
|
-
const getTargetSDK = <
|
|
36
|
+
const getTargetSDK = <SDK extends SupportedSDK>(sdk: SDK) => {
|
|
37
37
|
switch (sdk) {
|
|
38
38
|
case "openai":
|
|
39
39
|
return PROVIDER_TO_SDK.openai;
|
|
@@ -50,19 +50,19 @@ const getTargetSDK = <T extends SupportedSDK>(sdk: T) => {
|
|
|
50
50
|
* Parameters specific to the toSDK function
|
|
51
51
|
*/
|
|
52
52
|
export type ToSDKParams<
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
SDK extends SupportedSDK,
|
|
54
|
+
PromptVariables extends Variables = Variables,
|
|
55
55
|
> = {
|
|
56
56
|
/**
|
|
57
57
|
* String representing the SDK to convert to
|
|
58
58
|
*/
|
|
59
|
-
sdk:
|
|
59
|
+
sdk: SDK;
|
|
60
60
|
/**
|
|
61
61
|
* Optional variables to format the prompt with
|
|
62
62
|
* Keys are the variable names, values are the variable values
|
|
63
63
|
* The variable format is determined via prompt.template_format
|
|
64
64
|
*/
|
|
65
|
-
variables?:
|
|
65
|
+
variables?: PromptVariables;
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
/**
|
|
@@ -86,11 +86,16 @@ export type ToSDKParams<
|
|
|
86
86
|
* @param params - The parameters to convert a prompt to an SDK's parameters
|
|
87
87
|
* @returns The SDK's parameters
|
|
88
88
|
*/
|
|
89
|
-
export const toSDK = <
|
|
89
|
+
export const toSDK = <
|
|
90
|
+
SDK extends SupportedSDK,
|
|
91
|
+
PromptVariables extends Variables = Variables,
|
|
92
|
+
>({
|
|
90
93
|
sdk: _sdk,
|
|
91
94
|
...rest
|
|
92
|
-
}: ToSDKParams<
|
|
95
|
+
}: ToSDKParams<SDK, PromptVariables> & SDKParams<SDK>) => {
|
|
93
96
|
const sdk = getTargetSDK(_sdk);
|
|
94
97
|
invariant(sdk, `No SDK found for provider ${_sdk}`);
|
|
95
|
-
return sdk<
|
|
98
|
+
return sdk<PromptVariables>(rest) as ReturnType<
|
|
99
|
+
(typeof PROVIDER_TO_SDK)[SDK]
|
|
100
|
+
>;
|
|
96
101
|
};
|
|
@@ -11,7 +11,7 @@ export type Variables = Record<string, string | { toString: () => string }>;
|
|
|
11
11
|
/**
|
|
12
12
|
* Base parameters for an SDK conversion function
|
|
13
13
|
*/
|
|
14
|
-
export type toSDKParamsBase<
|
|
14
|
+
export type toSDKParamsBase<PromptVariables extends Variables = Variables> = {
|
|
15
15
|
/**
|
|
16
16
|
* The Phoenix prompt to convert
|
|
17
17
|
*/
|
|
@@ -19,7 +19,7 @@ export type toSDKParamsBase<V extends Variables = Variables> = {
|
|
|
19
19
|
/**
|
|
20
20
|
* The variables to use in the prompt
|
|
21
21
|
*/
|
|
22
|
-
variables?:
|
|
22
|
+
variables?: PromptVariables;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type { TestResult } from "./state";
|
|
2
|
+
import type {
|
|
3
|
+
AcceptanceCriterion,
|
|
4
|
+
AcceptanceResult,
|
|
5
|
+
Annotation,
|
|
6
|
+
OptimizationDirection,
|
|
7
|
+
} from "./types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Evaluate all configured aggregate acceptance rules against completed runs.
|
|
11
|
+
* @param params - Evaluation parameters.
|
|
12
|
+
* @param params.criteria - Aggregate rules configured on the suite.
|
|
13
|
+
* @param params.results - Completed test results in the suite.
|
|
14
|
+
*/
|
|
15
|
+
export function evaluateAcceptanceCriteria({
|
|
16
|
+
criteria,
|
|
17
|
+
results,
|
|
18
|
+
}: {
|
|
19
|
+
criteria: readonly AcceptanceCriterion[] | undefined;
|
|
20
|
+
results: readonly TestResult[];
|
|
21
|
+
}): AcceptanceResult[] {
|
|
22
|
+
if (!criteria || criteria.length === 0) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
return criteria.map((criterion) =>
|
|
26
|
+
evaluateAcceptanceCriterion({ criterion, results })
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Build one error containing every failed aggregate criterion.
|
|
32
|
+
* @param results - Computed acceptance results.
|
|
33
|
+
*/
|
|
34
|
+
export function createAcceptanceFailureError(
|
|
35
|
+
results: readonly AcceptanceResult[]
|
|
36
|
+
): Error | undefined {
|
|
37
|
+
const failedResults = results.filter((result) => !result.passed);
|
|
38
|
+
if (failedResults.length === 0) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return new Error(
|
|
42
|
+
[
|
|
43
|
+
"Acceptance criteria failed:",
|
|
44
|
+
...failedResults.map((result) => ` ${formatAcceptanceResult(result)}`),
|
|
45
|
+
].join("\n")
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Format an acceptance result for reporters and thrown errors. */
|
|
50
|
+
export function formatAcceptanceResult(result: AcceptanceResult): string {
|
|
51
|
+
const status = result.passed ? "PASS" : "FAIL";
|
|
52
|
+
const value = result.value === null ? "n/a" : result.value.toFixed(3);
|
|
53
|
+
const sampleLabel = result.sampleCount === 1 ? "sample" : "samples";
|
|
54
|
+
let requirement: string;
|
|
55
|
+
if (result.metric === "average") {
|
|
56
|
+
const cmp = (result.direction ?? "maximize") === "minimize" ? "<=" : ">=";
|
|
57
|
+
requirement = `mean ${cmp} ${result.threshold.toFixed(3)}`;
|
|
58
|
+
} else {
|
|
59
|
+
requirement = `pass rate >= ${result.minPassRate.toFixed(3)}`;
|
|
60
|
+
}
|
|
61
|
+
const reason = result.failureReason ? ` - ${result.failureReason}` : "";
|
|
62
|
+
return `${status} ${result.annotationName} ${result.metric} ${value} (need ${requirement}; ${result.sampleCount} ${sampleLabel})${reason}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function evaluateAcceptanceCriterion({
|
|
66
|
+
criterion,
|
|
67
|
+
results,
|
|
68
|
+
}: {
|
|
69
|
+
criterion: AcceptanceCriterion;
|
|
70
|
+
results: readonly TestResult[];
|
|
71
|
+
}): AcceptanceResult {
|
|
72
|
+
const annotations = collectAnnotations({ criterion, results });
|
|
73
|
+
|
|
74
|
+
if (criterion.metric === "average") {
|
|
75
|
+
// Only numeric / boolean scores can be averaged.
|
|
76
|
+
const scores = annotations
|
|
77
|
+
.map((annotation) => annotation.score)
|
|
78
|
+
.filter(isValidScore);
|
|
79
|
+
if (scores.length === 0) {
|
|
80
|
+
return {
|
|
81
|
+
...criterion,
|
|
82
|
+
value: null,
|
|
83
|
+
sampleCount: 0,
|
|
84
|
+
passed: false,
|
|
85
|
+
failureReason: "no numeric or boolean scores found",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const direction = criterion.direction ?? "maximize";
|
|
89
|
+
const value = calculateAverage(scores);
|
|
90
|
+
return {
|
|
91
|
+
...criterion,
|
|
92
|
+
value,
|
|
93
|
+
sampleCount: scores.length,
|
|
94
|
+
passed: meetsBar(value, criterion.threshold, direction),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// passRate: each run passes when `passFn` returns true for its annotation;
|
|
99
|
+
// the suite passes when the fraction of passing runs is at least
|
|
100
|
+
// `minPassRate`. The reported value is that fraction.
|
|
101
|
+
if (annotations.length === 0) {
|
|
102
|
+
return {
|
|
103
|
+
...criterion,
|
|
104
|
+
value: null,
|
|
105
|
+
sampleCount: 0,
|
|
106
|
+
passed: false,
|
|
107
|
+
failureReason: "no matching annotations found",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const passed = annotations.filter((annotation) =>
|
|
111
|
+
criterion.passFn(annotation)
|
|
112
|
+
).length;
|
|
113
|
+
const value = passed / annotations.length;
|
|
114
|
+
return {
|
|
115
|
+
...criterion,
|
|
116
|
+
value,
|
|
117
|
+
sampleCount: annotations.length,
|
|
118
|
+
passed: value >= criterion.minPassRate,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Whether `value` clears `bar` in the given optimization direction. */
|
|
123
|
+
function meetsBar(
|
|
124
|
+
value: number,
|
|
125
|
+
bar: number,
|
|
126
|
+
direction: OptimizationDirection
|
|
127
|
+
): boolean {
|
|
128
|
+
return direction === "minimize" ? value <= bar : value >= bar;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The last annotation matching `annotationName` from each non-skipped run that
|
|
133
|
+
* logged it. One entry per run; runs that never logged the annotation are
|
|
134
|
+
* omitted.
|
|
135
|
+
*/
|
|
136
|
+
function collectAnnotations({
|
|
137
|
+
criterion,
|
|
138
|
+
results,
|
|
139
|
+
}: {
|
|
140
|
+
criterion: AcceptanceCriterion;
|
|
141
|
+
results: readonly TestResult[];
|
|
142
|
+
}): Annotation[] {
|
|
143
|
+
return results
|
|
144
|
+
.filter((result) => result.status !== "skipped")
|
|
145
|
+
.map((result) =>
|
|
146
|
+
findLastAnnotation({
|
|
147
|
+
annotations: result.annotations,
|
|
148
|
+
annotationName: criterion.annotationName,
|
|
149
|
+
})
|
|
150
|
+
)
|
|
151
|
+
.filter((annotation): annotation is Annotation => annotation !== undefined);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function findLastAnnotation({
|
|
155
|
+
annotations,
|
|
156
|
+
annotationName,
|
|
157
|
+
}: {
|
|
158
|
+
annotations: readonly Annotation[];
|
|
159
|
+
annotationName: string;
|
|
160
|
+
}): Annotation | undefined {
|
|
161
|
+
for (
|
|
162
|
+
let annotationIndex = annotations.length - 1;
|
|
163
|
+
annotationIndex >= 0;
|
|
164
|
+
annotationIndex--
|
|
165
|
+
) {
|
|
166
|
+
const annotation = annotations[annotationIndex];
|
|
167
|
+
if (annotation?.name === annotationName) {
|
|
168
|
+
return annotation;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function isValidScore(score: Annotation["score"]): score is number | boolean {
|
|
175
|
+
return (
|
|
176
|
+
typeof score === "boolean" ||
|
|
177
|
+
(typeof score === "number" && Number.isFinite(score))
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function calculateAverage(scores: readonly (number | boolean)[]): number {
|
|
182
|
+
const total = scores
|
|
183
|
+
.map(scoreToNumber)
|
|
184
|
+
.reduce((sum, score) => sum + score, 0);
|
|
185
|
+
return total / scores.length;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function scoreToNumber(score: number | boolean): number {
|
|
189
|
+
return typeof score === "boolean" ? (score ? 1 : 0) : score;
|
|
190
|
+
}
|