@dudousxd/nestjs-agent-store-drizzle 0.18.3 → 0.19.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/README.md +17 -0
- package/dist/index.cjs +207 -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 +209 -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,124 @@ 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
|
+
await this.db.update(agentQueuedMessage).set(updates).where(eq(agentQueuedMessage.id, id));
|
|
867
|
+
return this.getQueuedMessage(id);
|
|
868
|
+
}
|
|
869
|
+
/** Rewrites the thread's positions as 0..n-1 in the new order — a queue is a handful of rows. */
|
|
870
|
+
async moveQueuedMessage(id, index2) {
|
|
871
|
+
const moving = await this.getQueuedMessage(id);
|
|
872
|
+
if (moving === null) {
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
const order = (await this.listQueue(moving.threadId)).filter((message) => message.id !== id);
|
|
876
|
+
const target = Math.max(0, Math.min(order.length, Math.trunc(index2)));
|
|
877
|
+
order.splice(target, 0, moving);
|
|
878
|
+
for (const [position, message] of order.entries()) {
|
|
879
|
+
await this.db.update(agentQueuedMessage).set({
|
|
880
|
+
position
|
|
881
|
+
}).where(eq(agentQueuedMessage.id, message.id));
|
|
882
|
+
}
|
|
883
|
+
return true;
|
|
884
|
+
}
|
|
885
|
+
async removeQueuedMessage(id) {
|
|
886
|
+
const removed = await this.db.delete(agentQueuedMessage).where(eq(agentQueuedMessage.id, id)).returning({
|
|
887
|
+
id: agentQueuedMessage.id
|
|
888
|
+
});
|
|
889
|
+
return removed.length > 0;
|
|
890
|
+
}
|
|
891
|
+
async clearQueue(threadId) {
|
|
892
|
+
const removed = await this.db.delete(agentQueuedMessage).where(eq(agentQueuedMessage.threadId, threadId)).returning({
|
|
893
|
+
id: agentQueuedMessage.id
|
|
894
|
+
});
|
|
895
|
+
return removed.length;
|
|
896
|
+
}
|
|
897
|
+
async queuePause(threadId) {
|
|
898
|
+
const [thread] = await this.db.select({
|
|
899
|
+
queuePause: agentThread.queuePause
|
|
900
|
+
}).from(agentThread).where(eq(agentThread.id, threadId));
|
|
901
|
+
return thread?.queuePause ?? null;
|
|
902
|
+
}
|
|
903
|
+
async setQueuePause(threadId, pause) {
|
|
904
|
+
await this.db.update(agentThread).set({
|
|
905
|
+
queuePause: pause
|
|
906
|
+
}).where(eq(agentThread.id, threadId));
|
|
907
|
+
}
|
|
729
908
|
async setActiveStream(threadId, runId) {
|
|
730
909
|
await this.db.update(agentThread).set({
|
|
731
910
|
activeStreamId: runId
|
|
@@ -1049,6 +1228,32 @@ var DrizzleAgentStore = class {
|
|
|
1049
1228
|
};
|
|
1050
1229
|
}
|
|
1051
1230
|
};
|
|
1231
|
+
function toQueuedMessage(row) {
|
|
1232
|
+
return {
|
|
1233
|
+
id: row.id,
|
|
1234
|
+
threadId: row.threadId,
|
|
1235
|
+
actor: row.actor,
|
|
1236
|
+
content: row.content,
|
|
1237
|
+
...row.attachments !== null && row.attachments.length > 0 ? {
|
|
1238
|
+
attachments: row.attachments
|
|
1239
|
+
} : {},
|
|
1240
|
+
...row.agentName !== null ? {
|
|
1241
|
+
agentName: row.agentName
|
|
1242
|
+
} : {},
|
|
1243
|
+
...row.model !== null ? {
|
|
1244
|
+
model: row.model
|
|
1245
|
+
} : {},
|
|
1246
|
+
...row.pageContext !== null ? {
|
|
1247
|
+
pageContext: row.pageContext
|
|
1248
|
+
} : {},
|
|
1249
|
+
...row.interrupt ? {
|
|
1250
|
+
interrupt: true
|
|
1251
|
+
} : {},
|
|
1252
|
+
createdAt: row.createdAt.toISOString(),
|
|
1253
|
+
updatedAt: row.updatedAt.toISOString()
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
__name(toQueuedMessage, "toQueuedMessage");
|
|
1052
1257
|
|
|
1053
1258
|
// src/drizzle-governance-queries.ts
|
|
1054
1259
|
import { bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, rollupThreadUsage, truncateDetailContent } from "@dudousxd/nestjs-agent-core";
|
|
@@ -1889,7 +2094,7 @@ var DrizzlePricingStore = class {
|
|
|
1889
2094
|
// src/drizzle-rag-ingestion-log.ts
|
|
1890
2095
|
import { subscribe, unsubscribe } from "diagnostics_channel";
|
|
1891
2096
|
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";
|
|
2097
|
+
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
2098
|
function _ts_decorate(decorators, target, key, desc4) {
|
|
1894
2099
|
var c = arguments.length, r = c < 3 ? target : desc4 === null ? desc4 = Object.getOwnPropertyDescriptor(target, key) : desc4, d;
|
|
1895
2100
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -2140,7 +2345,7 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
|
|
|
2140
2345
|
if (cursor === void 0) {
|
|
2141
2346
|
return base;
|
|
2142
2347
|
}
|
|
2143
|
-
return and5(base,
|
|
2348
|
+
return and5(base, or2(lt(ragIngestionLog.updatedAt, cursor.updatedAt), and5(eq5(ragIngestionLog.updatedAt, cursor.updatedAt), gt(ragIngestionLog.documentId, cursor.documentId))));
|
|
2144
2349
|
}
|
|
2145
2350
|
/**
|
|
2146
2351
|
* Upsert one outcome. Keyed by document id so the row always reflects the *current* state — a
|
|
@@ -2317,6 +2522,7 @@ export {
|
|
|
2317
2522
|
agentMemory,
|
|
2318
2523
|
agentMessage,
|
|
2319
2524
|
agentModelPricing,
|
|
2525
|
+
agentQueuedMessage,
|
|
2320
2526
|
agentRun,
|
|
2321
2527
|
agentSchema,
|
|
2322
2528
|
agentThread,
|