● Zion Boggan
repos/Zion Pm/lib/router.ts
zionboggan.com ↗
60 lines · typescript
History for this file →
1
import { getChannel, addMessage, type Message } from './db';
2
import { queryMemory, queryGraph } from './memory';
3
import { runConductor } from './mastra';
4
import { delegate } from './workers/delegate';
5
import type { ModelId, OllamaModel } from './workers/types';
6
 
7
const MENTION_RE = /@(glm|claude|codex|ollama)(?::(\S+))?/gi;
8
 
9
export interface Mention { model: ModelId; ollamaModel?: string; }
10
 
11
export function parseMentions(text: string): Mention[] {
12
  const out: Mention[] = [];
13
  let m: RegExpExecArray | null;
14
  MENTION_RE.lastIndex = 0;
15
  while ((m = MENTION_RE.exec(text)) !== null) {
16
    out.push({ model: m[1].toLowerCase() as ModelId, ollamaModel: m[2] });
17
  }
18
  return out;
19
}
20
 
21
const stripMentions = (text: string) => text.replace(MENTION_RE, '').replace(/\s{2,}/g, ' ').trim();
22
 
23
 
24
export async function handleMessage(channelId: string, userText: string): Promise<Message[]> {
25
  const ch = getChannel(channelId);
26
  if (!ch) throw new Error('channel not found');
27
 
28
  const userMsg = addMessage(channelId, 'user', userText, null);
29
 
30
  const mentions = parseMentions(userText);
31
  const targets: Mention[] = mentions.length ? mentions : [{ model: ch.default_model as ModelId }];
32
  const task = mentions.length ? stripMentions(userText) || userText : userText;
33
 
34
  const needsMemory = targets.some((t) => t.model === 'glm');
35
  const memoryContext = needsMemory ? await queryMemory(userText) : '';
36
 
37
  const produced: Message[] = [];
38
  for (const target of targets) {
39
    let reply = '';
40
    let authorModel: string = target.model;
41
    try {
42
      if (target.model === 'glm') {
43
        const graphContext = await queryGraph(userText);
44
        reply = await runConductor(userText, { memoryContext, graphContext });
45
      } else {
46
        const r = await delegate({
47
          model: target.model,
48
          ollamaModel: target.ollamaModel as OllamaModel | undefined,
49
          task,
50
        });
51
        authorModel = r.model;
52
        reply = r.ok ? r.output : `(${r.model} unavailable: ${r.error})`;
53
      }
54
    } catch (e) {
55
      reply = `(${target.model} error: ${(e as Error).message})`;
56
    }
57
    produced.push(addMessage(channelId, 'assistant', reply || '(empty reply)', authorModel, userMsg.id));
58
  }
59
  return produced;
60
}