惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
A
About on SuperTechFans
博客园 - 【当耐特】
Microsoft Security Blog
Microsoft Security Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
雷峰网
雷峰网
博客园_首页
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
IT之家
IT之家
博客园 - 叶小钗
Google DeepMind News
Google DeepMind News
aimingoo的专栏
aimingoo的专栏
博客园 - 聂微东
B
Blog RSS Feed
H
Help Net Security
Recent Announcements
Recent Announcements
阮一峰的网络日志
阮一峰的网络日志
D
DataBreaches.Net
L
LangChain Blog
Vercel News
Vercel News

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix: apply Discord voice channel prompts · openclaw/openc...
steipete · 2026-05-01 · via Recent Commits to openclaw:main

File tree

  • docs/channels

  • extensions/discord/src/voice

Original file line numberDiff line numberDiff line change

@@ -18,6 +18,7 @@ Docs: https://docs.openclaw.ai

1818
1919

### Fixes

2020
21+

- Discord/voice: apply per-channel Discord `systemPrompt` overrides to voice transcript turns by forwarding the trusted channel prompt through the voice agent run. Fixes #47095. Thanks @qearlyao.

2122

- Discord/voice: run voice-channel turns under a voice-output policy that hides the agent `tts` tool and asks for spoken reply text, so `/vc join` sessions synthesize and play agent replies instead of ending with `NO_REPLY`. Fixes #61536. Thanks @aounakram.

2223

- Plugins/runtime-deps: prune inactive same-package versioned runtime-deps roots after bundled dependency repair, so upgrades do not leave old `openclaw-<version>-<hash>` package caches behind after doctor runs. Thanks @vincentkoc.

2324

- Plugins/runtime-deps: prune legacy version-scoped plugin runtime-deps roots during bundled dependency repair and cover the path in Package Acceptance's upgrade-survivor matrix, so upgrades from 2026.4.x no longer leave stale per-plugin runtime trees after doctor runs. Thanks @vincentkoc.

Original file line numberDiff line numberDiff line change

@@ -1063,6 +1063,7 @@ Notes:

10631063

- `voice.tts` overrides `messages.tts` for voice playback only.

10641064

- `voice.model` overrides the LLM used for Discord voice channel responses only. Leave it unset to inherit the routed agent model.

10651065

- STT uses `tools.media.audio`; `voice.model` does not affect transcription.

1066+

- Per-channel Discord `systemPrompt` overrides apply to voice transcript turns for that voice channel.

10661067

- Voice transcript turns derive owner status from Discord `allowFrom` (or `dm.allowFrom`); non-owner speakers cannot access owner-only tools (for example `gateway` and `cron`).

10671068

- Voice is enabled by default; set `channels.discord.voice.enabled=false` to disable voice runtime and the `GuildVoiceStates` gateway intent.

10681069

- `channels.discord.intents.voiceStates` can explicitly override voice-state intent subscription. Leave it unset for the intent to follow `voice.enabled`.

Original file line numberDiff line numberDiff line change

@@ -62,7 +62,8 @@ describe("authorizeDiscordVoiceIngress", () => {

6262

},

6363

});

6464
65-

expect(access).toEqual({ ok: true });

65+

expect(access).toMatchObject({ ok: true });

66+

expect(access.ok && access.channelConfig?.users).toEqual(["discord:u-owner"]);

6667

});

6768
6869

it("allows slug-keyed guild configs when manager context only has guild name", async () => {

@@ -91,7 +92,7 @@ describe("authorizeDiscordVoiceIngress", () => {

9192

},

9293

});

9394
94-

expect(access).toEqual({ ok: true });

95+

expect(access).toMatchObject({ ok: true });

9596

});

9697
9798

it("allows wildcard guild configs when only the guild id is available", async () => {

@@ -119,7 +120,7 @@ describe("authorizeDiscordVoiceIngress", () => {

119120

},

120121

});

121122
122-

expect(access).toEqual({ ok: true });

123+

expect(access).toMatchObject({ ok: true });

123124

});

124125
125126

it("blocks commands when channel id is unavailable for an allowlisted channel", async () => {

@@ -211,6 +212,6 @@ describe("authorizeDiscordVoiceIngress", () => {

211212

},

212213

});

213214
214-

expect(access).toEqual({ ok: true });

215+

expect(access).toMatchObject({ ok: true });

215216

});

