feat(plugin): inject 🔚 ending instruction for bypass/end-symbol discord turns
This commit is contained in:
@@ -4,6 +4,9 @@
|
||||
|
||||
- `message:received` caches a per-session decision from deterministic rules.
|
||||
- `before_model_resolve` applies `providerOverride + modelOverride` when decision says no-reply.
|
||||
- `before_prompt_build` prepends instruction `你的这次发言必须以🔚作为结尾。` when decision is:
|
||||
- `bypass_sender`
|
||||
- `end_symbol:*`
|
||||
|
||||
## Rules (in order)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ type DecisionRecord = {
|
||||
const sessionDecision = new Map<string, DecisionRecord>();
|
||||
const MAX_SESSION_DECISIONS = 2000;
|
||||
const DECISION_TTL_MS = 5 * 60 * 1000;
|
||||
const END_MARKER_INSTRUCTION = "你的这次发言必须以🔚作为结尾。";
|
||||
|
||||
function normalizeChannel(ctx: Record<string, unknown>): string {
|
||||
const candidates = [ctx.commandSource, ctx.messageProvider, ctx.channelId, ctx.channel];
|
||||
@@ -48,6 +49,10 @@ function pruneDecisionMap(now = Date.now()) {
|
||||
}
|
||||
}
|
||||
|
||||
function shouldInjectEndMarker(reason: string): boolean {
|
||||
return reason === "bypass_sender" || reason.startsWith("end_symbol:");
|
||||
}
|
||||
|
||||
export default {
|
||||
id: "whispergate",
|
||||
name: "WhisperGate",
|
||||
@@ -87,10 +92,10 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
// one-shot decision per inbound turn
|
||||
sessionDecision.delete(key);
|
||||
if (!rec.decision.shouldUseNoReply) return;
|
||||
|
||||
// no-reply path is consumed here
|
||||
sessionDecision.delete(key);
|
||||
api.logger.info(
|
||||
`whispergate: override model for session=${key}, provider=${config.noReplyProvider}, model=${config.noReplyModel}, reason=${rec.decision.reason}`,
|
||||
);
|
||||
@@ -100,5 +105,27 @@ export default {
|
||||
modelOverride: config.noReplyModel,
|
||||
};
|
||||
});
|
||||
|
||||
api.on("before_prompt_build", async (_event, ctx) => {
|
||||
const key = ctx.sessionKey;
|
||||
if (!key) return;
|
||||
const rec = sessionDecision.get(key);
|
||||
if (!rec) return;
|
||||
|
||||
if (Date.now() - rec.createdAt > DECISION_TTL_MS) {
|
||||
sessionDecision.delete(key);
|
||||
return;
|
||||
}
|
||||
|
||||
// consume non-no-reply paths here to avoid stale carry-over
|
||||
sessionDecision.delete(key);
|
||||
|
||||
if (!shouldInjectEndMarker(rec.decision.reason)) return;
|
||||
|
||||
api.logger.info(`whispergate: prepend end marker instruction for session=${key}, reason=${rec.decision.reason}`);
|
||||
return {
|
||||
prependContext: END_MARKER_INSTRUCTION,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user