authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-10-14 01:38:10-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-14 01:38:10-07:00
logc8a6768f079f9448228668c40ffe2262bda202a6
tree06be4ed8c91400b3234f896b71a70b22bb6a3523
parent4f909be2c1a2eb4a88e6a51c8d0ef25e47a027d2
signature Signed by PGP key B5690EEEBB952194

fix(server): HTML and Markdown attachments no longer fail OpenCode turns (#19319)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

2 files changed, 10 insertions(+), 4 deletions(-)

packages/provider-opencode/src/server/OpenCodeRuntime.cliParsers.test.ts+6-2
...@@ -293,11 +293,15 @@ describe("toOpenCodeFileParts", () => {...@@ -293,11 +293,15 @@ describe("toOpenCodeFileParts", () => {
293 const parts = OpenCodeRuntime.toOpenCodeFileParts({293 const parts = OpenCodeRuntime.toOpenCodeFileParts({
294 attachments: [294 attachments: [
295 attachment("application/pdf"),295 attachment("application/pdf"),
296 attachment("text/markdown"),296 attachment("text/plain"),
297 attachment("image/png"),297 attachment("image/png"),
298 // A ZIP file part makes OpenCode's Anthropic path throw before the298 // A ZIP file part makes OpenCode's Anthropic path throw before the
299 // turn starts; it must ride only as the prompt's file path line.299 // turn starts; it must ride only as the prompt's file path line.
300 attachment("application/zip"),300 attachment("application/zip"),
301 // OpenCode inlines only text/plain itself. Other text types reach the
302 // model API as raw file parts, which Anthropic and OpenAI reject.
303 attachment("text/html"),
304 attachment("text/markdown"),
301 attachment("application/octet-stream"),305 attachment("application/octet-stream"),
302 // Image formats the model APIs reject stay on the fallback path too.306 // Image formats the model APIs reject stay on the fallback path too.
303 attachment("image/bmp"),307 attachment("image/bmp"),
...@@ -310,7 +314,7 @@ describe("toOpenCodeFileParts", () => {...@@ -310,7 +314,7 @@ describe("toOpenCodeFileParts", () => {
310314
311 NodeAssert.deepEqual(315 NodeAssert.deepEqual(
312 parts.map((part) => part.mime),316 parts.map((part) => part.mime),
313 ["application/pdf", "text/markdown", "image/png"],317 ["application/pdf", "text/plain", "image/png"],
314 );318 );
315 });319 });
316320
packages/provider-opencode/src/server/OpenCodeRuntime.ts+4-2
...@@ -469,7 +469,9 @@ export function openCodeQuestionId(...@@ -469,7 +469,9 @@ export function openCodeQuestionId(
469 * else (ZIP, binaries, image formats like BMP/AVIF/SVG that model APIs469 * else (ZIP, binaries, image formats like BMP/AVIF/SVG that model APIs
470 * reject, or files over the direct-attachment size limit) would make the turn470 * reject, or files over the direct-attachment size limit) would make the turn
471 * fail before it starts, so those ride only as the file path ProviderService471 * fail before it starts, so those ride only as the file path ProviderService
472 * puts in the prompt.472 * puts in the prompt. Text is native only as text/plain, which OpenCode reads
473 * itself; other text types (HTML, Markdown, CSV) reach the model API as raw
474 * file parts, which Anthropic and OpenAI reject.
473 */475 */
474const OPENCODE_NATIVE_IMAGE_MIMES = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);476const OPENCODE_NATIVE_IMAGE_MIMES = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
475const OPENCODE_NATIVE_FILE_PART_MAX_BYTES = 20 * 1024 * 1024;477const OPENCODE_NATIVE_FILE_PART_MAX_BYTES = 20 * 1024 * 1024;
...@@ -484,7 +486,7 @@ function isOpenCodeNativeFilePart(input: {...@@ -484,7 +486,7 @@ function isOpenCodeNativeFilePart(input: {
484 const normalized = input.mimeType.trim().toLowerCase();486 const normalized = input.mimeType.trim().toLowerCase();
485 return (487 return (
486 OPENCODE_NATIVE_IMAGE_MIMES.has(normalized) ||488 OPENCODE_NATIVE_IMAGE_MIMES.has(normalized) ||
487 normalized.startsWith("text/") ||489 normalized === "text/plain" ||
488 normalized === "application/pdf"490 normalized === "application/pdf"
489 );491 );
490}492}