@dudousxd/nestjs-agent-store-drizzle 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -107,7 +107,9 @@ var agentToolCall = (0, import_sqlite_core.sqliteTable)("agent_tool_call", {
107
107
  }).notNull(),
108
108
  executedAt: (0, import_sqlite_core.integer)("executed_at", {
109
109
  mode: "timestamp_ms"
110
- })
110
+ }),
111
+ /** The run (turn) this call belongs to, for a trace deep-link; null for a pre-rollout row. */
112
+ runId: (0, import_sqlite_core.text)("run_id")
111
113
  });
112
114
  var agentTokenUsage = (0, import_sqlite_core.sqliteTable)("agent_token_usage", {
113
115
  id: (0, import_sqlite_core.text)("id").primaryKey(),
@@ -222,7 +224,8 @@ var statements = [
222
224
  execution_ms INTEGER,
223
225
  error TEXT,
224
226
  created_at INTEGER NOT NULL,
225
- executed_at INTEGER
227
+ executed_at INTEGER,
228
+ run_id TEXT
226
229
  )`,
227
230
  `CREATE TABLE IF NOT EXISTS agent_token_usage (
228
231
  id TEXT PRIMARY KEY NOT NULL,
@@ -495,7 +498,8 @@ var DrizzleAgentStore = class {
495
498
  executionMs: null,
496
499
  error: null,
497
500
  createdAt: /* @__PURE__ */ new Date(),
498
- executedAt: null
501
+ executedAt: null,
502
+ runId: input.runId ?? null
499
503
  });
500
504
  }
501
505
  async updateToolCall(input) {
@@ -588,6 +592,58 @@ var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
588
592
  var import_drizzle_orm3 = require("drizzle-orm");
589
593
  var UNCLASSIFIED_ERROR_CODE = "unknown";
590
594
  var DEFAULT_AGENT_BUCKET = "(default)";
595
+ var TOOL_CALL_STATUSES = [
596
+ "auto_executed",
597
+ "pending_approval",
598
+ "executed",
599
+ "rejected",
600
+ "failed"
601
+ ];
602
+ function isToolCallStatus(value) {
603
+ return TOOL_CALL_STATUSES.includes(value);
604
+ }
605
+ __name(isToolCallStatus, "isToolCallStatus");
606
+ var TOOL_KINDS = [
607
+ "read",
608
+ "action",
609
+ "agent"
610
+ ];
611
+ function isToolKind(value) {
612
+ return TOOL_KINDS.includes(value);
613
+ }
614
+ __name(isToolKind, "isToolKind");
615
+ var RUN_STATUSES = [
616
+ "running",
617
+ "completed",
618
+ "failed"
619
+ ];
620
+ function isRunStatus(value) {
621
+ return RUN_STATUSES.includes(value);
622
+ }
623
+ __name(isRunStatus, "isRunStatus");
624
+ function dayStartUtc(day) {
625
+ return (0, import_nestjs_agent_core.dayBoundsUtc)({
626
+ fromDay: day,
627
+ toDay: day
628
+ }).start;
629
+ }
630
+ __name(dayStartUtc, "dayStartUtc");
631
+ function dayEndUtc(day) {
632
+ return (0, import_nestjs_agent_core.dayBoundsUtc)({
633
+ fromDay: day,
634
+ toDay: day
635
+ }).end;
636
+ }
637
+ __name(dayEndUtc, "dayEndUtc");
638
+ function emptyPage(query) {
639
+ return {
640
+ rows: [],
641
+ total: 0,
642
+ page: query.page,
643
+ pageSize: query.pageSize
644
+ };
645
+ }
646
+ __name(emptyPage, "emptyPage");
591
647
  function toUsageInput(row) {
592
648
  return {
593
649
  modelId: row.modelId,
@@ -684,7 +740,8 @@ var DrizzleGovernanceQueries = class {
684
740
  toolType: agentToolCall.toolType,
685
741
  status: agentToolCall.status,
686
742
  threadId: agentMessage.threadId,
687
- createdAt: agentToolCall.createdAt
743
+ createdAt: agentToolCall.createdAt,
744
+ runId: agentToolCall.runId
688
745
  }).from(agentToolCall).innerJoin(agentMessage, (0, import_drizzle_orm3.eq)(agentToolCall.messageId, agentMessage.id)).orderBy((0, import_drizzle_orm3.desc)(agentToolCall.createdAt), (0, import_drizzle_orm3.desc)(agentToolCall.id)).limit(limit);
689
746
  return rows.map((row) => ({
690
747
  toolCallId: row.toolCallId,
@@ -692,7 +749,8 @@ var DrizzleGovernanceQueries = class {
692
749
  toolType: row.toolType,
693
750
  status: row.status,
694
751
  threadId: row.threadId,
695
- createdAt: row.createdAt.toISOString()
752
+ createdAt: row.createdAt.toISOString(),
753
+ runId: row.runId
696
754
  }));
697
755
  }
698
756
  async recentThreads(limit) {
@@ -843,7 +901,8 @@ var DrizzleGovernanceQueries = class {
843
901
  threadTitle: agentThread.title,
844
902
  actorRef: agentThread.actorRef,
845
903
  agentName: agentMessage.agentName,
846
- requestedAt: agentToolCall.createdAt
904
+ requestedAt: agentToolCall.createdAt,
905
+ runId: agentToolCall.runId
847
906
  }).from(agentToolCall).innerJoin(agentMessage, (0, import_drizzle_orm3.eq)(agentToolCall.messageId, agentMessage.id)).innerJoin(agentThread, (0, import_drizzle_orm3.eq)(agentMessage.threadId, agentThread.id)).where((0, import_drizzle_orm3.eq)(agentToolCall.status, "pending_approval")).orderBy(agentToolCall.createdAt, agentToolCall.id).limit(limit);
848
907
  return rows.map((row) => ({
849
908
  toolCallId: row.toolCallId,
@@ -853,7 +912,8 @@ var DrizzleGovernanceQueries = class {
853
912
  threadTitle: row.threadTitle,
854
913
  actorRef: row.actorRef,
855
914
  agentName: row.agentName ?? null,
856
- requestedAt: row.requestedAt.toISOString()
915
+ requestedAt: row.requestedAt.toISOString(),
916
+ runId: row.runId
857
917
  }));
858
918
  }
859
919
  /**
@@ -898,6 +958,117 @@ var DrizzleGovernanceQueries = class {
898
958
  result.sort((left, right) => right.calls - left.calls || left.toolName.localeCompare(right.toolName));
899
959
  return result;
900
960
  }
961
+ /**
962
+ * Paged, filterable tool-call activity, newest-first (same ordering as {@link recentToolCalls}).
963
+ * `toolType`/`status` values outside the known literals can never match a row — short-circuits to
964
+ * an empty page rather than issuing a query. Joins `agent_message` unconditionally (like
965
+ * `recentToolCalls`) to resolve `threadId` and to support the `threadId` filter.
966
+ */
967
+ async toolCallsPage(query) {
968
+ const filters = query.where;
969
+ if (filters?.status !== void 0 && !isToolCallStatus(filters.status)) {
970
+ return emptyPage(query);
971
+ }
972
+ if (filters?.toolType !== void 0 && !isToolKind(filters.toolType)) {
973
+ return emptyPage(query);
974
+ }
975
+ const whereClause = (0, import_drizzle_orm3.and)(filters?.toolName !== void 0 ? (0, import_drizzle_orm3.eq)(agentToolCall.toolName, filters.toolName) : void 0, filters?.toolType !== void 0 && isToolKind(filters.toolType) ? (0, import_drizzle_orm3.eq)(agentToolCall.toolType, filters.toolType) : void 0, filters?.status !== void 0 && isToolCallStatus(filters.status) ? (0, import_drizzle_orm3.eq)(agentToolCall.status, filters.status) : void 0, filters?.threadId !== void 0 ? (0, import_drizzle_orm3.eq)(agentMessage.threadId, filters.threadId) : void 0, filters?.fromDay !== void 0 ? (0, import_drizzle_orm3.gte)(agentToolCall.createdAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? (0, import_drizzle_orm3.lte)(agentToolCall.createdAt, dayEndUtc(filters.toDay)) : void 0);
976
+ const [totalRow] = await this.db.select({
977
+ value: (0, import_drizzle_orm3.count)()
978
+ }).from(agentToolCall).innerJoin(agentMessage, (0, import_drizzle_orm3.eq)(agentToolCall.messageId, agentMessage.id)).where(whereClause);
979
+ const rows = await this.db.select({
980
+ toolCallId: agentToolCall.id,
981
+ toolName: agentToolCall.toolName,
982
+ toolType: agentToolCall.toolType,
983
+ status: agentToolCall.status,
984
+ threadId: agentMessage.threadId,
985
+ createdAt: agentToolCall.createdAt,
986
+ runId: agentToolCall.runId
987
+ }).from(agentToolCall).innerJoin(agentMessage, (0, import_drizzle_orm3.eq)(agentToolCall.messageId, agentMessage.id)).where(whereClause).orderBy((0, import_drizzle_orm3.desc)(agentToolCall.createdAt), (0, import_drizzle_orm3.desc)(agentToolCall.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
988
+ return {
989
+ rows: rows.map((row) => ({
990
+ toolCallId: row.toolCallId,
991
+ toolName: row.toolName,
992
+ toolType: row.toolType,
993
+ status: row.status,
994
+ threadId: row.threadId,
995
+ createdAt: row.createdAt.toISOString(),
996
+ runId: row.runId
997
+ })),
998
+ total: totalRow?.value ?? 0,
999
+ page: query.page,
1000
+ pageSize: query.pageSize
1001
+ };
1002
+ }
1003
+ /**
1004
+ * Paged, filterable thread activity, newest-first (same ordering as {@link recentThreads}).
1005
+ * `title` is a case-insensitive substring match via `lower(...)` on both sides (portable across
1006
+ * dialects, regardless of the underlying column collation). Soft-deleted threads are excluded,
1007
+ * mirroring `recentThreads`.
1008
+ */
1009
+ async threadsPage(query) {
1010
+ const filters = query.where;
1011
+ const whereClause = (0, import_drizzle_orm3.and)((0, import_drizzle_orm3.isNull)(agentThread.deletedAt), filters?.actorRef !== void 0 ? (0, import_drizzle_orm3.eq)(agentThread.actorRef, filters.actorRef) : void 0, filters?.title !== void 0 ? (0, import_drizzle_orm3.like)(import_drizzle_orm3.sql`lower(${agentThread.title})`, `%${filters.title.toLowerCase()}%`) : void 0, filters?.fromDay !== void 0 ? (0, import_drizzle_orm3.gte)(agentThread.updatedAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? (0, import_drizzle_orm3.lte)(agentThread.updatedAt, dayEndUtc(filters.toDay)) : void 0);
1012
+ const [totalRow] = await this.db.select({
1013
+ value: (0, import_drizzle_orm3.count)()
1014
+ }).from(agentThread).where(whereClause);
1015
+ const threads = await this.db.select().from(agentThread).where(whereClause).orderBy((0, import_drizzle_orm3.desc)(agentThread.updatedAt), (0, import_drizzle_orm3.desc)(agentThread.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
1016
+ const rows = [];
1017
+ for (const thread of threads) {
1018
+ const [messageCountRow] = await this.db.select({
1019
+ value: (0, import_drizzle_orm3.count)()
1020
+ }).from(agentMessage).where((0, import_drizzle_orm3.eq)(agentMessage.threadId, thread.id));
1021
+ const usageRows = await this.db.select().from(agentTokenUsage).where((0, import_drizzle_orm3.eq)(agentTokenUsage.threadId, thread.id));
1022
+ const totalTokens = usageRows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);
1023
+ rows.push({
1024
+ threadId: thread.id,
1025
+ title: thread.title,
1026
+ actorRef: thread.actorRef,
1027
+ messageCount: messageCountRow?.value ?? 0,
1028
+ totalTokens,
1029
+ lastActivityAt: thread.updatedAt.toISOString()
1030
+ });
1031
+ }
1032
+ return {
1033
+ rows,
1034
+ total: totalRow?.value ?? 0,
1035
+ page: query.page,
1036
+ pageSize: query.pageSize
1037
+ };
1038
+ }
1039
+ /**
1040
+ * Paged, filterable run activity, newest-first (same ordering as {@link recentRuns}). `status`
1041
+ * values outside the known literals can never match a row — short-circuits to an empty page.
1042
+ */
1043
+ async runsPage(query) {
1044
+ const filters = query.where;
1045
+ if (filters?.status !== void 0 && !isRunStatus(filters.status)) {
1046
+ return emptyPage(query);
1047
+ }
1048
+ const whereClause = (0, import_drizzle_orm3.and)(filters?.agentName !== void 0 ? (0, import_drizzle_orm3.eq)(agentRun.agentName, filters.agentName) : void 0, filters?.status !== void 0 && isRunStatus(filters.status) ? (0, import_drizzle_orm3.eq)(agentRun.status, filters.status) : void 0, filters?.errorCode !== void 0 ? (0, import_drizzle_orm3.eq)(agentRun.errorCode, filters.errorCode) : void 0, filters?.threadId !== void 0 ? (0, import_drizzle_orm3.eq)(agentRun.threadId, filters.threadId) : void 0, filters?.fromDay !== void 0 ? (0, import_drizzle_orm3.gte)(agentRun.startedAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? (0, import_drizzle_orm3.lte)(agentRun.startedAt, dayEndUtc(filters.toDay)) : void 0);
1049
+ const [totalRow] = await this.db.select({
1050
+ value: (0, import_drizzle_orm3.count)()
1051
+ }).from(agentRun).where(whereClause);
1052
+ const runs = await this.db.select().from(agentRun).where(whereClause).orderBy((0, import_drizzle_orm3.desc)(agentRun.startedAt), (0, import_drizzle_orm3.desc)(agentRun.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
1053
+ return {
1054
+ rows: runs.map((run) => ({
1055
+ runId: run.id,
1056
+ threadId: run.threadId,
1057
+ actorRef: run.actorRef,
1058
+ agentName: run.agentName ?? null,
1059
+ status: run.status,
1060
+ durationMs: run.durationMs ?? null,
1061
+ errorCode: run.errorCode ?? null,
1062
+ errorMessage: run.errorMessage ?? null,
1063
+ retries: run.retries,
1064
+ startedAt: run.startedAt.toISOString(),
1065
+ promptHash: run.promptHash ?? null
1066
+ })),
1067
+ total: totalRow?.value ?? 0,
1068
+ page: query.page,
1069
+ pageSize: query.pageSize
1070
+ };
1071
+ }
901
1072
  };
902
1073
 
903
1074
  // src/drizzle-pricing-store.ts