@mastra/react 1.13.0-alpha.3 → 1.13.0-alpha.5

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 (149) hide show
  1. package/dist/{accumulator-BmD8-x9I.cjs → accumulator-Bjfckb5t.cjs} +5 -9
  2. package/dist/{accumulator-BmD8-x9I.cjs.map → accumulator-Bjfckb5t.cjs.map} +1 -1
  3. package/dist/{accumulator-D9jAph99.js → accumulator-DysrPe6U.js} +5 -9
  4. package/dist/{accumulator-D9jAph99.js.map → accumulator-DysrPe6U.js.map} +1 -1
  5. package/dist/chat/index.cjs +1 -1
  6. package/dist/chat/index.js +1 -1
  7. package/dist/{combine-by-ids-CcaZKGT9.js → combine-by-ids-C-0oe4eH.js} +2 -3
  8. package/dist/{combine-by-ids-CcaZKGT9.js.map → combine-by-ids-C-0oe4eH.js.map} +1 -1
  9. package/dist/{combine-by-ids-D_lp6Dvq.cjs → combine-by-ids-ERVPXXBi.cjs} +2 -3
  10. package/dist/{combine-by-ids-D_lp6Dvq.cjs.map → combine-by-ids-ERVPXXBi.cjs.map} +1 -1
  11. package/dist/{experiments-CJw1N3FB.cjs → experiments-Duv0RgkM.cjs} +12 -19
  12. package/dist/{experiments-CJw1N3FB.cjs.map → experiments-Duv0RgkM.cjs.map} +1 -1
  13. package/dist/{experiments-B7vRMK5T.js → experiments-DyecjEut.js} +12 -19
  14. package/dist/{experiments-B7vRMK5T.js.map → experiments-DyecjEut.js.map} +1 -1
  15. package/dist/{feedback-refetch-interval-XD5FVc2k.cjs → feedback-refetch-interval-BBcT9r8s.cjs} +3 -4
  16. package/dist/{feedback-refetch-interval-XD5FVc2k.cjs.map → feedback-refetch-interval-BBcT9r8s.cjs.map} +1 -1
  17. package/dist/{feedback-refetch-interval-DLHzQoVV.js → feedback-refetch-interval-C12Nzb2r.js} +3 -4
  18. package/dist/{feedback-refetch-interval-DLHzQoVV.js.map → feedback-refetch-interval-C12Nzb2r.js.map} +1 -1
  19. package/dist/hooks/agents/index.cjs +19 -37
  20. package/dist/hooks/agents/index.cjs.map +1 -1
  21. package/dist/hooks/agents/index.js +19 -37
  22. package/dist/hooks/agents/index.js.map +1 -1
  23. package/dist/hooks/auth/index.cjs +11 -21
  24. package/dist/hooks/auth/index.cjs.map +1 -1
  25. package/dist/hooks/auth/index.js +11 -21
  26. package/dist/hooks/auth/index.js.map +1 -1
  27. package/dist/hooks/capabilities/index.cjs +11 -21
  28. package/dist/hooks/capabilities/index.cjs.map +1 -1
  29. package/dist/hooks/capabilities/index.js +11 -21
  30. package/dist/hooks/capabilities/index.js.map +1 -1
  31. package/dist/hooks/configuration/index.cjs +2 -3
  32. package/dist/hooks/configuration/index.js +2 -3
  33. package/dist/hooks/datasets/index.cjs +12 -21
  34. package/dist/hooks/datasets/index.cjs.map +1 -1
  35. package/dist/hooks/datasets/index.js +12 -21
  36. package/dist/hooks/datasets/index.js.map +1 -1
  37. package/dist/hooks/embedders/index.cjs +2 -3
  38. package/dist/hooks/embedders/index.js +2 -3
  39. package/dist/hooks/experiments/index.cjs +1 -1
  40. package/dist/hooks/experiments/index.js +1 -1
  41. package/dist/hooks/feedback/index.cjs +3 -4
  42. package/dist/hooks/feedback/index.js +3 -4
  43. package/dist/hooks/llm/index.cjs +2 -3
  44. package/dist/hooks/llm/index.js +2 -3
  45. package/dist/hooks/logs/index.cjs +4 -5
  46. package/dist/hooks/logs/index.js +4 -5
  47. package/dist/hooks/mcps/index.cjs +8 -15
  48. package/dist/hooks/mcps/index.cjs.map +1 -1
  49. package/dist/hooks/mcps/index.js +8 -15
  50. package/dist/hooks/mcps/index.js.map +1 -1
  51. package/dist/hooks/memory/index.cjs +5 -9
  52. package/dist/hooks/memory/index.cjs.map +1 -1
  53. package/dist/hooks/memory/index.js +5 -9
  54. package/dist/hooks/memory/index.js.map +1 -1
  55. package/dist/hooks/metrics/index.cjs +19 -36
  56. package/dist/hooks/metrics/index.cjs.map +1 -1
  57. package/dist/hooks/metrics/index.js +19 -36
  58. package/dist/hooks/metrics/index.js.map +1 -1
  59. package/dist/hooks/processors/index.cjs +2 -3
  60. package/dist/hooks/processors/index.js +2 -3
  61. package/dist/hooks/prompt-blocks/index.cjs +3 -5
  62. package/dist/hooks/prompt-blocks/index.cjs.map +1 -1
  63. package/dist/hooks/prompt-blocks/index.js +3 -5
  64. package/dist/hooks/prompt-blocks/index.js.map +1 -1
  65. package/dist/hooks/query/index.cjs +2 -3
  66. package/dist/hooks/query/index.js +2 -3
  67. package/dist/hooks/review/index.cjs +4 -6
  68. package/dist/hooks/review/index.cjs.map +1 -1
  69. package/dist/hooks/review/index.js +4 -6
  70. package/dist/hooks/review/index.js.map +1 -1
  71. package/dist/hooks/schedules/index.cjs +6 -10
  72. package/dist/hooks/schedules/index.cjs.map +1 -1
  73. package/dist/hooks/schedules/index.js +6 -10
  74. package/dist/hooks/schedules/index.js.map +1 -1
  75. package/dist/hooks/scores/index.cjs +8 -13
  76. package/dist/hooks/scores/index.cjs.map +1 -1
  77. package/dist/hooks/scores/index.js +8 -13
  78. package/dist/hooks/scores/index.js.map +1 -1
  79. package/dist/hooks/templates/index.cjs +2 -3
  80. package/dist/hooks/templates/index.js +2 -3
  81. package/dist/hooks/tool-providers/index.cjs +10 -19
  82. package/dist/hooks/tool-providers/index.cjs.map +1 -1
  83. package/dist/hooks/tool-providers/index.js +10 -19
  84. package/dist/hooks/tool-providers/index.js.map +1 -1
  85. package/dist/hooks/tools/index.cjs +3 -5
  86. package/dist/hooks/tools/index.cjs.map +1 -1
  87. package/dist/hooks/tools/index.js +3 -5
  88. package/dist/hooks/tools/index.js.map +1 -1
  89. package/dist/hooks/traces/index.cjs +71 -54
  90. package/dist/hooks/traces/index.cjs.map +1 -1
  91. package/dist/hooks/traces/index.d.ts +2 -0
  92. package/dist/hooks/traces/index.d.ts.map +1 -1
  93. package/dist/hooks/traces/index.js +70 -55
  94. package/dist/hooks/traces/index.js.map +1 -1
  95. package/dist/hooks/traces/use-span-aggregate.d.ts +16 -0
  96. package/dist/hooks/traces/use-span-aggregate.d.ts.map +1 -0
  97. package/dist/hooks/traces/use-trace-aggregate.d.ts +17 -0
  98. package/dist/hooks/traces/use-trace-aggregate.d.ts.map +1 -0
  99. package/dist/hooks/traces/use-trace-column-preferences-storage-key.d.ts +4 -2
  100. package/dist/hooks/traces/use-trace-column-preferences-storage-key.d.ts.map +1 -1
  101. package/dist/hooks/vectors/index.cjs +2 -3
  102. package/dist/hooks/vectors/index.js +2 -3
  103. package/dist/hooks/voice/index.cjs +3 -4
  104. package/dist/hooks/voice/index.js +3 -4
  105. package/dist/hooks/workflows/index.cjs +7 -11
  106. package/dist/hooks/workflows/index.cjs.map +1 -1
  107. package/dist/hooks/workflows/index.js +7 -11
  108. package/dist/hooks/workflows/index.js.map +1 -1
  109. package/dist/hooks/workspace/index.cjs +12 -22
  110. package/dist/hooks/workspace/index.cjs.map +1 -1
  111. package/dist/hooks/workspace/index.js +12 -22
  112. package/dist/hooks/workspace/index.js.map +1 -1
  113. package/dist/{hooks-XYsmqFCz.cjs → hooks-Bt15IwzP.cjs} +6 -9
  114. package/dist/{hooks-XYsmqFCz.cjs.map → hooks-Bt15IwzP.cjs.map} +1 -1
  115. package/dist/{hooks-DG-Y1KFe.js → hooks-Btt7PyI-.js} +6 -9
  116. package/dist/{hooks-DG-Y1KFe.js.map → hooks-Btt7PyI-.js.map} +1 -1
  117. package/dist/{hooks-BfysjY_K.js → hooks-CEikbhrN.js} +9 -15
  118. package/dist/{hooks-BfysjY_K.js.map → hooks-CEikbhrN.js.map} +1 -1
  119. package/dist/{hooks-BbUMSab8.cjs → hooks-D6LDSEcm.cjs} +9 -15
  120. package/dist/{hooks-BbUMSab8.cjs.map → hooks-D6LDSEcm.cjs.map} +1 -1
  121. package/dist/index.cjs +7 -9
  122. package/dist/index.cjs.map +1 -1
  123. package/dist/index.js +7 -9
  124. package/dist/index.js.map +1 -1
  125. package/dist/{map-CDv4fbu4.js → map-5-4U5rwA.js} +2 -3
  126. package/dist/{map-CDv4fbu4.js.map → map-5-4U5rwA.js.map} +1 -1
  127. package/dist/{map-wjmL1y5O.cjs → map-BGoWBTGy.cjs} +2 -3
  128. package/dist/{map-wjmL1y5O.cjs.map → map-BGoWBTGy.cjs.map} +1 -1
  129. package/dist/{mastra-client-context-Bx_g84YB.js → mastra-client-context-DQ5z_ze9.js} +2 -3
  130. package/dist/{mastra-client-context-Bx_g84YB.js.map → mastra-client-context-DQ5z_ze9.js.map} +1 -1
  131. package/dist/{mastra-client-context-DzX3f0RF.cjs → mastra-client-context-DX8wJM9p.cjs} +2 -3
  132. package/dist/{mastra-client-context-DzX3f0RF.cjs.map → mastra-client-context-DX8wJM9p.cjs.map} +1 -1
  133. package/dist/{query-utils-CcrChYgz.cjs → query-utils-BVgE_xxj.cjs} +2 -3
  134. package/dist/{query-utils-CcrChYgz.cjs.map → query-utils-BVgE_xxj.cjs.map} +1 -1
  135. package/dist/{query-utils-D1NgFnWU.js → query-utils-DvMERIwf.js} +2 -3
  136. package/dist/{query-utils-D1NgFnWU.js.map → query-utils-DvMERIwf.js.map} +1 -1
  137. package/dist/ui/index.cjs +15 -30
  138. package/dist/ui/index.cjs.map +1 -1
  139. package/dist/ui/index.js +14 -28
  140. package/dist/ui/index.js.map +1 -1
  141. package/dist/{use-in-view-B6eJO9Zi.cjs → use-in-view-BxdrrnCw.cjs} +2 -3
  142. package/dist/{use-in-view-B6eJO9Zi.cjs.map → use-in-view-BxdrrnCw.cjs.map} +1 -1
  143. package/dist/{use-in-view-C9sYPGRm.js → use-in-view-CyjKdplM.js} +2 -3
  144. package/dist/{use-in-view-C9sYPGRm.js.map → use-in-view-CyjKdplM.js.map} +1 -1
  145. package/dist/{voice-BOtUdMi8.cjs → voice-Didej2E1.cjs} +5 -8
  146. package/dist/{voice-BOtUdMi8.cjs.map → voice-Didej2E1.cjs.map} +1 -1
  147. package/dist/{voice-DgirjEyH.js → voice-ugGu7VyA.js} +5 -8
  148. package/dist/{voice-DgirjEyH.js.map → voice-ugGu7VyA.js.map} +1 -1
  149. package/package.json +19 -19
@@ -1,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_hooks = require("../hooks-BbUMSab8.cjs");
2
+ const require_hooks = require("../hooks-D6LDSEcm.cjs");
3
3
  exports.useChat = require_hooks.useChat;
@@ -1 +1 @@
1
- export { t as useChat } from "../hooks-BfysjY_K.js";
1
+ export { t as useChat } from "../hooks-CEikbhrN.js";
@@ -1,5 +1,5 @@
1
1
  import { useCallback } from "react";
