Unverified 提交 a6baaef1 authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Remove deprecated agent mode and consolidate with build mode (#2435)

## Summary - Remove "Build with MCP" option from chat mode selector dropdowns - Route build mode to MCP agent code path when MCP servers are enabled - Add MCP chip showing "N MCP" next to Build button when servers enabled - Show MCP tools picker in build mode when MCP servers are enabled - Skip deprecated agent mode in keyboard shortcut toggle cycle - Update e2e tests to use build mode instead of agent mode ## Test plan - [x] MCP e2e tests pass (verified locally) - [ ] Verify Build mode works normally without MCP servers configured - [ ] Configure an MCP server and verify the "N MCP" chip appears next to Build button - [ ] Verify clicking MCP tools picker shows enabled MCP servers - [ ] Verify sending a message in Build mode with MCP servers uses the agent code path 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2435"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes the chat-mode UI and the main chat streaming branching so Build may enter the MCP/tooling code path when MCP servers are enabled; this can alter assistant behavior and tool-consent flows. Lockfile churn may also affect dependency installs across environments. > > **Overview** > **Removes the user-facing “Build with MCP”/`agent` mode selection** and treats stored `agent` settings as **Build** for backwards compatibility. > > **Build now conditionally enables MCP tooling**: the MCP tools picker appears in Build only when at least one MCP server is enabled, and the main streaming handler runs the MCP agent pre-pass only when Build has enabled MCP servers (or when legacy `agent` is set). > > Adds a small **“N MCP” status chip** next to Build when MCP servers are enabled, updates the keyboard mode-toggle cycle to skip deprecated `agent`, updates MCP e2e tests to select Build, and includes a large `package-lock.json` metadata update (peer flag changes). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 6338761b9e45313d399dd2f4873e5ef9a53ff36a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Removed the deprecated Agent mode by folding it into Build. Build now uses MCP tooling only when MCP servers are enabled; the UI shows an MCP count chip and tools picker, and old “agent” settings still work. - **Refactors** - Removed Agent from mode selectors; legacy “agent” appears as Build and the keyboard toggle skips it. - Build routes through the MCP agent path only when enabled MCP servers exist; otherwise behaves like normal Build. - Preserved compatibility for users with “agent” in settings and in the streaming path. - Updated E2E tests to use Build and aligned test_helper with the modular PageObject structure. - **New Features** - Added an “N MCP” chip next to Build when servers are enabled. - Show the MCP tools picker in Build when MCP servers are enabled. <sup>Written for commit 6338761b9e45313d399dd2f4873e5ef9a53ff36a. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: 's avatarClaude Opus 4.5 <noreply@anthropic.com> Co-authored-by: 's avatarclaude[bot] <41898282+claude[bot]@users.noreply.github.com>
上级 743672c3
......@@ -30,7 +30,7 @@ testSkipIfWindows("mcp - call calculator", async ({ po }) => {
await po.page.getByRole("textbox", { name: "Value" }).fill("testValue1");
await po.page.getByRole("button", { name: "Save" }).click();
await po.navigation.goToAppsTab();
await po.chatActions.selectChatMode("agent");
await po.chatActions.selectChatMode("build");
await po.sendPrompt("[call_tool=calculator_add]", {
skipWaitForCompletion: true,
});
......@@ -115,7 +115,7 @@ testSkipIfWindows("mcp - call calculator via http", async ({ po }) => {
await po.navigation.goToSettingsTab();
await po.page.getByRole("button", { name: "Tools (MCP)" }).click();
await po.navigation.goToAppsTab();
await po.chatActions.selectChatMode("agent");
await po.chatActions.selectChatMode("build");
await po.sendPrompt("[call_tool=calculator_add]", {
skipWaitForCompletion: true,
});
......
......@@ -451,7 +451,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
......@@ -674,7 +673,6 @@
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/parser": "^7.27.2",
......@@ -1420,7 +1418,6 @@
"integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"chalk": "^4.1.1",
"fs-extra": "^9.0.1",
......@@ -2742,8 +2739,7 @@
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/@flakiness/flakiness-report/-/flakiness-report-0.22.0.tgz",
"integrity": "sha512-soo8VpTu1/LqFXrwv7HX/YcvKHRN6gjyGZqpOeSa0u5ZrtysuFL4u59FhDhnfKqCC17UQUACPBE8KSM36PiOaw==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@flakiness/playwright": {
"version": "1.0.0",
......@@ -2906,6 +2902,7 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -2928,6 +2925,7 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -2950,6 +2948,7 @@
"os": [
"darwin"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -2966,6 +2965,7 @@
"os": [
"darwin"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -2982,6 +2982,7 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -2998,6 +2999,7 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3014,6 +3016,7 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3030,6 +3033,7 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3046,6 +3050,7 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3062,6 +3067,7 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3078,6 +3084,7 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3094,6 +3101,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3116,6 +3124,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3138,6 +3147,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3160,6 +3170,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3182,6 +3193,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3204,6 +3216,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3226,6 +3239,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3245,6 +3259,7 @@
],
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"peer": true,
"dependencies": {
"@emnapi/runtime": "^1.4.4"
},
......@@ -3267,6 +3282,7 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3286,6 +3302,7 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3305,6 +3322,7 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3590,7 +3608,6 @@
"integrity": "sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@inquirer/checkbox": "^3.0.1",
"@inquirer/confirm": "^4.0.1",
......@@ -4354,6 +4371,7 @@
"resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.35.0.tgz",
"integrity": "sha512-2H393EYDnFznYCDFOW3MHiRzwEO5M/UBhtUjvTT+9kc+qhX4U3zc8ixQalo5UmZ5B2nh7L/inXdTFzvSRXtsRA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@lexical/list": "0.35.0",
"@lexical/selection": "0.35.0",
......@@ -4366,6 +4384,7 @@
"resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.35.0.tgz",
"integrity": "sha512-ko7xSIIiayvDiqjNDX6fgH9RlcM6r9vrrvJYTcfGVBor5httx16lhIi0QJZ4+RNPvGtTjyFv4bwRmsixRRwImg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@lexical/html": "0.35.0",
"@lexical/list": "0.35.0",
......@@ -4379,6 +4398,7 @@
"resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.35.0.tgz",
"integrity": "sha512-rXGFE5S5rKsg3tVnr1s4iEgOfCApNXGpIFI3T2jGEShaCZ5HLaBY9NVBXnE9Nb49e9bkDkpZ8FZd1qokCbQXbw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@lexical/selection": "0.35.0",
"@lexical/utils": "0.35.0",
......@@ -4390,6 +4410,7 @@
"resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.35.0.tgz",
"integrity": "sha512-owsmc8iwgExBX8sFe8fKTiwJVhYULt9hD1RZ/HwfaiEtRZZkINijqReOBnW2mJfRxBzhFSWc4NG3ISB+fHYzqw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@lexical/selection": "0.35.0",
"@lexical/utils": "0.35.0",
......@@ -4401,6 +4422,7 @@
"resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.35.0.tgz",
"integrity": "sha512-mMtDE7Q0nycXdFTTH/+ta6EBrBwxBB4Tg8QwsGntzQ1Cq//d838dpXpFjJOqHEeVHUqXpiuj+cBG8+bvz/rPRw==",
"license": "MIT",
"peer": true,
"dependencies": {
"lexical": "0.35.0"
}
......@@ -4410,6 +4432,7 @@
"resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.35.0.tgz",
"integrity": "sha512-9jlTlkVideBKwsEnEkqkdg7A3mije1SvmfiqoYnkl1kKJCLA5iH90ywx327PU0p+bdnURAytWUeZPXaEuEl2OA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@lexical/clipboard": "0.35.0",
"@lexical/utils": "0.35.0",
......@@ -4420,7 +4443,8 @@
"version": "0.35.0",
"resolved": "https://registry.npmjs.org/lexical/-/lexical-0.35.0.tgz",
"integrity": "sha512-3VuV8xXhh5xJA6tzvfDvE0YBCMkIZUmxtRilJQDDdCgJCc+eut6qAv2qbN+pbqvarqcQqPN1UF+8YvsjmyOZpw==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@lexical/yjs": {
"version": "0.33.1",
......@@ -4575,7 +4599,6 @@
"resolved": "https://registry.npmjs.org/@neondatabase/serverless/-/serverless-1.0.1.tgz",
"integrity": "sha512-O6yC5TT0jbw86VZVkmnzCZJB0hfxBl0JJz6f+3KHoZabjb/X08r9eFA+vuY06z1/qaovykvdkrXYq3SPUuvogA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "^22.15.30",
"@types/pg": "^8.8.0"
......@@ -4588,7 +4611,8 @@
"version": "15.5.2",
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.2.tgz",
"integrity": "sha512-Qe06ew4zt12LeO6N7j8/nULSOe3fMXE4dM6xgpBQNvdzyK1sv5y4oAP3bq4LamrvGCZtmRYnW8URFCeX5nFgGg==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@next/swc-darwin-arm64": {
"version": "15.5.2",
......@@ -4602,6 +4626,7 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4618,6 +4643,7 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4634,6 +4660,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4650,6 +4677,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4666,6 +4694,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4682,6 +4711,7 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4698,6 +4728,7 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4714,6 +4745,7 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4840,7 +4872,6 @@
"integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0",
......@@ -5402,7 +5433,6 @@
"integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"playwright": "1.58.2"
},
......@@ -6827,7 +6857,6 @@
"integrity": "sha512-EwquDRUDVvWcZds3T2abmB5wSN/Vattal4YtZ6fpBlIUqONV4o/cOBX39cFfQSUCBrIXIjQ6RmapQCHK/PvBYw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@storybook/global": "^5.0.0",
"@storybook/instrumenter": "8.6.15",
......@@ -6972,6 +7001,7 @@
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"tslib": "^2.8.0"
}
......@@ -7611,7 +7641,6 @@
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*"
}
......@@ -7857,7 +7886,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz",
"integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
......@@ -7868,7 +7896,6 @@
"integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==",
"devOptional": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.0.0"
}
......@@ -7977,7 +8004,6 @@
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
......@@ -8413,7 +8439,6 @@
"integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vitest/utils": "3.2.4",
"fflate": "^0.8.2",
......@@ -8705,7 +8730,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
......@@ -9178,7 +9202,6 @@
"integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/types": "^7.26.0"
}
......@@ -9325,7 +9348,6 @@
"integrity": "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==",
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"dependencies": {
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
......@@ -9454,7 +9476,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
......@@ -10031,7 +10052,8 @@
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/cliui": {
"version": "8.0.1",
......@@ -10152,6 +10174,7 @@
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
......@@ -10184,6 +10207,7 @@
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
......@@ -12351,7 +12375,6 @@
"integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
......@@ -12434,7 +12457,6 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
......@@ -13807,7 +13829,6 @@
"integrity": "sha512-Newg9X7mRYskoBjSw70l1YnJ/ZGbq64VPyR821H5WVkTGpHG2O0mQILxCeUhxdYERLFY9B4tUyKLyf3uMTjtKw==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@petamoriken/float16": "^3.8.7",
"debug": "^4.3.4",
......@@ -14300,7 +14321,6 @@
"integrity": "sha512-UVIHeVhxmxedbWPCfgS55Jg2rDfwf2BCKeylcPSqazLz5w3Kri7Q4xdBJubsr/+VUzFLh0VjIvh13RaDA2/Xug==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"webidl-conversions": "^7.0.0",
"whatwg-mimetype": "^3.0.0"
......@@ -15448,6 +15468,7 @@
"resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
"license": "MIT",
"peer": true,
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
......@@ -15761,8 +15782,7 @@
"url": "https://github.com/sponsors/lavrton"
}
],
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/levn": {
"version": "0.4.1",
......@@ -15782,8 +15802,7 @@
"version": "0.33.1",
"resolved": "https://registry.npmjs.org/lexical/-/lexical-0.33.1.tgz",
"integrity": "sha512-+kiCS/GshQmCs/meMb8MQT4AMvw3S3Ef0lSCv2Xi6Itvs59OD+NjQWNfYkDteIbKtVE/w0Yiqh56VyGwIb8UcA==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/lexical-beautiful-mentions": {
"version": "0.1.48",
......@@ -15803,6 +15822,7 @@
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.114.tgz",
"integrity": "sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"isomorphic.js": "^0.2.4"
},
......@@ -18001,8 +18021,7 @@
"version": "0.52.2",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz",
"integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/motion-dom": {
"version": "12.23.12",
......@@ -19177,6 +19196,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
......@@ -19626,7 +19646,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
......@@ -19668,7 +19687,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
"integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
......@@ -20456,7 +20474,6 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz",
"integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
......@@ -20657,7 +20674,6 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
......@@ -20798,7 +20814,6 @@
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz",
"integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
}
......@@ -20911,6 +20926,7 @@
"hasInstallScript": true,
"license": "Apache-2.0",
"optional": true,
"peer": true,
"dependencies": {
"color": "^4.2.3",
"detect-libc": "^2.0.4",
......@@ -21303,6 +21319,7 @@
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"is-arrayish": "^0.3.1"
}
......@@ -21312,7 +21329,8 @@
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"license": "MIT",
"optional": true
"optional": true,
"peer": true
},
"node_modules/sirv": {
"version": "3.0.2",
......@@ -21649,7 +21667,6 @@
"integrity": "sha512-Ob7DMlwWx8s7dMvcQ3xPc02TvUeralb+xX3oaPRk9wY9Hc6M1IBC/7cEoITkSmRS2v38DHubC+mtEKNc1u2gQg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@storybook/core": "8.6.15"
},
......@@ -21998,6 +22015,7 @@
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
"integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
"license": "MIT",
"peer": true,
"dependencies": {
"client-only": "0.0.1"
},
......@@ -22075,8 +22093,7 @@
"version": "4.1.13",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
"integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/tapable": {
"version": "2.3.0",
......@@ -22743,7 +22760,6 @@
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
......@@ -23266,7 +23282,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz",
"integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==",
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
......@@ -23798,7 +23813,6 @@
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/chai": "^5.2.2",
"@vitest/expect": "3.2.4",
......@@ -24451,7 +24465,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
......
......@@ -4,6 +4,7 @@ import { ProModeSelector } from "./ProModeSelector";
import { ChatModeSelector } from "./ChatModeSelector";
import { McpToolsPicker } from "@/components/McpToolsPicker";
import { useSettings } from "@/hooks/useSettings";
import { useMcp } from "@/hooks/useMcp";
export function ChatInputControls({
showContextFilesPicker = false,
......@@ -11,11 +12,20 @@ export function ChatInputControls({
showContextFilesPicker?: boolean;
}) {
const { settings } = useSettings();
const { servers } = useMcp();
const enabledMcpServersCount = servers.filter((s) => s.enabled).length;
// Show MCP tools picker when:
// 1. Mode is "agent" (backwards compatibility) OR
// 2. Mode is "build" AND there are enabled MCP servers
const showMcpToolsPicker =
settings?.selectedChatMode === "agent" ||
(settings?.selectedChatMode === "build" && enabledMcpServersCount > 0);
return (
<div className="flex">
<ChatModeSelector />
{settings?.selectedChatMode === "agent" && (
{showMcpToolsPicker && (
<>
<div className="w-1.5"></div>
<McpToolsPicker />
......
......@@ -12,6 +12,7 @@ import {
} from "@/components/ui/tooltip";
import { useSettings } from "@/hooks/useSettings";
import { useFreeAgentQuota } from "@/hooks/useFreeAgentQuota";
import { useMcp } from "@/hooks/useMcp";
import type { ChatMode } from "@/lib/schemas";
import { isDyadProEnabled } from "@/lib/schemas";
import { cn } from "@/lib/utils";
......@@ -38,9 +39,13 @@ export function ChatModeSelector() {
const chatId = routerState.location.search.id as number | undefined;
const currentChatMessages = chatId ? (messagesById.get(chatId) ?? []) : [];
const selectedMode = settings?.selectedChatMode || "build";
// Treat "agent" mode as "build" for UI purposes (backwards compatibility)
const rawSelectedMode = settings?.selectedChatMode || "build";
const selectedMode = rawSelectedMode === "agent" ? "build" : rawSelectedMode;
const isProEnabled = settings ? isDyadProEnabled(settings) : false;
const { messagesRemaining, isQuotaExceeded } = useFreeAgentQuota();
const { servers } = useMcp();
const enabledMcpServersCount = servers.filter((s) => s.enabled).length;
const handleModeChange = (value: string) => {
const newMode = value as ChatMode;
......@@ -77,11 +82,10 @@ export function ChatModeSelector() {
const getModeDisplayName = (mode: ChatMode) => {
switch (mode) {
case "build":
case "agent": // backwards compatibility - treat as build
return "Build";
case "ask":
return "Ask";
case "agent":
return "Build (MCP)";
case "local-agent":
// Show "Basic Agent" for non-Pro users, "Agent" for Pro users
return isProEnabled ? "Agent" : "Basic Agent";
......@@ -94,105 +98,121 @@ export function ChatModeSelector() {
const isMac = detectIsMac();
return (
<Select
value={selectedMode}
onValueChange={(v) => v && handleModeChange(v)}
>
<Tooltip>
<TooltipTrigger
render={
<MiniSelectTrigger
data-testid="chat-mode-selector"
className={cn(
"h-6 w-fit px-1.5 py-0 text-xs-sm font-medium shadow-none gap-0.5",
selectedMode === "build" ||
selectedMode === "local-agent" ||
selectedMode === "plan"
? "bg-background hover:bg-muted/50 focus:bg-muted/50"
: "bg-primary/10 hover:bg-primary/20 focus:bg-primary/20 text-primary border-primary/20 dark:bg-primary/20 dark:hover:bg-primary/30 dark:focus:bg-primary/30",
)}
size="sm"
/>
}
>
<SelectValue>{getModeDisplayName(selectedMode)}</SelectValue>
</TooltipTrigger>
<TooltipContent>
{`Open mode menu (${isMac ? "\u2318 + ." : "Ctrl + ."} to toggle)`}
</TooltipContent>
</Tooltip>
<SelectContent align="start">
{isProEnabled && (
<>
<SelectItem value="local-agent">
<div className="flex flex-col items-start">
<div className="flex items-center gap-1.5">
<span className="font-medium">Agent v2</span>
<NewBadge />
<div className="flex items-center gap-1.5">
<Select
value={selectedMode}
onValueChange={(v) => v && handleModeChange(v)}
>
<Tooltip>
<TooltipTrigger
render={
<MiniSelectTrigger
data-testid="chat-mode-selector"
className={cn(
"h-6 w-fit px-1.5 py-0 text-xs-sm font-medium shadow-none gap-0.5",
selectedMode === "build" ||
selectedMode === "local-agent" ||
selectedMode === "plan"
? "bg-background hover:bg-muted/50 focus:bg-muted/50"
: "bg-primary/10 hover:bg-primary/20 focus:bg-primary/20 text-primary border-primary/20 dark:bg-primary/20 dark:hover:bg-primary/30 dark:focus:bg-primary/30",
)}
size="sm"
/>
}
>
<SelectValue>{getModeDisplayName(selectedMode)}</SelectValue>
</TooltipTrigger>
<TooltipContent>
{`Open mode menu (${isMac ? "\u2318 + ." : "Ctrl + ."} to toggle)`}
</TooltipContent>
</Tooltip>
<SelectContent align="start">
{isProEnabled && (
<>
<SelectItem value="local-agent">
<div className="flex flex-col items-start">
<div className="flex items-center gap-1.5">
<span className="font-medium">Agent v2</span>
<NewBadge />
</div>
<span className="text-xs text-muted-foreground">
Better at bigger tasks and debugging
</span>
</div>
<span className="text-xs text-muted-foreground">
Better at bigger tasks and debugging
</span>
</div>
</SelectItem>
<SelectItem value="plan">
</SelectItem>
<SelectItem value="plan">
<div className="flex flex-col items-start">
<div className="flex items-center gap-1.5">
<span className="font-medium">Plan</span>
<NewBadge />
</div>
<span className="text-xs text-muted-foreground">
Design before you build
</span>
</div>
</SelectItem>
</>
)}
{!isProEnabled && (
<SelectItem value="local-agent" disabled={isQuotaExceeded}>
<div className="flex flex-col items-start">
<div className="flex items-center gap-1.5">
<span className="font-medium">Plan</span>
<NewBadge />
<span className="font-medium">Basic Agent</span>
<span className="text-xs text-muted-foreground">
({isQuotaExceeded ? "0" : messagesRemaining}/5 remaining for
today)
</span>
</div>
<span className="text-xs text-muted-foreground">
Design before you build
{isQuotaExceeded
? "Daily limit reached"
: "Try our AI agent for free"}
</span>
</div>
</SelectItem>
</>
)}
{!isProEnabled && (
<SelectItem value="local-agent" disabled={isQuotaExceeded}>
)}
<SelectItem value="build">
<div className="flex flex-col items-start">
<div className="flex items-center gap-1.5">
<span className="font-medium">Basic Agent</span>
<span className="text-xs text-muted-foreground">
({isQuotaExceeded ? "0" : messagesRemaining}/5 remaining for
today)
</span>
</div>
<span className="font-medium">Build</span>
<span className="text-xs text-muted-foreground">
{isQuotaExceeded
? "Daily limit reached"
: "Try our AI agent for free"}
Generate and edit code
</span>
</div>
</SelectItem>
)}
<SelectItem value="build">
<div className="flex flex-col items-start">
<span className="font-medium">Build</span>
<span className="text-xs text-muted-foreground">
Generate and edit code
</span>
</div>
</SelectItem>
<SelectItem value="ask">
<div className="flex flex-col items-start">
<span className="font-medium">Ask</span>
<span className="text-xs text-muted-foreground">
Ask questions about the app
</span>
</div>
</SelectItem>
<SelectItem value="agent">
<div className="flex flex-col items-start">
<div className="flex items-center gap-1.5">
<span className="font-medium">Build with MCP</span>
<SelectItem value="ask">
<div className="flex flex-col items-start">
<span className="font-medium">Ask</span>
<span className="text-xs text-muted-foreground">
Ask questions about the app
</span>
</div>
<span className="text-xs text-muted-foreground">
Like Build, but can use tools (MCP) to generate code
</span>
</div>
</SelectItem>
</SelectContent>
</Select>
</SelectItem>
</SelectContent>
</Select>
{selectedMode === "build" && <McpChip count={enabledMcpServersCount} />}
</div>
);
}
function McpChip({ count }: { count: number }) {
if (count === 0) return null;
return (
<Tooltip>
<TooltipTrigger
render={
<span
data-testid="mcp-servers-chip"
className="inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium bg-purple-100 text-purple-700 dark:bg-purple-900/40 dark:text-purple-400 border border-purple-200 dark:border-purple-800 cursor-default"
/>
}
>
{count} MCP
</TooltipTrigger>
<TooltipContent>
<span>
{count} MCP server{count !== 1 ? "s" : ""} enabled
</span>
</TooltipContent>
</Tooltip>
);
}
......@@ -36,9 +36,8 @@ export function DefaultChatModeSelector() {
const getModeDisplayName = (mode: ChatMode) => {
switch (mode) {
case "build":
case "agent": // backwards compatibility - treat as build
return "Build";
case "agent":
return "Build (MCP)";
case "local-agent":
return isProEnabled ? "Agent" : "Basic Agent";
case "ask":
......@@ -86,14 +85,6 @@ export function DefaultChatModeSelector() {
</span>
</div>
</SelectItem>
<SelectItem value="agent">
<div className="flex flex-col items-start">
<span className="font-medium">Build with MCP</span>
<span className="text-xs text-muted-foreground">
Build with tools (MCP)
</span>
</div>
</SelectItem>
</SelectContent>
</Select>
</div>
......
......@@ -20,13 +20,17 @@ export function useChatModeToggle() {
[isMac],
);
// Function to toggle between ask and build chat modes
// Function to toggle between chat modes (skipping deprecated "agent" mode)
const toggleChatMode = useCallback(() => {
if (!settings || !settings.selectedChatMode) return;
const currentMode = settings.selectedChatMode;
const modes = ChatModeSchema.options;
const currentIndex = modes.indexOf(settings.selectedChatMode);
// Filter out deprecated "agent" mode from toggle cycle
const modes = ChatModeSchema.options.filter((m) => m !== "agent");
// If current mode is "agent", treat it as "build" for indexing
const effectiveCurrentMode =
currentMode === "agent" ? "build" : currentMode;
const currentIndex = modes.indexOf(effectiveCurrentMode);
const newMode = modes[(currentIndex + 1) % modes.length];
updateSettings({ selectedChatMode: newMode });
......
......@@ -1202,46 +1202,58 @@ This conversation includes one or more image attachments. When the user uploads
return;
}
if (settings.selectedChatMode === "agent") {
// Use MCP agent code path if:
// 1. Mode is explicitly "agent" (backwards compatibility for existing settings)
// 2. Mode is "build" AND there are enabled MCP servers
if (
settings.selectedChatMode === "agent" ||
settings.selectedChatMode === "build"
) {
const tools = await getMcpTools(event);
const { fullStream } = await simpleStreamText({
chatMessages: limitedHistoryChatMessages,
modelClient,
tools: {
...tools,
"generate-code": {
description:
"ALWAYS use this tool whenever generating or editing code for the codebase.",
inputSchema: z.object({}),
execute: async () => "",
const hasEnabledMcpServers = Object.keys(tools).length > 0;
// Only run MCP agent path if mode is "agent" OR if build mode has enabled MCP servers
if (settings.selectedChatMode === "agent" || hasEnabledMcpServers) {
const { fullStream } = await simpleStreamText({
chatMessages: limitedHistoryChatMessages,
modelClient,
tools: {
...tools,
"generate-code": {
description:
"ALWAYS use this tool whenever generating or editing code for the codebase.",
inputSchema: z.object({}),
execute: async () => "",
},
},
},
systemPromptOverride: constructSystemPrompt({
aiRules: await readAiRules(getDyadAppPath(updatedChat.app.path)),
chatMode: "agent",
enableTurboEditsV2: false,
}),
files: files,
dyadDisableFiles: true,
});
systemPromptOverride: constructSystemPrompt({
aiRules: await readAiRules(
getDyadAppPath(updatedChat.app.path),
),
chatMode: "agent",
enableTurboEditsV2: false,
}),
files: files,
dyadDisableFiles: true,
});
const result = await processStreamChunks({
fullStream,
fullResponse,
abortController,
chatId: req.chatId,
processResponseChunkUpdate,
});
fullResponse = result.fullResponse;
chatMessages.push({
role: "assistant",
content: fullResponse,
});
chatMessages.push({
role: "user",
content: "OK.",
});
const result = await processStreamChunks({
fullStream,
fullResponse,
abortController,
chatId: req.chatId,
processResponseChunkUpdate,
});
fullResponse = result.fullResponse;
chatMessages.push({
role: "assistant",
content: fullResponse,
});
chatMessages.push({
role: "user",
content: "OK.",
});
}
}
// When calling streamText, the messages need to be properly formatted for mixed content
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论