feat(remote-control): 优化 Web 展示、状态同步与桥接控制流程 (#288)

Co-authored-by: chengzifeng <chengzifeng@meituan.com>
This commit is contained in:
Cheng Zi Feng
2026-04-17 16:21:27 +08:00
committed by GitHub
parent b5c299f5d2
commit 72a2093cd6
64 changed files with 4138 additions and 312 deletions

View File

@@ -0,0 +1,96 @@
import { describe, expect, test } from 'bun:test'
import {
shouldReportRunningForMessage,
shouldReportRunningForMessages,
} from '../bridgeMessaging.js'
import { createUserMessage } from '../../utils/messages.js'
describe('bridge running-state classification', () => {
test('treats real user prompts as turn-starting work', () => {
expect(
shouldReportRunningForMessage(
createUserMessage({ content: 'please inspect the repo' }),
),
).toBe(true)
})
test('keeps tool-result style user messages eligible during mid-turn attach', () => {
expect(
shouldReportRunningForMessage(
createUserMessage({
content: '<local-command-stdout>done</local-command-stdout>',
toolUseResult: { ok: true },
}),
),
).toBe(true)
})
test('ignores local slash-command scaffolding that should not reopen a turn', () => {
expect(
shouldReportRunningForMessage(
createUserMessage({
content:
'<local-command-caveat>Caveat: hidden local command scaffolding</local-command-caveat>',
isMeta: true,
}),
),
).toBe(false)
expect(
shouldReportRunningForMessage(
createUserMessage({
content:
'<system-reminder>\nProactive mode is now enabled. You will receive periodic <tick> prompts.\n</system-reminder>',
isMeta: true,
}),
),
).toBe(false)
})
test('still marks real automation triggers as running', () => {
expect(
shouldReportRunningForMessage(
createUserMessage({
content: '<tick>2:56:47 PM</tick>',
isMeta: true,
}),
),
).toBe(true)
expect(
shouldReportRunningForMessage(
createUserMessage({
content: 'scheduled job: refresh analytics cache',
isMeta: true,
}),
),
).toBe(true)
})
test('classifies batches by any work-starting message', () => {
const scaffoldingOnly = [
createUserMessage({
content:
'<local-command-caveat>Caveat: hidden local command scaffolding</local-command-caveat>',
isMeta: true,
}),
createUserMessage({
content:
'<system-reminder>\nProactive mode is now enabled.\n</system-reminder>',
isMeta: true,
}),
]
expect(shouldReportRunningForMessages(scaffoldingOnly)).toBe(false)
expect(
shouldReportRunningForMessages([
...scaffoldingOnly,
createUserMessage({
content: '<tick>2:57:17 PM</tick>',
isMeta: true,
}),
]),
).toBe(true)
})
})

View File

@@ -0,0 +1,76 @@
import { describe, expect, test } from 'bun:test'
import { parseBridgePermissionResponse } from '../bridgePermissionCallbacks.js'
import type { SDKControlResponse } from '../../entrypoints/sdk/controlTypes.js'
describe('parseBridgePermissionResponse', () => {
test('passes through allow responses', () => {
const message: SDKControlResponse = {
type: 'control_response',
response: {
subtype: 'success',
request_id: 'req-1',
response: {
behavior: 'allow',
updatedPermissions: [
{ type: 'setMode', mode: 'acceptEdits', destination: 'session' },
],
},
},
}
expect(parseBridgePermissionResponse(message)).toEqual({
behavior: 'allow',
updatedPermissions: [
{ type: 'setMode', mode: 'acceptEdits', destination: 'session' },
],
})
})
test('maps error responses with feedback to deny', () => {
const message = {
type: 'control_response',
response: {
subtype: 'error',
request_id: 'req-2',
error: 'Permission denied by user',
response: { behavior: 'deny' },
message: 'Need more detail',
},
} as unknown as SDKControlResponse
expect(parseBridgePermissionResponse(message)).toEqual({
behavior: 'deny',
message: 'Need more detail',
})
})
test('falls back to error text when deny feedback is absent', () => {
const message = {
type: 'control_response',
response: {
subtype: 'error',
request_id: 'req-3',
error: 'Permission denied by user',
},
} as unknown as SDKControlResponse
expect(parseBridgePermissionResponse(message)).toEqual({
behavior: 'deny',
message: 'Permission denied by user',
})
})
test('returns null for unrelated control responses', () => {
const message = {
type: 'control_response',
response: {
subtype: 'error',
request_id: 'req-4',
error: '',
},
} as unknown as SDKControlResponse
expect(parseBridgePermissionResponse(message)).toBeNull()
})
})

View File

@@ -0,0 +1,53 @@
import { describe, expect, test } from 'bun:test'
import {
hasPendingBridgeMessages,
isTranscriptResetResultReady,
shouldDeferBridgeResult,
} from '../bridgeResultScheduling.js'
describe('bridgeResultScheduling', () => {
test('detects pending mirrored messages', () => {
expect(hasPendingBridgeMessages(2, 3)).toBe(true)
expect(hasPendingBridgeMessages(3, 3)).toBe(false)
})
test('defers when the bridge handle is unavailable', () => {
expect(
shouldDeferBridgeResult({
hasHandle: false,
isConnected: true,
lastWrittenIndex: 3,
messageCount: 3,
}),
).toBe(true)
})
test('defers when the bridge is connected but transcript flush is pending', () => {
expect(
shouldDeferBridgeResult({
hasHandle: true,
isConnected: true,
lastWrittenIndex: 1,
messageCount: 2,
}),
).toBe(true)
})
test('sends immediately once the latest transcript is already mirrored', () => {
expect(
shouldDeferBridgeResult({
hasHandle: true,
isConnected: true,
lastWrittenIndex: 2,
messageCount: 2,
}),
).toBe(false)
})
test('treats transcript reset as ready only after the transcript is empty', () => {
expect(isTranscriptResetResultReady(true, 0)).toBe(true)
expect(isTranscriptResetResultReady(true, 1)).toBe(false)
expect(isTranscriptResetResultReady(false, 0)).toBe(false)
})
})

View File

@@ -0,0 +1,37 @@
import { feature } from 'bun:bundle'
import { afterEach, describe, expect, test } from 'bun:test'
import { handleRemoteInterrupt } from '../remoteInterruptHandling.js'
import {
activateProactive,
deactivateProactive,
isProactivePaused,
} from '../../proactive/index.js'
function isProactiveFeatureEnabled() {
if (feature('PROACTIVE')) return true
return feature('KAIROS') ? true : false
}
describe('handleRemoteInterrupt', () => {
afterEach(() => {
deactivateProactive()
})
test('always aborts the active request', () => {
const controller = new AbortController()
handleRemoteInterrupt(controller)
expect(controller.signal.aborted).toBe(true)
})
test('pauses proactive mode to return control to the user', () => {
activateProactive('test')
expect(isProactivePaused()).toBe(false)
handleRemoteInterrupt(new AbortController())
expect(isProactivePaused()).toBe(isProactiveFeatureEnabled())
})
})