mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
fix(docs): validate channel config snippets
This commit is contained in:
@@ -36,6 +36,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Google Meet: refresh realtime browser state during status and retry delayed speech after Meet finishes joining, so a just-opened in-call tab no longer leaves speech stuck behind stale `not-in-call` health.
|
||||
- Plugins/install: recover the install ledger from the managed npm root when `plugins/installs.json` is empty or partial, so reinstalling Discord and Codex no longer makes the other installed plugin disappear.
|
||||
- Google Meet: grant Meet media permissions through the Playwright browser context when CDP grants do not affect the attached Chrome page, and report in-call microphone/speaker permission problems instead of marking realtime speech ready.
|
||||
- Channel docs: keep JSON5 channel config examples parseable and schema-valid, fixing BlueBubbles and QQ Bot snippets that could not be copied into config as shown. Thanks @vincentkoc.
|
||||
- Tlon: expose `groupInviteAllowlist` in the channel config schema and clarify that group invite auto-accept fails closed without an invite allowlist. Thanks @vincentkoc.
|
||||
- Google Chat: update the setup example to use the accepted `groups.<space>.enabled` key instead of the legacy `allow` alias, with a schema regression for the documented group shape. Thanks @vincentkoc.
|
||||
- Control UI/WebChat: collapse duplicate in-flight internal text sends onto the active Gateway run so rapid repeat submits do not start fresh `agent:main:main` dispatches. Fixes #75737. Thanks @dsdsddd1 and @BunsDev.
|
||||
|
||||
@@ -267,15 +267,7 @@ With the BlueBubbles Private API enabled, inbound messages arrive with short mes
|
||||
bluebubbles: {
|
||||
groups: {
|
||||
"iMessage;+;chat-family": {
|
||||
systemPrompt: [
|
||||
"When replying in this group, always call action=reply with the",
|
||||
"[[reply_to:N]] messageId from context so your response threads",
|
||||
"under the triggering message. Never send a new unlinked message.",
|
||||
"",
|
||||
"For short acknowledgements ('ok', 'got it', 'on it'), use",
|
||||
"action=react with an appropriate tapback emoji (❤️, 👍, 😂, ‼️, ❓)",
|
||||
"instead of sending a text reply.",
|
||||
].join(" "),
|
||||
systemPrompt: "When replying in this group, always call action=reply with the [[reply_to:N]] messageId from context so your response threads under the triggering message. Never send a new unlinked message. For short acknowledgements ('ok', 'got it', 'on it'), use action=react with an appropriate tapback emoji (❤️, 👍, 😂, ‼️, ❓) instead of sending a text reply.",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -209,7 +209,7 @@ STT and TTS support two-level configuration with priority fallback:
|
||||
voice: "your-voice",
|
||||
},
|
||||
accounts: {
|
||||
qq-main: {
|
||||
"qq-main": {
|
||||
tts: {
|
||||
providers: {
|
||||
openai: { voice: "shimmer" },
|
||||
|
||||
47
src/docs/channel-config-examples.test.ts
Normal file
47
src/docs/channel-config-examples.test.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import JSON5 from "json5";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { OpenClawSchema } from "../config/zod-schema.js";
|
||||
|
||||
const CHANNEL_DOCS_DIR = path.join(process.cwd(), "docs", "channels");
|
||||
|
||||
function lineNumberAt(source: string, index: number): number {
|
||||
return source.slice(0, index).split("\n").length;
|
||||
}
|
||||
|
||||
describe("channel docs config examples", () => {
|
||||
it("keeps OpenClaw channel config snippets parseable and schema-valid", () => {
|
||||
const failures: string[] = [];
|
||||
for (const fileName of fs
|
||||
.readdirSync(CHANNEL_DOCS_DIR)
|
||||
.filter((entry) => entry.endsWith(".md"))) {
|
||||
const docPath = path.join(CHANNEL_DOCS_DIR, fileName);
|
||||
const markdown = fs.readFileSync(docPath, "utf8");
|
||||
const blocks = markdown.matchAll(/```(?:json5|json)\n([\s\S]*?)```/g);
|
||||
for (const match of blocks) {
|
||||
const code = match[1] ?? "";
|
||||
if (!/(^|\n)\s*(?:"channels"|channels)\s*:/.test(code)) {
|
||||
continue;
|
||||
}
|
||||
const location = `${fileName}:${lineNumberAt(markdown, match.index ?? 0)}`;
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON5.parse(code);
|
||||
} catch (error) {
|
||||
failures.push(`${location} JSON5 parse failed: ${String(error)}`);
|
||||
continue;
|
||||
}
|
||||
const result = OpenClawSchema.safeParse(parsed);
|
||||
if (!result.success) {
|
||||
const issues = result.error.issues
|
||||
.slice(0, 3)
|
||||
.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`)
|
||||
.join("; ");
|
||||
failures.push(`${location} schema failed: ${issues}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(failures).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -92,6 +92,7 @@ export const forcedUnitFastTestFiles = [
|
||||
"src/context-engine/context-engine.test.ts",
|
||||
"src/canvas-host/server.state-dir.test.ts",
|
||||
"src/docs/clawhub-plugin-docs.test.ts",
|
||||
"src/docs/channel-config-examples.test.ts",
|
||||
"src/docs/install-cloud-secrets.test.ts",
|
||||
"src/docker-build-cache.test.ts",
|
||||
"src/docker-image-digests.test.ts",
|
||||
|
||||
Reference in New Issue
Block a user