2
- //#region src/hooks/shared/combine-by-ids.ts
2
+ // src/hooks/shared/combine-by-ids.ts
3
3
  /**
4
4
  * Stable `combine` for `useQueries`: keyed on the ids' contents (callers pass a fresh array every
5
5
  * render), so TanStack only recombines when a query result actually changes.
@@ -18,7 +18,6 @@ const useCombineByIds = (ids) => {
18
18
  };
19
19
  }, [idsKey]);
20
20
  };
21
- //#endregion
22
21
  export { useCombineByIds as t };
23
22
 
24
- //# sourceMappingURL=combine-by-ids-CcaZKGT9.js.map
23
+ //# sourceMappingURL=combine-by-ids-C-0oe4eH.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"combine-by-ids-CcaZKGT9.js","names":[],"sources":["../src/hooks/shared/combine-by-ids.ts"],"sourcesContent":["import type { UseQueryResult } from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\n/** One entry per requested experiment id, in the order the ids were given. */\nexport interface ExperimentQueriesResult<T> {\n data: Record<string, T | undefined>;\n /** True while any experiment has not loaded yet. */\n isLoading: boolean;\n /** First error among the experiments, if any. */\n error: Error | null;\n}\n\n/**\n * Stable `combine` for `useQueries`: keyed on the ids' contents (callers pass a fresh array every\n * render), so TanStack only recombines when a query result actually changes.\n */\nexport const useCombineByIds = <T>(ids: string[]) => {\n const idsKey = JSON.stringify(ids);\n return useCallback(\n (results: Array<UseQueryResult<T, Error>>): ExperimentQueriesResult<T> => {\n const data: Record<string, T | undefined> = {};\n (JSON.parse(idsKey) as string[]).forEach((id, index) => {\n data[id] = results[index]?.data;\n });\n return {\n data,\n isLoading: results.some(result => result.isLoading),\n error: results.find(result => result.error)?.error ?? null,\n };\n },\n [idsKey],\n );\n};\n"],"mappings":";;;;;;AAgBA,MAAa,mBAAsB,QAAkB;CACnD,MAAM,SAAS,KAAK,UAAU,GAAG;CACjC,OAAO,aACJ,YAAyE;EACxE,MAAM,OAAsC,CAAC;EAC7C,KAAM,MAAM,MAAM,CAAC,CAAc,SAAS,IAAI,UAAU;GACtD,KAAK,MAAM,QAAQ,MAAM,EAAE;EAC7B,CAAC;EACD,OAAO;GACL;GACA,WAAW,QAAQ,MAAK,WAAU,OAAO,SAAS;GAClD,OAAO,QAAQ,MAAK,WAAU,OAAO,KAAK,CAAC,EAAE,SAAS;EACxD;CACF,GACA,CAAC,MAAM,CACT;AACF"}
1
+ {"version":3,"file":"combine-by-ids-C-0oe4eH.js","names":[],"sources":["../src/hooks/shared/combine-by-ids.ts"],"sourcesContent":["import type { UseQueryResult } from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\n/** One entry per requested experiment id, in the order the ids were given. */\nexport interface ExperimentQueriesResult<T> {\n data: Record<string, T | undefined>;\n /** True while any experiment has not loaded yet. */\n isLoading: boolean;\n /** First error among the experiments, if any. */\n error: Error | null;\n}\n\n/**\n * Stable `combine` for `useQueries`: keyed on the ids' contents (callers pass a fresh array every\n * render), so TanStack only recombines when a query result actually changes.\n */\nexport const useCombineByIds = <T>(ids: string[]) => {\n const idsKey = JSON.stringify(ids);\n return useCallback(\n (results: Array<UseQueryResult<T, Error>>): ExperimentQueriesResult<T> => {\n const data: Record<string, T | undefined> = {};\n (JSON.parse(idsKey) as string[]).forEach((id, index) => {\n data[id] = results[index]?.data;\n });\n return {\n data,\n isLoading: results.some(result => result.isLoading),\n error: results.find(result => result.error)?.error ?? null,\n };\n },\n [idsKey],\n );\n};\n"],"mappings":";;;;;;AAgBA,MAAa,mBAAsB,QAAkB;CACnD,MAAM,SAAS,KAAK,UAAU,GAAG;CACjC,OAAO,aACJ,YAAyE;EACxE,MAAM,OAAsC,CAAC;EAC7C,KAAM,MAAM,MAAM,CAAC,CAAc,SAAS,IAAI,UAAU;GACtD,KAAK,MAAM,QAAQ,MAAM,EAAE;EAC7B,CAAC;EACD,OAAO;GACL;GACA,WAAW,QAAQ,MAAK,WAAU,OAAO,SAAS;GAClD,OAAO,QAAQ,MAAK,WAAU,OAAO,KAAK,CAAC,EAAE,SAAS;EACxD;CACF,GACA,CAAC,MAAM,CACT;AACF"}
@@ -1,5 +1,5 @@
1
1
  let react = require("react");
2
- //#region src/hooks/shared/combine-by-ids.ts
2
+ // src/hooks/shared/combine-by-ids.ts
3
3
  /**
4
4
  * Stable `combine` for `useQueries`: keyed on the ids' contents (callers pass a fresh array every
5
5
  * render), so TanStack only recombines when a query result actually changes.
@@ -18,7 +18,6 @@ const useCombineByIds = (ids) => {
18
18
  };
19
19
  }, [idsKey]);
20
20
  };
21
- //#endregion
22
21
  Object.defineProperty(exports, "useCombineByIds", {
23
22
  enumerable: true,
24
23
  get: function() {
@@ -26,4 +25,4 @@ Object.defineProperty(exports, "useCombineByIds", {
26
25
  }
27
26
  });
28
27
 
29
- //# sourceMappingURL=combine-by-ids-D_lp6Dvq.cjs.map
28
+ //# sourceMappingURL=combine-by-ids-ERVPXXBi.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"combine-by-ids-D_lp6Dvq.cjs","names":["useCallback"],"sources":["../src/hooks/shared/combine-by-ids.ts"],"sourcesContent":["import type { UseQueryResult } from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\n/** One entry per requested experiment id, in the order the ids were given. */\nexport interface ExperimentQueriesResult<T> {\n data: Record<string, T | undefined>;\n /** True while any experiment has not loaded yet. */\n isLoading: boolean;\n /** First error among the experiments, if any. */\n error: Error | null;\n}\n\n/**\n * Stable `combine` for `useQueries`: keyed on the ids' contents (callers pass a fresh array every\n * render), so TanStack only recombines when a query result actually changes.\n */\nexport const useCombineByIds = <T>(ids: string[]) => {\n const idsKey = JSON.stringify(ids);\n return useCallback(\n (results: Array<UseQueryResult<T, Error>>): ExperimentQueriesResult<T> => {\n const data: Record<string, T | undefined> = {};\n (JSON.parse(idsKey) as string[]).forEach((id, index) => {\n data[id] = results[index]?.data;\n });\n return {\n data,\n isLoading: results.some(result => result.isLoading),\n error: results.find(result => result.error)?.error ?? null,\n };\n },\n [idsKey],\n );\n};\n"],"mappings":";;;;;;AAgBA,MAAa,mBAAsB,QAAkB;CACnD,MAAM,SAAS,KAAK,UAAU,GAAG;CACjC,QAAA,GAAOA,MAAAA,YAAAA,EACJ,YAAyE;EACxE,MAAM,OAAsC,CAAC;EAC7C,KAAM,MAAM,MAAM,CAAC,CAAc,SAAS,IAAI,UAAU;GACtD,KAAK,MAAM,QAAQ,MAAM,EAAE;EAC7B,CAAC;EACD,OAAO;GACL;GACA,WAAW,QAAQ,MAAK,WAAU,OAAO,SAAS;GAClD,OAAO,QAAQ,MAAK,WAAU,OAAO,KAAK,CAAC,EAAE,SAAS;EACxD;CACF,GACA,CAAC,MAAM,CACT;AACF"}
1
+ {"version":3,"file":"combine-by-ids-ERVPXXBi.cjs","names":["useCallback"],"sources":["../src/hooks/shared/combine-by-ids.ts"],"sourcesContent":["import type { UseQueryResult } from '@tanstack/react-query';\nimport { useCallback } from 'react';\n\n/** One entry per requested experiment id, in the order the ids were given. */\nexport interface ExperimentQueriesResult<T> {\n data: Record<string, T | undefined>;\n /** True while any experiment has not loaded yet. */\n isLoading: boolean;\n /** First error among the experiments, if any. */\n error: Error | null;\n}\n\n/**\n * Stable `combine` for `useQueries`: keyed on the ids' contents (callers pass a fresh array every\n * render), so TanStack only recombines when a query result actually changes.\n */\nexport const useCombineByIds = <T>(ids: string[]) => {\n const idsKey = JSON.stringify(ids);\n return useCallback(\n (results: Array<UseQueryResult<T, Error>>): ExperimentQueriesResult<T> => {\n const data: Record<string, T | undefined> = {};\n (JSON.parse(idsKey) as string[]).forEach((id, index) => {\n data[id] = results[index]?.data;\n });\n return {\n data,\n isLoading: results.some(result => result.isLoading),\n error: results.find(result => result.error)?.error ?? null,\n };\n },\n [idsKey],\n );\n};\n"],"mappings":";;;;;;AAgBA,MAAa,mBAAsB,QAAkB;CACnD,MAAM,SAAS,KAAK,UAAU,GAAG;CACjC,QAAA,GAAOA,MAAAA,YAAAA,EACJ,YAAyE;EACxE,MAAM,OAAsC,CAAC;EAC7C,KAAM,MAAM,MAAM,CAAC,CAAc,SAAS,IAAI,UAAU;GACtD,KAAK,MAAM,QAAQ,MAAM,EAAE;EAC7B,CAAC;EACD,OAAO;GACL;GACA,WAAW,QAAQ,MAAK,WAAU,OAAO,SAAS;GAClD,OAAO,QAAQ,MAAK,WAAU,OAAO,KAAK,CAAC,EAAE,SAAS;EACxD;CACF,GACA,CAAC,MAAM,CACT;AACF"}
@@ -1,10 +1,10 @@
1
- const require_mastra_client_context = require("./mastra-client-context-DzX3f0RF.cjs");
2
- const require_use_in_view = require("./use-in-view-B6eJO9Zi.cjs");
3
- const require_combine_by_ids = require("./combine-by-ids-D_lp6Dvq.cjs");
4
- const require_map = require("./map-wjmL1y5O.cjs");
1
+ const require_mastra_client_context = require("./mastra-client-context-DX8wJM9p.cjs");
2
+ const require_use_in_view = require("./use-in-view-BxdrrnCw.cjs");
3
+ const require_combine_by_ids = require("./combine-by-ids-ERVPXXBi.cjs");
4
+ const require_map = require("./map-BGoWBTGy.cjs");
5
5
  let react = require("react");
6
6
  let _tanstack_react_query = require("@tanstack/react-query");
7
- //#region src/hooks/experiments/usage-accumulator.ts
7
+ // src/hooks/experiments/usage-accumulator.ts
8
8
  const INPUT_TOKEN_METRIC = "mastra_model_total_input_tokens";
9
9
  const OUTPUT_TOKEN_METRIC = "mastra_model_total_output_tokens";
10
10
  const createAccumulator = () => ({
@@ -34,8 +34,7 @@ function toUsage(accumulator) {
34
34
  costUnit: isPriced ? [...accumulator.costUnits][0] : void 0
35
35
  };
36
36
  }
37
- //#endregion
38
- //#region src/hooks/experiments/use-experiment-item-usage.ts
37
+ // src/hooks/experiments/use-experiment-item-usage.ts
39
38
  const POLL_INTERVAL_MS$1 = 2e3;
40
39
  /** Builds the experiment totals and the per-trace usage in a single pass over the groups. */
41
40
  function toExperimentUsage(response) {
@@ -91,8 +90,7 @@ const useExperimentsItemUsage = ({ experiments, supportsMetrics }) => {
91
90
  combine
92
91
  });
93
92
  };
94
- //#endregion
95
- //#region src/hooks/experiments/use-experiment-metrics.ts
93
+ // src/hooks/experiments/use-experiment-metrics.ts
96
94
  /**
97
95
  * Experiment-scoped metrics (tokens, cost, avg agent latency).
98
96
  * Filters only by experimentId — no time window, since the experiment already bounds the row set.
@@ -142,8 +140,7 @@ const useExperimentMetrics = ({ experimentId, experimentStatus, supportsMetrics,
142
140
  isEnabled
143
141
  };
144
142
  };
145
- //#endregion
146
- //#region src/hooks/experiments/use-experiment-trace.ts
143
+ // src/hooks/experiments/use-experiment-trace.ts
147
144
  /**
148
145
  * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.
149
146
  */
@@ -158,8 +155,7 @@ const useExperimentTrace = ({ traceId, queryOptions }) => {
158
155
  ...queryOptions
159
156
  });
160
157
  };
161
- //#endregion
162
- //#region src/hooks/experiments/use-experiments-for-dataset-filter.ts
158
+ // src/hooks/experiments/use-experiments-for-dataset-filter.ts
163
159
  /** Explicit page size: server defaults are 20 (global) / 10 (per dataset), which is too small for the list. */
164
160
  const EXPERIMENTS_PAGE_SIZE = 100;
165
161
  function useExperimentsForDatasetFilter({ datasetId, target, queryOptions }) {
@@ -177,8 +173,7 @@ function useExperimentsForDatasetFilter({ datasetId, target, queryOptions }) {
177
173
  ...queryOptions
178
174
  });
179
175
  }
180
- //#endregion
181
- //#region src/hooks/experiments/use-experiments-list-metrics.ts
176
+ // src/hooks/experiments/use-experiments-list-metrics.ts
182
177
  const AGENT_DURATION_METRIC = "mastra_agent_duration_ms";
183
178
  const EXPERIMENT_IDS_PER_REQUEST = 500;
184
179
  const POLL_INTERVAL_MS = 5e3;
@@ -247,8 +242,7 @@ const useExperimentsListMetrics = ({ experiments, supportsMetrics }) => {
247
242
  refetchInterval: hasActiveExperiment ? POLL_INTERVAL_MS : false
248
243
  });
249
244
  };
250
- //#endregion
251
- //#region src/hooks/experiments/use-infinite-experiments.ts
245
+ // src/hooks/experiments/use-infinite-experiments.ts
252
246
  const EXPERIMENTS_PER_PAGE = 100;
253
247
  function useInfiniteExperiments({ datasetId, target, orderBy, queryOptions }) {
254
248
  const client = require_mastra_client_context.useMastraClient();
@@ -300,7 +294,6 @@ function useInfiniteExperiments({ datasetId, target, orderBy, queryOptions }) {
300
294
  setEndOfListElement
301
295
  };
302
296
  }
