mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-13 23:52:06 +00:00
fix(image): disable attachment resizing by default
This commit is contained in:
@@ -4,8 +4,13 @@ import { Schema } from "effect"
|
||||
import { PositiveInt } from "@opencode-ai/core/schema"
|
||||
|
||||
export const Image = Schema.Struct({
|
||||
enforce_limits: Schema.optional(Schema.Boolean).annotate({
|
||||
description:
|
||||
"Enforce image attachment size limits before sending images to the model. When false, images pass through unchanged (default: false)",
|
||||
}),
|
||||
auto_resize: Schema.optional(Schema.Boolean).annotate({
|
||||
description: "Resize images before sending them to the model when they exceed configured limits (default: true)",
|
||||
description:
|
||||
"Resize images before sending them to the model when they exceed configured limits. Requires enforce_limits to be true (default: false)",
|
||||
}),
|
||||
max_width: Schema.optional(PositiveInt).annotate({
|
||||
description: "Maximum image width before resizing or rejecting the attachment (default: 2000)",
|
||||
|
||||
@@ -6,7 +6,8 @@ import { Context, Effect, Layer, Schema } from "effect"
|
||||
const MAX_BASE64_BYTES = 4.5 * 1024 * 1024
|
||||
const MAX_WIDTH = 2000
|
||||
const MAX_HEIGHT = 2000
|
||||
const AUTO_RESIZE = true
|
||||
const ENFORCE_LIMITS = false
|
||||
const AUTO_RESIZE = false
|
||||
const JPEG_QUALITIES = [80, 85, 70, 55, 40]
|
||||
const log = Log.create({ service: "image" })
|
||||
|
||||
@@ -76,11 +77,13 @@ export const layer = Layer.effect(
|
||||
const normalize = Effect.fn("Image.normalize")(function* (input: MessageV2.FilePart) {
|
||||
const image = (yield* config.get()).attachment?.image
|
||||
const info = {
|
||||
enforceLimits: image?.enforce_limits ?? ENFORCE_LIMITS,
|
||||
autoResize: image?.auto_resize ?? AUTO_RESIZE,
|
||||
maxWidth: image?.max_width ?? MAX_WIDTH,
|
||||
maxHeight: image?.max_height ?? MAX_HEIGHT,
|
||||
maxBase64Bytes: image?.max_base64_bytes ?? MAX_BASE64_BYTES,
|
||||
}
|
||||
if (!info.enforceLimits) return input
|
||||
if (!input.url.startsWith("data:") || !input.url.includes(";base64,"))
|
||||
return yield* new InvalidDataUrlError({ url: input.url })
|
||||
|
||||
|
||||
@@ -6,11 +6,24 @@ import { TestConfig } from "../fixture/config"
|
||||
import { testEffect } from "../lib/effect"
|
||||
|
||||
const it = testEffect(Layer.mergeAll(Image.layer.pipe(Layer.provide(TestConfig.layer()))))
|
||||
const enforcing = testEffect(
|
||||
Layer.mergeAll(
|
||||
Image.layer.pipe(
|
||||
Layer.provide(
|
||||
TestConfig.layer({
|
||||
get: () => Effect.succeed({ attachment: { image: { enforce_limits: true, auto_resize: true } } }),
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
const tiny = testEffect(
|
||||
Layer.mergeAll(
|
||||
Image.layer.pipe(
|
||||
Layer.provide(
|
||||
TestConfig.layer({ get: () => Effect.succeed({ attachment: { image: { max_base64_bytes: 1 } } }) }),
|
||||
TestConfig.layer({
|
||||
get: () => Effect.succeed({ attachment: { image: { enforce_limits: true, max_base64_bytes: 1 } } }),
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -28,7 +41,16 @@ function part(mime: string, data: string) {
|
||||
}
|
||||
|
||||
describe("Image", () => {
|
||||
it.effect("normalizes generated png and jpeg attachments", () =>
|
||||
it.effect("passes images through by default without loading the resizer", () =>
|
||||
Effect.gen(function* () {
|
||||
const image = yield* Image.Service
|
||||
const input = part("image/png", "not-valid-image-data")
|
||||
|
||||
expect(yield* image.normalize(input)).toEqual(input)
|
||||
}),
|
||||
)
|
||||
|
||||
enforcing.effect("normalizes generated png and jpeg attachments when limit enforcement is enabled", () =>
|
||||
Effect.gen(function* () {
|
||||
const photon = yield* Effect.promise(() => import("@silvia-odwyer/photon-node"))
|
||||
const source = new photon.PhotonImage(
|
||||
|
||||
@@ -1143,6 +1143,7 @@ export type McpRemoteConfig = {
|
||||
export type LayoutConfig = "auto" | "stretch"
|
||||
|
||||
export type ImageAttachmentConfig = {
|
||||
enforce_limits?: boolean
|
||||
auto_resize?: boolean
|
||||
max_width?: number
|
||||
max_height?: number
|
||||
|
||||
@@ -345,6 +345,39 @@ You can manage the tools an LLM can use through the `tools` option.
|
||||
|
||||
---
|
||||
|
||||
### Attachments
|
||||
|
||||
You can configure how image attachments are processed before they are sent to the model through the `attachment.image` option.
|
||||
|
||||
By default OpenCode does not enforce image attachment limits and does not resize images. Images pass through unchanged unless you explicitly enable limit enforcement.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"attachment": {
|
||||
"image": {
|
||||
"enforce_limits": true,
|
||||
"auto_resize": false,
|
||||
"max_width": 2000,
|
||||
"max_height": 2000,
|
||||
"max_base64_bytes": 4718592
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Available options:
|
||||
|
||||
- `enforce_limits` - Enforce configured image limits before sending images to the model. Defaults to `false`, which passes images through unchanged.
|
||||
- `auto_resize` - Resize images that exceed configured limits. This only applies when `enforce_limits` is `true`. Defaults to `false`.
|
||||
- `max_width` - Maximum image width when limit enforcement is enabled. Defaults to `2000`.
|
||||
- `max_height` - Maximum image height when limit enforcement is enabled. Defaults to `2000`.
|
||||
- `max_base64_bytes` - Maximum base64 payload size when limit enforcement is enabled. Defaults to `4718592`.
|
||||
|
||||
When `enforce_limits` is `true` and `auto_resize` is `false`, images over the configured limits are omitted. When both are `true`, OpenCode attempts to resize oversized images before omitting them.
|
||||
|
||||
---
|
||||
|
||||
### Models
|
||||
|
||||
You can configure the providers and models you want to use in your OpenCode config through the `provider`, `model` and `small_model` options.
|
||||
|
||||
Reference in New Issue
Block a user