@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.
Files changed (244) hide show
  1. package/README.md +62 -0
  2. package/dist/esm/__generated__/api/v1.d.ts +452 -28
  3. package/dist/esm/__generated__/api/v1.d.ts.map +1 -1
  4. package/dist/esm/experiments/helpers/getExampleGlobalId.d.ts +8 -0
  5. package/dist/esm/experiments/helpers/getExampleGlobalId.d.ts.map +1 -0
  6. package/dist/esm/experiments/helpers/getExampleGlobalId.js +9 -0
  7. package/dist/esm/experiments/helpers/getExampleGlobalId.js.map +1 -0
  8. package/dist/esm/experiments/resumeEvaluation.d.ts.map +1 -1
  9. package/dist/esm/experiments/resumeEvaluation.js +2 -1
  10. package/dist/esm/experiments/resumeEvaluation.js.map +1 -1
  11. package/dist/esm/experiments/resumeExperiment.d.ts.map +1 -1
  12. package/dist/esm/experiments/resumeExperiment.js +3 -2
  13. package/dist/esm/experiments/resumeExperiment.js.map +1 -1
  14. package/dist/esm/experiments/runExperiment.d.ts.map +1 -1
  15. package/dist/esm/experiments/runExperiment.js +6 -3
  16. package/dist/esm/experiments/runExperiment.js.map +1 -1
  17. package/dist/esm/jest/index.d.ts +5 -0
  18. package/dist/esm/jest/index.d.ts.map +1 -0
  19. package/dist/esm/jest/index.js +49 -0
  20. package/dist/esm/jest/index.js.map +1 -0
  21. package/dist/esm/jest/reporter.d.ts +13 -0
  22. package/dist/esm/jest/reporter.d.ts.map +1 -0
  23. package/dist/esm/jest/reporter.js +19 -0
  24. package/dist/esm/jest/reporter.js.map +1 -0
  25. package/dist/esm/prompts/sdks/toAI.d.ts +2 -2
  26. package/dist/esm/prompts/sdks/toAI.d.ts.map +1 -1
  27. package/dist/esm/prompts/sdks/toAI.js.map +1 -1
  28. package/dist/esm/prompts/sdks/toAnthropic.d.ts +2 -2
  29. package/dist/esm/prompts/sdks/toAnthropic.d.ts.map +1 -1
  30. package/dist/esm/prompts/sdks/toAnthropic.js.map +1 -1
  31. package/dist/esm/prompts/sdks/toOpenAI.d.ts +2 -2
  32. package/dist/esm/prompts/sdks/toOpenAI.d.ts.map +1 -1
  33. package/dist/esm/prompts/sdks/toOpenAI.js.map +1 -1
  34. package/dist/esm/prompts/sdks/toSDK.d.ts +8 -8
  35. package/dist/esm/prompts/sdks/toSDK.d.ts.map +1 -1
  36. package/dist/esm/prompts/sdks/toSDK.js.map +1 -1
  37. package/dist/esm/prompts/sdks/types.d.ts +2 -2
  38. package/dist/esm/prompts/sdks/types.d.ts.map +1 -1
  39. package/dist/esm/schemas/llm/anthropic/converters.d.ts +8 -8
  40. package/dist/esm/schemas/llm/anthropic/messagePartSchemas.d.ts +4 -4
  41. package/dist/esm/schemas/llm/anthropic/messageSchemas.d.ts +6 -6
  42. package/dist/esm/schemas/llm/constants.d.ts +3 -3
  43. package/dist/esm/schemas/llm/converters.d.ts +12 -12
  44. package/dist/esm/schemas/llm/openai/converters.d.ts +3 -3
  45. package/dist/esm/schemas/llm/schemas.d.ts +2 -2
  46. package/dist/esm/testing/acceptance.d.ts +20 -0
  47. package/dist/esm/testing/acceptance.d.ts.map +1 -0
  48. package/dist/esm/testing/acceptance.js +129 -0
  49. package/dist/esm/testing/acceptance.js.map +1 -0
  50. package/dist/esm/testing/define-api.d.ts +157 -0
  51. package/dist/esm/testing/define-api.d.ts.map +1 -0
  52. package/dist/esm/testing/define-api.js +78 -0
  53. package/dist/esm/testing/define-api.js.map +1 -0
  54. package/dist/esm/testing/helpers.d.ts +55 -0
  55. package/dist/esm/testing/helpers.d.ts.map +1 -0
  56. package/dist/esm/testing/helpers.js +179 -0
  57. package/dist/esm/testing/helpers.js.map +1 -0
  58. package/dist/esm/testing/phoenix-test-tracking.d.ts +68 -0
  59. package/dist/esm/testing/phoenix-test-tracking.d.ts.map +1 -0
  60. package/dist/esm/testing/phoenix-test-tracking.js +521 -0
  61. package/dist/esm/testing/phoenix-test-tracking.js.map +1 -0
  62. package/dist/esm/testing/report-artifacts.d.ts +45 -0
  63. package/dist/esm/testing/report-artifacts.d.ts.map +1 -0
  64. package/dist/esm/testing/report-artifacts.js +218 -0
  65. package/dist/esm/testing/report-artifacts.js.map +1 -0
  66. package/dist/esm/testing/report-run.d.ts +22 -0
  67. package/dist/esm/testing/report-run.d.ts.map +1 -0
  68. package/dist/esm/testing/report-run.js +41 -0
  69. package/dist/esm/testing/report-run.js.map +1 -0
  70. package/dist/esm/testing/reporter-format.d.ts +83 -0
  71. package/dist/esm/testing/reporter-format.d.ts.map +1 -0
  72. package/dist/esm/testing/reporter-format.js +852 -0
  73. package/dist/esm/testing/reporter-format.js.map +1 -0
  74. package/dist/esm/testing/runner.d.ts +31 -0
  75. package/dist/esm/testing/runner.d.ts.map +1 -0
  76. package/dist/esm/testing/runner.js +238 -0
  77. package/dist/esm/testing/runner.js.map +1 -0
  78. package/dist/esm/testing/state.d.ts +138 -0
  79. package/dist/esm/testing/state.d.ts.map +1 -0
  80. package/dist/esm/testing/state.js +31 -0
  81. package/dist/esm/testing/state.js.map +1 -0
  82. package/dist/esm/testing/types.d.ts +319 -0
  83. package/dist/esm/testing/types.d.ts.map +1 -0
  84. package/dist/esm/testing/types.js +9 -0
  85. package/dist/esm/testing/types.js.map +1 -0
  86. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  87. package/dist/esm/utils/channel.d.ts +7 -7
  88. package/dist/esm/utils/channel.d.ts.map +1 -1
  89. package/dist/esm/utils/channel.js +1 -1
  90. package/dist/esm/utils/channel.js.map +1 -1
  91. package/dist/esm/utils/formatPromptMessages.d.ts.map +1 -1
  92. package/dist/esm/utils/getPromptBySelector.d.ts.map +1 -1
  93. package/dist/esm/utils/promisifyResult.d.ts +1 -1
  94. package/dist/esm/utils/promisifyResult.d.ts.map +1 -1
  95. package/dist/esm/utils/promisifyResult.js.map +1 -1
  96. package/dist/esm/utils/schemaMatches.d.ts +5 -5
  97. package/dist/esm/utils/schemaMatches.d.ts.map +1 -1
  98. package/dist/esm/utils/schemaMatches.js.map +1 -1
  99. package/dist/esm/vitest/index.d.ts +5 -0
  100. package/dist/esm/vitest/index.d.ts.map +1 -0
  101. package/dist/esm/vitest/index.js +15 -0
  102. package/dist/esm/vitest/index.js.map +1 -0
  103. package/dist/esm/vitest/reporter.d.ts +19 -0
  104. package/dist/esm/vitest/reporter.d.ts.map +1 -0
  105. package/dist/esm/vitest/reporter.js +27 -0
  106. package/dist/esm/vitest/reporter.js.map +1 -0
  107. package/dist/src/__generated__/api/v1.d.ts +452 -28
  108. package/dist/src/__generated__/api/v1.d.ts.map +1 -1
  109. package/dist/src/experiments/helpers/getExampleGlobalId.d.ts +8 -0
  110. package/dist/src/experiments/helpers/getExampleGlobalId.d.ts.map +1 -0
  111. package/dist/src/experiments/helpers/getExampleGlobalId.js +13 -0
  112. package/dist/src/experiments/helpers/getExampleGlobalId.js.map +1 -0
  113. package/dist/src/experiments/resumeEvaluation.d.ts.map +1 -1
  114. package/dist/src/experiments/resumeEvaluation.js +2 -1
  115. package/dist/src/experiments/resumeEvaluation.js.map +1 -1
  116. package/dist/src/experiments/resumeExperiment.d.ts.map +1 -1
  117. package/dist/src/experiments/resumeExperiment.js +3 -2
  118. package/dist/src/experiments/resumeExperiment.js.map +1 -1
  119. package/dist/src/experiments/runExperiment.d.ts.map +1 -1
  120. package/dist/src/experiments/runExperiment.js +6 -3
  121. package/dist/src/experiments/runExperiment.js.map +1 -1
  122. package/dist/src/jest/index.d.ts +5 -0
  123. package/dist/src/jest/index.d.ts.map +1 -0
  124. package/dist/src/jest/index.js +58 -0
  125. package/dist/src/jest/index.js.map +1 -0
  126. package/dist/src/jest/reporter.d.ts +13 -0
  127. package/dist/src/jest/reporter.d.ts.map +1 -0
  128. package/dist/src/jest/reporter.js +23 -0
  129. package/dist/src/jest/reporter.js.map +1 -0
  130. package/dist/src/prompts/sdks/toAI.d.ts +2 -2
  131. package/dist/src/prompts/sdks/toAI.d.ts.map +1 -1
  132. package/dist/src/prompts/sdks/toAI.js.map +1 -1
  133. package/dist/src/prompts/sdks/toAnthropic.d.ts +2 -2
  134. package/dist/src/prompts/sdks/toAnthropic.d.ts.map +1 -1
  135. package/dist/src/prompts/sdks/toAnthropic.js.map +1 -1
  136. package/dist/src/prompts/sdks/toOpenAI.d.ts +2 -2
  137. package/dist/src/prompts/sdks/toOpenAI.d.ts.map +1 -1
  138. package/dist/src/prompts/sdks/toOpenAI.js.map +1 -1
  139. package/dist/src/prompts/sdks/toSDK.d.ts +8 -8
  140. package/dist/src/prompts/sdks/toSDK.d.ts.map +1 -1
  141. package/dist/src/prompts/sdks/toSDK.js.map +1 -1
  142. package/dist/src/prompts/sdks/types.d.ts +2 -2
  143. package/dist/src/prompts/sdks/types.d.ts.map +1 -1
  144. package/dist/src/schemas/llm/anthropic/converters.d.ts +8 -8
  145. package/dist/src/schemas/llm/anthropic/messagePartSchemas.d.ts +4 -4
  146. package/dist/src/schemas/llm/anthropic/messageSchemas.d.ts +6 -6
  147. package/dist/src/schemas/llm/constants.d.ts +3 -3
  148. package/dist/src/schemas/llm/converters.d.ts +12 -12
  149. package/dist/src/schemas/llm/openai/converters.d.ts +3 -3
  150. package/dist/src/schemas/llm/schemas.d.ts +2 -2
  151. package/dist/src/testing/acceptance.d.ts +20 -0
  152. package/dist/src/testing/acceptance.d.ts.map +1 -0
  153. package/dist/src/testing/acceptance.js +114 -0
  154. package/dist/src/testing/acceptance.js.map +1 -0
  155. package/dist/src/testing/define-api.d.ts +157 -0
  156. package/dist/src/testing/define-api.d.ts.map +1 -0
  157. package/dist/src/testing/define-api.js +81 -0
  158. package/dist/src/testing/define-api.js.map +1 -0
  159. package/dist/src/testing/helpers.d.ts +55 -0
  160. package/dist/src/testing/helpers.d.ts.map +1 -0
  161. package/dist/src/testing/helpers.js +182 -0
  162. package/dist/src/testing/helpers.js.map +1 -0
  163. package/dist/src/testing/phoenix-test-tracking.d.ts +68 -0
  164. package/dist/src/testing/phoenix-test-tracking.d.ts.map +1 -0
  165. package/dist/src/testing/phoenix-test-tracking.js +530 -0
  166. package/dist/src/testing/phoenix-test-tracking.js.map +1 -0
  167. package/dist/src/testing/report-artifacts.d.ts +45 -0
  168. package/dist/src/testing/report-artifacts.d.ts.map +1 -0
  169. package/dist/src/testing/report-artifacts.js +225 -0
  170. package/dist/src/testing/report-artifacts.js.map +1 -0
  171. package/dist/src/testing/report-run.d.ts +22 -0
  172. package/dist/src/testing/report-run.d.ts.map +1 -0
  173. package/dist/src/testing/report-run.js +47 -0
  174. package/dist/src/testing/report-run.js.map +1 -0
  175. package/dist/src/testing/reporter-format.d.ts +83 -0
  176. package/dist/src/testing/reporter-format.d.ts.map +1 -0
  177. package/dist/src/testing/reporter-format.js +870 -0
  178. package/dist/src/testing/reporter-format.js.map +1 -0
  179. package/dist/src/testing/runner.d.ts +31 -0
  180. package/dist/src/testing/runner.d.ts.map +1 -0
  181. package/dist/src/testing/runner.js +258 -0
  182. package/dist/src/testing/runner.js.map +1 -0
  183. package/dist/src/testing/state.d.ts +138 -0
  184. package/dist/src/testing/state.d.ts.map +1 -0
  185. package/dist/src/testing/state.js +38 -0
  186. package/dist/src/testing/state.js.map +1 -0
  187. package/dist/src/testing/types.d.ts +319 -0
  188. package/dist/src/testing/types.d.ts.map +1 -0
  189. package/dist/src/testing/types.js +13 -0
  190. package/dist/src/testing/types.js.map +1 -0
  191. package/dist/src/utils/channel.d.ts +7 -7
  192. package/dist/src/utils/channel.d.ts.map +1 -1
  193. package/dist/src/utils/channel.js +1 -1
  194. package/dist/src/utils/channel.js.map +1 -1
  195. package/dist/src/utils/formatPromptMessages.d.ts.map +1 -1
  196. package/dist/src/utils/getPromptBySelector.d.ts.map +1 -1
  197. package/dist/src/utils/promisifyResult.d.ts +1 -1
  198. package/dist/src/utils/promisifyResult.d.ts.map +1 -1
  199. package/dist/src/utils/promisifyResult.js.map +1 -1
  200. package/dist/src/utils/schemaMatches.d.ts +5 -5
  201. package/dist/src/utils/schemaMatches.d.ts.map +1 -1
  202. package/dist/src/utils/schemaMatches.js.map +1 -1
  203. package/dist/src/vitest/index.d.ts +5 -0
  204. package/dist/src/vitest/index.d.ts.map +1 -0
  205. package/dist/src/vitest/index.js +23 -0
  206. package/dist/src/vitest/index.js.map +1 -0
  207. package/dist/src/vitest/reporter.d.ts +19 -0
  208. package/dist/src/vitest/reporter.d.ts.map +1 -0
  209. package/dist/src/vitest/reporter.js +34 -0
  210. package/dist/src/vitest/reporter.js.map +1 -0
  211. package/dist/tsconfig.tsbuildinfo +1 -1
  212. package/docs/ci-evals-annotations.mdx +190 -0
  213. package/docs/ci-evals-jest.mdx +78 -0
  214. package/docs/ci-evals-vitest.mdx +240 -0
  215. package/docs/ci-evals.mdx +263 -0
  216. package/docs/overview.mdx +9 -1
  217. package/package.json +49 -17
  218. package/src/__generated__/api/v1.ts +452 -28
  219. package/src/experiments/helpers/getExampleGlobalId.ts +12 -0
  220. package/src/experiments/resumeEvaluation.ts +2 -1
  221. package/src/experiments/resumeExperiment.ts +3 -2
  222. package/src/experiments/runExperiment.ts +6 -3
  223. package/src/jest/index.ts +124 -0
  224. package/src/jest/reporter.ts +22 -0
  225. package/src/prompts/sdks/toAI.ts +4 -3
  226. package/src/prompts/sdks/toAnthropic.ts +4 -3
  227. package/src/prompts/sdks/toOpenAI.ts +4 -3
  228. package/src/prompts/sdks/toSDK.ts +16 -11
  229. package/src/prompts/sdks/types.ts +2 -2
  230. package/src/testing/acceptance.ts +190 -0
  231. package/src/testing/define-api.ts +279 -0
  232. package/src/testing/helpers.ts +251 -0
  233. package/src/testing/phoenix-test-tracking.ts +637 -0
  234. package/src/testing/report-artifacts.ts +272 -0
  235. package/src/testing/report-run.ts +44 -0
  236. package/src/testing/reporter-format.ts +1072 -0
  237. package/src/testing/runner.ts +350 -0
  238. package/src/testing/state.ts +165 -0
  239. package/src/testing/types.ts +366 -0
  240. package/src/utils/channel.ts +17 -15
  241. package/src/utils/promisifyResult.ts +6 -4
  242. package/src/utils/schemaMatches.ts +12 -10
  243. package/src/vitest/index.ts +57 -0
  244. package/src/vitest/reporter.ts +32 -0
