fix(chat): show inbound channel messages on the active main session (#1055)

This commit is contained in:
paisley
2026-05-21 15:01:50 +08:00
committed by GitHub
parent 94de6fb08e
commit 3659179fc9
4 changed files with 35 additions and 1 deletions

View File

@@ -1596,6 +1596,7 @@ function isInternalMessage(msg: { role?: unknown; content?: unknown; idempotency
if (!hasImageUrlBlock) return true;
}
}
if (msg.role === 'user' && /^\[OpenClaw heartbeat poll\]\s*$/i.test(text.trim())) return true;
// Runtime system injections: these arrive as user or assistant-role messages
// but are internal plumbing (exec results, async-command notices, time pings, etc.)
if ((msg.role === 'user' || msg.role === 'assistant') && isRuntimeSystemInjection(text)) return true;
@@ -3146,8 +3147,17 @@ export const useChatStore = create<ChatState>((set, get) => ({
return;
}
// Only process events for the active run (or if no active run set)
// Only process events for the active run (or if no active run set).
// Inbound channel traffic (Feishu/Telegram/etc.) on the current session uses a
// different runId than a stale desktop activeRunId — still refresh history on finals.
if (activeRunId && runId && runId !== activeRunId) {
const isCurrentSession = eventSessionKey == null || eventSessionKey === currentSessionKey;
const inboundTerminal = eventState === 'final' || eventState === 'error'
|| (event.message && typeof event.message === 'object'
&& getMessageStopReason(event.message as Record<string, unknown>) != null);
if (isCurrentSession && inboundTerminal) {
void get().loadHistory(true);
}
return;
}

View File

@@ -1084,6 +1084,7 @@ function isInternalMessage(msg: { role?: unknown; content?: unknown }): boolean
if (msg.role === 'assistant') {
if (/^(HEARTBEAT_OK|NO_REPLY)\s*$/.test(text)) return true;
}
if (msg.role === 'user' && /^\[OpenClaw heartbeat poll\]\s*$/i.test(text.trim())) return true;
// Runtime system injections: these arrive as user or assistant-role messages
// but are internal plumbing (exec results, async-command notices, time pings, etc.)
if ((msg.role === 'user' || msg.role === 'assistant') && isRuntimeSystemInjection(text)) return true;

View File

@@ -153,6 +153,21 @@ function maybeLoadHistory(
void state.loadHistory(true);
}
/** Bump sidebar ordering when any session receives gateway traffic (e.g. Feishu DM). */
function touchSessionActivity(sessionKey: string | null | undefined, activityMs = Date.now()): void {
if (!sessionKey) return;
import('./chat')
.then(({ useChatStore }) => {
useChatStore.setState((state) => ({
sessionLastActivity: {
...state.sessionLastActivity,
[sessionKey]: Math.max(state.sessionLastActivity[sessionKey] ?? 0, activityMs),
},
}));
})
.catch(() => {});
}
function handleGatewayNotification(notification: { method?: string; params?: Record<string, unknown> } | undefined): void {
const payload = notification;
if (!payload || payload.method !== 'agent' || !payload.params || typeof payload.params !== 'object') {
@@ -185,6 +200,10 @@ function handleGatewayNotification(notification: { method?: string; params?: Rec
const runId = p.runId ?? data.runId;
const sessionKey = p.sessionKey ?? data.sessionKey;
const resolvedSessionKeyForActivity = sessionKey != null ? String(sessionKey) : null;
if (resolvedSessionKeyForActivity) {
touchSessionActivity(resolvedSessionKeyForActivity);
}
if (phase === 'started' && runId != null && sessionKey != null) {
import('./chat')
.then(({ useChatStore }) => {

View File

@@ -29,4 +29,8 @@ describe('chat internal message filter', () => {
expect(isInternalMessage({ role: 'assistant', content })).toBe(false);
});
it('filters OpenClaw heartbeat poll user turns', () => {
expect(isInternalMessage({ role: 'user', content: '[OpenClaw heartbeat poll]' })).toBe(true);
});
});