48```
49
50### Images
51
52```
53
54```
55
67- Implement categories in addition to tags
68- Add search functionality
69- Support for images in blog posts
70- RSS feed generation
57```
58
59## Images
60
61```markdown
62
63
64```
65
29 - [x] File write as a code embed
30 - [x] str_replace as a diff view
31- [x] make image drop area invisible and bigger
32- [x] Give it all the code (except maybe .txt files) as initial context (like cursor sonnet max)
33- [x] I seem to have lost the delete file tool and instructions, try to find them back in history or re-create?
55- [x] Create branch
56- [x] URL input + pathname
57- [x] Image upload controls
58- [x] Preview refresh button
59- [x] Audio controls
1
2export const PROMPT_IMAGE_LIMIT = 5;
3
4export const processFiles = async (files: File[], images: (string | null)[], setImages: (images: (string | null)[]) => void) => {
5 const imageFiles = files.filter(file => file.type.startsWith('image/'));
6 const filesToProcess = imageFiles.slice(0, PROMPT_IMAGE_LIMIT - images.filter(Boolean).length);
7
8 if (filesToProcess.length === 0) return;
9
10 const newImages = [...images, ...Array(filesToProcess.length).fill(null)];
11 setImages(newImages);
12
13 const processedImages = await Promise.all(
14 filesToProcess.map(async (file) => {
15 return await readFileAsDataURL(file);
17 );
18
19 const updatedImages = [...images];
20 processedImages.forEach((dataUrl, index) => {
21 updatedImages[images.length + index] = dataUrl;
22 });
23
24 setImages(updatedImages.slice(0, PROMPT_IMAGE_LIMIT));
25};
26
30 reader.onload = () => {
31 const result = reader.result as string;
32 console.log("Image loaded, size:", result.length, "bytes");
33 resolve(result);
34 };
9 bearerToken: string;
10 selectedFiles: string[];
11 images: (string | null)[];
12 soundEnabled: boolean;
13}
19 bearerToken,
20 selectedFiles,
21 images,
22 soundEnabled,
23}: UseChatLogicProps) {
43 anthropicApiKey,
44 selectedFiles,
45 images: images
46 .filter((img): img is string => {
47 const isValid = typeof img === "string" && img.startsWith("data:");
48 if (!isValid && img !== null) {
49 console.warn("Invalid image format:", img?.substring(0, 50) + "...");
50 }
51 return isValid;
29 - [x] File write as a code embed
30 - [x] str_replace as a diff view
31- [x] make image drop area invisible and bigger
32- [x] Give it all the code (except maybe .txt files) as initial context (like cursor sonnet max)
33- [x] I seem to have lost the delete file tool and instructions, try to find them back in history or re-create?
55- [x] Create branch
56- [x] URL input + pathname
57- [x] Image upload controls
58- [x] Preview refresh button
59- [x] Audio controls
172
173- **Redirects:** Use `return new Response(null, { status: 302, headers: { Location: "/place/to/redirect" }})` instead of `Response.redirect` which is broken
174- **Images:** Avoid external images or base64 images. Use emojis, unicode symbols, or icon fonts/libraries instead
175- **AI Image:** To inline generate an AI image use: `<img src="https://maxm-imggenurl.web.val.run/the-description-of-your-image" />`
176- **Storage:** DO NOT use the Deno KV module for storage
177- **Browser APIs:** DO NOT use the `alert()`, `prompt()`, or `confirm()` methods
682 background-color: var(--highlight);
683}
684.card-image {
685 display: flex;
686 align-items: center;
704}
705
706.image-placeholder,
707.image-thumbnail {
708 width: 40px;
709 height: 40px;
711 object-fit: cover;
712}
713.image-placeholder {
714 background-color: var(--muted);
715}
722}
723
724.image-row {
725 display: flex;
726 gap: var(--space-1);
727}
728.input-image {
729 position: relative;
730 border: 1px solid var(--muted);
731 border-radius: 6px;
732}
733.remove-image-button {
734 position: absolute;
735 top: 0;
744 opacity: 0;
745}
746.input-image:hover .remove-image-button {
747 opacity: 1;
748}
749
750.image-drop-overlay {
751 position: fixed;
752 top: 0;
761 justify-content: center;
762}
763.image-drop-inner {
764 padding: var(--space-2);
765 background-color: var(--background);
766}
767
768.transition, .input-box, .icon-button, .button, .remove-image-button {
769 transition-property: color, background-color, border-color, opacity;
770 transition-duration: 200ms;
19 }
20
21 const { messages, project, branchId, anthropicApiKey, selectedFiles, images } = await c.req.json();
22 console.log("Original messages:", JSON.stringify(messages, null, 2));
23 console.log("Images received:", JSON.stringify(images, null, 2));
24
25 // Check if API key is available
47 let coreMessages = convertToCoreMessages(messages);
48
49 // If there are images, we need to add them to the last user message
50 if (images && Array.isArray(images) && images.length > 0) {
51 // Find the last user message
52 const lastUserMessageIndex = coreMessages.findIndex(
70 };
71
72 // Add each image to the content array using the correct ImagePart format
73 for (const image of images) {
74 if (image && image.url) {
75 // Extract mime type from data URL if available
76 let mimeType = undefined;
77 if (image.url.startsWith("data:")) {
78 const matches = image.url.match(/^data:([^;]+);/);
79 if (matches && matches.length > 1) {
80 mimeType = matches[1];
83
84 newUserMessage.content.push({
85 type: "image",
86 image: image.url,
87 mimeType,
88 });