@mastra/upstash 0.10.3-alpha.2 → 0.10.3-alpha.3

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.
@@ -15,6 +15,9 @@ import type {
15
15
  EvalRow,
16
16
  WorkflowRuns,
17
17
  WorkflowRun,
18
+ PaginationInfo,
19
+ PaginationArgs,
20
+ StorageGetTracesArg,
18
21
  } from '@mastra/core/storage';
19
22
  import type { WorkflowRunState } from '@mastra/core/workflows';
20
23
  import { Redis } from '@upstash/redis';
@@ -272,82 +275,44 @@ export class UpstashStore extends MastraStorage {
272
275
  }
273
276
  }
274
277
 
275
- public async getTraces(args: {
276
- name?: string;
277
- scope?: string;
278
- attributes?: Record<string, string>;
279
- filters?: Record<string, any>;
280
- page: number;
281
- perPage?: number;
282
- fromDate?: Date;
283
- toDate?: Date;
284
- }): Promise<any[]>;
285
- public async getTraces(args: {
286
- name?: string;
287
- scope?: string;
288
- page: number;
289
- perPage?: number;
290
- attributes?: Record<string, string>;
291
- filters?: Record<string, any>;
292
- fromDate?: Date;
293
- toDate?: Date;
294
- returnPaginationResults: true;
295
- }): Promise<{
296
- traces: any[];
297
- total: number;
298
- page: number;
299
- perPage: number;
300
- hasMore: boolean;
301
- }>;
302
- public async getTraces(args: {
303
- name?: string;
304
- scope?: string;
305
- page: number;
306
- perPage?: number;
307
- attributes?: Record<string, string>;
308
- filters?: Record<string, any>;
309
- fromDate?: Date;
310
- toDate?: Date;
311
- returnPaginationResults?: boolean;
312
- }): Promise<
313
- | any[]
314
- | {
315
- traces: any[];
316
- total: number;
317
- page: number;
318
- perPage: number;
319
- hasMore: boolean;
320
- }
321
- > {
322
- const {
323
- name,
324
- scope,
325
- page,
326
- perPage: perPageInput,
327
- attributes,
328
- filters,
329
- fromDate,
330
- toDate,
331
- returnPaginationResults,
332
- } = args;
278
+ /**
279
+ * @deprecated use getTracesPaginated instead
280
+ */
281
+ public async getTraces(args: StorageGetTracesArg): Promise<any[]> {
282
+ if (args.fromDate || args.toDate) {
283
+ (args as any).dateRange = {
284
+ start: args.fromDate,
285
+ end: args.toDate,
286
+ };
287
+ }
288
+ const { traces } = await this.getTracesPaginated(args);
289
+ return traces;
290
+ }
333
291
 
334
- const perPage = perPageInput !== undefined ? perPageInput : 100;
292
+ public async getTracesPaginated(
293
+ args: {
294
+ name?: string;
295
+ scope?: string;
296
+ attributes?: Record<string, string>;
297
+ filters?: Record<string, any>;
298
+ } & PaginationArgs,
299
+ ): Promise<PaginationInfo & { traces: any[] }> {
300
+ const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
301
+ const fromDate = dateRange?.start;
302
+ const toDate = dateRange?.end;
335
303
 
336
304
  try {
337
305
  const pattern = `${TABLE_TRACES}:*`;
338
306
  const keys = await this.scanKeys(pattern);
339
307
 
340
308
  if (keys.length === 0) {
341
- if (returnPaginationResults) {
342
- return {
343
- traces: [],
344
- total: 0,
345
- page,
346
- perPage: perPage || 100,
347
- hasMore: false,
348
- };
349
- }
350
- return [];
309
+ return {
310
+ traces: [],
311
+ total: 0,
312
+ page,
313
+ perPage: perPage || 100,
314
+ hasMore: false,
315
+ };
351
316
  }
352
317
 
353
318
  const pipeline = this.redis.pipeline();
@@ -414,29 +379,23 @@ export class UpstashStore extends MastraStorage {
414
379
  const end = start + resolvedPerPage;
415
380
  const paginatedTraces = transformedTraces.slice(start, end);
416
381
  const hasMore = end < total;
417
- if (returnPaginationResults) {
418
- return {
419
- traces: paginatedTraces,
420
- total,
421
- page,
422
- perPage: resolvedPerPage,
423
- hasMore,
424
- };
425
- } else {
426
- return paginatedTraces;
427
- }
382
+
383
+ return {
384
+ traces: paginatedTraces,
385
+ total,
386
+ page,
387
+ perPage: resolvedPerPage,
388
+ hasMore,
389
+ };
428
390
  } catch (error) {
429
391
  console.error('Failed to get traces:', error);
430
- if (returnPaginationResults) {
431
- return {
432
- traces: [],
433
- total: 0,
434
- page,
435
- perPage: perPage || 100,
436
- hasMore: false,
437
- };
438
- }
439
- return [];
392
+ return {
393
+ traces: [],
394
+ total: 0,
395
+ page,
396
+ perPage: perPage || 100,
397
+ hasMore: false,
398
+ };
440
399
  }
441
400
  }
442
401
 
@@ -515,44 +474,15 @@ export class UpstashStore extends MastraStorage {
515
474
  };
516
475
  }
517
476
 
518
- async getThreadsByResourceId(args: { resourceId: string }): Promise<StorageThreadType[]>;
519
- async getThreadsByResourceId(args: { resourceId: string; page: number; perPage?: number }): Promise<{
520
- threads: StorageThreadType[];
521
- total: number;
522
- page: number;
523
- perPage: number;
524
- hasMore: boolean;
525
- }>;
526
- async getThreadsByResourceId(args: { resourceId: string; page?: number; perPage?: number }): Promise<
527
- | StorageThreadType[]
528
- | {
529
- threads: StorageThreadType[];
530
- total: number;
531
- page: number;
532
- perPage: number;
533
- hasMore: boolean;
534
- }
535
- > {
536
- const resourceId: string = args.resourceId;
537
- const page: number | undefined = args.page;
538
- // Determine perPage only if page is actually provided. Otherwise, its value is not critical for the non-paginated path.
539
- // If page is provided, perPage defaults to 100 if not specified.
540
- const perPage: number = page !== undefined ? (args.perPage !== undefined ? args.perPage : 100) : 100;
541
-
477
+ /**
478
+ * @deprecated use getThreadsByResourceIdPaginated instead
479
+ */
480
+ async getThreadsByResourceId({ resourceId }: { resourceId: string }): Promise<StorageThreadType[]> {
542
481
  try {
543
482
  const pattern = `${TABLE_THREADS}:*`;
544
483
  const keys = await this.scanKeys(pattern);
545
484
 
546
485
  if (keys.length === 0) {
547
- if (page !== undefined) {
548
- return {
549
- threads: [],
550
- total: 0,
551
- page,
552
- perPage, // perPage is number here
553
- hasMore: false,
554
- };
555
- }
556
486
  return [];
557
487
  }
558
488
 
@@ -574,40 +504,48 @@ export class UpstashStore extends MastraStorage {
574
504
  }
575
505
 
576
506
  allThreads.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
577
-
578
- if (page !== undefined) {
579
- // If page is defined, perPage is also a number (due to the defaulting logic above)
580
- const total = allThreads.length;
581
- const start = page * perPage;
582
- const end = start + perPage;
583
- const paginatedThreads = allThreads.slice(start, end);
584
- const hasMore = end < total;
585
- return {
586
- threads: paginatedThreads,
587
- total,
588
- page,
589
- perPage,
590
- hasMore,
591
- };
592
- } else {
593
- // page is undefined, return all threads
594
- return allThreads;
595
- }
507
+ return allThreads;
596
508
  } catch (error) {
597
509
  console.error('Error in getThreadsByResourceId:', error);
598
- if (page !== undefined) {
599
- return {
600
- threads: [],
601
- total: 0,
602
- page,
603
- perPage, // perPage is number here
604
- hasMore: false,
605
- };
606
- }
607
510
  return [];
608
511
  }
609
512
  }
610
513
 
514
+ public async getThreadsByResourceIdPaginated(
515
+ args: {
516
+ resourceId: string;
517
+ } & PaginationArgs,
518
+ ): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
519
+ const { resourceId, page = 0, perPage = 100 } = args;
520
+
521
+ try {
522
+ const allThreads = await this.getThreadsByResourceId({ resourceId });
523
+
524
+ const total = allThreads.length;
525
+ const start = page * perPage;
526
+ const end = start + perPage;
527
+ const paginatedThreads = allThreads.slice(start, end);
528
+ const hasMore = end < total;
529
+
530
+ return {
531
+ threads: paginatedThreads,
532
+ total,
533
+ page,
534
+ perPage,
535
+ hasMore,
536
+ };
537
+ } catch (error) {
538
+ console.error('Error in getThreadsByResourceIdPaginated:', error);
539
+ return {
540
+ threads: [],
541
+ total: 0,
542
+ page,
543
+ perPage,
544
+ hasMore: false,
545
+ };
546
+ }
547
+ }
548
+
611
549
  async saveThread({ thread }: { thread: StorageThreadType }): Promise<StorageThreadType> {
612
550
  await this.insert({
613
551
  tableName: TABLE_THREADS,
@@ -717,160 +655,13 @@ export class UpstashStore extends MastraStorage {
717
655
  return list.get.all.v1();
718
656
  }
719
657
 
720
- // Function overloads for different return types
721
- public async getMessages(args: StorageGetMessagesArg & { format?: 'v1' }): Promise<MastraMessageV1[]>;
722
- public async getMessages(args: StorageGetMessagesArg & { format: 'v2' }): Promise<MastraMessageV2[]>;
723
- public async getMessages(
724
- args: StorageGetMessagesArg & {
725
- format?: 'v1' | 'v2';
726
- page: number;
727
- perPage?: number;
728
- fromDate?: Date;
729
- toDate?: Date;
730
- },
731
- ): Promise<{
732
- messages: MastraMessageV1[] | MastraMessageV2[];
733
- total: number;
734
- page: number;
735
- perPage: number;
736
- hasMore: boolean;
737
- }>;
738
- public async getMessages({
739
- threadId,
740
- selectBy,
741
- format,
742
- page,
743
- perPage = 40,
744
- fromDate,
745
- toDate,
746
- }: StorageGetMessagesArg & {
747
- format?: 'v1' | 'v2';
748
- page?: number;
749
- perPage?: number;
750
- fromDate?: Date;
751
- toDate?: Date;
752
- }): Promise<
753
- | MastraMessageV1[]
754
- | MastraMessageV2[]
755
- | {
756
- messages: MastraMessageV1[] | MastraMessageV2[];
757
- total: number;
758
- page: number;
759
- perPage: number;
760
- hasMore: boolean;
761
- }
762
- > {
763
- const threadMessagesKey = this.getThreadMessagesKey(threadId);
764
-
765
- const allMessageIds = await this.redis.zrange(threadMessagesKey, 0, -1);
766
- // If pagination is requested, use the new pagination logic
767
- if (page !== undefined) {
768
- try {
769
- // Get all message IDs from the sorted set
770
-
771
- if (allMessageIds.length === 0) {
772
- return {
773
- messages: [],
774
- total: 0,
775
- page,
776
- perPage,
777
- hasMore: false,
778
- };
779
- }
780
-
781
- // Use pipeline to fetch all messages efficiently
782
- const pipeline = this.redis.pipeline();
783
- allMessageIds.forEach(id => pipeline.get(this.getMessageKey(threadId, id as string)));
784
- const results = await pipeline.exec();
785
-
786
- // Process messages and apply filters - handle undefined results from pipeline
787
- let messages = results
788
- .map((result: any) => result as MastraMessageV2 | null)
789
- .filter((msg): msg is MastraMessageV2 => msg !== null) as (MastraMessageV2 & { _index?: number })[];
790
-
791
- // Apply date filters if provided
792
- if (fromDate) {
793
- messages = messages.filter(msg => msg && new Date(msg.createdAt).getTime() >= fromDate.getTime());
794
- }
795
-
796
- if (toDate) {
797
- messages = messages.filter(msg => msg && new Date(msg.createdAt).getTime() <= toDate.getTime());
798
- }
799
-
800
- // Sort messages by their position in the sorted set
801
- messages.sort((a, b) => allMessageIds.indexOf(a!.id) - allMessageIds.indexOf(b!.id));
802
-
803
- const total = messages.length;
804
-
805
- // Apply pagination
806
- const start = page * perPage;
807
- const end = start + perPage;
808
- const hasMore = end < total;
809
- const paginatedMessages = messages.slice(start, end);
810
-
811
- // Remove _index before returning and handle format conversion properly
812
- const prepared = paginatedMessages
813
- .filter(message => message !== null && message !== undefined)
814
- .map(message => {
815
- const { _index, ...messageWithoutIndex } = message as MastraMessageV2 & { _index?: number };
816
- return messageWithoutIndex as unknown as MastraMessageV1;
817
- });
818
-
819
- // Return pagination object with correct format
820
- if (format === 'v2') {
821
- // Convert V1 format back to V2 format
822
- const v2Messages = prepared.map(msg => ({
823
- ...msg,
824
- content: msg.content || { format: 2, parts: [{ type: 'text', text: '' }] },
825
- })) as MastraMessageV2[];
826
-
827
- return {
828
- messages: v2Messages,
829
- total,
830
- page,
831
- perPage,
832
- hasMore,
833
- };
834
- }
835
-
836
- return {
837
- messages: prepared,
838
- total,
839
- page,
840
- perPage,
841
- hasMore,
842
- };
843
- } catch (error) {
844
- console.error('Failed to get paginated messages:', error);
845
- return {
846
- messages: [],
847
- total: 0,
848
- page,
849
- perPage,
850
- hasMore: false,
851
- };
852
- }
853
- }
854
-
855
- // Original logic for backward compatibility
856
- // When selectBy is undefined or selectBy.last is undefined, get ALL messages (not just 40)
857
- let limit: number;
858
- if (typeof selectBy?.last === 'number') {
859
- limit = Math.max(0, selectBy.last);
860
- } else if (selectBy?.last === false) {
861
- limit = 0;
862
- } else {
863
- // No limit specified - get all messages
864
- limit = Number.MAX_SAFE_INTEGER;
865
- }
866
-
658
+ private async _getIncludedMessages(
659
+ threadId: string,
660
+ selectBy: StorageGetMessagesArg['selectBy'],
661
+ ): Promise<MastraMessageV2[] | MastraMessageV1[]> {
867
662
  const messageIds = new Set<string>();
868
663
  const messageIdToThreadIds: Record<string, string> = {};
869
664
 
870
- if (limit === 0 && !selectBy?.include) {
871
- return [];
872
- }
873
-
874
665
  // First, get specifically included messages and their context
875
666
  if (selectBy?.include?.length) {
876
667
  for (const item of selectBy.include) {
@@ -904,6 +695,47 @@ export class UpstashStore extends MastraStorage {
904
695
  });
905
696
  }
906
697
  }
698
+
699
+ const pipeline = this.redis.pipeline();
700
+ Array.from(messageIds).forEach(id => {
701
+ const tId = messageIdToThreadIds[id] || threadId;
702
+ pipeline.get(this.getMessageKey(tId, id as string));
703
+ });
704
+ const results = await pipeline.exec();
705
+ return results.filter(result => result !== null) as MastraMessageV2[] | MastraMessageV1[];
706
+ }
707
+
708
+ return [];
709
+ }
710
+
711
+ /**
712
+ * @deprecated use getMessagesPaginated instead
713
+ */
714
+ public async getMessages(args: StorageGetMessagesArg & { format?: 'v1' }): Promise<MastraMessageV1[]>;
715
+ public async getMessages(args: StorageGetMessagesArg & { format: 'v2' }): Promise<MastraMessageV2[]>;
716
+ public async getMessages({
717
+ threadId,
718
+ selectBy,
719
+ format,
720
+ }: StorageGetMessagesArg & { format?: 'v1' | 'v2' }): Promise<MastraMessageV1[] | MastraMessageV2[]> {
721
+ const threadMessagesKey = this.getThreadMessagesKey(threadId);
722
+ const allMessageIds = await this.redis.zrange(threadMessagesKey, 0, -1);
723
+ // When selectBy is undefined or selectBy.last is undefined, get ALL messages (not just 40)
724
+ let limit: number;
725
+ if (typeof selectBy?.last === 'number') {
726
+ limit = Math.max(0, selectBy.last);
727
+ } else if (selectBy?.last === false) {
728
+ limit = 0;
729
+ } else {
730
+ // No limit specified - get all messages
731
+ limit = Number.MAX_SAFE_INTEGER;
732
+ }
733
+
734
+ const messageIds = new Set<string>();
735
+ const messageIdToThreadIds: Record<string, string> = {};
736
+
737
+ if (limit === 0 && !selectBy?.include) {
738
+ return [];
907
739
  }
908
740
 
909
741
  // Then get the most recent messages (or all if no limit)
@@ -923,24 +755,36 @@ export class UpstashStore extends MastraStorage {
923
755
  });
924
756
  }
925
757
 
758
+ const includedMessages = await this._getIncludedMessages(threadId, selectBy);
759
+
926
760
  // Fetch all needed messages in parallel
927
- const messages = (
928
- await Promise.all(
929
- Array.from(messageIds).map(async id => {
930
- const tId = messageIdToThreadIds[id] || threadId;
931
- const byThreadId = await this.redis.get<MastraMessageV2 & { _index?: number }>(this.getMessageKey(tId, id));
932
- if (byThreadId) return byThreadId;
933
-
934
- return null;
935
- }),
936
- )
937
- ).filter(msg => msg !== null) as (MastraMessageV2 & { _index?: number })[];
761
+ const messages = [
762
+ ...includedMessages,
763
+ ...((
764
+ await Promise.all(
765
+ Array.from(messageIds).map(async id => {
766
+ const tId = messageIdToThreadIds[id] || threadId;
767
+ const byThreadId = await this.redis.get<MastraMessageV2 & { _index?: number }>(this.getMessageKey(tId, id));
768
+ if (byThreadId) return byThreadId;
769
+
770
+ return null;
771
+ }),
772
+ )
773
+ ).filter(msg => msg !== null) as (MastraMessageV2 & { _index?: number })[]),
774
+ ];
938
775
 
939
776
  // Sort messages by their position in the sorted set
940
777
  messages.sort((a, b) => allMessageIds.indexOf(a!.id) - allMessageIds.indexOf(b!.id));
941
778
 
779
+ const seen = new Set<string>();
780
+ const dedupedMessages = messages.filter(row => {
781
+ if (seen.has(row.id)) return false;
782
+ seen.add(row.id);
783
+ return true;
784
+ });
785
+
942
786
  // Remove _index before returning and handle format conversion properly
943
- const prepared = messages
787
+ const prepared = dedupedMessages
944
788
  .filter(message => message !== null && message !== undefined)
945
789
  .map(message => {
946
790
  const { _index, ...messageWithoutIndex } = message as MastraMessageV2 & { _index?: number };
@@ -960,6 +804,89 @@ export class UpstashStore extends MastraStorage {
960
804
  return prepared;
961
805
  }
962
806
 
807
+ public async getMessagesPaginated(
808
+ args: StorageGetMessagesArg & {
809
+ format?: 'v1' | 'v2';
810
+ },
811
+ ): Promise<PaginationInfo & { messages: MastraMessageV1[] | MastraMessageV2[] }> {
812
+ const { threadId, selectBy, format } = args;
813
+ const { page = 0, perPage = 40, dateRange } = selectBy?.pagination || {};
814
+ const fromDate = dateRange?.start;
815
+ const toDate = dateRange?.end;
816
+ const threadMessagesKey = this.getThreadMessagesKey(threadId);
817
+ const messages: (MastraMessageV2 | MastraMessageV1)[] = [];
818
+
819
+ const includedMessages = await this._getIncludedMessages(threadId, selectBy);
820
+ messages.push(...includedMessages);
821
+
822
+ try {
823
+ const allMessageIds = await this.redis.zrange(threadMessagesKey, 0, -1);
824
+ if (allMessageIds.length === 0) {
825
+ return {
826
+ messages: [],
827
+ total: 0,
828
+ page,
829
+ perPage,
830
+ hasMore: false,
831
+ };
832
+ }
833
+
834
+ // Use pipeline to fetch all messages efficiently
835
+ const pipeline = this.redis.pipeline();
836
+ allMessageIds.forEach(id => pipeline.get(this.getMessageKey(threadId, id as string)));
837
+ const results = await pipeline.exec();
838
+
839
+ // Process messages and apply filters - handle undefined results from pipeline
840
+ let messagesData = results.filter((msg): msg is MastraMessageV2 | MastraMessageV1 => msg !== null) as (
841
+ | MastraMessageV2
842
+ | MastraMessageV1
843
+ )[];
844
+
845
+ // Apply date filters if provided
846
+ if (fromDate) {
847
+ messagesData = messagesData.filter(msg => msg && new Date(msg.createdAt).getTime() >= fromDate.getTime());
848
+ }
849
+
850
+ if (toDate) {
851
+ messagesData = messagesData.filter(msg => msg && new Date(msg.createdAt).getTime() <= toDate.getTime());
852
+ }
853
+
854
+ // Sort messages by their position in the sorted set
855
+ messagesData.sort((a, b) => allMessageIds.indexOf(a!.id) - allMessageIds.indexOf(b!.id));
856
+
857
+ const total = messagesData.length;
858
+
859
+ const start = page * perPage;
860
+ const end = start + perPage;
861
+ const hasMore = end < total;
862
+ const paginatedMessages = messagesData.slice(start, end);
863
+
864
+ messages.push(...paginatedMessages);
865
+
866
+ const list = new MessageList().add(messages, 'memory');
867
+ const finalMessages = (format === `v2` ? list.get.all.v2() : list.get.all.v1()) as
868
+ | MastraMessageV1[]
869
+ | MastraMessageV2[];
870
+
871
+ return {
872
+ messages: finalMessages,
873
+ total,
874
+ page,
875
+ perPage,
876
+ hasMore,
877
+ };
878
+ } catch (error) {
879
+ console.error('Failed to get paginated messages:', error);
880
+ return {
881
+ messages: [],
882
+ total: 0,
883
+ page,
884
+ perPage,
885
+ hasMore: false,
886
+ };
887
+ }
888
+ }
889
+
963
890
  async persistWorkflowSnapshot(params: {
964
891
  namespace: string;
965
892
  workflowName: string;
@@ -1006,28 +933,17 @@ export class UpstashStore extends MastraStorage {
1006
933
  * @param options Pagination and filtering options
1007
934
  * @returns Object with evals array and total count
1008
935
  */
1009
- async getEvals(options?: {
1010
- agentName?: string;
1011
- type?: 'test' | 'live';
1012
- page?: number;
1013
- perPage?: number;
1014
- limit?: number;
1015
- offset?: number;
1016
- fromDate?: Date;
1017
- toDate?: Date;
1018
- }): Promise<{
1019
- evals: EvalRow[];
1020
- total: number;
1021
- page?: number;
1022
- perPage?: number;
1023
- hasMore?: boolean;
1024
- }> {
936
+ async getEvals(
937
+ options?: {
938
+ agentName?: string;
939
+ type?: 'test' | 'live';
940
+ } & PaginationArgs,
941
+ ): Promise<PaginationInfo & { evals: EvalRow[] }> {
1025
942
  try {
1026
943
  // Default pagination parameters
1027
- const page = options?.page ?? 0;
1028
- const perPage = options?.perPage ?? 100;
1029
- const limit = options?.limit;
1030
- const offset = options?.offset;
944
+ const { agentName, type, page = 0, perPage = 100, dateRange } = options || {};
945
+ const fromDate = dateRange?.start;
946
+ const toDate = dateRange?.end;
1031
947
 
1032
948
  // Get all keys that match the evals table pattern using cursor-based scanning
1033
949
  const pattern = `${TABLE_EVALS}:*`;
@@ -1038,8 +954,8 @@ export class UpstashStore extends MastraStorage {
1038
954
  return {
1039
955
  evals: [],
1040
956
  total: 0,
1041
- page: options?.page ?? 0,
1042
- perPage: options?.perPage ?? 100,
957
+ page,
958
+ perPage,
1043
959
  hasMore: false,
1044
960
  };
1045
961
  }
@@ -1055,12 +971,12 @@ export class UpstashStore extends MastraStorage {
1055
971
  .filter((record): record is Record<string, any> => record !== null && typeof record === 'object');
1056
972
 
1057
973
  // Apply agent name filter if provided
1058
- if (options?.agentName) {
1059
- filteredEvals = filteredEvals.filter(record => record.agent_name === options.agentName);
974
+ if (agentName) {
975
+ filteredEvals = filteredEvals.filter(record => record.agent_name === agentName);
1060
976
  }
1061
977
 
1062
978
  // Apply type filter if provided
1063
- if (options?.type === 'test') {
979
+ if (type === 'test') {
1064
980
  filteredEvals = filteredEvals.filter(record => {
1065
981
  if (!record.test_info) return false;
1066
982
 
@@ -1074,7 +990,7 @@ export class UpstashStore extends MastraStorage {
1074
990
  return false;
1075
991
  }
1076
992
  });
1077
- } else if (options?.type === 'live') {
993
+ } else if (type === 'live') {
1078
994
  filteredEvals = filteredEvals.filter(record => {
1079
995
  if (!record.test_info) return true;
1080
996
 
@@ -1091,17 +1007,17 @@ export class UpstashStore extends MastraStorage {
1091
1007
  }
1092
1008
 
1093
1009
  // Apply date filters if provided
1094
- if (options?.fromDate) {
1010
+ if (fromDate) {
1095
1011
  filteredEvals = filteredEvals.filter(record => {
1096
1012
  const createdAt = new Date(record.created_at || record.createdAt || 0);
1097
- return createdAt.getTime() >= options.fromDate!.getTime();
1013
+ return createdAt.getTime() >= fromDate.getTime();
1098
1014
  });
1099
1015
  }
1100
1016
 
1101
- if (options?.toDate) {
1017
+ if (toDate) {
1102
1018
  filteredEvals = filteredEvals.filter(record => {
1103
1019
  const createdAt = new Date(record.created_at || record.createdAt || 0);
1104
- return createdAt.getTime() <= options.toDate!.getTime();
1020
+ return createdAt.getTime() <= toDate.getTime();
1105
1021
  });
1106
1022
  }
1107
1023
 
@@ -1114,21 +1030,11 @@ export class UpstashStore extends MastraStorage {
1114
1030
 
1115
1031
  const total = filteredEvals.length;
1116
1032
 
1117
- // Apply pagination - support both page/perPage and limit/offset patterns
1118
- let paginatedEvals: Record<string, any>[];
1119
- let hasMore = false;
1120
-
1121
- if (limit !== undefined && offset !== undefined) {
1122
- // Offset-based pagination
1123
- paginatedEvals = filteredEvals.slice(offset, offset + limit);
1124
- hasMore = offset + limit < total;
1125
- } else {
1126
- // Page-based pagination
1127
- const start = page * perPage;
1128
- const end = start + perPage;
1129
- paginatedEvals = filteredEvals.slice(start, end);
1130
- hasMore = end < total;
1131
- }
1033
+ // Apply pagination
1034
+ const start = page * perPage;
1035
+ const end = start + perPage;
1036
+ const paginatedEvals = filteredEvals.slice(start, end);
1037
+ const hasMore = end < total;
1132
1038
 
1133
1039
  // Transform to EvalRow format
1134
1040
  const evals = paginatedEvals.map(record => this.transformEvalRecord(record));
@@ -1136,17 +1042,18 @@ export class UpstashStore extends MastraStorage {
1136
1042
  return {
1137
1043
  evals,
1138
1044
  total,
1139
- page: limit !== undefined ? undefined : page,
1140
- perPage: limit !== undefined ? undefined : perPage,
1045
+ page,
1046
+ perPage,
1141
1047
  hasMore,
1142
1048
  };
1143
1049
  } catch (error) {
1050
+ const { page = 0, perPage = 100 } = options || {};
1144
1051
  console.error('Failed to get evals:', error);
1145
1052
  return {
1146
1053
  evals: [],
1147
1054
  total: 0,
1148
- page: options?.page ?? 0,
1149
- perPage: options?.perPage ?? 100,
1055
+ page,
1056
+ perPage,
1150
1057
  hasMore: false,
1151
1058
  };
1152
1059
  }