303
- //#endregion
304
297
  Object.defineProperty(exports, "EXPERIMENTS_PAGE_SIZE", {
305
298
  enumerable: true,
306
299
  get: function() {
@@ -350,4 +343,4 @@ Object.defineProperty(exports, "useInfiniteExperiments", {
350
343
  }
351
344
  });
352
345
 
353
- //# sourceMappingURL=experiments-CJw1N3FB.cjs.map
346
+ //# sourceMappingURL=experiments-Duv0RgkM.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"experiments-CJw1N3FB.cjs","names":["POLL_INTERVAL_MS","getOrCreate","useMastraClient","useCombineByIds","useQueries","useMastraClient","useQuery","useMastraClient","useQuery","useMastraClient","useQuery","getOrCreate","useMastraClient","useQuery","keepPreviousData","useMastraClient","useInView","useInfiniteQuery"],"sources":["../src/hooks/experiments/usage-accumulator.ts","../src/hooks/experiments/use-experiment-item-usage.ts","../src/hooks/experiments/use-experiment-metrics.ts","../src/hooks/experiments/use-experiment-trace.ts","../src/hooks/experiments/use-experiments-for-dataset-filter.ts","../src/hooks/experiments/use-experiments-list-metrics.ts","../src/hooks/experiments/use-infinite-experiments.ts"],"sourcesContent":["import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\n\nexport const INPUT_TOKEN_METRIC = 'mastra_model_total_input_tokens';\nexport const OUTPUT_TOKEN_METRIC = 'mastra_model_total_output_tokens';\n\nexport interface ExperimentItemUsage {\n inputTokens?: number;\n outputTokens?: number;\n /** Undefined when no group is priced or when groups use different cost units. */\n estimatedCost?: number;\n costUnit?: string;\n}\n\nexport type UsageAccumulator = {\n inputTokens?: number;\n outputTokens?: number;\n estimatedCost: number;\n costUnits: Set<string>;\n hasUnknownCostUnit: boolean;\n};\n\nexport const createAccumulator = (): UsageAccumulator => ({\n estimatedCost: 0,\n costUnits: new Set(),\n hasUnknownCostUnit: false,\n});\n\ntype BreakdownGroup = GetMetricBreakdownResponse['groups'][number];\n\n/** The token field a breakdown group feeds, or undefined when the group is not a token metric. */\nexport function tokenFieldOf(group: BreakdownGroup): 'inputTokens' | 'outputTokens' | undefined {\n const metricName = group.dimensions.name;\n if (metricName === INPUT_TOKEN_METRIC) return 'inputTokens';\n if (metricName === OUTPUT_TOKEN_METRIC) return 'outputTokens';\n return undefined;\n}\n\nexport function accumulate(\n accumulator: UsageAccumulator,\n tokenField: 'inputTokens' | 'outputTokens',\n group: BreakdownGroup,\n) {\n accumulator[tokenField] = (accumulator[tokenField] ?? 0) + group.value;\n\n if (group.estimatedCost == null) return;\n accumulator.estimatedCost += group.estimatedCost;\n if (group.costUnit) {\n accumulator.costUnits.add(group.costUnit.toLowerCase());\n } else {\n accumulator.hasUnknownCostUnit = true;\n }\n}\n\nexport function toUsage(accumulator: UsageAccumulator): ExperimentItemUsage {\n // A single known unit implies at least one priced group.\n const isPriced = !accumulator.hasUnknownCostUnit && accumulator.costUnits.size === 1;\n return {\n inputTokens: accumulator.inputTokens,\n outputTokens: accumulator.outputTokens,\n estimatedCost: isPriced ? accumulator.estimatedCost : undefined,\n costUnit: isPriced ? [...accumulator.costUnits][0] : undefined,\n };\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport { useQueries } from '@tanstack/react-query';\nimport type { Query } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { ExperimentRef } from '../datasets/use-dataset-experiments';\nimport { useCombineByIds } from '../shared/combine-by-ids';\nimport type { ExperimentQueriesResult } from '../shared/combine-by-ids';\nimport { getOrCreate } from '../shared/map';\nimport {\n INPUT_TOKEN_METRIC,\n OUTPUT_TOKEN_METRIC,\n accumulate,\n createAccumulator,\n tokenFieldOf,\n toUsage,\n} from './usage-accumulator';\nimport type { ExperimentItemUsage, UsageAccumulator } from './usage-accumulator';\n\nexport type { ExperimentItemUsage } from './usage-accumulator';\n\nconst POLL_INTERVAL_MS = 2000;\n\n/** Usage of one experiment: its totals, and each item's usage keyed by the trace id of its run. */\nexport interface ExperimentUsage {\n /** Totals across every item. The cost sums priced groups only. */\n summary: ExperimentItemUsage;\n traces: Record<string, ExperimentItemUsage>;\n}\n\n/** Builds the experiment totals and the per-trace usage in a single pass over the groups. */\nfunction toExperimentUsage(response: GetMetricBreakdownResponse): ExperimentUsage {\n const summary = createAccumulator();\n const accumulators = new Map<string, UsageAccumulator>();\n\n for (const group of response.groups) {\n const tokenField = tokenFieldOf(group);\n if (!tokenField) continue;\n\n accumulate(summary, tokenField, group);\n\n const traceId = group.dimensions.traceId;\n if (traceId) accumulate(getOrCreate(accumulators, traceId, createAccumulator), tokenField, group);\n }\n\n const traces: Record<string, ExperimentItemUsage> = {};\n for (const [traceId, accumulator] of accumulators) {\n traces[traceId] = toUsage(accumulator);\n }\n return { summary: toUsage(summary), traces };\n}\n\n/** How many breakdowns to fetch after completion while the exporter may still be flushing metrics. */\nconst MAX_EMPTY_ATTEMPTS = 5;\n\nconst isEmptyUsage = (usage: ExperimentUsage | undefined) =>\n !usage ||\n (Object.keys(usage.traces).length === 0 &&\n usage.summary.inputTokens === undefined &&\n usage.summary.outputTokens === undefined);\n\n/**\n * Token and cost usage of several experiments, keyed by experiment id: each entry holds the\n * experiment totals (`summary`) and every item's usage keyed by trace id (`traces`).\n * Sends one metric breakdown request per experiment, filtered by its id rather than by trace ids,\n * so it does not wait for the experiment results. Usage is only fetched once an experiment has\n * finished; while the breakdown is still empty (metrics flushing), it retries every 2 seconds up to\n * 5 attempts. No request is made when the observability store cannot serve metrics.\n */\nexport const useExperimentsItemUsage = ({\n experiments,\n supportsMetrics,\n}: {\n experiments: ExperimentRef[];\n supportsMetrics: boolean;\n}): ExperimentQueriesResult<ExperimentUsage> => {\n const client = useMastraClient();\n const combine = useCombineByIds<ExperimentUsage>(experiments.map(experiment => experiment.id));\n\n return useQueries({\n queries: experiments.map(({ id, status }) => {\n const finished = status !== 'running' && status !== 'pending';\n return {\n queryKey: ['experiment-item-usage', id, finished],\n queryFn: async () =>\n toExperimentUsage(\n await client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['traceId', 'name'],\n filters: { experimentId: id },\n }),\n ),\n enabled: supportsMetrics && finished,\n refetchInterval: (query: Query<ExperimentUsage>) =>\n isEmptyUsage(query.state.data) && query.state.dataUpdateCount < MAX_EMPTY_ATTEMPTS ? POLL_INTERVAL_MS : false,\n };\n }),\n combine,\n });\n};\n","import type { DatasetExperiment } from '@mastra/client-js';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\nexport interface ExperimentMetrics {\n totalTokens: number | null;\n estimatedCost: number | null;\n costUnit: string | null;\n avgAgentDurationMs: number | null;\n agentRuns: number | null;\n}\n\ninterface UseExperimentMetricsArgs {\n experimentId: string | undefined;\n experimentStatus: DatasetExperiment['status'] | undefined;\n /** Whether the observability store can serve metrics; no requests are made when false. */\n supportsMetrics: boolean;\n queryOptions?: MastraQueryOptions<ExperimentMetrics>;\n}\n\n/**\n * Experiment-scoped metrics (tokens, cost, avg agent latency).\n * Filters only by experimentId — no time window, since the experiment already bounds the row set.\n * Polls every 2 seconds while the experiment is running or pending.\n *\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useExperimentMetrics = ({\n experimentId,\n experimentStatus,\n supportsMetrics,\n queryOptions,\n}: UseExperimentMetricsArgs) => {\n const client = useMastraClient();\n const isEnabled = Boolean(experimentId) && supportsMetrics;\n const isActive = experimentStatus === 'running' || experimentStatus === 'pending';\n\n const query = useQuery({\n queryKey: ['experiment-metrics', experimentId],\n refetchInterval: isActive ? 2000 : false,\n queryFn: async (): Promise<ExperimentMetrics> => {\n // `enabled` already guards this; the check exists to narrow the type.\n if (!experimentId) throw new Error('experimentId is required');\n const filters = { experimentId };\n\n const [tokens, avgDuration, runs] = await Promise.all([\n client.getMetricAggregate({\n name: ['mastra_model_total_input_tokens', 'mastra_model_total_output_tokens'],\n aggregation: 'sum',\n filters,\n }),\n client.getMetricAggregate({ name: ['mastra_agent_duration_ms'], aggregation: 'avg', filters }),\n client.getMetricAggregate({ name: ['mastra_agent_duration_ms'], aggregation: 'count', filters }),\n ]);\n\n return {\n totalTokens: tokens.value ?? null,\n estimatedCost: tokens.estimatedCost ?? null,\n costUnit: tokens.costUnit ?? null,\n avgAgentDurationMs: avgDuration.value ?? null,\n agentRuns: runs.value ?? null,\n };\n },\n ...queryOptions,\n });\n\n return { data: query.data, isLoading: query.isLoading, isEnabled };\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\ntype TraceLightResponse = Awaited<ReturnType<MastraClient['getTraceLight']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useExperimentTrace = <TData = TraceLightResponse>({\n traceId,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n queryOptions?: MastraQueryOptions<TraceLightResponse, TData>;\n}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['experiment-trace-light', traceId],\n queryFn: async () => {\n if (!traceId) {\n throw new Error('Trace ID is required');\n }\n return client.getTraceLight(traceId);\n },\n ...queryOptions,\n });\n};\n","import type { ExperimentTargetType, ListExperimentsParams, MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\n/** Explicit page size: server defaults are 20 (global) / 10 (per dataset), which is too small for the list. */\nexport const EXPERIMENTS_PAGE_SIZE = 100;\n\nexport interface ExperimentTargetFilter {\n targetType?: ExperimentTargetType | '';\n targetId?: string;\n}\n\n/**\n * Experiments for the list page: the global list, or the dataset-scoped list when a dataset filter is active.\n * A dataset's runs may not be in the first page of the global list, so filtering client-side is not enough.\n * The optional target filter is applied server-side for the same reason.\n */\ntype ListExperimentsResponse = Awaited<ReturnType<MastraClient['listExperiments']>>;\n\nexport function useExperimentsForDatasetFilter<TData = ListExperimentsResponse>({\n datasetId,\n target,\n queryOptions,\n}: {\n datasetId: string | undefined;\n target?: ExperimentTargetFilter;\n queryOptions?: MastraQueryOptions<ListExperimentsResponse, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n const params: ListExperimentsParams = { perPage: EXPERIMENTS_PAGE_SIZE };\n if (target?.targetType) params.targetType = target.targetType;\n if (target?.targetId) params.targetId = target.targetId;\n\n return useQuery({\n // Prefixes match the keys invalidated by dataset/experiment mutations.\n queryKey: datasetId ? ['dataset-experiments', datasetId, params] : ['experiments', params],\n queryFn: () => (datasetId ? client.listDatasetExperiments(datasetId, params) : client.listExperiments(params)),\n ...queryOptions,\n });\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport { keepPreviousData, useQuery } from '@tanstack/react-query';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { ExperimentRef } from '../datasets/use-dataset-experiments';\nimport { getOrCreate } from '../shared/map';\nimport {\n INPUT_TOKEN_METRIC,\n OUTPUT_TOKEN_METRIC,\n accumulate,\n createAccumulator,\n tokenFieldOf,\n toUsage,\n} from './usage-accumulator';\nimport type { ExperimentItemUsage, UsageAccumulator } from './usage-accumulator';\n\nconst AGENT_DURATION_METRIC = 'mastra_agent_duration_ms';\n// Each experiment can return two token groups, while the breakdown endpoint allows at most 1,000.\nconst EXPERIMENT_IDS_PER_REQUEST = 500;\nconst POLL_INTERVAL_MS = 5000;\n\n/** Totals of one experiment: token usage, its estimated cost, and the average agent run duration. */\nexport interface ExperimentListMetrics extends ExperimentItemUsage {\n avgDurationMs?: number;\n}\n\nfunction chunk(ids: readonly string[]): string[][] {\n const chunks: string[][] = [];\n for (let index = 0; index < ids.length; index += EXPERIMENT_IDS_PER_REQUEST) {\n chunks.push(ids.slice(index, index + EXPERIMENT_IDS_PER_REQUEST));\n }\n return chunks;\n}\n\nfunction settledValues<T>(results: PromiseSettledResult<T>[]): T[] {\n return results.flatMap(result => (result.status === 'fulfilled' ? [result.value] : []));\n}\n\n/**\n * Builds each requested experiment's metrics. Groups for other experiments are skipped,\n * in case a store ignores the `experimentIds` filter.\n */\nfunction toListMetrics(\n experimentIds: readonly string[],\n tokenResponses: GetMetricBreakdownResponse[],\n durationResponses: GetMetricBreakdownResponse[],\n): Map<string, ExperimentListMetrics> {\n const requested = new Set(experimentIds);\n const accumulators = new Map<string, UsageAccumulator>();\n for (const group of tokenResponses.flatMap(response => response.groups)) {\n const experimentId = group.dimensions.experimentId;\n const tokenField = tokenFieldOf(group);\n if (!experimentId || !requested.has(experimentId) || !tokenField) continue;\n accumulate(getOrCreate(accumulators, experimentId, createAccumulator), tokenField, group);\n }\n\n const metrics = new Map<string, ExperimentListMetrics>();\n for (const [experimentId, accumulator] of accumulators) {\n metrics.set(experimentId, toUsage(accumulator));\n }\n for (const group of durationResponses.flatMap(response => response.groups)) {\n const experimentId = group.dimensions.experimentId;\n if (!experimentId || !requested.has(experimentId)) continue;\n getOrCreate(metrics, experimentId, (): ExperimentListMetrics => ({})).avgDurationMs = group.value;\n }\n return metrics;\n}\n\n/**\n * Token usage, estimated cost and average agent duration of many experiments, keyed by experiment id.\n * Sends two metric breakdowns per 500 experiments (tokens grouped by experiment and metric name,\n * durations grouped by experiment) instead of one request per experiment.\n * Experiments without any metric are absent from the map. Polls while an experiment is running\n * or pending. No request is made when the observability store cannot serve metrics.\n */\nexport const useExperimentsListMetrics = ({\n experiments,\n supportsMetrics,\n}: {\n experiments: ExperimentRef[];\n supportsMetrics: boolean;\n}): UseQueryResult<Map<string, ExperimentListMetrics>, Error> => {\n const client = useMastraClient();\n const experimentIds = [...new Set(experiments.map(experiment => experiment.id))].toSorted();\n const hasActiveExperiment = experiments.some(({ status }) => status === 'running' || status === 'pending');\n\n return useQuery({\n queryKey: ['experiments-list-metrics', experimentIds],\n enabled: supportsMetrics && experimentIds.length > 0,\n queryFn: async () => {\n const batches = chunk(experimentIds);\n const [tokenResults, durationResults] = await Promise.all([\n Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['experimentId', 'name'],\n filters: { experimentIds: batch },\n limit: batch.length * 2,\n }),\n ),\n ),\n Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [AGENT_DURATION_METRIC],\n aggregation: 'avg',\n groupBy: ['experimentId'],\n filters: { experimentIds: batch },\n limit: batch.length,\n }),\n ),\n ),\n ]);\n return toListMetrics(experimentIds, settledValues(tokenResults), settledValues(durationResults));\n },\n // Loading another page changes the ids; keep the rows already shown filled meanwhile.\n placeholderData: keepPreviousData,\n refetchInterval: hasActiveExperiment ? POLL_INTERVAL_MS : false,\n });\n};\n","import type { DatasetExperiment, ListExperimentsParams, MastraClient } from '@mastra/client-js';\nimport { useInfiniteQuery } from '@tanstack/react-query';\nimport type { InfiniteData, QueryKey, UseInfiniteQueryResult } from '@tanstack/react-query';\nimport { useEffect } from 'react';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraInfiniteQueryOptions } from '../shared/query-options';\nimport { useInView } from '../shared/use-in-view';\nimport type { ExperimentTargetFilter } from './use-experiments-for-dataset-filter';\n\nexport const EXPERIMENTS_PER_PAGE = 100;\n\n/**\n * Infinite-scroll experiments for the list page: the global list, or the dataset-scoped list when a\n * dataset filter is active (a dataset's runs may not be in the first pages of the global list). The\n * optional target filter is applied server-side for the same reason.\n */\nexport type ExperimentsOrderBy = NonNullable<ListExperimentsParams['orderBy']>;\n\ntype ListExperimentsResponse = Awaited<ReturnType<MastraClient['listExperiments']>>;\n\nexport function useInfiniteExperiments<TData = DatasetExperiment[]>({\n datasetId,\n target,\n orderBy,\n queryOptions,\n}: {\n datasetId: string | undefined;\n target?: ExperimentTargetFilter;\n orderBy?: ExperimentsOrderBy;\n queryOptions?: MastraInfiniteQueryOptions<ListExperimentsResponse, TData, QueryKey, number>;\n}): UseInfiniteQueryResult<TData, Error> & {\n setEndOfListElement: (element: HTMLDivElement | null) => void;\n} {\n const client = useMastraClient();\n const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();\n const targetType = target?.targetType || undefined;\n const targetId = target?.targetId || undefined;\n\n const query = useInfiniteQuery({\n // Prefixes match the keys invalidated by dataset/experiment mutations.\n queryKey: datasetId\n ? ['dataset-experiments', datasetId, 'infinite', { targetType, targetId, orderBy }]\n : ['experiments', 'infinite', { targetType, targetId, orderBy }],\n queryFn: ({ pageParam }) => {\n const params: ListExperimentsParams = { page: pageParam, perPage: EXPERIMENTS_PER_PAGE };\n if (targetType) params.targetType = targetType;\n if (targetId) params.targetId = targetId;\n if (orderBy) params.orderBy = orderBy;\n return datasetId ? client.listDatasetExperiments(datasetId, params) : client.listExperiments(params);\n },\n initialPageParam: 0,\n getNextPageParam: (lastPage, _, lastPageParam) => {\n if (!lastPage?.experiments?.length || !lastPage.pagination?.hasMore) {\n return undefined;\n }\n return lastPageParam + 1;\n },\n select: (data: InfiniteData<ListExperimentsResponse, number>) =>\n data.pages.flatMap(page => page?.experiments ?? []) as TData,\n ...queryOptions,\n });\n\n useEffect(() => {\n if (isEndOfListInView && query.hasNextPage && !query.isFetchingNextPage) {\n void query.fetchNextPage();\n }\n }, [isEndOfListInView, query]);\n\n return { ...query, setEndOfListElement };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"experiments-Duv0RgkM.cjs","names":["POLL_INTERVAL_MS","getOrCreate","useMastraClient","useCombineByIds","useQueries","useMastraClient","useQuery","useMastraClient","useQuery","useMastraClient","useQuery","getOrCreate","useMastraClient","useQuery","keepPreviousData","useMastraClient","useInView","useInfiniteQuery"],"sources":["../src/hooks/experiments/usage-accumulator.ts","../src/hooks/experiments/use-experiment-item-usage.ts","../src/hooks/experiments/use-experiment-metrics.ts","../src/hooks/experiments/use-experiment-trace.ts","../src/hooks/experiments/use-experiments-for-dataset-filter.ts","../src/hooks/experiments/use-experiments-list-metrics.ts","../src/hooks/experiments/use-infinite-experiments.ts"],"sourcesContent":["import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\n\nexport const INPUT_TOKEN_METRIC = 'mastra_model_total_input_tokens';\nexport const OUTPUT_TOKEN_METRIC = 'mastra_model_total_output_tokens';\n\nexport interface ExperimentItemUsage {\n inputTokens?: number;\n outputTokens?: number;\n /** Undefined when no group is priced or when groups use different cost units. */\n estimatedCost?: number;\n costUnit?: string;\n}\n\nexport type UsageAccumulator = {\n inputTokens?: number;\n outputTokens?: number;\n estimatedCost: number;\n costUnits: Set<string>;\n hasUnknownCostUnit: boolean;\n};\n\nexport const createAccumulator = (): UsageAccumulator => ({\n estimatedCost: 0,\n costUnits: new Set(),\n hasUnknownCostUnit: false,\n});\n\ntype BreakdownGroup = GetMetricBreakdownResponse['groups'][number];\n\n/** The token field a breakdown group feeds, or undefined when the group is not a token metric. */\nexport function tokenFieldOf(group: BreakdownGroup): 'inputTokens' | 'outputTokens' | undefined {\n const metricName = group.dimensions.name;\n if (metricName === INPUT_TOKEN_METRIC) return 'inputTokens';\n if (metricName === OUTPUT_TOKEN_METRIC) return 'outputTokens';\n return undefined;\n}\n\nexport function accumulate(\n accumulator: UsageAccumulator,\n tokenField: 'inputTokens' | 'outputTokens',\n group: BreakdownGroup,\n) {\n accumulator[tokenField] = (accumulator[tokenField] ?? 0) + group.value;\n\n if (group.estimatedCost == null) return;\n accumulator.estimatedCost += group.estimatedCost;\n if (group.costUnit) {\n accumulator.costUnits.add(group.costUnit.toLowerCase());\n } else {\n accumulator.hasUnknownCostUnit = true;\n }\n}\n\nexport function toUsage(accumulator: UsageAccumulator): ExperimentItemUsage {\n // A single known unit implies at least one priced group.\n const isPriced = !accumulator.hasUnknownCostUnit && accumulator.costUnits.size === 1;\n return {\n inputTokens: accumulator.inputTokens,\n outputTokens: accumulator.outputTokens,\n estimatedCost: isPriced ? accumulator.estimatedCost : undefined,\n costUnit: isPriced ? [...accumulator.costUnits][0] : undefined,\n };\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport { useQueries } from '@tanstack/react-query';\nimport type { Query } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { ExperimentRef } from '../datasets/use-dataset-experiments';\nimport { useCombineByIds } from '../shared/combine-by-ids';\nimport type { ExperimentQueriesResult } from '../shared/combine-by-ids';\nimport { getOrCreate } from '../shared/map';\nimport {\n INPUT_TOKEN_METRIC,\n OUTPUT_TOKEN_METRIC,\n accumulate,\n createAccumulator,\n tokenFieldOf,\n toUsage,\n} from './usage-accumulator';\nimport type { ExperimentItemUsage, UsageAccumulator } from './usage-accumulator';\n\nexport type { ExperimentItemUsage } from './usage-accumulator';\n\nconst POLL_INTERVAL_MS = 2000;\n\n/** Usage of one experiment: its totals, and each item's usage keyed by the trace id of its run. */\nexport interface ExperimentUsage {\n /** Totals across every item. The cost sums priced groups only. */\n summary: ExperimentItemUsage;\n traces: Record<string, ExperimentItemUsage>;\n}\n\n/** Builds the experiment totals and the per-trace usage in a single pass over the groups. */\nfunction toExperimentUsage(response: GetMetricBreakdownResponse): ExperimentUsage {\n const summary = createAccumulator();\n const accumulators = new Map<string, UsageAccumulator>();\n\n for (const group of response.groups) {\n const tokenField = tokenFieldOf(group);\n if (!tokenField) continue;\n\n accumulate(summary, tokenField, group);\n\n const traceId = group.dimensions.traceId;\n if (traceId) accumulate(getOrCreate(accumulators, traceId, createAccumulator), tokenField, group);\n }\n\n const traces: Record<string, ExperimentItemUsage> = {};\n for (const [traceId, accumulator] of accumulators) {\n traces[traceId] = toUsage(accumulator);\n }\n return { summary: toUsage(summary), traces };\n}\n\n/** How many breakdowns to fetch after completion while the exporter may still be flushing metrics. */\nconst MAX_EMPTY_ATTEMPTS = 5;\n\nconst isEmptyUsage = (usage: ExperimentUsage | undefined) =>\n !usage ||\n (Object.keys(usage.traces).length === 0 &&\n usage.summary.inputTokens === undefined &&\n usage.summary.outputTokens === undefined);\n\n/**\n * Token and cost usage of several experiments, keyed by experiment id: each entry holds the\n * experiment totals (`summary`) and every item's usage keyed by trace id (`traces`).\n * Sends one metric breakdown request per experiment, filtered by its id rather than by trace ids,\n * so it does not wait for the experiment results. Usage is only fetched once an experiment has\n * finished; while the breakdown is still empty (metrics flushing), it retries every 2 seconds up to\n * 5 attempts. No request is made when the observability store cannot serve metrics.\n */\nexport const useExperimentsItemUsage = ({\n experiments,\n supportsMetrics,\n}: {\n experiments: ExperimentRef[];\n supportsMetrics: boolean;\n}): ExperimentQueriesResult<ExperimentUsage> => {\n const client = useMastraClient();\n const combine = useCombineByIds<ExperimentUsage>(experiments.map(experiment => experiment.id));\n\n return useQueries({\n queries: experiments.map(({ id, status }) => {\n const finished = status !== 'running' && status !== 'pending';\n return {\n queryKey: ['experiment-item-usage', id, finished],\n queryFn: async () =>\n toExperimentUsage(\n await client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['traceId', 'name'],\n filters: { experimentId: id },\n }),\n ),\n enabled: supportsMetrics && finished,\n refetchInterval: (query: Query<ExperimentUsage>) =>\n isEmptyUsage(query.state.data) && query.state.dataUpdateCount < MAX_EMPTY_ATTEMPTS ? POLL_INTERVAL_MS : false,\n };\n }),\n combine,\n });\n};\n","import type { DatasetExperiment } from '@mastra/client-js';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\nexport interface ExperimentMetrics {\n totalTokens: number | null;\n estimatedCost: number | null;\n costUnit: string | null;\n avgAgentDurationMs: number | null;\n agentRuns: number | null;\n}\n\ninterface UseExperimentMetricsArgs {\n experimentId: string | undefined;\n experimentStatus: DatasetExperiment['status'] | undefined;\n /** Whether the observability store can serve metrics; no requests are made when false. */\n supportsMetrics: boolean;\n queryOptions?: MastraQueryOptions<ExperimentMetrics>;\n}\n\n/**\n * Experiment-scoped metrics (tokens, cost, avg agent latency).\n * Filters only by experimentId — no time window, since the experiment already bounds the row set.\n * Polls every 2 seconds while the experiment is running or pending.\n *\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useExperimentMetrics = ({\n experimentId,\n experimentStatus,\n supportsMetrics,\n queryOptions,\n}: UseExperimentMetricsArgs) => {\n const client = useMastraClient();\n const isEnabled = Boolean(experimentId) && supportsMetrics;\n const isActive = experimentStatus === 'running' || experimentStatus === 'pending';\n\n const query = useQuery({\n queryKey: ['experiment-metrics', experimentId],\n refetchInterval: isActive ? 2000 : false,\n queryFn: async (): Promise<ExperimentMetrics> => {\n // `enabled` already guards this; the check exists to narrow the type.\n if (!experimentId) throw new Error('experimentId is required');\n const filters = { experimentId };\n\n const [tokens, avgDuration, runs] = await Promise.all([\n client.getMetricAggregate({\n name: ['mastra_model_total_input_tokens', 'mastra_model_total_output_tokens'],\n aggregation: 'sum',\n filters,\n }),\n client.getMetricAggregate({ name: ['mastra_agent_duration_ms'], aggregation: 'avg', filters }),\n client.getMetricAggregate({ name: ['mastra_agent_duration_ms'], aggregation: 'count', filters }),\n ]);\n\n return {\n totalTokens: tokens.value ?? null,\n estimatedCost: tokens.estimatedCost ?? null,\n costUnit: tokens.costUnit ?? null,\n avgAgentDurationMs: avgDuration.value ?? null,\n agentRuns: runs.value ?? null,\n };\n },\n ...queryOptions,\n });\n\n return { data: query.data, isLoading: query.isLoading, isEnabled };\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\ntype TraceLightResponse = Awaited<ReturnType<MastraClient['getTraceLight']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useExperimentTrace = <TData = TraceLightResponse>({\n traceId,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n queryOptions?: MastraQueryOptions<TraceLightResponse, TData>;\n}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['experiment-trace-light', traceId],\n queryFn: async () => {\n if (!traceId) {\n throw new Error('Trace ID is required');\n }\n return client.getTraceLight(traceId);\n },\n ...queryOptions,\n });\n};\n","import type { ExperimentTargetType, ListExperimentsParams, MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\n/** Explicit page size: server defaults are 20 (global) / 10 (per dataset), which is too small for the list. */\nexport const EXPERIMENTS_PAGE_SIZE = 100;\n\nexport interface ExperimentTargetFilter {\n targetType?: ExperimentTargetType | '';\n targetId?: string;\n}\n\n/**\n * Experiments for the list page: the global list, or the dataset-scoped list when a dataset filter is active.\n * A dataset's runs may not be in the first page of the global list, so filtering client-side is not enough.\n * The optional target filter is applied server-side for the same reason.\n */\ntype ListExperimentsResponse = Awaited<ReturnType<MastraClient['listExperiments']>>;\n\nexport function useExperimentsForDatasetFilter<TData = ListExperimentsResponse>({\n datasetId,\n target,\n queryOptions,\n}: {\n datasetId: string | undefined;\n target?: ExperimentTargetFilter;\n queryOptions?: MastraQueryOptions<ListExperimentsResponse, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n const params: ListExperimentsParams = { perPage: EXPERIMENTS_PAGE_SIZE };\n if (target?.targetType) params.targetType = target.targetType;\n if (target?.targetId) params.targetId = target.targetId;\n\n return useQuery({\n // Prefixes match the keys invalidated by dataset/experiment mutations.\n queryKey: datasetId ? ['dataset-experiments', datasetId, params] : ['experiments', params],\n queryFn: () => (datasetId ? client.listDatasetExperiments(datasetId, params) : client.listExperiments(params)),\n ...queryOptions,\n });\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport { keepPreviousData, useQuery } from '@tanstack/react-query';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { ExperimentRef } from '../datasets/use-dataset-experiments';\nimport { getOrCreate } from '../shared/map';\nimport {\n INPUT_TOKEN_METRIC,\n OUTPUT_TOKEN_METRIC,\n accumulate,\n createAccumulator,\n tokenFieldOf,\n toUsage,\n} from './usage-accumulator';\nimport type { ExperimentItemUsage, UsageAccumulator } from './usage-accumulator';\n\nconst AGENT_DURATION_METRIC = 'mastra_agent_duration_ms';\n// Each experiment can return two token groups, while the breakdown endpoint allows at most 1,000.\nconst EXPERIMENT_IDS_PER_REQUEST = 500;\nconst POLL_INTERVAL_MS = 5000;\n\n/** Totals of one experiment: token usage, its estimated cost, and the average agent run duration. */\nexport interface ExperimentListMetrics extends ExperimentItemUsage {\n avgDurationMs?: number;\n}\n\nfunction chunk(ids: readonly string[]): string[][] {\n const chunks: string[][] = [];\n for (let index = 0; index < ids.length; index += EXPERIMENT_IDS_PER_REQUEST) {\n chunks.push(ids.slice(index, index + EXPERIMENT_IDS_PER_REQUEST));\n }\n return chunks;\n}\n\nfunction settledValues<T>(results: PromiseSettledResult<T>[]): T[] {\n return results.flatMap(result => (result.status === 'fulfilled' ? [result.value] : []));\n}\n\n/**\n * Builds each requested experiment's metrics. Groups for other experiments are skipped,\n * in case a store ignores the `experimentIds` filter.\n */\nfunction toListMetrics(\n experimentIds: readonly string[],\n tokenResponses: GetMetricBreakdownResponse[],\n durationResponses: GetMetricBreakdownResponse[],\n): Map<string, ExperimentListMetrics> {\n const requested = new Set(experimentIds);\n const accumulators = new Map<string, UsageAccumulator>();\n for (const group of tokenResponses.flatMap(response => response.groups)) {\n const experimentId = group.dimensions.experimentId;\n const tokenField = tokenFieldOf(group);\n if (!experimentId || !requested.has(experimentId) || !tokenField) continue;\n accumulate(getOrCreate(accumulators, experimentId, createAccumulator), tokenField, group);\n }\n\n const metrics = new Map<string, ExperimentListMetrics>();\n for (const [experimentId, accumulator] of accumulators) {\n metrics.set(experimentId, toUsage(accumulator));\n }\n for (const group of durationResponses.flatMap(response => response.groups)) {\n const experimentId = group.dimensions.experimentId;\n if (!experimentId || !requested.has(experimentId)) continue;\n getOrCreate(metrics, experimentId, (): ExperimentListMetrics => ({})).avgDurationMs = group.value;\n }\n return metrics;\n}\n\n/**\n * Token usage, estimated cost and average agent duration of many experiments, keyed by experiment id.\n * Sends two metric breakdowns per 500 experiments (tokens grouped by experiment and metric name,\n * durations grouped by experiment) instead of one request per experiment.\n * Experiments without any metric are absent from the map. Polls while an experiment is running\n * or pending. No request is made when the observability store cannot serve metrics.\n */\nexport const useExperimentsListMetrics = ({\n experiments,\n supportsMetrics,\n}: {\n experiments: ExperimentRef[];\n supportsMetrics: boolean;\n}): UseQueryResult<Map<string, ExperimentListMetrics>, Error> => {\n const client = useMastraClient();\n const experimentIds = [...new Set(experiments.map(experiment => experiment.id))].toSorted();\n const hasActiveExperiment = experiments.some(({ status }) => status === 'running' || status === 'pending');\n\n return useQuery({\n queryKey: ['experiments-list-metrics', experimentIds],\n enabled: supportsMetrics && experimentIds.length > 0,\n queryFn: async () => {\n const batches = chunk(experimentIds);\n const [tokenResults, durationResults] = await Promise.all([\n Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['experimentId', 'name'],\n filters: { experimentIds: batch },\n limit: batch.length * 2,\n }),\n ),\n ),\n Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [AGENT_DURATION_METRIC],\n aggregation: 'avg',\n groupBy: ['experimentId'],\n filters: { experimentIds: batch },\n limit: batch.length,\n }),\n ),\n ),\n ]);\n return toListMetrics(experimentIds, settledValues(tokenResults), settledValues(durationResults));\n },\n // Loading another page changes the ids; keep the rows already shown filled meanwhile.\n placeholderData: keepPreviousData,\n refetchInterval: hasActiveExperiment ? POLL_INTERVAL_MS : false,\n });\n};\n","import type { DatasetExperiment, ListExperimentsParams, MastraClient } from '@mastra/client-js';\nimport { useInfiniteQuery } from '@tanstack/react-query';\nimport type { InfiniteData, QueryKey, UseInfiniteQueryResult } from '@tanstack/react-query';\nimport { useEffect } from 'react';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraInfiniteQueryOptions } from '../shared/query-options';\nimport { useInView } from '../shared/use-in-view';\nimport type { ExperimentTargetFilter } from './use-experiments-for-dataset-filter';\n\nexport const EXPERIMENTS_PER_PAGE = 100;\n\n/**\n * Infinite-scroll experiments for the list page: the global list, or the dataset-scoped list when a\n * dataset filter is active (a dataset's runs may not be in the first pages of the global list). The\n * optional target filter is applied server-side for the same reason.\n */\nexport type ExperimentsOrderBy = NonNullable<ListExperimentsParams['orderBy']>;\n\ntype ListExperimentsResponse = Awaited<ReturnType<MastraClient['listExperiments']>>;\n\nexport function useInfiniteExperiments<TData = DatasetExperiment[]>({\n datasetId,\n target,\n orderBy,\n queryOptions,\n}: {\n datasetId: string | undefined;\n target?: ExperimentTargetFilter;\n orderBy?: ExperimentsOrderBy;\n queryOptions?: MastraInfiniteQueryOptions<ListExperimentsResponse, TData, QueryKey, number>;\n}): UseInfiniteQueryResult<TData, Error> & {\n setEndOfListElement: (element: HTMLDivElement | null) => void;\n} {\n const client = useMastraClient();\n const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();\n const targetType = target?.targetType || undefined;\n const targetId = target?.targetId || undefined;\n\n const query = useInfiniteQuery({\n // Prefixes match the keys invalidated by dataset/experiment mutations.\n queryKey: datasetId\n ? ['dataset-experiments', datasetId, 'infinite', { targetType, targetId, orderBy }]\n : ['experiments', 'infinite', { targetType, targetId, orderBy }],\n queryFn: ({ pageParam }) => {\n const params: ListExperimentsParams = { page: pageParam, perPage: EXPERIMENTS_PER_PAGE };\n if (targetType) params.targetType = targetType;\n if (targetId) params.targetId = targetId;\n if (orderBy) params.orderBy = orderBy;\n return datasetId ? client.listDatasetExperiments(datasetId, params) : client.listExperiments(params);\n },\n initialPageParam: 0,\n getNextPageParam: (lastPage, _, lastPageParam) => {\n if (!lastPage?.experiments?.length || !lastPage.pagination?.hasMore) {\n return undefined;\n }\n return lastPageParam + 1;\n },\n select: (data: InfiniteData<ListExperimentsResponse, number>) =>\n data.pages.flatMap(page => page?.experiments ?? []) as TData,\n ...queryOptions,\n });\n\n useEffect(() => {\n if (isEndOfListInView && query.hasNextPage && !query.isFetchingNextPage) {\n void query.fetchNextPage();\n }\n }, [isEndOfListInView, query]);\n\n return { ...query, setEndOfListElement };\n}\n"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
- import { n as useMastraClient } from "./mastra-client-context-Bx_g84YB.js";
2
- import { t as useInView } from "./use-in-view-C9sYPGRm.js";
3
- import { t as useCombineByIds } from "./combine-by-ids-CcaZKGT9.js";
4
- import { t as getOrCreate } from "./map-CDv4fbu4.js";
1
+ import { n as useMastraClient } from "./mastra-client-context-DQ5z_ze9.js";
2
+ import { t as useInView } from "./use-in-view-CyjKdplM.js";
3
+ import { t as useCombineByIds } from "./combine-by-ids-C-0oe4eH.js";
4
+ import { t as getOrCreate } from "./map-5-4U5rwA.js";
5
5
  import { useEffect } from "react";
6
6
  import { keepPreviousData, useInfiniteQuery, useQueries, useQuery } from "@tanstack/react-query";
7
- //#region src/hooks/experiments/usage-accumulator.ts
7
+ // src/hooks/experiments/usage-accumulator.ts
8
8
  const INPUT_TOKEN_METRIC = "mastra_model_total_input_tokens";
9
9
  const OUTPUT_TOKEN_METRIC = "mastra_model_total_output_tokens";
10
10
  const createAccumulator = () => ({
@@ -34,8 +34,7 @@ function toUsage(accumulator) {
34
34
  costUnit: isPriced ? [...accumulator.costUnits][0] : void 0
35
35
  };
36
36
  }
37
- //#endregion
38
- //#region src/hooks/experiments/use-experiment-item-usage.ts
37
+ // src/hooks/experiments/use-experiment-item-usage.ts
39
38
  const POLL_INTERVAL_MS$1 = 2e3;
40
39
  /** Builds the experiment totals and the per-trace usage in a single pass over the groups. */
41
40
  function toExperimentUsage(response) {
@@ -91,8 +90,7 @@ const useExperimentsItemUsage = ({ experiments, supportsMetrics }) => {
91
90
  combine
92
91
  });
93
92
  };
94
- //#endregion
95
- //#region src/hooks/experiments/use-experiment-metrics.ts
93
+ // src/hooks/experiments/use-experiment-metrics.ts
96
94
  /**
97
95
  * Experiment-scoped metrics (tokens, cost, avg agent latency).
98
96
  * Filters only by experimentId — no time window, since the experiment already bounds the row set.
@@ -142,8 +140,7 @@ const useExperimentMetrics = ({ experimentId, experimentStatus, supportsMetrics,
142
140
  isEnabled
143
141
  };
144
142
  };
145
- //#endregion
146
- //#region src/hooks/experiments/use-experiment-trace.ts
143
+ // src/hooks/experiments/use-experiment-trace.ts
147
144
  /**
148
145
  * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.
149
146
  */
@@ -158,8 +155,7 @@ const useExperimentTrace = ({ traceId, queryOptions }) => {
158
155
  ...queryOptions
159
156
  });
160
157
  };
