@mastra/lance 0.2.10 → 0.2.11-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/package.json +17 -4
- package/.turbo/turbo-build.log +0 -4
- package/eslint.config.js +0 -6
- package/src/index.ts +0 -2
- package/src/storage/domains/legacy-evals/index.ts +0 -156
- package/src/storage/domains/memory/index.ts +0 -1000
- package/src/storage/domains/operations/index.ts +0 -489
- package/src/storage/domains/scores/index.ts +0 -243
- package/src/storage/domains/traces/index.ts +0 -212
- package/src/storage/domains/utils.ts +0 -158
- package/src/storage/domains/workflows/index.ts +0 -245
- package/src/storage/index.test.ts +0 -10
- package/src/storage/index.ts +0 -494
- package/src/vector/filter.test.ts +0 -295
- package/src/vector/filter.ts +0 -443
- package/src/vector/index.test.ts +0 -1493
- package/src/vector/index.ts +0 -941
- package/src/vector/types.ts +0 -16
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -5
- package/tsup.config.ts +0 -17
- package/vitest.config.ts +0 -11
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import type { Connection } from '@lancedb/lancedb';
|
|
2
|
-
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
3
|
-
import type { ScoreRowData, ScoringSource } from '@mastra/core/scores';
|
|
4
|
-
import { ScoresStorage, TABLE_SCORERS } from '@mastra/core/storage';
|
|
5
|
-
import type { PaginationInfo, StoragePagination } from '@mastra/core/storage';
|
|
6
|
-
import { getTableSchema, processResultWithTypeConversion } from '../utils';
|
|
7
|
-
|
|
8
|
-
export class StoreScoresLance extends ScoresStorage {
|
|
9
|
-
private client: Connection;
|
|
10
|
-
constructor({ client }: { client: Connection }) {
|
|
11
|
-
super();
|
|
12
|
-
this.client = client;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async saveScore(score: ScoreRowData): Promise<{ score: ScoreRowData }> {
|
|
16
|
-
try {
|
|
17
|
-
const id = crypto.randomUUID();
|
|
18
|
-
const table = await this.client.openTable(TABLE_SCORERS);
|
|
19
|
-
// Fetch schema fields for mastra_scorers
|
|
20
|
-
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
21
|
-
const allowedFields = new Set(schema.fields.map((f: any) => f.name));
|
|
22
|
-
// Filter out fields not in schema
|
|
23
|
-
const filteredScore: Record<string, any> = {};
|
|
24
|
-
(Object.keys(score) as (keyof ScoreRowData)[]).forEach(key => {
|
|
25
|
-
if (allowedFields.has(key)) {
|
|
26
|
-
filteredScore[key] = score[key];
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
// Convert any object fields to JSON strings for storage
|
|
30
|
-
for (const key in filteredScore) {
|
|
31
|
-
if (
|
|
32
|
-
filteredScore[key] !== null &&
|
|
33
|
-
typeof filteredScore[key] === 'object' &&
|
|
34
|
-
!(filteredScore[key] instanceof Date)
|
|
35
|
-
) {
|
|
36
|
-
filteredScore[key] = JSON.stringify(filteredScore[key]);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
filteredScore.id = id;
|
|
41
|
-
await table.add([filteredScore], { mode: 'append' });
|
|
42
|
-
return { score };
|
|
43
|
-
} catch (error: any) {
|
|
44
|
-
throw new MastraError(
|
|
45
|
-
{
|
|
46
|
-
id: 'LANCE_STORAGE_SAVE_SCORE_FAILED',
|
|
47
|
-
text: 'Failed to save score in LanceStorage',
|
|
48
|
-
domain: ErrorDomain.STORAGE,
|
|
49
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
50
|
-
details: { error: error?.message },
|
|
51
|
-
},
|
|
52
|
-
error,
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async getScoreById({ id }: { id: string }): Promise<ScoreRowData | null> {
|
|
58
|
-
try {
|
|
59
|
-
const table = await this.client.openTable(TABLE_SCORERS);
|
|
60
|
-
|
|
61
|
-
const query = table.query().where(`id = '${id}'`).limit(1);
|
|
62
|
-
|
|
63
|
-
const records = await query.toArray();
|
|
64
|
-
|
|
65
|
-
if (records.length === 0) return null;
|
|
66
|
-
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
67
|
-
return processResultWithTypeConversion(records[0], schema) as ScoreRowData;
|
|
68
|
-
} catch (error: any) {
|
|
69
|
-
throw new MastraError(
|
|
70
|
-
{
|
|
71
|
-
id: 'LANCE_STORAGE_GET_SCORE_BY_ID_FAILED',
|
|
72
|
-
text: 'Failed to get score by id in LanceStorage',
|
|
73
|
-
domain: ErrorDomain.STORAGE,
|
|
74
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
75
|
-
details: { error: error?.message },
|
|
76
|
-
},
|
|
77
|
-
error,
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async getScoresByScorerId({
|
|
83
|
-
scorerId,
|
|
84
|
-
pagination,
|
|
85
|
-
entityId,
|
|
86
|
-
entityType,
|
|
87
|
-
source,
|
|
88
|
-
}: {
|
|
89
|
-
scorerId: string;
|
|
90
|
-
pagination: StoragePagination;
|
|
91
|
-
entityId?: string;
|
|
92
|
-
entityType?: string;
|
|
93
|
-
source?: ScoringSource;
|
|
94
|
-
}): Promise<{ pagination: PaginationInfo; scores: ScoreRowData[] }> {
|
|
95
|
-
try {
|
|
96
|
-
const table = await this.client.openTable(TABLE_SCORERS);
|
|
97
|
-
// Use zero-based pagination (default page = 0)
|
|
98
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
99
|
-
const offset = page * perPage;
|
|
100
|
-
|
|
101
|
-
let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
102
|
-
|
|
103
|
-
if (source) {
|
|
104
|
-
query = query.where(`\`source\` = '${source}'`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (entityId) {
|
|
108
|
-
query = query.where(`\`entityId\` = '${entityId}'`);
|
|
109
|
-
}
|
|
110
|
-
if (entityType) {
|
|
111
|
-
query = query.where(`\`entityType\` = '${entityType}'`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
query = query.limit(perPage);
|
|
115
|
-
if (offset > 0) query.offset(offset);
|
|
116
|
-
const records = await query.toArray();
|
|
117
|
-
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
118
|
-
const scores = processResultWithTypeConversion(records, schema) as ScoreRowData[];
|
|
119
|
-
|
|
120
|
-
let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
121
|
-
if (source) {
|
|
122
|
-
totalQuery = totalQuery.where(`\`source\` = '${source}'`);
|
|
123
|
-
}
|
|
124
|
-
const allRecords = await totalQuery.toArray();
|
|
125
|
-
const total = allRecords.length;
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
pagination: {
|
|
129
|
-
page,
|
|
130
|
-
perPage,
|
|
131
|
-
total,
|
|
132
|
-
hasMore: offset + scores.length < total,
|
|
133
|
-
},
|
|
134
|
-
scores,
|
|
135
|
-
};
|
|
136
|
-
} catch (error: any) {
|
|
137
|
-
throw new MastraError(
|
|
138
|
-
{
|
|
139
|
-
id: 'LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED',
|
|
140
|
-
text: 'Failed to get scores by scorerId in LanceStorage',
|
|
141
|
-
domain: ErrorDomain.STORAGE,
|
|
142
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
143
|
-
details: { error: error?.message },
|
|
144
|
-
},
|
|
145
|
-
error,
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async getScoresByRunId({
|
|
151
|
-
runId,
|
|
152
|
-
pagination,
|
|
153
|
-
}: {
|
|
154
|
-
runId: string;
|
|
155
|
-
pagination: StoragePagination;
|
|
156
|
-
}): Promise<{ pagination: PaginationInfo; scores: ScoreRowData[] }> {
|
|
157
|
-
try {
|
|
158
|
-
const table = await this.client.openTable(TABLE_SCORERS);
|
|
159
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
160
|
-
const offset = page * perPage;
|
|
161
|
-
// Query for scores with the given runId
|
|
162
|
-
const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
|
|
163
|
-
if (offset > 0) query.offset(offset);
|
|
164
|
-
const records = await query.toArray();
|
|
165
|
-
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
166
|
-
const scores = processResultWithTypeConversion(records, schema) as ScoreRowData[];
|
|
167
|
-
// Get total count for pagination
|
|
168
|
-
const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
|
|
169
|
-
const total = allRecords.length;
|
|
170
|
-
return {
|
|
171
|
-
pagination: {
|
|
172
|
-
page,
|
|
173
|
-
perPage,
|
|
174
|
-
total,
|
|
175
|
-
hasMore: offset + scores.length < total,
|
|
176
|
-
},
|
|
177
|
-
scores,
|
|
178
|
-
};
|
|
179
|
-
} catch (error: any) {
|
|
180
|
-
throw new MastraError(
|
|
181
|
-
{
|
|
182
|
-
id: 'LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED',
|
|
183
|
-
text: 'Failed to get scores by runId in LanceStorage',
|
|
184
|
-
domain: ErrorDomain.STORAGE,
|
|
185
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
186
|
-
details: { error: error?.message },
|
|
187
|
-
},
|
|
188
|
-
error,
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async getScoresByEntityId({
|
|
194
|
-
entityId,
|
|
195
|
-
entityType,
|
|
196
|
-
pagination,
|
|
197
|
-
}: {
|
|
198
|
-
pagination: StoragePagination;
|
|
199
|
-
entityId: string;
|
|
200
|
-
entityType: string;
|
|
201
|
-
}): Promise<{ pagination: PaginationInfo; scores: ScoreRowData[] }> {
|
|
202
|
-
try {
|
|
203
|
-
const table = await this.client.openTable(TABLE_SCORERS);
|
|
204
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
205
|
-
const offset = page * perPage;
|
|
206
|
-
// Query for scores with the given entityId and entityType
|
|
207
|
-
const query = table
|
|
208
|
-
.query()
|
|
209
|
-
.where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`)
|
|
210
|
-
.limit(perPage);
|
|
211
|
-
if (offset > 0) query.offset(offset);
|
|
212
|
-
const records = await query.toArray();
|
|
213
|
-
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
214
|
-
const scores = processResultWithTypeConversion(records, schema) as ScoreRowData[];
|
|
215
|
-
// Get total count for pagination
|
|
216
|
-
const allRecords = await table
|
|
217
|
-
.query()
|
|
218
|
-
.where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`)
|
|
219
|
-
.toArray();
|
|
220
|
-
const total = allRecords.length;
|
|
221
|
-
return {
|
|
222
|
-
pagination: {
|
|
223
|
-
page,
|
|
224
|
-
perPage,
|
|
225
|
-
total,
|
|
226
|
-
hasMore: offset + scores.length < total,
|
|
227
|
-
},
|
|
228
|
-
scores,
|
|
229
|
-
};
|
|
230
|
-
} catch (error: any) {
|
|
231
|
-
throw new MastraError(
|
|
232
|
-
{
|
|
233
|
-
id: 'LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED',
|
|
234
|
-
text: 'Failed to get scores by entityId and entityType in LanceStorage',
|
|
235
|
-
domain: ErrorDomain.STORAGE,
|
|
236
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
237
|
-
details: { error: error?.message },
|
|
238
|
-
},
|
|
239
|
-
error,
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import type { Connection } from '@lancedb/lancedb';
|
|
2
|
-
import { MastraError, ErrorDomain, ErrorCategory } from '@mastra/core/error';
|
|
3
|
-
import type { TraceType } from '@mastra/core/memory';
|
|
4
|
-
import { TABLE_TRACES, TracesStorage } from '@mastra/core/storage';
|
|
5
|
-
import type { PaginationInfo, StorageGetTracesPaginatedArg } from '@mastra/core/storage';
|
|
6
|
-
import type { Trace } from '@mastra/core/telemetry';
|
|
7
|
-
import type { StoreOperationsLance } from '../operations';
|
|
8
|
-
|
|
9
|
-
export class StoreTracesLance extends TracesStorage {
|
|
10
|
-
private client: Connection;
|
|
11
|
-
private operations: StoreOperationsLance;
|
|
12
|
-
constructor({ client, operations }: { client: Connection; operations: StoreOperationsLance }) {
|
|
13
|
-
super();
|
|
14
|
-
this.client = client;
|
|
15
|
-
this.operations = operations;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async saveTrace({ trace }: { trace: TraceType }): Promise<TraceType> {
|
|
19
|
-
try {
|
|
20
|
-
const table = await this.client.openTable(TABLE_TRACES);
|
|
21
|
-
const record = {
|
|
22
|
-
...trace,
|
|
23
|
-
attributes: JSON.stringify(trace.attributes),
|
|
24
|
-
status: JSON.stringify(trace.status),
|
|
25
|
-
events: JSON.stringify(trace.events),
|
|
26
|
-
links: JSON.stringify(trace.links),
|
|
27
|
-
other: JSON.stringify(trace.other),
|
|
28
|
-
};
|
|
29
|
-
await table.add([record], { mode: 'append' });
|
|
30
|
-
return trace;
|
|
31
|
-
} catch (error: any) {
|
|
32
|
-
throw new MastraError(
|
|
33
|
-
{
|
|
34
|
-
id: 'LANCE_STORE_SAVE_TRACE_FAILED',
|
|
35
|
-
domain: ErrorDomain.STORAGE,
|
|
36
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
37
|
-
},
|
|
38
|
-
error,
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async getTraceById({ traceId }: { traceId: string }): Promise<TraceType> {
|
|
44
|
-
try {
|
|
45
|
-
const table = await this.client.openTable(TABLE_TRACES);
|
|
46
|
-
const query = table.query().where(`id = '${traceId}'`);
|
|
47
|
-
const records = await query.toArray();
|
|
48
|
-
return records[0] as TraceType;
|
|
49
|
-
} catch (error: any) {
|
|
50
|
-
throw new MastraError(
|
|
51
|
-
{
|
|
52
|
-
id: 'LANCE_STORE_GET_TRACE_BY_ID_FAILED',
|
|
53
|
-
domain: ErrorDomain.STORAGE,
|
|
54
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
55
|
-
},
|
|
56
|
-
error,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async getTraces({
|
|
62
|
-
name,
|
|
63
|
-
scope,
|
|
64
|
-
page = 1,
|
|
65
|
-
perPage = 10,
|
|
66
|
-
attributes,
|
|
67
|
-
}: {
|
|
68
|
-
name?: string;
|
|
69
|
-
scope?: string;
|
|
70
|
-
page: number;
|
|
71
|
-
perPage: number;
|
|
72
|
-
attributes?: Record<string, string>;
|
|
73
|
-
}): Promise<Trace[]> {
|
|
74
|
-
try {
|
|
75
|
-
const table = await this.client.openTable(TABLE_TRACES);
|
|
76
|
-
const query = table.query();
|
|
77
|
-
if (name) {
|
|
78
|
-
query.where(`name = '${name}'`);
|
|
79
|
-
}
|
|
80
|
-
if (scope) {
|
|
81
|
-
query.where(`scope = '${scope}'`);
|
|
82
|
-
}
|
|
83
|
-
if (attributes) {
|
|
84
|
-
query.where(`attributes = '${JSON.stringify(attributes)}'`);
|
|
85
|
-
}
|
|
86
|
-
// Calculate offset based on page and perPage
|
|
87
|
-
const offset = (page - 1) * perPage;
|
|
88
|
-
query.limit(perPage);
|
|
89
|
-
if (offset > 0) {
|
|
90
|
-
query.offset(offset);
|
|
91
|
-
}
|
|
92
|
-
const records = await query.toArray();
|
|
93
|
-
return records.map(record => {
|
|
94
|
-
const processed = {
|
|
95
|
-
...record,
|
|
96
|
-
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
97
|
-
status: record.status ? JSON.parse(record.status) : {},
|
|
98
|
-
events: record.events ? JSON.parse(record.events) : [],
|
|
99
|
-
links: record.links ? JSON.parse(record.links) : [],
|
|
100
|
-
other: record.other ? JSON.parse(record.other) : {},
|
|
101
|
-
startTime: new Date(record.startTime),
|
|
102
|
-
endTime: new Date(record.endTime),
|
|
103
|
-
createdAt: new Date(record.createdAt),
|
|
104
|
-
};
|
|
105
|
-
if (processed.parentSpanId === null || processed.parentSpanId === undefined) {
|
|
106
|
-
processed.parentSpanId = '';
|
|
107
|
-
} else {
|
|
108
|
-
processed.parentSpanId = String(processed.parentSpanId);
|
|
109
|
-
}
|
|
110
|
-
return processed as Trace;
|
|
111
|
-
});
|
|
112
|
-
} catch (error: any) {
|
|
113
|
-
throw new MastraError(
|
|
114
|
-
{
|
|
115
|
-
id: 'LANCE_STORE_GET_TRACES_FAILED',
|
|
116
|
-
domain: ErrorDomain.STORAGE,
|
|
117
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
118
|
-
details: { name: name ?? '', scope: scope ?? '' },
|
|
119
|
-
},
|
|
120
|
-
error,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async getTracesPaginated(args: StorageGetTracesPaginatedArg): Promise<PaginationInfo & { traces: Trace[] }> {
|
|
126
|
-
try {
|
|
127
|
-
const table = await this.client.openTable(TABLE_TRACES);
|
|
128
|
-
const query = table.query();
|
|
129
|
-
const conditions: string[] = [];
|
|
130
|
-
if (args.name) {
|
|
131
|
-
conditions.push(`name = '${args.name}'`);
|
|
132
|
-
}
|
|
133
|
-
if (args.scope) {
|
|
134
|
-
conditions.push(`scope = '${args.scope}'`);
|
|
135
|
-
}
|
|
136
|
-
if (args.attributes) {
|
|
137
|
-
const attributesStr = JSON.stringify(args.attributes);
|
|
138
|
-
conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
|
|
139
|
-
}
|
|
140
|
-
if (args.dateRange?.start) {
|
|
141
|
-
conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
|
|
142
|
-
}
|
|
143
|
-
if (args.dateRange?.end) {
|
|
144
|
-
conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
|
|
145
|
-
}
|
|
146
|
-
if (conditions.length > 0) {
|
|
147
|
-
const whereClause = conditions.join(' AND ');
|
|
148
|
-
query.where(whereClause);
|
|
149
|
-
}
|
|
150
|
-
let total = 0;
|
|
151
|
-
if (conditions.length > 0) {
|
|
152
|
-
const countQuery = table.query().where(conditions.join(' AND '));
|
|
153
|
-
const allRecords = await countQuery.toArray();
|
|
154
|
-
total = allRecords.length;
|
|
155
|
-
} else {
|
|
156
|
-
total = await table.countRows();
|
|
157
|
-
}
|
|
158
|
-
const page = args.page || 0;
|
|
159
|
-
const perPage = args.perPage || 10;
|
|
160
|
-
const offset = page * perPage;
|
|
161
|
-
query.limit(perPage);
|
|
162
|
-
if (offset > 0) {
|
|
163
|
-
query.offset(offset);
|
|
164
|
-
}
|
|
165
|
-
const records = await query.toArray();
|
|
166
|
-
const traces = records.map(record => {
|
|
167
|
-
const processed = {
|
|
168
|
-
...record,
|
|
169
|
-
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
170
|
-
status: record.status ? JSON.parse(record.status) : {},
|
|
171
|
-
events: record.events ? JSON.parse(record.events) : [],
|
|
172
|
-
links: record.links ? JSON.parse(record.links) : [],
|
|
173
|
-
other: record.other ? JSON.parse(record.other) : {},
|
|
174
|
-
startTime: new Date(record.startTime),
|
|
175
|
-
endTime: new Date(record.endTime),
|
|
176
|
-
createdAt: new Date(record.createdAt),
|
|
177
|
-
};
|
|
178
|
-
if (processed.parentSpanId === null || processed.parentSpanId === undefined) {
|
|
179
|
-
processed.parentSpanId = '';
|
|
180
|
-
} else {
|
|
181
|
-
processed.parentSpanId = String(processed.parentSpanId);
|
|
182
|
-
}
|
|
183
|
-
return processed as Trace;
|
|
184
|
-
});
|
|
185
|
-
return {
|
|
186
|
-
traces,
|
|
187
|
-
total,
|
|
188
|
-
page,
|
|
189
|
-
perPage,
|
|
190
|
-
hasMore: total > (page + 1) * perPage,
|
|
191
|
-
};
|
|
192
|
-
} catch (error: any) {
|
|
193
|
-
throw new MastraError(
|
|
194
|
-
{
|
|
195
|
-
id: 'LANCE_STORE_GET_TRACES_PAGINATED_FAILED',
|
|
196
|
-
domain: ErrorDomain.STORAGE,
|
|
197
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
198
|
-
details: { name: args.name ?? '', scope: args.scope ?? '' },
|
|
199
|
-
},
|
|
200
|
-
error,
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async batchTraceInsert({ records }: { records: Record<string, any>[] }): Promise<void> {
|
|
206
|
-
this.logger.debug('Batch inserting traces', { count: records.length });
|
|
207
|
-
await this.operations.batchInsert({
|
|
208
|
-
tableName: TABLE_TRACES,
|
|
209
|
-
records,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import type { Connection, FieldLike, SchemaLike } from '@lancedb/lancedb';
|
|
2
|
-
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
3
|
-
import { TABLE_EVALS, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
|
|
4
|
-
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
5
|
-
|
|
6
|
-
export function getPrimaryKeys(tableName: TABLE_NAMES): string[] {
|
|
7
|
-
let primaryId: string[] = ['id'];
|
|
8
|
-
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
9
|
-
primaryId = ['workflow_name', 'run_id'];
|
|
10
|
-
} else if (tableName === TABLE_EVALS) {
|
|
11
|
-
primaryId = ['agent_name', 'metric_name', 'run_id'];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return primaryId;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function validateKeyTypes(keys: Record<string, any>, tableSchema: SchemaLike): void {
|
|
18
|
-
// Create a map of field names to their expected types
|
|
19
|
-
const fieldTypes = new Map(
|
|
20
|
-
tableSchema.fields.map((field: any) => [field.name, field.type?.toString().toLowerCase()]),
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
for (const [key, value] of Object.entries(keys)) {
|
|
24
|
-
const fieldType = fieldTypes.get(key);
|
|
25
|
-
|
|
26
|
-
if (!fieldType) {
|
|
27
|
-
throw new Error(`Field '${key}' does not exist in table schema`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Type validation
|
|
31
|
-
if (value !== null) {
|
|
32
|
-
if ((fieldType.includes('int') || fieldType.includes('bigint')) && typeof value !== 'number') {
|
|
33
|
-
throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (fieldType.includes('utf8') && typeof value !== 'string') {
|
|
37
|
-
throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (fieldType.includes('timestamp') && !(value instanceof Date) && typeof value !== 'string') {
|
|
41
|
-
throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function processResultWithTypeConversion(
|
|
48
|
-
rawResult: Record<string, any> | Record<string, any>[],
|
|
49
|
-
tableSchema: SchemaLike,
|
|
50
|
-
): Record<string, any> | Record<string, any>[] {
|
|
51
|
-
// Build a map of field names to their schema types
|
|
52
|
-
const fieldTypeMap = new Map();
|
|
53
|
-
tableSchema.fields.forEach((field: any) => {
|
|
54
|
-
const fieldName = field.name;
|
|
55
|
-
const fieldTypeStr = field.type.toString().toLowerCase();
|
|
56
|
-
fieldTypeMap.set(fieldName, fieldTypeStr);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Handle array case
|
|
60
|
-
if (Array.isArray(rawResult)) {
|
|
61
|
-
return rawResult.map(item => processResultWithTypeConversion(item, tableSchema));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Handle single record case
|
|
65
|
-
const processedResult = { ...rawResult };
|
|
66
|
-
|
|
67
|
-
// Convert each field according to its schema type
|
|
68
|
-
for (const key in processedResult) {
|
|
69
|
-
const fieldTypeStr = fieldTypeMap.get(key);
|
|
70
|
-
if (!fieldTypeStr) continue;
|
|
71
|
-
|
|
72
|
-
// Skip conversion for ID fields - preserve their original format
|
|
73
|
-
// if (key === 'id') {
|
|
74
|
-
// continue;
|
|
75
|
-
// }
|
|
76
|
-
|
|
77
|
-
// Only try to convert string values
|
|
78
|
-
if (typeof processedResult[key] === 'string') {
|
|
79
|
-
// Numeric types
|
|
80
|
-
if (fieldTypeStr.includes('int32') || fieldTypeStr.includes('float32')) {
|
|
81
|
-
if (!isNaN(Number(processedResult[key]))) {
|
|
82
|
-
processedResult[key] = Number(processedResult[key]);
|
|
83
|
-
}
|
|
84
|
-
} else if (fieldTypeStr.includes('int64')) {
|
|
85
|
-
processedResult[key] = Number(processedResult[key]);
|
|
86
|
-
} else if (fieldTypeStr.includes('utf8') && key !== 'id') {
|
|
87
|
-
try {
|
|
88
|
-
const parsed = JSON.parse(processedResult[key]);
|
|
89
|
-
if (typeof parsed === 'object') {
|
|
90
|
-
processedResult[key] = JSON.parse(processedResult[key]);
|
|
91
|
-
}
|
|
92
|
-
} catch {}
|
|
93
|
-
}
|
|
94
|
-
} else if (typeof processedResult[key] === 'bigint') {
|
|
95
|
-
// Convert BigInt values to regular numbers for application layer
|
|
96
|
-
processedResult[key] = Number(processedResult[key]);
|
|
97
|
-
} else if (fieldTypeStr.includes('float64') && ['createdAt', 'updatedAt'].includes(key)) {
|
|
98
|
-
processedResult[key] = new Date(processedResult[key]);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
console.log(key, 'processedResult', processedResult);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return processedResult;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export async function getTableSchema({
|
|
108
|
-
tableName,
|
|
109
|
-
client,
|
|
110
|
-
}: {
|
|
111
|
-
tableName: TABLE_NAMES;
|
|
112
|
-
client: Connection;
|
|
113
|
-
}): Promise<SchemaLike> {
|
|
114
|
-
try {
|
|
115
|
-
if (!client) {
|
|
116
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
117
|
-
}
|
|
118
|
-
if (!tableName) {
|
|
119
|
-
throw new Error('tableName is required for getTableSchema.');
|
|
120
|
-
}
|
|
121
|
-
} catch (validationError: any) {
|
|
122
|
-
throw new MastraError(
|
|
123
|
-
{
|
|
124
|
-
id: 'STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS',
|
|
125
|
-
domain: ErrorDomain.STORAGE,
|
|
126
|
-
category: ErrorCategory.USER,
|
|
127
|
-
text: validationError.message,
|
|
128
|
-
details: { tableName },
|
|
129
|
-
},
|
|
130
|
-
validationError,
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
const table = await client.openTable(tableName);
|
|
136
|
-
const rawSchema = await table.schema();
|
|
137
|
-
const fields = rawSchema.fields as FieldLike[];
|
|
138
|
-
|
|
139
|
-
// Convert schema to SchemaLike format
|
|
140
|
-
return {
|
|
141
|
-
fields,
|
|
142
|
-
metadata: new Map<string, string>(),
|
|
143
|
-
get names() {
|
|
144
|
-
return fields.map((field: FieldLike) => field.name);
|
|
145
|
-
},
|
|
146
|
-
};
|
|
147
|
-
} catch (error: any) {
|
|
148
|
-
throw new MastraError(
|
|
149
|
-
{
|
|
150
|
-
id: 'STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED',
|
|
151
|
-
domain: ErrorDomain.STORAGE,
|
|
152
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
153
|
-
details: { tableName },
|
|
154
|
-
},
|
|
155
|
-
error,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
}
|