Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289import assert from "node:assert/strict";import { test } from "node:test";import { resolve } from "node:path";import { build } from "esbuild";import { Miniflare, convertV4MiniflareOptions } from "miniflare";import { requestedAttachmentReader, attachmentCapabilities,} from "../shared/attachments.ts";import { MODEL_INPUTS, MODEL_PROVIDERS } from "../shared/model-providers.ts";
test("attachment questions require a read and capabilities cover every model", () => { const image = { id: crypto.randomUUID(), name: "Thumbnail 001.png", mediaType: "image/png", size: 100, }; const message = (text, attachments) => ({ id: crypto.randomUUID(), role: "user", parts: [{ type: "text", text }], metadata: { attachments }, }); const first = message("What's this?", [image]); assert.equal(requestedAttachmentReader([first]), true); assert.equal(requestedAttachmentReader([first], true), false); assert.equal( requestedAttachmentReader([first, message("The attached image?")]), true, ); assert.equal( requestedAttachmentReader([ first, message("Write a document about gardening"), ]), false, ); assert.equal( requestedAttachmentReader([message("The attached image?")]), false, ); for (const [provider, definition] of Object.entries(MODEL_PROVIDERS)) assert.deepEqual( Object.keys(MODEL_INPUTS[provider]).sort(), Object.keys(definition.models).sort(), ); assert.deepEqual( attachmentCapabilities({ provider: "openrouter", model: "openai/gpt-5.6-luna", }), { images: true, pdf: true }, ); assert.deepEqual( attachmentCapabilities({ provider: "workers-ai", model: "@cf/qwen/qwen3.8-27b", }), { images: true, pdf: false }, ); assert.deepEqual( attachmentCapabilities({ provider: "openrouter", model: "tencent/hy4-preview", }), { images: false, pdf: false }, );});
test( "native workspace attachment reads preserve bytes, extract PDF text and clean R2", { timeout: 30000 }, async () => { const bundle = await build({ stdin: { resolveDir: resolve("."), loader: "ts", contents: ` import { DurableObject } from 'cloudflare:workers'; import { Workspace } from '@cloudflare/shell'; import { ConversationAttachments } from './worker/attachments'; import { deleteConversationAttachmentObjects } from './worker/attachment-objects'; export class Store extends DurableObject { workspace = new Workspace({sql: this.ctx.storage.sql, r2: this.env.R2, name: () => 'fixture', inlineThreshold: 1000}); conversions = 0; files = new ConversationAttachments((strings, ...values) => this.ctx.storage.sql.exec(strings.join('?'), ...values).toArray(), this.workspace, { toMarkdown: async () => { this.conversions++; return {format: 'markdown', data: '# Extracted\\nA useful document'}; } }); async fetch(request) { try { const url = new URL(request.url); if (url.pathname === '/upload') return Response.json(await this.files.upload('fixture.pdf', new Uint8Array(await request.arrayBuffer()))); if (url.pathname === '/delete-objects') { await deleteConversationAttachmentObjects(this.env.R2, 'fixture'); return Response.json({ok:true}); } const input = await request.json(); if (url.pathname === '/remove') { await this.files.remove(input.id); return Response.json({ok:true}); } if (url.pathname === '/download') {const file = await this.files.download(input.id); return file ? new Response(file.bytes) : new Response(null, {status:404});} const messages = [{id:'message', role:'user', parts:[{type:'text', text:'Read this'}], metadata:{attachments:input.files}}]; const config = this.files.prepare(messages, input.configuration); const read = config.tools.read_attachment; const args = {id: input.id}; const output = await read.execute(args, {toolCallId:'read', messages:[]}); if (input.replayPath) output.readPath = input.replayPath; const model = await read.toModelOutput({input:args, output, toolCallId:'read'}); return Response.json({output, model, conversions: this.conversions}); } catch(error) {return Response.json({error: error.message}, {status:400});} } } export default {fetch(request, env) {return env.Store.getByName('fixture').fetch(request);}}; `, }, external: ["cloudflare:workers", "cloudflare:sockets", "node:*"], bundle: true, format: "esm", platform: "browser", write: false, }); const mf = new Miniflare( convertV4MiniflareOptions({ modules: true, script: bundle.outputFiles[0].text, compatibilityDate: "2026-09-04", compatibilityFlags: ["nodejs_compat"], durableObjects: { Store: { className: "Store", useSQLite: true } }, r2Buckets: ["R2"], }), ); const request = (path, body) => mf.dispatchFetch(`http://localhost/${path}`, { method: "POST", body: typeof body === "string" || body instanceof Uint8Array ? body : JSON.stringify(body), }); const upload = async (bytes) => { const response = await request("upload", bytes); assert.equal(response.status, 200, await response.clone().text()); return response.json(); }; const anthropic = { provider: "anthropic", model: "claude-haiku-4-5-20251001", }; const textModel = { provider: "workers-ai", model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", }; try { const png = Uint8Array.from( Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jRZkAAAAASUVORK5CYII=", "base64", ), ); const image = await upload(png); let result = await ( await request("read", { id: image.id, files: [image], configuration: anthropic, }) ).json(); assert.equal( result.model.value.find((p) => p.type === "image-data").data, Buffer.from(png).toString("base64"), ); assert.ok( JSON.stringify(result.output).length < 500, "persisted tool output is a file descriptor", ); const invalidReplay = await ( await request("read", { id: image.id, files: [image], configuration: anthropic, replayPath: "/unrelated.png", }) ).json(); assert.equal(invalidReplay.model.type, "error-text"); assert.equal( ( await request("read", { id: image.id, files: [image], configuration: textModel, }) ).status, 400, ); assert.equal( ( await request("read", { id: image.id, files: [], configuration: anthropic, }) ).status, 400, ); const pdfBytes = Buffer.from( "%PDF-1.4\n" + "fixture ".repeat(300) + "\n%%EOF", ); const pdf = await upload(pdfBytes); const bucket = await mf.getR2Bucket("R2"); assert.equal( (await bucket.list()).objects.length, 1, "large original spills to R2", ); assert.deepEqual( Buffer.from( await (await request("download", { id: pdf.id })).arrayBuffer(), ), pdfBytes, ); result = await ( await request("read", { id: pdf.id, files: [pdf], configuration: anthropic, }) ).json(); assert.equal( result.model.value.find((p) => p.type === "file-data").data, pdfBytes.toString("base64"), ); result = await ( await request("read", { id: pdf.id, files: [pdf], configuration: textModel, }) ).json(); assert.match(result.model.value, /A useful document/); assert.match(result.model.value, /page images and charts may be missing/); assert.equal(result.conversions, 1); result = await ( await request("read", { id: pdf.id, files: [pdf], configuration: textModel, }) ).json(); assert.equal(result.conversions, 1, "extracted text is reused"); const large = new Uint8Array(4 * 1024 * 1024); large.set(new TextEncoder().encode("%PDF-1.4\n")); const largePdf = await upload(large); result = await ( await request("read", { id: largePdf.id, files: [largePdf], configuration: anthropic, }) ).json(); assert.match( result.model.value, /Extracted/, "large PDFs use text even with a PDF-capable model", ); assert.equal( (await request("upload", "<html>not a PDF</html>")).status, 400, ); const oversized = new Uint8Array(4 * 1024 * 1024); oversized.set(png); assert.equal((await request("upload", oversized)).status, 400); await bucket.put("other/default/attachments/kept.pdf", pdfBytes); await bucket.put("fixture/default/unrelated.txt", "keep"); await request("delete-objects", {}); await request("delete-objects", {}); assert.deepEqual( (await bucket.list()).objects.map((o) => o.key).sort(), ["fixture/default/unrelated.txt", "other/default/attachments/kept.pdf"], "parent cleanup is repeatable and only deletes this conversation’s attachment objects", ); await bucket.delete([ "fixture/default/unrelated.txt", "other/default/attachments/kept.pdf", ]); await request("remove", { id: pdf.id }); assert.equal((await bucket.list()).objects.length, 0); assert.equal((await request("download", { id: pdf.id })).status, 404); } finally { await mf.dispose(); } },);