161
- //#endregion
162
- //#region src/hooks/experiments/use-experiments-for-dataset-filter.ts
158
+ // src/hooks/experiments/use-experiments-for-dataset-filter.ts
163
159
  /** Explicit page size: server defaults are 20 (global) / 10 (per dataset), which is too small for the list. */
164
160
  const EXPERIMENTS_PAGE_SIZE = 100;
165
161
  function useExperimentsForDatasetFilter({ datasetId, target, queryOptions }) {
@@ -177,8 +173,7 @@ function useExperimentsForDatasetFilter({ datasetId, target, queryOptions }) {
177
173
  ...queryOptions
178
174
  });
179
175
  }
180
- //#endregion
181
- //#region src/hooks/experiments/use-experiments-list-metrics.ts
176
+ // src/hooks/experiments/use-experiments-list-metrics.ts
182
177
  const AGENT_DURATION_METRIC = "mastra_agent_duration_ms";
183
178
  const EXPERIMENT_IDS_PER_REQUEST = 500;
184
179
  const POLL_INTERVAL_MS = 5e3;
@@ -247,8 +242,7 @@ const useExperimentsListMetrics = ({ experiments, supportsMetrics }) => {
247
242
  refetchInterval: hasActiveExperiment ? POLL_INTERVAL_MS : false
248
243
  });
