cc6ab1addc
Intercepts Read tool output with image attachments and resizes to comply with Anthropic API limits (≤1568px long edge, ≤5MB). Only activates for Anthropic provider sessions and appends resize metadata (original/new resolution, token count) to tool output. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
109 lines
2.7 KiB
TypeScript
109 lines
2.7 KiB
TypeScript
/// <reference types="bun-types" />
|
|
|
|
import { describe, expect, it } from "bun:test"
|
|
|
|
import { parseImageDimensions } from "./image-dimensions"
|
|
|
|
const PNG_1X1_DATA_URL =
|
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
|
|
|
|
const GIF_1X1_DATA_URL =
|
|
"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
|
|
|
function createPngDataUrl(width: number, height: number): string {
|
|
const buf = Buffer.alloc(33)
|
|
buf.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a], 0)
|
|
buf.writeUInt32BE(13, 8)
|
|
buf.set([0x49, 0x48, 0x44, 0x52], 12)
|
|
buf.writeUInt32BE(width, 16)
|
|
buf.writeUInt32BE(height, 20)
|
|
return `data:image/png;base64,${buf.toString("base64")}`
|
|
}
|
|
|
|
function createGifDataUrl(width: number, height: number): string {
|
|
const buf = Buffer.alloc(10)
|
|
buf.set([0x47, 0x49, 0x46, 0x38, 0x39, 0x61], 0)
|
|
buf.writeUInt16LE(width, 6)
|
|
buf.writeUInt16LE(height, 8)
|
|
return `data:image/gif;base64,${buf.toString("base64")}`
|
|
}
|
|
|
|
describe("parseImageDimensions", () => {
|
|
it("parses PNG 1x1 dimensions", () => {
|
|
//#given
|
|
const dataUrl = PNG_1X1_DATA_URL
|
|
|
|
//#when
|
|
const result = parseImageDimensions(dataUrl, "image/png")
|
|
|
|
//#then
|
|
expect(result).toEqual({ width: 1, height: 1 })
|
|
})
|
|
|
|
it("parses PNG dimensions from IHDR", () => {
|
|
//#given
|
|
const dataUrl = createPngDataUrl(3000, 2000)
|
|
|
|
//#when
|
|
const result = parseImageDimensions(dataUrl, "image/png")
|
|
|
|
//#then
|
|
expect(result).toEqual({ width: 3000, height: 2000 })
|
|
})
|
|
|
|
it("parses GIF 1x1 dimensions", () => {
|
|
//#given
|
|
const dataUrl = GIF_1X1_DATA_URL
|
|
|
|
//#when
|
|
const result = parseImageDimensions(dataUrl, "image/gif")
|
|
|
|
//#then
|
|
expect(result).toEqual({ width: 1, height: 1 })
|
|
})
|
|
|
|
it("parses GIF dimensions from logical screen descriptor", () => {
|
|
//#given
|
|
const dataUrl = createGifDataUrl(320, 240)
|
|
|
|
//#when
|
|
const result = parseImageDimensions(dataUrl, "image/gif")
|
|
|
|
//#then
|
|
expect(result).toEqual({ width: 320, height: 240 })
|
|
})
|
|
|
|
it("returns null for empty input", () => {
|
|
//#given
|
|
const dataUrl = ""
|
|
|
|
//#when
|
|
const result = parseImageDimensions(dataUrl, "image/png")
|
|
|
|
//#then
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it("returns null for too-short PNG buffer", () => {
|
|
//#given
|
|
const dataUrl = "data:image/png;base64,AAAA"
|
|
|
|
//#when
|
|
const result = parseImageDimensions(dataUrl, "image/png")
|
|
|
|
//#then
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it("returns null for unsupported mime type", () => {
|
|
//#given
|
|
const dataUrl = PNG_1X1_DATA_URL
|
|
|
|
//#when
|
|
const result = parseImageDimensions(dataUrl, "image/heic")
|
|
|
|
//#then
|
|
expect(result).toBeNull()
|
|
})
|
|
})
|