move image description to debug message

This commit is contained in:
arkml 2025-09-19 18:28:00 +05:30
parent 527afff601
commit b5f5301761
2 changed files with 64 additions and 15 deletions

View file

@ -152,11 +152,24 @@ export function Chat({
} }
}, []); }, []);
function handleUserMessage(prompt: string) { function handleUserMessage(prompt: string, imageDebug?: { url: string; description?: string | null }) {
const updatedMessages: z.infer<typeof Message>[] = [...messages, { // Insert an internal-only debug message with image URL/markdown (if provided),
role: 'user', // then the actual user message last so streaming triggers correctly.
content: prompt, const debugMessages: z.infer<typeof Message>[] = imageDebug ? [{
}]; role: 'assistant',
content: `Image Description\n\nURL: ${imageDebug.url}\n\n${imageDebug.description ? imageDebug.description : ''}`.trim(),
agentName: 'Image Description',
responseType: 'internal',
} as any] : [];
const updatedMessages: z.infer<typeof Message>[] = [
...messages,
...debugMessages,
{
role: 'user',
content: prompt,
} as any,
];
setMessages(updatedMessages); setMessages(updatedMessages);
setError(null); setError(null);
setIsLastInteracted(true); setIsLastInteracted(true);
@ -229,9 +242,46 @@ export function Chat({
} }
// set up a cached turn // set up a cached turn
// Merge-at-send: if the immediately preceding message is our internal
// Image Description debug message, append its details (URL/markdown)
// to the outgoing user message content, without changing the UI.
const last = messages[messages.length - 1];
let mergedContent = (typeof last?.content === 'string' ? last.content : '') || '';
if (messages.length >= 2) {
const prev = messages[messages.length - 2] as any;
const isImageDebug = prev && prev.role === 'assistant' && prev.responseType === 'internal' && prev.agentName === 'Image Description' && typeof prev.content === 'string';
if (isImageDebug) {
// Expect prev.content to have: "Image Description\n\nURL: <url>\n\n<markdown>"
// Extract URL and markdown blocks for a clean append
const content = prev.content as string;
let url: string | undefined;
let markdown: string | undefined;
const urlMatch = content.match(/URL:\s*(\S+)/i);
if (urlMatch) url = urlMatch[1];
// markdown is whatever comes after the blank line following URL
const parts = content.split(/\n\n/);
if (parts.length >= 3) {
markdown = parts.slice(2).join('\n\n').trim();
}
const appendSections: string[] = [];
if (url) appendSections.push(`The user uploaded an image. URL: ${url}`);
if (markdown) appendSections.push(`Image description (markdown):\n\n${markdown}`);
if (appendSections.length > 0) {
mergedContent = [mergedContent, appendSections.join('\n\n')]
.filter(Boolean)
.join('\n\n');
}
}
}
const messagesToSend: z.infer<typeof Message>[] = [{
role: 'user',
content: mergedContent,
} as any];
const response = await createCachedTurn({ const response = await createCachedTurn({
conversationId: conversationId.current, conversationId: conversationId.current,
messages: messages.slice(-1), // only send the last message messages: messagesToSend, // send merged content only
}); });
if (ignore) { if (ignore) {
return; return;
@ -500,4 +550,4 @@ export function Chat({
/> />
</div> </div>
); );
} }

View file

@ -3,7 +3,7 @@ import { Textarea } from '@/components/ui/textarea';
import { Button, Spinner } from "@heroui/react"; import { Button, Spinner } from "@heroui/react";
interface ComposeBoxPlaygroundProps { interface ComposeBoxPlaygroundProps {
handleUserMessage: (message: string) => void; handleUserMessage: (message: string, imageDebug?: { url: string; description?: string | null }) => void;
messages: any[]; messages: any[];
loading: boolean; loading: boolean;
disabled?: boolean; disabled?: boolean;
@ -41,21 +41,20 @@ export function ComposeBoxPlayground({
if (!text && !pendingImage) { if (!text && !pendingImage) {
return; return;
} }
// Only include the user's typed text; omit image URL/markdown from user message
const parts: string[] = []; const parts: string[] = [];
if (text) parts.push(text); if (text) parts.push(text);
if (pendingImage?.url) {
parts.push(`The user uploaded an image. URL: ${pendingImage.url}`);
if (pendingImage.description) {
parts.push(`Image description (markdown):\n\n${pendingImage.description}`);
}
}
const prompt = parts.join('\n\n'); const prompt = parts.join('\n\n');
// Build optional debug payload to render as internal-only message in debug view
const imageDebug = pendingImage?.url
? { url: pendingImage.url, description: pendingImage.description ?? null }
: undefined;
setInput(''); setInput('');
if (pendingImage?.previewSrc) { if (pendingImage?.previewSrc) {
try { URL.revokeObjectURL(pendingImage.previewSrc); } catch {} try { URL.revokeObjectURL(pendingImage.previewSrc); } catch {}
} }
setPendingImage(null); setPendingImage(null);
handleUserMessage(prompt); handleUserMessage(prompt, imageDebug);
} }
const handleInputKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { const handleInputKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {