Explicit thinking (#183)
This commit is contained in:
@@ -9,6 +9,7 @@ import { DyadExecuteSql } from "./DyadExecuteSql";
|
||||
import { DyadAddIntegration } from "./DyadAddIntegration";
|
||||
import { DyadEdit } from "./DyadEdit";
|
||||
import { DyadCodebaseContext } from "./DyadCodebaseContext";
|
||||
import { DyadThink } from "./DyadThink";
|
||||
import { CodeHighlight } from "./CodeHighlight";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { isStreamingAtom } from "@/atoms/chatAtoms";
|
||||
@@ -119,6 +120,7 @@ function preprocessUnclosedTags(content: string): {
|
||||
"dyad-chat-summary",
|
||||
"dyad-edit",
|
||||
"dyad-codebase-context",
|
||||
"think",
|
||||
];
|
||||
|
||||
let processedContent = content;
|
||||
@@ -183,6 +185,7 @@ function parseCustomTags(content: string): ContentPiece[] {
|
||||
"dyad-chat-summary",
|
||||
"dyad-edit",
|
||||
"dyad-codebase-context",
|
||||
"think",
|
||||
];
|
||||
|
||||
const tagPattern = new RegExp(
|
||||
@@ -268,6 +271,18 @@ function renderCustomTag(
|
||||
const { tag, attributes, content, inProgress } = tagInfo;
|
||||
|
||||
switch (tag) {
|
||||
case "think":
|
||||
return (
|
||||
<DyadThink
|
||||
node={{
|
||||
properties: {
|
||||
state: getState({ isStreaming, inProgress }),
|
||||
},
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</DyadThink>
|
||||
);
|
||||
case "dyad-write":
|
||||
return (
|
||||
<DyadWrite
|
||||
|
||||
75
src/components/chat/DyadThink.tsx
Normal file
75
src/components/chat/DyadThink.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Brain, ChevronDown, ChevronUp, Loader } from "lucide-react";
|
||||
import { VanillaMarkdownParser } from "./DyadMarkdownParser";
|
||||
import { CustomTagState } from "./stateTypes";
|
||||
|
||||
interface DyadThinkProps {
|
||||
node?: any;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const DyadThink: React.FC<DyadThinkProps> = ({ children, node }) => {
|
||||
const state = node?.properties?.state as CustomTagState;
|
||||
const inProgress = state === "pending";
|
||||
const [isExpanded, setIsExpanded] = useState(inProgress);
|
||||
|
||||
// Collapse when transitioning from in-progress to not-in-progress
|
||||
useEffect(() => {
|
||||
if (!inProgress && isExpanded) {
|
||||
setIsExpanded(false);
|
||||
}
|
||||
}, [inProgress]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative bg-(--background-lightest) dark:bg-zinc-900 hover:bg-(--background-lighter) rounded-lg px-4 py-2 border my-2 cursor-pointer ${
|
||||
inProgress ? "border-purple-500" : "border-border"
|
||||
}`}
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
role="button"
|
||||
aria-expanded={isExpanded}
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
setIsExpanded(!isExpanded);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Top-left label badge */}
|
||||
<div
|
||||
className="absolute top-2 left-2 flex items-center gap-1 px-2 py-0.5 rounded text-xs font-semibold text-purple-500 bg-white dark:bg-zinc-900"
|
||||
style={{ zIndex: 1 }}
|
||||
>
|
||||
<Brain size={16} className="text-purple-500" />
|
||||
<span>Thinking</span>
|
||||
{inProgress && (
|
||||
<Loader size={14} className="ml-1 text-purple-500 animate-spin" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Indicator icon */}
|
||||
<div className="absolute top-2 right-2 p-1 text-gray-500">
|
||||
{isExpanded ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
|
||||
</div>
|
||||
|
||||
{/* Main content with smooth transition */}
|
||||
<div
|
||||
className="pt-6 overflow-hidden transition-all duration-300 ease-in-out"
|
||||
style={{
|
||||
maxHeight: isExpanded ? "1000px" : "0px",
|
||||
opacity: isExpanded ? 1 : 0,
|
||||
marginBottom: isExpanded ? "0" : "-6px", // Compensate for padding
|
||||
}}
|
||||
>
|
||||
<div className="px-0 text-sm text-gray-600 dark:text-gray-300">
|
||||
{typeof children === "string" ? (
|
||||
<VanillaMarkdownParser content={children} />
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,3 +1,55 @@
|
||||
export const THINKING_PROMPT = `
|
||||
# Thinking Process
|
||||
|
||||
Before responding to user requests, ALWAYS use <think></think> tags to carefully plan your approach. This structured thinking process helps you organize your thoughts and ensure you provide the most accurate and helpful response. Your thinking should:
|
||||
|
||||
- Use **bullet points** to break down the steps
|
||||
- **Bold key insights** and important considerations
|
||||
- Follow a clear analytical framework
|
||||
|
||||
Example of proper thinking structure for a debugging request:
|
||||
|
||||
<think>
|
||||
• **Identify the specific UI/FE bug described by the user**
|
||||
- "Form submission button doesn't work when clicked"
|
||||
- User reports clicking the button has no effect
|
||||
- This appears to be a **functional issue**, not just styling
|
||||
|
||||
• **Examine relevant components in the codebase**
|
||||
- Form component at \`src/components/ContactForm.jsx\`
|
||||
- Button component at \`src/components/Button.jsx\`
|
||||
- Form submission logic in \`src/utils/formHandlers.js\`
|
||||
- **Key observation**: onClick handler in Button component doesn't appear to be triggered
|
||||
|
||||
• **Diagnose potential causes**
|
||||
- Event handler might not be properly attached to the button
|
||||
- **State management issue**: form validation state might be blocking submission
|
||||
- Button could be disabled by a condition we're missing
|
||||
- Event propagation might be stopped elsewhere
|
||||
- Possible React synthetic event issues
|
||||
|
||||
• **Plan debugging approach**
|
||||
- Add console.logs to track execution flow
|
||||
- **Fix #1**: Ensure onClick prop is properly passed through Button component
|
||||
- **Fix #2**: Check form validation state before submission
|
||||
- **Fix #3**: Verify event handler is properly bound in the component
|
||||
- Add error handling to catch and display submission issues
|
||||
|
||||
• **Consider improvements beyond the fix**
|
||||
- Add visual feedback when button is clicked (loading state)
|
||||
- Implement better error handling for form submissions
|
||||
- Add logging to help debug edge cases
|
||||
</think>
|
||||
|
||||
After completing your thinking process, proceed with your response following the guidelines above. Remember to be concise in your explanations to the user while being thorough in your thinking process.
|
||||
|
||||
This structured thinking ensures you:
|
||||
1. Don't miss important aspects of the request
|
||||
2. Consider all relevant factors before making changes
|
||||
3. Deliver more accurate and helpful responses
|
||||
4. Maintain a consistent approach to problem-solving
|
||||
`;
|
||||
|
||||
export const SYSTEM_PROMPT = `
|
||||
<role> You are Dyad, an AI editor that creates and modifies web applications. You assist users by chatting with them and making changes to their code in real-time. You understand that users can see a live preview of their application in an iframe on the right side of the screen while you make code changes.
|
||||
Not every interaction requires code changes - you're happy to discuss, explain concepts, or provide guidance without modifying the codebase. When code changes are needed, you make efficient and effective updates to React codebases while following best practices for maintainability and readability. You take pride in keeping things simple and elegant. You are friendly and helpful, always aiming to provide clear explanations. </role>
|
||||
@@ -290,6 +342,8 @@ Available packages and libraries:
|
||||
- You have ALL the necessary Radix UI components installed.
|
||||
- Use prebuilt components from the shadcn/ui library after importing them. Note that these files shouldn't't be edited, so make new components if you need to change them.
|
||||
|
||||
${THINKING_PROMPT}
|
||||
|
||||
# REMEMBER
|
||||
|
||||
> **CODE FORMATTING IS NON-NEGOTIABLE:**
|
||||
|
||||
Reference in New Issue
Block a user