style: apply prettier formatting to v2 source files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-08 23:59:08 +03:00
parent 03c4e3b672
commit d35386a46e
6 changed files with 168 additions and 34 deletions
+4 -1
View File
@@ -263,7 +263,10 @@ async function buildContainerArgs(
// Override entrypoint: compile agent-runner source, run v2 entry point (no stdin)
args.push('--entrypoint', 'bash');
args.push(CONTAINER_IMAGE);
args.push('-c', 'cd /app && npx tsc --outDir /tmp/dist 2>&1 >&2 && ln -sf /app/node_modules /tmp/dist/node_modules && node /tmp/dist/index-v2.js');
args.push(
'-c',
'cd /app && npx tsc --outDir /tmp/dist 2>&1 >&2 && ln -sf /app/node_modules /tmp/dist/node_modules && node /tmp/dist/index-v2.js',
);
return args;
}
+15 -2
View File
@@ -15,7 +15,13 @@ const ACTIVE_POLL_MS = 1000;
const SWEEP_POLL_MS = 60_000;
export interface ChannelDeliveryAdapter {
deliver(channelType: string, platformId: string, threadId: string | null, kind: string, content: string): Promise<void>;
deliver(
channelType: string,
platformId: string,
threadId: string | null,
kind: string,
content: string,
): Promise<void>;
setTyping?(channelType: string, platformId: string, threadId: string | null): Promise<void>;
}
@@ -116,7 +122,14 @@ async function deliverSessionMessages(session: Session): Promise<void> {
}
async function deliverMessage(
msg: { id: string; kind: string; platform_id: string | null; channel_type: string | null; thread_id: string | null; content: string },
msg: {
id: string;
kind: string;
platform_id: string | null;
channel_type: string | null;
thread_id: string | null;
content: string;
},
session: Session,
): Promise<void> {
if (!deliveryAdapter) {
+96 -12
View File
@@ -8,8 +8,22 @@ import fs from 'fs';
import path from 'path';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { initTestDb, closeDb, runMigrations, createAgentGroup, createMessagingGroup, createMessagingGroupAgent } from './db/index.js';
import { resolveSession, writeSessionMessage, initSessionFolder, sessionDir, sessionDbPath, sessionsBaseDir } from './session-manager.js';
import {
initTestDb,
closeDb,
runMigrations,
createAgentGroup,
createMessagingGroup,
createMessagingGroupAgent,
} from './db/index.js';
import {
resolveSession,
writeSessionMessage,
initSessionFolder,
sessionDir,
sessionDbPath,
sessionsBaseDir,
} from './session-manager.js';
import { getSession, findSession } from './db/sessions.js';
import type { InboundEvent } from './router-v2.js';
@@ -50,8 +64,24 @@ afterEach(() => {
describe('session manager', () => {
beforeEach(() => {
createAgentGroup({ id: 'ag-1', name: 'Test Agent', folder: 'test-agent', is_admin: 0, agent_provider: null, container_config: null, created_at: now() });
createMessagingGroup({ id: 'mg-1', channel_type: 'discord', platform_id: 'chan-123', name: 'General', is_group: 1, admin_user_id: null, created_at: now() });
createAgentGroup({
id: 'ag-1',
name: 'Test Agent',
folder: 'test-agent',
is_admin: 0,
agent_provider: null,
container_config: null,
created_at: now(),
});
createMessagingGroup({
id: 'mg-1',
channel_type: 'discord',
platform_id: 'chan-123',
name: 'General',
is_group: 1,
admin_user_id: null,
created_at: now(),
});
});
it('should create session folder and DB', () => {
@@ -110,7 +140,12 @@ describe('session manager', () => {
// Read from the session DB
const dbPath = sessionDbPath('ag-1', session.id);
const db = new Database(dbPath);
const rows = db.prepare('SELECT * FROM messages_in').all() as Array<{ id: string; kind: string; status: string; content: string }>;
const rows = db.prepare('SELECT * FROM messages_in').all() as Array<{
id: string;
kind: string;
status: string;
content: string;
}>;
db.close();
expect(rows).toHaveLength(1);
@@ -136,9 +171,34 @@ describe('session manager', () => {
describe('router', () => {
beforeEach(() => {
createAgentGroup({ id: 'ag-1', name: 'Test Agent', folder: 'test-agent', is_admin: 0, agent_provider: null, container_config: null, created_at: now() });
createMessagingGroup({ id: 'mg-1', channel_type: 'discord', platform_id: 'chan-123', name: 'General', is_group: 1, admin_user_id: null, created_at: now() });
createMessagingGroupAgent({ id: 'mga-1', messaging_group_id: 'mg-1', agent_group_id: 'ag-1', trigger_rules: null, response_scope: 'all', session_mode: 'shared', priority: 0, created_at: now() });
createAgentGroup({
id: 'ag-1',
name: 'Test Agent',
folder: 'test-agent',
is_admin: 0,
agent_provider: null,
container_config: null,
created_at: now(),
});
createMessagingGroup({
id: 'mg-1',
channel_type: 'discord',
platform_id: 'chan-123',
name: 'General',
is_group: 1,
admin_user_id: null,
created_at: now(),
});
createMessagingGroupAgent({
id: 'mga-1',
messaging_group_id: 'mg-1',
agent_group_id: 'ag-1',
trigger_rules: null,
response_scope: 'all',
session_mode: 'shared',
priority: 0,
created_at: now(),
});
});
it('should route a message end-to-end', async () => {
@@ -215,7 +275,12 @@ describe('router', () => {
channelType: 'discord',
platformId: 'chan-123',
threadId: null,
message: { id: 'msg-b', kind: 'chat', content: JSON.stringify({ sender: 'B', text: 'Second' }), timestamp: now() },
message: {
id: 'msg-b',
kind: 'chat',
content: JSON.stringify({ sender: 'B', text: 'Second' }),
timestamp: now(),
},
});
// Both should be in the same session
@@ -231,8 +296,24 @@ describe('router', () => {
describe('delivery', () => {
it('should detect undelivered messages in session DB', () => {
createAgentGroup({ id: 'ag-1', name: 'Agent', folder: 'agent', is_admin: 0, agent_provider: null, container_config: null, created_at: now() });
createMessagingGroup({ id: 'mg-test', channel_type: 'discord', platform_id: 'chan-test', name: 'Test', is_group: 0, admin_user_id: null, created_at: now() });
createAgentGroup({
id: 'ag-1',
name: 'Agent',
folder: 'agent',
is_admin: 0,
agent_provider: null,
container_config: null,
created_at: now(),
});
createMessagingGroup({
id: 'mg-test',
channel_type: 'discord',
platform_id: 'chan-test',
name: 'Test',
is_group: 0,
admin_user_id: null,
created_at: now(),
});
const { session } = resolveSession('ag-1', 'mg-test', null, 'shared');
@@ -245,7 +326,10 @@ describe('delivery', () => {
VALUES ('out-1', datetime('now'), 0, 'chat', 'chan-123', 'discord', ?)`,
).run(JSON.stringify({ text: 'Agent response' }));
const undelivered = db.prepare("SELECT * FROM messages_out WHERE delivered = 0").all() as Array<{ id: string; content: string }>;
const undelivered = db.prepare('SELECT * FROM messages_out WHERE delivered = 0').all() as Array<{
id: string;
content: string;
}>;
db.close();
expect(undelivered).toHaveLength(1);
+17 -4
View File
@@ -89,12 +89,16 @@ async function sweepSession(session: Session): Promise<void> {
for (const msg of staleMessages) {
if (msg.tries >= MAX_TRIES) {
db.prepare("UPDATE messages_in SET status = 'failed', status_changed = datetime('now') WHERE id = ?").run(msg.id);
db.prepare("UPDATE messages_in SET status = 'failed', status_changed = datetime('now') WHERE id = ?").run(
msg.id,
);
log.warn('Message marked as failed after max retries', { messageId: msg.id, sessionId: session.id });
} else {
const backoffMs = BACKOFF_BASE_MS * Math.pow(2, msg.tries);
const backoffSec = Math.floor(backoffMs / 1000);
db.prepare(`UPDATE messages_in SET status = 'pending', status_changed = datetime('now'), process_after = datetime('now', '+${backoffSec} seconds') WHERE id = ?`).run(msg.id);
db.prepare(
`UPDATE messages_in SET status = 'pending', status_changed = datetime('now'), process_after = datetime('now', '+${backoffSec} seconds') WHERE id = ?`,
).run(msg.id);
log.info('Reset stale message with backoff', { messageId: msg.id, tries: msg.tries, backoffMs });
}
}
@@ -102,7 +106,16 @@ async function sweepSession(session: Session): Promise<void> {
// 3. Handle recurrence for completed messages
const completedRecurring = db
.prepare("SELECT * FROM messages_in WHERE status = 'completed' AND recurrence IS NOT NULL")
.all() as Array<{ id: string; kind: string; content: string; recurrence: string; process_after: string | null; platform_id: string | null; channel_type: string | null; thread_id: string | null }>;
.all() as Array<{
id: string;
kind: string;
content: string;
recurrence: string;
process_after: string | null;
platform_id: string | null;
channel_type: string | null;
thread_id: string | null;
}>;
for (const msg of completedRecurring) {
try {
@@ -118,7 +131,7 @@ async function sweepSession(session: Session): Promise<void> {
).run(newId, msg.kind, nextRun, msg.recurrence, msg.platform_id, msg.channel_type, msg.thread_id, msg.content);
// Remove recurrence from the completed message so it doesn't spawn again
db.prepare("UPDATE messages_in SET recurrence = NULL WHERE id = ?").run(msg.id);
db.prepare('UPDATE messages_in SET recurrence = NULL WHERE id = ?').run(msg.id);
log.info('Inserted next recurrence', { originalId: msg.id, newId, nextRun });
} catch (err) {
+15 -3
View File
@@ -48,13 +48,20 @@ export async function routeInbound(event: InboundEvent): Promise<void> {
created_at: new Date().toISOString(),
};
createMessagingGroup(mg);
log.info('Auto-created messaging group', { id: mgId, channelType: event.channelType, platformId: event.platformId });
log.info('Auto-created messaging group', {
id: mgId,
channelType: event.channelType,
platformId: event.platformId,
});
}
// 2. Resolve agent group via messaging_group_agents
const agents = getMessagingGroupAgents(mg.id);
if (agents.length === 0) {
log.warn('No agent groups configured for messaging group', { messagingGroupId: mg.id, platformId: event.platformId });
log.warn('No agent groups configured for messaging group', {
messagingGroupId: mg.id,
platformId: event.platformId,
});
return;
}
@@ -79,7 +86,12 @@ export async function routeInbound(event: InboundEvent): Promise<void> {
content: event.message.content,
});
log.info('Message routed', { sessionId: session.id, agentGroup: match.agent_group_id, kind: event.message.kind, created });
log.info('Message routed', {
sessionId: session.id,
agentGroup: match.agent_group_id,
kind: event.message.kind,
created,
});
// 5. Wake container
const freshSession = getSession(session.id);
+21 -12
View File
@@ -35,7 +35,12 @@ function generateId(): string {
* Find or create a session for a messaging group + thread.
* Returns the session and whether it was newly created.
*/
export function resolveSession(agentGroupId: string, messagingGroupId: string, threadId: string | null, sessionMode: 'shared' | 'per-thread'): { session: Session; created: boolean } {
export function resolveSession(
agentGroupId: string,
messagingGroupId: string,
threadId: string | null,
sessionMode: 'shared' | 'per-thread',
): { session: Session; created: boolean } {
// For shared mode, look for any active session with this messaging group (threadId ignored)
// For per-thread mode, look for an active session with this specific thread
const lookupThreadId = sessionMode === 'shared' ? null : threadId;
@@ -83,17 +88,21 @@ export function initSessionFolder(agentGroupId: string, sessionId: string): void
}
/** Write a message to a session's messages_in table. */
export function writeSessionMessage(agentGroupId: string, sessionId: string, message: {
id: string;
kind: string;
timestamp: string;
platformId?: string | null;
channelType?: string | null;
threadId?: string | null;
content: string;
processAfter?: string | null;
recurrence?: string | null;
}): void {
export function writeSessionMessage(
agentGroupId: string,
sessionId: string,
message: {
id: string;
kind: string;
timestamp: string;
platformId?: string | null;
channelType?: string | null;
threadId?: string | null;
content: string;
processAfter?: string | null;
recurrence?: string | null;
},
): void {
const dbPath = sessionDbPath(agentGroupId, sessionId);
const db = new Database(dbPath);
db.pragma('journal_mode = WAL');