Aviary
Packages

@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-orm
npm install @dudousxd/nestjs-agent-store-drizzle drizzle-orm

Minimal 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

ExportKindPurpose
DrizzleAgentStoreModuleDynamicModule factory.forRoot({ db }) binds AGENT_STORE + AGENT_GOVERNANCE_QUERIES + AGENT_PRICING_STORE globally over your db handle
DrizzleAgentStoreclassAgentStore implementation — the write side, including the optional recordRunStart/recordRunEnd/bumpRunRetries run-reliability hooks the loop and durable runners call
DrizzleGovernanceQueriesclassAgentGovernanceQueries 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)
DrizzlePricingStoreclassAgentPricingStore implementation — upsertModelPrice / listCurrentPrices, the write side of model pricing (see Cost & Governance)
agentSchemaDrizzle schema objectThe six agent tables (agentThread, agentMessage, agentToolCall, agentTokenUsage, agentModelPricing, agentRun)
ensureAgentSchema(db)functionIdempotent CREATE TABLE IF NOT EXISTS DDL for all six tables
AgentDrizzleDbtypeThe db handle shape (drizzle(client, { schema: agentSchema })) the module and store expect
AgentRunRow / AgentThreadRow / AgentMessageRowtype$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.

  • Persistence — the AgentStore SPI, the two bound tokens, and choosing an adapter

On this page