fix: add sessionChannelId mapping for message_sent
- Add sessionChannelId Map to track sessionKey -> channelId - Save channelId in before_model_resolve when we have derived.channelId - Fix message_sent to use sessionChannelId fallback when ctx.channelId is undefined - Add debug logging to message_sent
This commit is contained in:
@@ -26,6 +26,7 @@ type DebugConfig = {
|
||||
const sessionDecision = new Map<string, DecisionRecord>();
|
||||
const sessionAllowed = new Map<string, boolean>(); // Track if session was allowed to speak (true) or forced no-reply (false)
|
||||
const sessionInjected = new Set<string>(); // Track which sessions have already injected the end marker
|
||||
const sessionChannelId = new Map<string, string>(); // Track sessionKey -> channelId mapping
|
||||
const MAX_SESSION_DECISIONS = 2000;
|
||||
const DECISION_TTL_MS = 5 * 60 * 1000;
|
||||
function buildEndMarkerInstruction(endSymbols: string[], isGroupChat: boolean): string {
|
||||
@@ -636,6 +637,10 @@ export default {
|
||||
}
|
||||
// Allowed to speak - record this session as allowed
|
||||
sessionAllowed.set(key, true);
|
||||
// Also save channelId for this session
|
||||
if (derived.channelId) {
|
||||
sessionChannelId.set(key, derived.channelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -808,33 +813,74 @@ export default {
|
||||
// NOTE: This hook is synchronous, do not use async/await
|
||||
api.on("before_message_write", (event, ctx) => {
|
||||
try {
|
||||
const key = ctx.sessionKey;
|
||||
const channelId = ctx.channelId as string | undefined;
|
||||
const accountId = ctx.accountId as string | undefined;
|
||||
// Debug: print all available keys in event and ctx
|
||||
api.logger.info(
|
||||
`whispergate: DEBUG before_message_write eventKeys=${JSON.stringify(Object.keys(event ?? {}))} ctxKeys=${JSON.stringify(Object.keys(ctx ?? {}))}`,
|
||||
);
|
||||
|
||||
// Try multiple sources for channelId and accountId
|
||||
const deliveryContext = (ctx as Record<string, unknown>)?.deliveryContext as Record<string, unknown> | undefined;
|
||||
let key = ctx.sessionKey;
|
||||
let channelId = ctx.channelId as string | undefined;
|
||||
let accountId = ctx.accountId as string | undefined;
|
||||
let content = (event.content as string) || "";
|
||||
|
||||
// Fallback: get channelId from deliveryContext.to
|
||||
if (!channelId && deliveryContext?.to) {
|
||||
const toStr = String(deliveryContext.to);
|
||||
channelId = toStr.startsWith("channel:") ? toStr.replace("channel:", "") : toStr;
|
||||
}
|
||||
|
||||
// Fallback: get accountId from deliveryContext.accountId
|
||||
if (!accountId && deliveryContext?.accountId) {
|
||||
accountId = String(deliveryContext.accountId);
|
||||
}
|
||||
|
||||
// Fallback: get content from event.message.content
|
||||
if (!content && (event as Record<string, unknown>).message) {
|
||||
const msg = (event as Record<string, unknown>).message as Record<string, unknown>;
|
||||
content = String(msg.content ?? "");
|
||||
}
|
||||
|
||||
// Always log for debugging - show all available info
|
||||
api.logger.info(
|
||||
`whispergate: DEBUG before_message_write session=${key ?? "undefined"} channel=${channelId ?? "undefined"} accountId=${accountId ?? "undefined"} contentType=${typeof content} content=${String(content).slice(0, 200)}`,
|
||||
);
|
||||
|
||||
if (!key || !channelId || !accountId) return;
|
||||
|
||||
const live = getLivePluginConfig(api, baseConfig as WhisperGateConfig) as WhisperGateConfig & DebugConfig;
|
||||
|
||||
// Get the agent's output content
|
||||
const content = (event.content as string) || "";
|
||||
const trimmed = content.trim();
|
||||
const isNoReply = /^NO_REPLY$/i.test(trimmed);
|
||||
|
||||
if (!isNoReply) return;
|
||||
// Log turn state for debugging
|
||||
const turnDebug = getTurnDebugInfo(channelId);
|
||||
api.logger.info(
|
||||
`whispergate: DEBUG turn state channel=${channelId} turnOrder=${JSON.stringify(turnDebug.turnOrder)} currentSpeaker=${turnDebug.currentSpeaker} noRepliedThisCycle=${JSON.stringify([...turnDebug.noRepliedThisCycle])}`,
|
||||
);
|
||||
|
||||
if (!isNoReply) {
|
||||
api.logger.info(
|
||||
`whispergate: before_message_write content is not NO_REPLY, skipping channel=${channelId}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this session was forced no-reply or allowed to speak
|
||||
const wasAllowed = sessionAllowed.get(key);
|
||||
api.logger.info(
|
||||
`whispergate: DEBUG NO_REPLY detected session=${key} wasAllowed=${wasAllowed}`,
|
||||
);
|
||||
|
||||
if (wasAllowed === undefined) return; // No record, skip
|
||||
|
||||
if (wasAllowed === false) {
|
||||
// Forced no-reply - do not advance turn
|
||||
sessionAllowed.delete(key);
|
||||
if (shouldDebugLog(live, channelId)) {
|
||||
api.logger.info(
|
||||
`whispergate: before_message_write forced no-reply session=${key} channel=${channelId} - not advancing turn`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -844,11 +890,9 @@ export default {
|
||||
|
||||
sessionAllowed.delete(key);
|
||||
|
||||
if (shouldDebugLog(live, channelId)) {
|
||||
api.logger.info(
|
||||
`whispergate: before_message_write real no-reply session=${key} channel=${channelId} nextSpeaker=${nextSpeaker ?? "dormant"}`,
|
||||
);
|
||||
}
|
||||
|
||||
// If all agents NO_REPLY'd (dormant), don't trigger handoff
|
||||
if (!nextSpeaker) {
|
||||
@@ -880,9 +924,19 @@ export default {
|
||||
// Turn advance: when an agent sends a message, check if it signals end of turn
|
||||
api.on("message_sent", async (event, ctx) => {
|
||||
try {
|
||||
const channelId = ctx.channelId;
|
||||
const accountId = ctx.accountId;
|
||||
const content = event.content || "";
|
||||
const key = ctx.sessionKey;
|
||||
// Try ctx.channelId first, fallback to sessionChannelId mapping
|
||||
let channelId = ctx.channelId as string | undefined;
|
||||
if (!channelId && key) {
|
||||
channelId = sessionChannelId.get(key);
|
||||
}
|
||||
const accountId = ctx.accountId as string | undefined;
|
||||
const content = (event.content as string) || "";
|
||||
|
||||
// Debug log
|
||||
api.logger.info(
|
||||
`whispergate: DEBUG message_sent session=${key ?? "undefined"} channelId=${channelId ?? "undefined"} accountId=${accountId ?? "undefined"} content=${content.slice(0, 100)}`,
|
||||
);
|
||||
|
||||
if (!channelId || !accountId) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user