@@ -0,0 +1,157 @@
1
+ import { type RunnerHooks } from "./runner.js";
2
+ import { type KVMap, type SuiteConfig, type TestEachRow, type TestFn, type TestParams } from "./types.js";
3
+ /**
4
+ * Declare Phoenix eval test suites.
5
+ *
6
+ * Drop-in replacement for the test runner's own `describe`. The suite name
7
+ * doubles as the dataset and experiment name on the Phoenix server, and the
8
+ * optional {@link SuiteConfig} controls dataset naming, repetitions, dry-run
9
+ * mode, and CI acceptance criteria.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import * as px from "@arizeai/phoenix-client/vitest";
14
+ *
15
+ * px.describe("generate sql demo", () => {
16
+ * px.test("offtopic input", { input: { question: "hi" } }, async ({ input }) => {
17
+ * // ...
18
+ * });
19
+ * }, { metadata: { model: "gpt-4o-mini" } });
20
+ * ```
21
+ */
22
+ export interface PhoenixDescribe {
23
+ /**
24
+ * Declare a Phoenix eval test suite.
25
+ *
26
+ * @param name - Suite name; doubles as the dataset / experiment name on Phoenix.
27
+ * @param fn - Suite body that declares its `test` / `it` cases.
28
+ * @param config - Optional suite-level config (dataset name, repetitions, dry-run, acceptance criteria).
29
+ */
30
+ (name: string, fn: () => void, config?: SuiteConfig): void;
31
+ /**
32
+ * Run only this suite, skipping all sibling suites
33
+ * (matches the runner's `describe.only`).
34
+ *
35
+ * @param name - Suite name; doubles as the dataset / experiment name on Phoenix.
36
+ * @param fn - Suite body that declares its `test` / `it` cases.
37
+ * @param config - Optional suite-level config.
38
+ */
39
+ only(name: string, fn: () => void, config?: SuiteConfig): void;
40
+ /**
41
+ * Skip this suite entirely (matches the runner's `describe.skip`). No dataset
42
+ * or experiment is created on Phoenix.
43
+ *
44
+ * @param name - Suite name; doubles as the dataset / experiment name on Phoenix.
45
+ * @param fn - Suite body (not executed).
46
+ * @param config - Optional suite-level config.
47
+ */
48
+ skip(name: string, fn: () => void, config?: SuiteConfig): void;
49
+ }
50
+ /**
51
+ * The test body returned by {@link PhoenixTest.each} after a table is bound.
52
+ *
53
+ * @param name - Test name, or a template (`%i` / `%s` / `%j`), or a function
54
+ * that derives the name from the row and its index.
55
+ * @param fn - The test handler, run once per row in the bound table.
56
+ * @param timeout - Optional per-test timeout in milliseconds.
57
+ */
58
+ export type PhoenixTestEach<Input extends KVMap = KVMap, Expected extends KVMap = KVMap> = (name: string | ((row: TestEachRow<Input, Expected>, index: number) => string), fn: TestFn<Input, Expected>, timeout?: number) => void;
59
+ /**
60
+ * Declare a single Phoenix eval test case.
61
+ *
62
+ * Drop-in replacement for the test runner's own `test` / `it`. The `params`
63
+ * argument carries the `input` and the reference output (`expected` /
64
+ * `reference` / `output`) that become the dataset example; whatever the handler
65
+ * returns (or passes to `logOutput()`) is recorded as the experiment run's
66
+ * output and made available to evaluators.
67
+ *
68
+ * `it` is the canonical alias for `test`; the two are identical.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * px.test(
73
+ * "summarizes the article",
74
+ * { input: { article }, expected: { summary } },
75
+ * async ({ input, expected }) => {
76
+ * const output = await summarize(input.article);
77
+ * px.logOutput(output);
78
+ * await px.evaluate({ name: "matches", evaluate: () => output === expected.summary });
79
+ * }
80
+ * );
81
+ * ```
82
+ */
83
+ export interface PhoenixTest {
84
+ /**
85
+ * Declare a single Phoenix eval test case.
86
+ *
87
+ * @param name - Test case name; doubles as the dataset example label.
88
+ * @param params - Inline `input` and reference output that become the dataset example.
89
+ * @param fn - Test handler; receives `{ input, expected, metadata }`.
90
+ * @param timeout - Optional per-test timeout in milliseconds.
91
+ */
92
+ <Input extends KVMap = KVMap, Expected extends KVMap = KVMap>(name: string, params: TestParams<Input, Expected>, fn: TestFn<Input, Expected>, timeout?: number): void;
93
+ /**
94
+ * Run only this test case, skipping its siblings
95
+ * (matches the runner's `test.only`).
96
+ *
97
+ * @param name - Test case name; doubles as the dataset example label.
98
+ * @param params - Inline `input` and reference output that become the dataset example.
99
+ * @param fn - Test handler; receives `{ input, expected, metadata }`.
100
+ * @param timeout - Optional per-test timeout in milliseconds.
101
+ */
102
+ only<Input extends KVMap = KVMap, Expected extends KVMap = KVMap>(name: string, params: TestParams<Input, Expected>, fn: TestFn<Input, Expected>, timeout?: number): void;
103
+ /**
104
+ * Skip this test case (matches the runner's `test.skip`). No dataset example
105
+ * or experiment run is created on Phoenix.
106
+ *
107
+ * @param name - Test case name; doubles as the dataset example label.
108
+ * @param params - Inline `input` and reference output (not used while skipped).
109
+ * @param fn - Test handler (not executed).
110
+ * @param timeout - Optional per-test timeout in milliseconds.
111
+ */
112
+ skip<Input extends KVMap = KVMap, Expected extends KVMap = KVMap>(name: string, params: TestParams<Input, Expected>, fn: TestFn<Input, Expected>, timeout?: number): void;
113
+ /**
114
+ * Run the same test handler across many examples. Returns a function that
115
+ * takes a name (or template / name-builder) and the shared test body; each
116
+ * row in `table` becomes its own dataset example and experiment run.
117
+ *
118
+ * @param table - Rows of `{ input, expected?, metadata?, ... }` to fan out over.
119
+ * @returns A {@link PhoenixTestEach} that binds the name and shared handler.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * px.test.each([
124
+ * { input: { a: 1, b: 2 }, expected: { sum: 3 } },
125
+ * { input: { a: 2, b: 2 }, expected: { sum: 4 } },
126
+ * ])("adds %j", async ({ input, expected }) => {
127
+ * // ...
128
+ * });
129
+ * ```
130
+ */
131
+ each<Input extends KVMap, Expected extends KVMap>(table: TestEachRow<Input, Expected>[]): PhoenixTestEach<Input, Expected>;
132
+ }
133
+ /** The public testing surface returned by {@link createTestApi}. */
134
+ export interface PhoenixTestApi {
135
+ /** Declare a Phoenix eval test suite. See {@link PhoenixDescribe}. */
136
+ describe: PhoenixDescribe;
137
+ /** Declare a Phoenix eval test case. See {@link PhoenixTest}. */
138
+ test: PhoenixTest;
139
+ /** Canonical alias for {@link PhoenixTestApi.test}. */
140
+ it: PhoenixTest;
141
+ }
142
+ /**
143
+ * Build the public `describe`/`test`/`it` API for a runner adapter.
144
+ *
145
+ * Both the jest and vitest entrypoints expose the identical surface; the only
146
+ * thing that differs between them is how the {@link RunnerHooks} are obtained
147
+ * (vitest imports them statically, jest resolves them lazily from globals).
148
+ * That difference is captured by `getHooks`, which is invoked once per
149
+ * declaration so adapters are free to resolve hooks lazily.
150
+ *
151
+ * The JSDoc that surfaces in editors lives on the {@link PhoenixDescribe} and
152
+ * {@link PhoenixTest} interfaces rather than the implementations below, so the
153
+ * docs survive the `export const { describe, test, it } = createTestApi(...)`
154
+ * destructuring in each adapter.
155
+ */
156
+ export declare function createTestApi(getHooks: () => RunnerHooks): PhoenixTestApi;
157
+ //# sourceMappingURL=define-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-api.d.ts","sourceRoot":"","sources":["../../../src/testing/define-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { declareDescribe, declareTest } from "./runner.js";
2
+ import { resolveReference, } from "./types.js";
3
+ /**
4
+ * Build the public `describe`/`test`/`it` API for a runner adapter.
5
+ *
6
+ * Both the jest and vitest entrypoints expose the identical surface; the only
7
+ * thing that differs between them is how the {@link RunnerHooks} are obtained
8
+ * (vitest imports them statically, jest resolves them lazily from globals).
9
+ * That difference is captured by `getHooks`, which is invoked once per
10
+ * declaration so adapters are free to resolve hooks lazily.
11
+ *
12
+ * The JSDoc that surfaces in editors lives on the {@link PhoenixDescribe} and
13
+ * {@link PhoenixTest} interfaces rather than the implementations below, so the
14
+ * docs survive the `export const { describe, test, it } = createTestApi(...)`
15
+ * destructuring in each adapter.
16
+ */
17
+ export function createTestApi(getHooks) {
18
+ const describe = ((name, fn, config) => {
19
+ declareDescribe(getHooks(), name, fn, config ?? {});
20
+ });
21
+ describe.only = (name, fn, config) => {
22
+ declareDescribe(getHooks(), name, fn, config ?? {}, "only");
23
+ };
24
+ describe.skip = (name, fn, config) => {
25
+ declareDescribe(getHooks(), name, fn, config ?? {}, "skip");
26
+ };
27
+ const test = ((name, params, fn, timeout) => {
28
+ declareTest(getHooks(), name, params, fn, "default", timeout);
29
+ });
30
+ test.only = (name, params, fn, timeout) => {
31
+ declareTest(getHooks(), name, params, fn, "only", timeout);
32
+ };
33
+ test.skip = (name, params, fn, timeout) => {
34
+ declareTest(getHooks(), name, params, fn, "skip", timeout);
35
+ };
36
+ test.each = (table) => {
37
+ return (name, fn, timeout) => {
38
+ table.forEach((row, i) => {
39
+ const testName = typeof name === "function"
40
+ ? name(row, i)
41
+ : interpolateName(name, row, i);
42
+ declareTest(getHooks(), testName, {
43
+ id: row.id,
44
+ input: row.input,
45
+ expected: resolveReference(row),
46
+ metadata: row.metadata,
47
+ splits: row.splits,
48
+ repetitions: row.repetitions,
49
+ dryRun: row.dryRun,
50
+ }, fn, "default", timeout);
51
+ });
52
+ };
53
+ };
54
+ // `it` is the canonical alias for `test`.
55
+ const it = test;
56
+ return { describe, test, it };
57
+ }
58
+ /**
59
+ * Interpolate a `test.each` name template for a single row. Supports the
60
+ * common `%i`/`%s`/`%j` placeholders for surface parity with the underlying
61
+ * runners; when no placeholder is present the 1-based row index is appended.
62
+ */
63
+ function interpolateName(name, row, index) {
64
+ if (!name.includes("%")) {
65
+ return `${name} #${index + 1}`;
66
+ }
67
+ const replacements = [
68
+ [/%i/g, String(index)],
69
+ [/%s/g, JSON.stringify(row.input)],
70
+ [/%j/g, JSON.stringify(row)],
71
+ ];
72
+ let out = name;
73
+ for (const [pattern, value] of replacements) {
74
+ out = out.replace(pattern, value);
75
+ }
76
+ return out;
77
+ }
78
+ //# sourceMappingURL=define-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-api.js","sourceRoot":"","sources":["../../../src/testing/define-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { type SuiteState } from "./state.js";
2
+ import type { Annotation, EvaluationParams, EvaluationResult, Evaluator, KVMap } from "./types.js";
3
+ /**
4
+ * Log the output produced by the test for the current run.
5
+ *
6
+ * Calling this multiple times overwrites the previously recorded value.
7
+ * The argument can be any JSON-serializable value — typically an object
8
+ * matching the shape of the example's `expected` field.
9
+ */
10
+ export declare function logOutput(output: unknown): void;
11
+ /**
12
+ * Record an annotation on the current run.
13
+ *
14
+ * Annotations are collected during the test and posted to Phoenix as
15
+ * experiment evaluations after the test completes. The `name` is the
16
+ * Phoenix evaluation name; `score`, `label`, and `explanation` map to
17
+ * the standard Phoenix `EvaluationResult` fields.
18
+ *
19
+ * The annotation name `"pass"` is reserved — Phoenix eval tests always write
20
+ * a `pass` annotation derived from the test's assertion outcome, so a
21
+ * user-supplied annotation with that name would race / overwrite the
22
+ * built-in one. Such calls are silently ignored.
23
+ */
24
+ export declare function logAnnotation(annotation: Annotation): void;
25
+ /**
26
+ * Run an evaluator object against the current test run and record the result.
27
+ *
28
+ * The evaluator may come from `@arizeai/phoenix-evals.createEvaluator`,
29
+ * `asExperimentEvaluator`, or any plain object with `{ name, evaluate }`.
30
+ * When `params` is omitted, the current test's `input`, recorded `output`,
31
+ * `expected`, `metadata`, and task `traceId` are supplied.
32
+ */
33
+ export declare function evaluate<Params extends KVMap = EvaluationParams & KVMap, Result = EvaluationResult>(evaluator: Evaluator<Params, Result>, params?: Partial<Params> & KVMap): Promise<Result>;
34
+ /**
35
+ * Trace an evaluator function so its execution shows up as a separate
36
+ * `EVALUATOR` span in Phoenix and any `{ name, score }`-shaped return
37
+ * value is automatically captured as an annotation on the current run.
38
+ *
39
+ * The annotation name defaults to the traced function's name, falling
40
+ * back to `"evaluator"`.
41
+ */
42
+ export declare function traceEvaluator<EvaluatorParams extends KVMap, EvaluatorResult>(fn: (params: EvaluatorParams) => EvaluatorResult | Promise<EvaluatorResult>, options?: {
43
+ name?: string;
44
+ }): (params: EvaluatorParams) => Promise<EvaluatorResult>;
45
+ /**
46
+ * Internal: persist all collected annotations for the run.
47
+ *
48
+ * Phoenix's `experiment_evaluations` endpoint is keyed by
49
+ * `(experiment_run_id, name)` so two annotations with the same name on
50
+ * the same run race each other. We collapse duplicates by name (last
51
+ * wins) up front, which makes the final state deterministic; the
52
+ * remaining writes target distinct names, so they post in parallel.
53
+ */
54
+ export declare function flushAnnotations(runId: string | undefined, annotations: Annotation[], suite: SuiteState): Promise<void>;
55
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/testing/helpers.ts"],"names":[],"mappings":"AAKA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAEhB,SAAS,EACT,KAAK,EACN,MAAM,SAAS,CAAC;AAEjB;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAU/C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAS1D;AAED;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,SAAS,KAAK,GAAG,gBAAgB,GAAG,KAAK,EAC/C,MAAM,GAAG,gBAAgB,EAEzB,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,KAAK,GAC/B,OAAO,CAAC,MAAM,CAAC,CAoCjB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,eAAe,SAAS,KAAK,EAAE,eAAe,EAC3E,EAAE,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,EAC3E,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,eAAe,CAAC,CAoBvD;AAqFD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,WAAW,EAAE,UAAU,EAAE,EACzB,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -0,0 +1,179 @@
1
+ import { endTaskSpanForRun, postAnnotation, runEvaluatorWithTracing, } from "./phoenix-test-tracking.js";
2
+ import { currentRun } from "./state.js";
3
+ /**
4
+ * Log the output produced by the test for the current run.
5
+ *
6
+ * Calling this multiple times overwrites the previously recorded value.
7
+ * The argument can be any JSON-serializable value — typically an object
8
+ * matching the shape of the example's `expected` field.
9
+ */
10
+ export function logOutput(output) {
11
+ const run = currentRun();
12
+ if (!run) {
13
+ throw new Error("logOutput() must be called inside a Phoenix eval test body");
14
+ }
15
+ run.output = output;
16
+ run.outputSet = true;
17
+ endTaskSpanForRun(run);
18
+ }
19
+ /**
20
+ * Record an annotation on the current run.
21
+ *
22
+ * Annotations are collected during the test and posted to Phoenix as
23
+ * experiment evaluations after the test completes. The `name` is the
24
+ * Phoenix evaluation name; `score`, `label`, and `explanation` map to
25
+ * the standard Phoenix `EvaluationResult` fields.
26
+ *
27
+ * The annotation name `"pass"` is reserved — Phoenix eval tests always write
28
+ * a `pass` annotation derived from the test's assertion outcome, so a
29
+ * user-supplied annotation with that name would race / overwrite the
30
+ * built-in one. Such calls are silently ignored.
31
+ */
32
+ export function logAnnotation(annotation) {
33
+ const run = currentRun();
34
+ if (!run) {
35
+ throw new Error("logAnnotation() must be called inside a Phoenix eval test body");
36
+ }
37
+ if (annotation.name === "pass")
38
+ return;
39
+ run.annotations.push(annotation);
40
+ }
41
+ /**
42
+ * Run an evaluator object against the current test run and record the result.
43
+ *
44
+ * The evaluator may come from `@arizeai/phoenix-evals.createEvaluator`,
45
+ * `asExperimentEvaluator`, or any plain object with `{ name, evaluate }`.
46
+ * When `params` is omitted, the current test's `input`, recorded `output`,
47
+ * `expected`, `metadata`, and task `traceId` are supplied.
48
+ */
49
+ export async function evaluate(evaluator, params) {
50
+ const run = currentRun();
51
+ if (!run) {
52
+ return await evaluator.evaluate((params ?? {}));
53
+ }
54
+ if (!run.outputSet && !(params && "output" in params)) {
55
+ warnEvaluateBeforeOutput(run.suite, evaluator.name, run.testName);
56
+ }
57
+ const evaluatorParams = {
58
+ input: run.params.input,
59
+ // `run.output` is only ever set together with `outputSet`, so it is already
60
+ // `undefined` until a value is recorded.
61
+ output: run.output,
62
+ expected: run.params.expected,
63
+ metadata: run.params.metadata,
64
+ traceId: run.traceId ?? null,
65
+ ...(params ?? {}),
66
+ };
67
+ const { result, traceId } = await runEvaluatorWithTracing(run.suite, evaluator.name, evaluatorParams, (paramsToEvaluate) => evaluator.evaluate(paramsToEvaluate));
68
+ logAnnotation(toAnnotation({
69
+ name: evaluator.name,
70
+ kind: evaluator.kind,
71
+ result,
72
+ traceId,
73
+ }));
74
+ return result;
75
+ }
76
+ /**
77
+ * Trace an evaluator function so its execution shows up as a separate
78
+ * `EVALUATOR` span in Phoenix and any `{ name, score }`-shaped return
79
+ * value is automatically captured as an annotation on the current run.
80
+ *
81
+ * The annotation name defaults to the traced function's name, falling
82
+ * back to `"evaluator"`.
83
+ */
84
+ export function traceEvaluator(fn, options) {
85
+ const evaluatorName = options?.name ?? (fn.name && fn.name !== "" ? fn.name : "evaluator");
86
+ return async (params) => {
87
+ const run = currentRun();
88
+ if (!run) {
89
+ // outside a test context, just call the function plainly
90
+ return await fn(params);
91
+ }
92
+ const { result, traceId } = await runEvaluatorWithTracing(run.suite, evaluatorName, params, fn);
93
+ if (isAnnotationShaped(result)) {
94
+ logAnnotation({ ...result, traceId });
95
+ }
96
+ return result;
97
+ };
98
+ }
99
+ /**
100
+ * Warn (at most once per suite) when an evaluator runs before any output was
101
+ * recorded and none was passed explicitly. Such an evaluator receives
102
+ * `output: undefined`, which silently scores against nothing — almost always a
103
+ * forgotten `logOutput()`. Harmless for evaluators that only read `input`.
104
+ */
105
+ const warnedOutputSuites = new WeakSet();
106
+ function warnEvaluateBeforeOutput(suite, evaluatorName, testName) {
107
+ if (warnedOutputSuites.has(suite))
108
+ return;
109
+ warnedOutputSuites.add(suite);
110
+ // eslint-disable-next-line no-console
111
+ console.warn(`[@arizeai/phoenix-client] evaluate("${evaluatorName}") ran before ` +
112
+ `logOutput() on test "${testName}", so the evaluator received ` +
113
+ `output=undefined. Call logOutput(...) first, or pass { output } ` +
114
+ `explicitly. (Ignore if this evaluator only needs input.)`);
115
+ }
116
+ /**
117
+ * Normalize an evaluator's return value into an {@link Annotation}. The value
118
+ * is already typed as an {@link EvaluationResult}, so we only dispatch on its
119
+ * runtime shape: a string becomes a `label`, a number/boolean/null becomes a
120
+ * `score`, and an object contributes its `score`/`label`/`explanation`/
121
+ * `metadata` directly.
122
+ */
123
+ function toAnnotation({ name, kind, result, traceId, }) {
124
+ const annotatorKind = kind ?? "CODE";
125
+ if (typeof result === "string") {
126
+ return { name, label: result, annotatorKind, traceId };
127
+ }
128
+ if (typeof result === "number" ||
129
+ typeof result === "boolean" ||
130
+ result === null) {
131
+ return { name, score: result, annotatorKind, traceId };
132
+ }
133
+ if (typeof result === "object" && !Array.isArray(result)) {
134
+ const { score, label, explanation, metadata } = result;
135
+ return {
136
+ name,
137
+ score,
138
+ label,
139
+ explanation,
140
+ metadata,
141
+ annotatorKind,
142
+ traceId,
143
+ };
144
+ }
145
+ return { name, annotatorKind, traceId };
146
+ }
147
+ function isAnnotationShaped(value) {
148
+ if (!value || typeof value !== "object")
149
+ return false;
150
+ const v = value;
151
+ if (typeof v.name !== "string")
152
+ return false;
153
+ if (v.score !== undefined &&
154
+ typeof v.score !== "number" &&
155
+ typeof v.score !== "boolean" &&
156
+ v.score !== null) {
157
+ return false;
158
+ }
159
+ return true;
160
+ }
161
+ /**
162
+ * Internal: persist all collected annotations for the run.
163
+ *
164
+ * Phoenix's `experiment_evaluations` endpoint is keyed by
165
+ * `(experiment_run_id, name)` so two annotations with the same name on
166
+ * the same run race each other. We collapse duplicates by name (last
167
+ * wins) up front, which makes the final state deterministic; the
168
+ * remaining writes target distinct names, so they post in parallel.
169
+ */
170
+ export async function flushAnnotations(runId, annotations, suite) {
171
+ if (!annotations.length)
172
+ return;
173
+ const byName = new Map();
174
+ for (const annotation of annotations) {
175
+ byName.set(annotation.name, annotation);
176
+ }
177
+ await Promise.all(Array.from(byName.values(), (annotation) => postAnnotation(suite, runId, annotation)));
178
+ }
179
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/testing/helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { type GlobalTracerProviderRegistration, type NodeTracerProvider } from "@arizeai/phoenix-otel";
2
+ import { type RunState, type SuiteState } from "./state.js";
3
+ import type { Annotation, KVMap } from "./types.js";
4
+ /**
5
+ * Decide whether tests should sync to Phoenix.
6
+ *
7
+ * Tracing is enabled by default. It can be disabled globally by setting
8
+ * `PHOENIX_TEST_TRACING=false`, or per suite via `SuiteConfig.dryRun`.
9
+ */
10
+ export declare function isTrackingEnabled(suite?: SuiteState): {
11
+ enabled: boolean;
12
+ reason?: string;
13
+ };
14
+ /**
15
+ * Resolve the repetition count for a test: per-test value, else suite-level,
16
+ * else the `PHOENIX_TEST_REPETITIONS` env var, else `1`. Non-positive or
17
+ * non-finite values fall back to `1`.
18
+ */
19
+ export declare function resolveRepetitions(perTest: number | undefined, suite: SuiteState): number;
20
+ /**
21
+ * Initialize the suite: upload the dataset, create the experiment, and
22
+ * register the OpenInference tracer.
23
+ *
24
+ * If tracing is disabled (no Phoenix env vars, or PHOENIX_TEST_TRACING=false),
25
+ * this populates a no-op tracer and exits without making any network calls.
26
+ */
27
+ export declare function initializeSuite(suite: SuiteState): Promise<void>;
28
+ /**
29
+ * Wrap the user's test body in an OpenInference task span and return the
30
+ * trace id so we can submit it with the experiment run.
31
+ */
32
+ export declare function runTaskWithTracing<Result>(suite: SuiteState, testName: string, fn: () => Promise<Result>): Promise<{
33
+ traceId: string;
34
+ result: Result;
35
+ } | {
36
+ traceId: string;
37
+ error: Error;
38
+ isTaskError: boolean;
39
+ }>;
40
+ /**
41
+ * End the current run's task span. `logOutput()` calls this immediately so
42
+ * evaluator work that follows is not included in the task span duration.
43
+ */
44
+ export declare function endTaskSpanForRun(run: RunState): void;
45
+ /**
46
+ * POST a single experiment run for one test case to Phoenix.
47
+ *
48
+ * Best-effort: failures are captured and surfaced via the test reporter but
49
+ * do not fail the test itself.
50
+ */
51
+ export declare function postExperimentRun(suite: SuiteState, run: RunState): Promise<string | undefined>;
52
+ /**
53
+ * POST one annotation (an "experiment_evaluation") for a run.
54
+ */
55
+ export declare function postAnnotation(suite: SuiteState, runId: string | undefined, annotation: Annotation): Promise<void>;
56
+ /** Run an evaluator in an OpenInference evaluator span. */
57
+ export declare function runEvaluatorWithTracing<EvaluatorParams extends KVMap, EvaluatorResult>(suite: SuiteState, name: string, params: EvaluatorParams, fn: (params: EvaluatorParams) => EvaluatorResult | Promise<EvaluatorResult>): Promise<{
58
+ result: EvaluatorResult;
59
+ traceId: string | null;
60
+ }>;
61
+ /**
62
+ * Tear down the tracer provider created for the suite, flushing any pending
63
+ * spans before the process exits.
64
+ */
65
+ export declare function teardownSuite(suite: SuiteState): Promise<void>;
66
+ /** Re-export the ones the entrypoint files consume. */
67
+ export type { GlobalTracerProviderRegistration, NodeTracerProvider };
68
+ //# sourceMappingURL=phoenix-test-tracking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phoenix-test-tracking.d.ts","sourceRoot":"","sources":["../../../src/testing/phoenix-test-tracking.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,gCAAgC,EAErC,KAAK,kBAAkB,EAQxB,MAAM,uBAAuB,CAAC;AAa/B,OAAO,EAAc,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAOjD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAQA;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,KAAK,EAAE,UAAU,GAChB,MAAM,CAaR;AAoGD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgKtE;AAeD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAC7C,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GACxB,OAAO,CACN;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAC1D,CAiCA;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAErD;AAsDD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAwC7B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED,2DAA2D;AAC3D,wBAAsB,uBAAuB,CAC3C,eAAe,SAAS,KAAK,EAC7B,eAAe,EAEf,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,EACvB,EAAE,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,GAC1E,OAAO,CAAC;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAiC9D;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAYpE;AAgBD,uDAAuD;AACvD,YAAY,EAAE,gCAAgC,EAAE,kBAAkB,EAAE,CAAC"}