@mastra/react 1.11.1-alpha.5 → 1.12.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/hooks.d.ts +9 -0
- package/dist/agent/hooks.d.ts.map +1 -1
- package/dist/chat/index.cjs +1 -1
- package/dist/chat/index.js +1 -1
- package/dist/hooks/feedback/use-feedback.d.ts +3 -3
- package/dist/hooks/logs/use-logs.d.ts +3 -3
- package/dist/hooks/traces/index.cjs +2 -1
- package/dist/hooks/traces/index.cjs.map +1 -1
- package/dist/hooks/traces/index.js +2 -1
- package/dist/hooks/traces/index.js.map +1 -1
- package/dist/hooks/traces/types.d.ts +1 -0
- package/dist/hooks/traces/types.d.ts.map +1 -1
- package/dist/hooks/traces/use-traces.d.ts +4 -4
- package/dist/{hooks-CIwCEruG.cjs → hooks-CIutb3DO.cjs} +22 -2
- package/dist/hooks-CIutb3DO.cjs.map +1 -0
- package/dist/{hooks-CbX7Q4A3.js → hooks-FVbeHlov.js} +22 -2
- package/dist/hooks-FVbeHlov.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/dist/hooks-CIwCEruG.cjs.map +0 -1
- package/dist/hooks-CbX7Q4A3.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["IMMUTABLE_CACHE_TIME","tanstackQueryOptions"],"sources":["../../../src/hooks/traces/discovery-cache.ts","../../../src/hooks/traces/use-branch.ts","../../../src/hooks/traces/types.ts","../../../src/hooks/traces/use-entity-names.ts","../../../src/hooks/traces/use-environments.ts","../../../src/hooks/traces/use-service-names.ts","../../../src/hooks/traces/use-span-detail.ts","../../../src/hooks/traces/use-tags.ts","../../../src/hooks/traces/use-thread-has-other-traces.ts","../../../src/hooks/traces/use-trace-light-spans.ts","../../../src/hooks/traces/use-trace-spans.ts","../../../src/hooks/traces/use-trace-or-branch-spans.ts","../../../src/hooks/traces/use-trace-query.ts","../../../src/hooks/traces/use-trace-usage.ts","../../../src/hooks/traces/use-traces.tsx","../../../src/hooks/traces/use-create-feedback.tsx","../../../src/hooks/traces/use-delete-feedback.tsx","../../../src/hooks/traces/use-span-feedback.tsx","../../../src/hooks/traces/use-trace-feedback.tsx","../../../src/hooks/traces/use-trace-metadata-filter-fields.ts","../../../src/hooks/traces/use-trace-column-preferences-storage-key.ts"],"sourcesContent":["/**\n * How long discovery results (tags, environments, service names, entity\n * names) stay fresh on the client.\n *\n * Discovery values are filter suggestions that change slowly, and the server\n * caches them for 5 minutes anyway. Without a staleTime, React Query refetches\n * on every mount and window focus, which pushes those refetches straight\n * through to the store's discovery refresh. Matching the server TTL keeps the\n * client from asking more often than the answer can change.\n */\nexport const DISCOVERY_STALE_TIME = 5 * 60 * 1000;\n","import 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';\nimport type { LightSpanRecord } from './types';\n\nexport type BranchResponse = { traceId: string; spans: LightSpanRecord[] } | null;\n\nexport interface UseBranchArgs<TData = BranchResponse> {\n traceId: string | null | undefined;\n spanId: string | null | undefined;\n depth?: number;\n queryOptions?: MastraQueryOptions<BranchResponse, TData>;\n}\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useBranch<TData = BranchResponse>({\n traceId,\n spanId,\n depth,\n queryOptions,\n}: UseBranchArgs<TData>): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['branch', traceId, spanId, depth],\n queryFn: async (): Promise<BranchResponse> => {\n if (!traceId || !spanId) {\n throw new Error('traceId and spanId are required');\n }\n return client.getBranch({ traceId, spanId, depth });\n },\n // A finished subtree can still gain spans from a resumed run or delayed export.\n staleTime: 0,\n ...queryOptions,\n });\n}\n","import type { MastraClient } from '@mastra/client-js';\nimport type { EntityType } from '@mastra/core/observability';\n\ntype GetTraceLightResponse = Awaited<ReturnType<MastraClient['getTraceLight']>>;\ntype GetSpanResponse = Awaited<ReturnType<MastraClient['getSpan']>>;\nexport type LightSpanRecord = GetTraceLightResponse['spans'][number];\nexport type SpanRecord = GetSpanResponse['span'];\n\nexport type TraceListMode = 'traces' | 'branches';\n\nexport type TraceUsageSummary = {\n inputTokens?: number;\n outputTokens?: number;\n estimatedCost?: number;\n costUnit?: string;\n};\n\nexport const ROOT_ENTITY_TYPES = {\n AGENT: 'agent',\n WORKFLOW: 'workflow_run',\n SCORER: 'scorer',\n INGEST: 'rag_ingestion',\n} as const satisfies Record<string, `${EntityType}`>;\n","import type { MastraClient } from '@mastra/client-js';\nimport { EntityType } from '@mastra/core/observability';\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';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\nimport { ROOT_ENTITY_TYPES } from './types';\n\ntype EntityTypeValue = `${EntityType}`;\n\ntype EntityNamesResponse = Awaited<ReturnType<MastraClient['getEntityNames']>>;\n\ntype UseEntityNamesOptions<TData> = {\n entityType?: EntityTypeValue;\n rootOnly?: boolean;\n queryOptions?: MastraQueryOptions<EntityNamesResponse, TData>;\n};\n\nfunction resolveEntityType(entityType: EntityTypeValue) {\n return Object.values(EntityType).find(candidate => candidate === entityType);\n}\n\nexport const useEntityNames = <TData = EntityNamesResponse['names']>({\n entityType,\n rootOnly = false,\n queryOptions,\n}: UseEntityNamesOptions<TData> = {}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n // Mirror the queryFn branches so the cache key reflects what the server\n // actually returns. rootOnly only matters when entityType is not set; when\n // entityType is set, the query ignores rootOnly entirely.\n const queryKey = entityType\n ? ['observability-entity-names', 'by-type', entityType]\n : ['observability-entity-names', 'all', rootOnly ? 'root-only' : 'all-types'];\n\n return useQuery({\n queryKey,\n queryFn: async (): Promise<EntityNamesResponse> => {\n try {\n if (entityType) {\n const resolvedEntityType = resolveEntityType(entityType);\n if (!resolvedEntityType) return { names: [] };\n return await client.getEntityNames({ entityType: resolvedEntityType });\n }\n\n if (!rootOnly) {\n return await client.getEntityNames();\n }\n\n const responses = await Promise.all(\n Object.values(ROOT_ENTITY_TYPES).map(rootEntityType => {\n const resolvedEntityType = resolveEntityType(rootEntityType);\n if (!resolvedEntityType) return { names: [] };\n return client.getEntityNames({ entityType: resolvedEntityType });\n }),\n );\n\n return {\n names: Array.from(new Set(responses.flatMap(response => response?.names ?? []))).sort(),\n };\n } catch {\n return { names: [] };\n }\n },\n select: data => (data?.names ?? []) as TData,\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n ...queryOptions,\n });\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';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\n\ntype EnvironmentsResponse = Awaited<ReturnType<MastraClient['getEnvironments']>>;\ntype EnvironmentsData = EnvironmentsResponse['environments'];\n\nexport const useEnvironments = <TData = EnvironmentsData>({\n queryOptions,\n}: {\n queryOptions?: MastraQueryOptions<EnvironmentsResponse, TData>;\n} = {}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['observability-environments'],\n queryFn: async (): Promise<EnvironmentsResponse> => {\n try {\n return await client.getEnvironments();\n } catch {\n return { environments: [] };\n }\n },\n select: data => (data?.environments ?? []) as TData,\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n ...queryOptions,\n });\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';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\n\ntype ServiceNamesResponse = Awaited<ReturnType<MastraClient['getServiceNames']>>;\ntype ServiceNamesData = ServiceNamesResponse['serviceNames'];\n\nexport const useServiceNames = <TData = ServiceNamesData>({\n queryOptions,\n}: {\n queryOptions?: MastraQueryOptions<ServiceNamesResponse, TData>;\n} = {}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['observability-service-names'],\n queryFn: async (): Promise<ServiceNamesResponse> => {\n try {\n return await client.getServiceNames();\n } catch {\n return { serviceNames: [] };\n }\n },\n select: data => (data?.serviceNames ?? []) as TData,\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n ...queryOptions,\n });\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\nconst IMMUTABLE_CACHE_TIME = 1000 * 60 * 60 * 24 * 30; // 30 days, massive cache, span data is immutable\n\ntype SpanDetailResponse = Awaited<ReturnType<MastraClient['getSpan']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useSpanDetail<TData = SpanDetailResponse>({\n traceId,\n spanId,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n spanId: string | null | undefined;\n queryOptions?: MastraQueryOptions<SpanDetailResponse, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['span-detail', traceId, spanId],\n queryFn: async () => {\n if (!traceId || !spanId) {\n throw new Error('Trace ID and Span ID are required');\n }\n return client.getSpan(traceId, spanId);\n },\n staleTime: query => {\n const data = query.state.data;\n\n if (data?.span?.endedAt) {\n return IMMUTABLE_CACHE_TIME;\n }\n\n return 0;\n },\n ...queryOptions,\n });\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';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\n\ntype TagsResponse = Awaited<ReturnType<MastraClient['getTags']>>;\ntype TagsData = TagsResponse['tags'];\n\nexport const useTags = <TData = TagsData>({\n queryOptions,\n}: {\n queryOptions?: MastraQueryOptions<TagsResponse, TData>;\n} = {}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['observability-tags'],\n queryFn: async (): Promise<TagsResponse> => {\n try {\n return await client.getTags();\n } catch {\n // Storage provider may not support tag discovery (e.g. LibSQL)\n return { tags: [] };\n }\n },\n select: data => (data?.tags ?? []) as TData,\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n ...queryOptions,\n });\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\n/**\n * Whether the memory thread holds more than one trace, i.e. whether a \"full thread\" view would\n * show anything beyond the current turn. `false` while loading or on error, so the link only\n * appears once we know it leads somewhere.\n */\ntype ThreadTracesResponse = Awaited<ReturnType<MastraClient['listTracesLight']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useThreadHasOtherTraces({\n threadId,\n queryOptions,\n}: {\n threadId: string | undefined;\n queryOptions?: MastraQueryOptions<ThreadTracesResponse, boolean>;\n}): boolean {\n const client = useMastraClient();\n const { data } = useQuery({\n queryKey: ['thread-trace-count', threadId],\n queryFn: () =>\n client.listTracesLight({\n filters: { threadId: threadId ?? '' },\n // Some stores apply metadata filters after paging, so a tiny page can miss sibling traces.\n // Match the page size the full thread view uses and count what actually comes back.\n pagination: { page: 0, perPage: 25 },\n }),\n select: response => (response.spans?.length ?? 0) > 1,\n ...queryOptions,\n });\n return data ?? false;\n}\n","import 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';\nimport type { LightSpanRecord } from './types';\n\nconst IMMUTABLE_CACHE_TIME = 1000 * 60 * 60 * 24 * 30; // 30 days, massive cache, span data is immutable\n\ntype TraceLightSpansResponse = { traceId: string; spans: LightSpanRecord[] } | null;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useTraceLightSpans<TData = TraceLightSpansResponse>({\n traceId,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n queryOptions?: MastraQueryOptions<TraceLightSpansResponse, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['trace-light-spans', traceId],\n queryFn: async (): Promise<TraceLightSpansResponse> => {\n if (!traceId) {\n throw new Error('Trace ID is required');\n }\n const res = await client.getTraceLight(traceId);\n return res;\n },\n staleTime: query => {\n const data = query.state.data;\n\n const isFinished = data?.spans.every(d => Boolean(d.endedAt));\n\n if (isFinished) {\n return IMMUTABLE_CACHE_TIME;\n }\n\n return 0;\n },\n ...queryOptions,\n });\n}\n","import type { MastraClient } from '@mastra/client-js';\nimport { queryOptions as tanstackQueryOptions, useQueries, useQuery, useQueryClient } from '@tanstack/react-query';\nimport type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\n/**\n * Key, fetcher and stale policy of the `trace-spans` query. Every observer of this key must\n * share these (rather than only the key) so one observer with a stricter `staleTime` does not\n * refetch data another one considers fresh.\n */\ntype TraceResponse = Awaited<ReturnType<MastraClient['getTrace']>>;\n\nexport const traceSpansQueryOptions = (\n client: MastraClient,\n traceId: string | null | undefined,\n): UseQueryOptions<TraceResponse, Error, TraceResponse, (string | null | undefined)[]> =>\n tanstackQueryOptions({\n queryKey: ['trace-spans', traceId],\n queryFn: async () => {\n if (!traceId) {\n throw new Error('Trace ID is required');\n }\n const res = await client.getTrace(traceId);\n return res;\n },\n // Resumed runs and delayed exports can append spans even when every known span has ended.\n staleTime: 0,\n });\n\n/**\n * Every span of a single trace, with its full payload.\n *\n * The lightweight projection exists to keep blob columns off the read path of a\n * *list*, where the cost is paid once per trace on screen. A trace that is open\n * has already narrowed that to one, and the panel both renders and searches\n * these spans -- `input`, `output` and `attributes` included -- so the\n * projection would only hide content the reader is looking at.\n */\nexport type TraceSpansData = Awaited<ReturnType<MastraClient['getTrace']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useTraceSpans<TData = TraceSpansData>({\n traceId,\n passive = false,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n passive?: boolean;\n queryOptions?: MastraQueryOptions<TraceSpansData, TData, (string | null | undefined)[]>;\n}): UseQueryResult<TData> {\n const client = useMastraClient();\n\n const { queryKey, queryFn, enabled, staleTime } = traceSpansQueryOptions(client, traceId);\n\n return useQuery<TraceSpansData, Error, TData, (string | null | undefined)[]>({\n queryKey,\n queryFn,\n enabled,\n staleTime,\n // History rows share updates but leave automatic refreshes to the selected detail.\n refetchOnMount: !passive,\n refetchOnWindowFocus: !passive,\n refetchOnReconnect: !passive,\n ...queryOptions,\n });\n}\n\n/**\n * Returns a function that loads a full trace through the shared `trace-spans` cache, so an\n * imperative read (e.g. an export) and the trace panel always see the same payload.\n */\nexport function useFetchTraceSpans(): (traceId: string) => Promise<TraceSpansData> {\n const client = useMastraClient();\n const queryClient = useQueryClient();\n\n return (traceId: string) => queryClient.fetchQuery(traceSpansQueryOptions(client, traceId));\n}\n\n/**\n * Observes the `trace-spans` query of several traces at once and projects each one with `select`.\n * Traces still loading (or failed) yield `fallback(traceId)` so the result always lines up with `traceIds`.\n */\nexport function useTraceSpansQueries<T>({\n traceIds,\n select,\n fallback,\n queryOptions,\n}: {\n traceIds: string[];\n select: (traceId: string, data: TraceSpansData) => T;\n fallback: (traceId: string) => T;\n /** Applied to every per-trace query. */\n queryOptions?: MastraQueryOptions<TraceSpansData, T, (string | null | undefined)[]>;\n}): T[] {\n const client = useMastraClient();\n\n return useQueries({\n queries: traceIds.map(traceId => ({\n ...traceSpansQueryOptions(client, traceId),\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n select: (data: TraceSpansData) => select(traceId, data),\n ...queryOptions,\n })),\n combine: results =>\n results.map((result, index) =>\n result.data === undefined ? fallback(traceIds[index] ?? '') : (result.data as T),\n ),\n });\n}\n","import type { MastraQueryOptions } from '../shared/query-options';\nimport type { TraceListMode, LightSpanRecord } from './types';\nimport { useBranch } from './use-branch';\nimport type { BranchResponse } from './use-branch';\nimport { useTraceSpans } from './use-trace-spans';\nimport type { TraceSpansData } from './use-trace-spans';\n\nexport interface UseTraceOrBranchSpansArgs {\n traceId: string | null | undefined;\n /** Required when `listMode === 'branches'` — the anchor span identifying the displayed\n * subtree. The hook fetches `getBranch(traceId, anchorSpanId)`. Intra-panel span selection\n * is separate (the caller's `spanIdParam`); the anchor stays put while it changes. */\n anchorSpanId?: string | null;\n listMode: TraceListMode;\n depth?: number;\n /**\n * Per-query TanStack overrides, spread last. `select` must keep the default data shape\n * because this hook reads `.spans` from both results.\n */\n queryOptions?: {\n trace?: MastraQueryOptions<TraceSpansData, TraceSpansData, (string | null | undefined)[]>;\n branch?: MastraQueryOptions<BranchResponse, BranchResponse>;\n };\n}\n\nexport interface UseTraceOrBranchSpansResult {\n spans: LightSpanRecord[] | undefined;\n /** Set in branches mode; undefined in traces mode (which uses parentSpanId == null). */\n anchorSpanId: string | undefined;\n isLoading: boolean;\n isError: boolean;\n error: unknown;\n}\n\n/**\n * Unified data source for the trace/span detail panel. Returns trace spans (full tree from the\n * root) in traces mode, or branch spans (subtree rooted at `anchorSpanId`) in branches mode.\n * Only the active query fires; the inactive one is disabled via its `enabled` flag.\n *\n * Both modes carry full span payloads: the panel renders and searches them, so a lightweight\n * projection here would hide content from the reader looking straight at it.\n */\nexport function useTraceOrBranchSpans({\n traceId,\n anchorSpanId,\n listMode,\n depth,\n queryOptions,\n}: UseTraceOrBranchSpansArgs): UseTraceOrBranchSpansResult {\n const isBranches = listMode === 'branches';\n\n const traceQuery = useTraceSpans({\n traceId: isBranches ? null : traceId,\n queryOptions: { enabled: !isBranches && !!traceId, ...queryOptions?.trace },\n });\n const branchQuery = useBranch({\n traceId: isBranches ? traceId : null,\n spanId: isBranches ? anchorSpanId : null,\n depth,\n queryOptions: { enabled: isBranches && !!traceId && !!anchorSpanId, ...queryOptions?.branch },\n });\n\n if (isBranches) {\n return {\n spans: branchQuery.data?.spans,\n anchorSpanId: anchorSpanId ?? undefined,\n isLoading: branchQuery.isLoading,\n isError: branchQuery.isError,\n error: branchQuery.error,\n };\n }\n\n return {\n spans: traceQuery.data?.spans,\n anchorSpanId: undefined,\n isLoading: traceQuery.isLoading,\n isError: traceQuery.isError,\n error: traceQuery.error,\n };\n}\n","import { MastraClient } from '@mastra/client-js';\nimport type { QueryTracesKeysetInput, TraceQueryKeysetTraceResponse } from '@mastra/client-js';\nimport type { ListTracesArgs as StorageListTracesArgs } from '@mastra/core/storage';\nimport { keepPreviousData, skipToken, useInfiniteQuery } 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';\n\nexport const TRACE_QUERY_PER_PAGE = 25;\n\ntype TraceQueryTrace = TraceQueryKeysetTraceResponse['traces'][number];\n\ntype ListTracesArgs = NonNullable<Parameters<MastraClient['listTracesLight']>[0]>;\ntype LegacyTraceListFilters = StorageListTracesArgs['filters'];\ntype ListTracesLightResponse = Awaited<ReturnType<MastraClient['listTracesLight']>>;\ntype LightSpanRecord = ListTracesLightResponse['spans'][number];\n\nexport type TraceQueryArgs = Omit<QueryTracesKeysetInput, 'page' | 'pagination'>;\n\nexport interface UseTraceQueryArgs {\n query: TraceQueryArgs | undefined;\n limit?: number;\n enabled?: boolean;\n /** When false, lists traces through the legacy `listTracesLight` endpoint instead of the trace-query API. */\n withQueryTrace?: boolean;\n /** Filters for the legacy endpoint, as built by `buildTraceListFilters`. Only read when `withQueryTrace` is false. */\n legacyFilters?: LegacyTraceListFilters;\n /** TanStack options spread last into the trace-query (`traceQuery`) and legacy (`legacy`) infinite queries. */\n queryOptions?: {\n traceQuery?: MastraInfiniteQueryOptions<\n TraceQueryKeysetTraceResponse,\n TraceQueryTrace[],\n readonly unknown[],\n string | undefined\n >;\n legacy?: MastraInfiniteQueryOptions<ListTracesLightResponse, TraceQueryTrace[], readonly unknown[], number>;\n };\n}\n\nexport interface UseTraceQueryReturn {\n data: TraceQueryTrace[] | undefined;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n fetchNextPage: () => void;\n isLoading: boolean;\n /** The rows belong to the previous query key (e.g. another thread) while the new one loads. */\n isPlaceholderData: boolean;\n isFetching: boolean;\n isRefetching: boolean;\n fetchStatus: 'idle' | 'fetching' | 'paused';\n isError: boolean;\n error: Error | null;\n refetch: () => void;\n setEndOfListElement: (node: HTMLDivElement | null) => void;\n}\n\nexport function getTraceQueryNextPageParam(lastPage: TraceQueryKeysetTraceResponse | undefined): string | undefined {\n return lastPage?.page.next ?? undefined;\n}\n\nexport function selectTraceQueryTraces(data: { pages: TraceQueryKeysetTraceResponse[] }): TraceQueryTrace[] {\n const seen = new Set<string>();\n return data.pages.flatMap(page =>\n page.traces.filter(trace => {\n if (seen.has(trace.traceId)) return false;\n seen.add(trace.traceId);\n return true;\n }),\n );\n}\n\nconst toIsoString = (value: Date | string): string => (typeof value === 'string' ? value : value.toISOString());\n\n/** Maps a legacy light root span to a trace-query row. The light record carries no\n * environment, so it stays null. Running spans have no `endedAt` and may carry a\n * status outside the query API's enum; both are kept as-is (the list view handles them), hence the\n * assertion at this compatibility boundary. */\nexport function lightSpanToTraceQueryTrace(span: LightSpanRecord): TraceQueryTrace {\n const row = {\n traceId: span.traceId,\n rootSpanId: span.spanId,\n name: span.name,\n entityId: span.entityId ?? null,\n parentSpanId: span.parentSpanId ?? null,\n createdAt: toIsoString(span.createdAt),\n metadata: span.metadata ?? null,\n inputPreview: span.inputPreview ?? null,\n outputPreview: span.outputPreview ?? null,\n errorPreview: span.errorPreview ?? null,\n threadId: span.threadId ?? null,\n resourceId: span.resourceId ?? null,\n startedAt: toIsoString(span.startedAt),\n endedAt: span.endedAt == null ? span.endedAt : toIsoString(span.endedAt),\n entityName: span.entityName ?? null,\n entityType: span.entityType ?? null,\n environment: null,\n status: span.status,\n };\n return row as TraceQueryTrace;\n}\n\nexport function selectLegacyTraceQueryTraces(data: { pages: ListTracesLightResponse[] }): TraceQueryTrace[] {\n const seen = new Set<string>();\n return data.pages.flatMap(page =>\n page.spans.flatMap(span => {\n if (seen.has(span.traceId)) return [];\n seen.add(span.traceId);\n return [lightSpanToTraceQueryTrace(span)];\n }),\n );\n}\n\nexport function getLegacyTraceQueryNextPageParam(lastPage: ListTracesLightResponse): number | undefined {\n return lastPage.pagination?.hasMore ? lastPage.pagination.page + 1 : undefined;\n}\n\n/** Queries traces with cursor pagination and viewport-driven loading. */\nexport function useTraceQuery({\n query,\n limit = TRACE_QUERY_PER_PAGE,\n enabled = true,\n withQueryTrace = true,\n legacyFilters,\n queryOptions,\n}: UseTraceQueryArgs): UseTraceQueryReturn {\n const client = useMastraClient();\n const { inView, setRef: setEndOfListElement } = useInView();\n const queryResult = useInfiniteQuery<\n TraceQueryKeysetTraceResponse,\n Error,\n TraceQueryTrace[],\n readonly unknown[],\n string | undefined\n >({\n queryKey: ['trace-query', query, limit] as const,\n queryFn: query\n ? async ({ pageParam }) => {\n // Capability failures must reach the fallback without the SDK retrying 501 responses.\n const queryClient = new MastraClient({ ...client.options, retries: 0 });\n const response = await queryClient.queryTraces({ ...query, page: { limit, after: pageParam ?? null } });\n if ('traces' in response && 'page' in response) return response;\n throw new Error('Expected a cursor-paginated trace query response');\n }\n : skipToken,\n initialPageParam: undefined,\n getNextPageParam: getTraceQueryNextPageParam,\n select: selectTraceQueryTraces,\n retry: false,\n placeholderData: keepPreviousData,\n enabled: enabled && withQueryTrace,\n ...queryOptions?.traceQuery,\n });\n const orderBy = query?.orderBy;\n const legacyDirection = orderBy?.[0]?.direction === 'asc' ? 'ASC' : 'DESC';\n const legacyResult = useInfiniteQuery<ListTracesLightResponse, Error, TraceQueryTrace[], readonly unknown[], number>({\n queryKey: ['trace-query-legacy', legacyFilters, limit, orderBy] as const,\n queryFn: ({ pageParam }) =>\n client.listTracesLight({\n // Core's date-range filter types `start`/`end` loosely; the client param type is stricter.\n filters: legacyFilters as ListTracesArgs['filters'],\n pagination: { page: pageParam, perPage: limit },\n orderBy: { field: 'startedAt', direction: legacyDirection },\n }),\n initialPageParam: 0,\n getNextPageParam: getLegacyTraceQueryNextPageParam,\n select: selectLegacyTraceQueryTraces,\n retry: false,\n placeholderData: keepPreviousData,\n enabled: enabled && !withQueryTrace,\n ...queryOptions?.legacy,\n });\n const result = withQueryTrace ? queryResult : legacyResult;\n const {\n data,\n hasNextPage,\n isFetchingNextPage,\n fetchNextPage,\n isLoading,\n isPlaceholderData,\n isFetching,\n isRefetching,\n fetchStatus,\n isError,\n error,\n refetch,\n isFetchNextPageError,\n } = result;\n\n useEffect(() => {\n if (enabled && inView && hasNextPage && !isFetching && !isFetchNextPageError) {\n void fetchNextPage();\n }\n }, [enabled, inView, hasNextPage, isFetching, isFetchNextPageError, fetchNextPage]);\n\n return {\n data,\n hasNextPage,\n isFetchingNextPage,\n fetchNextPage,\n isLoading,\n isPlaceholderData,\n isFetching,\n isRefetching,\n fetchStatus,\n isError,\n error,\n refetch,\n setEndOfListElement,\n };\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport { getOrCreate } from '../shared/map';\nimport type { MastraQueryOptions } from '../shared/query-options';\nimport type { TraceUsageSummary } from './types';\n\nconst INPUT_TOKEN_METRIC = 'mastra_model_total_input_tokens';\nconst OUTPUT_TOKEN_METRIC = 'mastra_model_total_output_tokens';\n// Each trace can return two groups, while the breakdown endpoint allows at most 1,000.\nconst TRACE_IDS_PER_REQUEST = 500;\n\ntype TraceUsageAccumulator = {\n inputTokens?: number;\n outputTokens?: number;\n estimatedCost: number;\n hasEstimatedCost: boolean;\n costUnits: Set<string>;\n hasUnknownCostUnit: boolean;\n};\n\nfunction chunkTraceIds(traceIds: readonly string[]): string[][] {\n const chunks: string[][] = [];\n for (let index = 0; index < traceIds.length; index += TRACE_IDS_PER_REQUEST) {\n chunks.push(traceIds.slice(index, index + TRACE_IDS_PER_REQUEST));\n }\n return chunks;\n}\n\nfunction createTraceUsageAccumulator(): TraceUsageAccumulator {\n return {\n estimatedCost: 0,\n hasEstimatedCost: false,\n costUnits: new Set(),\n hasUnknownCostUnit: false,\n };\n}\n\nfunction addBreakdown(accumulators: Map<string, TraceUsageAccumulator>, response: GetMetricBreakdownResponse) {\n for (const group of response.groups) {\n const traceId = group.dimensions.traceId;\n const metricName = group.dimensions.name;\n if (!traceId || (metricName !== INPUT_TOKEN_METRIC && metricName !== OUTPUT_TOKEN_METRIC)) continue;\n\n const accumulator = getOrCreate(accumulators, traceId, createTraceUsageAccumulator);\n const tokenField = metricName === INPUT_TOKEN_METRIC ? 'inputTokens' : 'outputTokens';\n accumulator[tokenField] = (accumulator[tokenField] ?? 0) + group.value;\n\n if (group.estimatedCost == null) continue;\n accumulator.estimatedCost += group.estimatedCost;\n accumulator.hasEstimatedCost = true;\n if (group.costUnit) {\n accumulator.costUnits.add(group.costUnit.toLowerCase());\n } else {\n accumulator.hasUnknownCostUnit = true;\n }\n }\n}\n\nfunction summarizeUsage(accumulators: Map<string, TraceUsageAccumulator>): Map<string, TraceUsageSummary> {\n const summaries = new Map<string, TraceUsageSummary>();\n for (const [traceId, accumulator] of accumulators) {\n const summary: TraceUsageSummary = {\n inputTokens: accumulator.inputTokens,\n outputTokens: accumulator.outputTokens,\n };\n\n if (accumulator.hasEstimatedCost && !accumulator.hasUnknownCostUnit && accumulator.costUnits.size === 1) {\n summary.estimatedCost = accumulator.estimatedCost;\n summary.costUnit = [...accumulator.costUnits][0];\n }\n\n summaries.set(traceId, summary);\n }\n return summaries;\n}\n\nexport function useTraceUsage<TData = Map<string, TraceUsageSummary>>({\n traceIds,\n enabled,\n autoRefetch,\n queryOptions,\n}: {\n traceIds: readonly string[];\n enabled: boolean;\n autoRefetch: boolean;\n queryOptions?: MastraQueryOptions<Map<string, TraceUsageSummary>, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n const uniqueTraceIds = [...new Set(traceIds)].toSorted();\n const projectUrl =\n client.options.baseUrl || (typeof window === 'undefined' ? 'local' : window.location.origin || 'local');\n const projectKey = `${projectUrl}:${client.options.apiPrefix ?? '/api'}`;\n\n return useQuery({\n queryKey: ['trace-usage', projectKey, uniqueTraceIds],\n enabled: enabled && uniqueTraceIds.length > 0,\n queryFn: async () => {\n const batches = chunkTraceIds(uniqueTraceIds);\n const responses = await Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['traceId', 'name'],\n filters: { traceIds: batch },\n limit: batch.length * 2,\n }),\n ),\n );\n\n const accumulators = new Map<string, TraceUsageAccumulator>();\n for (const response of responses) {\n if (response.status === 'fulfilled') {\n addBreakdown(accumulators, response.value);\n }\n }\n return summarizeUsage(accumulators);\n },\n placeholderData: (previousData, previousQuery) =>\n previousQuery?.queryKey[1] === projectKey ? previousData : undefined,\n refetchInterval: enabled && autoRefetch ? 10_000 : false,\n ...queryOptions,\n });\n}\n","import type { MastraClient } from '@mastra/client-js';\nimport type { InfiniteData } from '@tanstack/react-query';\nimport { useInfiniteQuery, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useEffect, useRef, useState } from 'react';\nimport { useMastraClient } from '../../mastra-client-context';\nimport { is403ForbiddenError } from '../query/query-utils';\nimport type { MastraInfiniteQueryOptions, MastraQueryOptions } from '../shared/query-options';\nimport { useInView } from '../shared/use-in-view';\nimport type { TraceListMode } from './types';\n\ntype ListBranchesArgs = NonNullable<Parameters<MastraClient['listBranches']>[0]>;\ntype ListBranchesResponse = Awaited<ReturnType<MastraClient['listBranches']>>;\ntype ListTracesArgs = NonNullable<Parameters<MastraClient['listTraces']>[0]>;\ntype ListTracesLightResponse = Awaited<ReturnType<MastraClient['listTracesLight']>>;\ntype LightSpanRecord = ListTracesLightResponse['spans'][number] | ListBranchesResponse['branches'][number];\n\n/**\n * Per-MastraClient delta-polling support cache. Sticks once we observe a 501\n * or a page-0 response without `deltaCursor` (legacy server or store without\n * delta capability), so we don't re-probe on every mount.\n */\ntype DeltaSupport = 'unknown' | 'unsupported';\nconst deltaSupportByClient = new WeakMap<ReturnType<typeof useMastraClient>, DeltaSupport>();\n\n/**\n * Per-MastraClient light-list support cache. Sticks once the light endpoint is\n * shown not to be served, so every subsequent page fetch, delta poll and periodic\n * refresh uses the full list endpoint instead. Other failures (auth, rate limits,\n * outages) propagate without pinning — they'd hit the full endpoint too.\n */\ntype LightListSupport = 'unknown' | 'unsupported';\nconst lightListSupportByClient = new WeakMap<ReturnType<typeof useMastraClient>, LightListSupport>();\n\n/** When the current run of light-endpoint 500s started, per client. Cleared by any light success. */\nconst lightListFirstServerErrorAtByClient = new WeakMap<ReturnType<typeof useMastraClient>, number>();\n\n/** A 500 is ambiguous — an old core's store throwing, or a transient fault (DB hiccup, timeout).\n * Serve the request from the full endpoint either way, but only pin the session once the 500s\n * have outlasted a blip; a hiccup would otherwise degrade the list until the tab is reloaded.\n * Elapsed time, not a request count: the page refetch, the delta poll and the status refresh can\n * fail in the same instant, and a fallback response still looks like a success to the delta query,\n * so chase mode keeps re-polling every `deltaChaseIntervalMs` throughout the outage. */\nconst LIGHT_LIST_SERVER_ERROR_PIN_AFTER_MS = 10_000;\n\n/** Tunables for live-tail polling. All fields optional — defaults below.\n * Platform consumers override individual fields to throttle traffic or\n * reshape the freshness/visibility trade-offs. */\nexport interface TracesPollingConfig {\n /** Interval between delta polls. Default 5_000ms. */\n deltaPollIntervalMs?: number;\n /** Refetch delay when the server signals `delta.hasMore` (chase remaining updates immediately). Default 100ms. */\n deltaChaseIntervalMs?: number;\n /** Max rows per delta poll. Server caps at 100. Default 100. */\n deltaLimit?: number;\n /** Page-mode refetch interval used when the configured store does not support delta polling. Default 10_000ms. */\n pageModeRefetchIntervalMs?: number;\n /** Periodic page-0 refetch interval while delta is active. Delta only delivers new rows, so this\n * is how we surface status flips (running → success/error) on rows already visible. Default 60_000ms. */\n page0StatusRefreshIntervalMs?: number;\n /** When the tab returns from being hidden and the last successful poll was older than this, the\n * cursor is treated as stale (ClickHouse delta tables TTL after 2 days; other stores may be more\n * aggressive). The infinite query is reset so page 0 refetches and delta resumes from a fresh\n * cursor. Default 900_000ms (15 min). */\n idleGuardThresholdMs?: number;\n /** Minimum visible duration for `isRefetching` after any query completes. On localhost a delta\n * poll can resolve in tens of ms — too brief for the spinner's 1s rotation to register visually,\n * and quick enough that React may batch the start/finish transitions. Pulsing for this duration\n * on completion (~144° of rotation at 400ms) makes each poll perceptible as a heartbeat.\n * Default 400ms. */\n minRefetchSpinMs?: number;\n /** Window during which a delta-arrived row's key stays in `recentlyAddedKeys` so the list view\n * can apply its `animate-row-highlight` class. Should match the CSS animation duration\n * (currently 1_000ms — see `index.css`). Default 1_000ms. */\n deltaHighlightMs?: number;\n}\n\nconst DEFAULT_POLLING_CONFIG: Required<TracesPollingConfig> = {\n deltaPollIntervalMs: 5_000,\n deltaChaseIntervalMs: 100,\n deltaLimit: 100,\n pageModeRefetchIntervalMs: 10_000,\n page0StatusRefreshIntervalMs: 60_000,\n idleGuardThresholdMs: 15 * 60_000,\n minRefetchSpinMs: 400,\n deltaHighlightMs: 1_000,\n};\n\n/** Returns true when the cursor should be considered stale and re-seeded.\n * Exported for testing — pure function of timestamps. */\nexport function shouldResetAfterIdle(lastSuccessAt: number, now: number, thresholdMs: number): boolean {\n if (lastSuccessAt === 0) return false;\n return now - lastSuccessAt > thresholdMs;\n}\n\nfunction isHttp501(error: unknown): boolean {\n return (error as { status?: number } | null)?.status === 501;\n}\n\n/** Only 404 and 500 can mean the light endpoint isn't served: 404 from servers without\n * the route, 500 from cores whose store throws instead of serving the projection.\n * Anything else (401, 403, 429, other 5xx, the 501 disabled-domain signal) is a\n * condition the full endpoint would hit too, so it propagates instead of falling\n * back — mirroring how the delta-support cache matches exactly 501. */\nfunction lightListFallbackStatus(error: unknown): 404 | 500 | undefined {\n const status = (error as { status?: number } | null)?.status;\n return status === 404 || status === 500 ? status : undefined;\n}\n\n/** Whether a failed light-list request should pin the session to the full endpoint.\n * `firstServerErrorAt` is undefined when this 500 opens a new run of them, so a single\n * fault never pins. Exported for testing — pure function of the status and timestamps. */\nexport function shouldPinLightList(\n status: number | undefined,\n firstServerErrorAt: number | undefined,\n now: number,\n): boolean {\n if (status === 404) return true;\n if (status !== 500) return false;\n if (firstServerErrorAt === undefined) return false;\n return now - firstServerErrorAt >= LIGHT_LIST_SERVER_ERROR_PIN_AFTER_MS;\n}\n\ntype FetchTracesFnArgs = TracesFilters & {\n client: ReturnType<typeof useMastraClient>;\n} & ({ mode: 'delta'; after?: string; limit?: number } | { mode?: 'page'; page: number; perPage: number });\n\nconst fetchTracesFn = async (args: FetchTracesFnArgs) => {\n const { client, filters, listMode = 'traces' } = args;\n const params =\n args.mode === 'delta'\n ? { mode: 'delta' as const, after: args.after, limit: args.limit, filters }\n : { pagination: { page: args.page, perPage: args.perPage }, filters };\n\n if (listMode === 'branches') {\n return client.listBranches(params as ListBranchesArgs);\n }\n\n // The list only renders identity, timing, status and a short input preview, so ask\n // for the lightweight projection. Selecting a row fetches the full record separately.\n // Clients pinned to full mode keep using listTraces (page and delta alike), exactly\n // as before the light endpoint existed; full rows are a superset of the light ones.\n if (lightListSupportByClient.get(client) === 'unsupported') {\n return client.listTraces(params as ListTracesArgs);\n }\n try {\n const response = await client.listTracesLight(params as ListTracesArgs);\n // A 200 can still be a legacy projection: servers whose store implements the\n // pre-preview light list answer with rows carrying none of the new fields.\n // Current servers always set `status` on every row, so a non-empty page where\n // every row lacks it is legacy-shaped — pin and refetch the full rows. Empty\n // pages never pin (indistinguishable, and they render identically either way;\n // the next non-empty page decides).\n if (args.mode !== 'delta') {\n const spans = response.spans ?? [];\n if (spans.length > 0 && spans.every(span => span.status === undefined)) {\n lightListSupportByClient.set(client, 'unsupported');\n return client.listTraces(params as ListTracesArgs);\n }\n }\n lightListFirstServerErrorAtByClient.delete(client);\n return response;\n } catch (error) {\n const status = lightListFallbackStatus(error);\n if (status === undefined) throw error;\n\n const now = Date.now();\n const firstServerErrorAt = lightListFirstServerErrorAtByClient.get(client);\n if (status === 500 && firstServerErrorAt === undefined) {\n lightListFirstServerErrorAtByClient.set(client, now);\n }\n if (shouldPinLightList(status, firstServerErrorAt, now)) {\n lightListSupportByClient.set(client, 'unsupported');\n }\n return client.listTraces(params as ListTracesArgs);\n }\n};\n\nexport const TRACES_PER_PAGE = 25;\n\nexport interface TracesFilters {\n filters?: ListTracesArgs['filters'] | ListBranchesArgs['filters'];\n listMode?: TraceListMode;\n}\n\n/** Returns the next page number if the server indicates more pages are available. */\nexport function getTracesNextPageParam(\n lastPage: ListTracesLightResponse | ListBranchesResponse | undefined,\n _allPages: unknown,\n lastPageParam: number,\n) {\n if (lastPage?.pagination?.hasMore) {\n return lastPageParam + 1;\n }\n return undefined;\n}\n\ntype TracesPageResponse = ListTracesLightResponse | ListBranchesResponse;\n\n/** Branch rows are full spans and trace rows are lightweight; the list only reads the\n * fields they share, so both are surfaced as `LightSpanRecord`. */\nfunction getPageSpans(page: TracesPageResponse): LightSpanRecord[] {\n if ('branches' in page) return page.branches ?? [];\n return page.spans ?? [];\n}\n\n/** Deduplicates trace/branch rows by traceId + spanId across all loaded pages.\n * Also surfaces page 0's deltaCursor so the live-tail query can read it reactively. */\nexport function selectUniqueTraces(data: { pages: TracesPageResponse[] }): {\n spans: LightSpanRecord[];\n deltaCursor: string | undefined;\n} {\n const seen = new Set<string>();\n const spans = data.pages\n .flatMap(page => getPageSpans(page))\n .filter(span => {\n const key = `${span.traceId}:${span.spanId}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n return { spans, deltaCursor: data.pages[0]?.deltaCursor };\n}\n\ntype RowIdentity = { traceId: string; spanId?: string | null };\n\nfunction rowKey(row: RowIdentity): string {\n return `${row.traceId}:${row.spanId}`;\n}\n\nfunction indexRowsByKey<TRow extends RowIdentity>(rows: TRow[]): Map<string, TRow> {\n return new Map(rows.map(row => [rowKey(row), row]));\n}\n\n/** Replaces existing page-0 rows in place (keyed by traceId:spanId) with\n * refreshed copies from the server. Rows the server doesn't return are kept\n * as-is so delta-accumulated rows that have aged off the server's page 0\n * aren't dropped from the UI. New rows aren't added here — delta polling\n * delivers those. */\nexport function refreshPage0Rows(\n old: InfiniteData<TracesPageResponse> | undefined,\n refreshed: ListTracesLightResponse | ListBranchesResponse,\n listMode: TraceListMode,\n): InfiniteData<TracesPageResponse> | undefined {\n if (!old || old.pages.length === 0) return old;\n const [firstPage, ...rest] = old.pages;\n if (!firstPage) return old;\n\n // Branch and trace rows have different row shapes, so each mode keys its own map.\n let updatedFirst: TracesPageResponse;\n if (listMode === 'branches' && 'branches' in firstPage && 'branches' in refreshed) {\n const refreshedByKey = indexRowsByKey(refreshed.branches ?? []);\n if (refreshedByKey.size === 0) return old;\n updatedFirst = {\n ...firstPage,\n branches: (firstPage.branches ?? []).map(existing => refreshedByKey.get(rowKey(existing)) ?? existing),\n };\n } else if ('spans' in firstPage && 'spans' in refreshed) {\n const refreshedByKey = indexRowsByKey(refreshed.spans ?? []);\n if (refreshedByKey.size === 0) return old;\n updatedFirst = {\n ...firstPage,\n spans: (firstPage.spans ?? []).map(existing => refreshedByKey.get(rowKey(existing)) ?? existing),\n };\n } else {\n return old;\n }\n\n return { ...old, pages: [updatedFirst, ...rest] };\n}\n\n/** Stable `startedAt DESC` sort matching the server's default page-mode\n * ordering for both list endpoints. Rows missing `startedAt` sink to the\n * bottom (compared as time 0). */\nfunction sortRowsByStartedAtDesc<T extends { startedAt?: unknown }>(rows: T[]): T[] {\n return [...rows].sort((a, b) => {\n const aTime = a.startedAt ? new Date(a.startedAt as string | number | Date).getTime() : 0;\n const bTime = b.startedAt ? new Date(b.startedAt as string | number | Date).getTime() : 0;\n return bTime - aTime;\n });\n}\n\n/** Prepends delta-mode rows into page 0 and advances its deltaCursor.\n * Delta responses come back in server cursor order (insertion order into\n * the per-store delta index), not the `startedAt DESC` order page-mode\n * uses — so we re-sort the merged page 0 to match what the user sees on\n * a fresh page-mode load. Cross-page duplication is handled later by\n * selectUniqueTraces. */\nexport function mergeDeltaIntoPage0(\n old: InfiniteData<TracesPageResponse> | undefined,\n delta: ListTracesLightResponse | ListBranchesResponse,\n listMode: TraceListMode,\n): InfiniteData<TracesPageResponse> | undefined {\n if (!old || old.pages.length === 0) return old;\n const [firstPage, ...rest] = old.pages;\n if (!firstPage) return old;\n const nextCursor = delta.deltaCursor ?? firstPage.deltaCursor;\n\n let updatedFirst: TracesPageResponse;\n if (listMode === 'branches' && 'branches' in firstPage) {\n const newRows = (delta as ListBranchesResponse).branches ?? [];\n updatedFirst = {\n ...firstPage,\n branches: sortRowsByStartedAtDesc([...newRows, ...(firstPage.branches ?? [])]),\n deltaCursor: nextCursor,\n };\n } else if ('spans' in firstPage) {\n const newRows = (delta as ListTracesLightResponse).spans ?? [];\n updatedFirst = {\n ...firstPage,\n spans: sortRowsByStartedAtDesc([...newRows, ...(firstPage.spans ?? [])]),\n deltaCursor: nextCursor,\n };\n } else {\n return old;\n }\n\n return { ...old, pages: [updatedFirst, ...rest] };\n}\n\nexport interface UseTracesArgs extends TracesFilters {\n enabled?: boolean;\n /** Optional overrides for the live-tail polling tunables. Any omitted fields fall back to the\n * built-in defaults; pass only what you want to change. */\n polling?: TracesPollingConfig;\n /** TanStack overrides for each underlying query, spread last. The hook consumes each query's data internally, so `select` must keep the default shape. */\n queryOptions?: {\n traces?: MastraInfiniteQueryOptions<\n TracesPageResponse,\n ReturnType<typeof selectUniqueTraces>,\n readonly ['traces', TraceListMode, TracesFilters['filters']],\n number\n >;\n delta?: MastraQueryOptions<Awaited<ReturnType<typeof fetchTracesFn>> | null>;\n statusRefresh?: MastraQueryOptions<Awaited<ReturnType<typeof fetchTracesFn>>>;\n };\n}\n\ninterface UseTracesReturn {\n data: { spans: LightSpanRecord[]; deltaCursor: string | undefined } | undefined;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n fetchNextPage: () => void;\n isLoading: boolean;\n isError: boolean;\n error: Error | null;\n setEndOfListElement: (node: HTMLDivElement | null) => void;\n isRefetching: boolean;\n autoRefetch: boolean;\n setAutoRefetch: (v: boolean) => void;\n recentlyAddedKeys: Set<string>;\n dataUpdatedAt: number;\n errorUpdatedAt: number;\n isFetching: boolean;\n isSuccess: boolean;\n fetchStatus: 'idle' | 'fetching' | 'paused';\n refetch: () => void;\n}\n\nexport const useTraces: (args: UseTracesArgs) => UseTracesReturn = ({\n filters,\n listMode = 'traces',\n polling = {},\n enabled = true,\n queryOptions,\n}: UseTracesArgs) => {\n const {\n deltaPollIntervalMs = DEFAULT_POLLING_CONFIG.deltaPollIntervalMs,\n deltaChaseIntervalMs = DEFAULT_POLLING_CONFIG.deltaChaseIntervalMs,\n deltaLimit = DEFAULT_POLLING_CONFIG.deltaLimit,\n pageModeRefetchIntervalMs = DEFAULT_POLLING_CONFIG.pageModeRefetchIntervalMs,\n page0StatusRefreshIntervalMs = DEFAULT_POLLING_CONFIG.page0StatusRefreshIntervalMs,\n idleGuardThresholdMs = DEFAULT_POLLING_CONFIG.idleGuardThresholdMs,\n minRefetchSpinMs = DEFAULT_POLLING_CONFIG.minRefetchSpinMs,\n deltaHighlightMs = DEFAULT_POLLING_CONFIG.deltaHighlightMs,\n } = polling;\n const client = useMastraClient();\n const queryClient = useQueryClient();\n const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();\n\n const [deltaSupport, setDeltaSupport] = useState<DeltaSupport>(() => deltaSupportByClient.get(client) ?? 'unknown');\n const deltaUnsupported = deltaSupport === 'unsupported';\n\n // When false, all automatic polling stops: delta polls, status refresh,\n // idle-guard resets, and the page-mode fallback interval. Manual `resync`\n // still works. Session-scoped (no persistence across mounts).\n const [autoRefetch, setAutoRefetch] = useState(true);\n\n // Keys (`traceId:spanId`) of rows that arrived via the most recent delta\n // poll(s). The list view reads this to apply a temporary highlight class\n // for deltaHighlightMs, then they auto-expire. Resets on filter/listMode\n // change since a new query key spawns a fresh list.\n const [recentlyAddedKeys, setRecentlyAddedKeys] = useState<Set<string>>(() => new Set());\n useEffect(() => {\n setRecentlyAddedKeys(new Set());\n }, [listMode, filters]);\n\n const tracesQueryKey = ['traces', listMode, filters] as const;\n\n const query = useInfiniteQuery({\n queryKey: tracesQueryKey,\n enabled,\n queryFn: ({ pageParam }) =>\n fetchTracesFn({\n client,\n page: pageParam,\n perPage: TRACES_PER_PAGE,\n filters,\n listMode,\n }),\n initialPageParam: 0,\n getNextPageParam: getTracesNextPageParam,\n select: selectUniqueTraces,\n retry: false,\n // Disable polling on 403 to prevent flickering.\n // Fall back to page-mode polling only when delta isn't running.\n refetchInterval: q => {\n if (is403ForbiddenError(q.state.error)) return false;\n if (!autoRefetch) return false;\n return deltaUnsupported ? pageModeRefetchIntervalMs : false;\n },\n ...queryOptions?.traces,\n });\n\n const cursor = query.data?.deltaCursor;\n\n // If page 0 came back without a deltaCursor, the server/store doesn't\n // support delta polling. Pin the client to 'unsupported' so the infinite\n // query resumes page-mode polling and we stop probing.\n useEffect(() => {\n if (query.isSuccess && cursor === undefined && deltaSupport === 'unknown') {\n deltaSupportByClient.set(client, 'unsupported');\n setDeltaSupport('unsupported');\n }\n }, [query.isSuccess, cursor, deltaSupport, client]);\n\n const deltaQuery = useQuery({\n queryKey: ['traces-delta', listMode, filters] as const,\n queryFn: () => {\n const current = queryClient.getQueryData<InfiniteData<TracesPageResponse>>(tracesQueryKey)?.pages[0]?.deltaCursor;\n if (!current) return null;\n return fetchTracesFn({\n client,\n mode: 'delta',\n after: current,\n limit: deltaLimit,\n filters,\n listMode,\n });\n },\n enabled: enabled && !!cursor && !deltaUnsupported && autoRefetch,\n retry: false,\n refetchInterval: q => {\n if (q.state.error) return false;\n const data = q.state.data as ListTracesLightResponse | ListBranchesResponse | null | undefined;\n if (data?.delta?.hasMore) return deltaChaseIntervalMs;\n return deltaPollIntervalMs;\n },\n ...queryOptions?.delta,\n });\n\n // Merge new delta rows into the infinite-query cache. Also captures the\n // arrived keys into `recentlyAddedKeys` for deltaHighlightMs so the UI\n // can briefly distinguish them. The cleanup timer is intentionally NOT\n // tied to the effect lifecycle — if a newer delta arrives first, we still\n // want each prior batch to expire on its own schedule.\n useEffect(() => {\n const result = deltaQuery.data;\n if (!result) return;\n queryClient.setQueryData<InfiniteData<TracesPageResponse>>(tracesQueryKey, old =>\n mergeDeltaIntoPage0(old, result, listMode),\n );\n\n const newRows: RowIdentity[] =\n listMode === 'branches' && 'branches' in result\n ? (result.branches ?? [])\n : 'spans' in result\n ? (result.spans ?? [])\n : [];\n if (newRows.length === 0) return;\n const keys = newRows.map(r => `${r.traceId}:${r.spanId ?? ''}`);\n setRecentlyAddedKeys(prev => {\n const next = new Set(prev);\n for (const k of keys) next.add(k);\n return next;\n });\n setTimeout(() => {\n setRecentlyAddedKeys(prev => {\n const next = new Set(prev);\n for (const k of keys) next.delete(k);\n return next;\n });\n }, deltaHighlightMs);\n // tracesQueryKey is a new array each render but its contents drive cache keying;\n // depending on its members (listMode/filters) is enough.\n }, [deltaQuery.data, queryClient, listMode, filters, deltaHighlightMs]);\n\n // A 501 means the server is too old (or store doesn't support delta) — pin\n // 'unsupported' so the delta query disables and page-mode polling resumes.\n useEffect(() => {\n if (isHttp501(deltaQuery.error)) {\n deltaSupportByClient.set(client, 'unsupported');\n setDeltaSupport('unsupported');\n }\n }, [deltaQuery.error, client]);\n\n // Periodic page-0 refresh to surface status updates on visible rows\n // (running → success/error). Only runs while delta is the primary polling\n // mechanism; otherwise the infinite query's own refetchInterval covers it.\n const statusRefreshQuery = useQuery({\n queryKey: ['traces-status-refresh', listMode, filters] as const,\n queryFn: () =>\n fetchTracesFn({\n client,\n page: 0,\n perPage: TRACES_PER_PAGE,\n filters,\n listMode,\n }),\n enabled: enabled && !!cursor && !deltaUnsupported && autoRefetch,\n refetchInterval: page0StatusRefreshIntervalMs,\n refetchOnMount: false,\n retry: false,\n ...queryOptions?.statusRefresh,\n });\n\n useEffect(() => {\n const result = statusRefreshQuery.data;\n if (!result) return;\n queryClient.setQueryData<InfiniteData<TracesPageResponse>>(tracesQueryKey, old =>\n refreshPage0Rows(old, result, listMode),\n );\n }, [statusRefreshQuery.data, queryClient, listMode, filters]);\n\n // Idle guard: when the tab returns from being hidden, check how long it's\n // been since the last successful poll. If past the threshold, reset the\n // infinite query so page 0 refetches and the cursor is re-seeded.\n const lastSuccessAtRef = useRef(0);\n useEffect(() => {\n const ts = Math.max(query.dataUpdatedAt, deltaQuery.dataUpdatedAt, statusRefreshQuery.dataUpdatedAt);\n if (ts > lastSuccessAtRef.current) {\n lastSuccessAtRef.current = ts;\n }\n }, [query.dataUpdatedAt, deltaQuery.dataUpdatedAt, statusRefreshQuery.dataUpdatedAt]);\n\n // Track autoRefetch in a ref so the visibility listener (attached once)\n // reads the current value without needing to re-attach.\n const autoRefetchRef = useRef(autoRefetch);\n useEffect(() => {\n autoRefetchRef.current = enabled && autoRefetch;\n }, [enabled, autoRefetch]);\n\n useEffect(() => {\n const handler = () => {\n if (document.visibilityState !== 'visible') return;\n if (!autoRefetchRef.current) return;\n if (!shouldResetAfterIdle(lastSuccessAtRef.current, Date.now(), idleGuardThresholdMs)) return;\n void queryClient.resetQueries({ queryKey: ['traces', listMode, filters] });\n };\n document.addEventListener('visibilitychange', handler);\n return () => document.removeEventListener('visibilitychange', handler);\n }, [queryClient, listMode, filters, idleGuardThresholdMs]);\n\n const { hasNextPage, isFetchingNextPage, fetchNextPage } = query;\n\n useEffect(() => {\n if (enabled && isEndOfListInView && hasNextPage && !isFetchingNextPage) {\n void fetchNextPage();\n }\n }, [enabled, isEndOfListInView, hasNextPage, isFetchingNextPage, fetchNextPage]);\n\n // `isRefetching` aggregates every active fetch — page-mode (initial, next\n // page, manual resync, idle reset), the 60s page-0 status refresh, AND the\n // delta polls — so a spinner bound to it acts as a heartbeat indicator.\n //\n // Short polls (e.g. delta on localhost) can resolve in tens of ms — too\n // brief for `animate-spin` (1s/rotation) to register visually, and quick\n // enough that React may batch the start/finish transitions so we never\n // even observe `isFetching: true`. So we also watch every query's\n // data/errorUpdatedAt; any advance pulses `isRefetching` true for at least\n // minRefetchSpinMs, which is ~144° of rotation — clearly perceptible.\n const isFetchingAny = query.isFetching || statusRefreshQuery.isFetching || deltaQuery.isFetching;\n const lastActivityAt = Math.max(\n query.dataUpdatedAt,\n query.errorUpdatedAt,\n deltaQuery.dataUpdatedAt,\n deltaQuery.errorUpdatedAt,\n statusRefreshQuery.dataUpdatedAt,\n statusRefreshQuery.errorUpdatedAt,\n );\n const [pulse, setPulse] = useState(false);\n const prevActivityAtRef = useRef(lastActivityAt);\n useEffect(() => {\n if (lastActivityAt > prevActivityAtRef.current) {\n prevActivityAtRef.current = lastActivityAt;\n setPulse(true);\n const t = setTimeout(() => setPulse(false), minRefetchSpinMs);\n return () => clearTimeout(t);\n }\n }, [lastActivityAt, minRefetchSpinMs]);\n const isRefetching = isFetchingAny || pulse;\n\n return {\n ...query,\n setEndOfListElement,\n isRefetching,\n autoRefetch,\n setAutoRefetch,\n recentlyAddedKeys,\n };\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraMutationOptions } from '../shared/query-options';\n\ntype CreateFeedbackResponse = Awaited<ReturnType<MastraClient['createFeedback']>>;\n\ntype UseCreateFeedbackProps = {\n traceId: string;\n spanId?: string;\n queryOptions?: MastraMutationOptions<CreateFeedbackResponse, { text: string }>;\n};\n\n/**\n * Submits a free-text comment as a feedback record, scoped to the trace or to a\n * single span, then invalidates the matching feedback list so it refreshes.\n */\nexport const useCreateFeedback = ({ traceId, spanId, queryOptions }: UseCreateFeedbackProps) => {\n const client = useMastraClient();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ text }: { text: string }) =>\n client.createFeedback({\n feedback: {\n traceId,\n ...(spanId ? { spanId } : {}),\n feedbackType: 'comment',\n feedbackSource: 'user',\n value: text,\n },\n }),\n onSuccess: () =>\n queryClient.invalidateQueries({\n queryKey: spanId ? ['span-feedback', traceId, spanId] : ['trace-feedback', traceId],\n }),\n ...queryOptions,\n });\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraMutationOptions } from '../shared/query-options';\n\ntype DeleteFeedbackResponse = Awaited<ReturnType<MastraClient['deleteFeedback']>>;\n\ntype UseDeleteFeedbackProps = {\n traceId: string;\n spanId?: string;\n queryOptions?: MastraMutationOptions<DeleteFeedbackResponse, { feedbackId: string }>;\n};\n\n/**\n * Deletes a single feedback record by id, then invalidates the matching\n * feedback list (trace- or span-scoped) so it refreshes.\n */\nexport const useDeleteFeedback = ({ traceId, spanId, queryOptions }: UseDeleteFeedbackProps) => {\n const client = useMastraClient();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ feedbackId }: { feedbackId: string }) => client.deleteFeedback({ feedbackIds: [feedbackId] }),\n onSuccess: () =>\n queryClient.invalidateQueries({\n queryKey: spanId ? ['span-feedback', traceId, spanId] : ['trace-feedback', traceId],\n }),\n ...queryOptions,\n });\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\n\nimport { useMastraClient } from '../../mastra-client-context';\nimport { getFeedbackRefetchInterval } from '../feedback/feedback-refetch-interval';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\ntype SpanFeedbackResponse = Awaited<ReturnType<MastraClient['listFeedback']>>;\n\ntype UseSpanFeedbackProps<TData> = {\n traceId?: string;\n spanId?: string;\n page?: number;\n queryOptions?: MastraQueryOptions<SpanFeedbackResponse, TData>;\n};\n\n/**\n * Feedback scoped to a single span. Both identifiers are required: without a `spanId`\n * the query stays disabled rather than falling back to trace-wide feedback.\n *\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useSpanFeedback = <TData = SpanFeedbackResponse,>({\n traceId = '',\n spanId = '',\n page,\n queryOptions,\n}: UseSpanFeedbackProps<TData>): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n const pageNumber = page ?? 0;\n return useQuery({\n // `spanId` must stay in the key, otherwise React Query serves the previously\n // selected span's feedback when switching spans within the same trace.\n queryKey: ['span-feedback', traceId, spanId, pageNumber],\n queryFn: () =>\n client.listFeedback({\n filters: { traceId, spanId },\n pagination: { page: pageNumber, perPage: 10 },\n }),\n refetchInterval: getFeedbackRefetchInterval,\n gcTime: 0,\n staleTime: 0,\n ...queryOptions,\n });\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 { getFeedbackRefetchInterval } from '../feedback/feedback-refetch-interval';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\ntype TraceFeedbackResponse = Awaited<ReturnType<MastraClient['listFeedback']>>;\n\ntype UseTraceFeedbackProps<TData> = {\n traceId?: string;\n page?: number;\n queryOptions?: MastraQueryOptions<TraceFeedbackResponse, TData>;\n};\n\n/** Loads a page of trace-level feedback and stops polling when storage cannot serve feedback. */\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useTraceFeedback = <TData = TraceFeedbackResponse,>({\n traceId = '',\n page,\n queryOptions,\n}: UseTraceFeedbackProps<TData>): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n const pageNumber = page ?? 0;\n return useQuery({\n queryKey: ['trace-feedback', traceId, pageNumber],\n queryFn: () =>\n client.listFeedback({\n filters: { traceId },\n pagination: { page: pageNumber, perPage: 10 },\n }),\n // The API can't express \"spanId is null\", so trace-level records are isolated client-side.\n // Note: this runs after server-side pagination, so a page may hold fewer than `perPage` rows.\n select: data => {\n const feedback = data.feedback.filter(item => !item.spanId);\n if (!data.pagination) return { ...data, feedback } as TData;\n return { ...data, feedback, pagination: { ...data.pagination, total: feedback.length } } as TData;\n },\n refetchInterval: getFeedbackRefetchInterval,\n gcTime: 0,\n staleTime: 0,\n ...queryOptions,\n });\n};\n","import { MastraClientError } from '@mastra/client-js';\nimport type {\n GetTraceQueryFieldsArgs,\n GetTraceQueryFieldsResponse,\n GetTraceQueryValuesArgs,\n MastraClient,\n} from '@mastra/client-js';\nimport { keepPreviousData, useQuery } from '@tanstack/react-query';\nimport { useMemo } from 'react';\n\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\n\nexport type TraceQueryDiscoveryTimeRange = GetTraceQueryFieldsArgs['timeRange'];\n\n/** Lazy value lookup for one discovered field. Structurally compatible with filter bar suggestion resolvers. */\nexport type TraceQueryValuesResolver = (ctx: { query: string; signal: AbortSignal }) => Promise<{ value: string }[]>;\n\nexport type TraceMetadataFilterField = {\n /** `metadata.<key>` — doubles as the filter bar field id. */\n path: string;\n suggestions: TraceQueryValuesResolver;\n};\n\n// Server caps discovery limits at 100 (TRACE_QUERY_DISCOVERY_MAX_LIMIT).\nconst DISCOVERY_LIMIT = 100;\n\nconst EMPTY_FIELDS: GetTraceQueryFieldsResponse = {\n canonicalFields: [],\n observedFields: [],\n observedFieldsTruncated: false,\n};\n\nconst TRACE_QUERY_DISCOVERY_UNSUPPORTED = 'TRACE_QUERY_DISCOVERY_UNSUPPORTED';\n\nconst isDiscoveryUnsupportedError = (error: unknown) =>\n error instanceof MastraClientError &&\n typeof error.body === 'object' &&\n error.body !== null &&\n (error.body as { code?: unknown }).code === TRACE_QUERY_DISCOVERY_UNSUPPORTED;\n\nexport const traceQueryFieldsQueryKey = (timeRange: TraceQueryDiscoveryTimeRange) =>\n ['trace-query-fields', timeRange.from, timeRange.to] as const;\n\n/** Lazy FilterBar suggestions resolver backed by the value-discovery endpoint for one\n * `predicateScope` + `path`. the caller owns debounce/abort; this only fetches. */\nexport const createTraceQueryValuesResolver = (\n client: MastraClient,\n timeRange: TraceQueryDiscoveryTimeRange,\n predicateScope: GetTraceQueryValuesArgs['predicateScope'],\n path: string,\n): TraceQueryValuesResolver => {\n return async ({ query: search, signal }) => {\n const { values } = await client.getTraceQueryValues(\n { timeRange, predicateScope, path, search: search.trim() || undefined, limit: DISCOVERY_LIMIT },\n { signal },\n );\n return values.map(({ value }) => ({ value }));\n };\n};\n\n/**\n * Discovers the `metadata.*` fields observed on traces in the given time range and returns\n * them as filter bar fields, each with a lazy `suggestions` resolver that fetches the field's\n * values when the user opens the value step (the caller owns debounce/abort).\n *\n * Resolves to an empty field list when the server or store does not support discovery\n * (`TRACE_QUERY_DISCOVERY_UNSUPPORTED`) so callers never stay blocked.\n */\nexport const useTraceMetadataFilterFields = ({\n timeRange,\n queryOptions,\n}: {\n timeRange: TraceQueryDiscoveryTimeRange;\n queryOptions?: MastraQueryOptions<GetTraceQueryFieldsResponse>;\n}) => {\n const client = useMastraClient();\n\n const query = useQuery({\n queryKey: traceQueryFieldsQueryKey(timeRange),\n queryFn: async ({ signal }): Promise<GetTraceQueryFieldsResponse> => {\n try {\n return await client.getTraceQueryFields(\n { timeRange, predicateScope: 'trace', limit: DISCOVERY_LIMIT },\n { signal },\n );\n } catch (error) {\n if (isDiscoveryUnsupportedError(error)) return EMPTY_FIELDS;\n throw error;\n }\n },\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n // Changing the time range must not tear down the filter bar behind a skeleton;\n // keep the previous field list until the new range resolves.\n placeholderData: keepPreviousData,\n ...queryOptions,\n });\n\n const observedFields = query.data?.observedFields;\n const canonicalFields = query.data?.canonicalFields ?? EMPTY_FIELDS.canonicalFields;\n\n const fields = useMemo<TraceMetadataFilterField[]>(\n () =>\n (observedFields ?? []).map(field => ({\n path: field.path,\n suggestions: createTraceQueryValuesResolver(client, timeRange, 'trace', field.path),\n })),\n [observedFields, client, timeRange],\n );\n\n return { fields, canonicalFields, isLoading: query.isLoading, error: query.error };\n};\n","import { useMastraClient } from '../../mastra-client-context';\n\n/**\n * Storage key for the trace list column preferences, scoped to the Mastra server the client\n * talks to so each project keeps its own column layout.\n */\nexport function useTraceColumnPreferencesStorageKey(): string {\n const client = useMastraClient();\n const projectUrl =\n client.options.baseUrl || (typeof window === 'undefined' ? 'local' : window.location.origin || 'local');\n const apiPrefix = client.options.apiPrefix ?? '/api';\n return `mastra:traces:columns:${projectUrl}:${apiPrefix}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["IMMUTABLE_CACHE_TIME","tanstackQueryOptions"],"sources":["../../../src/hooks/traces/discovery-cache.ts","../../../src/hooks/traces/use-branch.ts","../../../src/hooks/traces/types.ts","../../../src/hooks/traces/use-entity-names.ts","../../../src/hooks/traces/use-environments.ts","../../../src/hooks/traces/use-service-names.ts","../../../src/hooks/traces/use-span-detail.ts","../../../src/hooks/traces/use-tags.ts","../../../src/hooks/traces/use-thread-has-other-traces.ts","../../../src/hooks/traces/use-trace-light-spans.ts","../../../src/hooks/traces/use-trace-spans.ts","../../../src/hooks/traces/use-trace-or-branch-spans.ts","../../../src/hooks/traces/use-trace-query.ts","../../../src/hooks/traces/use-trace-usage.ts","../../../src/hooks/traces/use-traces.tsx","../../../src/hooks/traces/use-create-feedback.tsx","../../../src/hooks/traces/use-delete-feedback.tsx","../../../src/hooks/traces/use-span-feedback.tsx","../../../src/hooks/traces/use-trace-feedback.tsx","../../../src/hooks/traces/use-trace-metadata-filter-fields.ts","../../../src/hooks/traces/use-trace-column-preferences-storage-key.ts"],"sourcesContent":["/**\n * How long discovery results (tags, environments, service names, entity\n * names) stay fresh on the client.\n *\n * Discovery values are filter suggestions that change slowly, and the server\n * caches them for 5 minutes anyway. Without a staleTime, React Query refetches\n * on every mount and window focus, which pushes those refetches straight\n * through to the store's discovery refresh. Matching the server TTL keeps the\n * client from asking more often than the answer can change.\n */\nexport const DISCOVERY_STALE_TIME = 5 * 60 * 1000;\n","import 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';\nimport type { LightSpanRecord } from './types';\n\nexport type BranchResponse = { traceId: string; spans: LightSpanRecord[] } | null;\n\nexport interface UseBranchArgs<TData = BranchResponse> {\n traceId: string | null | undefined;\n spanId: string | null | undefined;\n depth?: number;\n queryOptions?: MastraQueryOptions<BranchResponse, TData>;\n}\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useBranch<TData = BranchResponse>({\n traceId,\n spanId,\n depth,\n queryOptions,\n}: UseBranchArgs<TData>): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['branch', traceId, spanId, depth],\n queryFn: async (): Promise<BranchResponse> => {\n if (!traceId || !spanId) {\n throw new Error('traceId and spanId are required');\n }\n return client.getBranch({ traceId, spanId, depth });\n },\n // A finished subtree can still gain spans from a resumed run or delayed export.\n staleTime: 0,\n ...queryOptions,\n });\n}\n","import type { MastraClient } from '@mastra/client-js';\nimport type { EntityType } from '@mastra/core/observability';\n\ntype GetTraceLightResponse = Awaited<ReturnType<MastraClient['getTraceLight']>>;\ntype GetSpanResponse = Awaited<ReturnType<MastraClient['getSpan']>>;\nexport type LightSpanRecord = GetTraceLightResponse['spans'][number];\nexport type SpanRecord = GetSpanResponse['span'];\n\nexport type TraceListMode = 'traces' | 'branches';\n\nexport type TraceUsageSummary = {\n inputTokens?: number;\n outputTokens?: number;\n estimatedCost?: number;\n costUnit?: string;\n};\n\nexport const ROOT_ENTITY_TYPES = {\n AGENT: 'agent',\n WORKFLOW: 'workflow_run',\n SCORER: 'scorer',\n INGEST: 'rag_ingestion',\n CLASSIFIER: 'classifier',\n} as const satisfies Record<string, `${EntityType}`>;\n","import type { MastraClient } from '@mastra/client-js';\nimport { EntityType } from '@mastra/core/observability';\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';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\nimport { ROOT_ENTITY_TYPES } from './types';\n\ntype EntityTypeValue = `${EntityType}`;\n\ntype EntityNamesResponse = Awaited<ReturnType<MastraClient['getEntityNames']>>;\n\ntype UseEntityNamesOptions<TData> = {\n entityType?: EntityTypeValue;\n rootOnly?: boolean;\n queryOptions?: MastraQueryOptions<EntityNamesResponse, TData>;\n};\n\nfunction resolveEntityType(entityType: EntityTypeValue) {\n return Object.values(EntityType).find(candidate => candidate === entityType);\n}\n\nexport const useEntityNames = <TData = EntityNamesResponse['names']>({\n entityType,\n rootOnly = false,\n queryOptions,\n}: UseEntityNamesOptions<TData> = {}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n // Mirror the queryFn branches so the cache key reflects what the server\n // actually returns. rootOnly only matters when entityType is not set; when\n // entityType is set, the query ignores rootOnly entirely.\n const queryKey = entityType\n ? ['observability-entity-names', 'by-type', entityType]\n : ['observability-entity-names', 'all', rootOnly ? 'root-only' : 'all-types'];\n\n return useQuery({\n queryKey,\n queryFn: async (): Promise<EntityNamesResponse> => {\n try {\n if (entityType) {\n const resolvedEntityType = resolveEntityType(entityType);\n if (!resolvedEntityType) return { names: [] };\n return await client.getEntityNames({ entityType: resolvedEntityType });\n }\n\n if (!rootOnly) {\n return await client.getEntityNames();\n }\n\n const responses = await Promise.all(\n Object.values(ROOT_ENTITY_TYPES).map(rootEntityType => {\n const resolvedEntityType = resolveEntityType(rootEntityType);\n if (!resolvedEntityType) return { names: [] };\n return client.getEntityNames({ entityType: resolvedEntityType });\n }),\n );\n\n return {\n names: Array.from(new Set(responses.flatMap(response => response?.names ?? []))).sort(),\n };\n } catch {\n return { names: [] };\n }\n },\n select: data => (data?.names ?? []) as TData,\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n ...queryOptions,\n });\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';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\n\ntype EnvironmentsResponse = Awaited<ReturnType<MastraClient['getEnvironments']>>;\ntype EnvironmentsData = EnvironmentsResponse['environments'];\n\nexport const useEnvironments = <TData = EnvironmentsData>({\n queryOptions,\n}: {\n queryOptions?: MastraQueryOptions<EnvironmentsResponse, TData>;\n} = {}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['observability-environments'],\n queryFn: async (): Promise<EnvironmentsResponse> => {\n try {\n return await client.getEnvironments();\n } catch {\n return { environments: [] };\n }\n },\n select: data => (data?.environments ?? []) as TData,\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n ...queryOptions,\n });\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';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\n\ntype ServiceNamesResponse = Awaited<ReturnType<MastraClient['getServiceNames']>>;\ntype ServiceNamesData = ServiceNamesResponse['serviceNames'];\n\nexport const useServiceNames = <TData = ServiceNamesData>({\n queryOptions,\n}: {\n queryOptions?: MastraQueryOptions<ServiceNamesResponse, TData>;\n} = {}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['observability-service-names'],\n queryFn: async (): Promise<ServiceNamesResponse> => {\n try {\n return await client.getServiceNames();\n } catch {\n return { serviceNames: [] };\n }\n },\n select: data => (data?.serviceNames ?? []) as TData,\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n ...queryOptions,\n });\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\nconst IMMUTABLE_CACHE_TIME = 1000 * 60 * 60 * 24 * 30; // 30 days, massive cache, span data is immutable\n\ntype SpanDetailResponse = Awaited<ReturnType<MastraClient['getSpan']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useSpanDetail<TData = SpanDetailResponse>({\n traceId,\n spanId,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n spanId: string | null | undefined;\n queryOptions?: MastraQueryOptions<SpanDetailResponse, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['span-detail', traceId, spanId],\n queryFn: async () => {\n if (!traceId || !spanId) {\n throw new Error('Trace ID and Span ID are required');\n }\n return client.getSpan(traceId, spanId);\n },\n staleTime: query => {\n const data = query.state.data;\n\n if (data?.span?.endedAt) {\n return IMMUTABLE_CACHE_TIME;\n }\n\n return 0;\n },\n ...queryOptions,\n });\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';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\n\ntype TagsResponse = Awaited<ReturnType<MastraClient['getTags']>>;\ntype TagsData = TagsResponse['tags'];\n\nexport const useTags = <TData = TagsData>({\n queryOptions,\n}: {\n queryOptions?: MastraQueryOptions<TagsResponse, TData>;\n} = {}): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['observability-tags'],\n queryFn: async (): Promise<TagsResponse> => {\n try {\n return await client.getTags();\n } catch {\n // Storage provider may not support tag discovery (e.g. LibSQL)\n return { tags: [] };\n }\n },\n select: data => (data?.tags ?? []) as TData,\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n ...queryOptions,\n });\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\n/**\n * Whether the memory thread holds more than one trace, i.e. whether a \"full thread\" view would\n * show anything beyond the current turn. `false` while loading or on error, so the link only\n * appears once we know it leads somewhere.\n */\ntype ThreadTracesResponse = Awaited<ReturnType<MastraClient['listTracesLight']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useThreadHasOtherTraces({\n threadId,\n queryOptions,\n}: {\n threadId: string | undefined;\n queryOptions?: MastraQueryOptions<ThreadTracesResponse, boolean>;\n}): boolean {\n const client = useMastraClient();\n const { data } = useQuery({\n queryKey: ['thread-trace-count', threadId],\n queryFn: () =>\n client.listTracesLight({\n filters: { threadId: threadId ?? '' },\n // Some stores apply metadata filters after paging, so a tiny page can miss sibling traces.\n // Match the page size the full thread view uses and count what actually comes back.\n pagination: { page: 0, perPage: 25 },\n }),\n select: response => (response.spans?.length ?? 0) > 1,\n ...queryOptions,\n });\n return data ?? false;\n}\n","import 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';\nimport type { LightSpanRecord } from './types';\n\nconst IMMUTABLE_CACHE_TIME = 1000 * 60 * 60 * 24 * 30; // 30 days, massive cache, span data is immutable\n\ntype TraceLightSpansResponse = { traceId: string; spans: LightSpanRecord[] } | null;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useTraceLightSpans<TData = TraceLightSpansResponse>({\n traceId,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n queryOptions?: MastraQueryOptions<TraceLightSpansResponse, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n\n return useQuery({\n queryKey: ['trace-light-spans', traceId],\n queryFn: async (): Promise<TraceLightSpansResponse> => {\n if (!traceId) {\n throw new Error('Trace ID is required');\n }\n const res = await client.getTraceLight(traceId);\n return res;\n },\n staleTime: query => {\n const data = query.state.data;\n\n const isFinished = data?.spans.every(d => Boolean(d.endedAt));\n\n if (isFinished) {\n return IMMUTABLE_CACHE_TIME;\n }\n\n return 0;\n },\n ...queryOptions,\n });\n}\n","import type { MastraClient } from '@mastra/client-js';\nimport { queryOptions as tanstackQueryOptions, useQueries, useQuery, useQueryClient } from '@tanstack/react-query';\nimport type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\n/**\n * Key, fetcher and stale policy of the `trace-spans` query. Every observer of this key must\n * share these (rather than only the key) so one observer with a stricter `staleTime` does not\n * refetch data another one considers fresh.\n */\ntype TraceResponse = Awaited<ReturnType<MastraClient['getTrace']>>;\n\nexport const traceSpansQueryOptions = (\n client: MastraClient,\n traceId: string | null | undefined,\n): UseQueryOptions<TraceResponse, Error, TraceResponse, (string | null | undefined)[]> =>\n tanstackQueryOptions({\n queryKey: ['trace-spans', traceId],\n queryFn: async () => {\n if (!traceId) {\n throw new Error('Trace ID is required');\n }\n const res = await client.getTrace(traceId);\n return res;\n },\n // Resumed runs and delayed exports can append spans even when every known span has ended.\n staleTime: 0,\n });\n\n/**\n * Every span of a single trace, with its full payload.\n *\n * The lightweight projection exists to keep blob columns off the read path of a\n * *list*, where the cost is paid once per trace on screen. A trace that is open\n * has already narrowed that to one, and the panel both renders and searches\n * these spans -- `input`, `output` and `attributes` included -- so the\n * projection would only hide content the reader is looking at.\n */\nexport type TraceSpansData = Awaited<ReturnType<MastraClient['getTrace']>>;\n\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport function useTraceSpans<TData = TraceSpansData>({\n traceId,\n passive = false,\n queryOptions,\n}: {\n traceId: string | null | undefined;\n passive?: boolean;\n queryOptions?: MastraQueryOptions<TraceSpansData, TData, (string | null | undefined)[]>;\n}): UseQueryResult<TData> {\n const client = useMastraClient();\n\n const { queryKey, queryFn, enabled, staleTime } = traceSpansQueryOptions(client, traceId);\n\n return useQuery<TraceSpansData, Error, TData, (string | null | undefined)[]>({\n queryKey,\n queryFn,\n enabled,\n staleTime,\n // History rows share updates but leave automatic refreshes to the selected detail.\n refetchOnMount: !passive,\n refetchOnWindowFocus: !passive,\n refetchOnReconnect: !passive,\n ...queryOptions,\n });\n}\n\n/**\n * Returns a function that loads a full trace through the shared `trace-spans` cache, so an\n * imperative read (e.g. an export) and the trace panel always see the same payload.\n */\nexport function useFetchTraceSpans(): (traceId: string) => Promise<TraceSpansData> {\n const client = useMastraClient();\n const queryClient = useQueryClient();\n\n return (traceId: string) => queryClient.fetchQuery(traceSpansQueryOptions(client, traceId));\n}\n\n/**\n * Observes the `trace-spans` query of several traces at once and projects each one with `select`.\n * Traces still loading (or failed) yield `fallback(traceId)` so the result always lines up with `traceIds`.\n */\nexport function useTraceSpansQueries<T>({\n traceIds,\n select,\n fallback,\n queryOptions,\n}: {\n traceIds: string[];\n select: (traceId: string, data: TraceSpansData) => T;\n fallback: (traceId: string) => T;\n /** Applied to every per-trace query. */\n queryOptions?: MastraQueryOptions<TraceSpansData, T, (string | null | undefined)[]>;\n}): T[] {\n const client = useMastraClient();\n\n return useQueries({\n queries: traceIds.map(traceId => ({\n ...traceSpansQueryOptions(client, traceId),\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n select: (data: TraceSpansData) => select(traceId, data),\n ...queryOptions,\n })),\n combine: results =>\n results.map((result, index) =>\n result.data === undefined ? fallback(traceIds[index] ?? '') : (result.data as T),\n ),\n });\n}\n","import type { MastraQueryOptions } from '../shared/query-options';\nimport type { TraceListMode, LightSpanRecord } from './types';\nimport { useBranch } from './use-branch';\nimport type { BranchResponse } from './use-branch';\nimport { useTraceSpans } from './use-trace-spans';\nimport type { TraceSpansData } from './use-trace-spans';\n\nexport interface UseTraceOrBranchSpansArgs {\n traceId: string | null | undefined;\n /** Required when `listMode === 'branches'` — the anchor span identifying the displayed\n * subtree. The hook fetches `getBranch(traceId, anchorSpanId)`. Intra-panel span selection\n * is separate (the caller's `spanIdParam`); the anchor stays put while it changes. */\n anchorSpanId?: string | null;\n listMode: TraceListMode;\n depth?: number;\n /**\n * Per-query TanStack overrides, spread last. `select` must keep the default data shape\n * because this hook reads `.spans` from both results.\n */\n queryOptions?: {\n trace?: MastraQueryOptions<TraceSpansData, TraceSpansData, (string | null | undefined)[]>;\n branch?: MastraQueryOptions<BranchResponse, BranchResponse>;\n };\n}\n\nexport interface UseTraceOrBranchSpansResult {\n spans: LightSpanRecord[] | undefined;\n /** Set in branches mode; undefined in traces mode (which uses parentSpanId == null). */\n anchorSpanId: string | undefined;\n isLoading: boolean;\n isError: boolean;\n error: unknown;\n}\n\n/**\n * Unified data source for the trace/span detail panel. Returns trace spans (full tree from the\n * root) in traces mode, or branch spans (subtree rooted at `anchorSpanId`) in branches mode.\n * Only the active query fires; the inactive one is disabled via its `enabled` flag.\n *\n * Both modes carry full span payloads: the panel renders and searches them, so a lightweight\n * projection here would hide content from the reader looking straight at it.\n */\nexport function useTraceOrBranchSpans({\n traceId,\n anchorSpanId,\n listMode,\n depth,\n queryOptions,\n}: UseTraceOrBranchSpansArgs): UseTraceOrBranchSpansResult {\n const isBranches = listMode === 'branches';\n\n const traceQuery = useTraceSpans({\n traceId: isBranches ? null : traceId,\n queryOptions: { enabled: !isBranches && !!traceId, ...queryOptions?.trace },\n });\n const branchQuery = useBranch({\n traceId: isBranches ? traceId : null,\n spanId: isBranches ? anchorSpanId : null,\n depth,\n queryOptions: { enabled: isBranches && !!traceId && !!anchorSpanId, ...queryOptions?.branch },\n });\n\n if (isBranches) {\n return {\n spans: branchQuery.data?.spans,\n anchorSpanId: anchorSpanId ?? undefined,\n isLoading: branchQuery.isLoading,\n isError: branchQuery.isError,\n error: branchQuery.error,\n };\n }\n\n return {\n spans: traceQuery.data?.spans,\n anchorSpanId: undefined,\n isLoading: traceQuery.isLoading,\n isError: traceQuery.isError,\n error: traceQuery.error,\n };\n}\n","import { MastraClient } from '@mastra/client-js';\nimport type { QueryTracesKeysetInput, TraceQueryKeysetTraceResponse } from '@mastra/client-js';\nimport type { ListTracesArgs as StorageListTracesArgs } from '@mastra/core/storage';\nimport { keepPreviousData, skipToken, useInfiniteQuery } 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';\n\nexport const TRACE_QUERY_PER_PAGE = 25;\n\ntype TraceQueryTrace = TraceQueryKeysetTraceResponse['traces'][number];\n\ntype ListTracesArgs = NonNullable<Parameters<MastraClient['listTracesLight']>[0]>;\ntype LegacyTraceListFilters = StorageListTracesArgs['filters'];\ntype ListTracesLightResponse = Awaited<ReturnType<MastraClient['listTracesLight']>>;\ntype LightSpanRecord = ListTracesLightResponse['spans'][number];\n\nexport type TraceQueryArgs = Omit<QueryTracesKeysetInput, 'page' | 'pagination'>;\n\nexport interface UseTraceQueryArgs {\n query: TraceQueryArgs | undefined;\n limit?: number;\n enabled?: boolean;\n /** When false, lists traces through the legacy `listTracesLight` endpoint instead of the trace-query API. */\n withQueryTrace?: boolean;\n /** Filters for the legacy endpoint, as built by `buildTraceListFilters`. Only read when `withQueryTrace` is false. */\n legacyFilters?: LegacyTraceListFilters;\n /** TanStack options spread last into the trace-query (`traceQuery`) and legacy (`legacy`) infinite queries. */\n queryOptions?: {\n traceQuery?: MastraInfiniteQueryOptions<\n TraceQueryKeysetTraceResponse,\n TraceQueryTrace[],\n readonly unknown[],\n string | undefined\n >;\n legacy?: MastraInfiniteQueryOptions<ListTracesLightResponse, TraceQueryTrace[], readonly unknown[], number>;\n };\n}\n\nexport interface UseTraceQueryReturn {\n data: TraceQueryTrace[] | undefined;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n fetchNextPage: () => void;\n isLoading: boolean;\n /** The rows belong to the previous query key (e.g. another thread) while the new one loads. */\n isPlaceholderData: boolean;\n isFetching: boolean;\n isRefetching: boolean;\n fetchStatus: 'idle' | 'fetching' | 'paused';\n isError: boolean;\n error: Error | null;\n refetch: () => void;\n setEndOfListElement: (node: HTMLDivElement | null) => void;\n}\n\nexport function getTraceQueryNextPageParam(lastPage: TraceQueryKeysetTraceResponse | undefined): string | undefined {\n return lastPage?.page.next ?? undefined;\n}\n\nexport function selectTraceQueryTraces(data: { pages: TraceQueryKeysetTraceResponse[] }): TraceQueryTrace[] {\n const seen = new Set<string>();\n return data.pages.flatMap(page =>\n page.traces.filter(trace => {\n if (seen.has(trace.traceId)) return false;\n seen.add(trace.traceId);\n return true;\n }),\n );\n}\n\nconst toIsoString = (value: Date | string): string => (typeof value === 'string' ? value : value.toISOString());\n\n/** Maps a legacy light root span to a trace-query row. The light record carries no\n * environment, so it stays null. Running spans have no `endedAt` and may carry a\n * status outside the query API's enum; both are kept as-is (the list view handles them), hence the\n * assertion at this compatibility boundary. */\nexport function lightSpanToTraceQueryTrace(span: LightSpanRecord): TraceQueryTrace {\n const row = {\n traceId: span.traceId,\n rootSpanId: span.spanId,\n name: span.name,\n entityId: span.entityId ?? null,\n parentSpanId: span.parentSpanId ?? null,\n createdAt: toIsoString(span.createdAt),\n metadata: span.metadata ?? null,\n inputPreview: span.inputPreview ?? null,\n outputPreview: span.outputPreview ?? null,\n errorPreview: span.errorPreview ?? null,\n threadId: span.threadId ?? null,\n resourceId: span.resourceId ?? null,\n startedAt: toIsoString(span.startedAt),\n endedAt: span.endedAt == null ? span.endedAt : toIsoString(span.endedAt),\n entityName: span.entityName ?? null,\n entityType: span.entityType ?? null,\n environment: null,\n status: span.status,\n };\n return row as TraceQueryTrace;\n}\n\nexport function selectLegacyTraceQueryTraces(data: { pages: ListTracesLightResponse[] }): TraceQueryTrace[] {\n const seen = new Set<string>();\n return data.pages.flatMap(page =>\n page.spans.flatMap(span => {\n if (seen.has(span.traceId)) return [];\n seen.add(span.traceId);\n return [lightSpanToTraceQueryTrace(span)];\n }),\n );\n}\n\nexport function getLegacyTraceQueryNextPageParam(lastPage: ListTracesLightResponse): number | undefined {\n return lastPage.pagination?.hasMore ? lastPage.pagination.page + 1 : undefined;\n}\n\n/** Queries traces with cursor pagination and viewport-driven loading. */\nexport function useTraceQuery({\n query,\n limit = TRACE_QUERY_PER_PAGE,\n enabled = true,\n withQueryTrace = true,\n legacyFilters,\n queryOptions,\n}: UseTraceQueryArgs): UseTraceQueryReturn {\n const client = useMastraClient();\n const { inView, setRef: setEndOfListElement } = useInView();\n const queryResult = useInfiniteQuery<\n TraceQueryKeysetTraceResponse,\n Error,\n TraceQueryTrace[],\n readonly unknown[],\n string | undefined\n >({\n queryKey: ['trace-query', query, limit] as const,\n queryFn: query\n ? async ({ pageParam }) => {\n // Capability failures must reach the fallback without the SDK retrying 501 responses.\n const queryClient = new MastraClient({ ...client.options, retries: 0 });\n const response = await queryClient.queryTraces({ ...query, page: { limit, after: pageParam ?? null } });\n if ('traces' in response && 'page' in response) return response;\n throw new Error('Expected a cursor-paginated trace query response');\n }\n : skipToken,\n initialPageParam: undefined,\n getNextPageParam: getTraceQueryNextPageParam,\n select: selectTraceQueryTraces,\n retry: false,\n placeholderData: keepPreviousData,\n enabled: enabled && withQueryTrace,\n ...queryOptions?.traceQuery,\n });\n const orderBy = query?.orderBy;\n const legacyDirection = orderBy?.[0]?.direction === 'asc' ? 'ASC' : 'DESC';\n const legacyResult = useInfiniteQuery<ListTracesLightResponse, Error, TraceQueryTrace[], readonly unknown[], number>({\n queryKey: ['trace-query-legacy', legacyFilters, limit, orderBy] as const,\n queryFn: ({ pageParam }) =>\n client.listTracesLight({\n // Core's date-range filter types `start`/`end` loosely; the client param type is stricter.\n filters: legacyFilters as ListTracesArgs['filters'],\n pagination: { page: pageParam, perPage: limit },\n orderBy: { field: 'startedAt', direction: legacyDirection },\n }),\n initialPageParam: 0,\n getNextPageParam: getLegacyTraceQueryNextPageParam,\n select: selectLegacyTraceQueryTraces,\n retry: false,\n placeholderData: keepPreviousData,\n enabled: enabled && !withQueryTrace,\n ...queryOptions?.legacy,\n });\n const result = withQueryTrace ? queryResult : legacyResult;\n const {\n data,\n hasNextPage,\n isFetchingNextPage,\n fetchNextPage,\n isLoading,\n isPlaceholderData,\n isFetching,\n isRefetching,\n fetchStatus,\n isError,\n error,\n refetch,\n isFetchNextPageError,\n } = result;\n\n useEffect(() => {\n if (enabled && inView && hasNextPage && !isFetching && !isFetchNextPageError) {\n void fetchNextPage();\n }\n }, [enabled, inView, hasNextPage, isFetching, isFetchNextPageError, fetchNextPage]);\n\n return {\n data,\n hasNextPage,\n isFetchingNextPage,\n fetchNextPage,\n isLoading,\n isPlaceholderData,\n isFetching,\n isRefetching,\n fetchStatus,\n isError,\n error,\n refetch,\n setEndOfListElement,\n };\n}\n","import type { GetMetricBreakdownResponse } from '@mastra/core/storage';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport { getOrCreate } from '../shared/map';\nimport type { MastraQueryOptions } from '../shared/query-options';\nimport type { TraceUsageSummary } from './types';\n\nconst INPUT_TOKEN_METRIC = 'mastra_model_total_input_tokens';\nconst OUTPUT_TOKEN_METRIC = 'mastra_model_total_output_tokens';\n// Each trace can return two groups, while the breakdown endpoint allows at most 1,000.\nconst TRACE_IDS_PER_REQUEST = 500;\n\ntype TraceUsageAccumulator = {\n inputTokens?: number;\n outputTokens?: number;\n estimatedCost: number;\n hasEstimatedCost: boolean;\n costUnits: Set<string>;\n hasUnknownCostUnit: boolean;\n};\n\nfunction chunkTraceIds(traceIds: readonly string[]): string[][] {\n const chunks: string[][] = [];\n for (let index = 0; index < traceIds.length; index += TRACE_IDS_PER_REQUEST) {\n chunks.push(traceIds.slice(index, index + TRACE_IDS_PER_REQUEST));\n }\n return chunks;\n}\n\nfunction createTraceUsageAccumulator(): TraceUsageAccumulator {\n return {\n estimatedCost: 0,\n hasEstimatedCost: false,\n costUnits: new Set(),\n hasUnknownCostUnit: false,\n };\n}\n\nfunction addBreakdown(accumulators: Map<string, TraceUsageAccumulator>, response: GetMetricBreakdownResponse) {\n for (const group of response.groups) {\n const traceId = group.dimensions.traceId;\n const metricName = group.dimensions.name;\n if (!traceId || (metricName !== INPUT_TOKEN_METRIC && metricName !== OUTPUT_TOKEN_METRIC)) continue;\n\n const accumulator = getOrCreate(accumulators, traceId, createTraceUsageAccumulator);\n const tokenField = metricName === INPUT_TOKEN_METRIC ? 'inputTokens' : 'outputTokens';\n accumulator[tokenField] = (accumulator[tokenField] ?? 0) + group.value;\n\n if (group.estimatedCost == null) continue;\n accumulator.estimatedCost += group.estimatedCost;\n accumulator.hasEstimatedCost = true;\n if (group.costUnit) {\n accumulator.costUnits.add(group.costUnit.toLowerCase());\n } else {\n accumulator.hasUnknownCostUnit = true;\n }\n }\n}\n\nfunction summarizeUsage(accumulators: Map<string, TraceUsageAccumulator>): Map<string, TraceUsageSummary> {\n const summaries = new Map<string, TraceUsageSummary>();\n for (const [traceId, accumulator] of accumulators) {\n const summary: TraceUsageSummary = {\n inputTokens: accumulator.inputTokens,\n outputTokens: accumulator.outputTokens,\n };\n\n if (accumulator.hasEstimatedCost && !accumulator.hasUnknownCostUnit && accumulator.costUnits.size === 1) {\n summary.estimatedCost = accumulator.estimatedCost;\n summary.costUnit = [...accumulator.costUnits][0];\n }\n\n summaries.set(traceId, summary);\n }\n return summaries;\n}\n\nexport function useTraceUsage<TData = Map<string, TraceUsageSummary>>({\n traceIds,\n enabled,\n autoRefetch,\n queryOptions,\n}: {\n traceIds: readonly string[];\n enabled: boolean;\n autoRefetch: boolean;\n queryOptions?: MastraQueryOptions<Map<string, TraceUsageSummary>, TData>;\n}): UseQueryResult<TData, Error> {\n const client = useMastraClient();\n const uniqueTraceIds = [...new Set(traceIds)].toSorted();\n const projectUrl =\n client.options.baseUrl || (typeof window === 'undefined' ? 'local' : window.location.origin || 'local');\n const projectKey = `${projectUrl}:${client.options.apiPrefix ?? '/api'}`;\n\n return useQuery({\n queryKey: ['trace-usage', projectKey, uniqueTraceIds],\n enabled: enabled && uniqueTraceIds.length > 0,\n queryFn: async () => {\n const batches = chunkTraceIds(uniqueTraceIds);\n const responses = await Promise.allSettled(\n batches.map(batch =>\n client.getMetricBreakdown({\n name: [INPUT_TOKEN_METRIC, OUTPUT_TOKEN_METRIC],\n aggregation: 'sum',\n groupBy: ['traceId', 'name'],\n filters: { traceIds: batch },\n limit: batch.length * 2,\n }),\n ),\n );\n\n const accumulators = new Map<string, TraceUsageAccumulator>();\n for (const response of responses) {\n if (response.status === 'fulfilled') {\n addBreakdown(accumulators, response.value);\n }\n }\n return summarizeUsage(accumulators);\n },\n placeholderData: (previousData, previousQuery) =>\n previousQuery?.queryKey[1] === projectKey ? previousData : undefined,\n refetchInterval: enabled && autoRefetch ? 10_000 : false,\n ...queryOptions,\n });\n}\n","import type { MastraClient } from '@mastra/client-js';\nimport type { InfiniteData } from '@tanstack/react-query';\nimport { useInfiniteQuery, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useEffect, useRef, useState } from 'react';\nimport { useMastraClient } from '../../mastra-client-context';\nimport { is403ForbiddenError } from '../query/query-utils';\nimport type { MastraInfiniteQueryOptions, MastraQueryOptions } from '../shared/query-options';\nimport { useInView } from '../shared/use-in-view';\nimport type { TraceListMode } from './types';\n\ntype ListBranchesArgs = NonNullable<Parameters<MastraClient['listBranches']>[0]>;\ntype ListBranchesResponse = Awaited<ReturnType<MastraClient['listBranches']>>;\ntype ListTracesArgs = NonNullable<Parameters<MastraClient['listTraces']>[0]>;\ntype ListTracesLightResponse = Awaited<ReturnType<MastraClient['listTracesLight']>>;\ntype LightSpanRecord = ListTracesLightResponse['spans'][number] | ListBranchesResponse['branches'][number];\n\n/**\n * Per-MastraClient delta-polling support cache. Sticks once we observe a 501\n * or a page-0 response without `deltaCursor` (legacy server or store without\n * delta capability), so we don't re-probe on every mount.\n */\ntype DeltaSupport = 'unknown' | 'unsupported';\nconst deltaSupportByClient = new WeakMap<ReturnType<typeof useMastraClient>, DeltaSupport>();\n\n/**\n * Per-MastraClient light-list support cache. Sticks once the light endpoint is\n * shown not to be served, so every subsequent page fetch, delta poll and periodic\n * refresh uses the full list endpoint instead. Other failures (auth, rate limits,\n * outages) propagate without pinning — they'd hit the full endpoint too.\n */\ntype LightListSupport = 'unknown' | 'unsupported';\nconst lightListSupportByClient = new WeakMap<ReturnType<typeof useMastraClient>, LightListSupport>();\n\n/** When the current run of light-endpoint 500s started, per client. Cleared by any light success. */\nconst lightListFirstServerErrorAtByClient = new WeakMap<ReturnType<typeof useMastraClient>, number>();\n\n/** A 500 is ambiguous — an old core's store throwing, or a transient fault (DB hiccup, timeout).\n * Serve the request from the full endpoint either way, but only pin the session once the 500s\n * have outlasted a blip; a hiccup would otherwise degrade the list until the tab is reloaded.\n * Elapsed time, not a request count: the page refetch, the delta poll and the status refresh can\n * fail in the same instant, and a fallback response still looks like a success to the delta query,\n * so chase mode keeps re-polling every `deltaChaseIntervalMs` throughout the outage. */\nconst LIGHT_LIST_SERVER_ERROR_PIN_AFTER_MS = 10_000;\n\n/** Tunables for live-tail polling. All fields optional — defaults below.\n * Platform consumers override individual fields to throttle traffic or\n * reshape the freshness/visibility trade-offs. */\nexport interface TracesPollingConfig {\n /** Interval between delta polls. Default 5_000ms. */\n deltaPollIntervalMs?: number;\n /** Refetch delay when the server signals `delta.hasMore` (chase remaining updates immediately). Default 100ms. */\n deltaChaseIntervalMs?: number;\n /** Max rows per delta poll. Server caps at 100. Default 100. */\n deltaLimit?: number;\n /** Page-mode refetch interval used when the configured store does not support delta polling. Default 10_000ms. */\n pageModeRefetchIntervalMs?: number;\n /** Periodic page-0 refetch interval while delta is active. Delta only delivers new rows, so this\n * is how we surface status flips (running → success/error) on rows already visible. Default 60_000ms. */\n page0StatusRefreshIntervalMs?: number;\n /** When the tab returns from being hidden and the last successful poll was older than this, the\n * cursor is treated as stale (ClickHouse delta tables TTL after 2 days; other stores may be more\n * aggressive). The infinite query is reset so page 0 refetches and delta resumes from a fresh\n * cursor. Default 900_000ms (15 min). */\n idleGuardThresholdMs?: number;\n /** Minimum visible duration for `isRefetching` after any query completes. On localhost a delta\n * poll can resolve in tens of ms — too brief for the spinner's 1s rotation to register visually,\n * and quick enough that React may batch the start/finish transitions. Pulsing for this duration\n * on completion (~144° of rotation at 400ms) makes each poll perceptible as a heartbeat.\n * Default 400ms. */\n minRefetchSpinMs?: number;\n /** Window during which a delta-arrived row's key stays in `recentlyAddedKeys` so the list view\n * can apply its `animate-row-highlight` class. Should match the CSS animation duration\n * (currently 1_000ms — see `index.css`). Default 1_000ms. */\n deltaHighlightMs?: number;\n}\n\nconst DEFAULT_POLLING_CONFIG: Required<TracesPollingConfig> = {\n deltaPollIntervalMs: 5_000,\n deltaChaseIntervalMs: 100,\n deltaLimit: 100,\n pageModeRefetchIntervalMs: 10_000,\n page0StatusRefreshIntervalMs: 60_000,\n idleGuardThresholdMs: 15 * 60_000,\n minRefetchSpinMs: 400,\n deltaHighlightMs: 1_000,\n};\n\n/** Returns true when the cursor should be considered stale and re-seeded.\n * Exported for testing — pure function of timestamps. */\nexport function shouldResetAfterIdle(lastSuccessAt: number, now: number, thresholdMs: number): boolean {\n if (lastSuccessAt === 0) return false;\n return now - lastSuccessAt > thresholdMs;\n}\n\nfunction isHttp501(error: unknown): boolean {\n return (error as { status?: number } | null)?.status === 501;\n}\n\n/** Only 404 and 500 can mean the light endpoint isn't served: 404 from servers without\n * the route, 500 from cores whose store throws instead of serving the projection.\n * Anything else (401, 403, 429, other 5xx, the 501 disabled-domain signal) is a\n * condition the full endpoint would hit too, so it propagates instead of falling\n * back — mirroring how the delta-support cache matches exactly 501. */\nfunction lightListFallbackStatus(error: unknown): 404 | 500 | undefined {\n const status = (error as { status?: number } | null)?.status;\n return status === 404 || status === 500 ? status : undefined;\n}\n\n/** Whether a failed light-list request should pin the session to the full endpoint.\n * `firstServerErrorAt` is undefined when this 500 opens a new run of them, so a single\n * fault never pins. Exported for testing — pure function of the status and timestamps. */\nexport function shouldPinLightList(\n status: number | undefined,\n firstServerErrorAt: number | undefined,\n now: number,\n): boolean {\n if (status === 404) return true;\n if (status !== 500) return false;\n if (firstServerErrorAt === undefined) return false;\n return now - firstServerErrorAt >= LIGHT_LIST_SERVER_ERROR_PIN_AFTER_MS;\n}\n\ntype FetchTracesFnArgs = TracesFilters & {\n client: ReturnType<typeof useMastraClient>;\n} & ({ mode: 'delta'; after?: string; limit?: number } | { mode?: 'page'; page: number; perPage: number });\n\nconst fetchTracesFn = async (args: FetchTracesFnArgs) => {\n const { client, filters, listMode = 'traces' } = args;\n const params =\n args.mode === 'delta'\n ? { mode: 'delta' as const, after: args.after, limit: args.limit, filters }\n : { pagination: { page: args.page, perPage: args.perPage }, filters };\n\n if (listMode === 'branches') {\n return client.listBranches(params as ListBranchesArgs);\n }\n\n // The list only renders identity, timing, status and a short input preview, so ask\n // for the lightweight projection. Selecting a row fetches the full record separately.\n // Clients pinned to full mode keep using listTraces (page and delta alike), exactly\n // as before the light endpoint existed; full rows are a superset of the light ones.\n if (lightListSupportByClient.get(client) === 'unsupported') {\n return client.listTraces(params as ListTracesArgs);\n }\n try {\n const response = await client.listTracesLight(params as ListTracesArgs);\n // A 200 can still be a legacy projection: servers whose store implements the\n // pre-preview light list answer with rows carrying none of the new fields.\n // Current servers always set `status` on every row, so a non-empty page where\n // every row lacks it is legacy-shaped — pin and refetch the full rows. Empty\n // pages never pin (indistinguishable, and they render identically either way;\n // the next non-empty page decides).\n if (args.mode !== 'delta') {\n const spans = response.spans ?? [];\n if (spans.length > 0 && spans.every(span => span.status === undefined)) {\n lightListSupportByClient.set(client, 'unsupported');\n return client.listTraces(params as ListTracesArgs);\n }\n }\n lightListFirstServerErrorAtByClient.delete(client);\n return response;\n } catch (error) {\n const status = lightListFallbackStatus(error);\n if (status === undefined) throw error;\n\n const now = Date.now();\n const firstServerErrorAt = lightListFirstServerErrorAtByClient.get(client);\n if (status === 500 && firstServerErrorAt === undefined) {\n lightListFirstServerErrorAtByClient.set(client, now);\n }\n if (shouldPinLightList(status, firstServerErrorAt, now)) {\n lightListSupportByClient.set(client, 'unsupported');\n }\n return client.listTraces(params as ListTracesArgs);\n }\n};\n\nexport const TRACES_PER_PAGE = 25;\n\nexport interface TracesFilters {\n filters?: ListTracesArgs['filters'] | ListBranchesArgs['filters'];\n listMode?: TraceListMode;\n}\n\n/** Returns the next page number if the server indicates more pages are available. */\nexport function getTracesNextPageParam(\n lastPage: ListTracesLightResponse | ListBranchesResponse | undefined,\n _allPages: unknown,\n lastPageParam: number,\n) {\n if (lastPage?.pagination?.hasMore) {\n return lastPageParam + 1;\n }\n return undefined;\n}\n\ntype TracesPageResponse = ListTracesLightResponse | ListBranchesResponse;\n\n/** Branch rows are full spans and trace rows are lightweight; the list only reads the\n * fields they share, so both are surfaced as `LightSpanRecord`. */\nfunction getPageSpans(page: TracesPageResponse): LightSpanRecord[] {\n if ('branches' in page) return page.branches ?? [];\n return page.spans ?? [];\n}\n\n/** Deduplicates trace/branch rows by traceId + spanId across all loaded pages.\n * Also surfaces page 0's deltaCursor so the live-tail query can read it reactively. */\nexport function selectUniqueTraces(data: { pages: TracesPageResponse[] }): {\n spans: LightSpanRecord[];\n deltaCursor: string | undefined;\n} {\n const seen = new Set<string>();\n const spans = data.pages\n .flatMap(page => getPageSpans(page))\n .filter(span => {\n const key = `${span.traceId}:${span.spanId}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n return { spans, deltaCursor: data.pages[0]?.deltaCursor };\n}\n\ntype RowIdentity = { traceId: string; spanId?: string | null };\n\nfunction rowKey(row: RowIdentity): string {\n return `${row.traceId}:${row.spanId}`;\n}\n\nfunction indexRowsByKey<TRow extends RowIdentity>(rows: TRow[]): Map<string, TRow> {\n return new Map(rows.map(row => [rowKey(row), row]));\n}\n\n/** Replaces existing page-0 rows in place (keyed by traceId:spanId) with\n * refreshed copies from the server. Rows the server doesn't return are kept\n * as-is so delta-accumulated rows that have aged off the server's page 0\n * aren't dropped from the UI. New rows aren't added here — delta polling\n * delivers those. */\nexport function refreshPage0Rows(\n old: InfiniteData<TracesPageResponse> | undefined,\n refreshed: ListTracesLightResponse | ListBranchesResponse,\n listMode: TraceListMode,\n): InfiniteData<TracesPageResponse> | undefined {\n if (!old || old.pages.length === 0) return old;\n const [firstPage, ...rest] = old.pages;\n if (!firstPage) return old;\n\n // Branch and trace rows have different row shapes, so each mode keys its own map.\n let updatedFirst: TracesPageResponse;\n if (listMode === 'branches' && 'branches' in firstPage && 'branches' in refreshed) {\n const refreshedByKey = indexRowsByKey(refreshed.branches ?? []);\n if (refreshedByKey.size === 0) return old;\n updatedFirst = {\n ...firstPage,\n branches: (firstPage.branches ?? []).map(existing => refreshedByKey.get(rowKey(existing)) ?? existing),\n };\n } else if ('spans' in firstPage && 'spans' in refreshed) {\n const refreshedByKey = indexRowsByKey(refreshed.spans ?? []);\n if (refreshedByKey.size === 0) return old;\n updatedFirst = {\n ...firstPage,\n spans: (firstPage.spans ?? []).map(existing => refreshedByKey.get(rowKey(existing)) ?? existing),\n };\n } else {\n return old;\n }\n\n return { ...old, pages: [updatedFirst, ...rest] };\n}\n\n/** Stable `startedAt DESC` sort matching the server's default page-mode\n * ordering for both list endpoints. Rows missing `startedAt` sink to the\n * bottom (compared as time 0). */\nfunction sortRowsByStartedAtDesc<T extends { startedAt?: unknown }>(rows: T[]): T[] {\n return [...rows].sort((a, b) => {\n const aTime = a.startedAt ? new Date(a.startedAt as string | number | Date).getTime() : 0;\n const bTime = b.startedAt ? new Date(b.startedAt as string | number | Date).getTime() : 0;\n return bTime - aTime;\n });\n}\n\n/** Prepends delta-mode rows into page 0 and advances its deltaCursor.\n * Delta responses come back in server cursor order (insertion order into\n * the per-store delta index), not the `startedAt DESC` order page-mode\n * uses — so we re-sort the merged page 0 to match what the user sees on\n * a fresh page-mode load. Cross-page duplication is handled later by\n * selectUniqueTraces. */\nexport function mergeDeltaIntoPage0(\n old: InfiniteData<TracesPageResponse> | undefined,\n delta: ListTracesLightResponse | ListBranchesResponse,\n listMode: TraceListMode,\n): InfiniteData<TracesPageResponse> | undefined {\n if (!old || old.pages.length === 0) return old;\n const [firstPage, ...rest] = old.pages;\n if (!firstPage) return old;\n const nextCursor = delta.deltaCursor ?? firstPage.deltaCursor;\n\n let updatedFirst: TracesPageResponse;\n if (listMode === 'branches' && 'branches' in firstPage) {\n const newRows = (delta as ListBranchesResponse).branches ?? [];\n updatedFirst = {\n ...firstPage,\n branches: sortRowsByStartedAtDesc([...newRows, ...(firstPage.branches ?? [])]),\n deltaCursor: nextCursor,\n };\n } else if ('spans' in firstPage) {\n const newRows = (delta as ListTracesLightResponse).spans ?? [];\n updatedFirst = {\n ...firstPage,\n spans: sortRowsByStartedAtDesc([...newRows, ...(firstPage.spans ?? [])]),\n deltaCursor: nextCursor,\n };\n } else {\n return old;\n }\n\n return { ...old, pages: [updatedFirst, ...rest] };\n}\n\nexport interface UseTracesArgs extends TracesFilters {\n enabled?: boolean;\n /** Optional overrides for the live-tail polling tunables. Any omitted fields fall back to the\n * built-in defaults; pass only what you want to change. */\n polling?: TracesPollingConfig;\n /** TanStack overrides for each underlying query, spread last. The hook consumes each query's data internally, so `select` must keep the default shape. */\n queryOptions?: {\n traces?: MastraInfiniteQueryOptions<\n TracesPageResponse,\n ReturnType<typeof selectUniqueTraces>,\n readonly ['traces', TraceListMode, TracesFilters['filters']],\n number\n >;\n delta?: MastraQueryOptions<Awaited<ReturnType<typeof fetchTracesFn>> | null>;\n statusRefresh?: MastraQueryOptions<Awaited<ReturnType<typeof fetchTracesFn>>>;\n };\n}\n\ninterface UseTracesReturn {\n data: { spans: LightSpanRecord[]; deltaCursor: string | undefined } | undefined;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n fetchNextPage: () => void;\n isLoading: boolean;\n isError: boolean;\n error: Error | null;\n setEndOfListElement: (node: HTMLDivElement | null) => void;\n isRefetching: boolean;\n autoRefetch: boolean;\n setAutoRefetch: (v: boolean) => void;\n recentlyAddedKeys: Set<string>;\n dataUpdatedAt: number;\n errorUpdatedAt: number;\n isFetching: boolean;\n isSuccess: boolean;\n fetchStatus: 'idle' | 'fetching' | 'paused';\n refetch: () => void;\n}\n\nexport const useTraces: (args: UseTracesArgs) => UseTracesReturn = ({\n filters,\n listMode = 'traces',\n polling = {},\n enabled = true,\n queryOptions,\n}: UseTracesArgs) => {\n const {\n deltaPollIntervalMs = DEFAULT_POLLING_CONFIG.deltaPollIntervalMs,\n deltaChaseIntervalMs = DEFAULT_POLLING_CONFIG.deltaChaseIntervalMs,\n deltaLimit = DEFAULT_POLLING_CONFIG.deltaLimit,\n pageModeRefetchIntervalMs = DEFAULT_POLLING_CONFIG.pageModeRefetchIntervalMs,\n page0StatusRefreshIntervalMs = DEFAULT_POLLING_CONFIG.page0StatusRefreshIntervalMs,\n idleGuardThresholdMs = DEFAULT_POLLING_CONFIG.idleGuardThresholdMs,\n minRefetchSpinMs = DEFAULT_POLLING_CONFIG.minRefetchSpinMs,\n deltaHighlightMs = DEFAULT_POLLING_CONFIG.deltaHighlightMs,\n } = polling;\n const client = useMastraClient();\n const queryClient = useQueryClient();\n const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();\n\n const [deltaSupport, setDeltaSupport] = useState<DeltaSupport>(() => deltaSupportByClient.get(client) ?? 'unknown');\n const deltaUnsupported = deltaSupport === 'unsupported';\n\n // When false, all automatic polling stops: delta polls, status refresh,\n // idle-guard resets, and the page-mode fallback interval. Manual `resync`\n // still works. Session-scoped (no persistence across mounts).\n const [autoRefetch, setAutoRefetch] = useState(true);\n\n // Keys (`traceId:spanId`) of rows that arrived via the most recent delta\n // poll(s). The list view reads this to apply a temporary highlight class\n // for deltaHighlightMs, then they auto-expire. Resets on filter/listMode\n // change since a new query key spawns a fresh list.\n const [recentlyAddedKeys, setRecentlyAddedKeys] = useState<Set<string>>(() => new Set());\n useEffect(() => {\n setRecentlyAddedKeys(new Set());\n }, [listMode, filters]);\n\n const tracesQueryKey = ['traces', listMode, filters] as const;\n\n const query = useInfiniteQuery({\n queryKey: tracesQueryKey,\n enabled,\n queryFn: ({ pageParam }) =>\n fetchTracesFn({\n client,\n page: pageParam,\n perPage: TRACES_PER_PAGE,\n filters,\n listMode,\n }),\n initialPageParam: 0,\n getNextPageParam: getTracesNextPageParam,\n select: selectUniqueTraces,\n retry: false,\n // Disable polling on 403 to prevent flickering.\n // Fall back to page-mode polling only when delta isn't running.\n refetchInterval: q => {\n if (is403ForbiddenError(q.state.error)) return false;\n if (!autoRefetch) return false;\n return deltaUnsupported ? pageModeRefetchIntervalMs : false;\n },\n ...queryOptions?.traces,\n });\n\n const cursor = query.data?.deltaCursor;\n\n // If page 0 came back without a deltaCursor, the server/store doesn't\n // support delta polling. Pin the client to 'unsupported' so the infinite\n // query resumes page-mode polling and we stop probing.\n useEffect(() => {\n if (query.isSuccess && cursor === undefined && deltaSupport === 'unknown') {\n deltaSupportByClient.set(client, 'unsupported');\n setDeltaSupport('unsupported');\n }\n }, [query.isSuccess, cursor, deltaSupport, client]);\n\n const deltaQuery = useQuery({\n queryKey: ['traces-delta', listMode, filters] as const,\n queryFn: () => {\n const current = queryClient.getQueryData<InfiniteData<TracesPageResponse>>(tracesQueryKey)?.pages[0]?.deltaCursor;\n if (!current) return null;\n return fetchTracesFn({\n client,\n mode: 'delta',\n after: current,\n limit: deltaLimit,\n filters,\n listMode,\n });\n },\n enabled: enabled && !!cursor && !deltaUnsupported && autoRefetch,\n retry: false,\n refetchInterval: q => {\n if (q.state.error) return false;\n const data = q.state.data as ListTracesLightResponse | ListBranchesResponse | null | undefined;\n if (data?.delta?.hasMore) return deltaChaseIntervalMs;\n return deltaPollIntervalMs;\n },\n ...queryOptions?.delta,\n });\n\n // Merge new delta rows into the infinite-query cache. Also captures the\n // arrived keys into `recentlyAddedKeys` for deltaHighlightMs so the UI\n // can briefly distinguish them. The cleanup timer is intentionally NOT\n // tied to the effect lifecycle — if a newer delta arrives first, we still\n // want each prior batch to expire on its own schedule.\n useEffect(() => {\n const result = deltaQuery.data;\n if (!result) return;\n queryClient.setQueryData<InfiniteData<TracesPageResponse>>(tracesQueryKey, old =>\n mergeDeltaIntoPage0(old, result, listMode),\n );\n\n const newRows: RowIdentity[] =\n listMode === 'branches' && 'branches' in result\n ? (result.branches ?? [])\n : 'spans' in result\n ? (result.spans ?? [])\n : [];\n if (newRows.length === 0) return;\n const keys = newRows.map(r => `${r.traceId}:${r.spanId ?? ''}`);\n setRecentlyAddedKeys(prev => {\n const next = new Set(prev);\n for (const k of keys) next.add(k);\n return next;\n });\n setTimeout(() => {\n setRecentlyAddedKeys(prev => {\n const next = new Set(prev);\n for (const k of keys) next.delete(k);\n return next;\n });\n }, deltaHighlightMs);\n // tracesQueryKey is a new array each render but its contents drive cache keying;\n // depending on its members (listMode/filters) is enough.\n }, [deltaQuery.data, queryClient, listMode, filters, deltaHighlightMs]);\n\n // A 501 means the server is too old (or store doesn't support delta) — pin\n // 'unsupported' so the delta query disables and page-mode polling resumes.\n useEffect(() => {\n if (isHttp501(deltaQuery.error)) {\n deltaSupportByClient.set(client, 'unsupported');\n setDeltaSupport('unsupported');\n }\n }, [deltaQuery.error, client]);\n\n // Periodic page-0 refresh to surface status updates on visible rows\n // (running → success/error). Only runs while delta is the primary polling\n // mechanism; otherwise the infinite query's own refetchInterval covers it.\n const statusRefreshQuery = useQuery({\n queryKey: ['traces-status-refresh', listMode, filters] as const,\n queryFn: () =>\n fetchTracesFn({\n client,\n page: 0,\n perPage: TRACES_PER_PAGE,\n filters,\n listMode,\n }),\n enabled: enabled && !!cursor && !deltaUnsupported && autoRefetch,\n refetchInterval: page0StatusRefreshIntervalMs,\n refetchOnMount: false,\n retry: false,\n ...queryOptions?.statusRefresh,\n });\n\n useEffect(() => {\n const result = statusRefreshQuery.data;\n if (!result) return;\n queryClient.setQueryData<InfiniteData<TracesPageResponse>>(tracesQueryKey, old =>\n refreshPage0Rows(old, result, listMode),\n );\n }, [statusRefreshQuery.data, queryClient, listMode, filters]);\n\n // Idle guard: when the tab returns from being hidden, check how long it's\n // been since the last successful poll. If past the threshold, reset the\n // infinite query so page 0 refetches and the cursor is re-seeded.\n const lastSuccessAtRef = useRef(0);\n useEffect(() => {\n const ts = Math.max(query.dataUpdatedAt, deltaQuery.dataUpdatedAt, statusRefreshQuery.dataUpdatedAt);\n if (ts > lastSuccessAtRef.current) {\n lastSuccessAtRef.current = ts;\n }\n }, [query.dataUpdatedAt, deltaQuery.dataUpdatedAt, statusRefreshQuery.dataUpdatedAt]);\n\n // Track autoRefetch in a ref so the visibility listener (attached once)\n // reads the current value without needing to re-attach.\n const autoRefetchRef = useRef(autoRefetch);\n useEffect(() => {\n autoRefetchRef.current = enabled && autoRefetch;\n }, [enabled, autoRefetch]);\n\n useEffect(() => {\n const handler = () => {\n if (document.visibilityState !== 'visible') return;\n if (!autoRefetchRef.current) return;\n if (!shouldResetAfterIdle(lastSuccessAtRef.current, Date.now(), idleGuardThresholdMs)) return;\n void queryClient.resetQueries({ queryKey: ['traces', listMode, filters] });\n };\n document.addEventListener('visibilitychange', handler);\n return () => document.removeEventListener('visibilitychange', handler);\n }, [queryClient, listMode, filters, idleGuardThresholdMs]);\n\n const { hasNextPage, isFetchingNextPage, fetchNextPage } = query;\n\n useEffect(() => {\n if (enabled && isEndOfListInView && hasNextPage && !isFetchingNextPage) {\n void fetchNextPage();\n }\n }, [enabled, isEndOfListInView, hasNextPage, isFetchingNextPage, fetchNextPage]);\n\n // `isRefetching` aggregates every active fetch — page-mode (initial, next\n // page, manual resync, idle reset), the 60s page-0 status refresh, AND the\n // delta polls — so a spinner bound to it acts as a heartbeat indicator.\n //\n // Short polls (e.g. delta on localhost) can resolve in tens of ms — too\n // brief for `animate-spin` (1s/rotation) to register visually, and quick\n // enough that React may batch the start/finish transitions so we never\n // even observe `isFetching: true`. So we also watch every query's\n // data/errorUpdatedAt; any advance pulses `isRefetching` true for at least\n // minRefetchSpinMs, which is ~144° of rotation — clearly perceptible.\n const isFetchingAny = query.isFetching || statusRefreshQuery.isFetching || deltaQuery.isFetching;\n const lastActivityAt = Math.max(\n query.dataUpdatedAt,\n query.errorUpdatedAt,\n deltaQuery.dataUpdatedAt,\n deltaQuery.errorUpdatedAt,\n statusRefreshQuery.dataUpdatedAt,\n statusRefreshQuery.errorUpdatedAt,\n );\n const [pulse, setPulse] = useState(false);\n const prevActivityAtRef = useRef(lastActivityAt);\n useEffect(() => {\n if (lastActivityAt > prevActivityAtRef.current) {\n prevActivityAtRef.current = lastActivityAt;\n setPulse(true);\n const t = setTimeout(() => setPulse(false), minRefetchSpinMs);\n return () => clearTimeout(t);\n }\n }, [lastActivityAt, minRefetchSpinMs]);\n const isRefetching = isFetchingAny || pulse;\n\n return {\n ...query,\n setEndOfListElement,\n isRefetching,\n autoRefetch,\n setAutoRefetch,\n recentlyAddedKeys,\n };\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraMutationOptions } from '../shared/query-options';\n\ntype CreateFeedbackResponse = Awaited<ReturnType<MastraClient['createFeedback']>>;\n\ntype UseCreateFeedbackProps = {\n traceId: string;\n spanId?: string;\n queryOptions?: MastraMutationOptions<CreateFeedbackResponse, { text: string }>;\n};\n\n/**\n * Submits a free-text comment as a feedback record, scoped to the trace or to a\n * single span, then invalidates the matching feedback list so it refreshes.\n */\nexport const useCreateFeedback = ({ traceId, spanId, queryOptions }: UseCreateFeedbackProps) => {\n const client = useMastraClient();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ text }: { text: string }) =>\n client.createFeedback({\n feedback: {\n traceId,\n ...(spanId ? { spanId } : {}),\n feedbackType: 'comment',\n feedbackSource: 'user',\n value: text,\n },\n }),\n onSuccess: () =>\n queryClient.invalidateQueries({\n queryKey: spanId ? ['span-feedback', traceId, spanId] : ['trace-feedback', traceId],\n }),\n ...queryOptions,\n });\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraMutationOptions } from '../shared/query-options';\n\ntype DeleteFeedbackResponse = Awaited<ReturnType<MastraClient['deleteFeedback']>>;\n\ntype UseDeleteFeedbackProps = {\n traceId: string;\n spanId?: string;\n queryOptions?: MastraMutationOptions<DeleteFeedbackResponse, { feedbackId: string }>;\n};\n\n/**\n * Deletes a single feedback record by id, then invalidates the matching\n * feedback list (trace- or span-scoped) so it refreshes.\n */\nexport const useDeleteFeedback = ({ traceId, spanId, queryOptions }: UseDeleteFeedbackProps) => {\n const client = useMastraClient();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ feedbackId }: { feedbackId: string }) => client.deleteFeedback({ feedbackIds: [feedbackId] }),\n onSuccess: () =>\n queryClient.invalidateQueries({\n queryKey: spanId ? ['span-feedback', traceId, spanId] : ['trace-feedback', traceId],\n }),\n ...queryOptions,\n });\n};\n","import type { MastraClient } from '@mastra/client-js';\nimport type { UseQueryResult } from '@tanstack/react-query';\nimport { useQuery } from '@tanstack/react-query';\n\nimport { useMastraClient } from '../../mastra-client-context';\nimport { getFeedbackRefetchInterval } from '../feedback/feedback-refetch-interval';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\ntype SpanFeedbackResponse = Awaited<ReturnType<MastraClient['listFeedback']>>;\n\ntype UseSpanFeedbackProps<TData> = {\n traceId?: string;\n spanId?: string;\n page?: number;\n queryOptions?: MastraQueryOptions<SpanFeedbackResponse, TData>;\n};\n\n/**\n * Feedback scoped to a single span. Both identifiers are required: without a `spanId`\n * the query stays disabled rather than falling back to trace-wide feedback.\n *\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useSpanFeedback = <TData = SpanFeedbackResponse,>({\n traceId = '',\n spanId = '',\n page,\n queryOptions,\n}: UseSpanFeedbackProps<TData>): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n const pageNumber = page ?? 0;\n return useQuery({\n // `spanId` must stay in the key, otherwise React Query serves the previously\n // selected span's feedback when switching spans within the same trace.\n queryKey: ['span-feedback', traceId, spanId, pageNumber],\n queryFn: () =>\n client.listFeedback({\n filters: { traceId, spanId },\n pagination: { page: pageNumber, perPage: 10 },\n }),\n refetchInterval: getFeedbackRefetchInterval,\n gcTime: 0,\n staleTime: 0,\n ...queryOptions,\n });\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 { getFeedbackRefetchInterval } from '../feedback/feedback-refetch-interval';\nimport type { MastraQueryOptions } from '../shared/query-options';\n\ntype TraceFeedbackResponse = Awaited<ReturnType<MastraClient['listFeedback']>>;\n\ntype UseTraceFeedbackProps<TData> = {\n traceId?: string;\n page?: number;\n queryOptions?: MastraQueryOptions<TraceFeedbackResponse, TData>;\n};\n\n/** Loads a page of trace-level feedback and stops polling when storage cannot serve feedback. */\n/**\n * Does not guard on empty ids; pass `queryOptions: { enabled }` to skip the fetch.\n */\nexport const useTraceFeedback = <TData = TraceFeedbackResponse,>({\n traceId = '',\n page,\n queryOptions,\n}: UseTraceFeedbackProps<TData>): UseQueryResult<TData, Error> => {\n const client = useMastraClient();\n const pageNumber = page ?? 0;\n return useQuery({\n queryKey: ['trace-feedback', traceId, pageNumber],\n queryFn: () =>\n client.listFeedback({\n filters: { traceId },\n pagination: { page: pageNumber, perPage: 10 },\n }),\n // The API can't express \"spanId is null\", so trace-level records are isolated client-side.\n // Note: this runs after server-side pagination, so a page may hold fewer than `perPage` rows.\n select: data => {\n const feedback = data.feedback.filter(item => !item.spanId);\n if (!data.pagination) return { ...data, feedback } as TData;\n return { ...data, feedback, pagination: { ...data.pagination, total: feedback.length } } as TData;\n },\n refetchInterval: getFeedbackRefetchInterval,\n gcTime: 0,\n staleTime: 0,\n ...queryOptions,\n });\n};\n","import { MastraClientError } from '@mastra/client-js';\nimport type {\n GetTraceQueryFieldsArgs,\n GetTraceQueryFieldsResponse,\n GetTraceQueryValuesArgs,\n MastraClient,\n} from '@mastra/client-js';\nimport { keepPreviousData, useQuery } from '@tanstack/react-query';\nimport { useMemo } from 'react';\n\nimport { useMastraClient } from '../../mastra-client-context';\nimport type { MastraQueryOptions } from '../shared/query-options';\nimport { DISCOVERY_STALE_TIME } from './discovery-cache';\n\nexport type TraceQueryDiscoveryTimeRange = GetTraceQueryFieldsArgs['timeRange'];\n\n/** Lazy value lookup for one discovered field. Structurally compatible with filter bar suggestion resolvers. */\nexport type TraceQueryValuesResolver = (ctx: { query: string; signal: AbortSignal }) => Promise<{ value: string }[]>;\n\nexport type TraceMetadataFilterField = {\n /** `metadata.<key>` — doubles as the filter bar field id. */\n path: string;\n suggestions: TraceQueryValuesResolver;\n};\n\n// Server caps discovery limits at 100 (TRACE_QUERY_DISCOVERY_MAX_LIMIT).\nconst DISCOVERY_LIMIT = 100;\n\nconst EMPTY_FIELDS: GetTraceQueryFieldsResponse = {\n canonicalFields: [],\n observedFields: [],\n observedFieldsTruncated: false,\n};\n\nconst TRACE_QUERY_DISCOVERY_UNSUPPORTED = 'TRACE_QUERY_DISCOVERY_UNSUPPORTED';\n\nconst isDiscoveryUnsupportedError = (error: unknown) =>\n error instanceof MastraClientError &&\n typeof error.body === 'object' &&\n error.body !== null &&\n (error.body as { code?: unknown }).code === TRACE_QUERY_DISCOVERY_UNSUPPORTED;\n\nexport const traceQueryFieldsQueryKey = (timeRange: TraceQueryDiscoveryTimeRange) =>\n ['trace-query-fields', timeRange.from, timeRange.to] as const;\n\n/** Lazy FilterBar suggestions resolver backed by the value-discovery endpoint for one\n * `predicateScope` + `path`. the caller owns debounce/abort; this only fetches. */\nexport const createTraceQueryValuesResolver = (\n client: MastraClient,\n timeRange: TraceQueryDiscoveryTimeRange,\n predicateScope: GetTraceQueryValuesArgs['predicateScope'],\n path: string,\n): TraceQueryValuesResolver => {\n return async ({ query: search, signal }) => {\n const { values } = await client.getTraceQueryValues(\n { timeRange, predicateScope, path, search: search.trim() || undefined, limit: DISCOVERY_LIMIT },\n { signal },\n );\n return values.map(({ value }) => ({ value }));\n };\n};\n\n/**\n * Discovers the `metadata.*` fields observed on traces in the given time range and returns\n * them as filter bar fields, each with a lazy `suggestions` resolver that fetches the field's\n * values when the user opens the value step (the caller owns debounce/abort).\n *\n * Resolves to an empty field list when the server or store does not support discovery\n * (`TRACE_QUERY_DISCOVERY_UNSUPPORTED`) so callers never stay blocked.\n */\nexport const useTraceMetadataFilterFields = ({\n timeRange,\n queryOptions,\n}: {\n timeRange: TraceQueryDiscoveryTimeRange;\n queryOptions?: MastraQueryOptions<GetTraceQueryFieldsResponse>;\n}) => {\n const client = useMastraClient();\n\n const query = useQuery({\n queryKey: traceQueryFieldsQueryKey(timeRange),\n queryFn: async ({ signal }): Promise<GetTraceQueryFieldsResponse> => {\n try {\n return await client.getTraceQueryFields(\n { timeRange, predicateScope: 'trace', limit: DISCOVERY_LIMIT },\n { signal },\n );\n } catch (error) {\n if (isDiscoveryUnsupportedError(error)) return EMPTY_FIELDS;\n throw error;\n }\n },\n retry: false,\n staleTime: DISCOVERY_STALE_TIME,\n // Changing the time range must not tear down the filter bar behind a skeleton;\n // keep the previous field list until the new range resolves.\n placeholderData: keepPreviousData,\n ...queryOptions,\n });\n\n const observedFields = query.data?.observedFields;\n const canonicalFields = query.data?.canonicalFields ?? EMPTY_FIELDS.canonicalFields;\n\n const fields = useMemo<TraceMetadataFilterField[]>(\n () =>\n (observedFields ?? []).map(field => ({\n path: field.path,\n suggestions: createTraceQueryValuesResolver(client, timeRange, 'trace', field.path),\n })),\n [observedFields, client, timeRange],\n );\n\n return { fields, canonicalFields, isLoading: query.isLoading, error: query.error };\n};\n","import { useMastraClient } from '../../mastra-client-context';\n\n/**\n * Storage key for the trace list column preferences, scoped to the Mastra server the client\n * talks to so each project keeps its own column layout.\n */\nexport function useTraceColumnPreferencesStorageKey(): string {\n const client = useMastraClient();\n const projectUrl =\n client.options.baseUrl || (typeof window === 'undefined' ? 'local' : window.location.origin || 'local');\n const apiPrefix = client.options.apiPrefix ?? '/api';\n return `mastra:traces:columns:${projectUrl}:${apiPrefix}`;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/hooks/traces/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,KAAK,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAChF,KAAK,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpE,MAAM,MAAM,eAAe,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AACrE,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAEjD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,CAAC;AAElD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,iBAAiB;oBACrB,OAAO;uBACJ,cAAc;qBAChB,QAAQ;qBACR,eAAe;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/hooks/traces/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,KAAK,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAChF,KAAK,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpE,MAAM,MAAM,eAAe,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AACrE,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAEjD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,CAAC;AAElD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,iBAAiB;oBACrB,OAAO;uBACJ,cAAc;qBAChB,QAAQ;qBACR,eAAe;yBACX,YAAY;CAC0B,CAAC"}
|
|
@@ -77,13 +77,13 @@ declare const fetchTracesFn: (args: FetchTracesFnArgs) => Promise<{
|
|
|
77
77
|
isEvent: boolean;
|
|
78
78
|
startedAt: string;
|
|
79
79
|
parentSpanId?: (string | null) | undefined;
|
|
80
|
-
entityType?: (("agent" | "input_processor" | "input_step_processor" | "mcp_server" | "memory" | "output_processor" | "output_step_processor" | "rag_ingestion" | "scorer" | "tool" | "tool_result_processor" | "trajectory" | "workflow_run" | "workflow_step") | null) | undefined;
|
|
80
|
+
entityType?: (("agent" | "classifier" | "input_processor" | "input_step_processor" | "mcp_server" | "memory" | "output_processor" | "output_step_processor" | "rag_ingestion" | "scorer" | "tool" | "tool_result_processor" | "trajectory" | "workflow_run" | "workflow_step") | null) | undefined;
|
|
81
81
|
entityId?: (string | null) | undefined;
|
|
82
82
|
entityName?: (string | null) | undefined;
|
|
83
|
-
parentEntityType?: (("agent" | "input_processor" | "input_step_processor" | "mcp_server" | "memory" | "output_processor" | "output_step_processor" | "rag_ingestion" | "scorer" | "tool" | "tool_result_processor" | "trajectory" | "workflow_run" | "workflow_step") | null) | undefined;
|
|
83
|
+
parentEntityType?: (("agent" | "classifier" | "input_processor" | "input_step_processor" | "mcp_server" | "memory" | "output_processor" | "output_step_processor" | "rag_ingestion" | "scorer" | "tool" | "tool_result_processor" | "trajectory" | "workflow_run" | "workflow_step") | null) | undefined;
|
|
84
84
|
parentEntityId?: (string | null) | undefined;
|
|
85
85
|
parentEntityName?: (string | null) | undefined;
|
|
86
|
-
rootEntityType?: (("agent" | "input_processor" | "input_step_processor" | "mcp_server" | "memory" | "output_processor" | "output_step_processor" | "rag_ingestion" | "scorer" | "tool" | "tool_result_processor" | "trajectory" | "workflow_run" | "workflow_step") | null) | undefined;
|
|
86
|
+
rootEntityType?: (("agent" | "classifier" | "input_processor" | "input_step_processor" | "mcp_server" | "memory" | "output_processor" | "output_step_processor" | "rag_ingestion" | "scorer" | "tool" | "tool_result_processor" | "trajectory" | "workflow_run" | "workflow_step") | null) | undefined;
|
|
87
87
|
rootEntityId?: (string | null) | undefined;
|
|
88
88
|
rootEntityName?: (string | null) | undefined;
|
|
89
89
|
userId?: (string | null) | undefined;
|
|
@@ -149,7 +149,7 @@ declare const fetchTracesFn: (args: FetchTracesFnArgs) => Promise<{
|
|
|
149
149
|
endedAt?: string | null | undefined;
|
|
150
150
|
error?: (unknown | null) | undefined;
|
|
151
151
|
status?: (('success' | 'error' | 'running') | null) | undefined;
|
|
152
|
-
entityType?: (("agent" | "input_processor" | "input_step_processor" | "mcp_server" | "memory" | "output_processor" | "output_step_processor" | "rag_ingestion" | "scorer" | "tool" | "tool_result_processor" | "trajectory" | "workflow_run" | "workflow_step") | null) | undefined;
|
|
152
|
+
entityType?: (("agent" | "classifier" | "input_processor" | "input_step_processor" | "mcp_server" | "memory" | "output_processor" | "output_step_processor" | "rag_ingestion" | "scorer" | "tool" | "tool_result_processor" | "trajectory" | "workflow_run" | "workflow_step") | null) | undefined;
|
|
153
153
|
entityId?: (string | null) | undefined;
|
|
154
154
|
entityName?: (string | null) | undefined;
|
|
155
155
|
threadId?: ((string | null) | undefined) | null;
|
|
@@ -382,7 +382,10 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
382
382
|
const baseClient = require_mastra_client_context.useMastraClient();
|
|
383
383
|
const [isRunning, setIsRunning] = (0, react.useState)(false);
|
|
384
384
|
const [subscriptionHistory, setSubscriptionHistory] = (0, react.useState)(void 0);
|
|
385
|
+
const [subscriptionPagination, setSubscriptionPagination] = (0, react.useState)(void 0);
|
|
385
386
|
const historyKey = `${agentId}:${resourceId ?? ""}:${threadId ?? ""}`;
|
|
387
|
+
const historyConfigKey = !withInitialHistory ? "" : withInitialHistory === true ? "history" : `history:${withInitialHistory.perPage ?? ""}`;
|
|
388
|
+
const initialHistoryPagination = withInitialHistory && !threadSignalsDisabled && threadId && subscriptionPagination?.key === `${agentId}:${resourceId || agentId}:${threadId}:${streamPath ?? ""}:${historyConfigKey}` ? subscriptionPagination.pagination : void 0;
|
|
386
389
|
const hydratedMessages = withInitialHistory && subscriptionHistory?.key === historyKey ? subscriptionHistory.messages : initialMessages;
|
|
387
390
|
const lastHydration = (0, react.useRef)(void 0);
|
|
388
391
|
(0, react.useEffect)(() => {
|
|
@@ -490,6 +493,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
490
493
|
_threadSubscriptionAbortRef.current = null;
|
|
491
494
|
_threadSubscriptionKeyRef.current = void 0;
|
|
492
495
|
_threadSubscriptionPromiseRef.current = null;
|
|
496
|
+
setSubscriptionPagination(void 0);
|
|
493
497
|
}, []);
|
|
494
498
|
const processStreamChunk = (0, react.useCallback)(async (chunk, onChunk) => {
|
|
495
499
|
const isTerminal = chunk.type === "finish" || chunk.type === "abort" || chunk.type === "error";
|
|
@@ -566,7 +570,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
566
570
|
(onChunk ?? _onChunk.current)?.(chunk);
|
|
567
571
|
}, [onSignalEcho]);
|
|
568
572
|
const ensureThreadSubscription = (0, react.useCallback)(async ({ threadId, resourceId }) => {
|
|
569
|
-
const subscriptionKey = `${agentId}:${resourceId ?? ""}:${threadId}:${streamPath ?? ""}`;
|
|
573
|
+
const subscriptionKey = `${agentId}:${resourceId ?? ""}:${threadId}:${streamPath ?? ""}:${historyConfigKey}`;
|
|
570
574
|
if (_threadSubscriptionKeyRef.current === subscriptionKey && _threadSubscriptionPromiseRef.current) {
|
|
571
575
|
await _threadSubscriptionPromiseRef.current;
|
|
572
576
|
return;
|
|
@@ -581,6 +585,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
581
585
|
_threadSubscriptionAbortRef.current = null;
|
|
582
586
|
_threadSubscriptionKeyRef.current = void 0;
|
|
583
587
|
_threadSubscriptionPromiseRef.current = null;
|
|
588
|
+
setSubscriptionPagination(void 0);
|
|
584
589
|
};
|
|
585
590
|
const subscriptionAgent = new _mastra_client_js.MastraClient({
|
|
586
591
|
...baseClient.options,
|
|
@@ -599,6 +604,13 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
599
604
|
_threadSubscriptionRef.current = subscription;
|
|
600
605
|
subscription.processDataStream({ onChunk: (chunk) => {
|
|
601
606
|
if (chunk.type === "thread-history") {
|
|
607
|
+
if (_threadSubscriptionAbortRef.current === subscriptionAbort) {
|
|
608
|
+
const { hasMore } = chunk.payload;
|
|
609
|
+
setSubscriptionPagination(typeof hasMore === "boolean" ? {
|
|
610
|
+
key: subscriptionKey,
|
|
611
|
+
pagination: { hasMore }
|
|
612
|
+
} : void 0);
|
|
613
|
+
}
|
|
602
614
|
const history = resolveInitialMessages(chunk.payload.messages);
|
|
603
615
|
const previousHistory = lastHydration.current?.formattedMessages ?? [];
|
|
604
616
|
setMessages((current) => mergeHistoryIntoConversation({
|
|
@@ -639,6 +651,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
639
651
|
agentId,
|
|
640
652
|
baseClient,
|
|
641
653
|
closeThreadSubscription,
|
|
654
|
+
historyConfigKey,
|
|
642
655
|
markThreadSignalsUnsupported,
|
|
643
656
|
processStreamChunk,
|
|
644
657
|
streamPath,
|
|
@@ -1229,6 +1242,13 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
1229
1242
|
activeRunId: isRunning || isAwaitingToolApproval ? _currentRunId.current : void 0,
|
|
1230
1243
|
isAwaitingToolApproval,
|
|
1231
1244
|
messages,
|
|
1245
|
+
/**
|
|
1246
|
+
* Pagination of the initial `thread-history` page from `withInitialHistory`:
|
|
1247
|
+
* `hasMore: true` when older messages exist, `false` when the page reached the
|
|
1248
|
+
* start of the thread, and `undefined` while history is disabled, pending, or
|
|
1249
|
+
* the subscription for the current agent/resource/thread/config has ended.
|
|
1250
|
+
*/
|
|
1251
|
+
initialHistoryPagination,
|
|
1232
1252
|
tasks,
|
|
1233
1253
|
approveToolCall,
|
|
1234
1254
|
declineToolCall,
|
|
@@ -1261,4 +1281,4 @@ Object.defineProperty(exports, "useChat", {
|
|
|
1261
1281
|
}
|
|
1262
1282
|
});
|
|
1263
1283
|
|
|
1264
|
-
//# sourceMappingURL=hooks-
|
|
1284
|
+
//# sourceMappingURL=hooks-CIutb3DO.cjs.map
|