Skip to content

Commit caf09c8

Browse files
author
linyuan.yang
committed
中间件
1 parent e3caad8 commit caf09c8

5 files changed

Lines changed: 92 additions & 16 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
export type Middleware<T> = (ctx: T, next: () => Promise<void>) => Promise<void>;
2+
3+
export class MiddlewarePipeline<T> {
4+
private stack: Middleware<T>[] = [];
5+
6+
use(fn: Middleware<T>): this {
7+
this.stack.push(fn);
8+
return this;
9+
}
10+
11+
prepend(fn: Middleware<T>): this {
12+
this.stack.unshift(fn);
13+
return this;
14+
}
15+
16+
remove(fn: Middleware<T>): boolean {
17+
const idx = this.stack.indexOf(fn);
18+
if (idx === -1) return false;
19+
this.stack.splice(idx, 1);
20+
return true;
21+
}
22+
23+
async execute(ctx: T, final: (ctx: T) => Promise<void>): Promise<void> {
24+
let index = -1;
25+
const dispatch = async (i: number): Promise<void> => {
26+
if (i <= index) throw new Error('next() called multiple times');
27+
index = i;
28+
if (i < this.stack.length) {
29+
await this.stack[i](ctx, () => dispatch(i + 1));
30+
} else {
31+
await final(ctx);
32+
}
33+
};
34+
await dispatch(0);
35+
}
36+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { MiddlewarePipeline, type Middleware } from './MiddlewarePipeline';
2+
export type { MessageContext, AIContext } from './types';
3+
export { intentFilterMiddleware } from './intentFilter';
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { Middleware } from "./MiddlewarePipeline";
2+
import type { MessageContext } from "./types";
3+
import { getChannelSession } from "../Core/Database";
4+
import { config } from "../Core/Config";
5+
import { classifyIntent } from "../Processing/classifyIntent";
6+
7+
export const intentFilterMiddleware: Middleware<MessageContext> = async (ctx, next) => {
8+
if (ctx.args.mentionBot) return next();
9+
10+
const dbSession = await getChannelSession(ctx.args.dbSessionId);
11+
const channel = ctx.args.channelId ? config.getChannel(ctx.args.channelId) : undefined;
12+
const intentModel = dbSession?.intentModel != null ? dbSession.intentModel : channel?.intentModel;
13+
if (!intentModel) return next();
14+
15+
const intentPrompt = dbSession?.intentPrompt != null ? dbSession.intentPrompt : (channel?.intentPrompt ?? null);
16+
const intentThreshold = dbSession?.intentThreshold != null ? dbSession.intentThreshold : (channel?.intentThreshold ?? 0.7);
17+
18+
if (await classifyIntent(ctx.query, intentModel, intentPrompt, intentThreshold, ctx.threadId)) {
19+
return next();
20+
}
21+
ctx.filtered = true;
22+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { MessageContent } from "scorpio.ai";
2+
import type { ChannelMessageArgs, ChannelSessionHandler } from "channel.base";
3+
import type { ChannelRouteArgs } from "../Session/SessionManager";
4+
import type { AgentRunOptions } from "../Agent/AgentRunner";
5+
6+
export interface MessageContext {
7+
query: MessageContent;
8+
args: ChannelRouteArgs;
9+
threadId: string;
10+
filtered: boolean;
11+
}
12+
13+
export interface AIContext {
14+
query: MessageContent;
15+
args: ChannelMessageArgs;
16+
sessionHandler: ChannelSessionHandler;
17+
runOptions: Partial<AgentRunOptions>;
18+
metadata: Record<string, any>;
19+
}

packages/sbot/src/Session/SessionManager.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import { config } from "../Core/Config";
77
import { ChannelSessionRow, getChannelSession } from "../Core/Database";
88
import { channelManager } from "../Channel/ChannelManager";
99
import { createProcessAIHandler } from "../Processing/createProcessAIHandler";
10-
import { classifyIntent } from "../Processing/classifyIntent";
10+
import { MiddlewarePipeline } from "../Middleware/MiddlewarePipeline";
11+
import { intentFilterMiddleware } from "../Middleware/intentFilter";
12+
import type { MessageContext } from "../Middleware/types";
1113

1214
import { getBuiltInCommands } from "./BuiltInCommands";
1315
import { WebSocketSessionHandler } from "../Channel/web/WebSocketSessionHandler";
1416

15-
interface ChannelRouteArgs extends ChannelMessageArgs {
17+
export interface ChannelRouteArgs extends ChannelMessageArgs {
1618
channelType: string;
1719
channelId: string;
1820
dbSessionId: number;
@@ -148,9 +150,11 @@ function mergeMessageContents(items: { query: MessageContent }[]): MessageConten
148150

149151
export class SbotSessionManager extends SessionManager {
150152
private mergeBuffers = new Map<string, MergeBufferEntry>();
153+
readonly messagePipeline = new MiddlewarePipeline<MessageContext>();
151154

152155
constructor() {
153156
super();
157+
this.messagePipeline.use(intentFilterMiddleware);
154158
}
155159

156160
protected createSession(threadId: string): SessionService {
@@ -216,20 +220,12 @@ export class SbotSessionManager extends SessionManager {
216220
}
217221

218222
private async dispatchToSession(threadId: string, query: MessageContent, args: ChannelRouteArgs): Promise<void> {
219-
if (!await this.passIntentFilter(query, args, threadId)) return;
220-
const session = this.getOrCreate(threadId);
221-
await session.onReceiveMessage(query, args);
222-
}
223-
224-
private async passIntentFilter(query: MessageContent, args: ChannelRouteArgs, threadId: string): Promise<boolean> {
225-
if (args?.mentionBot) return true;
226-
const dbSession = await getChannelSession(args?.dbSessionId);
227-
const channel = args.channelId ? config.getChannel(args.channelId) : undefined;
228-
const intentModel = dbSession?.intentModel != null ? dbSession.intentModel : channel?.intentModel;
229-
if (!intentModel) return true;
230-
const intentPrompt = dbSession?.intentPrompt != null ? dbSession.intentPrompt : (channel?.intentPrompt ?? null);
231-
const intentThreshold = dbSession?.intentThreshold != null ? dbSession.intentThreshold : (channel?.intentThreshold ?? 0.7);
232-
return classifyIntent(query, intentModel, intentPrompt, intentThreshold, threadId);
223+
const ctx: MessageContext = { query, args, threadId, filtered: false };
224+
await this.messagePipeline.execute(ctx, async (c) => {
225+
if (c.filtered) return;
226+
const session = this.getOrCreate(c.threadId);
227+
await session.onReceiveMessage(c.query, c.args);
228+
});
233229
}
234230

235231
async onReceiveWebMessage(threadId: string, query: MessageContent, sessionId: string, dbSessionId: number): Promise<void> {

0 commit comments

Comments
 (0)