Refresh proposal & loaders for proposal action
This commit is contained in:
@@ -2,12 +2,13 @@ import { ipcMain, type IpcMainInvokeEvent } from "electron";
|
||||
import type { Proposal } from "@/lib/schemas";
|
||||
import { db } from "../../db";
|
||||
import { messages } from "../../db/schema";
|
||||
import { desc, eq, and } from "drizzle-orm";
|
||||
import { desc, eq, and, Update } from "drizzle-orm";
|
||||
import path from "node:path"; // Import path for basename
|
||||
// Import tag parsers
|
||||
import {
|
||||
getDyadChatSummaryTag,
|
||||
getDyadWriteTags,
|
||||
processFullResponseActions,
|
||||
} from "../processors/response_processor";
|
||||
|
||||
// Placeholder Proposal data (can be removed or kept for reference)
|
||||
@@ -19,6 +20,12 @@ interface ParsedProposal {
|
||||
files: string[];
|
||||
}
|
||||
|
||||
// Define return type for getProposalHandler
|
||||
interface ProposalResult {
|
||||
proposal: Proposal;
|
||||
messageId: number;
|
||||
}
|
||||
|
||||
function isParsedProposal(obj: any): obj is ParsedProposal {
|
||||
return (
|
||||
obj &&
|
||||
@@ -32,7 +39,7 @@ function isParsedProposal(obj: any): obj is ParsedProposal {
|
||||
const getProposalHandler = async (
|
||||
_event: IpcMainInvokeEvent,
|
||||
{ chatId }: { chatId: number }
|
||||
): Promise<Proposal | null> => {
|
||||
): Promise<ProposalResult | null> => {
|
||||
console.log(`IPC: get-proposal called for chatId: ${chatId}`);
|
||||
|
||||
try {
|
||||
@@ -41,12 +48,16 @@ const getProposalHandler = async (
|
||||
where: and(eq(messages.chatId, chatId), eq(messages.role, "assistant")),
|
||||
orderBy: [desc(messages.createdAt)],
|
||||
columns: {
|
||||
id: true, // Fetch the ID
|
||||
content: true, // Fetch the content to parse
|
||||
},
|
||||
});
|
||||
|
||||
if (latestAssistantMessage?.content) {
|
||||
console.log("Found latest assistant message, parsing content...");
|
||||
if (latestAssistantMessage?.content && latestAssistantMessage.id) {
|
||||
const messageId = latestAssistantMessage.id; // Get the message ID
|
||||
console.log(
|
||||
`Found latest assistant message (ID: ${messageId}), parsing content...`
|
||||
);
|
||||
const messageContent = latestAssistantMessage.content;
|
||||
|
||||
// Parse tags directly from message content
|
||||
@@ -66,7 +77,7 @@ const getProposalHandler = async (
|
||||
})),
|
||||
};
|
||||
console.log("Generated proposal on the fly:", proposal);
|
||||
return proposal;
|
||||
return { proposal, messageId }; // Return proposal and messageId
|
||||
} else {
|
||||
console.log(
|
||||
"No relevant tags found in the latest assistant message content."
|
||||
@@ -83,8 +94,127 @@ const getProposalHandler = async (
|
||||
}
|
||||
};
|
||||
|
||||
// Handler to approve a proposal (process actions and update message)
|
||||
const approveProposalHandler = async (
|
||||
_event: IpcMainInvokeEvent,
|
||||
{ chatId, messageId }: { chatId: number; messageId: number }
|
||||
): Promise<{ success: boolean; error?: string }> => {
|
||||
console.log(
|
||||
`IPC: approve-proposal called for chatId: ${chatId}, messageId: ${messageId}`
|
||||
);
|
||||
|
||||
try {
|
||||
// 1. Fetch the specific assistant message
|
||||
const messageToApprove = await db.query.messages.findFirst({
|
||||
where: and(
|
||||
eq(messages.id, messageId),
|
||||
eq(messages.chatId, chatId),
|
||||
eq(messages.role, "assistant")
|
||||
),
|
||||
columns: {
|
||||
content: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!messageToApprove?.content) {
|
||||
console.error(
|
||||
`Assistant message not found for chatId: ${chatId}, messageId: ${messageId}`
|
||||
);
|
||||
return { success: false, error: "Assistant message not found." };
|
||||
}
|
||||
|
||||
// 2. Process the actions defined in the message content
|
||||
const chatSummary = getDyadChatSummaryTag(messageToApprove.content);
|
||||
const processResult = await processFullResponseActions(
|
||||
messageToApprove.content,
|
||||
chatId,
|
||||
{ chatSummary: chatSummary ?? undefined } // Pass summary if found
|
||||
);
|
||||
|
||||
if (processResult.error) {
|
||||
console.error(
|
||||
`Error processing actions for message ${messageId}:`,
|
||||
processResult.error
|
||||
);
|
||||
// Optionally: Update message state to 'error' or similar?
|
||||
// For now, just return error to frontend
|
||||
return {
|
||||
success: false,
|
||||
error: `Action processing failed: ${processResult.error}`,
|
||||
};
|
||||
}
|
||||
|
||||
// 3. Update the message's approval state to 'approved'
|
||||
await db
|
||||
.update(messages)
|
||||
.set({ approvalState: "approved" })
|
||||
.where(eq(messages.id, messageId));
|
||||
|
||||
console.log(`Message ${messageId} marked as approved.`);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Error approving proposal for messageId ${messageId}:`,
|
||||
error
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
error: (error as Error)?.message || "Unknown error",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Handler to reject a proposal (just update message state)
|
||||
const rejectProposalHandler = async (
|
||||
_event: IpcMainInvokeEvent,
|
||||
{ chatId, messageId }: { chatId: number; messageId: number }
|
||||
): Promise<{ success: boolean; error?: string }> => {
|
||||
console.log(
|
||||
`IPC: reject-proposal called for chatId: ${chatId}, messageId: ${messageId}`
|
||||
);
|
||||
|
||||
try {
|
||||
// 1. Verify the message exists and is an assistant message
|
||||
const messageToReject = await db.query.messages.findFirst({
|
||||
where: and(
|
||||
eq(messages.id, messageId),
|
||||
eq(messages.chatId, chatId),
|
||||
eq(messages.role, "assistant")
|
||||
),
|
||||
columns: { id: true }, // Only need to confirm existence
|
||||
});
|
||||
|
||||
if (!messageToReject) {
|
||||
console.error(
|
||||
`Assistant message not found for chatId: ${chatId}, messageId: ${messageId}`
|
||||
);
|
||||
return { success: false, error: "Assistant message not found." };
|
||||
}
|
||||
|
||||
// 2. Update the message's approval state to 'rejected'
|
||||
await db
|
||||
.update(messages)
|
||||
.set({ approvalState: "rejected" })
|
||||
.where(eq(messages.id, messageId));
|
||||
|
||||
console.log(`Message ${messageId} marked as rejected.`);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Error rejecting proposal for messageId ${messageId}:`,
|
||||
error
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
error: (error as Error)?.message || "Unknown error",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Function to register proposal-related handlers
|
||||
export function registerProposalHandlers() {
|
||||
ipcMain.handle("get-proposal", getProposalHandler);
|
||||
console.log("Registered proposal IPC handlers");
|
||||
ipcMain.handle("approve-proposal", approveProposalHandler);
|
||||
ipcMain.handle("reject-proposal", rejectProposalHandler);
|
||||
console.log("Registered proposal IPC handlers (get, approve, reject)");
|
||||
}
|
||||
|
||||
@@ -20,6 +20,12 @@ import type {
|
||||
import type { Proposal } from "@/lib/schemas";
|
||||
import { showError } from "@/lib/toast";
|
||||
|
||||
// Define the structure returned by getProposal
|
||||
interface ProposalResult {
|
||||
proposal: Proposal;
|
||||
messageId: number;
|
||||
}
|
||||
|
||||
export interface ChatStreamCallbacks {
|
||||
onUpdate: (messages: Message[]) => void;
|
||||
onEnd: (response: ChatResponseEnd) => void;
|
||||
@@ -616,11 +622,12 @@ export class IpcClient {
|
||||
}
|
||||
|
||||
// Get proposal details
|
||||
public async getProposal(chatId: number): Promise<Proposal> {
|
||||
public async getProposal(chatId: number): Promise<ProposalResult | null> {
|
||||
try {
|
||||
const data = await this.ipcRenderer.invoke("get-proposal", { chatId });
|
||||
// Assuming the main process returns data matching the Proposal interface
|
||||
return data as Proposal;
|
||||
// Assuming the main process returns data matching the ProposalResult interface
|
||||
// Add a type check/guard if necessary for robustness
|
||||
return data as ProposalResult | null;
|
||||
} catch (error) {
|
||||
showError(error);
|
||||
throw error;
|
||||
@@ -629,4 +636,44 @@ export class IpcClient {
|
||||
|
||||
// Example methods for listening to events (if needed)
|
||||
// public on(channel: string, func: (...args: any[]) => void): void {
|
||||
|
||||
// --- Proposal Management ---
|
||||
public async approveProposal({
|
||||
chatId,
|
||||
messageId,
|
||||
}: {
|
||||
chatId: number;
|
||||
messageId: number;
|
||||
}): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const result = await this.ipcRenderer.invoke("approve-proposal", {
|
||||
chatId,
|
||||
messageId,
|
||||
});
|
||||
return result as { success: boolean; error?: string };
|
||||
} catch (error) {
|
||||
showError(error);
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
}
|
||||
|
||||
public async rejectProposal({
|
||||
chatId,
|
||||
messageId,
|
||||
}: {
|
||||
chatId: number;
|
||||
messageId: number;
|
||||
}): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const result = await this.ipcRenderer.invoke("reject-proposal", {
|
||||
chatId,
|
||||
messageId,
|
||||
});
|
||||
return result as { success: boolean; error?: string };
|
||||
} catch (error) {
|
||||
showError(error);
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
}
|
||||
// --- End Proposal Management ---
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user