@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/README.md
CHANGED
|
@@ -124,6 +124,23 @@ ALTER TABLE agent_tool_call ADD COLUMN expires_at INTEGER;
|
|
|
124
124
|
ALTER TABLE agent_tool_call ADD COLUMN remember INTEGER;
|
|
125
125
|
ALTER TABLE agent_tool_call ADD COLUMN decided_via TEXT;
|
|
126
126
|
CREATE INDEX agent_tool_call_message_idx ON agent_tool_call (message_id);
|
|
127
|
+
-- the chat message queue
|
|
128
|
+
ALTER TABLE agent_thread ADD COLUMN queue_pause TEXT;
|
|
129
|
+
CREATE TABLE agent_queued_message (
|
|
130
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
131
|
+
thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,
|
|
132
|
+
actor TEXT NOT NULL,
|
|
133
|
+
content TEXT NOT NULL,
|
|
134
|
+
attachments TEXT,
|
|
135
|
+
agent_name TEXT,
|
|
136
|
+
model TEXT,
|
|
137
|
+
page_context TEXT,
|
|
138
|
+
interrupt INTEGER NOT NULL DEFAULT 0,
|
|
139
|
+
position INTEGER NOT NULL,
|
|
140
|
+
created_at INTEGER NOT NULL,
|
|
141
|
+
updated_at INTEGER NOT NULL
|
|
142
|
+
);
|
|
143
|
+
CREATE INDEX agent_queued_message_thread_position_idx ON agent_queued_message (thread_id, position);
|
|
127
144
|
```
|
|
128
145
|
|
|
129
146
|
The index is not optional on Postgres: `agent_tool_call.message_id` carries a foreign key, and
|
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ __export(index_exports, {
|
|
|
31
31
|
agentMemory: () => agentMemory,
|
|
32
32
|
agentMessage: () => agentMessage,
|
|
33
33
|
agentModelPricing: () => agentModelPricing,
|
|
34
|
+
agentQueuedMessage: () => agentQueuedMessage,
|
|
34
35
|
agentRun: () => agentRun,
|
|
35
36
|
agentSchema: () => agentSchema,
|
|
36
37
|
agentThread: () => agentThread,
|
|
@@ -56,6 +57,10 @@ var agentThread = (0, import_sqlite_core.sqliteTable)("agent_thread", {
|
|
|
56
57
|
defaultAgent: (0, import_sqlite_core.text)("default_agent"),
|
|
57
58
|
/** The model every turn on this thread runs on unless the send names one; `null` → default. */
|
|
58
59
|
model: (0, import_sqlite_core.text)("model"),
|
|
60
|
+
/** Why the thread's message queue stopped draining; `null` → it drains. */
|
|
61
|
+
queuePause: (0, import_sqlite_core.text)("queue_pause", {
|
|
62
|
+
mode: "json"
|
|
63
|
+
}).$type(),
|
|
59
64
|
createdAt: (0, import_sqlite_core.integer)("created_at", {
|
|
60
65
|
mode: "timestamp_ms"
|
|
61
66
|
}).notNull(),
|
|
@@ -149,6 +154,37 @@ var agentToolCall = (0, import_sqlite_core.sqliteTable)("agent_tool_call", {
|
|
|
149
154
|
}, (table) => [
|
|
150
155
|
(0, import_sqlite_core.index)("agent_tool_call_message_idx").on(table.messageId)
|
|
151
156
|
]);
|
|
157
|
+
var agentQueuedMessage = (0, import_sqlite_core.sqliteTable)("agent_queued_message", {
|
|
158
|
+
id: (0, import_sqlite_core.text)("id").primaryKey(),
|
|
159
|
+
threadId: (0, import_sqlite_core.text)("thread_id").notNull().references(() => agentThread.id, {
|
|
160
|
+
onDelete: "cascade"
|
|
161
|
+
}),
|
|
162
|
+
/** Who queued it — the turn it starts runs as this actor. */
|
|
163
|
+
actor: (0, import_sqlite_core.text)("actor", {
|
|
164
|
+
mode: "json"
|
|
165
|
+
}).$type().notNull(),
|
|
166
|
+
content: (0, import_sqlite_core.text)("content").notNull(),
|
|
167
|
+
attachments: (0, import_sqlite_core.text)("attachments", {
|
|
168
|
+
mode: "json"
|
|
169
|
+
}).$type(),
|
|
170
|
+
agentName: (0, import_sqlite_core.text)("agent_name"),
|
|
171
|
+
model: (0, import_sqlite_core.text)("model"),
|
|
172
|
+
pageContext: (0, import_sqlite_core.text)("page_context", {
|
|
173
|
+
mode: "json"
|
|
174
|
+
}).$type(),
|
|
175
|
+
interrupt: (0, import_sqlite_core.integer)("interrupt", {
|
|
176
|
+
mode: "boolean"
|
|
177
|
+
}).notNull().default(false),
|
|
178
|
+
position: (0, import_sqlite_core.integer)("position").notNull(),
|
|
179
|
+
createdAt: (0, import_sqlite_core.integer)("created_at", {
|
|
180
|
+
mode: "timestamp_ms"
|
|
181
|
+
}).notNull(),
|
|
182
|
+
updatedAt: (0, import_sqlite_core.integer)("updated_at", {
|
|
183
|
+
mode: "timestamp_ms"
|
|
184
|
+
}).notNull()
|
|
185
|
+
}, (table) => [
|
|
186
|
+
(0, import_sqlite_core.index)("agent_queued_message_thread_position_idx").on(table.threadId, table.position)
|
|
187
|
+
]);
|
|
152
188
|
var agentTokenUsage = (0, import_sqlite_core.sqliteTable)("agent_token_usage", {
|
|
153
189
|
id: (0, import_sqlite_core.text)("id").primaryKey(),
|
|
154
190
|
threadId: (0, import_sqlite_core.text)("thread_id").notNull().references(() => agentThread.id, {
|
|
@@ -274,6 +310,7 @@ var ragIngestionLog = (0, import_sqlite_core.sqliteTable)("rag_ingestion_log", {
|
|
|
274
310
|
var agentSchema = {
|
|
275
311
|
agentThread,
|
|
276
312
|
agentMessage,
|
|
313
|
+
agentQueuedMessage,
|
|
277
314
|
agentToolCall,
|
|
278
315
|
agentTokenUsage,
|
|
279
316
|
agentModelPricing,
|
|
@@ -294,6 +331,7 @@ var statements = [
|
|
|
294
331
|
active_stream_id TEXT,
|
|
295
332
|
default_agent TEXT,
|
|
296
333
|
model TEXT,
|
|
334
|
+
queue_pause TEXT,
|
|
297
335
|
created_at INTEGER NOT NULL,
|
|
298
336
|
updated_at INTEGER NOT NULL,
|
|
299
337
|
deleted_at INTEGER
|
|
@@ -320,6 +358,22 @@ var statements = [
|
|
|
320
358
|
)`,
|
|
321
359
|
`CREATE INDEX IF NOT EXISTS agent_message_thread_created_idx
|
|
322
360
|
ON agent_message (thread_id, created_at)`,
|
|
361
|
+
`CREATE TABLE IF NOT EXISTS agent_queued_message (
|
|
362
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
363
|
+
thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,
|
|
364
|
+
actor TEXT NOT NULL,
|
|
365
|
+
content TEXT NOT NULL,
|
|
366
|
+
attachments TEXT,
|
|
367
|
+
agent_name TEXT,
|
|
368
|
+
model TEXT,
|
|
369
|
+
page_context TEXT,
|
|
370
|
+
interrupt INTEGER NOT NULL DEFAULT 0,
|
|
371
|
+
position INTEGER NOT NULL,
|
|
372
|
+
created_at INTEGER NOT NULL,
|
|
373
|
+
updated_at INTEGER NOT NULL
|
|
374
|
+
)`,
|
|
375
|
+
`CREATE INDEX IF NOT EXISTS agent_queued_message_thread_position_idx
|
|
376
|
+
ON agent_queued_message (thread_id, position)`,
|
|
323
377
|
`CREATE TABLE IF NOT EXISTS agent_tool_call (
|
|
324
378
|
id TEXT PRIMARY KEY NOT NULL,
|
|
325
379
|
message_id TEXT NOT NULL REFERENCES agent_message(id) ON DELETE CASCADE,
|
|
@@ -480,6 +534,11 @@ var additiveColumns = [
|
|
|
480
534
|
column: "remember",
|
|
481
535
|
ddl: "ALTER TABLE agent_tool_call ADD COLUMN remember INTEGER"
|
|
482
536
|
},
|
|
537
|
+
{
|
|
538
|
+
table: "agent_thread",
|
|
539
|
+
column: "queue_pause",
|
|
540
|
+
ddl: "ALTER TABLE agent_thread ADD COLUMN queue_pause TEXT"
|
|
541
|
+
},
|
|
483
542
|
{
|
|
484
543
|
table: "agent_tool_call",
|
|
485
544
|
column: "decided_via",
|
|
@@ -531,6 +590,7 @@ var DrizzleAgentStore = class {
|
|
|
531
590
|
activeStreamId: null,
|
|
532
591
|
defaultAgent: null,
|
|
533
592
|
model: null,
|
|
593
|
+
queuePause: null,
|
|
534
594
|
createdAt: now,
|
|
535
595
|
updatedAt: now,
|
|
536
596
|
deletedAt: null
|
|
@@ -637,6 +697,8 @@ var DrizzleAgentStore = class {
|
|
|
637
697
|
activeStreamId: null,
|
|
638
698
|
defaultAgent: source.defaultAgent,
|
|
639
699
|
model: source.model,
|
|
700
|
+
// A fork is a new conversation: nothing is waiting on it, and nothing is paused.
|
|
701
|
+
queuePause: null,
|
|
640
702
|
createdAt: now,
|
|
641
703
|
updatedAt: now,
|
|
642
704
|
deletedAt: null
|
|
@@ -766,6 +828,127 @@ var DrizzleAgentStore = class {
|
|
|
766
828
|
updatedAt: /* @__PURE__ */ new Date()
|
|
767
829
|
}).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.id, threadId), (0, import_drizzle_orm2.eq)(agentThread.transient, true)));
|
|
768
830
|
}
|
|
831
|
+
/** The run streaming the thread, or `null` — a projection of the one column. */
|
|
832
|
+
async activeRunForThread(threadId) {
|
|
833
|
+
const [thread] = await this.db.select({
|
|
834
|
+
activeStreamId: agentThread.activeStreamId
|
|
835
|
+
}).from(agentThread).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.id, threadId), (0, import_drizzle_orm2.isNull)(agentThread.deletedAt)));
|
|
836
|
+
return thread?.activeStreamId ?? null;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* One conditional UPDATE, so of two racing claims exactly one changes the row: set the holder to
|
|
840
|
+
* `runId` only when there is none, it is already `runId`, or it is `replacing`.
|
|
841
|
+
*/
|
|
842
|
+
async claimActiveStream(threadId, runId, options = {}) {
|
|
843
|
+
const holders = [
|
|
844
|
+
(0, import_drizzle_orm2.isNull)(agentThread.activeStreamId),
|
|
845
|
+
(0, import_drizzle_orm2.eq)(agentThread.activeStreamId, runId),
|
|
846
|
+
...options.replacing !== void 0 ? [
|
|
847
|
+
(0, import_drizzle_orm2.eq)(agentThread.activeStreamId, options.replacing)
|
|
848
|
+
] : []
|
|
849
|
+
];
|
|
850
|
+
const claimed = await this.db.update(agentThread).set({
|
|
851
|
+
activeStreamId: runId
|
|
852
|
+
}).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.id, threadId), (0, import_drizzle_orm2.or)(...holders))).returning({
|
|
853
|
+
id: agentThread.id
|
|
854
|
+
});
|
|
855
|
+
return claimed.length > 0;
|
|
856
|
+
}
|
|
857
|
+
async releaseActiveStream(threadId, runId) {
|
|
858
|
+
const released = await this.db.update(agentThread).set({
|
|
859
|
+
activeStreamId: null
|
|
860
|
+
}).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.id, threadId), (0, import_drizzle_orm2.eq)(agentThread.activeStreamId, runId))).returning({
|
|
861
|
+
id: agentThread.id
|
|
862
|
+
});
|
|
863
|
+
return released.length > 0;
|
|
864
|
+
}
|
|
865
|
+
async enqueueMessage(input) {
|
|
866
|
+
const now = /* @__PURE__ */ new Date();
|
|
867
|
+
const [edge] = await this.db.select({
|
|
868
|
+
first: (0, import_drizzle_orm2.min)(agentQueuedMessage.position),
|
|
869
|
+
last: (0, import_drizzle_orm2.max)(agentQueuedMessage.position)
|
|
870
|
+
}).from(agentQueuedMessage).where((0, import_drizzle_orm2.eq)(agentQueuedMessage.threadId, input.threadId));
|
|
871
|
+
const position = input.at === "head" ? (edge?.first ?? 1) - 1 : (edge?.last ?? -1) + 1;
|
|
872
|
+
const row = {
|
|
873
|
+
id: crypto.randomUUID(),
|
|
874
|
+
threadId: input.threadId,
|
|
875
|
+
actor: input.actor,
|
|
876
|
+
content: input.content,
|
|
877
|
+
attachments: input.attachments !== void 0 && input.attachments.length > 0 ? input.attachments : null,
|
|
878
|
+
agentName: input.agentName ?? null,
|
|
879
|
+
model: input.model ?? null,
|
|
880
|
+
pageContext: input.pageContext ?? null,
|
|
881
|
+
interrupt: input.interrupt === true,
|
|
882
|
+
position,
|
|
883
|
+
createdAt: now,
|
|
884
|
+
updatedAt: now
|
|
885
|
+
};
|
|
886
|
+
await this.db.insert(agentQueuedMessage).values(row);
|
|
887
|
+
return toQueuedMessage(row);
|
|
888
|
+
}
|
|
889
|
+
async listQueue(threadId) {
|
|
890
|
+
const rows = await this.db.select().from(agentQueuedMessage).where((0, import_drizzle_orm2.eq)(agentQueuedMessage.threadId, threadId)).orderBy((0, import_drizzle_orm2.asc)(agentQueuedMessage.position), (0, import_drizzle_orm2.asc)(agentQueuedMessage.createdAt));
|
|
891
|
+
return rows.map(toQueuedMessage);
|
|
892
|
+
}
|
|
893
|
+
async getQueuedMessage(id) {
|
|
894
|
+
const [row] = await this.db.select().from(agentQueuedMessage).where((0, import_drizzle_orm2.eq)(agentQueuedMessage.id, id));
|
|
895
|
+
return row === void 0 ? null : toQueuedMessage(row);
|
|
896
|
+
}
|
|
897
|
+
async updateQueuedMessage(id, patch) {
|
|
898
|
+
const updates = {
|
|
899
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
900
|
+
};
|
|
901
|
+
if (patch.content !== void 0) {
|
|
902
|
+
updates.content = patch.content;
|
|
903
|
+
}
|
|
904
|
+
if (patch.attachments !== void 0) {
|
|
905
|
+
updates.attachments = patch.attachments === null || patch.attachments.length === 0 ? null : patch.attachments;
|
|
906
|
+
}
|
|
907
|
+
if (patch.interrupt !== void 0) {
|
|
908
|
+
updates.interrupt = patch.interrupt;
|
|
909
|
+
}
|
|
910
|
+
await this.db.update(agentQueuedMessage).set(updates).where((0, import_drizzle_orm2.eq)(agentQueuedMessage.id, id));
|
|
911
|
+
return this.getQueuedMessage(id);
|
|
912
|
+
}
|
|
913
|
+
/** Rewrites the thread's positions as 0..n-1 in the new order — a queue is a handful of rows. */
|
|
914
|
+
async moveQueuedMessage(id, index2) {
|
|
915
|
+
const moving = await this.getQueuedMessage(id);
|
|
916
|
+
if (moving === null) {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
const order = (await this.listQueue(moving.threadId)).filter((message) => message.id !== id);
|
|
920
|
+
const target = Math.max(0, Math.min(order.length, Math.trunc(index2)));
|
|
921
|
+
order.splice(target, 0, moving);
|
|
922
|
+
for (const [position, message] of order.entries()) {
|
|
923
|
+
await this.db.update(agentQueuedMessage).set({
|
|
924
|
+
position
|
|
925
|
+
}).where((0, import_drizzle_orm2.eq)(agentQueuedMessage.id, message.id));
|
|
926
|
+
}
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
async removeQueuedMessage(id) {
|
|
930
|
+
const removed = await this.db.delete(agentQueuedMessage).where((0, import_drizzle_orm2.eq)(agentQueuedMessage.id, id)).returning({
|
|
931
|
+
id: agentQueuedMessage.id
|
|
932
|
+
});
|
|
933
|
+
return removed.length > 0;
|
|
934
|
+
}
|
|
935
|
+
async clearQueue(threadId) {
|
|
936
|
+
const removed = await this.db.delete(agentQueuedMessage).where((0, import_drizzle_orm2.eq)(agentQueuedMessage.threadId, threadId)).returning({
|
|
937
|
+
id: agentQueuedMessage.id
|
|
938
|
+
});
|
|
939
|
+
return removed.length;
|
|
940
|
+
}
|
|
941
|
+
async queuePause(threadId) {
|
|
942
|
+
const [thread] = await this.db.select({
|
|
943
|
+
queuePause: agentThread.queuePause
|
|
944
|
+
}).from(agentThread).where((0, import_drizzle_orm2.eq)(agentThread.id, threadId));
|
|
945
|
+
return thread?.queuePause ?? null;
|
|
946
|
+
}
|
|
947
|
+
async setQueuePause(threadId, pause) {
|
|
948
|
+
await this.db.update(agentThread).set({
|
|
949
|
+
queuePause: pause
|
|
950
|
+
}).where((0, import_drizzle_orm2.eq)(agentThread.id, threadId));
|
|
951
|
+
}
|
|
769
952
|
async setActiveStream(threadId, runId) {
|
|
770
953
|
await this.db.update(agentThread).set({
|
|
771
954
|
activeStreamId: runId
|
|
@@ -1089,6 +1272,32 @@ var DrizzleAgentStore = class {
|
|
|
1089
1272
|
};
|
|
1090
1273
|
}
|
|
1091
1274
|
};
|
|
1275
|
+
function toQueuedMessage(row) {
|
|
1276
|
+
return {
|
|
1277
|
+
id: row.id,
|
|
1278
|
+
threadId: row.threadId,
|
|
1279
|
+
actor: row.actor,
|
|
1280
|
+
content: row.content,
|
|
1281
|
+
...row.attachments !== null && row.attachments.length > 0 ? {
|
|
1282
|
+
attachments: row.attachments
|
|
1283
|
+
} : {},
|
|
1284
|
+
...row.agentName !== null ? {
|
|
1285
|
+
agentName: row.agentName
|
|
1286
|
+
} : {},
|
|
1287
|
+
...row.model !== null ? {
|
|
1288
|
+
model: row.model
|
|
1289
|
+
} : {},
|
|
1290
|
+
...row.pageContext !== null ? {
|
|
1291
|
+
pageContext: row.pageContext
|
|
1292
|
+
} : {},
|
|
1293
|
+
...row.interrupt ? {
|
|
1294
|
+
interrupt: true
|
|
1295
|
+
} : {},
|
|
1296
|
+
createdAt: row.createdAt.toISOString(),
|
|
1297
|
+
updatedAt: row.updatedAt.toISOString()
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
__name(toQueuedMessage, "toQueuedMessage");
|
|
1092
1301
|
|
|
1093
1302
|
// src/drizzle-governance-queries.ts
|
|
1094
1303
|
var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
|
|
@@ -2358,6 +2567,7 @@ DrizzleAgentStoreModule = _ts_decorate2([
|
|
|
2358
2567
|
agentMemory,
|
|
2359
2568
|
agentMessage,
|
|
2360
2569
|
agentModelPricing,
|
|
2570
|
+
agentQueuedMessage,
|
|
2361
2571
|
agentRun,
|
|
2362
2572
|
agentSchema,
|
|
2363
2573
|
agentThread,
|