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

feat: make ask mode always use local agent handler (#2434)

## Summary - Ask mode now always uses the local agent handler with read-only tools, regardless of Dyad Pro status - This gives all users access to code reading tools while in ask mode - Ask mode does not consume free agent quota ## Test plan - Test ask mode in a non-Pro account and verify it can use local agent tools (file reading, searching) - Verify ask mode still operates in read-only mode (no editing capabilities) - Confirm ask mode doesn't consume free agent quota #skip-bugbot 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2434"> <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 --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Ask mode now always uses the local agent handler in read-only mode. It’s available to all users and doesn’t consume free agent quota. - **New Features** - Routes all Ask mode chats to the local agent. - Removes the Pro check; available to all users. - Read-only tools only; no edits. - Engine-dependent tools (code search, web search, web crawl) require Dyad Pro. - **Bug Fixes** - Skips file upload instructions in Ask mode since write tools aren’t available. <sup>Written for commit 9732679491a53e7be7fa40dae6f18db4b2d43701. 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>
上级 22d35641
......@@ -6,20 +6,23 @@ testSkipIfWindows("toggle chat panel visibility", async ({ po }) => {
// We are in the chat view after setUp
await po.sendPrompt("basic");
// Chat panel should be visible initially.
const chatPanel = po.page.locator("#chat-panel");
await expect(chatPanel).toBeVisible();
// Chat panel content should be visible initially.
// We check the ChatPanel content rather than the panel container itself,
// since the container is always present but resized to 1% when collapsed.
const chatPanelContent = po.page.getByTestId("messages-list");
await expect(chatPanelContent).toBeVisible();
// Toggle button
const toggleButton = po.page.getByTestId("preview-toggle-chat-panel-button");
// Collapse
await toggleButton.click();
await expect(chatPanel).toBeHidden();
// When collapsed, the ChatPanel component is not rendered (isChatPanelHidden = true)
await expect(chatPanelContent).toBeHidden();
// Expand
await toggleButton.click();
// Expect chat panel to be visible
await expect(chatPanel).toBeVisible();
// Expect chat panel content to be visible again
await expect(chatPanelContent).toBeVisible();
});
===
role: system
message:
# Role
You are a helpful AI assistant that specializes in web development, programming, and technical guidance. You assist users by providing clear explanations, answering questions, and offering guidance on best practices. You understand modern web development technologies and can explain concepts clearly to users of all skill levels.
# Guidelines
Always reply to the user in the same language they are using.
Focus on providing helpful explanations and guidance:
- Provide clear explanations of programming concepts and best practices
- Answer technical questions with accurate information
- Offer guidance and suggestions for solving problems
- Explain complex topics in an accessible way
- Share knowledge about web development technologies and patterns
If the user's input is unclear or ambiguous:
- Ask clarifying questions to better understand their needs
- Provide explanations that address the most likely interpretation
- Offer multiple perspectives when appropriate
When discussing code or technical concepts:
- Describe approaches and patterns in plain language
- Explain the reasoning behind recommendations
- Discuss trade-offs and alternatives through detailed descriptions
- Focus on best practices and maintainable solutions through conceptual explanations
- Use analogies and conceptual explanations instead of code examples
# Technical Expertise Areas
## Development Best Practices
- Component architecture and design patterns
- Code organization and file structure
- Responsive design principles
- Accessibility considerations
- Performance optimization
- Error handling strategies
## Problem-Solving Approach
- Break down complex problems into manageable parts
- Explain the reasoning behind technical decisions
- Provide multiple solution approaches when appropriate
- Consider maintainability and scalability
- Focus on user experience and functionality
# Communication Style
- **Clear and Concise**: Provide direct answers while being thorough
- **Educational**: Explain the "why" behind recommendations
- **Practical**: Focus on actionable advice and real-world applications
- **Supportive**: Encourage learning and experimentation
- **Professional**: Maintain a helpful and knowledgeable tone
# Key Principles
1. **NO CODE PRODUCTION**: Never write, generate, or produce any code snippets, examples, or implementations. This is the most important principle.
2. **Clarity First**: Always prioritize clear communication through conceptual explanations.
3. **Best Practices**: Recommend industry-standard approaches through detailed descriptions.
4. **Practical Solutions**: Focus on solution approaches that work in real-world scenarios.
5. **Educational Value**: Help users understand concepts through explanations, not code.
6. **Simplicity**: Prefer simple, elegant conceptual explanations over complex descriptions.
# Response Guidelines
- Keep explanations at an appropriate technical level for the user.
- Use analogies and conceptual descriptions instead of code examples.
- Provide context for recommendations and suggestions through detailed explanations.
- Be honest about limitations and trade-offs.
- Encourage good development practices through conceptual guidance.
- Suggest additional resources when helpful.
- **NEVER include any code snippets, syntax examples, or implementation details.**
<role>
You are Dyad, an AI assistant that helps users understand their web applications. You assist users by answering questions about their code, explaining concepts, and providing guidance. You can read and analyze code in the codebase to provide accurate, context-aware answers.
You are friendly and helpful, always aiming to provide clear explanations. You take pride in giving thorough, accurate answers based on the actual code.
</role>
<important_constraints>
**CRITICAL: You are in READ-ONLY mode.**
- You can read files, search code, and analyze the codebase
- You MUST NOT modify any files, create new files, or make any changes
- You MUST NOT suggest using write_file, delete_file, rename_file, add_dependency, or execute_sql tools
- Focus on explaining, answering questions, and providing guidance
- If the user asks you to make changes, politely explain that you're in Ask mode and can only provide explanations and guidance
</important_constraints>
<general_guidelines>
- Always reply to the user in the same language they are using.
- Use your tools to read and understand the codebase before answering questions
- Provide clear, accurate explanations based on the actual code
- When explaining code, reference specific files and line numbers when helpful
- If you're not sure about something, read the relevant files to find out
- Keep explanations clear and focused on what the user is asking about
</general_guidelines>
<tool_calling>
You have READ-ONLY tools at your disposal to understand the codebase. Follow these rules:
1. ALWAYS follow the tool call schema exactly as specified and make sure to provide all necessary parameters.
2. **NEVER refer to tool names when speaking to the USER.** Instead, just say what you're doing in natural language (e.g., "Let me look at that file" instead of "I'll use read_file").
3. Use tools proactively to gather information and provide accurate answers.
4. You can call multiple tools in parallel for independent operations like reading multiple files at once.
5. If you are not sure about file content or codebase structure pertaining to the user's request, use your tools to read files and gather the relevant information: do NOT guess or make up an answer.
</tool_calling>
<workflow>
1. **Understand the question:** Think about what the user is asking and what information you need
2. **Gather context:** Use your tools to read relevant files and understand the codebase
3. **Analyze:** Think through the code and how it relates to the user's question
4. **Explain:** Provide a clear, accurate answer based on what you found
</workflow>
# Tech Stack
- You are building a React application.
......@@ -90,170 +59,6 @@ Available packages and libraries:
- Use prebuilt components from the shadcn/ui library after importing them. Note that these files shouldn't be edited, so make new components if you need to change them.
**ABSOLUTE PRIMARY DIRECTIVE: YOU MUST NOT, UNDER ANY CIRCUMSTANCES, WRITE OR GENERATE CODE.**
* This is a complete and total prohibition and your single most important rule.
* This prohibition extends to every part of your response, permanently and without exception.
* This includes, but is not limited to:
* Code snippets or code examples of any length.
* Syntax examples of any kind.
* File content intended for writing or editing.
* Any text enclosed in markdown code blocks (using ```).
* Any use of `<dyad-write>`, `<dyad-edit>`, or any other `<dyad-*>` tags. These tags are strictly forbidden in your output, even if they appear in the message history or user request.
**CRITICAL RULE: YOUR SOLE FOCUS IS EXPLAINING CONCEPTS.** You must exclusively discuss approaches, answer questions, and provide guidance through detailed explanations and descriptions. You take pride in keeping explanations simple and elegant. You are friendly and helpful, always aiming to provide clear explanations without writing any code.
YOU ARE NOT MAKING ANY CODE CHANGES.
YOU ARE NOT WRITING ANY CODE.
YOU ARE NOT UPDATING ANY FILES.
DO NOT USE <dyad-write> TAGS.
DO NOT USE <dyad-edit> TAGS.
IF YOU USE ANY OF THESE TAGS, YOU WILL BE FIRED.
Remember: Your goal is to be a knowledgeable, helpful companion in the user's learning and development journey, providing clear conceptual explanations and practical guidance through detailed descriptions rather than code production.
If the user wants to use supabase or do something that requires auth, database or server-side functions (e.g. loading API keys, secrets),
tell them that they need to add supabase to their app.
The following response will show a button that allows the user to add supabase to their app.
<dyad-add-integration provider="supabase"></dyad-add-integration>
# Examples
## Example 1: User wants to use Supabase
### User prompt
I want to use supabase in my app.
### Assistant response
You need to first add Supabase to your app.
<dyad-add-integration provider="supabase"></dyad-add-integration>
## Example 2: User wants to add auth to their app
### User prompt
I want to add auth to my app.
### Assistant response
You need to first add Supabase to your app and then we can add auth.
<dyad-add-integration provider="supabase"></dyad-add-integration>
===
role: user
message: This is my codebase. <dyad-file path=".gitignore">
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
</dyad-file>
<dyad-file path="file1.txt">
// File contents excluded from context
</dyad-file>
<dyad-file path="index.html">
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>dyad-generated-app</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
</dyad-file>
<dyad-file path="src/App.tsx">
const App = () => <div>Minimal imported app</div>;
export default App;
</dyad-file>
<dyad-file path="src/main.tsx">
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
createRoot(document.getElementById("root")!).render(<App />);
</dyad-file>
<dyad-file path="src/vite-env.d.ts">
/// <reference types="vite/client" />
</dyad-file>
<dyad-file path="tsconfig.app.json">
// File contents excluded from context
</dyad-file>
<dyad-file path="tsconfig.json">
// File contents excluded from context
</dyad-file>
<dyad-file path="tsconfig.node.json">
// File contents excluded from context
</dyad-file>
<dyad-file path="vite.config.ts">
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
export default defineConfig(() => ({
server: {
host: "::",
port: 8080,
},
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
}));
</dyad-file>
===
role: assistant
message: OK, got it. I'm ready to help
===
role: user
......@@ -261,9 +66,18 @@ message: Generate an AI_RULES.md file for this app. Describe the tech stack in 5
===
role: assistant
message: More
message:
<dyad-write path="file1.txt">
A file (2)
</dyad-write>
More
EOM
===
role: user
message: [dump] hi
\ No newline at end of file
......@@ -451,6 +451,7 @@
"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",
......@@ -1418,6 +1419,7 @@
"integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"chalk": "^4.1.1",
"fs-extra": "^9.0.1",
......@@ -2902,7 +2904,6 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -2925,7 +2926,6 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -2948,7 +2948,6 @@
"os": [
"darwin"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -2965,7 +2964,6 @@
"os": [
"darwin"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -2982,7 +2980,6 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -2999,7 +2996,6 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3016,7 +3012,6 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3033,7 +3028,6 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3050,7 +3044,6 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3067,7 +3060,6 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3084,7 +3076,6 @@
"os": [
"linux"
],
"peer": true,
"funding": {
"url": "https://opencollective.com/libvips"
}
......@@ -3101,7 +3092,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3124,7 +3114,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3147,7 +3136,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3170,7 +3158,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3193,7 +3180,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3216,7 +3202,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3239,7 +3224,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3259,7 +3243,6 @@
],
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"peer": true,
"dependencies": {
"@emnapi/runtime": "^1.4.4"
},
......@@ -3282,7 +3265,6 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3302,7 +3284,6 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3322,7 +3303,6 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
......@@ -3608,6 +3588,7 @@
"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",
......@@ -4371,7 +4352,6 @@
"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",
......@@ -4384,7 +4364,6 @@
"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",
......@@ -4398,7 +4377,6 @@
"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",
......@@ -4410,7 +4388,6 @@
"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",
......@@ -4422,7 +4399,6 @@
"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"
}
......@@ -4432,7 +4408,6 @@
"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",
......@@ -4443,8 +4418,7 @@
"version": "0.35.0",
"resolved": "https://registry.npmjs.org/lexical/-/lexical-0.35.0.tgz",
"integrity": "sha512-3VuV8xXhh5xJA6tzvfDvE0YBCMkIZUmxtRilJQDDdCgJCc+eut6qAv2qbN+pbqvarqcQqPN1UF+8YvsjmyOZpw==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@lexical/yjs": {
"version": "0.33.1",
......@@ -4599,6 +4573,7 @@
"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"
......@@ -4611,8 +4586,7 @@
"version": "15.5.2",
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.2.tgz",
"integrity": "sha512-Qe06ew4zt12LeO6N7j8/nULSOe3fMXE4dM6xgpBQNvdzyK1sv5y4oAP3bq4LamrvGCZtmRYnW8URFCeX5nFgGg==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@next/swc-darwin-arm64": {
"version": "15.5.2",
......@@ -4626,7 +4600,6 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4643,7 +4616,6 @@
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4660,7 +4632,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4677,7 +4648,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4694,7 +4664,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4711,7 +4680,6 @@
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4728,7 +4696,6 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4745,7 +4712,6 @@
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">= 10"
}
......@@ -4872,6 +4838,7 @@
"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",
......@@ -5433,6 +5400,7 @@
"integrity": "sha512-04IXzPwHrW69XusN/SIdDdKZBzMfOT9UNT/YiJit/xpy2VuAoB8NHc8Aplb96zsWDddLnbkPL3TsmrS04ZU2xQ==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"playwright": "1.55.0"
},
......@@ -7001,7 +6969,6 @@
"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"
}
......@@ -7641,6 +7608,7 @@
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*"
}
......@@ -7886,6 +7854,7 @@
"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"
}
......@@ -7896,6 +7865,7 @@
"integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==",
"devOptional": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.0.0"
}
......@@ -8004,6 +7974,7 @@
"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",
......@@ -8439,6 +8410,7 @@
"integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vitest/utils": "3.2.4",
"fflate": "^0.8.2",
......@@ -8730,6 +8702,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
......@@ -9202,6 +9175,7 @@
"integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/types": "^7.26.0"
}
......@@ -9348,6 +9322,7 @@
"integrity": "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==",
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"dependencies": {
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
......@@ -9476,6 +9451,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
......@@ -10052,8 +10028,7 @@
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/cliui": {
"version": "8.0.1",
......@@ -10174,7 +10149,6 @@
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
......@@ -10207,7 +10181,6 @@
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
......@@ -12457,6 +12430,7 @@
"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",
......@@ -13829,6 +13803,7 @@
"integrity": "sha512-Newg9X7mRYskoBjSw70l1YnJ/ZGbq64VPyR821H5WVkTGpHG2O0mQILxCeUhxdYERLFY9B4tUyKLyf3uMTjtKw==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@petamoriken/float16": "^3.8.7",
"debug": "^4.3.4",
......@@ -14321,6 +14296,7 @@
"integrity": "sha512-UVIHeVhxmxedbWPCfgS55Jg2rDfwf2BCKeylcPSqazLz5w3Kri7Q4xdBJubsr/+VUzFLh0VjIvh13RaDA2/Xug==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"webidl-conversions": "^7.0.0",
"whatwg-mimetype": "^3.0.0"
......@@ -15468,7 +15444,6 @@
"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"
......@@ -15782,7 +15757,8 @@
"url": "https://github.com/sponsors/lavrton"
}
],
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/levn": {
"version": "0.4.1",
......@@ -15802,7 +15778,8 @@
"version": "0.33.1",
"resolved": "https://registry.npmjs.org/lexical/-/lexical-0.33.1.tgz",
"integrity": "sha512-+kiCS/GshQmCs/meMb8MQT4AMvw3S3Ef0lSCv2Xi6Itvs59OD+NjQWNfYkDteIbKtVE/w0Yiqh56VyGwIb8UcA==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lexical-beautiful-mentions": {
"version": "0.1.48",
......@@ -15822,7 +15799,6 @@
"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"
},
......@@ -18021,7 +17997,8 @@
"version": "0.52.2",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz",
"integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/motion-dom": {
"version": "12.23.12",
......@@ -19196,7 +19173,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
......@@ -19646,6 +19622,7 @@
"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"
}
......@@ -19687,6 +19664,7 @@
"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"
},
......@@ -20474,6 +20452,7 @@
"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"
},
......@@ -20674,6 +20653,7 @@
"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",
......@@ -20814,6 +20794,7 @@
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz",
"integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
}
......@@ -20926,7 +20907,6 @@
"hasInstallScript": true,
"license": "Apache-2.0",
"optional": true,
"peer": true,
"dependencies": {
"color": "^4.2.3",
"detect-libc": "^2.0.4",
......@@ -21319,7 +21299,6 @@
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"is-arrayish": "^0.3.1"
}
......@@ -21329,8 +21308,7 @@
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"license": "MIT",
"optional": true,
"peer": true
"optional": true
},
"node_modules/sirv": {
"version": "3.0.2",
......@@ -22015,7 +21993,6 @@
"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"
},
......@@ -22093,7 +22070,8 @@
"version": "4.1.13",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
"integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/tapable": {
"version": "2.3.0",
......@@ -22760,6 +22738,7 @@
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
......@@ -23282,6 +23261,7 @@
"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",
......@@ -23813,6 +23793,7 @@
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/chai": "^5.2.2",
"@vitest/expect": "3.2.4",
......@@ -24465,6 +24446,7 @@
"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"
}
......
......@@ -86,7 +86,6 @@ import { replacePromptReference } from "../utils/replacePromptReference";
import { mcpManager } from "../utils/mcp_manager";
import z from "zod";
import {
isDyadProEnabled,
isBasicAgentMode,
isSupabaseConnected,
isTurboEditsV2Enabled,
......@@ -536,8 +535,7 @@ ${componentSnippet}
);
const willUseLocalAgentStream =
(settings.selectedChatMode === "local-agent" ||
(settings.selectedChatMode === "ask" &&
isDyadProEnabled(settings))) &&
settings.selectedChatMode === "ask") &&
!mentionedAppsCodebases.length;
const isDeepContextEnabled =
......@@ -729,8 +727,9 @@ ${componentSnippet}
// print out the dyad-write tags.
// Usually, AI models will want to use the image as reference to generate code (e.g. UI mockups) anyways, so
// it's not that critical to include the image analysis instructions.
const isAskMode = settings.selectedChatMode === "ask";
if (hasUploadedAttachments) {
if (willUseLocalAgentStream) {
if (willUseLocalAgentStream && !isAskMode) {
systemPrompt += `
When files are attached to this conversation, upload them to the codebase using the \`write_file\` tool.
......@@ -742,7 +741,7 @@ write_file(path="src/components/Button.jsx", content="DYAD_ATTACHMENT_0", descri
\`\`\`
`;
} else {
} else if (!isAskMode) {
systemPrompt += `
When files are attached to this conversation, upload them to the codebase using this exact format:
......@@ -1029,11 +1028,11 @@ This conversation includes one or more image attachments. When the user uploads
return fullResponse;
};
// Handle pro ask mode: use local-agent in read-only mode
// This gives pro users access to code reading tools while in ask mode
// Handle ask mode: use local-agent in read-only mode
// This gives users access to code reading tools while in ask mode
// Ask mode does not consume free agent quota
if (
settings.selectedChatMode === "ask" &&
isDyadProEnabled(settings) &&
!mentionedAppsCodebases.length
) {
// Reconstruct system prompt for local-agent read-only mode
......@@ -1045,19 +1044,32 @@ This conversation includes one or more image attachments. When the user uploads
readOnly: true,
});
await handleLocalAgentStream(event, req, abortController, {
placeholderMessageId: placeholderAssistantMessage.id,
// Note: this is using the read-only system prompt rather than the
// regular system prompt which gets overrides for special intents
// like summarize chat, security review, etc.
//
// This is OK because those intents should always happen in a new chat
// and new chats will default to non-ask modes.
systemPrompt: readOnlySystemPrompt,
dyadRequestId: dyadRequestId ?? "[no-request-id]",
readOnly: true,
messageOverride: isSummarizeIntent ? chatMessages : undefined,
});
// Return value indicates success/failure for quota tracking.
// Ask mode doesn't consume quota, but we still capture it for
// consistent error handling.
const streamSuccess = await handleLocalAgentStream(
event,
req,
abortController,
{
placeholderMessageId: placeholderAssistantMessage.id,
// Note: this is using the read-only system prompt rather than the
// regular system prompt which gets overrides for special intents
// like summarize chat, security review, etc.
//
// This is OK because those intents should always happen in a new chat
// and new chats will default to non-ask modes.
systemPrompt: readOnlySystemPrompt,
dyadRequestId: dyadRequestId ?? "[no-request-id]",
readOnly: true,
messageOverride: isSummarizeIntent ? chatMessages : undefined,
},
);
if (!streamSuccess) {
logger.warn(
"Ask mode local agent stream did not complete successfully",
);
}
return;
}
......
......@@ -131,7 +131,8 @@ export async function handleLocalAgentStream(
// Check Pro status or Basic Agent mode
// Basic Agent mode allows non-Pro users with quota (quota check is done in chat_stream_handlers)
if (!isDyadProEnabled(settings) && !isBasicAgentMode(settings)) {
// Read-only mode (ask mode) is allowed for all users without Pro
if (!readOnly && !isDyadProEnabled(settings) && !isBasicAgentMode(settings)) {
safeSend(event.sender, "chat:response:error", {
chatId: req.chatId,
error:
......@@ -192,7 +193,7 @@ export async function handleLocalAgentStream(
todos: [],
dyadRequestId,
fileEditTracker,
isBasicAgentMode: isBasicAgentMode(settings),
isDyadPro: isDyadProEnabled(settings),
onXmlStream: (accumulatedXml: string) => {
// Stream accumulated XML to UI without persisting
streamingPreview = accumulatedXml;
......
......@@ -76,8 +76,8 @@ export const codeSearchTool: ToolDefinition<z.infer<typeof codeSearchSchema>> =
inputSchema: codeSearchSchema,
defaultConsent: "always",
// Disable in Basic Agent mode (free tier) - requires engine
isEnabled: (ctx) => !ctx.isBasicAgentMode,
// Requires Dyad Pro engine API
isEnabled: (ctx) => ctx.isDyadPro,
getConsentPreview: (args) => `Search for "${args.query}"`,
......
......@@ -142,8 +142,8 @@ export const editFileTool: ToolDefinition<z.infer<typeof editFileSchema>> = {
defaultConsent: "always",
modifiesState: true,
// Disable in Basic Agent mode (free tier) - requires engine
isEnabled: (ctx) => !ctx.isBasicAgentMode,
// Requires Dyad Pro engine API
isEnabled: (ctx) => ctx.isDyadPro,
getConsentPreview: (args) => `Edit ${args.path}`,
......
......@@ -45,7 +45,7 @@ describe("searchReplaceTool", () => {
supabaseOrganizationSlug: null,
messageId: 1,
isSharedModulesChanged: false,
isBasicAgentMode: false,
isDyadPro: false,
todos: [],
dyadRequestId: "test-request",
fileEditTracker: {},
......
......@@ -58,10 +58,10 @@ export interface AgentContext {
/** Tracks file edit tool usage per file for telemetry */
fileEditTracker: FileEditTracker;
/**
* If true, this is Basic Agent mode (free tier with quota).
* Engine-dependent tools are disabled in this mode.
* If true, the user has Dyad Pro enabled.
* Engine-dependent tools require this to access the Dyad Pro API.
*/
isBasicAgentMode: boolean;
isDyadPro: boolean;
/**
* Streams accumulated XML to UI without persisting to DB (for live preview).
* Call this repeatedly with the full accumulated XML so far.
......
......@@ -80,8 +80,8 @@ export const webCrawlTool: ToolDefinition<z.infer<typeof webCrawlSchema>> = {
inputSchema: webCrawlSchema,
defaultConsent: "ask",
// Disable in Basic Agent mode (free tier) - requires engine
isEnabled: (ctx) => !ctx.isBasicAgentMode,
// Requires Dyad Pro engine API
isEnabled: (ctx) => ctx.isDyadPro,
getConsentPreview: (args) => `Crawl URL: "${args.url}"`,
......
......@@ -161,8 +161,8 @@ export const webSearchTool: ToolDefinition<z.infer<typeof webSearchSchema>> = {
inputSchema: webSearchSchema,
defaultConsent: "ask",
// Disable in Basic Agent mode (free tier) - requires engine
isEnabled: (ctx) => !ctx.isBasicAgentMode,
// Requires Dyad Pro engine API
isEnabled: (ctx) => ctx.isDyadPro,
getConsentPreview: (args) => `Search the web: "${args.query}"`,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论