@dudousxd/nestjs-agent-store-mikro-orm
MikroORM AgentStore adapter — threads, messages, tool calls, usage, and run reliability — with safe auto-schema.
The AgentStore SPI (from @dudousxd/nestjs-agent-core) backed by MikroORM. The store is a POJO
that receives an EntityManager; every operation runs on a fresh em.fork() so per-request
identity maps never bleed across concurrent turns.
pnpm add @dudousxd/nestjs-agent-store-mikro-orm @mikro-orm/core @mikro-orm/nestjsnpm install @dudousxd/nestjs-agent-store-mikro-orm @mikro-orm/core @mikro-orm/nestjsMinimal example
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { MikroOrmAgentStoreModule } from '@dudousxd/nestjs-agent-store-mikro-orm';
import { AgentModule } from '@dudousxd/nestjs-agent';
@Module({
imports: [
MikroOrmModule.forRoot(/* your config */),
MikroOrmAgentStoreModule.forFeature(), // registers entities + binds AGENT_STORE (+ queries)
AgentModule.forRoot({
model: myModelProvider,
// no `store` — the agent reads it from AGENT_STORE
defaultRoles: ['ADMIN'],
actorResolver: new HeaderActorResolver(),
}),
],
})
export class AppModule {}Create the tables with your normal MikroORM migrations, or call the exported ensureAgentSchema
helper at boot for a quick start:
import { ensureAgentSchema } from '@dudousxd/nestjs-agent-store-mikro-orm';
await ensureAgentSchema(orm); // orm.schema.update({ safe: true }) — create + add-column onlyMikroOrmAgentStoreModule.forFeature() is global
It binds AGENT_STORE, AGENT_GOVERNANCE_QUERIES, and AGENT_PRICING_STORE on a global Nest
module. Import it once —
AgentModule.forRoot({...}) (and the dashboard/telescope surfaces) resolve both tokens app-wide with
no re-binding. Do not import it more than once expecting scoped behavior.
Exports
| Export | Kind | Purpose |
|---|---|---|
MikroOrmAgentStoreModule | DynamicModule factory | .forFeature() registers the six entities and binds AGENT_STORE + AGENT_GOVERNANCE_QUERIES + AGENT_PRICING_STORE globally |
MikroOrmAgentStore | class | AgentStore implementation — the write side (threads, messages, tool calls, usage), including the optional recordRunStart/recordRunEnd/bumpRunRetries run-reliability hooks the loop and durable runners call |
MikroOrmGovernanceQueries | 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) |
MikroOrmPricingStore | class | AgentPricingStore implementation — upsertModelPrice / listCurrentPrices, the write side of model pricing (see Cost & Governance) |
ensureAgentSchema(orm, opts?) | function | Non-destructive schema.update({ safe: true }) — create + add-column, never drop or alter |
agentManagedTables() | function → string[] | The six agent table names, for a host's own MikroORM schema-diff skipTables — mirrors durableManagedTables()/telescopeManagedTables() |
AGENT_ENTITIES | EntitySchema[] | The six agent entity schemas, pre-stamped with utf8mb4_unicode_ci for MySQL parity |
agentEntities({ collation? }) | function | Builds the entity schemas with a custom (or no) collation, e.g. for SQLite |
AGENT_COLLATION | 'utf8mb4_unicode_ci' | The default collation baked into AGENT_ENTITIES |
entity classes (AgentThread, AgentMessage, AgentToolCall, AgentTokenUsage, AgentModelPricing, AgentRun) | EntitySchema-backed classes | The six tables — agent_thread, agent_message, agent_tool_call, agent_token_usage, agent_model_pricing, agent_run |
agent_run — the reliability + approvals table
Every turn is recorded as a run in agent_run (status, duration, error code/message, retry count, a
promptHash for correlating error-rate shifts with prompt changes). MikroOrmGovernanceQueries reads
it for the dashboard's Reliability section and for pendingApprovals/toolStats — created and
healed by ensureAgentSchema like the other five tables, no separate wiring needed.
Peer dependencies
@mikro-orm/core (^6 \|\| ^7), @mikro-orm/nestjs (^6 \|\| ^7), and @nestjs/common
(^10 \|\| ^11) — plus your driver package (@mikro-orm/postgresql, @mikro-orm/mysql, …).
When to use it
Reach for this adapter when MikroORM is already your app's ORM — MikroOrmModule.forRoot(...)
owns the connection, and forFeature() just registers the agent's six entities alongside your own.
If you'd rather bring an already-opened handle and skip MikroORM entirely, see
store-drizzle.
Related
- Persistence — the
AgentStoreSPI, the two bound tokens, and choosing an adapter - Cost & Governance — the read-model this adapter feeds, and the ledger cost formula
@dudousxd/nestjs-agent-dashboard
A standalone AI-gateway governance console — bundled React SPA + JSON/SSE API mounted at its own route, no Telescope required — plus a dependency-free client subpath.
@dudousxd/nestjs-agent-store-drizzle
Drizzle AgentStore adapter — threads, messages, tool calls, usage, and run reliability — over an app-owned SQLite-dialect handle.