@dudousxd/nestjs-agent-store-drizzle 0.9.0 → 0.10.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 +75 -1
- package/dist/index.cjs +602 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1641 -425
- package/dist/index.d.ts +1641 -425
- package/dist/index.js +585 -12
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -36,7 +36,8 @@ export class AppModule {}
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
The package ships the `agentSchema` (Drizzle tables), `ensureAgentSchema` (a non-destructive
|
|
39
|
-
DDL helper for a quick start), `DrizzleAgentStore`,
|
|
39
|
+
DDL helper for a quick start), `DrizzleAgentStore`, `DrizzleGovernanceQueries`, and
|
|
40
|
+
`DrizzleRagIngestionLog`. For production,
|
|
40
41
|
prefer your normal drizzle-kit migrations over the `ensureAgentSchema` helper.
|
|
41
42
|
|
|
42
43
|
## The read a turn makes
|
|
@@ -52,6 +53,55 @@ ceiling is only a token budget, names no row bound and the whole thread is read
|
|
|
52
53
|
README. Nothing to wire: the loop probes for the method, and `getThread` remains the right read for
|
|
53
54
|
a client rendering a transcript.
|
|
54
55
|
|
|
56
|
+
## Memory
|
|
57
|
+
|
|
58
|
+
`DrizzleMemoryProvider` is a `MemoryProvider` over `agent_memory`, a table `ensureAgentSchema`
|
|
59
|
+
creates alongside the other six.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { DrizzleAgentStoreModule, DrizzleMemoryProvider } from '@dudousxd/nestjs-agent-store-drizzle';
|
|
63
|
+
|
|
64
|
+
AgentModule.forRootAsync({
|
|
65
|
+
// AGENT_STORE already comes from DrizzleAgentStoreModule.forRoot({ db }), which is global.
|
|
66
|
+
externalStore: true,
|
|
67
|
+
inject: [DrizzleMemoryProvider],
|
|
68
|
+
useFactory: (memory: DrizzleMemoryProvider) => ({
|
|
69
|
+
model,
|
|
70
|
+
actorResolver,
|
|
71
|
+
memory: { provider: memory },
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The store module exports the provider but never binds `AGENT_MEMORY`: that token's **presence** is
|
|
77
|
+
what turns memory on, so binding it here would switch the feature on for every host that installs the
|
|
78
|
+
store. Naming the provider is how you opt in.
|
|
79
|
+
|
|
80
|
+
What it holds to:
|
|
81
|
+
|
|
82
|
+
- `list` filters `scope in (…)` in the **query**. The library drops out-of-scope records it is handed,
|
|
83
|
+
but that is a backstop — a memory held for another actor or another tenant is never selected, so it
|
|
84
|
+
is unreachable rather than outranked.
|
|
85
|
+
- `write` upserts on the (`scope`, `key`) unique index in one statement, so two turns concluding the
|
|
86
|
+
same key at once cannot race to a duplicate-key insert. The conflict `set` names exactly what a
|
|
87
|
+
rewrite may change, so `pinned`, `created_at` and `id` are left alone by construction: a rewrite
|
|
88
|
+
must not unpin a record, lose when the belief was formed, or invalidate the delete handle a person
|
|
89
|
+
was already shown.
|
|
90
|
+
- `write` refuses an **agent-authored** record at any scope but the actor's own. A human-authored one
|
|
91
|
+
above it is allowed, because that is what a console publishing an organisation's policy does, and
|
|
92
|
+
whether that person may write there is what `memoryWriteVerdict` answers.
|
|
93
|
+
- `forget` deletes only from the actor's own scope, so an id alone cannot reach a tenant's memory.
|
|
94
|
+
- `pin({ id, pinned })` is the operator act the SPI has no method for — a pin grants a fact a
|
|
95
|
+
permanent place in every future prompt, so nothing an agent can reach may set it. Authorize it in
|
|
96
|
+
your own console.
|
|
97
|
+
|
|
98
|
+
**`search` is not implemented**, deliberately. It buys a block filled by relevance once the applicable
|
|
99
|
+
set outgrows `maxMemories`, and that needs an index over the memories themselves — whose shape depends
|
|
100
|
+
entirely on what you already run. Without it, `list` reads the applicable scopes whole and the ceiling
|
|
101
|
+
never bites. The signal that it is worth building is `MemoryDigest.omitted` going non-zero, and
|
|
102
|
+
`pinnedOmitted` especially: a standing policy that stopped reaching any prompt. Both are on the
|
|
103
|
+
`aviary:agent:memory.resolved` diagnostic.
|
|
104
|
+
|
|
55
105
|
## Upgrading a database that already exists
|
|
56
106
|
|
|
57
107
|
`ensureAgentSchema` is additive only — `CREATE TABLE IF NOT EXISTS` plus `CREATE INDEX IF NOT
|
|
@@ -89,6 +139,30 @@ A thread that was soft-deleted still counts as holding its references: the messa
|
|
|
89
139
|
the bytes are still reachable from stored state. Delete the thread for real and the cascade makes
|
|
90
140
|
them collectable on the next sweep.
|
|
91
141
|
|
|
142
|
+
## RAG ingestion outcomes
|
|
143
|
+
|
|
144
|
+
`rag_ingestion_log` holds the latest outcome for every RAG document — ingested, skipped, failed,
|
|
145
|
+
removed — one row per document id, overwritten on re-ingest. It answers the question a vector store
|
|
146
|
+
structurally cannot: *which documents failed to index, and why*. A document whose extraction came
|
|
147
|
+
back empty, whose mime type had no extractor, or whose embedding call threw produces zero chunks, so
|
|
148
|
+
`VectorStore.listDocuments()` cannot tell it from one nobody ever uploaded. Pair the two: the index
|
|
149
|
+
is the truth about what is retrievable, this table is the truth about what was attempted.
|
|
150
|
+
|
|
151
|
+
`DrizzleRagIngestionLog` fills it by subscribing to the `aviary:rag:*` diagnostics
|
|
152
|
+
`@dudousxd/nestjs-agent-rag-media` publishes — the RAG package owns no storage of its own. It is
|
|
153
|
+
bound and exported by `DrizzleAgentStoreModule.forRoot({ db })` by default; pass
|
|
154
|
+
`{ ragIngestionLog: false }` to bind nothing at all. `ensureAgentSchema` creates the table, indexed
|
|
155
|
+
by (`collection`, `updated_at`) for the per-collection listing.
|
|
156
|
+
|
|
157
|
+
Reads: `list` / `listPage` (a page plus the unpaginated total), `get`, `remove`,
|
|
158
|
+
`removeByCollection`, a delete-safe keyset `iterate`, and `listDocumentIds` for an orphan sweep that
|
|
159
|
+
wants a collection's id set without hydrating every stack trace in the table. The paging order is
|
|
160
|
+
exported as `RAG_INGESTION_LOG_PAGE_ORDER` — `updated_at desc` tiebroken on the primary key, which
|
|
161
|
+
is what keeps consecutive pages disjoint when a bulk upload stamps a whole batch with one timestamp.
|
|
162
|
+
|
|
163
|
+
Writes are best-effort: the recorder runs detached on a diagnostics channel, so a failed write is
|
|
164
|
+
reported and dropped rather than taking down the ingestion that triggered it.
|
|
165
|
+
|
|
92
166
|
## Cost accounting
|
|
93
167
|
|
|
94
168
|
`DrizzleGovernanceQueries` resolves cost per usage row as `COALESCE(reportedCostUsd, tokens × pricing)`:
|