diff --git a/docs/.generated/config-baseline.channel.json b/docs/.generated/config-baseline.channel.json index 08f78e5b768..ffbb21c8e8e 100644 --- a/docs/.generated/config-baseline.channel.json +++ b/docs/.generated/config-baseline.channel.json @@ -13821,16 +13821,6 @@ "tags": [], "hasChildren": false }, - { - "path": "channels.matrix.groups.*.allow", - "kind": "channel", - "type": "boolean", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, { "path": "channels.matrix.groups.*.allowBots", "kind": "channel", @@ -14200,16 +14190,6 @@ "tags": [], "hasChildren": false }, - { - "path": "channels.matrix.rooms.*.allow", - "kind": "channel", - "type": "boolean", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, { "path": "channels.matrix.rooms.*.allowBots", "kind": "channel", diff --git a/docs/.generated/config-baseline.core.json b/docs/.generated/config-baseline.core.json index 2cd4bbea7d0..eb4e40ed8ee 100644 --- a/docs/.generated/config-baseline.core.json +++ b/docs/.generated/config-baseline.core.json @@ -1704,7 +1704,7 @@ "tags": [ "automation" ], - "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage, line, bluebubbles, feishu, matrix, mattermost, msteams, nextcloud-talk, nostr, qqbot, synology-chat, tlon, twitch, zalo, zalouser.", + "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: feishu, googlechat, nostr, msteams, mattermost, nextcloud-talk, matrix, bluebubbles, line, zalo, zalouser, synology-chat, tlon, discord, imessage, irc, qqbot, signal, slack, telegram, twitch, whatsapp.", "hasChildren": false }, { @@ -4532,7 +4532,7 @@ "tags": [ "automation" ], - "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage, line, bluebubbles, feishu, matrix, mattermost, msteams, nextcloud-talk, nostr, qqbot, synology-chat, tlon, twitch, zalo, zalouser.", + "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: feishu, googlechat, nostr, msteams, mattermost, nextcloud-talk, matrix, bluebubbles, line, zalo, zalouser, synology-chat, tlon, discord, imessage, irc, qqbot, signal, slack, telegram, twitch, whatsapp.", "hasChildren": false }, { @@ -15426,6 +15426,16 @@ "tags": [], "hasChildren": false }, + { + "path": "models.providers.*.models.*.contextTokens", + "kind": "core", + "type": "integer", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, { "path": "models.providers.*.models.*.contextWindow", "kind": "core", diff --git a/docs/.generated/config-baseline.json b/docs/.generated/config-baseline.json index b07b4ee3151..63c2a496be1 100644 --- a/docs/.generated/config-baseline.json +++ b/docs/.generated/config-baseline.json @@ -1703,7 +1703,7 @@ "tags": [ "automation" ], - "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage, line, bluebubbles, feishu, matrix, mattermost, msteams, nextcloud-talk, nostr, qqbot, synology-chat, tlon, twitch, zalo, zalouser.", + "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: feishu, googlechat, nostr, msteams, mattermost, nextcloud-talk, matrix, bluebubbles, line, zalo, zalouser, synology-chat, tlon, discord, imessage, irc, qqbot, signal, slack, telegram, twitch, whatsapp.", "hasChildren": false }, { @@ -4531,7 +4531,7 @@ "tags": [ "automation" ], - "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage, line, bluebubbles, feishu, matrix, mattermost, msteams, nextcloud-talk, nostr, qqbot, synology-chat, tlon, twitch, zalo, zalouser.", + "help": "Delivery target (\"last\", \"none\", or a channel id). Known channels: feishu, googlechat, nostr, msteams, mattermost, nextcloud-talk, matrix, bluebubbles, line, zalo, zalouser, synology-chat, tlon, discord, imessage, irc, qqbot, signal, slack, telegram, twitch, whatsapp.", "hasChildren": false }, { @@ -15425,6 +15425,16 @@ "tags": [], "hasChildren": false }, + { + "path": "models.providers.*.models.*.contextTokens", + "kind": "core", + "type": "integer", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, { "path": "models.providers.*.models.*.contextWindow", "kind": "core", @@ -41851,16 +41861,6 @@ "tags": [], "hasChildren": false }, - { - "path": "channels.matrix.groups.*.allow", - "kind": "channel", - "type": "boolean", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, { "path": "channels.matrix.groups.*.allowBots", "kind": "channel", @@ -42230,16 +42230,6 @@ "tags": [], "hasChildren": false }, - { - "path": "channels.matrix.rooms.*.allow", - "kind": "channel", - "type": "boolean", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, { "path": "channels.matrix.rooms.*.allowBots", "kind": "channel", @@ -65406,6 +65396,120 @@ ], "label": "@openclaw/memory-core Config", "help": "Plugin-defined config payload for memory-core.", + "hasChildren": true + }, + { + "path": "plugins.entries.memory-core.config.dreaming", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.memory-core.config.dreaming.frequency", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Dreaming Frequency", + "help": "Optional cron cadence override for managed dreaming runs.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.limit", + "kind": "plugin", + "type": "number", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "performance" + ], + "label": "Promotion Limit", + "help": "Maximum short-term candidates promoted per dreaming run (set to 0 to skip promotions).", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.minRecallCount", + "kind": "plugin", + "type": "number", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Promotion Min Recalls", + "help": "Minimum recall count required for automatic promotion.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.minScore", + "kind": "plugin", + "type": "number", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Promotion Min Score", + "help": "Minimum weighted rank required for automatic promotion.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.minUniqueQueries", + "kind": "plugin", + "type": "number", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Promotion Min Queries", + "help": "Minimum unique query count required for automatic promotion.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.mode", + "kind": "plugin", + "type": "string", + "required": true, + "enumValues": [ + "off", + "core", + "deep", + "rem" + ], + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Dreaming Mode", + "help": "Select dreaming mode: off, core, deep, or rem.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.timezone", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Dreaming Timezone", + "help": "IANA timezone for the managed dreaming cron schedule.", "hasChildren": false }, { @@ -67287,6 +67391,21 @@ ], "label": "@openclaw/openai-provider Config", "help": "Plugin-defined config payload for openai.", + "hasChildren": true + }, + { + "path": "plugins.entries.openai.config.personalityOverlay", + "kind": "plugin", + "type": "string", + "required": false, + "enumValues": [ + "friendly", + "off" + ], + "defaultValue": "friendly", + "deprecated": false, + "sensitive": false, + "tags": [], "hasChildren": false }, { @@ -71224,6 +71343,199 @@ "label": "Public Webhook URL", "hasChildren": false }, + { + "path": "plugins.entries.voice-call.config.realtime", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.enabled", + "kind": "plugin", + "type": "boolean", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Enable Realtime Voice", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.instructions", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Realtime Instructions", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.provider", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Realtime Voice Provider", + "help": "Uses the first registered realtime voice provider when unset.", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.providers", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Realtime Provider Config", + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.providers.*", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.streamPath", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced", + "storage" + ], + "label": "Realtime Stream Path", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools", + "kind": "plugin", + "type": "array", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.description", + "kind": "plugin", + "type": "string", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.name", + "kind": "plugin", + "type": "string", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters", + "kind": "plugin", + "type": "object", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters.properties", + "kind": "plugin", + "type": "object", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters.required", + "kind": "plugin", + "type": "array", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters.required.*", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters.type", + "kind": "plugin", + "type": "string", + "required": true, + "enumValues": [ + "object" + ], + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.type", + "kind": "plugin", + "type": "string", + "required": true, + "enumValues": [ + "function" + ], + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, { "path": "plugins.entries.voice-call.config.responseModel", "kind": "plugin", @@ -71235,6 +71547,7 @@ "advanced" ], "label": "Response Model", + "help": "Optional override. Falls back to the runtime default model when unset.", "hasChildren": false }, { @@ -71423,21 +71736,6 @@ "tags": [], "hasChildren": false }, - { - "path": "plugins.entries.voice-call.config.streaming.openaiApiKey", - "kind": "plugin", - "type": "string", - "required": false, - "deprecated": false, - "sensitive": true, - "tags": [ - "advanced", - "auth", - "security" - ], - "label": "OpenAI Realtime API Key", - "hasChildren": false - }, { "path": "plugins.entries.voice-call.config.streaming.preStartTimeoutMs", "kind": "plugin", @@ -71449,9 +71747,36 @@ "hasChildren": false }, { - "path": "plugins.entries.voice-call.config.streaming.silenceDurationMs", + "path": "plugins.entries.voice-call.config.streaming.provider", "kind": "plugin", - "type": "integer", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Streaming Provider", + "help": "Uses the first registered realtime transcription provider when unset.", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.streaming.providers", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Streaming Provider Config", + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.streaming.providers.*", + "kind": "plugin", + "type": "object", "required": false, "deprecated": false, "sensitive": false, @@ -71472,76 +71797,6 @@ "label": "Media Stream Path", "hasChildren": false }, - { - "path": "plugins.entries.voice-call.config.streaming.sttModel", - "kind": "plugin", - "type": "string", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [ - "advanced", - "media" - ], - "label": "Realtime STT Model", - "hasChildren": false - }, - { - "path": "plugins.entries.voice-call.config.streaming.sttProvider", - "kind": "plugin", - "type": "string", - "required": false, - "enumValues": [ - "openai-realtime" - ], - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, - { - "path": "plugins.entries.voice-call.config.streaming.vadThreshold", - "kind": "plugin", - "type": "number", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, - { - "path": "plugins.entries.voice-call.config.stt", - "kind": "plugin", - "type": "object", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": true - }, - { - "path": "plugins.entries.voice-call.config.stt.model", - "kind": "plugin", - "type": "string", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, - { - "path": "plugins.entries.voice-call.config.stt.provider", - "kind": "plugin", - "type": "string", - "required": false, - "enumValues": [ - "openai" - ], - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, { "path": "plugins.entries.voice-call.config.tailscale", "kind": "plugin", @@ -71839,7 +72094,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [], + "tags": [ + "advanced", + "media" + ], + "label": "TTS Provider Config", "hasChildren": true }, { @@ -71994,12 +72253,10 @@ "deprecated": false, "sensitive": true, "tags": [ - "advanced", "auth", "media", "security" ], - "label": "ElevenLabs API Key", "hasChildren": false }, { @@ -72025,11 +72282,9 @@ "deprecated": false, "sensitive": false, "tags": [ - "advanced", "media", "url-secret" ], - "label": "ElevenLabs Base URL", "hasChildren": false }, { @@ -72049,12 +72304,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media", - "models" - ], - "label": "ElevenLabs Model ID", + "tags": [], "hasChildren": false }, { @@ -72074,11 +72324,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], - "label": "ElevenLabs Voice ID", + "tags": [], "hasChildren": false }, { @@ -72269,12 +72515,10 @@ "deprecated": false, "sensitive": true, "tags": [ - "advanced", "auth", "media", "security" ], - "label": "OpenAI API Key", "hasChildren": false }, { @@ -72307,12 +72551,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media", - "models" - ], - "label": "OpenAI TTS Model", + "tags": [], "hasChildren": false }, { @@ -72332,11 +72571,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], - "label": "OpenAI TTS Voice", + "tags": [], "hasChildren": false }, { diff --git a/docs/.generated/config-baseline.plugin.json b/docs/.generated/config-baseline.plugin.json index 3a142863820..898f06fad47 100644 --- a/docs/.generated/config-baseline.plugin.json +++ b/docs/.generated/config-baseline.plugin.json @@ -5731,6 +5731,120 @@ ], "label": "@openclaw/memory-core Config", "help": "Plugin-defined config payload for memory-core.", + "hasChildren": true + }, + { + "path": "plugins.entries.memory-core.config.dreaming", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.memory-core.config.dreaming.frequency", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Dreaming Frequency", + "help": "Optional cron cadence override for managed dreaming runs.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.limit", + "kind": "plugin", + "type": "number", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "performance" + ], + "label": "Promotion Limit", + "help": "Maximum short-term candidates promoted per dreaming run (set to 0 to skip promotions).", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.minRecallCount", + "kind": "plugin", + "type": "number", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Promotion Min Recalls", + "help": "Minimum recall count required for automatic promotion.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.minScore", + "kind": "plugin", + "type": "number", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Promotion Min Score", + "help": "Minimum weighted rank required for automatic promotion.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.minUniqueQueries", + "kind": "plugin", + "type": "number", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Promotion Min Queries", + "help": "Minimum unique query count required for automatic promotion.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.mode", + "kind": "plugin", + "type": "string", + "required": true, + "enumValues": [ + "off", + "core", + "deep", + "rem" + ], + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Dreaming Mode", + "help": "Select dreaming mode: off, core, deep, or rem.", + "hasChildren": false + }, + { + "path": "plugins.entries.memory-core.config.dreaming.timezone", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Dreaming Timezone", + "help": "IANA timezone for the managed dreaming cron schedule.", "hasChildren": false }, { @@ -7612,6 +7726,21 @@ ], "label": "@openclaw/openai-provider Config", "help": "Plugin-defined config payload for openai.", + "hasChildren": true + }, + { + "path": "plugins.entries.openai.config.personalityOverlay", + "kind": "plugin", + "type": "string", + "required": false, + "enumValues": [ + "friendly", + "off" + ], + "defaultValue": "friendly", + "deprecated": false, + "sensitive": false, + "tags": [], "hasChildren": false }, { @@ -11549,6 +11678,199 @@ "label": "Public Webhook URL", "hasChildren": false }, + { + "path": "plugins.entries.voice-call.config.realtime", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.enabled", + "kind": "plugin", + "type": "boolean", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Enable Realtime Voice", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.instructions", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Realtime Instructions", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.provider", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Realtime Voice Provider", + "help": "Uses the first registered realtime voice provider when unset.", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.providers", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Realtime Provider Config", + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.providers.*", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.streamPath", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced", + "storage" + ], + "label": "Realtime Stream Path", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools", + "kind": "plugin", + "type": "array", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.description", + "kind": "plugin", + "type": "string", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.name", + "kind": "plugin", + "type": "string", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters", + "kind": "plugin", + "type": "object", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters.properties", + "kind": "plugin", + "type": "object", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters.required", + "kind": "plugin", + "type": "array", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters.required.*", + "kind": "plugin", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.parameters.type", + "kind": "plugin", + "type": "string", + "required": true, + "enumValues": [ + "object" + ], + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.realtime.tools.*.type", + "kind": "plugin", + "type": "string", + "required": true, + "enumValues": [ + "function" + ], + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, { "path": "plugins.entries.voice-call.config.responseModel", "kind": "plugin", @@ -11560,6 +11882,7 @@ "advanced" ], "label": "Response Model", + "help": "Optional override. Falls back to the runtime default model when unset.", "hasChildren": false }, { @@ -11748,21 +12071,6 @@ "tags": [], "hasChildren": false }, - { - "path": "plugins.entries.voice-call.config.streaming.openaiApiKey", - "kind": "plugin", - "type": "string", - "required": false, - "deprecated": false, - "sensitive": true, - "tags": [ - "advanced", - "auth", - "security" - ], - "label": "OpenAI Realtime API Key", - "hasChildren": false - }, { "path": "plugins.entries.voice-call.config.streaming.preStartTimeoutMs", "kind": "plugin", @@ -11774,9 +12082,36 @@ "hasChildren": false }, { - "path": "plugins.entries.voice-call.config.streaming.silenceDurationMs", + "path": "plugins.entries.voice-call.config.streaming.provider", "kind": "plugin", - "type": "integer", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Streaming Provider", + "help": "Uses the first registered realtime transcription provider when unset.", + "hasChildren": false + }, + { + "path": "plugins.entries.voice-call.config.streaming.providers", + "kind": "plugin", + "type": "object", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "advanced" + ], + "label": "Streaming Provider Config", + "hasChildren": true + }, + { + "path": "plugins.entries.voice-call.config.streaming.providers.*", + "kind": "plugin", + "type": "object", "required": false, "deprecated": false, "sensitive": false, @@ -11797,76 +12132,6 @@ "label": "Media Stream Path", "hasChildren": false }, - { - "path": "plugins.entries.voice-call.config.streaming.sttModel", - "kind": "plugin", - "type": "string", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [ - "advanced", - "media" - ], - "label": "Realtime STT Model", - "hasChildren": false - }, - { - "path": "plugins.entries.voice-call.config.streaming.sttProvider", - "kind": "plugin", - "type": "string", - "required": false, - "enumValues": [ - "openai-realtime" - ], - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, - { - "path": "plugins.entries.voice-call.config.streaming.vadThreshold", - "kind": "plugin", - "type": "number", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, - { - "path": "plugins.entries.voice-call.config.stt", - "kind": "plugin", - "type": "object", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": true - }, - { - "path": "plugins.entries.voice-call.config.stt.model", - "kind": "plugin", - "type": "string", - "required": false, - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, - { - "path": "plugins.entries.voice-call.config.stt.provider", - "kind": "plugin", - "type": "string", - "required": false, - "enumValues": [ - "openai" - ], - "deprecated": false, - "sensitive": false, - "tags": [], - "hasChildren": false - }, { "path": "plugins.entries.voice-call.config.tailscale", "kind": "plugin", @@ -12164,7 +12429,11 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [], + "tags": [ + "advanced", + "media" + ], + "label": "TTS Provider Config", "hasChildren": true }, { @@ -12319,12 +12588,10 @@ "deprecated": false, "sensitive": true, "tags": [ - "advanced", "auth", "media", "security" ], - "label": "ElevenLabs API Key", "hasChildren": false }, { @@ -12350,11 +12617,9 @@ "deprecated": false, "sensitive": false, "tags": [ - "advanced", "media", "url-secret" ], - "label": "ElevenLabs Base URL", "hasChildren": false }, { @@ -12374,12 +12639,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media", - "models" - ], - "label": "ElevenLabs Model ID", + "tags": [], "hasChildren": false }, { @@ -12399,11 +12659,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], - "label": "ElevenLabs Voice ID", + "tags": [], "hasChildren": false }, { @@ -12594,12 +12850,10 @@ "deprecated": false, "sensitive": true, "tags": [ - "advanced", "auth", "media", "security" ], - "label": "OpenAI API Key", "hasChildren": false }, { @@ -12632,12 +12886,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media", - "models" - ], - "label": "OpenAI TTS Model", + "tags": [], "hasChildren": false }, { @@ -12657,11 +12906,7 @@ "required": false, "deprecated": false, "sensitive": false, - "tags": [ - "advanced", - "media" - ], - "label": "OpenAI TTS Voice", + "tags": [], "hasChildren": false }, { diff --git a/extensions/matrix/src/config-schema.test.ts b/extensions/matrix/src/config-schema.test.ts index e222aa3cfb0..806c66ceb78 100644 --- a/extensions/matrix/src/config-schema.test.ts +++ b/extensions/matrix/src/config-schema.test.ts @@ -37,7 +37,7 @@ describe("MatrixConfigSchema SecretInput", () => { accessToken: "token", groups: { "!room:example.org": { - allow: true, + enabled: true, account: "axis", }, }, @@ -55,7 +55,7 @@ describe("MatrixConfigSchema SecretInput", () => { accessToken: "token", rooms: { "!room:example.org": { - allow: true, + enabled: true, account: "axis", }, }, diff --git a/extensions/matrix/src/config-schema.ts b/extensions/matrix/src/config-schema.ts index 4845a2152de..da43e5b3d2a 100644 --- a/extensions/matrix/src/config-schema.ts +++ b/extensions/matrix/src/config-schema.ts @@ -45,7 +45,6 @@ const matrixRoomSchema = z .object({ account: z.string().optional(), enabled: z.boolean().optional(), - allow: z.boolean().optional(), requireMention: z.boolean().optional(), allowBots: z.union([z.boolean(), z.literal("mentions")]).optional(), tools: ToolPolicySchema, diff --git a/extensions/matrix/src/doctor.test.ts b/extensions/matrix/src/doctor.test.ts index 489e497e928..bf593c6ac76 100644 --- a/extensions/matrix/src/doctor.test.ts +++ b/extensions/matrix/src/doctor.test.ts @@ -8,6 +8,7 @@ import { collectMatrixInstallPathWarnings, formatMatrixLegacyCryptoPreview, formatMatrixLegacyStatePreview, + matrixDoctor, runMatrixDoctorSequence, } from "./doctor.js"; @@ -125,4 +126,50 @@ describe("matrix doctor", () => { }); expect(sequence.changeNotes.join("\n")).toContain("Matrix migration snapshot"); }); + + it("normalizes legacy Matrix room allow aliases to enabled", () => { + const normalize = matrixDoctor.normalizeCompatibilityConfig; + expect(normalize).toBeDefined(); + if (!normalize) { + return; + } + + const result = normalize({ + cfg: { + channels: { + matrix: { + groups: { + "!ops:example.org": { + allow: true, + }, + }, + accounts: { + work: { + rooms: { + "!legacy:example.org": { + allow: false, + }, + }, + }, + }, + }, + }, + } as never, + }); + + expect(result.config.channels?.matrix?.groups?.["!ops:example.org"]).toEqual({ + enabled: true, + }); + expect(result.config.channels?.matrix?.accounts?.work?.rooms?.["!legacy:example.org"]).toEqual( + { + enabled: false, + }, + ); + expect(result.changes).toEqual( + expect.arrayContaining([ + "Moved channels.matrix.groups.!ops:example.org.allow → channels.matrix.groups.!ops:example.org.enabled (true).", + "Moved channels.matrix.accounts.work.rooms.!legacy:example.org.allow → channels.matrix.accounts.work.rooms.!legacy:example.org.enabled (false).", + ]), + ); + }); }); diff --git a/extensions/matrix/src/doctor.ts b/extensions/matrix/src/doctor.ts index cf1019f6bac..c34d57bee59 100644 --- a/extensions/matrix/src/doctor.ts +++ b/extensions/matrix/src/doctor.ts @@ -1,4 +1,8 @@ -import type { ChannelDoctorAdapter } from "openclaw/plugin-sdk/channel-contract"; +import { + type ChannelDoctorAdapter, + type ChannelDoctorConfigMutation, + type ChannelDoctorLegacyConfigRule, +} from "openclaw/plugin-sdk/channel-contract"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { detectPluginInstallPathIssue, @@ -19,6 +23,161 @@ function isRecord(value: unknown): value is Record { return Boolean(value) && typeof value === "object" && !Array.isArray(value); } +function hasLegacyMatrixRoomAllowAlias(value: unknown): boolean { + const room = isRecord(value) ? value : null; + return Boolean(room && typeof room.allow === "boolean"); +} + +function hasLegacyMatrixRoomMapAllowAliases(value: unknown): boolean { + const rooms = isRecord(value) ? value : null; + return Boolean(rooms && Object.values(rooms).some((room) => hasLegacyMatrixRoomAllowAlias(room))); +} + +function hasLegacyMatrixAccountRoomAllowAliases(value: unknown): boolean { + const accounts = isRecord(value) ? value : null; + if (!accounts) { + return false; + } + return Object.values(accounts).some((account) => { + if (!isRecord(account)) { + return false; + } + return ( + hasLegacyMatrixRoomMapAllowAliases(account.groups) || + hasLegacyMatrixRoomMapAllowAliases(account.rooms) + ); + }); +} + +function normalizeMatrixRoomAllowAliases(params: { + rooms: Record; + pathPrefix: string; + changes: string[]; +}): { rooms: Record; changed: boolean } { + let changed = false; + const nextRooms: Record = { ...params.rooms }; + for (const [roomId, roomValue] of Object.entries(params.rooms)) { + const room = isRecord(roomValue) ? roomValue : null; + if (!room || typeof room.allow !== "boolean") { + continue; + } + const nextRoom = { ...room }; + if (typeof nextRoom.enabled !== "boolean") { + nextRoom.enabled = room.allow; + } + delete nextRoom.allow; + nextRooms[roomId] = nextRoom; + changed = true; + params.changes.push( + `Moved ${params.pathPrefix}.${roomId}.allow → ${params.pathPrefix}.${roomId}.enabled (${String(nextRoom.enabled)}).`, + ); + } + return { rooms: nextRooms, changed }; +} + +function normalizeMatrixCompatibilityConfig(cfg: OpenClawConfig): ChannelDoctorConfigMutation { + const channels = isRecord(cfg.channels) ? cfg.channels : null; + const matrix = isRecord(channels?.matrix) ? channels.matrix : null; + if (!matrix) { + return { config: cfg, changes: [] }; + } + + const changes: string[] = []; + let updatedMatrix: Record = matrix; + let changed = false; + + const normalizeTopLevelRoomScope = (key: "groups" | "rooms") => { + const rooms = isRecord(updatedMatrix[key]) ? updatedMatrix[key] : null; + if (!rooms) { + return; + } + const normalized = normalizeMatrixRoomAllowAliases({ + rooms, + pathPrefix: `channels.matrix.${key}`, + changes, + }); + if (normalized.changed) { + updatedMatrix = { ...updatedMatrix, [key]: normalized.rooms }; + changed = true; + } + }; + + normalizeTopLevelRoomScope("groups"); + normalizeTopLevelRoomScope("rooms"); + + const accounts = isRecord(updatedMatrix.accounts) ? updatedMatrix.accounts : null; + if (accounts) { + let accountsChanged = false; + const nextAccounts: Record = { ...accounts }; + for (const [accountId, accountValue] of Object.entries(accounts)) { + const account = isRecord(accountValue) ? accountValue : null; + if (!account) { + continue; + } + let nextAccount: Record = account; + let accountChanged = false; + for (const key of ["groups", "rooms"] as const) { + const rooms = isRecord(nextAccount[key]) ? nextAccount[key] : null; + if (!rooms) { + continue; + } + const normalized = normalizeMatrixRoomAllowAliases({ + rooms, + pathPrefix: `channels.matrix.accounts.${accountId}.${key}`, + changes, + }); + if (normalized.changed) { + nextAccount = { ...nextAccount, [key]: normalized.rooms }; + accountChanged = true; + } + } + if (accountChanged) { + nextAccounts[accountId] = nextAccount; + accountsChanged = true; + } + } + if (accountsChanged) { + updatedMatrix = { ...updatedMatrix, accounts: nextAccounts }; + changed = true; + } + } + + if (!changed) { + return { config: cfg, changes: [] }; + } + return { + config: { + ...cfg, + channels: { + ...cfg.channels, + matrix: updatedMatrix as OpenClawConfig["channels"]["matrix"], + }, + }, + changes, + }; +} + +const MATRIX_LEGACY_CONFIG_RULES: ChannelDoctorLegacyConfigRule[] = [ + { + path: ["channels", "matrix", "groups"], + message: + "channels.matrix.groups..allow is legacy; use channels.matrix.groups..enabled instead (auto-migrated on load).", + match: hasLegacyMatrixRoomMapAllowAliases, + }, + { + path: ["channels", "matrix", "rooms"], + message: + "channels.matrix.rooms..allow is legacy; use channels.matrix.rooms..enabled instead (auto-migrated on load).", + match: hasLegacyMatrixRoomMapAllowAliases, + }, + { + path: ["channels", "matrix", "accounts"], + message: + "channels.matrix.accounts..{groups,rooms}..allow is legacy; use channels.matrix.accounts..{groups,rooms}..enabled instead (auto-migrated on load).", + match: hasLegacyMatrixAccountRoomAllowAliases, + }, +]; + function hasConfiguredMatrixChannel(cfg: OpenClawConfig): boolean { const channels = cfg.channels as Record | undefined; return isRecord(channels?.matrix); @@ -259,6 +418,8 @@ export const matrixDoctor: ChannelDoctorAdapter = { groupModel: "sender", groupAllowFromFallbackToAllowFrom: false, warnOnEmptyGroupSenderAllowlist: true, + legacyConfigRules: MATRIX_LEGACY_CONFIG_RULES, + normalizeCompatibilityConfig: ({ cfg }) => normalizeMatrixCompatibilityConfig(cfg), runConfigSequence: async ({ cfg, env, shouldRepair }) => await runMatrixDoctorSequence({ cfg, env, shouldRepair }), cleanStaleConfig: async ({ cfg }) => await cleanStaleMatrixPluginConfig(cfg), diff --git a/extensions/matrix/src/matrix/accounts.test.ts b/extensions/matrix/src/matrix/accounts.test.ts index 886338ac5c0..c112cea94f7 100644 --- a/extensions/matrix/src/matrix/accounts.test.ts +++ b/extensions/matrix/src/matrix/accounts.test.ts @@ -476,15 +476,15 @@ describe("resolveMatrixAccount", () => { matrix: { groups: { "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!axis-room:example.org": { - allow: true, + enabled: true, account: "axis", }, "!unassigned-room:example.org": { - allow: true, + enabled: true, }, }, accounts: { @@ -503,20 +503,20 @@ describe("resolveMatrixAccount", () => { expect(resolveMatrixAccount({ cfg, accountId: "default" }).config.groups).toEqual({ "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!unassigned-room:example.org": { - allow: true, + enabled: true, }, }); expect(resolveMatrixAccount({ cfg, accountId: "axis" }).config.groups).toEqual({ "!axis-room:example.org": { - allow: true, + enabled: true, account: "axis", }, "!unassigned-room:example.org": { - allow: true, + enabled: true, }, }); }); @@ -529,15 +529,15 @@ describe("resolveMatrixAccount", () => { accessToken: "default-token", groups: { "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!ops-room:example.org": { - allow: true, + enabled: true, account: "ops", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }, accounts: { @@ -552,20 +552,20 @@ describe("resolveMatrixAccount", () => { expect(resolveMatrixAccount({ cfg, accountId: "default" }).config.groups).toEqual({ "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }); expect(resolveMatrixAccount({ cfg, accountId: "ops" }).config.groups).toEqual({ "!ops-room:example.org": { - allow: true, + enabled: true, account: "ops", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }); }); @@ -576,15 +576,15 @@ describe("resolveMatrixAccount", () => { matrix: { rooms: { "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!axis-room:example.org": { - allow: true, + enabled: true, account: "axis", }, "!unassigned-room:example.org": { - allow: true, + enabled: true, }, }, accounts: { @@ -603,20 +603,20 @@ describe("resolveMatrixAccount", () => { expect(resolveMatrixAccount({ cfg, accountId: "default" }).config.rooms).toEqual({ "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!unassigned-room:example.org": { - allow: true, + enabled: true, }, }); expect(resolveMatrixAccount({ cfg, accountId: "axis" }).config.rooms).toEqual({ "!axis-room:example.org": { - allow: true, + enabled: true, account: "axis", }, "!unassigned-room:example.org": { - allow: true, + enabled: true, }, }); }); @@ -629,15 +629,15 @@ describe("resolveMatrixAccount", () => { accessToken: "default-token", rooms: { "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!ops-room:example.org": { - allow: true, + enabled: true, account: "ops", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }, accounts: { @@ -652,20 +652,20 @@ describe("resolveMatrixAccount", () => { expect(resolveMatrixAccount({ cfg, accountId: "default" }).config.rooms).toEqual({ "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }); expect(resolveMatrixAccount({ cfg, accountId: "ops" }).config.rooms).toEqual({ "!ops-room:example.org": { - allow: true, + enabled: true, account: "ops", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }); }); @@ -683,15 +683,15 @@ describe("resolveMatrixAccount", () => { matrix: { groups: { "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!ops-room:example.org": { - allow: true, + enabled: true, account: "ops", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }, }, @@ -700,11 +700,11 @@ describe("resolveMatrixAccount", () => { expect(resolveMatrixAccount({ cfg, accountId: "ops", env }).config.groups).toEqual({ "!ops-room:example.org": { - allow: true, + enabled: true, account: "ops", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }); }); @@ -715,11 +715,11 @@ describe("resolveMatrixAccount", () => { matrix: { groups: { "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }, accounts: { @@ -734,7 +734,7 @@ describe("resolveMatrixAccount", () => { expect(resolveMatrixAccount({ cfg, accountId: "ops" }).config.groups).toEqual({ "!shared-room:example.org": { - allow: true, + enabled: true, }, }); }); @@ -745,11 +745,11 @@ describe("resolveMatrixAccount", () => { matrix: { rooms: { "!default-room:example.org": { - allow: true, + enabled: true, account: "default", }, "!shared-room:example.org": { - allow: true, + enabled: true, }, }, accounts: { @@ -764,7 +764,7 @@ describe("resolveMatrixAccount", () => { expect(resolveMatrixAccount({ cfg, accountId: "ops" }).config.rooms).toEqual({ "!shared-room:example.org": { - allow: true, + enabled: true, }, }); }); @@ -775,7 +775,7 @@ describe("resolveMatrixAccount", () => { matrix: { groups: { "!shared-room:example.org": { - allow: true, + enabled: true, }, }, accounts: { @@ -798,7 +798,7 @@ describe("resolveMatrixAccount", () => { matrix: { rooms: { "!shared-room:example.org": { - allow: true, + enabled: true, }, }, accounts: { diff --git a/extensions/matrix/src/matrix/config-update.test.ts b/extensions/matrix/src/matrix/config-update.test.ts index 65b27e3e8fe..b89c5d9fd55 100644 --- a/extensions/matrix/src/matrix/config-update.test.ts +++ b/extensions/matrix/src/matrix/config-update.test.ts @@ -122,7 +122,7 @@ describe("updateMatrixAccountConfig", () => { policy: "pairing", }, groups: { - "!default:example.org": { allow: true }, + "!default:example.org": { enabled: true }, }, accounts: { ops: { @@ -145,14 +145,14 @@ describe("updateMatrixAccountConfig", () => { }, groupPolicy: "allowlist", groups: { - "!ops-room:example.org": { allow: true }, + "!ops-room:example.org": { enabled: true }, }, rooms: null, }); expect(updated.channels?.["matrix"]?.dm?.policy).toBe("pairing"); expect(updated.channels?.["matrix"]?.groups).toEqual({ - "!default:example.org": { allow: true }, + "!default:example.org": { enabled: true }, }); expect(updated.channels?.["matrix"]?.accounts?.ops).toMatchObject({ dm: { @@ -162,7 +162,7 @@ describe("updateMatrixAccountConfig", () => { }, groupPolicy: "allowlist", groups: { - "!ops-room:example.org": { allow: true }, + "!ops-room:example.org": { enabled: true }, }, }); expect(updated.channels?.["matrix"]?.accounts?.ops?.rooms).toBeUndefined(); diff --git a/extensions/matrix/src/matrix/monitor/config.test.ts b/extensions/matrix/src/matrix/monitor/config.test.ts index 0b85ef811d5..10bf43e7469 100644 --- a/extensions/matrix/src/matrix/monitor/config.test.ts +++ b/extensions/matrix/src/matrix/monitor/config.test.ts @@ -39,13 +39,13 @@ describe("resolveMatrixMonitorConfig", () => { ); const roomsConfig: MatrixRoomsConfig = { - "*": { allow: true }, + "*": { enabled: true }, "room:!ops:example.org": { - allow: true, + enabled: true, users: ["Dana", "user:@Erin:Example.org"], }, General: { - allow: true, + enabled: true, }, }; @@ -62,13 +62,13 @@ describe("resolveMatrixMonitorConfig", () => { expect(result.allowFrom).toEqual(["@alice:example.org", "@bob:example.org"]); expect(result.groupAllowFrom).toEqual(["@carol:example.org"]); expect(result.roomsConfig).toEqual({ - "*": { allow: true }, + "*": { enabled: true }, "!ops:example.org": { - allow: true, + enabled: true, users: ["@dana:example.org", "@erin:example.org"], }, "!general:example.org": { - allow: true, + enabled: true, }, }); expect(resolveTargets).toHaveBeenCalledTimes(3); @@ -116,7 +116,7 @@ describe("resolveMatrixMonitorConfig", () => { groupAllowFrom: ["matrix:@known:example.org"], roomsConfig: { "channel:Project X": { - allow: true, + enabled: true, users: ["matrix:Ghost"], }, }, @@ -174,7 +174,7 @@ describe("resolveMatrixMonitorConfig", () => { accountId: "ops", roomsConfig: { "#allowed:example.org": { - allow: true, + enabled: true, }, }, runtime, @@ -183,7 +183,7 @@ describe("resolveMatrixMonitorConfig", () => { expect(result.roomsConfig).toEqual({ "!allowed-room:example.org": { - allow: true, + enabled: true, }, }); expect(resolveTargets).toHaveBeenCalledWith( diff --git a/extensions/matrix/src/matrix/monitor/rooms.test.ts b/extensions/matrix/src/matrix/monitor/rooms.test.ts index 6ee158cd302..0dbfa6e75da 100644 --- a/extensions/matrix/src/matrix/monitor/rooms.test.ts +++ b/extensions/matrix/src/matrix/monitor/rooms.test.ts @@ -4,9 +4,9 @@ import { resolveMatrixRoomConfig } from "./rooms.js"; describe("resolveMatrixRoomConfig", () => { it("matches room IDs and aliases, not names", () => { const rooms = { - "!room:example.org": { allow: true }, - "#alias:example.org": { allow: true }, - "Project Room": { allow: true }, + "!room:example.org": { enabled: true }, + "#alias:example.org": { enabled: true }, + "Project Room": { enabled: true }, }; const byId = resolveMatrixRoomConfig({ @@ -26,7 +26,7 @@ describe("resolveMatrixRoomConfig", () => { expect(byAlias.matchKey).toBe("#alias:example.org"); const byName = resolveMatrixRoomConfig({ - rooms: { "Project Room": { allow: true } }, + rooms: { "Project Room": { enabled: true } }, roomId: "!different:example.org", aliases: [], }); @@ -37,7 +37,7 @@ describe("resolveMatrixRoomConfig", () => { describe("matchSource classification", () => { it('returns matchSource="direct" for exact room ID match', () => { const result = resolveMatrixRoomConfig({ - rooms: { "!room:example.org": { allow: true } }, + rooms: { "!room:example.org": { enabled: true } }, roomId: "!room:example.org", aliases: [], }); @@ -47,7 +47,7 @@ describe("resolveMatrixRoomConfig", () => { it('returns matchSource="direct" for alias match', () => { const result = resolveMatrixRoomConfig({ - rooms: { "#alias:example.org": { allow: true } }, + rooms: { "#alias:example.org": { enabled: true } }, roomId: "!room:example.org", aliases: ["#alias:example.org"], }); @@ -57,7 +57,7 @@ describe("resolveMatrixRoomConfig", () => { it('returns matchSource="wildcard" for wildcard match', () => { const result = resolveMatrixRoomConfig({ - rooms: { "*": { allow: true } }, + rooms: { "*": { enabled: true } }, roomId: "!any:example.org", aliases: [], }); @@ -67,7 +67,7 @@ describe("resolveMatrixRoomConfig", () => { it("returns undefined matchSource when no match", () => { const result = resolveMatrixRoomConfig({ - rooms: { "!other:example.org": { allow: true } }, + rooms: { "!other:example.org": { enabled: true } }, roomId: "!room:example.org", aliases: [], }); @@ -78,8 +78,8 @@ describe("resolveMatrixRoomConfig", () => { it("direct match takes priority over wildcard", () => { const result = resolveMatrixRoomConfig({ rooms: { - "!room:example.org": { allow: true, systemPrompt: "room-specific" }, - "*": { allow: true, systemPrompt: "generic" }, + "!room:example.org": { enabled: true, systemPrompt: "room-specific" }, + "*": { enabled: true, systemPrompt: "generic" }, }, roomId: "!room:example.org", aliases: [], @@ -96,7 +96,7 @@ describe("resolveMatrixRoomConfig", () => { it("wildcard config should NOT be usable to override DM classification", () => { const result = resolveMatrixRoomConfig({ - rooms: { "*": { allow: true, skills: ["general"] } }, + rooms: { "*": { enabled: true, skills: ["general"] } }, roomId: "!dm-room:example.org", aliases: [], }); @@ -108,8 +108,8 @@ describe("resolveMatrixRoomConfig", () => { it("explicitly configured room should be usable to override DM classification", () => { const result = resolveMatrixRoomConfig({ rooms: { - "!configured-room:example.org": { allow: true }, - "*": { allow: true }, + "!configured-room:example.org": { enabled: true }, + "*": { enabled: true }, }, roomId: "!configured-room:example.org", aliases: [], diff --git a/extensions/matrix/src/matrix/monitor/rooms.ts b/extensions/matrix/src/matrix/monitor/rooms.ts index 159e51766d8..d428fac31c0 100644 --- a/extensions/matrix/src/matrix/monitor/rooms.ts +++ b/extensions/matrix/src/matrix/monitor/rooms.ts @@ -9,6 +9,11 @@ export type MatrixRoomConfigResolved = { matchSource?: "direct" | "wildcard"; }; +function readLegacyRoomAllowAlias(room: MatrixRoomConfig | undefined): boolean | undefined { + const rawRoom = room as Record | undefined; + return typeof rawRoom?.allow === "boolean" ? rawRoom.allow : undefined; +} + export function resolveMatrixRoomConfig(params: { rooms?: Record; roomId: string; @@ -33,7 +38,8 @@ export function resolveMatrixRoomConfig(params: { wildcardKey: "*", }); const resolved = matched ?? wildcardEntry; - const allowed = resolved ? resolved.enabled !== false && resolved.allow !== false : false; + const legacyAllow = readLegacyRoomAllowAlias(resolved); + const allowed = resolved ? resolved.enabled !== false && legacyAllow !== false : false; const matchKey = matchedKey ?? wildcardKey; const matchSource = matched ? "direct" : wildcardEntry ? "wildcard" : undefined; return { diff --git a/extensions/matrix/src/onboarding.test.ts b/extensions/matrix/src/onboarding.test.ts index 469a054b5fd..3cefb9e689e 100644 --- a/extensions/matrix/src/onboarding.test.ts +++ b/extensions/matrix/src/onboarding.test.ts @@ -308,7 +308,7 @@ describe("matrix onboarding", () => { }, groupPolicy: "allowlist", groups: { - "!ops-room:example.org": { allow: true }, + "!ops-room:example.org": { enabled: true }, }, }); expect(result.cfg.channels?.["matrix"]?.dm).toBeUndefined(); diff --git a/extensions/matrix/src/onboarding.ts b/extensions/matrix/src/onboarding.ts index 91e35a89e3a..211fa313f75 100644 --- a/extensions/matrix/src/onboarding.ts +++ b/extensions/matrix/src/onboarding.ts @@ -183,7 +183,7 @@ function setMatrixGroupPolicy( } function setMatrixGroupRooms(cfg: CoreConfig, roomKeys: string[], accountId?: string) { - const groups = Object.fromEntries(roomKeys.map((key) => [key, { allow: true }])); + const groups = Object.fromEntries(roomKeys.map((key) => [key, { enabled: true }])); return updateMatrixAccountConfig(cfg, resolveMatrixOnboardingAccountId(cfg, accountId), { groups, rooms: null, diff --git a/extensions/matrix/src/types.ts b/extensions/matrix/src/types.ts index 6ea0178fdf7..4924bb895bc 100644 --- a/extensions/matrix/src/types.ts +++ b/extensions/matrix/src/types.ts @@ -23,10 +23,8 @@ export type MatrixDmConfig = { export type MatrixRoomConfig = { /** Restrict this room entry to a specific Matrix account in multi-account setups. */ account?: string; - /** If false, disable the bot in this room (alias for allow: false). */ + /** If false, disable the bot in this room. */ enabled?: boolean; - /** Legacy room allow toggle; prefer enabled. */ - allow?: boolean; /** Require mentioning the bot to trigger replies. */ requireMention?: boolean; /** diff --git a/src/config/bundled-channel-config-metadata.generated.ts b/src/config/bundled-channel-config-metadata.generated.ts index 4463cc218f2..e88192d8bb7 100644 --- a/src/config/bundled-channel-config-metadata.generated.ts +++ b/src/config/bundled-channel-config-metadata.generated.ts @@ -6856,9 +6856,6 @@ export const GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA = [ enabled: { type: "boolean", }, - allow: { - type: "boolean", - }, requireMention: { type: "boolean", }, @@ -6938,9 +6935,6 @@ export const GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA = [ enabled: { type: "boolean", }, - allow: { - type: "boolean", - }, requireMention: { type: "boolean", }, diff --git a/src/config/legacy-migrate.test.ts b/src/config/legacy-migrate.test.ts index 24ecb9f947a..01bebd1fbb2 100644 --- a/src/config/legacy-migrate.test.ts +++ b/src/config/legacy-migrate.test.ts @@ -558,7 +558,7 @@ describe("legacy migrate nested channel enabled aliases", () => { }); }); - it("moves legacy allow toggles into enabled for slack, googlechat, and discord", () => { + it("moves legacy allow toggles into enabled for slack, googlechat, discord, and matrix", () => { const res = migrateLegacyConfig({ channels: { slack: { @@ -617,6 +617,22 @@ describe("legacy migrate nested channel enabled aliases", () => { }, }, }, + matrix: { + groups: { + "!ops:example.org": { + allow: false, + }, + }, + accounts: { + work: { + rooms: { + "!legacy:example.org": { + allow: true, + }, + }, + }, + }, + }, }, }); @@ -638,6 +654,12 @@ describe("legacy migrate nested channel enabled aliases", () => { expect(res.changes).toContain( "Moved channels.discord.accounts.work.guilds.200.channels.help.allow → channels.discord.accounts.work.guilds.200.channels.help.enabled.", ); + expect(res.changes).toContain( + "Moved channels.matrix.groups.!ops:example.org.allow → channels.matrix.groups.!ops:example.org.enabled (false).", + ); + expect(res.changes).toContain( + "Moved channels.matrix.accounts.work.rooms.!legacy:example.org.allow → channels.matrix.accounts.work.rooms.!legacy:example.org.enabled (true).", + ); expect(res.config?.channels?.slack?.channels?.ops).toEqual({ enabled: false, }); @@ -647,6 +669,12 @@ describe("legacy migrate nested channel enabled aliases", () => { expect(res.config?.channels?.discord?.guilds?.["100"]?.channels?.general).toEqual({ enabled: false, }); + expect(res.config?.channels?.matrix?.groups?.["!ops:example.org"]).toEqual({ + enabled: false, + }); + expect(res.config?.channels?.matrix?.accounts?.work?.rooms?.["!legacy:example.org"]).toEqual({ + enabled: true, + }); }); it("drops legacy allow when enabled is already set", () => {