@dudousxd/nestjs-agent-store-drizzle
Drizzle AgentStore adapter — threads, messages, tool calls, usage, and run reliability — over an app-owned SQLite-dialect handle.
The AgentStore SPI (from @dudousxd/nestjs-agent-core) backed by Drizzle. Unlike the MikroORM
adapter, this package never opens a connection itself — the host app owns and hands it an
already-opened Drizzle db.
pnpm add @dudousxd/nestjs-agent-store-drizzle drizzle-ormnpm install @dudousxd/nestjs-agent-store-drizzle drizzle-ormMinimal example
Any SQLite-dialect driver works (better-sqlite3, libsql, D1, …):
import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import {
DrizzleAgentStoreModule,
agentSchema,
ensureAgentSchema,
} from '@dudousxd/nestjs-agent-store-drizzle';
import { AgentModule } from '@dudousxd/nestjs-agent';
const db = drizzle(new Database('app.db'), { schema: agentSchema });
await ensureAgentSchema(db); // idempotent CREATE TABLE IF NOT EXISTS — or run your own migrations
@Module({
imports: [
DrizzleAgentStoreModule.forRoot({ db }), // binds AGENT_STORE + AGENT_GOVERNANCE_QUERIES
AgentModule.forRoot({
model: myModelProvider,
defaultRoles: ['ADMIN'],
actorResolver: new HeaderActorResolver(),
}),
],
})
export class AppModule {}DrizzleAgentStoreModule.forRoot() is global
Like the MikroORM adapter, this module binds AGENT_STORE, AGENT_GOVERNANCE_QUERIES, and
AGENT_PRICING_STORE on a global Nest module. Import it once — the agent, dashboard, and
telescope surfaces all resolve all three tokens app-wide with no re-binding.
ensureAgentSchema is a quick start, not a migration story
It never drops or alters an existing column, so it can't evolve a table once it exists. Prefer
drizzle-kit migrations in production; treat ensureAgentSchema as the "stand it up with no
migration files" path for tests, demos, and first boot.
Exports
| Export | Kind | Purpose |
|---|---|---|
DrizzleAgentStoreModule | DynamicModule factory | .forRoot({ db }) binds AGENT_STORE + AGENT_GOVERNANCE_QUERIES + AGENT_PRICING_STORE globally over your db handle |
DrizzleAgentStore | class | AgentStore implementation — the write side, including the optional recordRunStart/recordRunEnd/bumpRunRetries run-reliability hooks the loop and durable runners call |
DrizzleGovernanceQueries | class | AgentGovernanceQueries implementation — the full read-model: spend by model/actor/thread, usage trend, recent activity, run reliability (runMetrics/runsByAgent/runErrors/runTrend/recentRuns), the approvals inbox (pendingApprovals), per-tool stats (toolStats), and paged/filterable reads (toolCallsPage/threadsPage/runsPage) |
DrizzlePricingStore | class | AgentPricingStore implementation — upsertModelPrice / listCurrentPrices, the write side of model pricing (see Cost & Governance) |
agentSchema | Drizzle schema object | The six agent tables (agentThread, agentMessage, agentToolCall, agentTokenUsage, agentModelPricing, agentRun) |
ensureAgentSchema(db) | function | Idempotent CREATE TABLE IF NOT EXISTS DDL for all six tables |
AgentDrizzleDb | type | The db handle shape (drizzle(client, { schema: agentSchema })) the module and store expect |
AgentRunRow / AgentThreadRow / AgentMessageRow | type | $inferSelect row shapes for the agentRun/agentThread/agentMessage tables |
agent_run — the reliability + approvals table
Every turn is recorded as a run in agentRun (status, duration, error code/message, retry count, a
promptHash for correlating error-rate shifts with prompt changes). DrizzleGovernanceQueries reads
it for the dashboard's Reliability section and for pendingApprovals/toolStats — no separate table
or wiring needed, it's created by ensureAgentSchema like the other five.
Peer dependencies
drizzle-orm (>=0.40.0 <1.0.0) and @nestjs/common (^10 \|\| ^11).
When to use it
Reach for this adapter when your app already owns a Drizzle connection (or wants one) and you'd
rather hand the agent a db handle than let an ORM own the lifecycle. Dialect support is
SQLite-family only (better-sqlite3, libsql, D1, …) — for other engines use
store-mikro-orm.
Related
- Persistence — the
AgentStoreSPI, the two bound tokens, and choosing an adapter
@dudousxd/nestjs-agent-store-mikro-orm
MikroORM AgentStore adapter — threads, messages, tool calls, usage, and run reliability — with safe auto-schema.
@dudousxd/nestjs-agent-transport-redis
RedisTokenStreamSink — a TokenStreamSink over Redis for multi-replica deployments, so a token stream started on one pod is subscribable and resumable from any other.