mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
8cb53c7b55
* perf(doctor): keep bundled doctor contract closures dependency-light Doctor contract enumeration cold-loads each plugin's doctor-contract-api closure via jiti, so a static value import of openclaw/plugin-sdk/runtime-doctor pulled the state-db/kysely graph (~4.3s per closure) into listPluginDoctorLegacyConfigRules / listPluginDoctorStateMigrationEntries. - migrate all light doctor-contract closures (66 files) to the dependency-light openclaw/plugin-sdk/runtime-doctor-migrations subpath - voice-call: load detect/repairOpenClawStateDatabaseSchema* lazily inside the migration bodies; keep only a type-only static runtime-doctor import - matrix: split pure credential record shapes/normalizers into credentials-state.ts so the doctor closure no longer imports the sync plugin-state store through credentials-read - guard: doctor-contract-closure-guard.test.ts now forbids static value imports of runtime-doctor in closures alongside agent-runtime * fix(matrix): keep credential revocation record type module-local Knip production scan flags the export as consumer-less; the type is only referenced by the exported union and revocation guard signature.
135 lines
4.5 KiB
TypeScript
135 lines
4.5 KiB
TypeScript
// Googlechat plugin module implements doctor contract behavior.
|
|
import type {
|
|
ChannelDoctorConfigMutation,
|
|
ChannelDoctorLegacyConfigRule,
|
|
} from "openclaw/plugin-sdk/channel-contract";
|
|
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
|
import {
|
|
asObjectRecord,
|
|
defineChannelAliasMigration,
|
|
defineKeyMoveMigration,
|
|
hasLegacyAccountStreamingAliases,
|
|
normalizeChannelConfigEntries,
|
|
} from "openclaw/plugin-sdk/runtime-doctor-migrations";
|
|
|
|
// Google Chat's nested streaming schema is delivery-only ({chunkMode, block});
|
|
// it has no preview mode (legacy streamMode is removed outright above), so
|
|
// only the delivery flat aliases migrate. The plugin doctor below then
|
|
// materializes Google Chat's root < accounts.default < named precedence.
|
|
const streamingAliasMigration = defineChannelAliasMigration({
|
|
channelId: "googlechat",
|
|
streaming: { defaultMode: "partial", deliveryOnly: true },
|
|
accountStreamingInheritsDefaultAccount: true,
|
|
dm: { root: true, accounts: true },
|
|
});
|
|
|
|
function hasLegacyGoogleChatStreamMode(value: unknown): boolean {
|
|
return asObjectRecord(value)?.streamMode !== undefined;
|
|
}
|
|
|
|
function hasRetiredReactions(value: unknown): boolean {
|
|
return Object.hasOwn(asObjectRecord(asObjectRecord(value)?.actions) ?? {}, "reactions");
|
|
}
|
|
|
|
const groupAllowMigration = defineKeyMoveMigration({
|
|
scope: ["groups", "*"],
|
|
from: ["allow"],
|
|
to: ["enabled"],
|
|
});
|
|
|
|
function normalizeGoogleChatEntry(params: {
|
|
entry: Record<string, unknown>;
|
|
pathPrefix: string;
|
|
changes: string[];
|
|
}): { entry: Record<string, unknown>; changed: boolean } {
|
|
let updated = params.entry;
|
|
let changed = false;
|
|
|
|
if (updated.streamMode !== undefined) {
|
|
updated = { ...updated };
|
|
delete updated.streamMode;
|
|
params.changes.push(`Removed ${params.pathPrefix}.streamMode (legacy key no longer used).`);
|
|
changed = true;
|
|
}
|
|
|
|
if (hasRetiredReactions(updated)) {
|
|
const actions = { ...asObjectRecord(updated.actions) };
|
|
delete actions.reactions;
|
|
updated = { ...updated };
|
|
if (Object.keys(actions).length > 0) {
|
|
updated.actions = actions;
|
|
} else {
|
|
delete updated.actions;
|
|
}
|
|
params.changes.push(
|
|
`Removed ${params.pathPrefix}.actions.reactions (Google Chat does not support reactions).`,
|
|
);
|
|
changed = true;
|
|
}
|
|
|
|
const groups = groupAllowMigration.normalize({ ...params, entry: updated });
|
|
updated = groups.entry;
|
|
changed = changed || groups.changed;
|
|
|
|
return { entry: updated, changed };
|
|
}
|
|
|
|
export const legacyConfigRules: ChannelDoctorLegacyConfigRule[] = [
|
|
{
|
|
path: ["channels", "googlechat"],
|
|
message:
|
|
'channels.googlechat.actions.reactions is retired and ignored. Run "openclaw doctor --fix".',
|
|
match: hasRetiredReactions,
|
|
},
|
|
{
|
|
path: ["channels", "googlechat", "accounts"],
|
|
message:
|
|
'channels.googlechat.accounts.<id>.actions.reactions is retired and ignored. Run "openclaw doctor --fix".',
|
|
match: (value) => hasLegacyAccountStreamingAliases(value, hasRetiredReactions),
|
|
},
|
|
{
|
|
path: ["channels", "googlechat"],
|
|
message: "channels.googlechat.streamMode is legacy and no longer used; it is removed on load.",
|
|
match: hasLegacyGoogleChatStreamMode,
|
|
},
|
|
{
|
|
path: ["channels", "googlechat", "accounts"],
|
|
message:
|
|
"channels.googlechat.accounts.<id>.streamMode is legacy and no longer used; it is removed on load.",
|
|
match: (value) => hasLegacyAccountStreamingAliases(value, hasLegacyGoogleChatStreamMode),
|
|
},
|
|
{
|
|
path: ["channels", "googlechat"],
|
|
message:
|
|
'channels.googlechat.groups.<id>.allow is legacy; use channels.googlechat.groups.<id>.enabled instead. Run "openclaw doctor --fix".',
|
|
match: groupAllowMigration.hasLegacy,
|
|
},
|
|
{
|
|
path: ["channels", "googlechat", "accounts"],
|
|
message:
|
|
'channels.googlechat.accounts.<id>.groups.<id>.allow is legacy; use channels.googlechat.accounts.<id>.groups.<id>.enabled instead. Run "openclaw doctor --fix".',
|
|
match: (value) => hasLegacyAccountStreamingAliases(value, groupAllowMigration.hasLegacy),
|
|
},
|
|
...streamingAliasMigration.legacyConfigRules,
|
|
];
|
|
|
|
function normalizeRetiredGoogleChatKeys(cfg: OpenClawConfig): ChannelDoctorConfigMutation {
|
|
return normalizeChannelConfigEntries({
|
|
cfg,
|
|
channelId: "googlechat",
|
|
normalizeEntry: normalizeGoogleChatEntry,
|
|
});
|
|
}
|
|
|
|
export function normalizeCompatibilityConfig({
|
|
cfg,
|
|
}: {
|
|
cfg: OpenClawConfig;
|
|
}): ChannelDoctorConfigMutation {
|
|
const retired = normalizeRetiredGoogleChatKeys(cfg);
|
|
return streamingAliasMigration.normalizeChannelConfig({
|
|
cfg: retired.config,
|
|
changes: retired.changes,
|
|
});
|
|
}
|