Refactor auto-suggestion (#40)

This commit is contained in:
Will Chen
2025-04-28 22:43:37 -07:00
committed by GitHub
parent 322fcb002d
commit 7ab1aab9b0
4 changed files with 87 additions and 13 deletions

View File

@@ -317,7 +317,7 @@ export function ChatInput({ chatId }: { chatId?: number }) {
} }
function SummarizeInNewChatButton() { function SummarizeInNewChatButton() {
const [chatId] = useAtom(selectedChatIdAtom); const chatId = useAtomValue(selectedChatIdAtom);
const appId = useAtomValue(selectedAppIdAtom); const appId = useAtomValue(selectedAppIdAtom);
const { streamMessage } = useStreamChat(); const { streamMessage } = useStreamChat();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -349,10 +349,48 @@ function SummarizeInNewChatButton() {
</TooltipProvider> </TooltipProvider>
); );
} }
function RefactorFileButton({ path }: { path: string }) {
const chatId = useAtomValue(selectedChatIdAtom);
const { streamMessage } = useStreamChat();
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="sm"
onClick={() => {
if (!chatId) {
console.error("No chat id found");
return;
}
streamMessage({
prompt: `Refactor ${path} and make it more modular`,
chatId,
redo: false,
});
}}
>
<span className="max-w-[180px] overflow-hidden whitespace-nowrap text-ellipsis">
Refactor {path.split("/").slice(-2).join("/")}
</span>
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Refactor {path} to improve maintainability</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
function mapActionToButton(action: SuggestedAction) { function mapActionToButton(action: SuggestedAction) {
switch (action.id) { switch (action.id) {
case "summarize-in-new-chat": case "summarize-in-new-chat":
return <SummarizeInNewChatButton />; return <SummarizeInNewChatButton />;
case "refactor-file":
return <RefactorFileButton path={action.path} />;
default: default:
console.error(`Unsupported action: ${action.id}`); console.error(`Unsupported action: ${action.id}`);
return ( return (

View File

@@ -224,6 +224,23 @@ const getProposalHandler = async (
); );
} }
} }
const actions: ActionProposal["actions"] = [];
if (latestAssistantMessage?.content) {
const writeTags = getDyadWriteTags(latestAssistantMessage.content);
const refactorTarget = writeTags.reduce((largest, tag) => {
const lineCount = tag.content.split("\n").length;
return lineCount > 500 && (!largest || lineCount > largest.lineCount)
? { path: tag.path, lineCount }
: largest;
}, null as { path: string; lineCount: number } | null);
if (refactorTarget) {
actions.push({
id: "refactor-file",
path: refactorTarget.path,
});
}
}
// Get all chat messages to calculate token usage // Get all chat messages to calculate token usage
const chat = await db.query.chats.findFirst({ const chat = await db.query.chats.findFirst({
where: eq(chats.id, chatId), where: eq(chats.id, chatId),
@@ -260,16 +277,21 @@ const getProposalHandler = async (
logger.log( logger.log(
`Token usage high (${totalTokens}/${contextWindow}), suggesting summarize action` `Token usage high (${totalTokens}/${contextWindow}), suggesting summarize action`
); );
return { actions.push({
proposal: { id: "summarize-in-new-chat",
type: "action-proposal", });
actions: [{ id: "summarize-in-new-chat" }],
},
chatId,
messageId: latestAssistantMessage.id,
};
} }
} }
if (actions.length > 0 && latestAssistantMessage) {
return {
proposal: {
type: "action-proposal",
actions: actions,
},
chatId,
messageId: latestAssistantMessage.id,
};
}
return null; return null;
} catch (error) { } catch (error) {
logger.error(`Error processing proposal for chatId ${chatId}:`, error); logger.error(`Error processing proposal for chatId ${chatId}:`, error);

View File

@@ -155,8 +155,22 @@ export interface CodeProposal {
sqlQueries: SqlQuery[]; sqlQueries: SqlQuery[];
} }
export interface SuggestedAction { export type SuggestedAction =
id: "restart-app" | "summarize-in-new-chat"; | RestartAppAction
| SummarizeInNewChatAction
| RefactorFileAction;
export interface RestartAppAction {
id: "restart-app";
}
export interface SummarizeInNewChatAction {
id: "summarize-in-new-chat";
}
export interface RefactorFileAction {
id: "refactor-file";
path: string;
} }
export interface ActionProposal { export interface ActionProposal {

View File

@@ -29,7 +29,7 @@ If new code needs to be written (i.e., the requested feature does not exist), yo
- If the user asks for multiple packages, use <dyad-add-dependency packages="package1 package2 package3"></dyad-add-dependency> - If the user asks for multiple packages, use <dyad-add-dependency packages="package1 package2 package3"></dyad-add-dependency>
- MAKE SURE YOU USE SPACES BETWEEN PACKAGES AND NOT COMMAS. - MAKE SURE YOU USE SPACES BETWEEN PACKAGES AND NOT COMMAS.
- Look carefully at all imports and ensure the files you're importing are present. If any packages need to be installed, use <dyad-add-dependency>. - Look carefully at all imports and ensure the files you're importing are present. If any packages need to be installed, use <dyad-add-dependency>.
- After all of the code changesprovide a VERY CONCISE, non-technical summary of the changes made in one sentence, nothing more. This summary should be easy for non-technical users to understand. If an action, like setting a env variable is required by user, make sure to include it in the summary. - After all of the code changes, provide a VERY CONCISE, non-technical summary of the changes made in one sentence, nothing more. This summary should be easy for non-technical users to understand. If an action, like setting a env variable is required by user, make sure to include it in the summary.
Important Notes: Important Notes:
@@ -236,7 +236,7 @@ If a user asks for many features at once, you do not have to implement them all
Immediate Component Creation Immediate Component Creation
You MUST create a new file for every new component or hook, no matter how small. You MUST create a new file for every new component or hook, no matter how small.
Never add new components to existing files, even if they seem related. Never add new components to existing files, even if they seem related.
Aim for components that are 50 lines of code or less. Aim for components that are 100 lines of code or less.
Continuously be ready to refactor files that are getting too large. When they get too large, ask the user if they want you to refactor them. Continuously be ready to refactor files that are getting too large. When they get too large, ask the user if they want you to refactor them.
Important Rules for dyad-write operations: Important Rules for dyad-write operations: