fix: align WeChat channel modes

This commit is contained in:
lofyer
2026-08-10 11:47:03 +08:00
parent a9ae00a845
commit 2cb712e4ba
11 changed files with 36 additions and 27 deletions
+1 -1
View File
@@ -226,5 +226,5 @@ export function startEnvironmentChannels(
export function isReadOnlyChannelMessage(
message: ChannelInboundText
): boolean {
return message.workMode === 'ask' || message.workMode === 'plan'
return message.workMode === 'ask'
}
+7 -1
View File
@@ -71,7 +71,7 @@ async function waitForSent(
}
describe('channel contracts', () => {
it('normalizes text, defaults to ask, and strictly refuses execute mode', () => {
it('normalizes text, defaults to ask, and refuses non-ask modes', () => {
expect(
channelInboundTextSchema.parse({
channel: ' fake ',
@@ -98,6 +98,12 @@ describe('channel contracts', () => {
workMode: 'execute'
}).success
).toBe(false)
expect(
channelInboundTextSchema.safeParse({
...inbound(),
workMode: 'plan'
}).success
).toBe(false)
expect(
channelInboundTextSchema.parse({
channel: 'fake',
@@ -13,8 +13,8 @@ describe('parseRemoteChannelPrompt', () => {
workMode: 'execute',
prompt: '请整理下载目录'
})
expect(parseRemoteChannelPrompt('总结进展', 'plan')).toEqual({
workMode: 'plan',
expect(parseRemoteChannelPrompt('总结进展', 'ask')).toEqual({
workMode: 'ask',
prompt: '总结进展'
})
})
+3 -3
View File
@@ -1,4 +1,4 @@
import type { WorkMode } from '../../shared/assistant-contracts'
import type { InteractiveWorkMode } from '../../shared/assistant-contracts'
const COMMAND_PATTERN =
/^\/(?<command>ask|execute|exec)(?=$|[\s:])[\s:]*/iu
@@ -7,9 +7,9 @@ const CHINESE_PATTERN =
export function parseRemoteChannelPrompt(
text: string,
defaultWorkMode: WorkMode
defaultWorkMode: InteractiveWorkMode
): {
workMode: WorkMode
workMode: InteractiveWorkMode
prompt: string
} {
const value = text.trim()
+9 -9
View File
@@ -41,7 +41,7 @@ const channelMocks = vi.hoisted(() => ({
conversationType: 'direct' | 'group'
text: string
mentioned: boolean
workMode: 'ask' | 'plan'
workMode: 'ask'
attachments?: Array<{
name: string
mimeType: string
@@ -276,7 +276,7 @@ vi.mock('./agent/create-runtime', () => runtimeFactoryMocks)
vi.mock('./channels/channel-env', () => ({
isReadOnlyChannelMessage: (message: { workMode: string }) =>
message.workMode === 'ask' || message.workMode === 'plan',
message.workMode === 'ask',
startEnvironmentChannels: vi.fn(
(options: { executor: typeof channelMocks.executor }) => {
channelMocks.executor = options.executor
@@ -1873,7 +1873,7 @@ describe('registerIpcHandlers agent terminal state', () => {
await harness.dispose()
})
it('bridges channel requests to read-only delegation tasks without approval', async () => {
it('bridges channel ask requests to read-only tasks without approval', async () => {
let received:
| {
request: {
@@ -1928,9 +1928,9 @@ describe('registerIpcHandlers agent terminal state', () => {
senderId: 'user-1',
conversationId: 'conversation-1',
conversationType: 'direct',
text: '请制定只读计划',
text: '请只读分析',
mentioned: false,
workMode: 'plan'
workMode: 'ask'
},
new AbortController().signal
)
@@ -1939,8 +1939,8 @@ describe('registerIpcHandlers agent terminal state', () => {
output: '只读结果'
})
expect(received?.request).toMatchObject({
workMode: 'plan',
prompt: expect.stringContaining('请制定只读计划')
workMode: 'ask',
prompt: expect.stringContaining('请只读分析')
})
await expect(
received?.authorize?.({
@@ -1953,8 +1953,8 @@ describe('registerIpcHandlers agent terminal state', () => {
expect(harness.assistantDatabase.createTask).toHaveBeenCalledWith(
expect.objectContaining({
title: '企业微信远程请求',
instructions: '请制定只读计划',
workMode: 'plan',
instructions: '请只读分析',
workMode: 'ask',
origin: 'delegation'
})
)
+2 -6
View File
@@ -1352,9 +1352,7 @@ export function registerIpcHandlers(
try {
parsed = parseRemoteChannelPrompt(
remoteInput,
message.workMode === 'plan'
? 'plan'
: project.defaultWorkMode
normalizeInteractiveWorkMode(project.defaultWorkMode)
)
} catch (error) {
return {
@@ -1432,9 +1430,7 @@ export function registerIpcHandlers(
status: `${channelLabel} · ${
parsed.workMode === 'execute'
? '执行'
: parsed.workMode === 'plan'
? '规划'
: '对话'
: '对话'
}`
})
publishRemoteConversationChange()
@@ -330,6 +330,11 @@ describe('ChannelSettingsSection', () => {
const close = await screen.findByRole('button', {
name: '关闭微信绑定'
})
expect(
screen.getByText(
'请在微信中依次打开“设置 → ClawBot → 开始扫一扫”,扫描下方二维码。二维码不会发送到第三方页面。'
)
).toBeInTheDocument()
await waitFor(() => expect(close).toHaveFocus())
fireEvent.keyDown(document, { key: 'Escape' })
+3 -1
View File
@@ -681,7 +681,9 @@ function WeixinQrDialog({
<header>
<div>
<strong id="channel-qr-title"> ClawBot</strong>
<small>使</small>
<small>
ClawBot
</small>
</div>
<button
aria-label="关闭微信绑定"
+1 -1
View File
@@ -20,7 +20,7 @@ const channelIdentifierSchema = z
.min(1)
.max(CHANNEL_LIMITS.maximumIdentityLength)
export const channelWorkModeSchema = z.enum(['ask', 'plan'])
export const channelWorkModeSchema = z.literal('ask')
export type ChannelWorkMode = z.infer<typeof channelWorkModeSchema>
const attachmentBase64Schema = z