Skip to content

Commit 20a5934

Browse files
7418claude
andcommitted
fix: persist image generation results to DB for reload survival, bump v0.17.2
Root cause: after image generation, the message content in DB stayed as `image-gen-request` (the options form). On app restart, MessageItem re-parsed this as a generation form instead of showing the completed result. The result only lived in React state and localStorage. Fix: - db.ts: add updateMessageContent() to update a message's content by ID - /api/chat/messages: add PUT handler for message content updates - ImageGenConfirmation: accept messageId prop; on successful generation, replace message content from image-gen-request to image-gen-result format (with localPath references) via PUT API call - MessageItem: pass message.id to ImageGenConfirmation Now on restart, parseImageGenResult() matches the persisted image-gen-result block and renders ImageGenCard directly with the saved image paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fd03d17 commit 20a5934

File tree

6 files changed

+62
-4
lines changed

6 files changed

+62
-4
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codepilot",
3-
"version": "0.17.1",
3+
"version": "0.17.2",
44
"private": true,
55
"author": {
66
"name": "op7418",

src/app/api/chat/messages/route.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { NextRequest, NextResponse } from 'next/server';
2-
import { addMessage, getSession } from '@/lib/db';
2+
import { addMessage, updateMessageContent, getSession } from '@/lib/db';
33

44
export const runtime = 'nodejs';
55

@@ -37,3 +37,31 @@ export async function POST(request: NextRequest) {
3737
return NextResponse.json({ error: msg }, { status: 500 });
3838
}
3939
}
40+
41+
/**
42+
* PUT /api/chat/messages
43+
* Update the content of an existing message.
44+
* Used to replace image-gen-request with image-gen-result after generation.
45+
*/
46+
export async function PUT(request: NextRequest) {
47+
try {
48+
const body = await request.json();
49+
const { message_id, content } = body as {
50+
message_id: string;
51+
content: string;
52+
};
53+
54+
if (!message_id || !content) {
55+
return NextResponse.json(
56+
{ error: 'message_id and content are required' },
57+
{ status: 400 },
58+
);
59+
}
60+
61+
updateMessageContent(message_id, content);
62+
return NextResponse.json({ ok: true });
63+
} catch (error) {
64+
const msg = error instanceof Error ? error.message : 'Failed to update message';
65+
return NextResponse.json({ error: msg }, { status: 500 });
66+
}
67+
}

src/components/chat/ImageGenConfirmation.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const ASPECT_RATIOS = [
1717
const RESOLUTIONS = ['1K', '2K', '4K'] as const;
1818

1919
interface ImageGenConfirmationProps {
20+
messageId?: string;
2021
initialPrompt: string;
2122
initialAspectRatio: string;
2223
initialResolution: string;
@@ -32,6 +33,7 @@ function storageKey(prompt: string, sessionId?: string): string {
3233
}
3334

3435
export function ImageGenConfirmation({
36+
messageId,
3537
initialPrompt,
3638
initialAspectRatio,
3739
initialResolution,
@@ -140,6 +142,28 @@ export function ImageGenConfirmation({
140142
// storage full
141143
}
142144

145+
// Persist result to DB by replacing image-gen-request with image-gen-result
146+
if (messageId) {
147+
const resultBlock = JSON.stringify({
148+
status: 'completed',
149+
prompt,
150+
aspectRatio,
151+
resolution,
152+
images: genResult.images.map(img => ({
153+
mimeType: img.mimeType,
154+
localPath: img.localPath,
155+
})),
156+
});
157+
fetch('/api/chat/messages', {
158+
method: 'PUT',
159+
headers: { 'Content-Type': 'application/json' },
160+
body: JSON.stringify({
161+
message_id: messageId,
162+
content: '```image-gen-result\n' + resultBlock + '\n```',
163+
}),
164+
}).catch(() => {});
165+
}
166+
143167
// Defer event dispatch so React commits setResult/setStatus before
144168
// ChatView's handler calls sendMessage and triggers a re-render
145169
setTimeout(() => {

src/components/chat/MessageItem.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ export function MessageItem({ message }: MessageItemProps) {
491491
<>
492492
{parsed.beforeText && <MessageResponse>{parsed.beforeText}</MessageResponse>}
493493
<ImageGenConfirmation
494+
messageId={message.id}
494495
initialPrompt={parsed.request.prompt}
495496
initialAspectRatio={parsed.request.aspectRatio}
496497
initialResolution={parsed.request.resolution}

src/lib/db.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,11 @@ export function addMessage(
565565
return db.prepare('SELECT * FROM messages WHERE id = ?').get(id) as Message;
566566
}
567567

568+
export function updateMessageContent(messageId: string, content: string): void {
569+
const db = getDb();
570+
db.prepare('UPDATE messages SET content = ? WHERE id = ?').run(content, messageId);
571+
}
572+
568573
export function clearSessionMessages(sessionId: string): void {
569574
const db = getDb();
570575
db.prepare('DELETE FROM messages WHERE session_id = ?').run(sessionId);

0 commit comments

Comments
 (0)