249
244
  };
250
- //#endregion
251
- //#region src/hooks/experiments/use-infinite-experiments.ts
245
+ // src/hooks/experiments/use-infinite-experiments.ts
252
246
  const EXPERIMENTS_PER_PAGE = 100;
253
247
  function useInfiniteExperiments({ datasetId, target, orderBy, queryOptions }) {
254
248
  const client = useMastraClient();
@@ -300,7 +294,6 @@ function useInfiniteExperiments({ datasetId, target, orderBy, queryOptions }) {
300
294
  setEndOfListElement
301
295
  };
302
296
  }
303
- //#endregion
304
297
  export { useExperimentsForDatasetFilter as a, useExperimentsItemUsage as c, EXPERIMENTS_PAGE_SIZE as i, useInfiniteExperiments as n, useExperimentTrace as o, useExperimentsListMetrics as r, useExperimentMetrics as s, EXPERIMENTS_PER_PAGE as t };
305
298
 
306
- //# sourceMappingURL=experiments-B7vRMK5T.js.map
299
+ //# sourceMappingURL=experiments-DyecjEut.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"experiments-B7vRMK5T.js","names":["POLL_INTERVAL_MS"],"sources":["../src/hooks/experiments/usage-accumulator.ts","../src/hooks/experiments/use-experiment-item-usage.ts","../src/hooks/experiments/use-experiment-metrics.ts","../src/hooks/experiments/use-experiment-trace.ts","../src/hooks/experiments/use-experiments-for-dataset-filter.ts","../src/hooks/experiments/use-experiments-list-metrics.ts","../src/hooks/experiments/use-infinite-experiments.ts"],"sourcesContent":["import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\n\nexport const INPUT_TOKEN_METRIC = 'mastra_model_total_input_tokens';\nexport const OUTPUT_TOKEN_METRIC = 'mastra_model_total_output_tokens';\n\nexport interface ExperimentItemUsage {\n inputTokens?: number;\n outputTokens?: number;\n /** Undefined when no group is priced or when groups use different cost units. */\n estimatedCost?: number;\n costUnit?: string;\n}\n\nexport type UsageAccumulator = {\n inputTokens?: number;\n outputTokens?: number;\n estimatedCost: number;\n costUnits: Set<string>;\n hasUnknownCostUnit: boolean;\n};\n\nexport const createAccumulator = (): UsageAccumulator => ({\n estimatedCost: 0,\n costUnits: new Set(),\n hasUnknownCostUnit: false,\n});\n\ntype BreakdownGroup = GetMetricBreakdownResponse['groups'][number];\n\n/** The token field a breakdown group feeds, or undefined when the group is not a token metric. */\nexport function tokenFieldOf(group: BreakdownGroup): 'inputTokens' | 'outputTokens' | undefined {\n const metricName = group.dimensions.name;\n if (metricName === INPUT_TOKEN_METRIC) return 'inputTokens';\n if (metricName === OUTPUT_TOKEN_METRIC) return 'outputTokens';\n return undefined;\n}\n\nexport function accumulate(\n accumulator: UsageAccumulator,\n tokenField: 'inputTokens' | 'outputTokens',\n group: BreakdownGroup,\n) {\n accumulator[tokenField] = (accumulator[tokenField] ?? 0) + group.value;\n\n if (group.estimatedCost == null) return;\n accumulator.estimatedCost += group.estimatedCost;\n if (group.costUnit) {\n accumulator.costUnits.add(group.costUnit.toLowerCase());\n } else {\n accumulator.hasUnknownCostUnit = true;\n }\n}\n\nexport function toUsage(accumulator: UsageAccumulator): ExperimentItemUsage {\n // A single known unit implies at least one priced group.\n const isPriced = !accumulator.hasUnknownCostUnit && accumulator.costUnits.size === 1;\n return {\n inputTokens: accumulator.inputTokens,\n outputTokens: accumulator.outputTokens,\n estimatedCost: isPriced ? accumulator.estimatedCost : undefined,\n costUnit: isPriced ? [...accumulator.costUnits][0] : undefined,\n };\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport { useQueries } from '@tanstack/react-query';\nimport type { Query } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { ExperimentRef } from '../datasets/use-dataset-experiments';\nimport { useCombineByIds } from '../shared/combine-by-ids';\nimport type { ExperimentQueriesResult } from '../shared/combine-by-ids';\nimport { getOrCreate } from '../shared/map';\nimport {\n INPUT_TOKEN_METRIC,\n OUTPUT_TOKEN_METRIC,\n accumulate,\n createAccumulator,\n tokenFieldOf,\n toUsage,\n} from './usage-accumulator';\nimport type { ExperimentItemUsage, UsageAccumulator } from './usage-accumulator';\n\nexport type { ExperimentItemUsage } from './usage-accumulator';\n\nconst POLL_INTERVAL_MS = 2000;\n\n/** Usage of one experiment: its totals, and each item's usage keyed by the trace id of its run. */\nexport interface ExperimentUsage {\n /** Totals across every item. The cost sums priced groups only. */\n summary: ExperimentItemUsage;\n traces: Record<string, ExperimentItemUsage>;\n}\n\n/** Builds the experiment totals and the per-trace usage in a single pass over the groups. */\nfunction toExperimentUsage(response: GetMetricBreakdownResponse): ExperimentUsage {\n const summary = createAccumulator();\n const accumulators = new Map<string, UsageAccumulator>();\n\n for (const group of response.groups) {\n const tokenField = tokenFieldOf(group);\n if (!tokenField) continue;\n\n accumulate(summary, tokenField, group);\n\n const traceId = group.dimensions.traceId;\n if (traceId) accumulate(getOrCreate(accumulators, traceId, createAccumulator), tokenField, group);\n }\n\n const traces: Record<string, ExperimentItemUsage> = {};\n for (const [traceId, accumulator] of accumulators) {\n traces[traceId] = toUsage(accumulator);\n }\n return { summary: toUsage(summary), traces };\n}\n\n/** How many breakdowns to fetch after completion while the exporter may still be flushing metrics. */\nconst MAX_EMPTY_ATTEMPTS = 5;\n\nconst isEmptyUsage = (usage: ExperimentUsage | undefined) =>\n !usage ||\n (Object.keys(usage.traces).length === 0 &&\n usage.summary.inputTokens === undefined &&\n usage.summary.outputTokens === undefined);\n\n/**\n * Token and cost usage of several experiments, keyed by experiment id: each entry holds the\n * experiment totals (`summary`) and every item's usage keyed by trace id (`traces`).\n * Sends one metric breakdown request per experiment, filtered by its id rather than by trace ids,\n * so it does not wait for the experiment results. Usage is only fetched once an experiment has\n * finished; while the breakdown is still empty (metrics flushing), it retries every 2 seconds up to\n * 5 attempts. No request is made when the observability store cannot serve metrics.\n */\nexport const useExperimentsItemUsage = ({\n experiments,\n supportsMetrics,\n}: {\n experiments: ExperimentRef[];\n supportsMetrics: boolean;\n}): ExperimentQueriesResult<ExperimentUsage> => {\n const client = useMastraClient();\n const combine = useCombineByIds<ExperimentUsage>(experiments.map(experiment => experiment.id));\n\n return useQueries({\n queries: experiments.map(({ id, status }) => {\n const finished = status !== 'running' && status !== 'pending';\n return {\n queryKey: ['experiment-item-usage', id, finished],\n queryFn: async () =>\n toExperimentUsage(\n await client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['traceId', 'name'],\n filters: { experimentId: id },\n }),\n ),\n enabled: supportsMetrics && finished,\n refetchInterval: (query: Query<ExperimentUsage>) =>\n isEmptyUsage(query.state.data) && query.state.dataUpdateCount < MAX_EMPTY_ATTEMPTS ? POLL_INTERVAL_MS : false,\n };\n }),\n combine,\n });\n};\n","import type { DatasetExperiment } from '@mastra/client-js';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\nexport interface ExperimentMetrics {\n totalTokens: number | null;\n estimatedCost: number | null;\n costUnit: string | null;\n avgAgentDurationMs: number | null;\n agentRuns: number | null;\n}\n\ninterface UseExperimentMetricsArgs {\n experimentId: string | undefined;\n experimentStatus: DatasetExperiment['status'] | undefined;\n /** Whether the observability store can serve metrics; no requests are made when false. */\n supportsMetrics: boolean;\n queryOptions?: MastraQueryOptions<ExperimentMetrics>;\n}\n\n/**\n * Experiment-scoped metrics (tokens, cost, avg agent latency).\n * Filters only by experimentId — no time window, since the experiment already bounds the row set.\n * Polls every 2 seconds while the experiment is running or pending.\n *\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useExperimentMetrics = ({\n experimentId,\n experimentStatus,\n supportsMetrics,\n queryOptions,\n}: UseExperimentMetricsArgs) => {\n const client = useMastraClient();\n const isEnabled = Boolean(experimentId) && supportsMetrics;\n const isActive = experimentStatus === 'running' || experimentStatus === 'pending';\n\n const query = useQuery({\n queryKey: ['experiment-metrics', experimentId],\n refetchInterval: isActive ? 2000 : false,\n queryFn: async (): Promise<ExperimentMetrics> => {\n // `enabled` already guards this; the check exists to narrow the type.\n if (!experimentId) throw new Error('experimentId is required');\n const filters = { experimentId };\n\n const [tokens, avgDuration, runs] = await Promise.all([\n client.getMetricAggregate({\n name: ['mastra_model_total_input_tokens', 'mastra_model_total_output_tokens'],\n aggregation: 'sum',\n filters,\n }),\n client.getMetricAggregate({ name: ['mastra_agent_duration_ms'], aggregation: 'avg', filters }),\n client.getMetricAggregate({ name: ['mastra_agent_duration_ms'], aggregation: 'count', filters }),\n ]);\n\n return {\n totalTokens: tokens.value ?? null,\n estimatedCost: tokens.estimatedCost ?? null,\n costUnit: tokens.costUnit ?? null,\n avgAgentDurationMs: avgDuration.value ?? null,\n agentRuns: runs.value ?? null,\n };\n },\n ...queryOptions,\n });\n\n return { data: query.data, isLoading: query.isLoading, isEnabled };\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\ntype TraceLightResponse = Awaited<ReturnType<MastraClient['getTraceLight']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useExperimentTrace = <TData = TraceLightResponse>({\n traceId,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n queryOptions?: MastraQueryOptions<TraceLightResponse, TData>;\n}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['experiment-trace-light', traceId],\n queryFn: async () => {\n if (!traceId) {\n throw new Error('Trace ID is required');\n }\n return client.getTraceLight(traceId);\n },\n ...queryOptions,\n });\n};\n","import type { ExperimentTargetType, ListExperimentsParams, MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\n/** Explicit page size: server defaults are 20 (global) / 10 (per dataset), which is too small for the list. */\nexport const EXPERIMENTS_PAGE_SIZE = 100;\n\nexport interface ExperimentTargetFilter {\n targetType?: ExperimentTargetType | '';\n targetId?: string;\n}\n\n/**\n * Experiments for the list page: the global list, or the dataset-scoped list when a dataset filter is active.\n * A dataset's runs may not be in the first page of the global list, so filtering client-side is not enough.\n * The optional target filter is applied server-side for the same reason.\n */\ntype ListExperimentsResponse = Awaited<ReturnType<MastraClient['listExperiments']>>;\n\nexport function useExperimentsForDatasetFilter<TData = ListExperimentsResponse>({\n datasetId,\n target,\n queryOptions,\n}: {\n datasetId: string | undefined;\n target?: ExperimentTargetFilter;\n queryOptions?: MastraQueryOptions<ListExperimentsResponse, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n const params: ListExperimentsParams = { perPage: EXPERIMENTS_PAGE_SIZE };\n if (target?.targetType) params.targetType = target.targetType;\n if (target?.targetId) params.targetId = target.targetId;\n\n return useQuery({\n // Prefixes match the keys invalidated by dataset/experiment mutations.\n queryKey: datasetId ? ['dataset-experiments', datasetId, params] : ['experiments', params],\n queryFn: () => (datasetId ? client.listDatasetExperiments(datasetId, params) : client.listExperiments(params)),\n ...queryOptions,\n });\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport { keepPreviousData, useQuery } from '@tanstack/react-query';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { ExperimentRef } from '../datasets/use-dataset-experiments';\nimport { getOrCreate } from '../shared/map';\nimport {\n INPUT_TOKEN_METRIC,\n OUTPUT_TOKEN_METRIC,\n accumulate,\n createAccumulator,\n tokenFieldOf,\n toUsage,\n} from './usage-accumulator';\nimport type { ExperimentItemUsage, UsageAccumulator } from './usage-accumulator';\n\nconst AGENT_DURATION_METRIC = 'mastra_agent_duration_ms';\n// Each experiment can return two token groups, while the breakdown endpoint allows at most 1,000.\nconst EXPERIMENT_IDS_PER_REQUEST = 500;\nconst POLL_INTERVAL_MS = 5000;\n\n/** Totals of one experiment: token usage, its estimated cost, and the average agent run duration. */\nexport interface ExperimentListMetrics extends ExperimentItemUsage {\n avgDurationMs?: number;\n}\n\nfunction chunk(ids: readonly string[]): string[][] {\n const chunks: string[][] = [];\n for (let index = 0; index < ids.length; index += EXPERIMENT_IDS_PER_REQUEST) {\n chunks.push(ids.slice(index, index + EXPERIMENT_IDS_PER_REQUEST));\n }\n return chunks;\n}\n\nfunction settledValues<T>(results: PromiseSettledResult<T>[]): T[] {\n return results.flatMap(result => (result.status === 'fulfilled' ? [result.value] : []));\n}\n\n/**\n * Builds each requested experiment's metrics. Groups for other experiments are skipped,\n * in case a store ignores the `experimentIds` filter.\n */\nfunction toListMetrics(\n experimentIds: readonly string[],\n tokenResponses: GetMetricBreakdownResponse[],\n durationResponses: GetMetricBreakdownResponse[],\n): Map<string, ExperimentListMetrics> {\n const requested = new Set(experimentIds);\n const accumulators = new Map<string, UsageAccumulator>();\n for (const group of tokenResponses.flatMap(response => response.groups)) {\n const experimentId = group.dimensions.experimentId;\n const tokenField = tokenFieldOf(group);\n if (!experimentId || !requested.has(experimentId) || !tokenField) continue;\n accumulate(getOrCreate(accumulators, experimentId, createAccumulator), tokenField, group);\n }\n\n const metrics = new Map<string, ExperimentListMetrics>();\n for (const [experimentId, accumulator] of accumulators) {\n metrics.set(experimentId, toUsage(accumulator));\n }\n for (const group of durationResponses.flatMap(response => response.groups)) {\n const experimentId = group.dimensions.experimentId;\n if (!experimentId || !requested.has(experimentId)) continue;\n getOrCreate(metrics, experimentId, (): ExperimentListMetrics => ({})).avgDurationMs = group.value;\n }\n return metrics;\n}\n\n/**\n * Token usage, estimated cost and average agent duration of many experiments, keyed by experiment id.\n * Sends two metric breakdowns per 500 experiments (tokens grouped by experiment and metric name,\n * durations grouped by experiment) instead of one request per experiment.\n * Experiments without any metric are absent from the map. Polls while an experiment is running\n * or pending. No request is made when the observability store cannot serve metrics.\n */\nexport const useExperimentsListMetrics = ({\n experiments,\n supportsMetrics,\n}: {\n experiments: ExperimentRef[];\n supportsMetrics: boolean;\n}): UseQueryResult<Map<string, ExperimentListMetrics>, Error> => {\n const client = useMastraClient();\n const experimentIds = [...new Set(experiments.map(experiment => experiment.id))].toSorted();\n const hasActiveExperiment = experiments.some(({ status }) => status === 'running' || status === 'pending');\n\n return useQuery({\n queryKey: ['experiments-list-metrics', experimentIds],\n enabled: supportsMetrics && experimentIds.length > 0,\n queryFn: async () => {\n const batches = chunk(experimentIds);\n const [tokenResults, durationResults] = await Promise.all([\n Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['experimentId', 'name'],\n filters: { experimentIds: batch },\n limit: batch.length * 2,\n }),\n ),\n ),\n Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [AGENT_DURATION_METRIC],\n aggregation: 'avg',\n groupBy: ['experimentId'],\n filters: { experimentIds: batch },\n limit: batch.length,\n }),\n ),\n ),\n ]);\n return toListMetrics(experimentIds, settledValues(tokenResults), settledValues(durationResults));\n },\n // Loading another page changes the ids; keep the rows already shown filled meanwhile.\n placeholderData: keepPreviousData,\n refetchInterval: hasActiveExperiment ? POLL_INTERVAL_MS : false,\n });\n};\n","import type { DatasetExperiment, ListExperimentsParams, MastraClient } from '@mastra/client-js';\nimport { useInfiniteQuery } from '@tanstack/react-query';\nimport type { InfiniteData, QueryKey, UseInfiniteQueryResult } from '@tanstack/react-query';\nimport { useEffect } from 'react';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraInfiniteQueryOptions } from '../shared/query-options';\nimport { useInView } from '../shared/use-in-view';\nimport type { ExperimentTargetFilter } from './use-experiments-for-dataset-filter';\n\nexport const EXPERIMENTS_PER_PAGE = 100;\n\n/**\n * Infinite-scroll experiments for the list page: the global list, or the dataset-scoped list when a\n * dataset filter is active (a dataset's runs may not be in the first pages of the global list). The\n * optional target filter is applied server-side for the same reason.\n */\nexport type ExperimentsOrderBy = NonNullable<ListExperimentsParams['orderBy']>;\n\ntype ListExperimentsResponse = Awaited<ReturnType<MastraClient['listExperiments']>>;\n\nexport function useInfiniteExperiments<TData = DatasetExperiment[]>({\n datasetId,\n target,\n orderBy,\n queryOptions,\n}: {\n datasetId: string | undefined;\n target?: ExperimentTargetFilter;\n orderBy?: ExperimentsOrderBy;\n queryOptions?: MastraInfiniteQueryOptions<ListExperimentsResponse, TData, QueryKey, number>;\n}): UseInfiniteQueryResult<TData, Error> & {\n setEndOfListElement: (element: HTMLDivElement | null) => void;\n} {\n const client = useMastraClient();\n const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();\n const targetType = target?.targetType || undefined;\n const targetId = target?.targetId || undefined;\n\n const query = useInfiniteQuery({\n // Prefixes match the keys invalidated by dataset/experiment mutations.\n queryKey: datasetId\n ? ['dataset-experiments', datasetId, 'infinite', { targetType, targetId, orderBy }]\n : ['experiments', 'infinite', { targetType, targetId, orderBy }],\n queryFn: ({ pageParam }) => {\n const params: ListExperimentsParams = { page: pageParam, perPage: EXPERIMENTS_PER_PAGE };\n if (targetType) params.targetType = targetType;\n if (targetId) params.targetId = targetId;\n if (orderBy) params.orderBy = orderBy;\n return datasetId ? client.listDatasetExperiments(datasetId, params) : client.listExperiments(params);\n },\n initialPageParam: 0,\n getNextPageParam: (lastPage, _, lastPageParam) => {\n if (!lastPage?.experiments?.length || !lastPage.pagination?.hasMore) {\n return undefined;\n }\n return lastPageParam + 1;\n },\n select: (data: InfiniteData<ListExperimentsResponse, number>) =>\n data.pages.flatMap(page => page?.experiments ?? []) as TData,\n ...queryOptions,\n });\n\n useEffect(() => {\n if (isEndOfListInView && query.hasNextPage && !query.isFetchingNextPage) {\n void query.fetchNextPage();\n }\n }, [isEndOfListInView, query]);\n\n return { ...query, setEndOfListElement };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"experiments-DyecjEut.js","names":["POLL_INTERVAL_MS"],"sources":["../src/hooks/experiments/usage-accumulator.ts","../src/hooks/experiments/use-experiment-item-usage.ts","../src/hooks/experiments/use-experiment-metrics.ts","../src/hooks/experiments/use-experiment-trace.ts","../src/hooks/experiments/use-experiments-for-dataset-filter.ts","../src/hooks/experiments/use-experiments-list-metrics.ts","../src/hooks/experiments/use-infinite-experiments.ts"],"sourcesContent":["import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\n\nexport const INPUT_TOKEN_METRIC = 'mastra_model_total_input_tokens';\nexport const OUTPUT_TOKEN_METRIC = 'mastra_model_total_output_tokens';\n\nexport interface ExperimentItemUsage {\n inputTokens?: number;\n outputTokens?: number;\n /** Undefined when no group is priced or when groups use different cost units. */\n estimatedCost?: number;\n costUnit?: string;\n}\n\nexport type UsageAccumulator = {\n inputTokens?: number;\n outputTokens?: number;\n estimatedCost: number;\n costUnits: Set<string>;\n hasUnknownCostUnit: boolean;\n};\n\nexport const createAccumulator = (): UsageAccumulator => ({\n estimatedCost: 0,\n costUnits: new Set(),\n hasUnknownCostUnit: false,\n});\n\ntype BreakdownGroup = GetMetricBreakdownResponse['groups'][number];\n\n/** The token field a breakdown group feeds, or undefined when the group is not a token metric. */\nexport function tokenFieldOf(group: BreakdownGroup): 'inputTokens' | 'outputTokens' | undefined {\n const metricName = group.dimensions.name;\n if (metricName === INPUT_TOKEN_METRIC) return 'inputTokens';\n if (metricName === OUTPUT_TOKEN_METRIC) return 'outputTokens';\n return undefined;\n}\n\nexport function accumulate(\n accumulator: UsageAccumulator,\n tokenField: 'inputTokens' | 'outputTokens',\n group: BreakdownGroup,\n) {\n accumulator[tokenField] = (accumulator[tokenField] ?? 0) + group.value;\n\n if (group.estimatedCost == null) return;\n accumulator.estimatedCost += group.estimatedCost;\n if (group.costUnit) {\n accumulator.costUnits.add(group.costUnit.toLowerCase());\n } else {\n accumulator.hasUnknownCostUnit = true;\n }\n}\n\nexport function toUsage(accumulator: UsageAccumulator): ExperimentItemUsage {\n // A single known unit implies at least one priced group.\n const isPriced = !accumulator.hasUnknownCostUnit && accumulator.costUnits.size === 1;\n return {\n inputTokens: accumulator.inputTokens,\n outputTokens: accumulator.outputTokens,\n estimatedCost: isPriced ? accumulator.estimatedCost : undefined,\n costUnit: isPriced ? [...accumulator.costUnits][0] : undefined,\n };\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport { useQueries } from '@tanstack/react-query';\nimport type { Query } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { ExperimentRef } from '../datasets/use-dataset-experiments';\nimport { useCombineByIds } from '../shared/combine-by-ids';\nimport type { ExperimentQueriesResult } from '../shared/combine-by-ids';\nimport { getOrCreate } from '../shared/map';\nimport {\n INPUT_TOKEN_METRIC,\n OUTPUT_TOKEN_METRIC,\n accumulate,\n createAccumulator,\n tokenFieldOf,\n toUsage,\n} from './usage-accumulator';\nimport type { ExperimentItemUsage, UsageAccumulator } from './usage-accumulator';\n\nexport type { ExperimentItemUsage } from './usage-accumulator';\n\nconst POLL_INTERVAL_MS = 2000;\n\n/** Usage of one experiment: its totals, and each item's usage keyed by the trace id of its run. */\nexport interface ExperimentUsage {\n /** Totals across every item. The cost sums priced groups only. */\n summary: ExperimentItemUsage;\n traces: Record<string, ExperimentItemUsage>;\n}\n\n/** Builds the experiment totals and the per-trace usage in a single pass over the groups. */\nfunction toExperimentUsage(response: GetMetricBreakdownResponse): ExperimentUsage {\n const summary = createAccumulator();\n const accumulators = new Map<string, UsageAccumulator>();\n\n for (const group of response.groups) {\n const tokenField = tokenFieldOf(group);\n if (!tokenField) continue;\n\n accumulate(summary, tokenField, group);\n\n const traceId = group.dimensions.traceId;\n if (traceId) accumulate(getOrCreate(accumulators, traceId, createAccumulator), tokenField, group);\n }\n\n const traces: Record<string, ExperimentItemUsage> = {};\n for (const [traceId, accumulator] of accumulators) {\n traces[traceId] = toUsage(accumulator);\n }\n return { summary: toUsage(summary), traces };\n}\n\n/** How many breakdowns to fetch after completion while the exporter may still be flushing metrics. */\nconst MAX_EMPTY_ATTEMPTS = 5;\n\nconst isEmptyUsage = (usage: ExperimentUsage | undefined) =>\n !usage ||\n (Object.keys(usage.traces).length === 0 &&\n usage.summary.inputTokens === undefined &&\n usage.summary.outputTokens === undefined);\n\n/**\n * Token and cost usage of several experiments, keyed by experiment id: each entry holds the\n * experiment totals (`summary`) and every item's usage keyed by trace id (`traces`).\n * Sends one metric breakdown request per experiment, filtered by its id rather than by trace ids,\n * so it does not wait for the experiment results. Usage is only fetched once an experiment has\n * finished; while the breakdown is still empty (metrics flushing), it retries every 2 seconds up to\n * 5 attempts. No request is made when the observability store cannot serve metrics.\n */\nexport const useExperimentsItemUsage = ({\n experiments,\n supportsMetrics,\n}: {\n experiments: ExperimentRef[];\n supportsMetrics: boolean;\n}): ExperimentQueriesResult<ExperimentUsage> => {\n const client = useMastraClient();\n const combine = useCombineByIds<ExperimentUsage>(experiments.map(experiment => experiment.id));\n\n return useQueries({\n queries: experiments.map(({ id, status }) => {\n const finished = status !== 'running' && status !== 'pending';\n return {\n queryKey: ['experiment-item-usage', id, finished],\n queryFn: async () =>\n toExperimentUsage(\n await client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['traceId', 'name'],\n filters: { experimentId: id },\n }),\n ),\n enabled: supportsMetrics && finished,\n refetchInterval: (query: Query<ExperimentUsage>) =>\n isEmptyUsage(query.state.data) && query.state.dataUpdateCount < MAX_EMPTY_ATTEMPTS ? POLL_INTERVAL_MS : false,\n };\n }),\n combine,\n });\n};\n","import type { DatasetExperiment } from '@mastra/client-js';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\nexport interface ExperimentMetrics {\n totalTokens: number | null;\n estimatedCost: number | null;\n costUnit: string | null;\n avgAgentDurationMs: number | null;\n agentRuns: number | null;\n}\n\ninterface UseExperimentMetricsArgs {\n experimentId: string | undefined;\n experimentStatus: DatasetExperiment['status'] | undefined;\n /** Whether the observability store can serve metrics; no requests are made when false. */\n supportsMetrics: boolean;\n queryOptions?: MastraQueryOptions<ExperimentMetrics>;\n}\n\n/**\n * Experiment-scoped metrics (tokens, cost, avg agent latency).\n * Filters only by experimentId — no time window, since the experiment already bounds the row set.\n * Polls every 2 seconds while the experiment is running or pending.\n *\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useExperimentMetrics = ({\n experimentId,\n experimentStatus,\n supportsMetrics,\n queryOptions,\n}: UseExperimentMetricsArgs) => {\n const client = useMastraClient();\n const isEnabled = Boolean(experimentId) && supportsMetrics;\n const isActive = experimentStatus === 'running' || experimentStatus === 'pending';\n\n const query = useQuery({\n queryKey: ['experiment-metrics', experimentId],\n refetchInterval: isActive ? 2000 : false,\n queryFn: async (): Promise<ExperimentMetrics> => {\n // `enabled` already guards this; the check exists to narrow the type.\n if (!experimentId) throw new Error('experimentId is required');\n const filters = { experimentId };\n\n const [tokens, avgDuration, runs] = await Promise.all([\n client.getMetricAggregate({\n name: ['mastra_model_total_input_tokens', 'mastra_model_total_output_tokens'],\n aggregation: 'sum',\n filters,\n }),\n client.getMetricAggregate({ name: ['mastra_agent_duration_ms'], aggregation: 'avg', filters }),\n client.getMetricAggregate({ name: ['mastra_agent_duration_ms'], aggregation: 'count', filters }),\n ]);\n\n return {\n totalTokens: tokens.value ?? null,\n estimatedCost: tokens.estimatedCost ?? null,\n costUnit: tokens.costUnit ?? null,\n avgAgentDurationMs: avgDuration.value ?? null,\n agentRuns: runs.value ?? null,\n };\n },\n ...queryOptions,\n });\n\n return { data: query.data, isLoading: query.isLoading, isEnabled };\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\ntype TraceLightResponse = Awaited<ReturnType<MastraClient['getTraceLight']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useExperimentTrace = <TData = TraceLightResponse>({\n traceId,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n queryOptions?: MastraQueryOptions<TraceLightResponse, TData>;\n}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['experiment-trace-light', traceId],\n queryFn: async () => {\n if (!traceId) {\n throw new Error('Trace ID is required');\n }\n return client.getTraceLight(traceId);\n },\n ...queryOptions,\n });\n};\n","import type { ExperimentTargetType, ListExperimentsParams, MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\n/** Explicit page size: server defaults are 20 (global) / 10 (per dataset), which is too small for the list. */\nexport const EXPERIMENTS_PAGE_SIZE = 100;\n\nexport interface ExperimentTargetFilter {\n targetType?: ExperimentTargetType | '';\n targetId?: string;\n}\n\n/**\n * Experiments for the list page: the global list, or the dataset-scoped list when a dataset filter is active.\n * A dataset's runs may not be in the first page of the global list, so filtering client-side is not enough.\n * The optional target filter is applied server-side for the same reason.\n */\ntype ListExperimentsResponse = Awaited<ReturnType<MastraClient['listExperiments']>>;\n\nexport function useExperimentsForDatasetFilter<TData = ListExperimentsResponse>({\n datasetId,\n target,\n queryOptions,\n}: {\n datasetId: string | undefined;\n target?: ExperimentTargetFilter;\n queryOptions?: MastraQueryOptions<ListExperimentsResponse, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n const params: ListExperimentsParams = { perPage: EXPERIMENTS_PAGE_SIZE };\n if (target?.targetType) params.targetType = target.targetType;\n if (target?.targetId) params.targetId = target.targetId;\n\n return useQuery({\n // Prefixes match the keys invalidated by dataset/experiment mutations.\n queryKey: datasetId ? ['dataset-experiments', datasetId, params] : ['experiments', params],\n queryFn: () => (datasetId ? client.listDatasetExperiments(datasetId, params) : client.listExperiments(params)),\n ...queryOptions,\n });\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport { keepPreviousData, useQuery } from '@tanstack/react-query';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { ExperimentRef } from '../datasets/use-dataset-experiments';\nimport { getOrCreate } from '../shared/map';\nimport {\n INPUT_TOKEN_METRIC,\n OUTPUT_TOKEN_METRIC,\n accumulate,\n createAccumulator,\n tokenFieldOf,\n toUsage,\n} from './usage-accumulator';\nimport type { ExperimentItemUsage, UsageAccumulator } from './usage-accumulator';\n\nconst AGENT_DURATION_METRIC = 'mastra_agent_duration_ms';\n// Each experiment can return two token groups, while the breakdown endpoint allows at most 1,000.\nconst EXPERIMENT_IDS_PER_REQUEST = 500;\nconst POLL_INTERVAL_MS = 5000;\n\n/** Totals of one experiment: token usage, its estimated cost, and the average agent run duration. */\nexport interface ExperimentListMetrics extends ExperimentItemUsage {\n avgDurationMs?: number;\n}\n\nfunction chunk(ids: readonly string[]): string[][] {\n const chunks: string[][] = [];\n for (let index = 0; index < ids.length; index += EXPERIMENT_IDS_PER_REQUEST) {\n chunks.push(ids.slice(index, index + EXPERIMENT_IDS_PER_REQUEST));\n }\n return chunks;\n}\n\nfunction settledValues<T>(results: PromiseSettledResult<T>[]): T[] {\n return results.flatMap(result => (result.status === 'fulfilled' ? [result.value] : []));\n}\n\n/**\n * Builds each requested experiment's metrics. Groups for other experiments are skipped,\n * in case a store ignores the `experimentIds` filter.\n */\nfunction toListMetrics(\n experimentIds: readonly string[],\n tokenResponses: GetMetricBreakdownResponse[],\n durationResponses: GetMetricBreakdownResponse[],\n): Map<string, ExperimentListMetrics> {\n const requested = new Set(experimentIds);\n const accumulators = new Map<string, UsageAccumulator>();\n for (const group of tokenResponses.flatMap(response => response.groups)) {\n const experimentId = group.dimensions.experimentId;\n const tokenField = tokenFieldOf(group);\n if (!experimentId || !requested.has(experimentId) || !tokenField) continue;\n accumulate(getOrCreate(accumulators, experimentId, createAccumulator), tokenField, group);\n }\n\n const metrics = new Map<string, ExperimentListMetrics>();\n for (const [experimentId, accumulator] of accumulators) {\n metrics.set(experimentId, toUsage(accumulator));\n }\n for (const group of durationResponses.flatMap(response => response.groups)) {\n const experimentId = group.dimensions.experimentId;\n if (!experimentId || !requested.has(experimentId)) continue;\n getOrCreate(metrics, experimentId, (): ExperimentListMetrics => ({})).avgDurationMs = group.value;\n }\n return metrics;\n}\n\n/**\n * Token usage, estimated cost and average agent duration of many experiments, keyed by experiment id.\n * Sends two metric breakdowns per 500 experiments (tokens grouped by experiment and metric name,\n * durations grouped by experiment) instead of one request per experiment.\n * Experiments without any metric are absent from the map. Polls while an experiment is running\n * or pending. No request is made when the observability store cannot serve metrics.\n */\nexport const useExperimentsListMetrics = ({\n experiments,\n supportsMetrics,\n}: {\n experiments: ExperimentRef[];\n supportsMetrics: boolean;\n}): UseQueryResult<Map<string, ExperimentListMetrics>, Error> => {\n const client = useMastraClient();\n const experimentIds = [...new Set(experiments.map(experiment => experiment.id))].toSorted();\n const hasActiveExperiment = experiments.some(({ status }) => status === 'running' || status === 'pending');\n\n return useQuery({\n queryKey: ['experiments-list-metrics', experimentIds],\n enabled: supportsMetrics && experimentIds.length > 0,\n queryFn: async () => {\n const batches = chunk(experimentIds);\n const [tokenResults, durationResults] = await Promise.all([\n Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['experimentId', 'name'],\n filters: { experimentIds: batch },\n limit: batch.length * 2,\n }),\n ),\n ),\n Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [AGENT_DURATION_METRIC],\n aggregation: 'avg',\n groupBy: ['experimentId'],\n filters: { experimentIds: batch },\n limit: batch.length,\n }),\n ),\n ),\n ]);\n return toListMetrics(experimentIds, settledValues(tokenResults), settledValues(durationResults));\n },\n // Loading another page changes the ids; keep the rows already shown filled meanwhile.\n placeholderData: keepPreviousData,\n refetchInterval: hasActiveExperiment ? POLL_INTERVAL_MS : false,\n });\n};\n","import type { DatasetExperiment, ListExperimentsParams, MastraClient } from '@mastra/client-js';\nimport { useInfiniteQuery } from '@tanstack/react-query';\nimport type { InfiniteData, QueryKey, UseInfiniteQueryResult } from '@tanstack/react-query';\nimport { useEffect } from 'react';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraInfiniteQueryOptions } from '../shared/query-options';\nimport { useInView } from '../shared/use-in-view';\nimport type { ExperimentTargetFilter } from './use-experiments-for-dataset-filter';\n\nexport const EXPERIMENTS_PER_PAGE = 100;\n\n/**\n * Infinite-scroll experiments for the list page: the global list, or the dataset-scoped list when a\n * dataset filter is active (a dataset's runs may not be in the first pages of the global list). The\n * optional target filter is applied server-side for the same reason.\n */\nexport type ExperimentsOrderBy = NonNullable<ListExperimentsParams['orderBy']>;\n\ntype ListExperimentsResponse = Awaited<ReturnType<MastraClient['listExperiments']>>;\n\nexport function useInfiniteExperiments<TData = DatasetExperiment[]>({\n datasetId,\n target,\n orderBy,\n queryOptions,\n}: {\n datasetId: string | undefined;\n target?: ExperimentTargetFilter;\n orderBy?: ExperimentsOrderBy;\n queryOptions?: MastraInfiniteQueryOptions<ListExperimentsResponse, TData, QueryKey, number>;\n}): UseInfiniteQueryResult<TData, Error> & {\n setEndOfListElement: (element: HTMLDivElement | null) => void;\n} {\n const client = useMastraClient();\n const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();\n const targetType = target?.targetType || undefined;\n const targetId = target?.targetId || undefined;\n\n const query = useInfiniteQuery({\n // Prefixes match the keys invalidated by dataset/experiment mutations.\n queryKey: datasetId\n ? ['dataset-experiments', datasetId, 'infinite', { targetType, targetId, orderBy }]\n : ['experiments', 'infinite', { targetType, targetId, orderBy }],\n queryFn: ({ pageParam }) => {\n const params: ListExperimentsParams = { page: pageParam, perPage: EXPERIMENTS_PER_PAGE };\n if (targetType) params.targetType = targetType;\n if (targetId) params.targetId = targetId;\n if (orderBy) params.orderBy = orderBy;\n return datasetId ? client.listDatasetExperiments(datasetId, params) : client.listExperiments(params);\n },\n initialPageParam: 0,\n getNextPageParam: (lastPage, _, lastPageParam) => {\n if (!lastPage?.experiments?.length || !lastPage.pagination?.hasMore) {\n return undefined;\n }\n return lastPageParam + 1;\n },\n select: (data: InfiniteData<ListExperimentsResponse, number>) =>\n data.pages.flatMap(page => page?.experiments ?? []) as TData,\n ...queryOptions,\n });\n\n useEffect(() => {\n if (isEndOfListInView && query.hasNextPage && !query.isFetchingNextPage) {\n void query.fetchNextPage();\n }\n }, [isEndOfListInView, query]);\n\n return { ...query, setEndOfListElement };\n}\n"],"mappings":"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"}
@@ -1,12 +1,11 @@
1
- const require_query_utils = require("./query-utils-CcrChYgz.cjs");
2
- //#region src/hooks/feedback/feedback-refetch-interval.ts
1
+ const require_query_utils = require("./query-utils-BVgE_xxj.cjs");
2
+ // src/hooks/feedback/feedback-refetch-interval.ts
3
3
  const FEEDBACK_REFETCH_INTERVAL_MS = 3e4;
