fix(matrix): count top-level default account

This commit is contained in:
Gustavo Madeira Santana
2026-04-01 10:23:22 -04:00
parent 5881e50638
commit bf8db8d55d
4 changed files with 131 additions and 4 deletions

View File

@@ -436,6 +436,7 @@ Docs: https://docs.openclaw.ai
- Google/models: resolve Gemini 3.1 pro, flash, and flash-lite for all Google provider aliases by passing the actual runtime provider ID and adding a template-provider fallback; fix flash-lite prefix ordering. (#56567)
- OpenAI Codex/image tools: register Codex for media understanding and route image prompts through Codex instructions so image analysis no longer fails on missing provider registration or missing `instructions`. (#54829) Thanks @neeravmakwana.
- Agents/image tool: restore the generic image-runtime fallback when no provider-specific media-understanding provider is registered, so image analysis works again for providers like `openrouter` and `minimax-portal`. (#54858) Thanks @MonkeyLeeT.
- Matrix/multi-account: keep room-level `account` scoping and implicit default-account selection consistent when the default Matrix account is configured directly on top-level `channels.matrix.*` alongside named accounts. (#58449) thanks @Daanvdplas.
- WhatsApp: fix infinite echo loop in self-chat DM mode where the bot's own outbound replies were re-processed as new inbound user messages. (#54570) Thanks @joelnishanth
- Telegram/splitting: replace proportional text estimate with verified HTML-length search so long messages split at word boundaries instead of mid-word; gracefully degrade when tag overhead exceeds the limit. (#56595)
- Telegram/delivery: skip whitespace-only and hook-blanked text replies in bot delivery to prevent GrammyError 400 empty-text crashes. (#56620)

View File

@@ -656,6 +656,8 @@ See [Pairing](/channels/pairing) for the shared DM pairing flow and storage layo
```
Top-level `channels.matrix` values act as defaults for named accounts unless an account overrides them.
You can scope inherited room entries to one Matrix account with `groups.<room>.account` (or legacy `rooms.<room>.account`).
Entries without `account` stay shared across all Matrix accounts, and entries with `account: "default"` still work when the default account is configured directly on top-level `channels.matrix.*`.
Set `defaultAccount` when you want OpenClaw to prefer one named Matrix account for implicit routing, probing, and CLI operations.
If you configure multiple named accounts, set `defaultAccount` or pass `--account <id>` for CLI commands that rely on implicit account selection.
Pass `--account <id>` to `openclaw matrix verify ...` and `openclaw matrix devices ...` when you want to override that implicit selection for one command.

View File

@@ -11,6 +11,8 @@ import {
} from "openclaw/plugin-sdk/account-id";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { listMatrixEnvAccountIds } from "./env-vars.js";
import { hasExplicitMatrixAccountConfig } from "./matrix/account-config.js";
import type { CoreConfig } from "./types.js";
function isRecord(value: unknown): value is Record<string, unknown> {
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -42,11 +44,15 @@ export function resolveConfiguredMatrixAccountIds(
env: NodeJS.ProcessEnv = process.env,
): string[] {
const channel = resolveMatrixChannelConfig(cfg);
const configuredAccountIds = listConfiguredAccountIds({
accounts: channel && isRecord(channel.accounts) ? channel.accounts : undefined,
normalizeAccountId,
});
if (channel && hasExplicitMatrixAccountConfig(cfg as CoreConfig, DEFAULT_ACCOUNT_ID)) {
configuredAccountIds.push(DEFAULT_ACCOUNT_ID);
}
return listCombinedAccountIds({
configuredAccountIds: listConfiguredAccountIds({
accounts: channel && isRecord(channel.accounts) ? channel.accounts : undefined,
normalizeAccountId,
}),
configuredAccountIds,
additionalAccountIds: listMatrixEnvAccountIds(env),
fallbackAccountIdWhenEmpty: channel ? DEFAULT_ACCOUNT_ID : undefined,
});

View File

@@ -260,6 +260,26 @@ describe("resolveMatrixAccount", () => {
expect(resolveDefaultMatrixAccountId(cfg)).toBe("default");
});
it("includes a top-level configured default account alongside named accounts", () => {
const cfg: CoreConfig = {
channels: {
matrix: {
homeserver: "https://matrix.example.org",
accessToken: "default-token",
accounts: {
ops: {
homeserver: "https://matrix.example.org",
accessToken: "ops-token",
},
},
},
},
};
expect(listMatrixAccountIds(cfg)).toEqual(["default", "ops"]);
expect(resolveDefaultMatrixAccountId(cfg)).toBe("default");
});
it('uses the synthetic "default" account when multiple named accounts need explicit selection', () => {
const cfg: CoreConfig = {
channels: {
@@ -458,6 +478,55 @@ describe("resolveMatrixAccount", () => {
});
});
it("filters channel-level groups when the default account is configured at the top level", () => {
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org",
accessToken: "default-token",
groups: {
"!default-room:example.org": {
allow: true,
account: "default",
},
"!ops-room:example.org": {
allow: true,
account: "ops",
},
"!shared-room:example.org": {
allow: true,
},
},
accounts: {
ops: {
homeserver: "https://matrix.example.org",
accessToken: "ops-token",
},
},
},
},
} as unknown as CoreConfig;
expect(resolveMatrixAccount({ cfg, accountId: "default" }).config.groups).toEqual({
"!default-room:example.org": {
allow: true,
account: "default",
},
"!shared-room:example.org": {
allow: true,
},
});
expect(resolveMatrixAccount({ cfg, accountId: "ops" }).config.groups).toEqual({
"!ops-room:example.org": {
allow: true,
account: "ops",
},
"!shared-room:example.org": {
allow: true,
},
});
});
it("filters legacy channel-level rooms by room account in multi-account setups", () => {
const cfg = {
channels: {
@@ -509,6 +578,55 @@ describe("resolveMatrixAccount", () => {
});
});
it("filters legacy channel-level rooms when the default account is configured at the top level", () => {
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org",
accessToken: "default-token",
rooms: {
"!default-room:example.org": {
allow: true,
account: "default",
},
"!ops-room:example.org": {
allow: true,
account: "ops",
},
"!shared-room:example.org": {
allow: true,
},
},
accounts: {
ops: {
homeserver: "https://matrix.example.org",
accessToken: "ops-token",
},
},
},
},
} as unknown as CoreConfig;
expect(resolveMatrixAccount({ cfg, accountId: "default" }).config.rooms).toEqual({
"!default-room:example.org": {
allow: true,
account: "default",
},
"!shared-room:example.org": {
allow: true,
},
});
expect(resolveMatrixAccount({ cfg, accountId: "ops" }).config.rooms).toEqual({
"!ops-room:example.org": {
allow: true,
account: "ops",
},
"!shared-room:example.org": {
allow: true,
},
});
});
it("honors injected env when scoping room entries in multi-account setups", () => {
const env = {
MATRIX_HOMESERVER: "https://matrix.example.org",