Skip to content

Commit 69b66dd

Browse files
committed
fix(config): coerce visible replies booleans
1 parent 03e35b1 commit 69b66dd

6 files changed

Lines changed: 118 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai
2929

3030
### Fixes
3131

32+
- Config/messages: coerce boolean `messages.visibleReplies` and `messages.groupChat.visibleReplies` values to the documented enum modes so an intuitive toggle no longer invalidates config and drops channel startup. Fixes #75390. Thanks @scottgl9.
3233
- Feishu: accept and honor `channels.feishu.blockStreaming` at the top level and per account, while keeping the legacy default off so Feishu cards no longer reject documented config or silently drop block replies. Fixes #75555. Thanks @vincentkoc.
3334
- Google Chat: normalize custom Google auth transport headers before google-auth/gaxios interceptors run, restoring webhook token verification when certificate retrieval expects Fetch `Headers`. Fixes #76742. Thanks @donbowman.
3435
- Doctor/plugins: reset stale `plugins.slots.memory` and `plugins.slots.contextEngine` references during `doctor --fix`, so cleanup of missing plugin config does not leave unrecoverable slot owners behind. Fixes #76550 and #76551. Thanks @vincentkoc.
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
d9dbaace82aff4445be6ed11e52e69b4548239e3a4e659538f96dfb3ed3c57ac config-baseline.json
2-
9d4d4ab553dadca237d837f71dc7fc13e4ea65d33a564c2ea6775180c413e86a config-baseline.core.json
3-
f2a1aad257c570b497865680c331568a6775369528749826dfa35c1f644483fc config-baseline.channel.json
4-
858f82733d9828b28bf88bc226e155d8417c494215eb3f808f15799daa42a7d7 config-baseline.plugin.json
1+
c1de046645b03b1ec47ec41811b67c0e7ad5460842b54416a47757ef22b9b17e config-baseline.json
2+
f945a060012b3e7c675fb3ea0c5f18996cdcc06c9ec6cead389e04791a529ce9 config-baseline.core.json
3+
76979aba007500abc52b970da76b6512291916739c29d6a3f4218772d1a31186 config-baseline.channel.json
4+
245aa98aabc6c2e3c57a69e639c2fb10d84a7e1e1b3bcdadc340fa61ca998287 config-baseline.plugin.json

