@dudousxd/nestjs-agent-store-drizzle 0.5.0 → 0.6.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.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
2
2
  import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
3
- import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, AgentPricingStore, GovernanceRange, ModelSpendRow, ActorSpendRow, ThreadSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, PendingApprovalRow, ToolStatRow, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
3
+ import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, AgentPricingStore, GovernanceRange, ModelSpendRow, ActorSpendRow, ThreadSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, PendingApprovalRow, ToolStatRow, GovernancePageQuery, ToolCallWhere, GovernancePage, ThreadWhere, RunWhere, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
4
4
  import { Type, DynamicModule } from '@nestjs/common';
5
5
 
6
6
  /**
@@ -2531,6 +2531,25 @@ declare class DrizzleGovernanceQueries implements AgentGovernanceQueries {
2531
2531
  * their final status); `null` when none did.
2532
2532
  */
2533
2533
  toolStats(range: GovernanceRange): Promise<ToolStatRow[]>;
2534
+ /**
2535
+ * Paged, filterable tool-call activity, newest-first (same ordering as {@link recentToolCalls}).
2536
+ * `toolType`/`status` values outside the known literals can never match a row — short-circuits to
2537
+ * an empty page rather than issuing a query. Joins `agent_message` unconditionally (like
2538
+ * `recentToolCalls`) to resolve `threadId` and to support the `threadId` filter.
2539
+ */
2540
+ toolCallsPage(query: GovernancePageQuery<ToolCallWhere>): Promise<GovernancePage<ToolCallActivityRow>>;
2541
+ /**
2542
+ * Paged, filterable thread activity, newest-first (same ordering as {@link recentThreads}).
2543
+ * `title` is a case-insensitive substring match via `lower(...)` on both sides (portable across
2544
+ * dialects, regardless of the underlying column collation). Soft-deleted threads are excluded,
2545
+ * mirroring `recentThreads`.
2546
+ */
2547
+ threadsPage(query: GovernancePageQuery<ThreadWhere>): Promise<GovernancePage<ThreadActivityRow>>;
2548
+ /**
2549
+ * Paged, filterable run activity, newest-first (same ordering as {@link recentRuns}). `status`
2550
+ * values outside the known literals can never match a row — short-circuits to an empty page.
2551
+ */
2552
+ runsPage(query: GovernancePageQuery<RunWhere>): Promise<GovernancePage<RecentRunRow>>;
2534
2553
  }
2535
2554
 
2536
2555
  /**
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
2
2
  import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
3
- import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, AgentPricingStore, GovernanceRange, ModelSpendRow, ActorSpendRow, ThreadSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, PendingApprovalRow, ToolStatRow, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
3
+ import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, AgentPricingStore, GovernanceRange, ModelSpendRow, ActorSpendRow, ThreadSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, PendingApprovalRow, ToolStatRow, GovernancePageQuery, ToolCallWhere, GovernancePage, ThreadWhere, RunWhere, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
4
4
  import { Type, DynamicModule } from '@nestjs/common';
5
5
 
6
6
  /**
@@ -2531,6 +2531,25 @@ declare class DrizzleGovernanceQueries implements AgentGovernanceQueries {
2531
2531
  * their final status); `null` when none did.
2532
2532
  */
2533
2533
  toolStats(range: GovernanceRange): Promise<ToolStatRow[]>;
2534
+ /**
2535
+ * Paged, filterable tool-call activity, newest-first (same ordering as {@link recentToolCalls}).
2536
+ * `toolType`/`status` values outside the known literals can never match a row — short-circuits to
2537
+ * an empty page rather than issuing a query. Joins `agent_message` unconditionally (like
2538
+ * `recentToolCalls`) to resolve `threadId` and to support the `threadId` filter.
2539
+ */
2540
+ toolCallsPage(query: GovernancePageQuery<ToolCallWhere>): Promise<GovernancePage<ToolCallActivityRow>>;
2541
+ /**
2542
+ * Paged, filterable thread activity, newest-first (same ordering as {@link recentThreads}).
2543
+ * `title` is a case-insensitive substring match via `lower(...)` on both sides (portable across
2544
+ * dialects, regardless of the underlying column collation). Soft-deleted threads are excluded,
2545
+ * mirroring `recentThreads`.
2546
+ */
2547
+ threadsPage(query: GovernancePageQuery<ThreadWhere>): Promise<GovernancePage<ThreadActivityRow>>;
2548
+ /**
2549
+ * Paged, filterable run activity, newest-first (same ordering as {@link recentRuns}). `status`
2550
+ * values outside the known literals can never match a row — short-circuits to an empty page.
2551
+ */
2552
+ runsPage(query: GovernancePageQuery<RunWhere>): Promise<GovernancePage<RecentRunRow>>;
2534
2553
  }
2535
2554
 
