fix(antigravity): support uploaded_file attachments in prompt encoding

This commit is contained in:
ax
2026-11-01 06:07:46 +00:00
committed by paseo-bot[bot]
parent 6ae6308cfb
commit 7b53464b0d
2 changed files with 77 additions and 8 deletions
@@ -1,5 +1,5 @@
import { randomUUID } from "node:crypto";
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
import { chmod, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import type { ProviderPrompt } from "@getpaseo/plugin/server/provider";
@@ -10,6 +10,8 @@ interface EncodedPrompt {
nativeText: string;
}
const MAX_INLINE_FILE_BYTES = 2 * 1024 * 1024; // 2 MB
export class PromptFiles {
private directory: string | null = null;
@@ -20,19 +22,16 @@ export class PromptFiles {
prompt.outputSchema !== undefined
)
throw new AntigravityError("Antigravity supports messages only");
const parts = prompt.input.content.map((part) => {
if (part.type === "text") return part;
if (part.type === "image") return { ...part, extension: imageExtension(part.mimeType) };
throw new AntigravityError("Antigravity supports text and image content only");
});
const text: string[] = [];
const native: string[] = [];
for (const part of parts) {
for (const part of prompt.input.content) {
if (part.type === "text") {
text.push(part.text);
native.push(part.text);
} else if (part.type === "image") {
const extension = part.extension;
const extension = imageExtension(part.mimeType);
if (this.directory === null) {
this.directory = await mkdtemp(path.join(os.tmpdir(), "paseo-antigravity-images-"));
await chmod(this.directory, 0o700);
@@ -41,8 +40,32 @@ export class PromptFiles {
await writeFile(file, Buffer.from(part.data, "base64"), { flag: "wx", mode: 0o600 });
await chmod(file, 0o600);
native.push(`Attached image: ${file}`);
} else if (part.type === "uploaded_file") {
if (part.mimeType && part.mimeType.startsWith("image/")) {
native.push(`Attached image: ${part.path}`);
} else if (part.size > MAX_INLINE_FILE_BYTES) {
const notice = `[Attached large file: ${part.fileName} at ${part.path} (${part.size} bytes)]`;
text.push(notice);
native.push(notice);
} else {
try {
const content = await readFile(part.path, "utf8");
const fileBlock = `[File: ${part.fileName}]\n${content}`;
text.push(fileBlock);
native.push(fileBlock);
} catch {
const notice = `[Attached file: ${part.fileName} at ${part.path}]`;
text.push(notice);
native.push(notice);
}
}
} else {
throw new AntigravityError(
`Antigravity does not support content type: ${(part as { type?: string }).type ?? "unknown"}`,
);
}
}
return { text: text.join("\n"), nativeText: native.join("\n") };
}
@@ -774,6 +774,52 @@ describe("image prompts", () => {
});
});
describe("uploaded file prompts", () => {
it("inlines readable text files and references uploaded images and large files", async () => {
const h = await harness();
await h.open();
const txtFile = path.join(h.cwd, "notes.txt");
await writeFile(txtFile, "export const meaning = 42;");
const imgFile = path.join(h.cwd, "photo.png");
await writeFile(imgFile, "png bytes");
await h.completed(
await h.message([
{ type: "text", text: "Please review these attachments:" },
{
type: "uploaded_file",
id: "upload-txt-1",
fileName: "notes.txt",
mimeType: "text/plain",
size: 26,
path: txtFile,
},
{
type: "uploaded_file",
id: "upload-img-1",
fileName: "photo.png",
mimeType: "image/png",
size: 9,
path: imgFile,
},
{
type: "uploaded_file",
id: "upload-big-1",
fileName: "dataset.bin",
mimeType: "application/octet-stream",
size: 3 * 1024 * 1024,
path: "/tmp/dataset.bin",
},
]),
);
const sent = (await h.records()).find((entry) => entry.input).input.message.content;
expect(sent).toBe(
`SYSTEM PREFIX\n\nPlease review these attachments:\n[File: notes.txt]\nexport const meaning = 42;\nAttached image: ${imgFile}\n[Attached large file: dataset.bin at /tmp/dataset.bin (3145728 bytes)]`,
);
});
});
it.runIf(process.platform === "win32")(
"launches an Antigravity command shim for probes and conversation startup",
async () => {