src/config/schema.base.generated.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7388,8 +7388,15 @@ export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = {
73887388
maximum: 9007199254740991,
73897389
},
73907390
visibleReplies: {
7391-
type: "string",
7392-
enum: ["automatic", "message_tool"],
7391+
anyOf: [
7392+
{
7393+
type: "string",
7394+
enum: ["automatic", "message_tool"],
7395+
},
7396+
{
7397+
type: "boolean",
7398+
},
7399+
],
73937400
},
73947401
},
73957402
additionalProperties: false,
@@ -19019,8 +19026,15 @@ export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = {
1901919026
"Prefix text prepended to inbound user messages before they are handed to the agent runtime. Use this sparingly for channel context markers and keep it stable across sessions.",
1902019027
},
1902119028
visibleReplies: {
19022-
type: "string",
19023-
enum: ["automatic", "message_tool"],
19029+
anyOf: [
19030+
{
19031+
type: "string",
19032+
enum: ["automatic", "message_tool"],
19033+
},
19034+
{
19035+
type: "boolean",
19036+
},
19037+
],
1902419038
title: "Visible Replies",
1902519039
description:
1902619040
'Controls visible source replies across direct, group, and channel conversations. "message_tool" keeps normal final replies private and requires message(action=send) for visible output; "automatic" posts normal replies as before.',
@@ -19052,8 +19066,15 @@ export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = {
1905219066
"Maximum number of prior group messages loaded as context per turn for group sessions. Use higher values for richer continuity, or lower values for faster and cheaper responses.",
1905319067
},
1905419068
visibleReplies: {
19055-
type: "string",
19056-
enum: ["automatic", "message_tool"],
19069+
anyOf: [
19070+
{
19071+
type: "string",
19072+
enum: ["automatic", "message_tool"],
19073+
},
19074+
{
19075+
type: "boolean",
19076+
},
19077+
],
1905719078
title: "Group Visible Replies",
1905819079
description:
1905919080
'Overrides visible source replies for group/channel conversations. Defaults to "message_tool" when no global visible reply policy is set. "message_tool" keeps normal final replies private and requires message(action=send) for room output; "automatic" posts normal replies as before.',

src/config/zod-schema.core.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,25 @@ export const ModelsConfigSchema = z
386386
.strict()
387387
.optional();
388388

389+
const VisibleRepliesValueSchema = z.enum(["automatic", "message_tool"]);
390+
391+
export const VisibleRepliesSchema = z
392+
.union([VisibleRepliesValueSchema, z.boolean()])
393+
.overwrite((value) => {
394+
if (value === true) {
395+
return "automatic";
396+
}
397+
if (value === false) {
398+
return "message_tool";
399+
}
400+
return value;
401+
});
402+
389403
export const GroupChatSchema = z
390404
.object({
391405
mentionPatterns: z.array(z.string()).optional(),
392406
historyLimit: z.number().int().positive().optional(),
393-
visibleReplies: z.enum(["automatic", "message_tool"]).optional(),
407+
visibleReplies: VisibleRepliesSchema.optional(),
394408
})
395409
.strict()
396410
.optional();

src/config/zod-schema.session.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
QueueSchema,
1212
TypingModeSchema,
1313
TtsConfigSchema,
14+
VisibleRepliesSchema,
1415
} from "./zod-schema.core.js";
1516
import { sensitive } from "./zod-schema.sensitive.js";
1617

@@ -152,7 +153,7 @@ export const SessionSchema = z
152153
export const MessagesSchema = z
153154
.object({
154155
messagePrefix: z.string().optional(),
155-
visibleReplies: z.enum(["automatic", "message_tool"]).optional(),
156+
visibleReplies: VisibleRepliesSchema.optional(),
156157
responsePrefix: z.string().optional(),
157158
groupChat: GroupChatSchema,
158159
queue: QueueSchema,
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { describe, expect, it } from "vitest";
2+
import { validateConfigObjectRaw } from "./validation.js";
3+
4+
describe("visible reply config schema", () => {
5+
it("coerces boolean global visibleReplies values to the enum contract", () => {
6+
const automatic = validateConfigObjectRaw({
7+
messages: {
8+
visibleReplies: true,
9+
},
10+
});
11+
const toolOnly = validateConfigObjectRaw({
12+
messages: {
13+
visibleReplies: false,
14+
},
15+
});
16+
17+
expect(automatic.ok).toBe(true);
18+
expect(toolOnly.ok).toBe(true);
19+
if (automatic.ok) {
20+
expect(automatic.config.messages?.visibleReplies).toBe("automatic");
21+
}
22+
if (toolOnly.ok) {
23+
expect(toolOnly.config.messages?.visibleReplies).toBe("message_tool");
24+
}
25+
});
26+
27+
it("coerces boolean groupChat visibleReplies values to the enum contract", () => {
28+
const automatic = validateConfigObjectRaw({
29+
messages: {
30+
groupChat: {
31+
visibleReplies: true,
32+
},
33+
},
34+
});
35+
const toolOnly = validateConfigObjectRaw({
36+
messages: {
37+
groupChat: {
38+
visibleReplies: false,
39+
},
40+
},
41+
});
42+
43+
expect(automatic.ok).toBe(true);
44+
expect(toolOnly.ok).toBe(true);
45+
if (automatic.ok) {
46+
expect(automatic.config.messages?.groupChat?.visibleReplies).toBe("automatic");
47+
}
48+
if (toolOnly.ok) {
49+
expect(toolOnly.config.messages?.groupChat?.visibleReplies).toBe("message_tool");
50+
}
51+
});
52+
53+
it("keeps invalid visibleReplies values rejected", () => {
54+
const result = validateConfigObjectRaw({
55+
messages: {
56+
visibleReplies: "visible",
57+
},
58+
});
59+
60+
expect(result.ok).toBe(false);
61+
if (!result.ok) {
62+
expect(result.issues).toContainEqual(
63+
expect.objectContaining({
64+
path: "messages.visibleReplies",
65+
}),
66+
);
67+
}
68+
});
69+
});

0 commit comments

Comments
 (0)