@dudousxd/nestjs-agent-store-drizzle 0.18.3 → 0.19.1
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/README.md +17 -0
- package/dist/index.cjs +210 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +523 -3
- package/dist/index.d.ts +523 -3
- package/dist/index.js +212 -3
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -16,6 +16,10 @@ var agentThread = sqliteTable("agent_thread", {
|
|
|
16
16
|
defaultAgent: text("default_agent"),
|
|
17
17
|
/** The model every turn on this thread runs on unless the send names one; `null` → default. */
|
|
18
18
|
model: text("model"),
|
|
19
|
+
/** Why the thread's message queue stopped draining; `null` → it drains. */
|
|
20
|
+
queuePause: text("queue_pause", {
|
|
21
|
+
mode: "json"
|
|
22
|
+
}).$type(),
|
|
19
23
|
createdAt: integer("created_at", {
|
|
20
24
|
mode: "timestamp_ms"
|
|
21
25
|
}).notNull(),
|
|
@@ -109,6 +113,37 @@ var agentToolCall = sqliteTable("agent_tool_call", {
|
|
|
109
113
|
}, (table) => [
|
|
110
114
|
index("agent_tool_call_message_idx").on(table.messageId)
|
|
111
115
|
]);
|
|
116
|
+
var agentQueuedMessage = sqliteTable("agent_queued_message", {
|
|
117
|
+
id: text("id").primaryKey(),
|
|
118
|
+
threadId: text("thread_id").notNull().references(() => agentThread.id, {
|
|
119
|
+
onDelete: "cascade"
|
|
120
|
+
}),
|
|
121
|
+
/** Who queued it — the turn it starts runs as this actor. */
|
|
122
|
+
actor: text("actor", {
|
|
123
|
+
mode: "json"
|
|
124
|
+
}).$type().notNull(),
|
|
125
|
+
content: text("content").notNull(),
|
|
126
|
+
attachments: text("attachments", {
|
|
127
|
+
mode: "json"
|
|
128
|
+
}).$type(),
|
|
129
|
+
agentName: text("agent_name"),
|
|
130
|
+
model: text("model"),
|
|
131
|
+
pageContext: text("page_context", {
|
|
132
|
+
mode: "json"
|
|
133
|
+
}).$type(),
|
|
134
|
+
interrupt: integer("interrupt", {
|
|
135
|
+
mode: "boolean"
|
|
136
|
+
}).notNull().default(false),
|
|
137
|
+
position: integer("position").notNull(),
|
|
138
|
+
createdAt: integer("created_at", {
|
|
139
|
+
mode: "timestamp_ms"
|
|
140
|
+
}).notNull(),
|
|
141
|
+
updatedAt: integer("updated_at", {
|
|
142
|
+
mode: "timestamp_ms"
|
|
143
|
+
}).notNull()
|
|
144
|
+
}, (table) => [
|
|
145
|
+
index("agent_queued_message_thread_position_idx").on(table.threadId, table.position)
|
|
146
|
+
]);
|
|
112
147
|
var agentTokenUsage = sqliteTable("agent_token_usage", {
|
|
113
148
|
id: text("id").primaryKey(),
|
|
114
149
|
threadId: text("thread_id").notNull().references(() => agentThread.id, {
|
|
@@ -234,6 +269,7 @@ var ragIngestionLog = sqliteTable("rag_ingestion_log", {
|
|
|
234
269
|
var agentSchema = {
|
|
235
270
|
agentThread,
|
|
236
271
|
agentMessage,
|
|
272
|
+
agentQueuedMessage,
|
|
237
273
|
agentToolCall,
|
|
238
274
|
agentTokenUsage,
|
|
239
275
|
agentModelPricing,
|
|
@@ -254,6 +290,7 @@ var statements = [
|
|
|
254
290
|
active_stream_id TEXT,
|
|
255
291
|
default_agent TEXT,
|
|
256
292
|
model TEXT,
|
|
293
|
+
queue_pause TEXT,
|
|
257
294
|
created_at INTEGER NOT NULL,
|
|
258
295
|
updated_at INTEGER NOT NULL,
|
|
259
296
|
deleted_at INTEGER
|
|
@@ -280,6 +317,22 @@ var statements = [
|
|
|
280
317
|
)`,
|
|
281
318
|
`CREATE INDEX IF NOT EXISTS agent_message_thread_created_idx
|
|
282
319
|
ON agent_message (thread_id, created_at)`,
|
|
320
|
+
`CREATE TABLE IF NOT EXISTS agent_queued_message (
|
|
321
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
322
|
+
thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,
|
|
323
|
+
actor TEXT NOT NULL,
|
|
324
|
+
content TEXT NOT NULL,
|
|
325
|
+
attachments TEXT,
|
|
326
|
+
agent_name TEXT,
|
|
327
|
+
model TEXT,
|
|
328
|
+
page_context TEXT,
|
|
329
|
+
interrupt INTEGER NOT NULL DEFAULT 0,
|
|
330
|
+
position INTEGER NOT NULL,
|
|
331
|
+
created_at INTEGER NOT NULL,
|
|
332
|
+
updated_at INTEGER NOT NULL
|
|
333
|
+
)`,
|
|
334
|
+
`CREATE INDEX IF NOT EXISTS agent_queued_message_thread_position_idx
|
|
335
|
+
ON agent_queued_message (thread_id, position)`,
|
|
283
336
|
`CREATE TABLE IF NOT EXISTS agent_tool_call (
|
|
284
337
|
id TEXT PRIMARY KEY NOT NULL,
|
|
285
338
|
message_id TEXT NOT NULL REFERENCES agent_message(id) ON DELETE CASCADE,
|
|
@@ -440,6 +493,11 @@ var additiveColumns = [
|
|
|
440
493
|
column: "remember",
|
|
441
494
|
ddl: "ALTER TABLE agent_tool_call ADD COLUMN remember INTEGER"
|
|
442
495
|
},
|
|
496
|
+
{
|
|
497
|
+
table: "agent_thread",
|
|
498
|
+
column: "queue_pause",
|
|
499
|
+
ddl: "ALTER TABLE agent_thread ADD COLUMN queue_pause TEXT"
|
|
500
|
+
},
|
|
443
501
|
{
|
|
444
502
|
table: "agent_tool_call",
|
|
445
503
|
column: "decided_via",
|
|
@@ -461,7 +519,7 @@ __name(ensureAgentSchema, "ensureAgentSchema");
|
|
|
461
519
|
|
|
462
520
|
// src/drizzle-agent-store.ts
|
|
463
521
|
import { toolCallApprovalFromRow } from "@dudousxd/nestjs-agent-core";
|
|
464
|
-
import { and, asc, desc, eq, gte, inArray, isNotNull, isNull, lte, sql as sql2 } from "drizzle-orm";
|
|
522
|
+
import { and, asc, desc, eq, gte, inArray, isNotNull, isNull, lte, max, min, or, sql as sql2 } from "drizzle-orm";
|
|
465
523
|
var TURN_MESSAGE_COLUMNS = {
|
|
466
524
|
id: agentMessage.id,
|
|
467
525
|
role: agentMessage.role,
|
|
@@ -491,6 +549,7 @@ var DrizzleAgentStore = class {
|
|
|
491
549
|
activeStreamId: null,
|
|
492
550
|
defaultAgent: null,
|
|
493
551
|
model: null,
|
|
552
|
+
queuePause: null,
|
|
494
553
|
createdAt: now,
|
|
495
554
|
updatedAt: now,
|
|
496
555
|
deletedAt: null
|
|
@@ -597,6 +656,8 @@ var DrizzleAgentStore = class {
|
|
|
597
656
|
activeStreamId: null,
|
|
598
657
|
defaultAgent: source.defaultAgent,
|
|
599
658
|
model: source.model,
|
|
659
|
+
// A fork is a new conversation: nothing is waiting on it, and nothing is paused.
|
|
660
|
+
queuePause: null,
|
|
600
661
|
createdAt: now,
|
|
601
662
|
updatedAt: now,
|
|
602
663
|
deletedAt: null
|
|
@@ -726,6 +787,127 @@ var DrizzleAgentStore = class {
|
|
|
726
787
|
updatedAt: /* @__PURE__ */ new Date()
|
|
727
788
|
}).where(and(eq(agentThread.id, threadId), eq(agentThread.transient, true)));
|
|
728
789
|
}
|
|
790
|
+
/** The run streaming the thread, or `null` — a projection of the one column. */
|
|
791
|
+
async activeRunForThread(threadId) {
|
|
792
|
+
const [thread] = await this.db.select({
|
|
793
|
+
activeStreamId: agentThread.activeStreamId
|
|
794
|
+
}).from(agentThread).where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));
|
|
795
|
+
return thread?.activeStreamId ?? null;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* One conditional UPDATE, so of two racing claims exactly one changes the row: set the holder to
|
|
799
|
+
* `runId` only when there is none, it is already `runId`, or it is `replacing`.
|
|
800
|
+
*/
|
|
801
|
+
async claimActiveStream(threadId, runId, options = {}) {
|
|
802
|
+
const holders = [
|
|
803
|
+
isNull(agentThread.activeStreamId),
|
|
804
|
+
eq(agentThread.activeStreamId, runId),
|
|
805
|
+
...options.replacing !== void 0 ? [
|
|
806
|
+
eq(agentThread.activeStreamId, options.replacing)
|
|
807
|
+
] : []
|
|
808
|
+
];
|
|
809
|
+
const claimed = await this.db.update(agentThread).set({
|
|
810
|
+
activeStreamId: runId
|
|
811
|
+
}).where(and(eq(agentThread.id, threadId), or(...holders))).returning({
|
|
812
|
+
id: agentThread.id
|
|
813
|
+
});
|
|
814
|
+
return claimed.length > 0;
|
|
815
|
+
}
|
|
816
|
+
async releaseActiveStream(threadId, runId) {
|
|
817
|
+
const released = await this.db.update(agentThread).set({
|
|
818
|
+
activeStreamId: null
|
|
819
|
+
}).where(and(eq(agentThread.id, threadId), eq(agentThread.activeStreamId, runId))).returning({
|
|
820
|
+
id: agentThread.id
|
|
821
|
+
});
|
|
822
|
+
return released.length > 0;
|
|
823
|
+
}
|
|
824
|
+
async enqueueMessage(input) {
|
|
825
|
+
const now = /* @__PURE__ */ new Date();
|
|
826
|
+
const [edge] = await this.db.select({
|
|
827
|
+
first: min(agentQueuedMessage.position),
|
|
828
|
+
last: max(agentQueuedMessage.position)
|
|
829
|
+
}).from(agentQueuedMessage).where(eq(agentQueuedMessage.threadId, input.threadId));
|
|
830
|
+
const position = input.at === "head" ? (edge?.first ?? 1) - 1 : (edge?.last ?? -1) + 1;
|
|
831
|
+
const row = {
|
|
832
|
+
id: crypto.randomUUID(),
|
|
833
|
+
threadId: input.threadId,
|
|
834
|
+
actor: input.actor,
|
|
835
|
+
content: input.content,
|
|
836
|
+
attachments: input.attachments !== void 0 && input.attachments.length > 0 ? input.attachments : null,
|
|
837
|
+
agentName: input.agentName ?? null,
|
|
838
|
+
model: input.model ?? null,
|
|
839
|
+
pageContext: input.pageContext ?? null,
|
|
840
|
+
interrupt: input.interrupt === true,
|
|
841
|
+
position,
|
|
842
|
+
createdAt: now,
|
|
843
|
+
updatedAt: now
|
|
844
|
+
};
|
|
845
|
+
await this.db.insert(agentQueuedMessage).values(row);
|
|
846
|
+
return toQueuedMessage(row);
|
|
847
|
+
}
|
|
848
|
+
async listQueue(threadId) {
|
|
849
|
+
const rows = await this.db.select().from(agentQueuedMessage).where(eq(agentQueuedMessage.threadId, threadId)).orderBy(asc(agentQueuedMessage.position), asc(agentQueuedMessage.createdAt));
|
|
850
|
+
return rows.map(toQueuedMessage);
|
|
851
|
+
}
|
|
852
|
+
async getQueuedMessage(id) {
|
|
853
|
+
const [row] = await this.db.select().from(agentQueuedMessage).where(eq(agentQueuedMessage.id, id));
|
|
854
|
+
return row === void 0 ? null : toQueuedMessage(row);
|
|
855
|
+
}
|
|
856
|
+
async updateQueuedMessage(id, patch) {
|
|
857
|
+
const updates = {
|
|
858
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
859
|
+
};
|
|
860
|
+
if (patch.content !== void 0) {
|
|
861
|
+
updates.content = patch.content;
|
|
862
|
+
}
|
|
863
|
+
if (patch.attachments !== void 0) {
|
|
864
|
+
updates.attachments = patch.attachments === null || patch.attachments.length === 0 ? null : patch.attachments;
|
|
865
|
+
}
|
|
866
|
+
if (patch.interrupt !== void 0) {
|
|
867
|
+
updates.interrupt = patch.interrupt;
|
|
868
|
+
}
|
|
869
|
+
await this.db.update(agentQueuedMessage).set(updates).where(eq(agentQueuedMessage.id, id));
|
|
870
|
+
return this.getQueuedMessage(id);
|
|
871
|
+
}
|
|
872
|
+
/** Rewrites the thread's positions as 0..n-1 in the new order — a queue is a handful of rows. */
|
|
873
|
+
async moveQueuedMessage(id, index2) {
|
|
874
|
+
const moving = await this.getQueuedMessage(id);
|
|
875
|
+
if (moving === null) {
|
|
876
|
+
return false;
|
|
877
|
+
}
|
|
878
|
+
const order = (await this.listQueue(moving.threadId)).filter((message) => message.id !== id);
|
|
879
|
+
const target = Math.max(0, Math.min(order.length, Math.trunc(index2)));
|
|
880
|
+
order.splice(target, 0, moving);
|
|
881
|
+
for (const [position, message] of order.entries()) {
|
|
882
|
+
await this.db.update(agentQueuedMessage).set({
|
|
883
|
+
position
|
|
884
|
+
}).where(eq(agentQueuedMessage.id, message.id));
|
|
885
|
+
}
|
|
886
|
+
return true;
|
|
887
|
+
}
|
|
888
|
+
async removeQueuedMessage(id) {
|
|
889
|
+
const removed = await this.db.delete(agentQueuedMessage).where(eq(agentQueuedMessage.id, id)).returning({
|
|
890
|
+
id: agentQueuedMessage.id
|
|
891
|
+
});
|
|
892
|
+
return removed.length > 0;
|
|
893
|
+
}
|
|
894
|
+
async clearQueue(threadId) {
|
|
895
|
+
const removed = await this.db.delete(agentQueuedMessage).where(eq(agentQueuedMessage.threadId, threadId)).returning({
|
|
896
|
+
id: agentQueuedMessage.id
|
|
897
|
+
});
|
|
898
|
+
return removed.length;
|
|
899
|
+
}
|
|
900
|
+
async queuePause(threadId) {
|
|
901
|
+
const [thread] = await this.db.select({
|
|
902
|
+
queuePause: agentThread.queuePause
|
|
903
|
+
}).from(agentThread).where(eq(agentThread.id, threadId));
|
|
904
|
+
return thread?.queuePause ?? null;
|
|
905
|
+
}
|
|
906
|
+
async setQueuePause(threadId, pause) {
|
|
907
|
+
await this.db.update(agentThread).set({
|
|
908
|
+
queuePause: pause
|
|
909
|
+
}).where(eq(agentThread.id, threadId));
|
|
910
|
+
}
|
|
729
911
|
async setActiveStream(threadId, runId) {
|
|
730
912
|
await this.db.update(agentThread).set({
|
|
731
913
|
activeStreamId: runId
|
|
@@ -1049,6 +1231,32 @@ var DrizzleAgentStore = class {
|
|
|
1049
1231
|
};
|
|
1050
1232
|
}
|
|
1051
1233
|
};
|
|
1234
|
+
function toQueuedMessage(row) {
|
|
1235
|
+
return {
|
|
1236
|
+
id: row.id,
|
|
1237
|
+
threadId: row.threadId,
|
|
1238
|
+
actor: row.actor,
|
|
1239
|
+
content: row.content,
|
|
1240
|
+
...row.attachments !== null && row.attachments.length > 0 ? {
|
|
1241
|
+
attachments: row.attachments
|
|
1242
|
+
} : {},
|
|
1243
|
+
...row.agentName !== null ? {
|
|
1244
|
+
agentName: row.agentName
|
|
1245
|
+
} : {},
|
|
1246
|
+
...row.model !== null ? {
|
|
1247
|
+
model: row.model
|
|
1248
|
+
} : {},
|
|
1249
|
+
...row.pageContext !== null ? {
|
|
1250
|
+
pageContext: row.pageContext
|
|
1251
|
+
} : {},
|
|
1252
|
+
...row.interrupt ? {
|
|
1253
|
+
interrupt: true
|
|
1254
|
+
} : {},
|
|
1255
|
+
createdAt: row.createdAt.toISOString(),
|
|
1256
|
+
updatedAt: row.updatedAt.toISOString()
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
__name(toQueuedMessage, "toQueuedMessage");
|
|
1052
1260
|
|
|
1053
1261
|
// src/drizzle-governance-queries.ts
|
|
1054
1262
|
import { bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, rollupThreadUsage, truncateDetailContent } from "@dudousxd/nestjs-agent-core";
|
|
@@ -1889,7 +2097,7 @@ var DrizzlePricingStore = class {
|
|
|
1889
2097
|
// src/drizzle-rag-ingestion-log.ts
|
|
1890
2098
|
import { subscribe, unsubscribe } from "diagnostics_channel";
|
|
1891
2099
|
import { Injectable, Logger } from "@nestjs/common";
|
|
1892
|
-
import { and as and5, asc as asc3, count as count2, desc as desc3, eq as eq5, gt, lt, or } from "drizzle-orm";
|
|
2100
|
+
import { and as and5, asc as asc3, count as count2, desc as desc3, eq as eq5, gt, lt, or as or2 } from "drizzle-orm";
|
|
1893
2101
|
function _ts_decorate(decorators, target, key, desc4) {
|
|
1894
2102
|
var c = arguments.length, r = c < 3 ? target : desc4 === null ? desc4 = Object.getOwnPropertyDescriptor(target, key) : desc4, d;
|
|
1895
2103
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -2140,7 +2348,7 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
|
|
|
2140
2348
|
if (cursor === void 0) {
|
|
2141
2349
|
return base;
|
|
2142
2350
|
}
|
|
2143
|
-
return and5(base,
|
|
2351
|
+
return and5(base, or2(lt(ragIngestionLog.updatedAt, cursor.updatedAt), and5(eq5(ragIngestionLog.updatedAt, cursor.updatedAt), gt(ragIngestionLog.documentId, cursor.documentId))));
|
|
2144
2352
|
}
|
|
2145
2353
|
/**
|
|
2146
2354
|
* Upsert one outcome. Keyed by document id so the row always reflects the *current* state — a
|
|
@@ -2317,6 +2525,7 @@ export {
|
|
|
2317
2525
|
agentMemory,
|
|
2318
2526
|
agentMessage,
|
|
2319
2527
|
agentModelPricing,
|
|
2528
|
+
agentQueuedMessage,
|
|
2320
2529
|
agentRun,
|
|
2321
2530
|
agentSchema,
|
|
2322
2531
|
agentThread,
|