feat(M5-004,M5-005,M5-006,M5-007): session-conversation binding, session:info broadcast, agent creation from TUI, and session metrics
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/pr/ci Pipeline failed

- M5-004: Add `session_id` column to conversations table (nullable text) with Drizzle migration 0006_swift_shen.sql; bind sessionId to conversation on session creation; reuse existing sessionId when resuming a conversation
- M5-005: Emit session:info with agentName on model/agent switch via broadcastSessionInfo(); set:thinking and setModelOverride now broadcast updated session:info to all clients on a conversation
- M5-006: /agent new <name> gateway command creates an agent config via brain.agents.create() with defaults (provider/model from env vars) and returns agentId+agentName in command:result data
- M5-007: Track per-session metrics (input/output/cache tokens, modelSwitches, messageCount, lastActivityAt) accumulated across turns; exposed via GET /api/sessions/:id metrics field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 19:56:07 -05:00
parent b18976a7aa
commit 1232804c3e
10 changed files with 3159 additions and 12 deletions

View File

@@ -0,0 +1 @@
ALTER TABLE "conversations" ADD COLUMN "session_id" text;

File diff suppressed because it is too large Load Diff

View File

@@ -43,6 +43,13 @@
"when": 1774225763410,
"tag": "0005_minor_champions",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1774227064500,
"tag": "0006_swift_shen",
"breakpoints": true
}
]
}

View File

@@ -319,6 +319,8 @@ export const conversations = pgTable(
.references(() => users.id, { onDelete: 'cascade' }),
projectId: uuid('project_id').references(() => projects.id, { onDelete: 'set null' }),
agentId: uuid('agent_id').references(() => agents.id, { onDelete: 'set null' }),
/** M5-004: Agent session ID bound to this conversation. Nullable — set when a session is created. */
sessionId: text('session_id'),
archived: boolean('archived').notNull().default(false),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),