feat: add Redis Stream handoff for AI dev + monitor all messages
- Publish every non-spam message to tower:stream:messages immediately after DB insert in ingest.processor — before any admin approval or routing decision - Remove early tags.length === 0 drop in main.ts so no-rule-match messages are now stored and streamed (monitor-all behaviour) - Wire classify worker, review/p1/dnc queues into main.ts - Add streams/message-stream.ts with XADD wrapper (capped at ~50k entries) - Add docs/DATA_MODELS.md — full data model reference for all 29 models Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { Worker, Queue } from 'bullmq';
|
||||
import Redis from 'ioredis';
|
||||
import { IngestJobData, ForwardJobData, IndexJobData } from '@tower/types';
|
||||
import { parseRedisUrl } from './redis-connection';
|
||||
import { approveMessage } from '../core/approve-message';
|
||||
import { publishToMessageStream } from '../streams/message-stream';
|
||||
import { createLogger } from '@tower/logger';
|
||||
|
||||
const logger = createLogger('ingest-processor');
|
||||
@@ -12,6 +14,7 @@ export async function processIngestJob(
|
||||
pool?: any,
|
||||
forwardQueue?: Queue<ForwardJobData>,
|
||||
indexQueue?: Queue<IndexJobData>,
|
||||
redis?: Redis,
|
||||
): Promise<void> {
|
||||
// Defensive: drop messages from non-CLAIMED groups
|
||||
const group = await prisma.group.findUnique({
|
||||
@@ -87,6 +90,22 @@ export async function processIngestJob(
|
||||
update: {},
|
||||
});
|
||||
|
||||
// Publish to AI-dev stream immediately — before any routing decision.
|
||||
// Admin approval controls forwarding only; it must never block the stream.
|
||||
if (redis) {
|
||||
publishToMessageStream(redis, {
|
||||
messageId: msg.id,
|
||||
tenantId: job.tenantId,
|
||||
content: job.content,
|
||||
senderJid: job.senderJid,
|
||||
senderName: job.senderName,
|
||||
sourceGroupId: job.sourceGroupId,
|
||||
tags: job.tags,
|
||||
effectiveAction: job.effectiveAction ?? null,
|
||||
timestamp: new Date().toISOString(),
|
||||
}).catch((err: unknown) => logger.warn({ err, messageId: msg.id }, 'Failed to publish to message stream'));
|
||||
}
|
||||
|
||||
// For REJECT, create an approval record so it's searchable as rejected
|
||||
if (job.effectiveAction === 'REJECT') {
|
||||
await prisma.approval.upsert({
|
||||
@@ -133,10 +152,11 @@ export function createIngestWorker(
|
||||
pool?: any,
|
||||
forwardQueue?: Queue<ForwardJobData>,
|
||||
indexQueue?: Queue<IndexJobData>,
|
||||
redis?: Redis,
|
||||
): Worker<IngestJobData> {
|
||||
return new Worker<IngestJobData>(
|
||||
'tower-ingest',
|
||||
async (job) => processIngestJob(job.data, prisma, pool, forwardQueue, indexQueue),
|
||||
async (job) => processIngestJob(job.data, prisma, pool, forwardQueue, indexQueue, redis),
|
||||
{ connection: parseRedisUrl(redisUrl) },
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user