216217

});

Original file line numberDiff line numberDiff line change

@@ -6,6 +6,7 @@ import type { Guild } from "../internal/discord.js";

66

import {

77

isDiscordGroupAllowedByPolicy,

88

resolveDiscordChannelConfigWithFallback,

9+

type DiscordChannelConfigResolved,

910

resolveDiscordGuildEntry,

1011

resolveDiscordMemberAccessState,

1112

resolveDiscordOwnerAccess,

@@ -30,7 +31,9 @@ export async function authorizeDiscordVoiceIngress(params: {

3031

memberRoleIds: string[];

3132

ownerAllowFrom?: string[];

3233

sender: { id: string; name?: string; tag?: string };

33-

}): Promise<{ ok: true } | { ok: false; message: string }> {

34+

}): Promise<

35+

{ ok: true; channelConfig?: DiscordChannelConfigResolved | null } | { ok: false; message: string }

36+

> {

3437

const groupPolicy =

3538

params.groupPolicy ??

3639

resolveOpenProviderRuntimeGroupPolicy({

@@ -116,6 +119,6 @@ export async function authorizeDiscordVoiceIngress(params: {

116119

authorizers,

117120

modeWhenAccessGroupsOff: "configured",

118121

})

119-

? { ok: true }

122+

? { ok: true, channelConfig }

120123

: { ok: false, message: "You are not authorized to use this command." };

121124

}

Original file line numberDiff line numberDiff line change

@@ -574,6 +574,44 @@ describe("DiscordVoiceManager", () => {

574574

);

575575

});

576576
577+

it("passes per-channel system prompt overrides to voice agent runs", async () => {

578+

const client = createClient();

579+

client.fetchMember.mockResolvedValue({

580+

nickname: "Guest Nick",

581+

user: {

582+

id: "u-guest",

583+

username: "guest",

584+

globalName: "Guest",

585+

discriminator: "4321",

586+

},

587+

});

588+

const manager = createManager(

589+

{

590+

groupPolicy: "open",

591+

guilds: {

592+

g1: {

593+

channels: {

594+

"1001": {

595+

systemPrompt: " Use short voice replies. ",

596+

},

597+

},

598+

},

599+

},

600+

},

601+

client,

602+

{

603+

commands: { useAccessGroups: false },

604+

},

605+

);

606+

await processVoiceSegment(manager, "u-guest");

607+
608+

const commandArgs = agentCommandMock.mock.calls.at(-1)?.[0] as

609+

| { extraSystemPrompt?: string }

610+

| undefined;

611+
612+

expect(commandArgs?.extraSystemPrompt).toBe("Use short voice replies.");

613+

});

614+
577615

it("reuses speaker context cache for repeated segments from the same speaker", async () => {

578616

const client = createClient();

579617

client.fetchMember.mockResolvedValue({

Original file line numberDiff line numberDiff line change

@@ -6,6 +6,7 @@ import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";

66

import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";

77

import { formatMention } from "../mentions.js";

88

import { normalizeDiscordSlug } from "../monitor/allow-list.js";

9+

import { buildDiscordGroupSystemPrompt } from "../monitor/inbound-context.js";

910

import { authorizeDiscordVoiceIngress } from "./access.js";

1011

import { formatVoiceIngressPrompt } from "./prompt.js";

1112

import { loadDiscordVoiceSdk } from "./sdk-runtime.js";

@@ -82,6 +83,7 @@ export async function processDiscordVoiceSegment(params: {

8283

);

8384
8485

const prompt = formatVoiceIngressPrompt(transcript, speaker.label);

86+

const extraSystemPrompt = buildDiscordGroupSystemPrompt(access.channelConfig);

8587

const modelOverride = normalizeOptionalString(params.discordConfig.voice?.model);

8688
8789

const result = await agentCommandFromIngress(

@@ -91,6 +93,7 @@ export async function processDiscordVoiceSegment(params: {

9193

agentId: entry.route.agentId,

9294

messageChannel: "discord",

9395

messageProvider: DISCORD_VOICE_MESSAGE_PROVIDER,

96+

extraSystemPrompt,

9497

senderIsOwner: speaker.senderIsOwner,

9598

allowModelOverride: Boolean(modelOverride),

9699

model: modelOverride,