Merge branch 'main' into chore/harness

This commit is contained in:
易良 2026-07-09 12:46:13 +08:00 committed by GitHub
commit f5c3b15fda
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 28 additions and 15 deletions

View file

@ -102,7 +102,7 @@ function buildChromeDevToolsMcpRuntimeConfig(
) {
return undefined;
}
const command = resolveCdpMcpCommand();
const command = resolveCdpMcpCommand(process.env);
if (!command) {
writeStderrLine(
`qwen serve: set ${QWEN_CDP_MCP_COMMAND_ENV} to enable browser automation MCP (no adapter is bundled)`,

View file

@ -8,20 +8,23 @@
export const QWEN_CDP_MCP_COMMAND_ENV = 'QWEN_CDP_MCP_COMMAND';
export function resolveCdpMcpCommand(
env: NodeJS.ProcessEnv = process.env,
env: NodeJS.ProcessEnv,
): string | undefined {
const command = env[QWEN_CDP_MCP_COMMAND_ENV]?.trim();
return command ? command : undefined;
}
export function isBrowserAutomationMcpAvailable(opts: {
cdpTunnelOverWs?: boolean;
token?: string;
}): boolean {
export function isBrowserAutomationMcpAvailable(
opts: {
cdpTunnelOverWs?: boolean;
token?: string;
},
env: NodeJS.ProcessEnv,
): boolean {
return (
opts.cdpTunnelOverWs === true &&
!opts.token &&
process.env['QWEN_SERVE_ACP_HTTP'] !== '0' &&
resolveCdpMcpCommand() !== undefined
env['QWEN_SERVE_ACP_HTTP'] !== '0' &&
resolveCdpMcpCommand(env) !== undefined
);
}

View file

@ -1516,10 +1516,13 @@ describe('runQwenServe runtime startup failures', () => {
it('does not enable browser automation MCP on bearer-protected endpoints', () => {
expect(
isBrowserAutomationMcpAvailable({
cdpTunnelOverWs: true,
token: 'secret-token',
}),
isBrowserAutomationMcpAvailable(
{
cdpTunnelOverWs: true,
token: 'secret-token',
},
{},
),
).toBe(false);
});

View file

@ -854,7 +854,10 @@ function currentServeFeaturesForRunQwenServe(
// so the bootstrap `/capabilities` window doesn't briefly under-report them.
clientMcpOverWsEnabled: opts.clientMcpOverWs === true,
cdpTunnelOverWsEnabled: opts.cdpTunnelOverWs === true,
browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(opts),
browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(
opts,
process.env,
),
});
}

View file

@ -95,7 +95,10 @@ export function createServeFeatures(
multiWorkspaceSessionsEnabled,
clientMcpOverWsEnabled: opts.clientMcpOverWs === true,
cdpTunnelOverWsEnabled: opts.cdpTunnelOverWs === true,
browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(opts),
browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(
opts,
process.env,
),
voiceTranscriptionAvailable: getCachedVoiceTranscriptionAvailable(),
// Advertised whenever the `/voice/stream` WS endpoint exists (ACP HTTP
// on). A configured token no longer suppresses it — the browser carries

View file

@ -1247,7 +1247,8 @@ export const createMcpServer = (): McpServer => {
{ readOnlyHint: true },
async ({ device, compressed, output_path }) => {
const robot = getAndroidRobotFromDevice(device, 'mobile_ui_dump');
const xml = await robot.dumpUiHierarchy(compressed ?? false);
let xml = await robot.dumpUiHierarchy(compressed ?? false);
xml = xml.replace(/ bounds="\[[0-9,]+\]\[[0-9,]+\]"/g, '');
if (output_path) {
validateOutputPath(output_path);
fs.writeFileSync(output_path, xml, 'utf-8');