mirror of https://github.com/openclaw/openclaw.git
fix(matrix): fix multiple Conduit compatibility issues preventing message delivery
## Changes ### 1. Fix client.start() hanging forever (shared.ts) The bot-sdk's `client.start()` returns a promise that never resolves (infinite sync loop). The plugin awaited it, blocking the entire provider startup — `logged in as` never printed, no messages were processed. Fix: fire-and-forget with error handler + 2s initialization delay. ### 2. Fix DM false positive for 2-member rooms (direct.ts) `memberCount === 2` heuristic misclassified explicitly configured group rooms as DMs when only bot + one user were joined. Messages were routed through DM policy and silently dropped. Fix: remove member count heuristic; only trust `m.direct` account data and `is_direct` room state flag. Ref: #20145 ### 3. Prevent duplicate event listener registration (events.ts) When both bundled channel plugin and extension load, listeners were registered twice on the same shared client, causing inconsistent state. Fix: WeakSet guard to skip registration if client already has listeners. Ref: #18330 ### 4. Add startup grace period (index.ts) `startupGraceMs = 0` dropped messages timestamped during async setup. Especially problematic with Conduit which retries on `M_NOT_FOUND` during filter creation. Fix: 5-second grace period. ### 5. Fix room ID case sensitivity with Conduit (index.ts) Room IDs (`!xyz`) without `:server` suffix failed the `includes(':')` check and were sent to `resolveMatrixTargets`, which called Conduit's `resolveRoom` — returning lowercased IDs. The bot-sdk emits events with original-case IDs, causing config lookup mismatches and reply delivery failures (`M_UNKNOWN: non-create event for room of unknown version`). Fix: treat `!`-prefixed entries as room IDs directly (skip resolution). Only resolve `#alias:server` entries. ## Testing Tested with Conduit homeserver (lightweight Rust Matrix server). All fixes verified with gateway log tracing: - `logged in as @arvi:matrix.local` — first successful login - `room.message` events fire and reach handler - Room config matching returns `allowed: true` - Agent generates response and delivers it to Matrix room
This commit is contained in:
parent
43cad8268d
commit
f66f563c1a
|
|
@ -84,7 +84,15 @@ async function ensureSharedClientStarted(params: {
|
|||
}
|
||||
}
|
||||
|
||||
await client.start();
|
||||
// bot-sdk start() returns a promise that never resolves (infinite sync loop).
|
||||
// Fire-and-forget: the sync loop runs, events fire on the client,
|
||||
// but we must not await or the entire provider startup hangs.
|
||||
// See: https://github.com/openclaw/openclaw/issues/NEW
|
||||
client.start().catch((err: unknown) => {
|
||||
LogService.error("MatrixClientLite", "client.start() error:", err);
|
||||
});
|
||||
// Give the sync loop a moment to initialize
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
params.state.started = true;
|
||||
})();
|
||||
sharedClientStartPromises.set(key, startPromise);
|
||||
|
|
|
|||
|
|
@ -78,17 +78,13 @@ export function createDirectRoomTracker(client: MatrixClient, opts: DirectRoomTr
|
|||
const { roomId, senderId } = params;
|
||||
await refreshDmCache();
|
||||
|
||||
// Check m.direct account data (most authoritative)
|
||||
if (client.dms.isDm(roomId)) {
|
||||
log(`matrix: dm detected via m.direct room=${roomId}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
const memberCount = await resolveMemberCount(roomId);
|
||||
if (memberCount === 2) {
|
||||
log(`matrix: dm detected via member count room=${roomId} members=${memberCount}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check m.room.member state for is_direct flag
|
||||
const selfUserId = params.selfUserId ?? (await ensureSelfUserId());
|
||||
const directViaState =
|
||||
(await hasDirectFlag(roomId, senderId)) || (await hasDirectFlag(roomId, selfUserId ?? ""));
|
||||
|
|
@ -97,6 +93,12 @@ export function createDirectRoomTracker(client: MatrixClient, opts: DirectRoomTr
|
|||
return true;
|
||||
}
|
||||
|
||||
// Member count alone is NOT a reliable DM indicator.
|
||||
// Explicitly configured group rooms with 2 members (e.g. bot + one user)
|
||||
// were being misclassified as DMs, causing messages to be routed through
|
||||
// DM policy instead of group policy and silently dropped.
|
||||
// See: https://github.com/openclaw/openclaw/issues/20145
|
||||
const memberCount = await resolveMemberCount(roomId);
|
||||
log(`matrix: dm check room=${roomId} result=group members=${memberCount ?? "unknown"}`);
|
||||
return false;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@ import { sendReadReceiptMatrix } from "../send.js";
|
|||
import type { MatrixRawEvent } from "./types.js";
|
||||
import { EventType } from "./types.js";
|
||||
|
||||
// Track which clients have had monitor events registered to prevent
|
||||
// duplicate listener registration when the plugin loads twice
|
||||
// (e.g. bundled channel + extension both try to start).
|
||||
// See: https://github.com/openclaw/openclaw/issues/18330
|
||||
const registeredClients = new WeakSet<object>();
|
||||
|
||||
function createSelfUserIdResolver(client: Pick<MatrixClient, "getUserId">) {
|
||||
let selfUserId: string | undefined;
|
||||
let selfUserIdLookup: Promise<string | undefined> | undefined;
|
||||
|
|
@ -41,6 +47,12 @@ export function registerMatrixMonitorEvents(params: {
|
|||
formatNativeDependencyHint: PluginRuntime["system"]["formatNativeDependencyHint"];
|
||||
onRoomMessage: (roomId: string, event: MatrixRawEvent) => void | Promise<void>;
|
||||
}): void {
|
||||
if (registeredClients.has(params.client)) {
|
||||
console.error("[matrix] skipping duplicate listener registration for client");
|
||||
return;
|
||||
}
|
||||
registeredClients.add(params.client);
|
||||
|
||||
const {
|
||||
client,
|
||||
auth,
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|||
continue;
|
||||
}
|
||||
const cleaned = normalizeRoomEntry(trimmed);
|
||||
if ((cleaned.startsWith("!") || cleaned.startsWith("#")) && cleaned.includes(":")) {
|
||||
if (cleaned.startsWith("!") || (cleaned.startsWith("#") && cleaned.includes(":"))) {
|
||||
if (!nextRooms[cleaned]) {
|
||||
nextRooms[cleaned] = roomConfig;
|
||||
}
|
||||
|
|
@ -268,7 +268,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi
|
|||
const mediaMaxMb = opts.mediaMaxMb ?? accountConfig.mediaMaxMb ?? DEFAULT_MEDIA_MAX_MB;
|
||||
const mediaMaxBytes = Math.max(1, mediaMaxMb) * 1024 * 1024;
|
||||
const startupMs = Date.now();
|
||||
const startupGraceMs = 0;
|
||||
const startupGraceMs = 5000; // 5s grace for slow homeservers (e.g. Conduit filter M_NOT_FOUND retry)
|
||||
const directTracker = createDirectRoomTracker(client, { log: logVerboseMessage });
|
||||
registerMatrixAutoJoin({ client, cfg, runtime });
|
||||
const warnedEncryptedRooms = new Set<string>();
|
||||
|
|
|
|||
Loading…
Reference in New Issue