From 940ea787a1f5e29683fe4d89700bcbdb26f758e3 Mon Sep 17 00:00:00 2001 From: jh-block Date: Thu, 5 Mar 2026 14:18:38 -0500 Subject: [PATCH] fix: restore binary schema for diagnostics response to fix TS typecheck utoipa renders Vec as array, producing number[] in TS codegen. This fails typecheck: new Blob([response.data]) expects BlobPart, not number[]. Add a minimal Modify fixup to set the diagnostics response schema to string/binary (no utoipa annotation exists for response body format). Co-Authored-By: Claude Opus 4.6 --- crates/goose-server/src/openapi.rs | 32 +++++++++++++++++++++++++++++- ui/desktop/openapi.json | 8 ++------ ui/desktop/src/api/types.gen.ts | 2 +- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index a17372af44..4451ede6a3 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -14,7 +14,7 @@ use rmcp::model::{ RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ResourceContents, Role, TaskSupport, TextContent, Tool, ToolAnnotations, ToolExecution, }; -use utoipa::{OpenApi, ToSchema}; +use utoipa::{Modify, OpenApi, ToSchema}; use goose::config::declarative_providers::{ DeclarativeProviderConfig, LoadedProvider, ProviderEngine, @@ -333,8 +333,38 @@ derive_utoipa!(ResourceContents as ResourceContentsSchema); derive_utoipa!(JsonObject as JsonObjectSchema); derive_utoipa!(Icon as IconSchema); +/// utoipa renders `Vec` as `array` which produces `number[]` in TS codegen, +/// failing typecheck at `new Blob([response.data])`. This fixup sets `string/binary` so +/// codegen emits `Blob | File`. There is no utoipa annotation for response body format. +struct BinaryResponseFixup; + +impl Modify for BinaryResponseFixup { + fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) { + use utoipa::openapi::schema::Schema; + use utoipa::openapi::RefOr; + + if let Some(path) = openapi.paths.paths.get_mut("/diagnostics/{session_id}") { + if let Some(op) = &mut path.get { + if let Some(RefOr::T(resp)) = op.responses.responses.get_mut("200") { + if let Some(content) = resp.content.get_mut("application/zip") { + content.schema = Some(RefOr::T(Schema::Object( + ObjectBuilder::new() + .schema_type(SchemaType::new(Type::String)) + .format(Some(SchemaFormat::KnownFormat( + utoipa::openapi::schema::KnownFormat::Binary, + ))) + .build(), + ))); + } + } + } + } + } +} + #[derive(OpenApi)] #[openapi( + modifiers(&BinaryResponseFixup), paths( super::routes::status::status, super::routes::status::system_info, diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index 8a9241ca56..59e63f6cd3 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -1632,12 +1632,8 @@ "content": { "application/zip": { "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int32", - "minimum": 0 - } + "type": "string", + "format": "binary" } } } diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index 3a4e5aaf6d..d6fb7887c7 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -2822,7 +2822,7 @@ export type DiagnosticsResponses = { /** * Diagnostics zip file */ - 200: Array; + 200: Blob | File; }; export type DiagnosticsResponse = DiagnosticsResponses[keyof DiagnosticsResponses];