| author | |
| committer | |
| log | 2a33a18716854b8d07378008cf3101ad999209ae |
| tree | 90ac69468b735187863c075bf415cec620dc75c5 |
| parent | bde0a4c0dd2d420a5fd71f39448d5db1bab078da |
| signature | Signed by PGP key B5690EEEBB952194 |
4 files changed, 48 insertions(+), 4 deletions(-)
apps/mobile/src/lib/composerImages.test.ts+31-1| ... | ... | @@ -36,7 +36,37 @@ vi.mock("./uuid", () => ({ |
| 36 | 36 | uuidv4: () => "attachment-id", |
| 37 | 37 | })); |
| 38 | 38 | |
| 39 | import { convertPastedImagesToAttachments, isOwnedPastedImageUri } from "./composerImages"; | |
| 39 | import { | |
| 40 | convertPastedImagesToAttachments, | |
| 41 | isOwnedPastedImageUri, | |
| 42 | toUploadChatImageAttachments, | |
| 43 | } from "./composerImages"; | |
| 44 | ||
| 45 | describe("toUploadChatImageAttachments", () => { | |
| 46 | it("strips client draft id and previewUri for the startTurn wire shape", () => { | |
| 47 | expect( | |
| 48 | toUploadChatImageAttachments([ | |
| 49 | { | |
| 50 | id: "client-draft-id", | |
| 51 | type: "image", | |
| 52 | name: "pasted-image.png", | |
| 53 | mimeType: "image/png", | |
| 54 | sizeBytes: 12, | |
| 55 | dataUrl: "data:image/png;base64,AA==", | |
| 56 | previewUri: "file:///tmp/preview.png", | |
| 57 | }, | |
| 58 | ]), | |
| 59 | ).toEqual([ | |
| 60 | { | |
| 61 | type: "image", | |
| 62 | name: "pasted-image.png", | |
| 63 | mimeType: "image/png", | |
| 64 | sizeBytes: 12, | |
| 65 | dataUrl: "data:image/png;base64,AA==", | |
| 66 | }, | |
| 67 | ]); | |
| 68 | }); | |
| 69 | }); | |
| 40 | 70 | |
| 41 | 71 | describe("native pasted image cleanup", () => { |
| 42 | 72 | beforeEach(() => { |
apps/mobile/src/lib/composerImages.ts+13| ... | ... | @@ -10,6 +10,19 @@ export interface DraftComposerImageAttachment extends UploadChatImageAttachment |
| 10 | 10 | readonly previewUri: string; |
| 11 | 11 | } |
| 12 | 12 | |
| 13 | /** Wire shape for startTurn: pure uploads without client draft id / previewUri. */ | |
| 14 | export function toUploadChatImageAttachments( | |
| 15 | attachments: ReadonlyArray<DraftComposerImageAttachment>, | |
| 16 | ): ReadonlyArray<UploadChatImageAttachment> { | |
| 17 | return attachments.map((attachment) => ({ | |
| 18 | type: attachment.type, | |
| 19 | name: attachment.name, | |
| 20 | mimeType: attachment.mimeType, | |
| 21 | sizeBytes: attachment.sizeBytes, | |
| 22 | dataUrl: attachment.dataUrl, | |
| 23 | })); | |
| 24 | } | |
| 25 | ||
| 13 | 26 | const OWNED_PASTED_IMAGE_DIRECTORY = "t3-composer-paste"; |
| 14 | 27 | |
| 15 | 28 | function estimateBase64ByteSize(base64: string): number { |
apps/mobile/src/lib/projectThreadStartTurn.ts+2-2| ... | ... | @@ -8,7 +8,7 @@ import { |
| 8 | 8 | type RuntimeMode, |
| 9 | 9 | } from "@t3tools/contracts"; |
| 10 | 10 | |
| 11 | import type { DraftComposerImageAttachment } from "./composerImages"; | |
| 11 | import { toUploadChatImageAttachments, type DraftComposerImageAttachment } from "./composerImages"; | |
| 12 | 12 | |
| 13 | 13 | export function deriveThreadTitleFromPrompt(value: string): string { |
| 14 | 14 | const trimmed = value.trim(); |
| ... | ... | @@ -55,7 +55,7 @@ export function buildProjectThreadStartTurnInput(spec: ProjectThreadStartTurnSpe |
| 55 | 55 | messageId: MessageId.make(spec.messageId), |
| 56 | 56 | role: "user" as const, |
| 57 | 57 | text: spec.text, |
| 58 | attachments: spec.attachments, | |
| 58 | attachments: toUploadChatImageAttachments(spec.attachments), | |
| 59 | 59 | }, |
| 60 | 60 | modelSelection: spec.modelSelection, |
| 61 | 61 | titleSeed: title, |
apps/mobile/src/state/use-thread-outbox-drain.ts+2-1| ... | ... | @@ -17,6 +17,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; |
| 17 | 17 | |
| 18 | 18 | import { scopedThreadKey } from "../lib/scopedEntities"; |
| 19 | 19 | import { buildProjectThreadStartTurnInput } from "../lib/projectThreadStartTurn"; |
| 20 | import { toUploadChatImageAttachments } from "../lib/composerImages"; | |
| 20 | 21 | import { randomHex } from "../lib/uuid"; |
| 21 | 22 | import { appAtomRegistry } from "./atom-registry"; |
| 22 | 23 | import { useProjects, useThreadShells } from "./entities"; |
| ... | ... | @@ -221,7 +222,7 @@ export function useThreadOutboxDrain(): void { |
| 221 | 222 | messageId: queuedMessage.messageId, |
| 222 | 223 | role: "user", |
| 223 | 224 | text: queuedMessage.text, |
| 224 | attachments: queuedMessage.attachments, | |
| 225 | attachments: toUploadChatImageAttachments(queuedMessage.attachments), | |
| 225 | 226 | }, |
| 226 | 227 | modelSelection: settings.modelSelection, |
| 227 | 228 | runtimeMode: settings.runtimeMode, |