4
4
  /** Disables polling for unsupported or unavailable feedback storage; otherwise retries every thirty seconds. */
5
5
  function getFeedbackRefetchInterval(query) {
6
6
  if (require_query_utils.isUnsupportedObservabilityOperationError(query.state.error, "feedback") || require_query_utils.isObservabilityUnavailableError(query.state.error)) return false;
7
7
  return FEEDBACK_REFETCH_INTERVAL_MS;
8
8
  }
9
- //#endregion
10
9
  Object.defineProperty(exports, "getFeedbackRefetchInterval", {
11
10
  enumerable: true,
12
11
  get: function() {
@@ -14,4 +13,4 @@ Object.defineProperty(exports, "getFeedbackRefetchInterval", {
14
13
  }
15
14
  });
16
15
 
17
- //# sourceMappingURL=feedback-refetch-interval-XD5FVc2k.cjs.map
16
+ //# sourceMappingURL=feedback-refetch-interval-BBcT9r8s.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"feedback-refetch-interval-XD5FVc2k.cjs","names":["isUnsupportedObservabilityOperationError","isObservabilityUnavailableError"],"sources":["../src/hooks/feedback/feedback-refetch-interval.ts"],"sourcesContent":["import { isObservabilityUnavailableError, isUnsupportedObservabilityOperationError } from '../query/query-utils';\n\nconst FEEDBACK_REFETCH_INTERVAL_MS = 30_000;\n\n/** Disables polling for unsupported or unavailable feedback storage; otherwise retries every thirty seconds. */\nexport function getFeedbackRefetchInterval(query: { state: { error: unknown } }) {\n if (\n isUnsupportedObservabilityOperationError(query.state.error, 'feedback') ||\n isObservabilityUnavailableError(query.state.error)\n ) {\n return false;\n }\n return FEEDBACK_REFETCH_INTERVAL_MS;\n}\n"],"mappings":";;AAEA,MAAM,+BAA+B;;AAGrC,SAAgB,2BAA2B,OAAsC;CAC/E,IACEA,oBAAAA,yCAAyC,MAAM,MAAM,OAAO,UAAU,KACtEC,oBAAAA,gCAAgC,MAAM,MAAM,KAAK,GAEjD,OAAO;CAET,OAAO;AACT"}
1
+ {"version":3,"file":"feedback-refetch-interval-BBcT9r8s.cjs","names":["isUnsupportedObservabilityOperationError","isObservabilityUnavailableError"],"sources":["../src/hooks/feedback/feedback-refetch-interval.ts"],"sourcesContent":["import { isObservabilityUnavailableError, isUnsupportedObservabilityOperationError } from '../query/query-utils';\n\nconst FEEDBACK_REFETCH_INTERVAL_MS = 30_000;\n\n/** Disables polling for unsupported or unavailable feedback storage; otherwise retries every thirty seconds. */\nexport function getFeedbackRefetchInterval(query: { state: { error: unknown } }) {\n if (\n isUnsupportedObservabilityOperationError(query.state.error, 'feedback') ||\n isObservabilityUnavailableError(query.state.error)\n ) {\n return false;\n }\n return FEEDBACK_REFETCH_INTERVAL_MS;\n}\n"],"mappings":";;AAEA,MAAM,+BAA+B;;AAGrC,SAAgB,2BAA2B,OAAsC;CAC/E,IACEA,oBAAAA,yCAAyC,MAAM,MAAM,OAAO,UAAU,KACtEC,oBAAAA,gCAAgC,MAAM,MAAM,KAAK,GAEjD,OAAO;CAET,OAAO;AACT"}
@@ -1,12 +1,11 @@
1
- import { o as isObservabilityUnavailableError, s as isUnsupportedObservabilityOperationError } from "./query-utils-D1NgFnWU.js";
2
- //#region src/hooks/feedback/feedback-refetch-interval.ts
1
+ import { o as isObservabilityUnavailableError, s as isUnsupportedObservabilityOperationError } from "./query-utils-DvMERIwf.js";
2
+ // src/hooks/feedback/feedback-refetch-interval.ts
3
3
  const FEEDBACK_REFETCH_INTERVAL_MS = 3e4;
4
4
  /** Disables polling for unsupported or unavailable feedback storage; otherwise retries every thirty seconds. */
5
5
  function getFeedbackRefetchInterval(query) {
6
6
  if (isUnsupportedObservabilityOperationError(query.state.error, "feedback") || isObservabilityUnavailableError(query.state.error)) return false;
7
7
  return FEEDBACK_REFETCH_INTERVAL_MS;
8
8
  }
9
- //#endregion
10
9
  export { getFeedbackRefetchInterval as t };
11
10
 
12
- //# sourceMappingURL=feedback-refetch-interval-DLHzQoVV.js.map
11
+ //# sourceMappingURL=feedback-refetch-interval-C12Nzb2r.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feedback-refetch-interval-DLHzQoVV.js","names":[],"sources":["../src/hooks/feedback/feedback-refetch-interval.ts"],"sourcesContent":["import { isObservabilityUnavailableError, isUnsupportedObservabilityOperationError } from '../query/query-utils';\n\nconst FEEDBACK_REFETCH_INTERVAL_MS = 30_000;\n\n/** Disables polling for unsupported or unavailable feedback storage; otherwise retries every thirty seconds. */\nexport function getFeedbackRefetchInterval(query: { state: { error: unknown } }) {\n if (\n isUnsupportedObservabilityOperationError(query.state.error, 'feedback') ||\n isObservabilityUnavailableError(query.state.error)\n ) {\n return false;\n }\n return FEEDBACK_REFETCH_INTERVAL_MS;\n}\n"],"mappings":";;AAEA,MAAM,+BAA+B;;AAGrC,SAAgB,2BAA2B,OAAsC;CAC/E,IACE,yCAAyC,MAAM,MAAM,OAAO,UAAU,KACtE,gCAAgC,MAAM,MAAM,KAAK,GAEjD,OAAO;CAET,OAAO;AACT"}
1
+ {"version":3,"file":"feedback-refetch-interval-C12Nzb2r.js","names":[],"sources":["../src/hooks/feedback/feedback-refetch-interval.ts"],"sourcesContent":["import { isObservabilityUnavailableError, isUnsupportedObservabilityOperationError } from '../query/query-utils';\n\nconst FEEDBACK_REFETCH_INTERVAL_MS = 30_000;\n\n/** Disables polling for unsupported or unavailable feedback storage; otherwise retries every thirty seconds. */\nexport function getFeedbackRefetchInterval(query: { state: { error: unknown } }) {\n if (\n isUnsupportedObservabilityOperationError(query.state.error, 'feedback') ||\n isObservabilityUnavailableError(query.state.error)\n ) {\n return false;\n }\n return FEEDBACK_REFETCH_INTERVAL_MS;\n}\n"],"mappings":";;AAEA,MAAM,+BAA+B;;AAGrC,SAAgB,2BAA2B,OAAsC;CAC/E,IACE,yCAAyC,MAAM,MAAM,OAAO,UAAU,KACtE,gCAAgC,MAAM,MAAM,KAAK,GAEjD,OAAO;CAET,OAAO;AACT"}