@mastra/cloudflare-d1 0.0.0-share-agent-metadata-with-cloud-20250718110128 → 0.0.0-sidebar-window-undefined-fix-20251029233656
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 +1232 -0
- package/dist/index.cjs +1450 -727
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -7
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1451 -728
- package/dist/index.js.map +1 -0
- package/dist/storage/domains/legacy-evals/index.d.ts +20 -0
- package/dist/storage/domains/legacy-evals/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +90 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +72 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -0
- package/dist/storage/domains/scores/index.d.ts +60 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -0
- package/dist/storage/domains/utils.d.ts +3 -0
- package/dist/storage/domains/utils.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +52 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +279 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/sql-builder.d.ts +128 -0
- package/dist/storage/sql-builder.d.ts.map +1 -0
- package/dist/storage/test-utils.d.ts +19 -0
- package/dist/storage/test-utils.d.ts.map +1 -0
- package/package.json +24 -13
- package/dist/_tsup-dts-rollup.d.cts +0 -422
- package/dist/_tsup-dts-rollup.d.ts +0 -422
- package/dist/index.d.cts +0 -7
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { MessageList } from '@mastra/core/agent';
|
|
2
1
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
-
import { MastraStorage,
|
|
2
|
+
import { MastraStorage, StoreOperations, ScoresStorage, TABLE_SCORERS, LegacyEvalsStorage, TABLE_EVALS, serializeDate, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ensureDate, MemoryStorage, TABLE_RESOURCES, TABLE_THREADS, TABLE_MESSAGES, resolveMessageLimit, safelyParseJSON } from '@mastra/core/storage';
|
|
4
3
|
import Cloudflare from 'cloudflare';
|
|
5
4
|
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
5
|
+
import { MessageList } from '@mastra/core/agent';
|
|
6
|
+
import { saveScorePayloadSchema } from '@mastra/core/scores';
|
|
6
7
|
|
|
7
8
|
// src/storage/index.ts
|
|
8
9
|
var SqlBuilder = class {
|
|
@@ -235,402 +236,291 @@ function parseSelectIdentifier(column) {
|
|
|
235
236
|
return column;
|
|
236
237
|
}
|
|
237
238
|
|
|
238
|
-
// src/storage/
|
|
239
|
+
// src/storage/domains/utils.ts
|
|
239
240
|
function isArrayOfRecords(value) {
|
|
240
241
|
return value && Array.isArray(value) && value.length > 0;
|
|
241
242
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// D1Database binding
|
|
246
|
-
tablePrefix;
|
|
247
|
-
/**
|
|
248
|
-
* Creates a new D1Store instance
|
|
249
|
-
* @param config Configuration for D1 access (either REST API or Workers Binding API)
|
|
250
|
-
*/
|
|
251
|
-
constructor(config) {
|
|
243
|
+
function deserializeValue(value, type) {
|
|
244
|
+
if (value === null || value === void 0) return null;
|
|
245
|
+
if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
|
|
252
246
|
try {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
this.tablePrefix = config.tablePrefix || "";
|
|
258
|
-
if ("binding" in config) {
|
|
259
|
-
if (!config.binding) {
|
|
260
|
-
throw new Error("D1 binding is required when using Workers Binding API");
|
|
261
|
-
}
|
|
262
|
-
this.binding = config.binding;
|
|
263
|
-
this.logger.info("Using D1 Workers Binding API");
|
|
264
|
-
} else if ("client" in config) {
|
|
265
|
-
if (!config.client) {
|
|
266
|
-
throw new Error("D1 client is required when using D1ClientConfig");
|
|
267
|
-
}
|
|
268
|
-
this.client = config.client;
|
|
269
|
-
this.logger.info("Using D1 Client");
|
|
270
|
-
} else {
|
|
271
|
-
if (!config.accountId || !config.databaseId || !config.apiToken) {
|
|
272
|
-
throw new Error("accountId, databaseId, and apiToken are required when using REST API");
|
|
273
|
-
}
|
|
274
|
-
const cfClient = new Cloudflare({
|
|
275
|
-
apiToken: config.apiToken
|
|
276
|
-
});
|
|
277
|
-
this.client = {
|
|
278
|
-
query: ({ sql, params }) => {
|
|
279
|
-
return cfClient.d1.database.query(config.databaseId, {
|
|
280
|
-
account_id: config.accountId,
|
|
281
|
-
sql,
|
|
282
|
-
params
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
this.logger.info("Using D1 REST API");
|
|
287
|
-
}
|
|
288
|
-
} catch (error) {
|
|
289
|
-
throw new MastraError(
|
|
290
|
-
{
|
|
291
|
-
id: "CLOUDFLARE_D1_STORAGE_INITIALIZATION_ERROR",
|
|
292
|
-
domain: ErrorDomain.STORAGE,
|
|
293
|
-
category: ErrorCategory.SYSTEM,
|
|
294
|
-
text: "Error initializing D1Store"
|
|
295
|
-
},
|
|
296
|
-
error
|
|
297
|
-
);
|
|
247
|
+
return JSON.parse(value);
|
|
248
|
+
} catch {
|
|
249
|
+
return value;
|
|
298
250
|
}
|
|
299
251
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
252
|
+
return value;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/storage/domains/legacy-evals/index.ts
|
|
256
|
+
var LegacyEvalsStorageD1 = class extends LegacyEvalsStorage {
|
|
257
|
+
operations;
|
|
258
|
+
constructor({ operations }) {
|
|
259
|
+
super();
|
|
260
|
+
this.operations = operations;
|
|
306
261
|
}
|
|
307
|
-
async
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (
|
|
313
|
-
|
|
262
|
+
async getEvals(options) {
|
|
263
|
+
const { agentName, type, page = 0, perPage = 40, dateRange } = options || {};
|
|
264
|
+
const fullTableName = this.operations.getTableName(TABLE_EVALS);
|
|
265
|
+
const conditions = [];
|
|
266
|
+
const queryParams = [];
|
|
267
|
+
if (agentName) {
|
|
268
|
+
conditions.push(`agent_name = ?`);
|
|
269
|
+
queryParams.push(agentName);
|
|
314
270
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (formattedParams.length > 0) {
|
|
320
|
-
if (first) {
|
|
321
|
-
result = await statement.bind(...formattedParams).first();
|
|
322
|
-
if (!result) return null;
|
|
323
|
-
return result;
|
|
324
|
-
} else {
|
|
325
|
-
result = await statement.bind(...formattedParams).all();
|
|
326
|
-
const results = result.results || [];
|
|
327
|
-
if (result.meta) {
|
|
328
|
-
this.logger.debug("Query metadata", { meta: result.meta });
|
|
329
|
-
}
|
|
330
|
-
return results;
|
|
331
|
-
}
|
|
332
|
-
} else {
|
|
333
|
-
if (first) {
|
|
334
|
-
result = await statement.first();
|
|
335
|
-
if (!result) return null;
|
|
336
|
-
return result;
|
|
337
|
-
} else {
|
|
338
|
-
result = await statement.all();
|
|
339
|
-
const results = result.results || [];
|
|
340
|
-
if (result.meta) {
|
|
341
|
-
this.logger.debug("Query metadata", { meta: result.meta });
|
|
342
|
-
}
|
|
343
|
-
return results;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
} catch (workerError) {
|
|
347
|
-
this.logger.error("Workers Binding API error", {
|
|
348
|
-
message: workerError instanceof Error ? workerError.message : String(workerError),
|
|
349
|
-
sql
|
|
350
|
-
});
|
|
351
|
-
throw new Error(`D1 Workers API error: ${workerError.message}`);
|
|
271
|
+
if (type === "test") {
|
|
272
|
+
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
273
|
+
} else if (type === "live") {
|
|
274
|
+
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
352
275
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
params = [],
|
|
357
|
-
first = false
|
|
358
|
-
}) {
|
|
359
|
-
if (!this.client) {
|
|
360
|
-
throw new Error("Missing required REST API configuration");
|
|
276
|
+
if (dateRange?.start) {
|
|
277
|
+
conditions.push(`created_at >= ?`);
|
|
278
|
+
queryParams.push(serializeDate(dateRange.start));
|
|
361
279
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
params: this.formatSqlParams(params)
|
|
366
|
-
});
|
|
367
|
-
const result = response.result || [];
|
|
368
|
-
const results = result.flatMap((r) => r.results || []);
|
|
369
|
-
if (first) {
|
|
370
|
-
const firstResult = isArrayOfRecords(results) && results.length > 0 ? results[0] : null;
|
|
371
|
-
if (!firstResult) return null;
|
|
372
|
-
return firstResult;
|
|
373
|
-
}
|
|
374
|
-
return results;
|
|
375
|
-
} catch (restError) {
|
|
376
|
-
this.logger.error("REST API error", {
|
|
377
|
-
message: restError instanceof Error ? restError.message : String(restError),
|
|
378
|
-
sql
|
|
379
|
-
});
|
|
380
|
-
throw new Error(`D1 REST API error: ${restError.message}`);
|
|
280
|
+
if (dateRange?.end) {
|
|
281
|
+
conditions.push(`created_at <= ?`);
|
|
282
|
+
queryParams.push(serializeDate(dateRange.end));
|
|
381
283
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
* @param options Query options including SQL, parameters, and whether to return only the first result
|
|
386
|
-
* @returns Query results as an array or a single object if first=true
|
|
387
|
-
*/
|
|
388
|
-
async executeQuery(options) {
|
|
389
|
-
const { sql, params = [], first = false } = options;
|
|
390
|
-
try {
|
|
391
|
-
this.logger.debug("Executing SQL query", { sql, params, first });
|
|
392
|
-
if (this.binding) {
|
|
393
|
-
return this.executeWorkersBindingQuery({ sql, params, first });
|
|
394
|
-
} else if (this.client) {
|
|
395
|
-
return this.executeRestQuery({ sql, params, first });
|
|
396
|
-
} else {
|
|
397
|
-
throw new Error("No valid D1 configuration provided");
|
|
398
|
-
}
|
|
399
|
-
} catch (error) {
|
|
400
|
-
this.logger.error("Error executing SQL query", {
|
|
401
|
-
message: error instanceof Error ? error.message : String(error),
|
|
402
|
-
sql,
|
|
403
|
-
params,
|
|
404
|
-
first
|
|
405
|
-
});
|
|
406
|
-
throw new Error(`D1 query error: ${error.message}`);
|
|
284
|
+
const countQueryBuilder = createSqlBuilder().count().from(fullTableName);
|
|
285
|
+
if (conditions.length > 0) {
|
|
286
|
+
countQueryBuilder.where(conditions.join(" AND "), ...queryParams);
|
|
407
287
|
}
|
|
408
|
-
|
|
409
|
-
// Helper to get existing table columns
|
|
410
|
-
async getTableColumns(tableName) {
|
|
288
|
+
const { sql: countSql, params: countParams } = countQueryBuilder.build();
|
|
411
289
|
try {
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
return result.map((row) => ({
|
|
418
|
-
name: row.name,
|
|
419
|
-
type: row.type
|
|
420
|
-
}));
|
|
421
|
-
} catch (error) {
|
|
422
|
-
this.logger.error(`Error getting table columns for ${tableName}:`, {
|
|
423
|
-
message: error instanceof Error ? error.message : String(error)
|
|
290
|
+
const countResult = await this.operations.executeQuery({
|
|
291
|
+
sql: countSql,
|
|
292
|
+
params: countParams,
|
|
293
|
+
first: true
|
|
424
294
|
});
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
return JSON.stringify(value);
|
|
436
|
-
}
|
|
437
|
-
return value;
|
|
438
|
-
}
|
|
439
|
-
// Helper to deserialize JSON strings to objects
|
|
440
|
-
deserializeValue(value, type) {
|
|
441
|
-
if (value === null || value === void 0) return null;
|
|
442
|
-
if (type === "date" && typeof value === "string") {
|
|
443
|
-
return new Date(value);
|
|
444
|
-
}
|
|
445
|
-
if (type === "jsonb" && typeof value === "string") {
|
|
446
|
-
try {
|
|
447
|
-
return JSON.parse(value);
|
|
448
|
-
} catch {
|
|
449
|
-
return value;
|
|
295
|
+
const total = Number(countResult?.count || 0);
|
|
296
|
+
const currentOffset = page * perPage;
|
|
297
|
+
if (total === 0) {
|
|
298
|
+
return {
|
|
299
|
+
evals: [],
|
|
300
|
+
total: 0,
|
|
301
|
+
page,
|
|
302
|
+
perPage,
|
|
303
|
+
hasMore: false
|
|
304
|
+
};
|
|
450
305
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
return JSON.parse(value);
|
|
455
|
-
} catch {
|
|
456
|
-
return value;
|
|
306
|
+
const dataQueryBuilder = createSqlBuilder().select("*").from(fullTableName);
|
|
307
|
+
if (conditions.length > 0) {
|
|
308
|
+
dataQueryBuilder.where(conditions.join(" AND "), ...queryParams);
|
|
457
309
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
return
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
return `${colName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
483
|
-
});
|
|
484
|
-
const tableConstraints = [];
|
|
485
|
-
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
486
|
-
tableConstraints.push("UNIQUE (workflow_name, run_id)");
|
|
487
|
-
}
|
|
488
|
-
try {
|
|
489
|
-
const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
|
|
490
|
-
const { sql, params } = query.build();
|
|
491
|
-
await this.executeQuery({ sql, params });
|
|
492
|
-
this.logger.debug(`Created table ${fullTableName}`);
|
|
493
|
-
} catch (error) {
|
|
494
|
-
this.logger.error(`Error creating table ${fullTableName}:`, {
|
|
495
|
-
message: error instanceof Error ? error.message : String(error)
|
|
310
|
+
dataQueryBuilder.orderBy("created_at", "DESC").limit(perPage).offset(currentOffset);
|
|
311
|
+
const { sql: dataSql, params: dataParams } = dataQueryBuilder.build();
|
|
312
|
+
const rows = await this.operations.executeQuery({
|
|
313
|
+
sql: dataSql,
|
|
314
|
+
params: dataParams
|
|
315
|
+
});
|
|
316
|
+
const evals = (isArrayOfRecords(rows) ? rows : []).map((row) => {
|
|
317
|
+
const result = deserializeValue(row.result);
|
|
318
|
+
const testInfo = row.test_info ? deserializeValue(row.test_info) : void 0;
|
|
319
|
+
if (!result || typeof result !== "object" || !("score" in result)) {
|
|
320
|
+
throw new Error(`Invalid MetricResult format: ${JSON.stringify(result)}`);
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
input: row.input,
|
|
324
|
+
output: row.output,
|
|
325
|
+
result,
|
|
326
|
+
agentName: row.agent_name,
|
|
327
|
+
metricName: row.metric_name,
|
|
328
|
+
instructions: row.instructions,
|
|
329
|
+
testInfo,
|
|
330
|
+
globalRunId: row.global_run_id,
|
|
331
|
+
runId: row.run_id,
|
|
332
|
+
createdAt: row.created_at
|
|
333
|
+
};
|
|
496
334
|
});
|
|
335
|
+
const hasMore = currentOffset + evals.length < total;
|
|
336
|
+
return {
|
|
337
|
+
evals,
|
|
338
|
+
total,
|
|
339
|
+
page,
|
|
340
|
+
perPage,
|
|
341
|
+
hasMore
|
|
342
|
+
};
|
|
343
|
+
} catch (error) {
|
|
497
344
|
throw new MastraError(
|
|
498
345
|
{
|
|
499
|
-
id: "
|
|
346
|
+
id: "CLOUDFLARE_D1_STORAGE_GET_EVALS_ERROR",
|
|
500
347
|
domain: ErrorDomain.STORAGE,
|
|
501
348
|
category: ErrorCategory.THIRD_PARTY,
|
|
502
|
-
text: `Failed to
|
|
503
|
-
details: {
|
|
349
|
+
text: `Failed to retrieve evals for agent ${agentName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
350
|
+
details: { agentName: agentName ?? "", type: type ?? "" }
|
|
504
351
|
},
|
|
505
352
|
error
|
|
506
353
|
);
|
|
507
354
|
}
|
|
508
355
|
}
|
|
509
356
|
/**
|
|
510
|
-
*
|
|
511
|
-
* @param tableName Name of the table
|
|
512
|
-
* @param schema Schema of the table
|
|
513
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
357
|
+
* @deprecated use getEvals instead
|
|
514
358
|
*/
|
|
515
|
-
async
|
|
516
|
-
|
|
517
|
-
schema,
|
|
518
|
-
ifNotExists
|
|
519
|
-
}) {
|
|
520
|
-
const fullTableName = this.getTableName(tableName);
|
|
359
|
+
async getEvalsByAgentName(agentName, type) {
|
|
360
|
+
const fullTableName = this.operations.getTableName(TABLE_EVALS);
|
|
521
361
|
try {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const sqlType = this.getSqlType(columnDef.type);
|
|
528
|
-
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
529
|
-
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
530
|
-
const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
531
|
-
await this.executeQuery({ sql: alterSql, params: [] });
|
|
532
|
-
this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
|
|
533
|
-
}
|
|
362
|
+
let query = createSqlBuilder().select("*").from(fullTableName).where("agent_name = ?", agentName);
|
|
363
|
+
if (type === "test") {
|
|
364
|
+
query = query.andWhere("test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL");
|
|
365
|
+
} else if (type === "live") {
|
|
366
|
+
query = query.andWhere("(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)");
|
|
534
367
|
}
|
|
368
|
+
query.orderBy("created_at", "DESC");
|
|
369
|
+
const { sql, params } = query.build();
|
|
370
|
+
const results = await this.operations.executeQuery({ sql, params });
|
|
371
|
+
return isArrayOfRecords(results) ? results.map((row) => {
|
|
372
|
+
const result = deserializeValue(row.result);
|
|
373
|
+
const testInfo = row.test_info ? deserializeValue(row.test_info) : void 0;
|
|
374
|
+
return {
|
|
375
|
+
input: row.input || "",
|
|
376
|
+
output: row.output || "",
|
|
377
|
+
result,
|
|
378
|
+
agentName: row.agent_name || "",
|
|
379
|
+
metricName: row.metric_name || "",
|
|
380
|
+
instructions: row.instructions || "",
|
|
381
|
+
runId: row.run_id || "",
|
|
382
|
+
globalRunId: row.global_run_id || "",
|
|
383
|
+
createdAt: row.created_at || "",
|
|
384
|
+
testInfo
|
|
385
|
+
};
|
|
386
|
+
}) : [];
|
|
535
387
|
} catch (error) {
|
|
536
|
-
|
|
388
|
+
const mastraError = new MastraError(
|
|
537
389
|
{
|
|
538
|
-
id: "
|
|
390
|
+
id: "CLOUDFLARE_D1_STORAGE_GET_EVALS_ERROR",
|
|
539
391
|
domain: ErrorDomain.STORAGE,
|
|
540
392
|
category: ErrorCategory.THIRD_PARTY,
|
|
541
|
-
text: `Failed to
|
|
542
|
-
details: {
|
|
393
|
+
text: `Failed to retrieve evals for agent ${agentName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
394
|
+
details: { agentName }
|
|
543
395
|
},
|
|
544
396
|
error
|
|
545
397
|
);
|
|
398
|
+
this.logger?.error(mastraError.toString());
|
|
399
|
+
this.logger?.trackException(mastraError);
|
|
400
|
+
return [];
|
|
546
401
|
}
|
|
547
402
|
}
|
|
548
|
-
|
|
549
|
-
|
|
403
|
+
};
|
|
404
|
+
var MemoryStorageD1 = class extends MemoryStorage {
|
|
405
|
+
operations;
|
|
406
|
+
constructor({ operations }) {
|
|
407
|
+
super();
|
|
408
|
+
this.operations = operations;
|
|
409
|
+
}
|
|
410
|
+
async getResourceById({ resourceId }) {
|
|
411
|
+
const resource = await this.operations.load({
|
|
412
|
+
tableName: TABLE_RESOURCES,
|
|
413
|
+
keys: { id: resourceId }
|
|
414
|
+
});
|
|
415
|
+
if (!resource) return null;
|
|
550
416
|
try {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
417
|
+
return {
|
|
418
|
+
...resource,
|
|
419
|
+
createdAt: ensureDate(resource.createdAt),
|
|
420
|
+
updatedAt: ensureDate(resource.updatedAt),
|
|
421
|
+
metadata: typeof resource.metadata === "string" ? JSON.parse(resource.metadata || "{}") : resource.metadata
|
|
422
|
+
};
|
|
555
423
|
} catch (error) {
|
|
556
|
-
|
|
424
|
+
const mastraError = new MastraError(
|
|
557
425
|
{
|
|
558
|
-
id: "
|
|
426
|
+
id: "CLOUDFLARE_D1_STORAGE_GET_RESOURCE_BY_ID_ERROR",
|
|
559
427
|
domain: ErrorDomain.STORAGE,
|
|
560
428
|
category: ErrorCategory.THIRD_PARTY,
|
|
561
|
-
text: `
|
|
562
|
-
details: {
|
|
429
|
+
text: `Error processing resource ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
430
|
+
details: { resourceId }
|
|
563
431
|
},
|
|
564
432
|
error
|
|
565
433
|
);
|
|
434
|
+
this.logger?.error(mastraError.toString());
|
|
435
|
+
this.logger?.trackException(mastraError);
|
|
436
|
+
return null;
|
|
566
437
|
}
|
|
567
438
|
}
|
|
568
|
-
async
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
const processedRecord = await this.processRecord(
|
|
439
|
+
async saveResource({ resource }) {
|
|
440
|
+
const fullTableName = this.operations.getTableName(TABLE_RESOURCES);
|
|
441
|
+
const resourceToSave = {
|
|
442
|
+
id: resource.id,
|
|
443
|
+
workingMemory: resource.workingMemory,
|
|
444
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : null,
|
|
445
|
+
createdAt: resource.createdAt,
|
|
446
|
+
updatedAt: resource.updatedAt
|
|
447
|
+
};
|
|
448
|
+
const processedRecord = await this.operations.processRecord(resourceToSave);
|
|
578
449
|
const columns = Object.keys(processedRecord);
|
|
579
450
|
const values = Object.values(processedRecord);
|
|
580
|
-
const
|
|
451
|
+
const updateMap = {
|
|
452
|
+
workingMemory: "excluded.workingMemory",
|
|
453
|
+
metadata: "excluded.metadata",
|
|
454
|
+
createdAt: "excluded.createdAt",
|
|
455
|
+
updatedAt: "excluded.updatedAt"
|
|
456
|
+
};
|
|
457
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
581
458
|
const { sql, params } = query.build();
|
|
582
459
|
try {
|
|
583
|
-
await this.executeQuery({ sql, params });
|
|
460
|
+
await this.operations.executeQuery({ sql, params });
|
|
461
|
+
return resource;
|
|
584
462
|
} catch (error) {
|
|
585
463
|
throw new MastraError(
|
|
586
464
|
{
|
|
587
|
-
id: "
|
|
465
|
+
id: "CLOUDFLARE_D1_STORAGE_SAVE_RESOURCE_ERROR",
|
|
588
466
|
domain: ErrorDomain.STORAGE,
|
|
589
467
|
category: ErrorCategory.THIRD_PARTY,
|
|
590
|
-
text: `Failed to
|
|
591
|
-
details: {
|
|
468
|
+
text: `Failed to save resource to ${fullTableName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
469
|
+
details: { resourceId: resource.id }
|
|
592
470
|
},
|
|
593
471
|
error
|
|
594
472
|
);
|
|
595
473
|
}
|
|
596
474
|
}
|
|
597
|
-
async
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
475
|
+
async updateResource({
|
|
476
|
+
resourceId,
|
|
477
|
+
workingMemory,
|
|
478
|
+
metadata
|
|
479
|
+
}) {
|
|
480
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
481
|
+
if (!existingResource) {
|
|
482
|
+
const newResource = {
|
|
483
|
+
id: resourceId,
|
|
484
|
+
workingMemory,
|
|
485
|
+
metadata: metadata || {},
|
|
486
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
487
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
488
|
+
};
|
|
489
|
+
return this.saveResource({ resource: newResource });
|
|
608
490
|
}
|
|
609
|
-
|
|
491
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
492
|
+
const updatedResource = {
|
|
493
|
+
...existingResource,
|
|
494
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
495
|
+
metadata: {
|
|
496
|
+
...existingResource.metadata,
|
|
497
|
+
...metadata
|
|
498
|
+
},
|
|
499
|
+
updatedAt
|
|
500
|
+
};
|
|
501
|
+
const fullTableName = this.operations.getTableName(TABLE_RESOURCES);
|
|
502
|
+
const columns = ["workingMemory", "metadata", "updatedAt"];
|
|
503
|
+
const values = [updatedResource.workingMemory, JSON.stringify(updatedResource.metadata), updatedAt.toISOString()];
|
|
504
|
+
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", resourceId);
|
|
610
505
|
const { sql, params } = query.build();
|
|
611
506
|
try {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
const processedResult = {};
|
|
615
|
-
for (const [key, value] of Object.entries(result)) {
|
|
616
|
-
processedResult[key] = this.deserializeValue(value);
|
|
617
|
-
}
|
|
618
|
-
return processedResult;
|
|
507
|
+
await this.operations.executeQuery({ sql, params });
|
|
508
|
+
return updatedResource;
|
|
619
509
|
} catch (error) {
|
|
620
510
|
throw new MastraError(
|
|
621
511
|
{
|
|
622
|
-
id: "
|
|
512
|
+
id: "CLOUDFLARE_D1_STORAGE_UPDATE_RESOURCE_ERROR",
|
|
623
513
|
domain: ErrorDomain.STORAGE,
|
|
624
514
|
category: ErrorCategory.THIRD_PARTY,
|
|
625
|
-
text: `Failed to
|
|
626
|
-
details: {
|
|
515
|
+
text: `Failed to update resource ${resourceId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
516
|
+
details: { resourceId }
|
|
627
517
|
},
|
|
628
518
|
error
|
|
629
519
|
);
|
|
630
520
|
}
|
|
631
521
|
}
|
|
632
522
|
async getThreadById({ threadId }) {
|
|
633
|
-
const thread = await this.load({
|
|
523
|
+
const thread = await this.operations.load({
|
|
634
524
|
tableName: TABLE_THREADS,
|
|
635
525
|
keys: { id: threadId }
|
|
636
526
|
});
|
|
@@ -638,8 +528,8 @@ var D1Store = class extends MastraStorage {
|
|
|
638
528
|
try {
|
|
639
529
|
return {
|
|
640
530
|
...thread,
|
|
641
|
-
createdAt:
|
|
642
|
-
updatedAt:
|
|
531
|
+
createdAt: ensureDate(thread.createdAt),
|
|
532
|
+
updatedAt: ensureDate(thread.updatedAt),
|
|
643
533
|
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
|
|
644
534
|
};
|
|
645
535
|
} catch (error) {
|
|
@@ -662,15 +552,15 @@ var D1Store = class extends MastraStorage {
|
|
|
662
552
|
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
663
553
|
*/
|
|
664
554
|
async getThreadsByResourceId({ resourceId }) {
|
|
665
|
-
const fullTableName = this.getTableName(TABLE_THREADS);
|
|
555
|
+
const fullTableName = this.operations.getTableName(TABLE_THREADS);
|
|
666
556
|
try {
|
|
667
557
|
const query = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId);
|
|
668
558
|
const { sql, params } = query.build();
|
|
669
|
-
const results = await this.executeQuery({ sql, params });
|
|
559
|
+
const results = await this.operations.executeQuery({ sql, params });
|
|
670
560
|
return (isArrayOfRecords(results) ? results : []).map((thread) => ({
|
|
671
561
|
...thread,
|
|
672
|
-
createdAt:
|
|
673
|
-
updatedAt:
|
|
562
|
+
createdAt: ensureDate(thread.createdAt),
|
|
563
|
+
updatedAt: ensureDate(thread.updatedAt),
|
|
674
564
|
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata || "{}") : thread.metadata || {}
|
|
675
565
|
}));
|
|
676
566
|
} catch (error) {
|
|
@@ -691,19 +581,19 @@ var D1Store = class extends MastraStorage {
|
|
|
691
581
|
}
|
|
692
582
|
async getThreadsByResourceIdPaginated(args) {
|
|
693
583
|
const { resourceId, page, perPage } = args;
|
|
694
|
-
const fullTableName = this.getTableName(TABLE_THREADS);
|
|
584
|
+
const fullTableName = this.operations.getTableName(TABLE_THREADS);
|
|
695
585
|
const mapRowToStorageThreadType = (row) => ({
|
|
696
586
|
...row,
|
|
697
|
-
createdAt:
|
|
698
|
-
updatedAt:
|
|
587
|
+
createdAt: ensureDate(row.createdAt),
|
|
588
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
699
589
|
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata || "{}") : row.metadata || {}
|
|
700
590
|
});
|
|
701
591
|
try {
|
|
702
592
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("resourceId = ?", resourceId);
|
|
703
|
-
const countResult = await this.executeQuery(countQuery.build());
|
|
593
|
+
const countResult = await this.operations.executeQuery(countQuery.build());
|
|
704
594
|
const total = Number(countResult?.[0]?.count ?? 0);
|
|
705
595
|
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("resourceId = ?", resourceId).orderBy("createdAt", "DESC").limit(perPage).offset(page * perPage);
|
|
706
|
-
const results = await this.executeQuery(selectQuery.build());
|
|
596
|
+
const results = await this.operations.executeQuery(selectQuery.build());
|
|
707
597
|
const threads = results.map(mapRowToStorageThreadType);
|
|
708
598
|
return {
|
|
709
599
|
threads,
|
|
@@ -735,16 +625,16 @@ var D1Store = class extends MastraStorage {
|
|
|
735
625
|
}
|
|
736
626
|
}
|
|
737
627
|
async saveThread({ thread }) {
|
|
738
|
-
const fullTableName = this.getTableName(TABLE_THREADS);
|
|
628
|
+
const fullTableName = this.operations.getTableName(TABLE_THREADS);
|
|
739
629
|
const threadToSave = {
|
|
740
630
|
id: thread.id,
|
|
741
631
|
resourceId: thread.resourceId,
|
|
742
632
|
title: thread.title,
|
|
743
633
|
metadata: thread.metadata ? JSON.stringify(thread.metadata) : null,
|
|
744
|
-
createdAt: thread.createdAt,
|
|
745
|
-
updatedAt: thread.updatedAt
|
|
634
|
+
createdAt: thread.createdAt.toISOString(),
|
|
635
|
+
updatedAt: thread.updatedAt.toISOString()
|
|
746
636
|
};
|
|
747
|
-
const processedRecord = await this.processRecord(threadToSave);
|
|
637
|
+
const processedRecord = await this.operations.processRecord(threadToSave);
|
|
748
638
|
const columns = Object.keys(processedRecord);
|
|
749
639
|
const values = Object.values(processedRecord);
|
|
750
640
|
const updateMap = {
|
|
@@ -757,7 +647,7 @@ var D1Store = class extends MastraStorage {
|
|
|
757
647
|
const query = createSqlBuilder().insert(fullTableName, columns, values, ["id"], updateMap);
|
|
758
648
|
const { sql, params } = query.build();
|
|
759
649
|
try {
|
|
760
|
-
await this.executeQuery({ sql, params });
|
|
650
|
+
await this.operations.executeQuery({ sql, params });
|
|
761
651
|
return thread;
|
|
762
652
|
} catch (error) {
|
|
763
653
|
throw new MastraError(
|
|
@@ -782,16 +672,17 @@ var D1Store = class extends MastraStorage {
|
|
|
782
672
|
if (!thread) {
|
|
783
673
|
throw new Error(`Thread ${id} not found`);
|
|
784
674
|
}
|
|
785
|
-
const fullTableName = this.getTableName(TABLE_THREADS);
|
|
675
|
+
const fullTableName = this.operations.getTableName(TABLE_THREADS);
|
|
786
676
|
const mergedMetadata = {
|
|
787
677
|
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
788
678
|
...metadata
|
|
789
679
|
};
|
|
680
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
790
681
|
const columns = ["title", "metadata", "updatedAt"];
|
|
791
|
-
const values = [title, JSON.stringify(mergedMetadata),
|
|
682
|
+
const values = [title, JSON.stringify(mergedMetadata), updatedAt.toISOString()];
|
|
792
683
|
const query = createSqlBuilder().update(fullTableName, columns, values).where("id = ?", id);
|
|
793
684
|
const { sql, params } = query.build();
|
|
794
|
-
await this.executeQuery({ sql, params });
|
|
685
|
+
await this.operations.executeQuery({ sql, params });
|
|
795
686
|
return {
|
|
796
687
|
...thread,
|
|
797
688
|
title,
|
|
@@ -799,7 +690,7 @@ var D1Store = class extends MastraStorage {
|
|
|
799
690
|
...typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
800
691
|
...metadata
|
|
801
692
|
},
|
|
802
|
-
updatedAt
|
|
693
|
+
updatedAt
|
|
803
694
|
};
|
|
804
695
|
} catch (error) {
|
|
805
696
|
throw new MastraError(
|
|
@@ -815,15 +706,15 @@ var D1Store = class extends MastraStorage {
|
|
|
815
706
|
}
|
|
816
707
|
}
|
|
817
708
|
async deleteThread({ threadId }) {
|
|
818
|
-
const fullTableName = this.getTableName(TABLE_THREADS);
|
|
709
|
+
const fullTableName = this.operations.getTableName(TABLE_THREADS);
|
|
819
710
|
try {
|
|
820
711
|
const deleteThreadQuery = createSqlBuilder().delete(fullTableName).where("id = ?", threadId);
|
|
821
712
|
const { sql: threadSql, params: threadParams } = deleteThreadQuery.build();
|
|
822
|
-
await this.executeQuery({ sql: threadSql, params: threadParams });
|
|
823
|
-
const messagesTableName = this.getTableName(TABLE_MESSAGES);
|
|
713
|
+
await this.operations.executeQuery({ sql: threadSql, params: threadParams });
|
|
714
|
+
const messagesTableName = this.operations.getTableName(TABLE_MESSAGES);
|
|
824
715
|
const deleteMessagesQuery = createSqlBuilder().delete(messagesTableName).where("thread_id = ?", threadId);
|
|
825
716
|
const { sql: messagesSql, params: messagesParams } = deleteMessagesQuery.build();
|
|
826
|
-
await this.executeQuery({ sql: messagesSql, params: messagesParams });
|
|
717
|
+
await this.operations.executeQuery({ sql: messagesSql, params: messagesParams });
|
|
827
718
|
} catch (error) {
|
|
828
719
|
throw new MastraError(
|
|
829
720
|
{
|
|
@@ -854,6 +745,9 @@ var D1Store = class extends MastraStorage {
|
|
|
854
745
|
if (!message.role) {
|
|
855
746
|
throw new Error(`Message at index ${i} missing role`);
|
|
856
747
|
}
|
|
748
|
+
if (!message.resourceId) {
|
|
749
|
+
throw new Error(`Message at index ${i} missing resourceId`);
|
|
750
|
+
}
|
|
857
751
|
const thread = await this.getThreadById({ threadId: message.threadId });
|
|
858
752
|
if (!thread) {
|
|
859
753
|
throw new Error(`Thread ${message.threadId} not found`);
|
|
@@ -872,13 +766,13 @@ var D1Store = class extends MastraStorage {
|
|
|
872
766
|
};
|
|
873
767
|
});
|
|
874
768
|
await Promise.all([
|
|
875
|
-
this.batchUpsert({
|
|
769
|
+
this.operations.batchUpsert({
|
|
876
770
|
tableName: TABLE_MESSAGES,
|
|
877
771
|
records: messagesToInsert
|
|
878
772
|
}),
|
|
879
773
|
// Update thread's updatedAt timestamp
|
|
880
|
-
this.executeQuery({
|
|
881
|
-
sql: `UPDATE ${this.getTableName(TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
|
|
774
|
+
this.operations.executeQuery({
|
|
775
|
+
sql: `UPDATE ${this.operations.getTableName(TABLE_THREADS)} SET updatedAt = ? WHERE id = ?`,
|
|
882
776
|
params: [now.toISOString(), threadId]
|
|
883
777
|
})
|
|
884
778
|
]);
|
|
@@ -899,64 +793,78 @@ var D1Store = class extends MastraStorage {
|
|
|
899
793
|
}
|
|
900
794
|
}
|
|
901
795
|
async _getIncludedMessages(threadId, selectBy) {
|
|
796
|
+
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
902
797
|
const include = selectBy?.include;
|
|
903
798
|
if (!include) return null;
|
|
904
|
-
const
|
|
905
|
-
const
|
|
906
|
-
|
|
907
|
-
const
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
const messages = await this.executeQuery({ sql, params });
|
|
945
|
-
|
|
799
|
+
const unionQueries = [];
|
|
800
|
+
const params = [];
|
|
801
|
+
let paramIdx = 1;
|
|
802
|
+
for (const inc of include) {
|
|
803
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
804
|
+
const searchId = inc.threadId || threadId;
|
|
805
|
+
unionQueries.push(`
|
|
806
|
+
SELECT * FROM (
|
|
807
|
+
WITH ordered_messages AS (
|
|
808
|
+
SELECT
|
|
809
|
+
*,
|
|
810
|
+
ROW_NUMBER() OVER (ORDER BY createdAt ASC) AS row_num
|
|
811
|
+
FROM ${this.operations.getTableName(TABLE_MESSAGES)}
|
|
812
|
+
WHERE thread_id = ?
|
|
813
|
+
)
|
|
814
|
+
SELECT
|
|
815
|
+
m.id,
|
|
816
|
+
m.content,
|
|
817
|
+
m.role,
|
|
818
|
+
m.type,
|
|
819
|
+
m.createdAt,
|
|
820
|
+
m.thread_id AS threadId,
|
|
821
|
+
m.resourceId
|
|
822
|
+
FROM ordered_messages m
|
|
823
|
+
WHERE m.id = ?
|
|
824
|
+
OR EXISTS (
|
|
825
|
+
SELECT 1 FROM ordered_messages target
|
|
826
|
+
WHERE target.id = ?
|
|
827
|
+
AND (
|
|
828
|
+
(m.row_num <= target.row_num + ? AND m.row_num > target.row_num)
|
|
829
|
+
OR
|
|
830
|
+
(m.row_num >= target.row_num - ? AND m.row_num < target.row_num)
|
|
831
|
+
)
|
|
832
|
+
)
|
|
833
|
+
) AS query_${paramIdx}
|
|
834
|
+
`);
|
|
835
|
+
params.push(searchId, id, id, withNextMessages, withPreviousMessages);
|
|
836
|
+
paramIdx++;
|
|
837
|
+
}
|
|
838
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + " ORDER BY createdAt ASC";
|
|
839
|
+
const messages = await this.operations.executeQuery({ sql: finalQuery, params });
|
|
840
|
+
if (!Array.isArray(messages)) {
|
|
841
|
+
return [];
|
|
842
|
+
}
|
|
843
|
+
const processedMessages = messages.map((message) => {
|
|
844
|
+
const processedMsg = {};
|
|
845
|
+
for (const [key, value] of Object.entries(message)) {
|
|
846
|
+
if (key === `type` && value === `v2`) continue;
|
|
847
|
+
processedMsg[key] = deserializeValue(value);
|
|
848
|
+
}
|
|
849
|
+
return processedMsg;
|
|
850
|
+
});
|
|
851
|
+
return processedMessages;
|
|
946
852
|
}
|
|
947
853
|
async getMessages({
|
|
948
854
|
threadId,
|
|
855
|
+
resourceId,
|
|
949
856
|
selectBy,
|
|
950
857
|
format
|
|
951
858
|
}) {
|
|
952
|
-
const fullTableName = this.getTableName(TABLE_MESSAGES);
|
|
953
|
-
const limit = this.resolveMessageLimit({
|
|
954
|
-
last: selectBy?.last,
|
|
955
|
-
defaultLimit: 40
|
|
956
|
-
});
|
|
957
|
-
const include = selectBy?.include || [];
|
|
958
|
-
const messages = [];
|
|
959
859
|
try {
|
|
860
|
+
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
861
|
+
const fullTableName = this.operations.getTableName(TABLE_MESSAGES);
|
|
862
|
+
const limit = resolveMessageLimit({
|
|
863
|
+
last: selectBy?.last,
|
|
864
|
+
defaultLimit: 40
|
|
865
|
+
});
|
|
866
|
+
const include = selectBy?.include || [];
|
|
867
|
+
const messages = [];
|
|
960
868
|
if (include.length) {
|
|
961
869
|
const includeResult = await this._getIncludedMessages(threadId, selectBy);
|
|
962
870
|
if (Array.isArray(includeResult)) messages.push(...includeResult);
|
|
@@ -968,7 +876,7 @@ var D1Store = class extends MastraStorage {
|
|
|
968
876
|
}
|
|
969
877
|
query.orderBy("createdAt", "DESC").limit(limit);
|
|
970
878
|
const { sql, params } = query.build();
|
|
971
|
-
const result = await this.executeQuery({ sql, params });
|
|
879
|
+
const result = await this.operations.executeQuery({ sql, params });
|
|
972
880
|
if (Array.isArray(result)) messages.push(...result);
|
|
973
881
|
messages.sort((a, b) => {
|
|
974
882
|
const aRecord = a;
|
|
@@ -981,7 +889,7 @@ var D1Store = class extends MastraStorage {
|
|
|
981
889
|
const processedMsg = {};
|
|
982
890
|
for (const [key, value] of Object.entries(message)) {
|
|
983
891
|
if (key === `type` && value === `v2`) continue;
|
|
984
|
-
processedMsg[key] =
|
|
892
|
+
processedMsg[key] = deserializeValue(value);
|
|
985
893
|
}
|
|
986
894
|
return processedMsg;
|
|
987
895
|
});
|
|
@@ -996,7 +904,48 @@ var D1Store = class extends MastraStorage {
|
|
|
996
904
|
domain: ErrorDomain.STORAGE,
|
|
997
905
|
category: ErrorCategory.THIRD_PARTY,
|
|
998
906
|
text: `Failed to retrieve messages for thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
999
|
-
details: { threadId }
|
|
907
|
+
details: { threadId, resourceId: resourceId ?? "" }
|
|
908
|
+
},
|
|
909
|
+
error
|
|
910
|
+
);
|
|
911
|
+
this.logger?.error(mastraError.toString());
|
|
912
|
+
this.logger?.trackException(mastraError);
|
|
913
|
+
throw mastraError;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
async getMessagesById({
|
|
917
|
+
messageIds,
|
|
918
|
+
format
|
|
919
|
+
}) {
|
|
920
|
+
if (messageIds.length === 0) return [];
|
|
921
|
+
const fullTableName = this.operations.getTableName(TABLE_MESSAGES);
|
|
922
|
+
const messages = [];
|
|
923
|
+
try {
|
|
924
|
+
const query = createSqlBuilder().select(["id", "content", "role", "type", "createdAt", "thread_id AS threadId", "resourceId"]).from(fullTableName).where(`id in (${messageIds.map(() => "?").join(",")})`, ...messageIds);
|
|
925
|
+
query.orderBy("createdAt", "DESC");
|
|
926
|
+
const { sql, params } = query.build();
|
|
927
|
+
const result = await this.operations.executeQuery({ sql, params });
|
|
928
|
+
if (Array.isArray(result)) messages.push(...result);
|
|
929
|
+
const processedMessages = messages.map((message) => {
|
|
930
|
+
const processedMsg = {};
|
|
931
|
+
for (const [key, value] of Object.entries(message)) {
|
|
932
|
+
if (key === `type` && value === `v2`) continue;
|
|
933
|
+
processedMsg[key] = deserializeValue(value);
|
|
934
|
+
}
|
|
935
|
+
return processedMsg;
|
|
936
|
+
});
|
|
937
|
+
this.logger.debug(`Retrieved ${messages.length} messages`);
|
|
938
|
+
const list = new MessageList().add(processedMessages, "memory");
|
|
939
|
+
if (format === `v1`) return list.get.all.v1();
|
|
940
|
+
return list.get.all.v2();
|
|
941
|
+
} catch (error) {
|
|
942
|
+
const mastraError = new MastraError(
|
|
943
|
+
{
|
|
944
|
+
id: "CLOUDFLARE_D1_STORAGE_GET_MESSAGES_BY_ID_ERROR",
|
|
945
|
+
domain: ErrorDomain.STORAGE,
|
|
946
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
947
|
+
text: `Failed to retrieve messages by ID: ${error instanceof Error ? error.message : String(error)}`,
|
|
948
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1000
949
|
},
|
|
1001
950
|
error
|
|
1002
951
|
);
|
|
@@ -1007,44 +956,97 @@ var D1Store = class extends MastraStorage {
|
|
|
1007
956
|
}
|
|
1008
957
|
async getMessagesPaginated({
|
|
1009
958
|
threadId,
|
|
959
|
+
resourceId,
|
|
1010
960
|
selectBy,
|
|
1011
961
|
format
|
|
1012
962
|
}) {
|
|
1013
|
-
const { dateRange, page = 0, perPage
|
|
963
|
+
const { dateRange, page = 0, perPage: perPageInput } = selectBy?.pagination || {};
|
|
1014
964
|
const { start: fromDate, end: toDate } = dateRange || {};
|
|
1015
|
-
const
|
|
965
|
+
const perPage = perPageInput !== void 0 ? perPageInput : resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
966
|
+
const fullTableName = this.operations.getTableName(TABLE_MESSAGES);
|
|
1016
967
|
const messages = [];
|
|
1017
968
|
try {
|
|
969
|
+
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
1018
970
|
if (selectBy?.include?.length) {
|
|
1019
971
|
const includeResult = await this._getIncludedMessages(threadId, selectBy);
|
|
1020
972
|
if (Array.isArray(includeResult)) messages.push(...includeResult);
|
|
1021
973
|
}
|
|
1022
974
|
const countQuery = createSqlBuilder().count().from(fullTableName).where("thread_id = ?", threadId);
|
|
1023
975
|
if (fromDate) {
|
|
1024
|
-
countQuery.andWhere("createdAt >= ?",
|
|
976
|
+
countQuery.andWhere("createdAt >= ?", serializeDate(fromDate));
|
|
1025
977
|
}
|
|
1026
978
|
if (toDate) {
|
|
1027
|
-
countQuery.andWhere("createdAt <= ?",
|
|
979
|
+
countQuery.andWhere("createdAt <= ?", serializeDate(toDate));
|
|
1028
980
|
}
|
|
1029
|
-
const countResult = await this.executeQuery(countQuery.build());
|
|
981
|
+
const countResult = await this.operations.executeQuery(countQuery.build());
|
|
1030
982
|
const total = Number(countResult[0]?.count ?? 0);
|
|
1031
|
-
|
|
983
|
+
if (total === 0 && messages.length === 0) {
|
|
984
|
+
return {
|
|
985
|
+
messages: [],
|
|
986
|
+
total: 0,
|
|
987
|
+
page,
|
|
988
|
+
perPage,
|
|
989
|
+
hasMore: false
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
const excludeIds = messages.map((m) => m.id);
|
|
993
|
+
const excludeCondition = excludeIds.length > 0 ? `AND id NOT IN (${excludeIds.map(() => "?").join(",")})` : "";
|
|
994
|
+
let query;
|
|
995
|
+
let queryParams = [threadId];
|
|
1032
996
|
if (fromDate) {
|
|
1033
|
-
|
|
997
|
+
queryParams.push(serializeDate(fromDate));
|
|
1034
998
|
}
|
|
1035
999
|
if (toDate) {
|
|
1036
|
-
|
|
1000
|
+
queryParams.push(serializeDate(toDate));
|
|
1001
|
+
}
|
|
1002
|
+
if (excludeIds.length > 0) {
|
|
1003
|
+
queryParams.push(...excludeIds);
|
|
1004
|
+
}
|
|
1005
|
+
if (selectBy?.last && selectBy.last > 0) {
|
|
1006
|
+
query = `
|
|
1007
|
+
SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
|
|
1008
|
+
FROM ${fullTableName}
|
|
1009
|
+
WHERE thread_id = ?
|
|
1010
|
+
${fromDate ? "AND createdAt >= ?" : ""}
|
|
1011
|
+
${toDate ? "AND createdAt <= ?" : ""}
|
|
1012
|
+
${excludeCondition}
|
|
1013
|
+
ORDER BY createdAt DESC
|
|
1014
|
+
LIMIT ?
|
|
1015
|
+
`;
|
|
1016
|
+
queryParams.push(selectBy.last);
|
|
1017
|
+
} else {
|
|
1018
|
+
query = `
|
|
1019
|
+
SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId
|
|
1020
|
+
FROM ${fullTableName}
|
|
1021
|
+
WHERE thread_id = ?
|
|
1022
|
+
${fromDate ? "AND createdAt >= ?" : ""}
|
|
1023
|
+
${toDate ? "AND createdAt <= ?" : ""}
|
|
1024
|
+
${excludeCondition}
|
|
1025
|
+
ORDER BY createdAt DESC
|
|
1026
|
+
LIMIT ? OFFSET ?
|
|
1027
|
+
`;
|
|
1028
|
+
queryParams.push(perPage, page * perPage);
|
|
1029
|
+
}
|
|
1030
|
+
const results = await this.operations.executeQuery({ sql: query, params: queryParams });
|
|
1031
|
+
const processedMessages = results.map((message) => {
|
|
1032
|
+
const processedMsg = {};
|
|
1033
|
+
for (const [key, value] of Object.entries(message)) {
|
|
1034
|
+
if (key === `type` && value === `v2`) continue;
|
|
1035
|
+
processedMsg[key] = deserializeValue(value);
|
|
1036
|
+
}
|
|
1037
|
+
return processedMsg;
|
|
1038
|
+
});
|
|
1039
|
+
if (selectBy?.last) {
|
|
1040
|
+
processedMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
1037
1041
|
}
|
|
1038
|
-
|
|
1039
|
-
const results = await this.executeQuery(query.build());
|
|
1040
|
-
const list = new MessageList().add(results, "memory");
|
|
1042
|
+
const list = new MessageList().add(processedMessages, "memory");
|
|
1041
1043
|
messages.push(...format === `v2` ? list.get.all.v2() : list.get.all.v1());
|
|
1042
1044
|
return {
|
|
1043
1045
|
messages,
|
|
1044
1046
|
total,
|
|
1045
1047
|
page,
|
|
1046
1048
|
perPage,
|
|
1047
|
-
hasMore: page * perPage + messages.length < total
|
|
1049
|
+
hasMore: selectBy?.last ? false : page * perPage + messages.length < total
|
|
1048
1050
|
};
|
|
1049
1051
|
} catch (error) {
|
|
1050
1052
|
const mastraError = new MastraError(
|
|
@@ -1053,7 +1055,7 @@ var D1Store = class extends MastraStorage {
|
|
|
1053
1055
|
domain: ErrorDomain.STORAGE,
|
|
1054
1056
|
category: ErrorCategory.THIRD_PARTY,
|
|
1055
1057
|
text: `Failed to retrieve messages for thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1056
|
-
details: { threadId }
|
|
1058
|
+
details: { threadId, resourceId: resourceId ?? "" }
|
|
1057
1059
|
},
|
|
1058
1060
|
error
|
|
1059
1061
|
);
|
|
@@ -1068,132 +1070,446 @@ var D1Store = class extends MastraStorage {
|
|
|
1068
1070
|
};
|
|
1069
1071
|
}
|
|
1070
1072
|
}
|
|
1071
|
-
async
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
const
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
keys: { workflow_name: workflowName, run_id: runId }
|
|
1081
|
-
});
|
|
1082
|
-
const persisting = currentSnapshot ? {
|
|
1083
|
-
...currentSnapshot,
|
|
1084
|
-
snapshot: JSON.stringify(snapshot),
|
|
1085
|
-
updatedAt: now
|
|
1086
|
-
} : {
|
|
1087
|
-
workflow_name: workflowName,
|
|
1088
|
-
run_id: runId,
|
|
1089
|
-
snapshot,
|
|
1090
|
-
createdAt: now,
|
|
1091
|
-
updatedAt: now
|
|
1092
|
-
};
|
|
1093
|
-
const processedRecord = await this.processRecord(persisting);
|
|
1094
|
-
const columns = Object.keys(processedRecord);
|
|
1095
|
-
const values = Object.values(processedRecord);
|
|
1096
|
-
const updateMap = {
|
|
1097
|
-
snapshot: "excluded.snapshot",
|
|
1098
|
-
updatedAt: "excluded.updatedAt"
|
|
1099
|
-
};
|
|
1100
|
-
this.logger.debug("Persisting workflow snapshot", { workflowName, runId });
|
|
1101
|
-
const query = createSqlBuilder().insert(fullTableName, columns, values, ["workflow_name", "run_id"], updateMap);
|
|
1102
|
-
const { sql, params } = query.build();
|
|
1073
|
+
async updateMessages(args) {
|
|
1074
|
+
const { messages } = args;
|
|
1075
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1076
|
+
if (!messages.length) {
|
|
1077
|
+
return [];
|
|
1078
|
+
}
|
|
1079
|
+
const messageIds = messages.map((m) => m.id);
|
|
1080
|
+
const fullTableName = this.operations.getTableName(TABLE_MESSAGES);
|
|
1081
|
+
const threadsTableName = this.operations.getTableName(TABLE_THREADS);
|
|
1103
1082
|
try {
|
|
1104
|
-
|
|
1083
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
1084
|
+
const selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${fullTableName} WHERE id IN (${placeholders})`;
|
|
1085
|
+
const existingMessages = await this.operations.executeQuery({ sql: selectQuery, params: messageIds });
|
|
1086
|
+
if (existingMessages.length === 0) {
|
|
1087
|
+
return [];
|
|
1088
|
+
}
|
|
1089
|
+
const parsedExistingMessages = existingMessages.map((msg) => {
|
|
1090
|
+
if (typeof msg.content === "string") {
|
|
1091
|
+
try {
|
|
1092
|
+
msg.content = JSON.parse(msg.content);
|
|
1093
|
+
} catch {
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
return msg;
|
|
1097
|
+
});
|
|
1098
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1099
|
+
const updateQueries = [];
|
|
1100
|
+
for (const existingMessage of parsedExistingMessages) {
|
|
1101
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1102
|
+
if (!updatePayload) continue;
|
|
1103
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1104
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1105
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1106
|
+
if ("threadId" in updatePayload && updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1107
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1108
|
+
}
|
|
1109
|
+
const setClauses = [];
|
|
1110
|
+
const values = [];
|
|
1111
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
1112
|
+
if (updatableFields.content) {
|
|
1113
|
+
const existingContent = existingMessage.content || {};
|
|
1114
|
+
const newContent = {
|
|
1115
|
+
...existingContent,
|
|
1116
|
+
...updatableFields.content,
|
|
1117
|
+
// Deep merge metadata if it exists on both
|
|
1118
|
+
...existingContent?.metadata && updatableFields.content.metadata ? {
|
|
1119
|
+
metadata: {
|
|
1120
|
+
...existingContent.metadata,
|
|
1121
|
+
...updatableFields.content.metadata
|
|
1122
|
+
}
|
|
1123
|
+
} : {}
|
|
1124
|
+
};
|
|
1125
|
+
setClauses.push(`content = ?`);
|
|
1126
|
+
values.push(JSON.stringify(newContent));
|
|
1127
|
+
delete updatableFields.content;
|
|
1128
|
+
}
|
|
1129
|
+
for (const key in updatableFields) {
|
|
1130
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1131
|
+
const dbColumn = key === "threadId" ? "thread_id" : key;
|
|
1132
|
+
setClauses.push(`${dbColumn} = ?`);
|
|
1133
|
+
values.push(updatableFields[key]);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
if (setClauses.length > 0) {
|
|
1137
|
+
values.push(id);
|
|
1138
|
+
const updateQuery = `UPDATE ${fullTableName} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1139
|
+
updateQueries.push({ sql: updateQuery, params: values });
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
for (const query of updateQueries) {
|
|
1143
|
+
await this.operations.executeQuery(query);
|
|
1144
|
+
}
|
|
1145
|
+
if (threadIdsToUpdate.size > 0) {
|
|
1146
|
+
const threadPlaceholders = Array.from(threadIdsToUpdate).map(() => "?").join(",");
|
|
1147
|
+
const threadUpdateQuery = `UPDATE ${threadsTableName} SET updatedAt = ? WHERE id IN (${threadPlaceholders})`;
|
|
1148
|
+
const threadUpdateParams = [(/* @__PURE__ */ new Date()).toISOString(), ...Array.from(threadIdsToUpdate)];
|
|
1149
|
+
await this.operations.executeQuery({ sql: threadUpdateQuery, params: threadUpdateParams });
|
|
1150
|
+
}
|
|
1151
|
+
const updatedMessages = await this.operations.executeQuery({ sql: selectQuery, params: messageIds });
|
|
1152
|
+
return updatedMessages.map((message) => {
|
|
1153
|
+
if (typeof message.content === "string") {
|
|
1154
|
+
try {
|
|
1155
|
+
message.content = JSON.parse(message.content);
|
|
1156
|
+
} catch {
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
return message;
|
|
1160
|
+
});
|
|
1105
1161
|
} catch (error) {
|
|
1106
1162
|
throw new MastraError(
|
|
1107
1163
|
{
|
|
1108
|
-
id: "
|
|
1164
|
+
id: "CLOUDFLARE_D1_STORAGE_UPDATE_MESSAGES_FAILED",
|
|
1109
1165
|
domain: ErrorDomain.STORAGE,
|
|
1110
1166
|
category: ErrorCategory.THIRD_PARTY,
|
|
1111
|
-
|
|
1112
|
-
details: { workflowName, runId }
|
|
1167
|
+
details: { count: messages.length }
|
|
1113
1168
|
},
|
|
1114
1169
|
error
|
|
1115
1170
|
);
|
|
1116
1171
|
}
|
|
1117
1172
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1173
|
+
};
|
|
1174
|
+
var StoreOperationsD1 = class extends StoreOperations {
|
|
1175
|
+
client;
|
|
1176
|
+
binding;
|
|
1177
|
+
tablePrefix;
|
|
1178
|
+
constructor(config) {
|
|
1179
|
+
super();
|
|
1180
|
+
this.client = config.client;
|
|
1181
|
+
this.binding = config.binding;
|
|
1182
|
+
this.tablePrefix = config.tablePrefix || "";
|
|
1183
|
+
}
|
|
1184
|
+
async hasColumn(table, column) {
|
|
1185
|
+
const fullTableName = table.startsWith(this.tablePrefix) ? table : `${this.tablePrefix}${table}`;
|
|
1186
|
+
const sql = `PRAGMA table_info(${fullTableName});`;
|
|
1187
|
+
const result = await this.executeQuery({ sql, params: [] });
|
|
1188
|
+
if (!result || !Array.isArray(result)) return false;
|
|
1189
|
+
return result.some((col) => col.name === column || col.name === column.toLowerCase());
|
|
1190
|
+
}
|
|
1191
|
+
getTableName(tableName) {
|
|
1192
|
+
return `${this.tablePrefix}${tableName}`;
|
|
1193
|
+
}
|
|
1194
|
+
formatSqlParams(params) {
|
|
1195
|
+
return params.map((p) => p === void 0 || p === null ? null : p);
|
|
1196
|
+
}
|
|
1197
|
+
async executeWorkersBindingQuery({
|
|
1198
|
+
sql,
|
|
1199
|
+
params = [],
|
|
1200
|
+
first = false
|
|
1201
|
+
}) {
|
|
1202
|
+
if (!this.binding) {
|
|
1203
|
+
throw new Error("Workers binding is not configured");
|
|
1204
|
+
}
|
|
1121
1205
|
try {
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1206
|
+
const statement = this.binding.prepare(sql);
|
|
1207
|
+
const formattedParams = this.formatSqlParams(params);
|
|
1208
|
+
let result;
|
|
1209
|
+
if (formattedParams.length > 0) {
|
|
1210
|
+
if (first) {
|
|
1211
|
+
result = await statement.bind(...formattedParams).first();
|
|
1212
|
+
if (!result) return null;
|
|
1213
|
+
return result;
|
|
1214
|
+
} else {
|
|
1215
|
+
result = await statement.bind(...formattedParams).all();
|
|
1216
|
+
const results = result.results || [];
|
|
1217
|
+
return results;
|
|
1127
1218
|
}
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1219
|
+
} else {
|
|
1220
|
+
if (first) {
|
|
1221
|
+
result = await statement.first();
|
|
1222
|
+
if (!result) return null;
|
|
1223
|
+
return result;
|
|
1224
|
+
} else {
|
|
1225
|
+
result = await statement.all();
|
|
1226
|
+
const results = result.results || [];
|
|
1227
|
+
return results;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1130
1230
|
} catch (error) {
|
|
1131
1231
|
throw new MastraError(
|
|
1132
1232
|
{
|
|
1133
|
-
id: "
|
|
1233
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_WORKERS_BINDING_QUERY_FAILED",
|
|
1134
1234
|
domain: ErrorDomain.STORAGE,
|
|
1135
1235
|
category: ErrorCategory.THIRD_PARTY,
|
|
1136
|
-
|
|
1137
|
-
|
|
1236
|
+
details: { sql }
|
|
1237
|
+
},
|
|
1238
|
+
error
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
async executeRestQuery({
|
|
1243
|
+
sql,
|
|
1244
|
+
params = [],
|
|
1245
|
+
first = false
|
|
1246
|
+
}) {
|
|
1247
|
+
if (!this.client) {
|
|
1248
|
+
throw new Error("D1 client is not configured");
|
|
1249
|
+
}
|
|
1250
|
+
try {
|
|
1251
|
+
const formattedParams = this.formatSqlParams(params);
|
|
1252
|
+
const response = await this.client.query({
|
|
1253
|
+
sql,
|
|
1254
|
+
params: formattedParams
|
|
1255
|
+
});
|
|
1256
|
+
const result = response.result || [];
|
|
1257
|
+
const results = result.flatMap((r) => r.results || []);
|
|
1258
|
+
if (first) {
|
|
1259
|
+
return results[0] || null;
|
|
1260
|
+
}
|
|
1261
|
+
return results;
|
|
1262
|
+
} catch (error) {
|
|
1263
|
+
throw new MastraError(
|
|
1264
|
+
{
|
|
1265
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_REST_QUERY_FAILED",
|
|
1266
|
+
domain: ErrorDomain.STORAGE,
|
|
1267
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1268
|
+
details: { sql }
|
|
1269
|
+
},
|
|
1270
|
+
error
|
|
1271
|
+
);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
async executeQuery(options) {
|
|
1275
|
+
if (this.binding) {
|
|
1276
|
+
return this.executeWorkersBindingQuery(options);
|
|
1277
|
+
} else if (this.client) {
|
|
1278
|
+
return this.executeRestQuery(options);
|
|
1279
|
+
} else {
|
|
1280
|
+
throw new Error("Neither binding nor client is configured");
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
async getTableColumns(tableName) {
|
|
1284
|
+
try {
|
|
1285
|
+
const sql = `PRAGMA table_info(${tableName})`;
|
|
1286
|
+
const result = await this.executeQuery({ sql });
|
|
1287
|
+
if (!result || !Array.isArray(result)) {
|
|
1288
|
+
return [];
|
|
1289
|
+
}
|
|
1290
|
+
return result.map((row) => ({
|
|
1291
|
+
name: row.name,
|
|
1292
|
+
type: row.type
|
|
1293
|
+
}));
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
this.logger.warn(`Failed to get table columns for ${tableName}:`, error);
|
|
1296
|
+
return [];
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
serializeValue(value) {
|
|
1300
|
+
if (value === null || value === void 0) {
|
|
1301
|
+
return null;
|
|
1302
|
+
}
|
|
1303
|
+
if (value instanceof Date) {
|
|
1304
|
+
return value.toISOString();
|
|
1305
|
+
}
|
|
1306
|
+
if (typeof value === "object") {
|
|
1307
|
+
return JSON.stringify(value);
|
|
1308
|
+
}
|
|
1309
|
+
return value;
|
|
1310
|
+
}
|
|
1311
|
+
getSqlType(type) {
|
|
1312
|
+
switch (type) {
|
|
1313
|
+
case "bigint":
|
|
1314
|
+
return "INTEGER";
|
|
1315
|
+
// SQLite uses INTEGER for all integer sizes
|
|
1316
|
+
case "jsonb":
|
|
1317
|
+
return "TEXT";
|
|
1318
|
+
// Store JSON as TEXT in SQLite
|
|
1319
|
+
default:
|
|
1320
|
+
return super.getSqlType(type);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
async createTable({
|
|
1324
|
+
tableName,
|
|
1325
|
+
schema
|
|
1326
|
+
}) {
|
|
1327
|
+
try {
|
|
1328
|
+
const fullTableName = this.getTableName(tableName);
|
|
1329
|
+
const columnDefinitions = Object.entries(schema).map(([colName, colDef]) => {
|
|
1330
|
+
const type = this.getSqlType(colDef.type);
|
|
1331
|
+
const nullable = colDef.nullable === false ? "NOT NULL" : "";
|
|
1332
|
+
const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
|
|
1333
|
+
return `${colName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
1334
|
+
});
|
|
1335
|
+
const tableConstraints = [];
|
|
1336
|
+
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
1337
|
+
tableConstraints.push("UNIQUE (workflow_name, run_id)");
|
|
1338
|
+
}
|
|
1339
|
+
const query = createSqlBuilder().createTable(fullTableName, columnDefinitions, tableConstraints);
|
|
1340
|
+
const { sql, params } = query.build();
|
|
1341
|
+
await this.executeQuery({ sql, params });
|
|
1342
|
+
this.logger.debug(`Created table ${fullTableName}`);
|
|
1343
|
+
} catch (error) {
|
|
1344
|
+
throw new MastraError(
|
|
1345
|
+
{
|
|
1346
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_CREATE_TABLE_FAILED",
|
|
1347
|
+
domain: ErrorDomain.STORAGE,
|
|
1348
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1349
|
+
details: { tableName }
|
|
1350
|
+
},
|
|
1351
|
+
error
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
async clearTable({ tableName }) {
|
|
1356
|
+
try {
|
|
1357
|
+
const fullTableName = this.getTableName(tableName);
|
|
1358
|
+
const query = createSqlBuilder().delete(fullTableName);
|
|
1359
|
+
const { sql, params } = query.build();
|
|
1360
|
+
await this.executeQuery({ sql, params });
|
|
1361
|
+
this.logger.debug(`Cleared table ${fullTableName}`);
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
throw new MastraError(
|
|
1364
|
+
{
|
|
1365
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_CLEAR_TABLE_FAILED",
|
|
1366
|
+
domain: ErrorDomain.STORAGE,
|
|
1367
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1368
|
+
details: { tableName }
|
|
1369
|
+
},
|
|
1370
|
+
error
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
async dropTable({ tableName }) {
|
|
1375
|
+
try {
|
|
1376
|
+
const fullTableName = this.getTableName(tableName);
|
|
1377
|
+
const sql = `DROP TABLE IF EXISTS ${fullTableName}`;
|
|
1378
|
+
await this.executeQuery({ sql });
|
|
1379
|
+
this.logger.debug(`Dropped table ${fullTableName}`);
|
|
1380
|
+
} catch (error) {
|
|
1381
|
+
throw new MastraError(
|
|
1382
|
+
{
|
|
1383
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_DROP_TABLE_FAILED",
|
|
1384
|
+
domain: ErrorDomain.STORAGE,
|
|
1385
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1386
|
+
details: { tableName }
|
|
1387
|
+
},
|
|
1388
|
+
error
|
|
1389
|
+
);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
async alterTable(args) {
|
|
1393
|
+
try {
|
|
1394
|
+
const fullTableName = this.getTableName(args.tableName);
|
|
1395
|
+
const existingColumns = await this.getTableColumns(fullTableName);
|
|
1396
|
+
const existingColumnNames = new Set(existingColumns.map((col) => col.name));
|
|
1397
|
+
for (const [columnName, column] of Object.entries(args.schema)) {
|
|
1398
|
+
if (!existingColumnNames.has(columnName) && args.ifNotExists.includes(columnName)) {
|
|
1399
|
+
const sqlType = this.getSqlType(column.type);
|
|
1400
|
+
const defaultValue = this.getDefaultValue(column.type);
|
|
1401
|
+
const sql = `ALTER TABLE ${fullTableName} ADD COLUMN ${columnName} ${sqlType} ${defaultValue}`;
|
|
1402
|
+
await this.executeQuery({ sql });
|
|
1403
|
+
this.logger.debug(`Added column ${columnName} to table ${fullTableName}`);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
} catch (error) {
|
|
1407
|
+
throw new MastraError(
|
|
1408
|
+
{
|
|
1409
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_ALTER_TABLE_FAILED",
|
|
1410
|
+
domain: ErrorDomain.STORAGE,
|
|
1411
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1412
|
+
details: { tableName: args.tableName }
|
|
1413
|
+
},
|
|
1414
|
+
error
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
async insert({ tableName, record }) {
|
|
1419
|
+
try {
|
|
1420
|
+
const fullTableName = this.getTableName(tableName);
|
|
1421
|
+
const processedRecord = await this.processRecord(record);
|
|
1422
|
+
const columns = Object.keys(processedRecord);
|
|
1423
|
+
const values = Object.values(processedRecord);
|
|
1424
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
1425
|
+
const { sql, params } = query.build();
|
|
1426
|
+
await this.executeQuery({ sql, params });
|
|
1427
|
+
} catch (error) {
|
|
1428
|
+
throw new MastraError(
|
|
1429
|
+
{
|
|
1430
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_INSERT_FAILED",
|
|
1431
|
+
domain: ErrorDomain.STORAGE,
|
|
1432
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1433
|
+
details: { tableName }
|
|
1138
1434
|
},
|
|
1139
1435
|
error
|
|
1140
1436
|
);
|
|
1141
1437
|
}
|
|
1142
1438
|
}
|
|
1143
|
-
/**
|
|
1144
|
-
* Insert multiple records in a batch operation
|
|
1145
|
-
* @param tableName The table to insert into
|
|
1146
|
-
* @param records The records to insert
|
|
1147
|
-
*/
|
|
1148
1439
|
async batchInsert({ tableName, records }) {
|
|
1149
|
-
if (records.length === 0) return;
|
|
1150
|
-
const fullTableName = this.getTableName(tableName);
|
|
1151
1440
|
try {
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
}
|
|
1441
|
+
if (records.length === 0) return;
|
|
1442
|
+
const fullTableName = this.getTableName(tableName);
|
|
1443
|
+
const processedRecords = await Promise.all(records.map((record) => this.processRecord(record)));
|
|
1444
|
+
const columns = Object.keys(processedRecords[0] || {});
|
|
1445
|
+
for (const record of processedRecords) {
|
|
1446
|
+
const values = Object.values(record);
|
|
1447
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
1448
|
+
const { sql, params } = query.build();
|
|
1449
|
+
await this.executeQuery({ sql, params });
|
|
1450
|
+
}
|
|
1451
|
+
} catch (error) {
|
|
1452
|
+
throw new MastraError(
|
|
1453
|
+
{
|
|
1454
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_BATCH_INSERT_FAILED",
|
|
1455
|
+
domain: ErrorDomain.STORAGE,
|
|
1456
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1457
|
+
details: { tableName }
|
|
1458
|
+
},
|
|
1459
|
+
error
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
async load({ tableName, keys }) {
|
|
1464
|
+
try {
|
|
1465
|
+
const fullTableName = this.getTableName(tableName);
|
|
1466
|
+
const query = createSqlBuilder().select("*").from(fullTableName);
|
|
1467
|
+
let firstKey = true;
|
|
1468
|
+
for (const [key, value] of Object.entries(keys)) {
|
|
1469
|
+
if (firstKey) {
|
|
1470
|
+
query.where(`${key} = ?`, value);
|
|
1471
|
+
firstKey = false;
|
|
1472
|
+
} else {
|
|
1473
|
+
query.andWhere(`${key} = ?`, value);
|
|
1169
1474
|
}
|
|
1170
|
-
this.logger.debug(
|
|
1171
|
-
`Processed batch ${Math.floor(i / batchSize) + 1} of ${Math.ceil(records.length / batchSize)}`
|
|
1172
|
-
);
|
|
1173
1475
|
}
|
|
1174
|
-
|
|
1476
|
+
query.orderBy("createdAt", "DESC");
|
|
1477
|
+
query.limit(1);
|
|
1478
|
+
const { sql, params } = query.build();
|
|
1479
|
+
const result = await this.executeQuery({ sql, params, first: true });
|
|
1480
|
+
if (!result) {
|
|
1481
|
+
return null;
|
|
1482
|
+
}
|
|
1483
|
+
const deserializedResult = {};
|
|
1484
|
+
for (const [key, value] of Object.entries(result)) {
|
|
1485
|
+
deserializedResult[key] = deserializeValue(value);
|
|
1486
|
+
}
|
|
1487
|
+
return deserializedResult;
|
|
1175
1488
|
} catch (error) {
|
|
1176
1489
|
throw new MastraError(
|
|
1177
1490
|
{
|
|
1178
|
-
id: "
|
|
1491
|
+
id: "CLOUDFLARE_D1_STORE_OPERATIONS_LOAD_FAILED",
|
|
1179
1492
|
domain: ErrorDomain.STORAGE,
|
|
1180
1493
|
category: ErrorCategory.THIRD_PARTY,
|
|
1181
|
-
text: `Failed to batch insert into ${tableName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1182
1494
|
details: { tableName }
|
|
1183
1495
|
},
|
|
1184
1496
|
error
|
|
1185
1497
|
);
|
|
1186
1498
|
}
|
|
1187
1499
|
}
|
|
1500
|
+
async processRecord(record) {
|
|
1501
|
+
const processed = {};
|
|
1502
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1503
|
+
processed[key] = this.serializeValue(value);
|
|
1504
|
+
}
|
|
1505
|
+
return processed;
|
|
1506
|
+
}
|
|
1188
1507
|
/**
|
|
1189
1508
|
* Upsert multiple records in a batch operation
|
|
1190
1509
|
* @param tableName The table to insert into
|
|
1191
1510
|
* @param records The records to insert
|
|
1192
1511
|
*/
|
|
1193
|
-
async batchUpsert({
|
|
1194
|
-
tableName,
|
|
1195
|
-
records
|
|
1196
|
-
}) {
|
|
1512
|
+
async batchUpsert({ tableName, records }) {
|
|
1197
1513
|
if (records.length === 0) return;
|
|
1198
1514
|
const fullTableName = this.getTableName(tableName);
|
|
1199
1515
|
try {
|
|
@@ -1240,273 +1556,395 @@ var D1Store = class extends MastraStorage {
|
|
|
1240
1556
|
);
|
|
1241
1557
|
}
|
|
1242
1558
|
}
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1559
|
+
};
|
|
1560
|
+
function transformScoreRow(row) {
|
|
1561
|
+
const deserialized = { ...row };
|
|
1562
|
+
deserialized.input = safelyParseJSON(row.input);
|
|
1563
|
+
deserialized.output = safelyParseJSON(row.output);
|
|
1564
|
+
deserialized.scorer = safelyParseJSON(row.scorer);
|
|
1565
|
+
deserialized.preprocessStepResult = safelyParseJSON(row.preprocessStepResult);
|
|
1566
|
+
deserialized.analyzeStepResult = safelyParseJSON(row.analyzeStepResult);
|
|
1567
|
+
deserialized.metadata = safelyParseJSON(row.metadata);
|
|
1568
|
+
deserialized.additionalContext = safelyParseJSON(row.additionalContext);
|
|
1569
|
+
deserialized.runtimeContext = safelyParseJSON(row.runtimeContext);
|
|
1570
|
+
deserialized.entity = safelyParseJSON(row.entity);
|
|
1571
|
+
deserialized.createdAt = row.createdAtZ || row.createdAt;
|
|
1572
|
+
deserialized.updatedAt = row.updatedAtZ || row.updatedAt;
|
|
1573
|
+
return deserialized;
|
|
1574
|
+
}
|
|
1575
|
+
var ScoresStorageD1 = class extends ScoresStorage {
|
|
1576
|
+
operations;
|
|
1577
|
+
constructor({ operations }) {
|
|
1578
|
+
super();
|
|
1579
|
+
this.operations = operations;
|
|
1580
|
+
}
|
|
1581
|
+
async getScoreById({ id }) {
|
|
1256
1582
|
try {
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
}
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
1583
|
+
const fullTableName = this.operations.getTableName(TABLE_SCORERS);
|
|
1584
|
+
const query = createSqlBuilder().select("*").from(fullTableName).where("id = ?", id);
|
|
1585
|
+
const { sql, params } = query.build();
|
|
1586
|
+
const result = await this.operations.executeQuery({ sql, params, first: true });
|
|
1587
|
+
if (!result) {
|
|
1588
|
+
return null;
|
|
1263
1589
|
}
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1590
|
+
return transformScoreRow(result);
|
|
1591
|
+
} catch (error) {
|
|
1592
|
+
throw new MastraError(
|
|
1593
|
+
{
|
|
1594
|
+
id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORE_BY_ID_FAILED",
|
|
1595
|
+
domain: ErrorDomain.STORAGE,
|
|
1596
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1597
|
+
},
|
|
1598
|
+
error
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
async saveScore(score) {
|
|
1603
|
+
let parsedScore;
|
|
1604
|
+
try {
|
|
1605
|
+
parsedScore = saveScorePayloadSchema.parse(score);
|
|
1606
|
+
} catch (error) {
|
|
1607
|
+
throw new MastraError(
|
|
1608
|
+
{
|
|
1609
|
+
id: "CLOUDFLARE_D1_STORE_SCORES_SAVE_SCORE_FAILED_INVALID_SCORE_PAYLOAD",
|
|
1610
|
+
domain: ErrorDomain.STORAGE,
|
|
1611
|
+
category: ErrorCategory.USER,
|
|
1612
|
+
details: { scoreId: score.id }
|
|
1613
|
+
},
|
|
1614
|
+
error
|
|
1615
|
+
);
|
|
1616
|
+
}
|
|
1617
|
+
try {
|
|
1618
|
+
const id = crypto.randomUUID();
|
|
1619
|
+
const fullTableName = this.operations.getTableName(TABLE_SCORERS);
|
|
1620
|
+
const serializedRecord = {};
|
|
1621
|
+
for (const [key, value] of Object.entries(parsedScore)) {
|
|
1622
|
+
if (value !== null && value !== void 0) {
|
|
1623
|
+
if (typeof value === "object") {
|
|
1624
|
+
serializedRecord[key] = JSON.stringify(value);
|
|
1625
|
+
} else {
|
|
1626
|
+
serializedRecord[key] = value;
|
|
1627
|
+
}
|
|
1628
|
+
} else {
|
|
1629
|
+
serializedRecord[key] = null;
|
|
1267
1630
|
}
|
|
1268
1631
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
query.orderBy("startTime", "DESC").limit(perPage).offset(page * perPage);
|
|
1632
|
+
serializedRecord.id = id;
|
|
1633
|
+
serializedRecord.createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1634
|
+
serializedRecord.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1635
|
+
const columns = Object.keys(serializedRecord);
|
|
1636
|
+
const values = Object.values(serializedRecord);
|
|
1637
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values);
|
|
1276
1638
|
const { sql, params } = query.build();
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
...trace,
|
|
1281
|
-
attributes: this.deserializeValue(trace.attributes, "jsonb"),
|
|
1282
|
-
status: this.deserializeValue(trace.status, "jsonb"),
|
|
1283
|
-
events: this.deserializeValue(trace.events, "jsonb"),
|
|
1284
|
-
links: this.deserializeValue(trace.links, "jsonb"),
|
|
1285
|
-
other: this.deserializeValue(trace.other, "jsonb")
|
|
1286
|
-
})
|
|
1287
|
-
) : [];
|
|
1639
|
+
await this.operations.executeQuery({ sql, params });
|
|
1640
|
+
const scoreFromDb = await this.getScoreById({ id });
|
|
1641
|
+
return { score: scoreFromDb };
|
|
1288
1642
|
} catch (error) {
|
|
1289
|
-
|
|
1643
|
+
throw new MastraError(
|
|
1290
1644
|
{
|
|
1291
|
-
id: "
|
|
1645
|
+
id: "CLOUDFLARE_D1_STORE_SCORES_SAVE_SCORE_FAILED",
|
|
1292
1646
|
domain: ErrorDomain.STORAGE,
|
|
1293
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1294
|
-
text: `Failed to retrieve traces: ${error instanceof Error ? error.message : String(error)}`,
|
|
1295
|
-
details: {
|
|
1296
|
-
name: name ?? "",
|
|
1297
|
-
scope: scope ?? ""
|
|
1298
|
-
}
|
|
1647
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1299
1648
|
},
|
|
1300
1649
|
error
|
|
1301
1650
|
);
|
|
1302
|
-
this.logger?.error(mastraError.toString());
|
|
1303
|
-
this.logger?.trackException(mastraError);
|
|
1304
|
-
return [];
|
|
1305
1651
|
}
|
|
1306
1652
|
}
|
|
1307
|
-
async
|
|
1308
|
-
|
|
1309
|
-
|
|
1653
|
+
async getScoresByScorerId({
|
|
1654
|
+
scorerId,
|
|
1655
|
+
entityId,
|
|
1656
|
+
entityType,
|
|
1657
|
+
source,
|
|
1658
|
+
pagination
|
|
1659
|
+
}) {
|
|
1310
1660
|
try {
|
|
1311
|
-
const
|
|
1312
|
-
const countQuery = createSqlBuilder().count().from(fullTableName).where("
|
|
1313
|
-
if (
|
|
1314
|
-
|
|
1315
|
-
countQuery.andWhere("name LIKE ?", `%${name}%`);
|
|
1661
|
+
const fullTableName = this.operations.getTableName(TABLE_SCORERS);
|
|
1662
|
+
const countQuery = createSqlBuilder().count().from(fullTableName).where("scorerId = ?", scorerId);
|
|
1663
|
+
if (entityId) {
|
|
1664
|
+
countQuery.andWhere("entityId = ?", entityId);
|
|
1316
1665
|
}
|
|
1317
|
-
if (
|
|
1318
|
-
|
|
1319
|
-
countQuery.andWhere("scope = ?", scope);
|
|
1666
|
+
if (entityType) {
|
|
1667
|
+
countQuery.andWhere("entityType = ?", entityType);
|
|
1320
1668
|
}
|
|
1321
|
-
if (
|
|
1322
|
-
|
|
1323
|
-
dataQuery.jsonLike("attributes", key, value);
|
|
1324
|
-
countQuery.jsonLike("attributes", key, value);
|
|
1325
|
-
}
|
|
1669
|
+
if (source) {
|
|
1670
|
+
countQuery.andWhere("source = ?", source);
|
|
1326
1671
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1672
|
+
const countResult = await this.operations.executeQuery(countQuery.build());
|
|
1673
|
+
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1674
|
+
if (total === 0) {
|
|
1675
|
+
return {
|
|
1676
|
+
pagination: {
|
|
1677
|
+
total: 0,
|
|
1678
|
+
page: pagination.page,
|
|
1679
|
+
perPage: pagination.perPage,
|
|
1680
|
+
hasMore: false
|
|
1681
|
+
},
|
|
1682
|
+
scores: []
|
|
1683
|
+
};
|
|
1331
1684
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
countQuery.andWhere("createdAt <= ?", toDateStr);
|
|
1685
|
+
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("scorerId = ?", scorerId);
|
|
1686
|
+
if (entityId) {
|
|
1687
|
+
selectQuery.andWhere("entityId = ?", entityId);
|
|
1336
1688
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
links: this.deserializeValue(trace.links, "jsonb"),
|
|
1348
|
-
other: this.deserializeValue(trace.other, "jsonb")
|
|
1349
|
-
})
|
|
1350
|
-
) : [];
|
|
1689
|
+
if (entityType) {
|
|
1690
|
+
selectQuery.andWhere("entityType = ?", entityType);
|
|
1691
|
+
}
|
|
1692
|
+
if (source) {
|
|
1693
|
+
selectQuery.andWhere("source = ?", source);
|
|
1694
|
+
}
|
|
1695
|
+
selectQuery.limit(pagination.perPage).offset(pagination.page * pagination.perPage);
|
|
1696
|
+
const { sql, params } = selectQuery.build();
|
|
1697
|
+
const results = await this.operations.executeQuery({ sql, params });
|
|
1698
|
+
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1351
1699
|
return {
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1700
|
+
pagination: {
|
|
1701
|
+
total,
|
|
1702
|
+
page: pagination.page,
|
|
1703
|
+
perPage: pagination.perPage,
|
|
1704
|
+
hasMore: total > (pagination.page + 1) * pagination.perPage
|
|
1705
|
+
},
|
|
1706
|
+
scores
|
|
1357
1707
|
};
|
|
1358
1708
|
} catch (error) {
|
|
1359
|
-
|
|
1709
|
+
throw new MastraError(
|
|
1360
1710
|
{
|
|
1361
|
-
id: "
|
|
1711
|
+
id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
1362
1712
|
domain: ErrorDomain.STORAGE,
|
|
1363
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1364
|
-
text: `Failed to retrieve traces: ${error instanceof Error ? error.message : String(error)}`,
|
|
1365
|
-
details: { name: name ?? "", scope: scope ?? "" }
|
|
1713
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1366
1714
|
},
|
|
1367
1715
|
error
|
|
1368
1716
|
);
|
|
1369
|
-
this.logger?.error(mastraError.toString());
|
|
1370
|
-
this.logger?.trackException(mastraError);
|
|
1371
|
-
return { traces: [], total: 0, page, perPage, hasMore: false };
|
|
1372
1717
|
}
|
|
1373
1718
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
const fullTableName = this.getTableName(TABLE_EVALS);
|
|
1719
|
+
async getScoresByRunId({
|
|
1720
|
+
runId,
|
|
1721
|
+
pagination
|
|
1722
|
+
}) {
|
|
1379
1723
|
try {
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
}
|
|
1386
|
-
query.orderBy("created_at", "DESC");
|
|
1387
|
-
const { sql, params } = query.build();
|
|
1388
|
-
const results = await this.executeQuery({ sql, params });
|
|
1389
|
-
return isArrayOfRecords(results) ? results.map((row) => {
|
|
1390
|
-
const result = this.deserializeValue(row.result);
|
|
1391
|
-
const testInfo = row.test_info ? this.deserializeValue(row.test_info) : void 0;
|
|
1724
|
+
const fullTableName = this.operations.getTableName(TABLE_SCORERS);
|
|
1725
|
+
const countQuery = createSqlBuilder().count().from(fullTableName).where("runId = ?", runId);
|
|
1726
|
+
const countResult = await this.operations.executeQuery(countQuery.build());
|
|
1727
|
+
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1728
|
+
if (total === 0) {
|
|
1392
1729
|
return {
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
globalRunId: row.global_run_id || "",
|
|
1401
|
-
createdAt: row.created_at || "",
|
|
1402
|
-
testInfo
|
|
1730
|
+
pagination: {
|
|
1731
|
+
total: 0,
|
|
1732
|
+
page: pagination.page,
|
|
1733
|
+
perPage: pagination.perPage,
|
|
1734
|
+
hasMore: false
|
|
1735
|
+
},
|
|
1736
|
+
scores: []
|
|
1403
1737
|
};
|
|
1404
|
-
}
|
|
1738
|
+
}
|
|
1739
|
+
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("runId = ?", runId).limit(pagination.perPage).offset(pagination.page * pagination.perPage);
|
|
1740
|
+
const { sql, params } = selectQuery.build();
|
|
1741
|
+
const results = await this.operations.executeQuery({ sql, params });
|
|
1742
|
+
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1743
|
+
return {
|
|
1744
|
+
pagination: {
|
|
1745
|
+
total,
|
|
1746
|
+
page: pagination.page,
|
|
1747
|
+
perPage: pagination.perPage,
|
|
1748
|
+
hasMore: total > (pagination.page + 1) * pagination.perPage
|
|
1749
|
+
},
|
|
1750
|
+
scores
|
|
1751
|
+
};
|
|
1405
1752
|
} catch (error) {
|
|
1406
|
-
|
|
1753
|
+
throw new MastraError(
|
|
1407
1754
|
{
|
|
1408
|
-
id: "
|
|
1755
|
+
id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1409
1756
|
domain: ErrorDomain.STORAGE,
|
|
1410
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1411
|
-
text: `Failed to retrieve evals for agent ${agentName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1412
|
-
details: { agentName }
|
|
1757
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1413
1758
|
},
|
|
1414
1759
|
error
|
|
1415
1760
|
);
|
|
1416
|
-
this.logger?.error(mastraError.toString());
|
|
1417
|
-
this.logger?.trackException(mastraError);
|
|
1418
|
-
return [];
|
|
1419
1761
|
}
|
|
1420
1762
|
}
|
|
1421
|
-
async
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
if (agentName) {
|
|
1427
|
-
conditions.push(`agent_name = ?`);
|
|
1428
|
-
queryParams.push(agentName);
|
|
1429
|
-
}
|
|
1430
|
-
if (type === "test") {
|
|
1431
|
-
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
1432
|
-
} else if (type === "live") {
|
|
1433
|
-
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
1434
|
-
}
|
|
1435
|
-
if (fromDate) {
|
|
1436
|
-
conditions.push(`createdAt >= ?`);
|
|
1437
|
-
queryParams.push(this.serializeDate(fromDate));
|
|
1438
|
-
}
|
|
1439
|
-
if (toDate) {
|
|
1440
|
-
conditions.push(`createdAt <= ?`);
|
|
1441
|
-
queryParams.push(this.serializeDate(toDate));
|
|
1442
|
-
}
|
|
1443
|
-
const countQueryBuilder = createSqlBuilder().count().from(fullTableName);
|
|
1444
|
-
if (conditions.length > 0) {
|
|
1445
|
-
countQueryBuilder.where(conditions.join(" AND "), ...queryParams);
|
|
1446
|
-
}
|
|
1447
|
-
const { sql: countSql, params: countParams } = countQueryBuilder.build();
|
|
1763
|
+
async getScoresByEntityId({
|
|
1764
|
+
entityId,
|
|
1765
|
+
entityType,
|
|
1766
|
+
pagination
|
|
1767
|
+
}) {
|
|
1448
1768
|
try {
|
|
1449
|
-
const
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
});
|
|
1454
|
-
const total = Number(countResult?.count || 0);
|
|
1455
|
-
const currentOffset = page * perPage;
|
|
1769
|
+
const fullTableName = this.operations.getTableName(TABLE_SCORERS);
|
|
1770
|
+
const countQuery = createSqlBuilder().count().from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType);
|
|
1771
|
+
const countResult = await this.operations.executeQuery(countQuery.build());
|
|
1772
|
+
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1456
1773
|
if (total === 0) {
|
|
1457
1774
|
return {
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1775
|
+
pagination: {
|
|
1776
|
+
total: 0,
|
|
1777
|
+
page: pagination.page,
|
|
1778
|
+
perPage: pagination.perPage,
|
|
1779
|
+
hasMore: false
|
|
1780
|
+
},
|
|
1781
|
+
scores: []
|
|
1463
1782
|
};
|
|
1464
1783
|
}
|
|
1465
|
-
const
|
|
1466
|
-
|
|
1467
|
-
|
|
1784
|
+
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("entityId = ?", entityId).andWhere("entityType = ?", entityType).limit(pagination.perPage).offset(pagination.page * pagination.perPage);
|
|
1785
|
+
const { sql, params } = selectQuery.build();
|
|
1786
|
+
const results = await this.operations.executeQuery({ sql, params });
|
|
1787
|
+
const scores = Array.isArray(results) ? results.map(transformScoreRow) : [];
|
|
1788
|
+
return {
|
|
1789
|
+
pagination: {
|
|
1790
|
+
total,
|
|
1791
|
+
page: pagination.page,
|
|
1792
|
+
perPage: pagination.perPage,
|
|
1793
|
+
hasMore: total > (pagination.page + 1) * pagination.perPage
|
|
1794
|
+
},
|
|
1795
|
+
scores
|
|
1796
|
+
};
|
|
1797
|
+
} catch (error) {
|
|
1798
|
+
throw new MastraError(
|
|
1799
|
+
{
|
|
1800
|
+
id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1801
|
+
domain: ErrorDomain.STORAGE,
|
|
1802
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1803
|
+
},
|
|
1804
|
+
error
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
async getScoresBySpan({
|
|
1809
|
+
traceId,
|
|
1810
|
+
spanId,
|
|
1811
|
+
pagination
|
|
1812
|
+
}) {
|
|
1813
|
+
try {
|
|
1814
|
+
const fullTableName = this.operations.getTableName(TABLE_SCORERS);
|
|
1815
|
+
const countQuery = createSqlBuilder().count().from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId);
|
|
1816
|
+
const countResult = await this.operations.executeQuery(countQuery.build());
|
|
1817
|
+
const total = Array.isArray(countResult) ? Number(countResult?.[0]?.count ?? 0) : Number(countResult?.count ?? 0);
|
|
1818
|
+
if (total === 0) {
|
|
1819
|
+
return {
|
|
1820
|
+
pagination: {
|
|
1821
|
+
total: 0,
|
|
1822
|
+
page: pagination.page,
|
|
1823
|
+
perPage: pagination.perPage,
|
|
1824
|
+
hasMore: false
|
|
1825
|
+
},
|
|
1826
|
+
scores: []
|
|
1827
|
+
};
|
|
1468
1828
|
}
|
|
1469
|
-
|
|
1470
|
-
const
|
|
1471
|
-
const
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1829
|
+
const limit = pagination.perPage + 1;
|
|
1830
|
+
const selectQuery = createSqlBuilder().select("*").from(fullTableName).where("traceId = ?", traceId).andWhere("spanId = ?", spanId).orderBy("createdAt", "DESC").limit(limit).offset(pagination.page * pagination.perPage);
|
|
1831
|
+
const { sql, params } = selectQuery.build();
|
|
1832
|
+
const results = await this.operations.executeQuery({ sql, params });
|
|
1833
|
+
const rows = Array.isArray(results) ? results : [];
|
|
1834
|
+
const scores = rows.slice(0, pagination.perPage).map(transformScoreRow);
|
|
1835
|
+
return {
|
|
1836
|
+
pagination: {
|
|
1837
|
+
total,
|
|
1838
|
+
page: pagination.page,
|
|
1839
|
+
perPage: pagination.perPage,
|
|
1840
|
+
hasMore: rows.length > pagination.perPage
|
|
1841
|
+
},
|
|
1842
|
+
scores
|
|
1843
|
+
};
|
|
1844
|
+
} catch (error) {
|
|
1845
|
+
throw new MastraError(
|
|
1846
|
+
{
|
|
1847
|
+
id: "CLOUDFLARE_D1_STORE_SCORES_GET_SCORES_BY_SPAN_FAILED",
|
|
1848
|
+
domain: ErrorDomain.STORAGE,
|
|
1849
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1850
|
+
},
|
|
1851
|
+
error
|
|
1852
|
+
);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1856
|
+
var WorkflowsStorageD1 = class extends WorkflowsStorage {
|
|
1857
|
+
operations;
|
|
1858
|
+
constructor({ operations }) {
|
|
1859
|
+
super();
|
|
1860
|
+
this.operations = operations;
|
|
1861
|
+
}
|
|
1862
|
+
updateWorkflowResults({
|
|
1863
|
+
// workflowName,
|
|
1864
|
+
// runId,
|
|
1865
|
+
// stepId,
|
|
1866
|
+
// result,
|
|
1867
|
+
// runtimeContext,
|
|
1868
|
+
}) {
|
|
1869
|
+
throw new Error("Method not implemented.");
|
|
1870
|
+
}
|
|
1871
|
+
updateWorkflowState({
|
|
1872
|
+
// workflowName,
|
|
1873
|
+
// runId,
|
|
1874
|
+
// opts,
|
|
1875
|
+
}) {
|
|
1876
|
+
throw new Error("Method not implemented.");
|
|
1877
|
+
}
|
|
1878
|
+
async persistWorkflowSnapshot({
|
|
1879
|
+
workflowName,
|
|
1880
|
+
runId,
|
|
1881
|
+
resourceId,
|
|
1882
|
+
snapshot
|
|
1883
|
+
}) {
|
|
1884
|
+
const fullTableName = this.operations.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1885
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1886
|
+
const currentSnapshot = await this.operations.load({
|
|
1887
|
+
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
1888
|
+
keys: { workflow_name: workflowName, run_id: runId }
|
|
1889
|
+
});
|
|
1890
|
+
const persisting = currentSnapshot ? {
|
|
1891
|
+
...currentSnapshot,
|
|
1892
|
+
resourceId,
|
|
1893
|
+
snapshot: JSON.stringify(snapshot),
|
|
1894
|
+
updatedAt: now
|
|
1895
|
+
} : {
|
|
1896
|
+
workflow_name: workflowName,
|
|
1897
|
+
run_id: runId,
|
|
1898
|
+
resourceId,
|
|
1899
|
+
snapshot,
|
|
1900
|
+
createdAt: now,
|
|
1901
|
+
updatedAt: now
|
|
1902
|
+
};
|
|
1903
|
+
const processedRecord = await this.operations.processRecord(persisting);
|
|
1904
|
+
const columns = Object.keys(processedRecord);
|
|
1905
|
+
const values = Object.values(processedRecord);
|
|
1906
|
+
const updateMap = {
|
|
1907
|
+
snapshot: "excluded.snapshot",
|
|
1908
|
+
updatedAt: "excluded.updatedAt"
|
|
1909
|
+
};
|
|
1910
|
+
this.logger.debug("Persisting workflow snapshot", { workflowName, runId });
|
|
1911
|
+
const query = createSqlBuilder().insert(fullTableName, columns, values, ["workflow_name", "run_id"], updateMap);
|
|
1912
|
+
const { sql, params } = query.build();
|
|
1913
|
+
try {
|
|
1914
|
+
await this.operations.executeQuery({ sql, params });
|
|
1915
|
+
} catch (error) {
|
|
1916
|
+
throw new MastraError(
|
|
1917
|
+
{
|
|
1918
|
+
id: "CLOUDFLARE_D1_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_ERROR",
|
|
1919
|
+
domain: ErrorDomain.STORAGE,
|
|
1920
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1921
|
+
text: `Failed to persist workflow snapshot: ${error instanceof Error ? error.message : String(error)}`,
|
|
1922
|
+
details: { workflowName, runId }
|
|
1923
|
+
},
|
|
1924
|
+
error
|
|
1925
|
+
);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
async loadWorkflowSnapshot(params) {
|
|
1929
|
+
const { workflowName, runId } = params;
|
|
1930
|
+
this.logger.debug("Loading workflow snapshot", { workflowName, runId });
|
|
1931
|
+
try {
|
|
1932
|
+
const d = await this.operations.load({
|
|
1933
|
+
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
1934
|
+
keys: {
|
|
1935
|
+
workflow_name: workflowName,
|
|
1936
|
+
run_id: runId
|
|
1480
1937
|
}
|
|
1481
|
-
return {
|
|
1482
|
-
input: row.input,
|
|
1483
|
-
output: row.output,
|
|
1484
|
-
result,
|
|
1485
|
-
agentName: row.agent_name,
|
|
1486
|
-
metricName: row.metric_name,
|
|
1487
|
-
instructions: row.instructions,
|
|
1488
|
-
testInfo,
|
|
1489
|
-
globalRunId: row.global_run_id,
|
|
1490
|
-
runId: row.run_id,
|
|
1491
|
-
createdAt: row.createdAt
|
|
1492
|
-
};
|
|
1493
1938
|
});
|
|
1494
|
-
|
|
1495
|
-
return {
|
|
1496
|
-
evals,
|
|
1497
|
-
total,
|
|
1498
|
-
page,
|
|
1499
|
-
perPage,
|
|
1500
|
-
hasMore
|
|
1501
|
-
};
|
|
1939
|
+
return d ? d.snapshot : null;
|
|
1502
1940
|
} catch (error) {
|
|
1503
1941
|
throw new MastraError(
|
|
1504
1942
|
{
|
|
1505
|
-
id: "
|
|
1943
|
+
id: "CLOUDFLARE_D1_STORAGE_LOAD_WORKFLOW_SNAPSHOT_ERROR",
|
|
1506
1944
|
domain: ErrorDomain.STORAGE,
|
|
1507
1945
|
category: ErrorCategory.THIRD_PARTY,
|
|
1508
|
-
text: `Failed to
|
|
1509
|
-
details: {
|
|
1946
|
+
text: `Failed to load workflow snapshot: ${error instanceof Error ? error.message : String(error)}`,
|
|
1947
|
+
details: { workflowName, runId }
|
|
1510
1948
|
},
|
|
1511
1949
|
error
|
|
1512
1950
|
);
|
|
@@ -1525,17 +1963,11 @@ var D1Store = class extends MastraStorage {
|
|
|
1525
1963
|
workflowName: row.workflow_name,
|
|
1526
1964
|
runId: row.run_id,
|
|
1527
1965
|
snapshot: parsedSnapshot,
|
|
1528
|
-
createdAt:
|
|
1529
|
-
updatedAt:
|
|
1966
|
+
createdAt: ensureDate(row.createdAt),
|
|
1967
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
1530
1968
|
resourceId: row.resourceId
|
|
1531
1969
|
};
|
|
1532
1970
|
}
|
|
1533
|
-
async hasColumn(table, column) {
|
|
1534
|
-
const sql = `PRAGMA table_info(${table});`;
|
|
1535
|
-
const result = await this.executeQuery({ sql, params: [] });
|
|
1536
|
-
if (!result || !Array.isArray(result)) return false;
|
|
1537
|
-
return result.some((col) => col.name === column || col.name === column.toLowerCase());
|
|
1538
|
-
}
|
|
1539
1971
|
async getWorkflowRuns({
|
|
1540
1972
|
workflowName,
|
|
1541
1973
|
fromDate,
|
|
@@ -1544,13 +1976,13 @@ var D1Store = class extends MastraStorage {
|
|
|
1544
1976
|
offset,
|
|
1545
1977
|
resourceId
|
|
1546
1978
|
} = {}) {
|
|
1547
|
-
const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1979
|
+
const fullTableName = this.operations.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1548
1980
|
try {
|
|
1549
1981
|
const builder = createSqlBuilder().select().from(fullTableName);
|
|
1550
1982
|
const countBuilder = createSqlBuilder().count().from(fullTableName);
|
|
1551
1983
|
if (workflowName) builder.whereAnd("workflow_name = ?", workflowName);
|
|
1552
1984
|
if (resourceId) {
|
|
1553
|
-
const hasResourceId = await this.hasColumn(fullTableName, "resourceId");
|
|
1985
|
+
const hasResourceId = await this.operations.hasColumn(fullTableName, "resourceId");
|
|
1554
1986
|
if (hasResourceId) {
|
|
1555
1987
|
builder.whereAnd("resourceId = ?", resourceId);
|
|
1556
1988
|
countBuilder.whereAnd("resourceId = ?", resourceId);
|
|
@@ -1573,14 +2005,14 @@ var D1Store = class extends MastraStorage {
|
|
|
1573
2005
|
let total = 0;
|
|
1574
2006
|
if (limit !== void 0 && offset !== void 0) {
|
|
1575
2007
|
const { sql: countSql, params: countParams } = countBuilder.build();
|
|
1576
|
-
const countResult = await this.executeQuery({
|
|
2008
|
+
const countResult = await this.operations.executeQuery({
|
|
1577
2009
|
sql: countSql,
|
|
1578
2010
|
params: countParams,
|
|
1579
2011
|
first: true
|
|
1580
2012
|
});
|
|
1581
2013
|
total = Number(countResult?.count ?? 0);
|
|
1582
2014
|
}
|
|
1583
|
-
const results = await this.executeQuery({ sql, params });
|
|
2015
|
+
const results = await this.operations.executeQuery({ sql, params });
|
|
1584
2016
|
const runs = (isArrayOfRecords(results) ? results : []).map((row) => this.parseWorkflowRun(row));
|
|
1585
2017
|
return { runs, total: total || runs.length };
|
|
1586
2018
|
} catch (error) {
|
|
@@ -1603,7 +2035,7 @@ var D1Store = class extends MastraStorage {
|
|
|
1603
2035
|
runId,
|
|
1604
2036
|
workflowName
|
|
1605
2037
|
}) {
|
|
1606
|
-
const fullTableName = this.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
2038
|
+
const fullTableName = this.operations.getTableName(TABLE_WORKFLOW_SNAPSHOT);
|
|
1607
2039
|
try {
|
|
1608
2040
|
const conditions = [];
|
|
1609
2041
|
const params = [];
|
|
@@ -1617,7 +2049,7 @@ var D1Store = class extends MastraStorage {
|
|
|
1617
2049
|
}
|
|
1618
2050
|
const whereClause = conditions.length > 0 ? "WHERE " + conditions.join(" AND ") : "";
|
|
1619
2051
|
const sql = `SELECT * FROM ${fullTableName} ${whereClause} ORDER BY createdAt DESC LIMIT 1`;
|
|
1620
|
-
const result = await this.executeQuery({ sql, params, first: true });
|
|
2052
|
+
const result = await this.operations.executeQuery({ sql, params, first: true });
|
|
1621
2053
|
if (!result) return null;
|
|
1622
2054
|
return this.parseWorkflowRun(result);
|
|
1623
2055
|
} catch (error) {
|
|
@@ -1633,6 +2065,299 @@ var D1Store = class extends MastraStorage {
|
|
|
1633
2065
|
);
|
|
1634
2066
|
}
|
|
1635
2067
|
}
|
|
2068
|
+
};
|
|
2069
|
+
|
|
2070
|
+
// src/storage/index.ts
|
|
2071
|
+
var D1Store = class extends MastraStorage {
|
|
2072
|
+
client;
|
|
2073
|
+
binding;
|
|
2074
|
+
// D1Database binding
|
|
2075
|
+
tablePrefix;
|
|
2076
|
+
stores;
|
|
2077
|
+
/**
|
|
2078
|
+
* Creates a new D1Store instance
|
|
2079
|
+
* @param config Configuration for D1 access (either REST API or Workers Binding API)
|
|
2080
|
+
*/
|
|
2081
|
+
constructor(config) {
|
|
2082
|
+
try {
|
|
2083
|
+
super({ name: "D1" });
|
|
2084
|
+
if (config.tablePrefix && !/^[a-zA-Z0-9_]*$/.test(config.tablePrefix)) {
|
|
2085
|
+
throw new Error("Invalid tablePrefix: only letters, numbers, and underscores are allowed.");
|
|
2086
|
+
}
|
|
2087
|
+
this.tablePrefix = config.tablePrefix || "";
|
|
2088
|
+
if ("binding" in config) {
|
|
2089
|
+
if (!config.binding) {
|
|
2090
|
+
throw new Error("D1 binding is required when using Workers Binding API");
|
|
2091
|
+
}
|
|
2092
|
+
this.binding = config.binding;
|
|
2093
|
+
this.logger.info("Using D1 Workers Binding API");
|
|
2094
|
+
} else if ("client" in config) {
|
|
2095
|
+
if (!config.client) {
|
|
2096
|
+
throw new Error("D1 client is required when using D1ClientConfig");
|
|
2097
|
+
}
|
|
2098
|
+
this.client = config.client;
|
|
2099
|
+
this.logger.info("Using D1 Client");
|
|
2100
|
+
} else {
|
|
2101
|
+
if (!config.accountId || !config.databaseId || !config.apiToken) {
|
|
2102
|
+
throw new Error("accountId, databaseId, and apiToken are required when using REST API");
|
|
2103
|
+
}
|
|
2104
|
+
const cfClient = new Cloudflare({
|
|
2105
|
+
apiToken: config.apiToken
|
|
2106
|
+
});
|
|
2107
|
+
this.client = {
|
|
2108
|
+
query: ({ sql, params }) => {
|
|
2109
|
+
return cfClient.d1.database.query(config.databaseId, {
|
|
2110
|
+
account_id: config.accountId,
|
|
2111
|
+
sql,
|
|
2112
|
+
params
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
};
|
|
2116
|
+
this.logger.info("Using D1 REST API");
|
|
2117
|
+
}
|
|
2118
|
+
} catch (error) {
|
|
2119
|
+
throw new MastraError(
|
|
2120
|
+
{
|
|
2121
|
+
id: "CLOUDFLARE_D1_STORAGE_INITIALIZATION_ERROR",
|
|
2122
|
+
domain: ErrorDomain.STORAGE,
|
|
2123
|
+
category: ErrorCategory.SYSTEM,
|
|
2124
|
+
text: "Error initializing D1Store"
|
|
2125
|
+
},
|
|
2126
|
+
error
|
|
2127
|
+
);
|
|
2128
|
+
}
|
|
2129
|
+
const operations = new StoreOperationsD1({
|
|
2130
|
+
client: this.client,
|
|
2131
|
+
binding: this.binding,
|
|
2132
|
+
tablePrefix: this.tablePrefix
|
|
2133
|
+
});
|
|
2134
|
+
const scores = new ScoresStorageD1({
|
|
2135
|
+
operations
|
|
2136
|
+
});
|
|
2137
|
+
const legacyEvals = new LegacyEvalsStorageD1({
|
|
2138
|
+
operations
|
|
2139
|
+
});
|
|
2140
|
+
const workflows = new WorkflowsStorageD1({
|
|
2141
|
+
operations
|
|
2142
|
+
});
|
|
2143
|
+
const memory = new MemoryStorageD1({
|
|
2144
|
+
operations
|
|
2145
|
+
});
|
|
2146
|
+
this.stores = {
|
|
2147
|
+
operations,
|
|
2148
|
+
scores,
|
|
2149
|
+
legacyEvals,
|
|
2150
|
+
workflows,
|
|
2151
|
+
memory
|
|
2152
|
+
};
|
|
2153
|
+
}
|
|
2154
|
+
get supports() {
|
|
2155
|
+
return {
|
|
2156
|
+
selectByIncludeResourceScope: true,
|
|
2157
|
+
resourceWorkingMemory: true,
|
|
2158
|
+
hasColumn: true,
|
|
2159
|
+
createTable: true,
|
|
2160
|
+
deleteMessages: false,
|
|
2161
|
+
getScoresBySpan: true
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
async createTable({
|
|
2165
|
+
tableName,
|
|
2166
|
+
schema
|
|
2167
|
+
}) {
|
|
2168
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Alters table schema to add columns if they don't exist
|
|
2172
|
+
* @param tableName Name of the table
|
|
2173
|
+
* @param schema Schema of the table
|
|
2174
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
2175
|
+
*/
|
|
2176
|
+
async alterTable({
|
|
2177
|
+
tableName,
|
|
2178
|
+
schema,
|
|
2179
|
+
ifNotExists
|
|
2180
|
+
}) {
|
|
2181
|
+
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2182
|
+
}
|
|
2183
|
+
async clearTable({ tableName }) {
|
|
2184
|
+
return this.stores.operations.clearTable({ tableName });
|
|
2185
|
+
}
|
|
2186
|
+
async dropTable({ tableName }) {
|
|
2187
|
+
return this.stores.operations.dropTable({ tableName });
|
|
2188
|
+
}
|
|
2189
|
+
async hasColumn(table, column) {
|
|
2190
|
+
return this.stores.operations.hasColumn(table, column);
|
|
2191
|
+
}
|
|
2192
|
+
async insert({ tableName, record }) {
|
|
2193
|
+
return this.stores.operations.insert({ tableName, record });
|
|
2194
|
+
}
|
|
2195
|
+
async load({ tableName, keys }) {
|
|
2196
|
+
return this.stores.operations.load({ tableName, keys });
|
|
2197
|
+
}
|
|
2198
|
+
async getThreadById({ threadId }) {
|
|
2199
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
2200
|
+
}
|
|
2201
|
+
/**
|
|
2202
|
+
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
2203
|
+
*/
|
|
2204
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
2205
|
+
return this.stores.memory.getThreadsByResourceId({ resourceId });
|
|
2206
|
+
}
|
|
2207
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
2208
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2209
|
+
}
|
|
2210
|
+
async saveThread({ thread }) {
|
|
2211
|
+
return this.stores.memory.saveThread({ thread });
|
|
2212
|
+
}
|
|
2213
|
+
async updateThread({
|
|
2214
|
+
id,
|
|
2215
|
+
title,
|
|
2216
|
+
metadata
|
|
2217
|
+
}) {
|
|
2218
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2219
|
+
}
|
|
2220
|
+
async deleteThread({ threadId }) {
|
|
2221
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2222
|
+
}
|
|
2223
|
+
async saveMessages(args) {
|
|
2224
|
+
return this.stores.memory.saveMessages(args);
|
|
2225
|
+
}
|
|
2226
|
+
async getMessages({
|
|
2227
|
+
threadId,
|
|
2228
|
+
selectBy,
|
|
2229
|
+
format
|
|
2230
|
+
}) {
|
|
2231
|
+
return this.stores.memory.getMessages({ threadId, selectBy, format });
|
|
2232
|
+
}
|
|
2233
|
+
async getMessagesById({
|
|
2234
|
+
messageIds,
|
|
2235
|
+
format
|
|
2236
|
+
}) {
|
|
2237
|
+
return this.stores.memory.getMessagesById({ messageIds, format });
|
|
2238
|
+
}
|
|
2239
|
+
async getMessagesPaginated({
|
|
2240
|
+
threadId,
|
|
2241
|
+
selectBy,
|
|
2242
|
+
format
|
|
2243
|
+
}) {
|
|
2244
|
+
return this.stores.memory.getMessagesPaginated({ threadId, selectBy, format });
|
|
2245
|
+
}
|
|
2246
|
+
async updateWorkflowResults({
|
|
2247
|
+
workflowName,
|
|
2248
|
+
runId,
|
|
2249
|
+
stepId,
|
|
2250
|
+
result,
|
|
2251
|
+
runtimeContext
|
|
2252
|
+
}) {
|
|
2253
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
|
|
2254
|
+
}
|
|
2255
|
+
async updateWorkflowState({
|
|
2256
|
+
workflowName,
|
|
2257
|
+
runId,
|
|
2258
|
+
opts
|
|
2259
|
+
}) {
|
|
2260
|
+
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2261
|
+
}
|
|
2262
|
+
async persistWorkflowSnapshot({
|
|
2263
|
+
workflowName,
|
|
2264
|
+
runId,
|
|
2265
|
+
resourceId,
|
|
2266
|
+
snapshot
|
|
2267
|
+
}) {
|
|
2268
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2269
|
+
}
|
|
2270
|
+
async loadWorkflowSnapshot(params) {
|
|
2271
|
+
return this.stores.workflows.loadWorkflowSnapshot(params);
|
|
2272
|
+
}
|
|
2273
|
+
async getWorkflowRuns({
|
|
2274
|
+
workflowName,
|
|
2275
|
+
fromDate,
|
|
2276
|
+
toDate,
|
|
2277
|
+
limit,
|
|
2278
|
+
offset,
|
|
2279
|
+
resourceId
|
|
2280
|
+
} = {}) {
|
|
2281
|
+
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
2282
|
+
}
|
|
2283
|
+
async getWorkflowRunById({
|
|
2284
|
+
runId,
|
|
2285
|
+
workflowName
|
|
2286
|
+
}) {
|
|
2287
|
+
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2288
|
+
}
|
|
2289
|
+
/**
|
|
2290
|
+
* Insert multiple records in a batch operation
|
|
2291
|
+
* @param tableName The table to insert into
|
|
2292
|
+
* @param records The records to insert
|
|
2293
|
+
*/
|
|
2294
|
+
async batchInsert({ tableName, records }) {
|
|
2295
|
+
return this.stores.operations.batchInsert({ tableName, records });
|
|
2296
|
+
}
|
|
2297
|
+
/**
|
|
2298
|
+
* @deprecated use getEvals instead
|
|
2299
|
+
*/
|
|
2300
|
+
async getEvalsByAgentName(agentName, type) {
|
|
2301
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2302
|
+
}
|
|
2303
|
+
async getEvals(options) {
|
|
2304
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
2305
|
+
}
|
|
2306
|
+
async updateMessages(_args) {
|
|
2307
|
+
return this.stores.memory.updateMessages(_args);
|
|
2308
|
+
}
|
|
2309
|
+
async getResourceById({ resourceId }) {
|
|
2310
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2311
|
+
}
|
|
2312
|
+
async saveResource({ resource }) {
|
|
2313
|
+
return this.stores.memory.saveResource({ resource });
|
|
2314
|
+
}
|
|
2315
|
+
async updateResource({
|
|
2316
|
+
resourceId,
|
|
2317
|
+
workingMemory,
|
|
2318
|
+
metadata
|
|
2319
|
+
}) {
|
|
2320
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2321
|
+
}
|
|
2322
|
+
async getScoreById({ id: _id }) {
|
|
2323
|
+
return this.stores.scores.getScoreById({ id: _id });
|
|
2324
|
+
}
|
|
2325
|
+
async saveScore(_score) {
|
|
2326
|
+
return this.stores.scores.saveScore(_score);
|
|
2327
|
+
}
|
|
2328
|
+
async getScoresByRunId({
|
|
2329
|
+
runId: _runId,
|
|
2330
|
+
pagination: _pagination
|
|
2331
|
+
}) {
|
|
2332
|
+
return this.stores.scores.getScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2333
|
+
}
|
|
2334
|
+
async getScoresByEntityId({
|
|
2335
|
+
entityId: _entityId,
|
|
2336
|
+
entityType: _entityType,
|
|
2337
|
+
pagination: _pagination
|
|
2338
|
+
}) {
|
|
2339
|
+
return this.stores.scores.getScoresByEntityId({
|
|
2340
|
+
entityId: _entityId,
|
|
2341
|
+
entityType: _entityType,
|
|
2342
|
+
pagination: _pagination
|
|
2343
|
+
});
|
|
2344
|
+
}
|
|
2345
|
+
async getScoresByScorerId({
|
|
2346
|
+
scorerId,
|
|
2347
|
+
pagination,
|
|
2348
|
+
entityId,
|
|
2349
|
+
entityType,
|
|
2350
|
+
source
|
|
2351
|
+
}) {
|
|
2352
|
+
return this.stores.scores.getScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
|
|
2353
|
+
}
|
|
2354
|
+
async getScoresBySpan({
|
|
2355
|
+
traceId,
|
|
2356
|
+
spanId,
|
|
2357
|
+
pagination
|
|
2358
|
+
}) {
|
|
2359
|
+
return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination });
|
|
2360
|
+
}
|
|
1636
2361
|
/**
|
|
1637
2362
|
* Close the database connection
|
|
1638
2363
|
* No explicit cleanup needed for D1 in either REST or Workers Binding mode
|
|
@@ -1640,10 +2365,8 @@ var D1Store = class extends MastraStorage {
|
|
|
1640
2365
|
async close() {
|
|
1641
2366
|
this.logger.debug("Closing D1 connection");
|
|
1642
2367
|
}
|
|
1643
|
-
async updateMessages(_args) {
|
|
1644
|
-
this.logger.error("updateMessages is not yet implemented in CloudflareD1Store");
|
|
1645
|
-
throw new Error("Method not implemented");
|
|
1646
|
-
}
|
|
1647
2368
|
};
|
|
1648
2369
|
|
|
1649
2370
|
export { D1Store };
|
|
2371
|
+
//# sourceMappingURL=index.js.map
|
|
2372
|
+
//# sourceMappingURL=index.js.map
|