2536
2555
  /**
package/dist/index.js CHANGED
@@ -550,9 +550,61 @@ var DrizzleAgentStore = class {
550
550
 
551
551
  // src/drizzle-governance-queries.ts
552
552
  import { bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc } from "@dudousxd/nestjs-agent-core";
553
- import { and as and2, count, desc as desc2, eq as eq2, gte as gte2, inArray as inArray2, isNull as isNull2, lte as lte2 } from "drizzle-orm";
553
+ import { and as and2, count, desc as desc2, eq as eq2, gte as gte2, inArray as inArray2, isNull as isNull2, like, lte as lte2, sql as sql3 } from "drizzle-orm";
554
554
  var UNCLASSIFIED_ERROR_CODE = "unknown";
555
555
  var DEFAULT_AGENT_BUCKET = "(default)";
556
+ var TOOL_CALL_STATUSES = [
557
+ "auto_executed",
558
+ "pending_approval",
559
+ "executed",
560
+ "rejected",
561
+ "failed"
562
+ ];
563
+ function isToolCallStatus(value) {
564
+ return TOOL_CALL_STATUSES.includes(value);
565
+ }
566
+ __name(isToolCallStatus, "isToolCallStatus");
567
+ var TOOL_KINDS = [
568
+ "read",
569
+ "action",
570
+ "agent"
571
+ ];
572
+ function isToolKind(value) {
573
+ return TOOL_KINDS.includes(value);
574
+ }
575
+ __name(isToolKind, "isToolKind");
576
+ var RUN_STATUSES = [
577
+ "running",
578
+ "completed",
579
+ "failed"
580
+ ];
581
+ function isRunStatus(value) {
582
+ return RUN_STATUSES.includes(value);
583
+ }
584
+ __name(isRunStatus, "isRunStatus");
585
+ function dayStartUtc(day) {
586
+ return dayBoundsUtc({
587
+ fromDay: day,
588
+ toDay: day
589
+ }).start;
590
+ }
591
+ __name(dayStartUtc, "dayStartUtc");
592
+ function dayEndUtc(day) {
593
+ return dayBoundsUtc({
594
+ fromDay: day,
595
+ toDay: day
596
+ }).end;
597
+ }
598
+ __name(dayEndUtc, "dayEndUtc");
599
+ function emptyPage(query) {
600
+ return {
601
+ rows: [],
602
+ total: 0,
603
+ page: query.page,
604
+ pageSize: query.pageSize
605
+ };
606
+ }
607
+ __name(emptyPage, "emptyPage");
556
608
  function toUsageInput(row) {
557
609
  return {
558
610
  modelId: row.modelId,
@@ -863,6 +915,115 @@ var DrizzleGovernanceQueries = class {
863
915
  result.sort((left, right) => right.calls - left.calls || left.toolName.localeCompare(right.toolName));
864
916
  return result;
865
917
  }
918
+ /**
919
+ * Paged, filterable tool-call activity, newest-first (same ordering as {@link recentToolCalls}).
920
+ * `toolType`/`status` values outside the known literals can never match a row — short-circuits to
921
+ * an empty page rather than issuing a query. Joins `agent_message` unconditionally (like
922
+ * `recentToolCalls`) to resolve `threadId` and to support the `threadId` filter.
923
+ */
924
+ async toolCallsPage(query) {
925
+ const filters = query.where;
926
+ if (filters?.status !== void 0 && !isToolCallStatus(filters.status)) {
927
+ return emptyPage(query);
928
+ }
929
+ if (filters?.toolType !== void 0 && !isToolKind(filters.toolType)) {
930
+ return emptyPage(query);
931
+ }
932
+ const whereClause = and2(filters?.toolName !== void 0 ? eq2(agentToolCall.toolName, filters.toolName) : void 0, filters?.toolType !== void 0 && isToolKind(filters.toolType) ? eq2(agentToolCall.toolType, filters.toolType) : void 0, filters?.status !== void 0 && isToolCallStatus(filters.status) ? eq2(agentToolCall.status, filters.status) : void 0, filters?.threadId !== void 0 ? eq2(agentMessage.threadId, filters.threadId) : void 0, filters?.fromDay !== void 0 ? gte2(agentToolCall.createdAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte2(agentToolCall.createdAt, dayEndUtc(filters.toDay)) : void 0);
933
+ const [totalRow] = await this.db.select({
934
+ value: count()
935
+ }).from(agentToolCall).innerJoin(agentMessage, eq2(agentToolCall.messageId, agentMessage.id)).where(whereClause);
936
+ const rows = await this.db.select({
937
+ toolCallId: agentToolCall.id,
938
+ toolName: agentToolCall.toolName,
939
+ toolType: agentToolCall.toolType,
940
+ status: agentToolCall.status,
941
+ threadId: agentMessage.threadId,
942
+ createdAt: agentToolCall.createdAt
943
+ }).from(agentToolCall).innerJoin(agentMessage, eq2(agentToolCall.messageId, agentMessage.id)).where(whereClause).orderBy(desc2(agentToolCall.createdAt), desc2(agentToolCall.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
944
+ return {
945
+ rows: rows.map((row) => ({
946
+ toolCallId: row.toolCallId,
947
+ toolName: row.toolName,
948
+ toolType: row.toolType,
949
+ status: row.status,
950
+ threadId: row.threadId,
951
+ createdAt: row.createdAt.toISOString()
952
+ })),
953
+ total: totalRow?.value ?? 0,
954
+ page: query.page,
955
+ pageSize: query.pageSize
956
+ };
957
+ }
958
+ /**
959
+ * Paged, filterable thread activity, newest-first (same ordering as {@link recentThreads}).
960
+ * `title` is a case-insensitive substring match via `lower(...)` on both sides (portable across
961
+ * dialects, regardless of the underlying column collation). Soft-deleted threads are excluded,
962
+ * mirroring `recentThreads`.
963
+ */
964
+ async threadsPage(query) {
965
+ const filters = query.where;
966
+ const whereClause = and2(isNull2(agentThread.deletedAt), filters?.actorRef !== void 0 ? eq2(agentThread.actorRef, filters.actorRef) : void 0, filters?.title !== void 0 ? like(sql3`lower(${agentThread.title})`, `%${filters.title.toLowerCase()}%`) : void 0, filters?.fromDay !== void 0 ? gte2(agentThread.updatedAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte2(agentThread.updatedAt, dayEndUtc(filters.toDay)) : void 0);
967
+ const [totalRow] = await this.db.select({
968
+ value: count()
969
+ }).from(agentThread).where(whereClause);
970
+ const threads = await this.db.select().from(agentThread).where(whereClause).orderBy(desc2(agentThread.updatedAt), desc2(agentThread.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
971
+ const rows = [];
972
+ for (const thread of threads) {
973
+ const [messageCountRow] = await this.db.select({
974
+ value: count()
975
+ }).from(agentMessage).where(eq2(agentMessage.threadId, thread.id));
976
+ const usageRows = await this.db.select().from(agentTokenUsage).where(eq2(agentTokenUsage.threadId, thread.id));
977
+ const totalTokens = usageRows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);
978
+ rows.push({
979
+ threadId: thread.id,
980
+ title: thread.title,
981
+ actorRef: thread.actorRef,
982
+ messageCount: messageCountRow?.value ?? 0,
983
+ totalTokens,
984
+ lastActivityAt: thread.updatedAt.toISOString()
985
+ });
986
+ }
987
+ return {
988
+ rows,
989
+ total: totalRow?.value ?? 0,
990
+ page: query.page,
991
+ pageSize: query.pageSize
992
+ };
993
+ }
994
+ /**
995
+ * Paged, filterable run activity, newest-first (same ordering as {@link recentRuns}). `status`
996
+ * values outside the known literals can never match a row — short-circuits to an empty page.
997
+ */
998
+ async runsPage(query) {
999
+ const filters = query.where;
1000
+ if (filters?.status !== void 0 && !isRunStatus(filters.status)) {
1001
+ return emptyPage(query);
1002
+ }
1003
+ const whereClause = and2(filters?.agentName !== void 0 ? eq2(agentRun.agentName, filters.agentName) : void 0, filters?.status !== void 0 && isRunStatus(filters.status) ? eq2(agentRun.status, filters.status) : void 0, filters?.errorCode !== void 0 ? eq2(agentRun.errorCode, filters.errorCode) : void 0, filters?.fromDay !== void 0 ? gte2(agentRun.startedAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte2(agentRun.startedAt, dayEndUtc(filters.toDay)) : void 0);
1004
+ const [totalRow] = await this.db.select({
1005
+ value: count()
1006
+ }).from(agentRun).where(whereClause);
1007
+ const runs = await this.db.select().from(agentRun).where(whereClause).orderBy(desc2(agentRun.startedAt), desc2(agentRun.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
1008
+ return {
1009
+ rows: runs.map((run) => ({
1010
+ runId: run.id,
1011
+ threadId: run.threadId,
1012
+ actorRef: run.actorRef,
1013
+ agentName: run.agentName ?? null,
1014
+ status: run.status,
1015
+ durationMs: run.durationMs ?? null,
1016
+ errorCode: run.errorCode ?? null,
1017
+ errorMessage: run.errorMessage ?? null,
1018
+ retries: run.retries,
1019
+ startedAt: run.startedAt.toISOString(),
1020
+ promptHash: run.promptHash ?? null
1021
+ })),
1022
+ total: totalRow?.value ?? 0,
1023
+ page: query.page,
1024
+ pageSize: query.pageSize
1025
+ };
1026
+ }
866
1027
  };
867
1028
 
868
1029
  // src/drizzle-pricing-store.ts