mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 14:50:45 +00:00
fix(doctor): preserve discord streaming downgrade compatibility
This commit is contained in:
@@ -3,18 +3,7 @@ import type {
|
||||
ChannelDoctorLegacyConfigRule,
|
||||
} from "openclaw/plugin-sdk/channel-contract";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import {
|
||||
asObjectRecord,
|
||||
hasLegacyAccountStreamingAliases,
|
||||
hasLegacyStreamingAliases,
|
||||
normalizeLegacyDmAliases,
|
||||
normalizeLegacyStreamingAliases,
|
||||
} from "openclaw/plugin-sdk/runtime-doctor";
|
||||
import { resolveDiscordPreviewStreamMode } from "./preview-streaming.js";
|
||||
|
||||
function hasLegacyDiscordStreamingAliases(value: unknown): boolean {
|
||||
return hasLegacyStreamingAliases(value, { includePreviewChunk: true });
|
||||
}
|
||||
import { asObjectRecord, normalizeLegacyDmAliases } from "openclaw/plugin-sdk/runtime-doctor";
|
||||
|
||||
const LEGACY_TTS_PROVIDER_KEYS = ["openai", "elevenlabs", "microsoft", "edge"] as const;
|
||||
|
||||
@@ -114,18 +103,6 @@ function migrateLegacyTtsConfig(
|
||||
}
|
||||
|
||||
export const legacyConfigRules: ChannelDoctorLegacyConfigRule[] = [
|
||||
{
|
||||
path: ["channels", "discord"],
|
||||
message:
|
||||
"channels.discord.streamMode, channels.discord.streaming (scalar), chunkMode, blockStreaming, draftChunk, and blockStreamingCoalesce are legacy; use channels.discord.streaming.{mode,chunkMode,preview.chunk,block.enabled,block.coalesce}.",
|
||||
match: hasLegacyDiscordStreamingAliases,
|
||||
},
|
||||
{
|
||||
path: ["channels", "discord", "accounts"],
|
||||
message:
|
||||
"channels.discord.accounts.<id>.streamMode, streaming (scalar), chunkMode, blockStreaming, draftChunk, and blockStreamingCoalesce are legacy; use channels.discord.accounts.<id>.streaming.{mode,chunkMode,preview.chunk,block.enabled,block.coalesce}.",
|
||||
match: (value) => hasLegacyAccountStreamingAliases(value, hasLegacyDiscordStreamingAliases),
|
||||
},
|
||||
{
|
||||
path: ["channels", "discord", "voice", "tts"],
|
||||
message:
|
||||
@@ -164,18 +141,6 @@ export function normalizeCompatibilityConfig({
|
||||
updated = dm.entry;
|
||||
changed = changed || dm.changed;
|
||||
|
||||
const streaming = normalizeLegacyStreamingAliases({
|
||||
entry: updated,
|
||||
pathPrefix: "channels.discord",
|
||||
changes,
|
||||
includePreviewChunk: true,
|
||||
resolvedMode: resolveDiscordPreviewStreamMode(updated),
|
||||
offModeLegacyNotice: (pathPrefix) =>
|
||||
`${pathPrefix}.streaming remains off by default to avoid Discord preview-edit rate limits; set ${pathPrefix}.streaming.mode="partial" to opt in explicitly.`,
|
||||
});
|
||||
updated = streaming.entry;
|
||||
changed = changed || streaming.changed;
|
||||
|
||||
const rawAccounts = asObjectRecord(updated.accounts);
|
||||
if (rawAccounts) {
|
||||
let accountsChanged = false;
|
||||
@@ -194,17 +159,6 @@ export function normalizeCompatibilityConfig({
|
||||
});
|
||||
accountEntry = accountDm.entry;
|
||||
accountChanged = accountDm.changed;
|
||||
const accountStreaming = normalizeLegacyStreamingAliases({
|
||||
entry: accountEntry,
|
||||
pathPrefix: `channels.discord.accounts.${accountId}`,
|
||||
changes,
|
||||
includePreviewChunk: true,
|
||||
resolvedMode: resolveDiscordPreviewStreamMode(accountEntry),
|
||||
offModeLegacyNotice: (pathPrefix) =>
|
||||
`${pathPrefix}.streaming remains off by default to avoid Discord preview-edit rate limits; set ${pathPrefix}.streaming.mode="partial" to opt in explicitly.`,
|
||||
});
|
||||
accountEntry = accountStreaming.entry;
|
||||
accountChanged = accountChanged || accountStreaming.changed;
|
||||
const accountVoice = asObjectRecord(accountEntry.voice);
|
||||
if (
|
||||
accountVoice &&
|
||||
|
||||
@@ -1,46 +1,5 @@
|
||||
import type { ChannelDoctorLegacyConfigRule } from "openclaw/plugin-sdk/channel-contract";
|
||||
|
||||
function asObjectRecord(value: unknown): Record<string, unknown> | null {
|
||||
return value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: null;
|
||||
}
|
||||
|
||||
function hasLegacyDiscordStreamingAliases(value: unknown): boolean {
|
||||
const entry = asObjectRecord(value);
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
entry.streamMode !== undefined ||
|
||||
typeof entry.streaming === "boolean" ||
|
||||
typeof entry.streaming === "string" ||
|
||||
entry.chunkMode !== undefined ||
|
||||
entry.blockStreaming !== undefined ||
|
||||
entry.draftChunk !== undefined ||
|
||||
entry.blockStreamingCoalesce !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
function hasLegacyDiscordAccountStreamingAliases(value: unknown): boolean {
|
||||
const accounts = asObjectRecord(value);
|
||||
if (!accounts) {
|
||||
return false;
|
||||
}
|
||||
return Object.values(accounts).some((account) => hasLegacyDiscordStreamingAliases(account));
|
||||
}
|
||||
|
||||
export const DISCORD_LEGACY_CONFIG_RULES: ChannelDoctorLegacyConfigRule[] = [
|
||||
{
|
||||
path: ["channels", "discord"],
|
||||
message:
|
||||
"channels.discord.streamMode, channels.discord.streaming (scalar), chunkMode, blockStreaming, draftChunk, and blockStreamingCoalesce are legacy; use channels.discord.streaming.{mode,chunkMode,preview.chunk,block.enabled,block.coalesce}.",
|
||||
match: hasLegacyDiscordStreamingAliases,
|
||||
},
|
||||
{
|
||||
path: ["channels", "discord", "accounts"],
|
||||
message:
|
||||
"channels.discord.accounts.<id>.streamMode, streaming (scalar), chunkMode, blockStreaming, draftChunk, and blockStreamingCoalesce are legacy; use channels.discord.accounts.<id>.streaming.{mode,chunkMode,preview.chunk,block.enabled,block.coalesce}.",
|
||||
match: hasLegacyDiscordAccountStreamingAliases,
|
||||
},
|
||||
];
|
||||
// Runtime config loading already normalizes these aliases without rewriting the
|
||||
// source file. Keep doctor non-destructive so downgrade paths remain recoverable.
|
||||
export const DISCORD_LEGACY_CONFIG_RULES: ChannelDoctorLegacyConfigRule[] = [];
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "./doctor.js";
|
||||
|
||||
describe("discord doctor", () => {
|
||||
it("normalizes legacy discord streaming aliases into the nested streaming shape", () => {
|
||||
it("leaves legacy discord streaming aliases untouched during doctor normalization", () => {
|
||||
const normalize = discordDoctor.normalizeCompatibilityConfig;
|
||||
expect(normalize).toBeDefined();
|
||||
if (!normalize) {
|
||||
@@ -38,62 +38,23 @@ describe("discord doctor", () => {
|
||||
} as never,
|
||||
});
|
||||
|
||||
expect(result.config.channels?.discord?.streaming).toEqual({
|
||||
mode: "block",
|
||||
expect(result.config.channels?.discord).toEqual({
|
||||
streamMode: "block",
|
||||
chunkMode: "newline",
|
||||
block: {
|
||||
enabled: true,
|
||||
blockStreaming: true,
|
||||
draftChunk: {
|
||||
minChars: 120,
|
||||
},
|
||||
preview: {
|
||||
chunk: {
|
||||
minChars: 120,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result.config.channels?.discord?.accounts?.work?.streaming).toEqual({
|
||||
mode: "off",
|
||||
block: {
|
||||
coalesce: {
|
||||
idleMs: 250,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result.changes).toEqual(
|
||||
expect.arrayContaining([
|
||||
"Moved channels.discord.streamMode → channels.discord.streaming.mode (block).",
|
||||
"Moved channels.discord.chunkMode → channels.discord.streaming.chunkMode.",
|
||||
"Moved channels.discord.blockStreaming → channels.discord.streaming.block.enabled.",
|
||||
"Moved channels.discord.draftChunk → channels.discord.streaming.preview.chunk.",
|
||||
"Moved channels.discord.accounts.work.streaming (boolean) → channels.discord.accounts.work.streaming.mode (off).",
|
||||
"Moved channels.discord.accounts.work.blockStreamingCoalesce → channels.discord.accounts.work.streaming.block.coalesce.",
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not duplicate streaming.mode change messages when streamMode wins over boolean streaming", () => {
|
||||
const normalize = discordDoctor.normalizeCompatibilityConfig;
|
||||
expect(normalize).toBeDefined();
|
||||
if (!normalize) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = normalize({
|
||||
cfg: {
|
||||
channels: {
|
||||
discord: {
|
||||
streamMode: "block",
|
||||
streaming: false,
|
||||
accounts: {
|
||||
work: {
|
||||
streaming: false,
|
||||
blockStreamingCoalesce: {
|
||||
idleMs: 250,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.config.channels?.discord?.streaming).toEqual({
|
||||
mode: "block",
|
||||
});
|
||||
expect(
|
||||
result.changes.filter((change) => change.includes("channels.discord.streaming.mode")),
|
||||
).toEqual(["Moved channels.discord.streamMode → channels.discord.streaming.mode (block)."]);
|
||||
expect(result.changes).toEqual([]);
|
||||
});
|
||||
|
||||
it("moves account voice.tts.edge into providers.microsoft", () => {
|
||||
|
||||
Reference in New Issue
Block a user