feat: add agent_metrics table schema and Drizzle migration
Adds the agentMetrics table to SQLite schema for storing pre-computed per-agent event counts (questions, subagents, compactions), enabling listForRadar to fetch one row per agent instead of scanning log chunks. Also fixes pre-existing Drizzle snapshot chain collision in meta/ (0035/0036 snapshots had wrong prevId due to parallel agent branches) to unblock drizzle-kit generate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
48
apps/server/db/repositories/drizzle/agent-metrics.test.ts
Normal file
48
apps/server/db/repositories/drizzle/agent-metrics.test.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { createTestDatabase } from './test-helpers.js';
|
||||||
|
import { agentMetrics } from '../../schema.js';
|
||||||
|
|
||||||
|
describe('agentMetrics table', () => {
|
||||||
|
it('select from empty agentMetrics returns []', async () => {
|
||||||
|
const db = createTestDatabase();
|
||||||
|
const rows = await db.select().from(agentMetrics);
|
||||||
|
expect(rows).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('insert and select a metrics row round-trips correctly', async () => {
|
||||||
|
const db = createTestDatabase();
|
||||||
|
await db.insert(agentMetrics).values({
|
||||||
|
agentId: 'agent-abc',
|
||||||
|
questionsCount: 3,
|
||||||
|
subagentsCount: 1,
|
||||||
|
compactionsCount: 0,
|
||||||
|
updatedAt: new Date('2024-01-01T00:00:00Z'),
|
||||||
|
});
|
||||||
|
const rows = await db.select().from(agentMetrics);
|
||||||
|
expect(rows).toHaveLength(1);
|
||||||
|
expect(rows[0].agentId).toBe('agent-abc');
|
||||||
|
expect(rows[0].questionsCount).toBe(3);
|
||||||
|
expect(rows[0].subagentsCount).toBe(1);
|
||||||
|
expect(rows[0].compactionsCount).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('agentId is primary key — duplicate insert throws', async () => {
|
||||||
|
const db = createTestDatabase();
|
||||||
|
await db.insert(agentMetrics).values({
|
||||||
|
agentId: 'agent-dup',
|
||||||
|
questionsCount: 0,
|
||||||
|
subagentsCount: 0,
|
||||||
|
compactionsCount: 0,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
});
|
||||||
|
await expect(
|
||||||
|
db.insert(agentMetrics).values({
|
||||||
|
agentId: 'agent-dup',
|
||||||
|
questionsCount: 1,
|
||||||
|
subagentsCount: 0,
|
||||||
|
compactionsCount: 0,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
})
|
||||||
|
).rejects.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -513,6 +513,21 @@ export const agentLogChunks = sqliteTable('agent_log_chunks', {
|
|||||||
export type AgentLogChunk = InferSelectModel<typeof agentLogChunks>;
|
export type AgentLogChunk = InferSelectModel<typeof agentLogChunks>;
|
||||||
export type NewAgentLogChunk = InferInsertModel<typeof agentLogChunks>;
|
export type NewAgentLogChunk = InferInsertModel<typeof agentLogChunks>;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// AGENT METRICS
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const agentMetrics = sqliteTable('agent_metrics', {
|
||||||
|
agentId: text('agent_id').primaryKey(),
|
||||||
|
questionsCount: integer('questions_count').notNull().default(0),
|
||||||
|
subagentsCount: integer('subagents_count').notNull().default(0),
|
||||||
|
compactionsCount: integer('compactions_count').notNull().default(0),
|
||||||
|
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type AgentMetrics = InferSelectModel<typeof agentMetrics>;
|
||||||
|
export type NewAgentMetrics = InferInsertModel<typeof agentMetrics>;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// CONVERSATIONS (inter-agent communication)
|
// CONVERSATIONS (inter-agent communication)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
7
apps/server/drizzle/0037_eager_devos.sql
Normal file
7
apps/server/drizzle/0037_eager_devos.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
CREATE TABLE `agent_metrics` (
|
||||||
|
`agent_id` text PRIMARY KEY NOT NULL,
|
||||||
|
`questions_count` integer DEFAULT 0 NOT NULL,
|
||||||
|
`subagents_count` integer DEFAULT 0 NOT NULL,
|
||||||
|
`compactions_count` integer DEFAULT 0 NOT NULL,
|
||||||
|
`updated_at` integer NOT NULL
|
||||||
|
);
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "c84e499f-7df8-4091-b2a5-6b12847898bd",
|
"id": "c84e499f-7df8-4091-b2a5-6b12847898bd",
|
||||||
"prevId": "5fbe1151-1dfb-4b0c-a7fa-2177369543fd",
|
"prevId": "443071fe-31d6-498a-9f4a-4a3ff24a46fc",
|
||||||
"tables": {
|
"tables": {
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"name": "accounts",
|
"name": "accounts",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
2029
apps/server/drizzle/meta/0037_snapshot.json
Normal file
2029
apps/server/drizzle/meta/0037_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -260,6 +260,13 @@
|
|||||||
"when": 1772798869413,
|
"when": 1772798869413,
|
||||||
"tag": "0036_icy_silvermane",
|
"tag": "0036_icy_silvermane",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 37,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1772828694292,
|
||||||
|
"tag": "0037_eager_devos",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user