opencode/packages/ai/test/provider/alibaba-images.recorded.test.ts
2026-07-22 05:33:05 +00:00

164 lines
6 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { Effect, Option, Schema } from "effect"
import { Image, ImageInput } from "../../src"
import { Alibaba } from "../../src/providers"
import { dimensions } from "../lib/image"
import { recordedTests } from "../recorded-test"
const alibaba = Alibaba.configure({
apiKey: process.env.DASHSCOPE_API_KEY ?? "fixture",
})
const SIGNED_QUERY_CREDENTIALS = new Set(
[
"AccessKeyId",
"AWSAccessKeyId",
"GoogleAccessId",
"OSSAccessKeyId",
"Signature",
"SecurityToken",
"X-Amz-Credential",
"X-Amz-Security-Token",
"X-Amz-Signature",
"X-Goog-Credential",
"X-Goog-Signature",
"X-OSS-Security-Token",
].map((name) => name.replace(/[^a-z0-9]/gi, "").toLowerCase()),
)
const redactSignedUrl = (value: string) => {
if (!URL.canParse(value)) return value
const url = new URL(value)
if (url.protocol !== "http:" && url.protocol !== "https:") return value
url.searchParams.forEach((_, name) => {
if (SIGNED_QUERY_CREDENTIALS.has(name.replace(/[^a-z0-9]/gi, "").toLowerCase()))
url.searchParams.set(name, "[REDACTED]")
})
return url.toString()
}
const redactSignedUrls = (body: string) =>
Option.match(Schema.decodeUnknownOption(Schema.UnknownFromJsonString)(body), {
onNone: () => body,
onSome: (value) =>
JSON.stringify(
(function redact(input: unknown): unknown {
if (typeof input === "string") return redactSignedUrl(input)
if (Array.isArray(input)) return input.map(redact)
if (input === null || typeof input !== "object") return input
return Object.fromEntries(Object.entries(input).map(([key, child]) => [key, redact(child)]))
})(value),
),
})
const recorded = recordedTests({
prefix: "alibaba-images",
provider: "alibaba",
protocol: "alibaba-images",
requires: ["DASHSCOPE_API_KEY"],
options: { redact: { body: redactSignedUrls } },
})
const inspectLive = async (value: string | Uint8Array | undefined) => {
if (process.env.RECORD !== "true" || typeof value !== "string") return
const response = await fetch(value)
const bytes = new Uint8Array(await response.arrayBuffer())
expect(response.headers.get("content-type")).toMatch(/^image\//)
expect(dimensions(bytes).width).toBeGreaterThan(0)
expect(dimensions(bytes).height).toBeGreaterThan(0)
}
test("recorder redacts signed URL credentials in nested JSON strings repeatably", () => {
const body = JSON.stringify({
output: {
image:
"https://example.oss.aliyuncs.com/image.png?Expires=1893456000&OSSAccessKeyId=access&Signature=signature&x-oss-security-token=token",
},
mirrors: ["https://storage.googleapis.com/image.png?X-Goog-Credential=credential&X-Goog-Signature=signature"],
})
const once = redactSignedUrls(body)
const twice = redactSignedUrls(once)
const parsed = JSON.parse(once)
const oss = new URL(parsed.output.image)
const gcs = new URL(parsed.mirrors[0])
expect(oss.searchParams.get("Expires")).toBe("1893456000")
expect(oss.searchParams.get("OSSAccessKeyId")).toBe("[REDACTED]")
expect(oss.searchParams.get("Signature")).toBe("[REDACTED]")
expect(oss.searchParams.get("x-oss-security-token")).toBe("[REDACTED]")
expect(gcs.searchParams.get("X-Goog-Credential")).toBe("[REDACTED]")
expect(gcs.searchParams.get("X-Goog-Signature")).toBe("[REDACTED]")
expect(twice).toBe(once)
})
describe("Alibaba Images recorded", () => {
recorded.effect("generates with Qwen Image 2.0", () =>
Effect.gen(function* () {
const response = yield* Image.generate({
model: alibaba.image("qwen-image-2.0"),
prompt: "A simple flat black circle centered on a plain white background.",
options: { size: "512*512", promptExtend: false, watermark: false },
})
expect(response.images).toHaveLength(1)
expect(response.image?.mediaType).toBe("image/png")
expect(response.image?.data).toStartWith("https://")
}),
)
recorded.effect("generates with Wan 2.7", () =>
Effect.gen(function* () {
const response = yield* Image.generate({
model: alibaba.image("wan2.7-image"),
prompt: "A simple flat black square centered on a plain white background.",
options: { resolution: "1K", thinkingMode: false, watermark: false },
})
expect(response.images).toHaveLength(1)
expect(response.image?.mediaType).toBe("image/png")
expect(response.image?.data).toStartWith("https://")
}),
)
recorded.effect("edits with Qwen Image 2.0", () =>
Effect.gen(function* () {
const response = yield* Image.generate({
model: alibaba.image("qwen-image-2.0"),
prompt: "Turn the black source shape into a bright orange sun icon on a pale blue background.",
images: [
ImageInput.bytes(
yield* Effect.promise(() => Bun.file("test/fixtures/images/edit-source.jpg").bytes()),
"image/jpeg",
),
],
options: { promptExtend: false, watermark: false },
})
expect(response.images).toHaveLength(1)
expect(response.image?.mediaType).toBe("image/png")
expect(response.image?.data).toStartWith("https://")
yield* Effect.promise(() => inspectLive(response.image?.data))
}),
)
recorded.effect("edits with Wan 2.7", () =>
Effect.gen(function* () {
const response = yield* Image.generate({
model: alibaba.image("wan2.7-image"),
prompt: "Turn the black source shape into a bright orange sun icon on a pale blue background.",
images: [
ImageInput.bytes(
yield* Effect.promise(() => Bun.file("test/fixtures/images/edit-source-256.jpg").bytes()),
"image/jpeg",
),
],
options: { resolution: "1K", thinkingMode: false, watermark: false },
})
expect(response.images).toHaveLength(1)
expect(response.image?.mediaType).toBe("image/png")
expect(response.image?.data).toStartWith("https://")
yield* Effect.promise(() => inspectLive(response.image?.data))
}),
)
})