diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index f32030c13176..d5770225e15b 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -11,8 +11,8 @@ use goose::providers::base::{ConfigKey, ModelInfo, ProviderMetadata, ProviderTyp use goose::session::{Session, SessionInsights, SessionType, SystemInfo}; use rmcp::model::{ Annotations, Content, EmbeddedResource, Icon, ImageContent, JsonObject, RawAudioContent, - RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ResourceContents, Role, - TaskSupport, TextContent, Tool, ToolAnnotations, ToolExecution, + RawContent, RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, + ResourceContents, Role, TaskSupport, TextContent, Tool, ToolAnnotations, ToolExecution, }; use utoipa::{OpenApi, ToSchema}; @@ -36,7 +36,7 @@ use utoipa::openapi::{AllOfBuilder, Ref, RefOr}; macro_rules! derive_utoipa { ($inner_type:ident as $schema_name:ident) => { - struct $schema_name {} + pub struct $schema_name {} impl<'__s> ToSchema<'__s> for $schema_name { fn schema() -> (&'__s str, utoipa::openapi::RefOr) { @@ -47,6 +47,23 @@ macro_rules! derive_utoipa { (stringify!($inner_type), schema) } + fn aliases() -> Vec<(&'__s str, utoipa::openapi::schema::Schema)> { + Vec::new() + } + } + }; + ($inner_type:ident as $schema_name:ident => $output_name:expr) => { + pub struct $schema_name {} + + impl<'__s> ToSchema<'__s> for $schema_name { + fn schema() -> (&'__s str, utoipa::openapi::RefOr) { + let settings = rmcp::schemars::generate::SchemaSettings::openapi3(); + let generator = settings.into_generator(); + let schema = generator.into_root_schema_for::<$inner_type>(); + let schema = convert_schemars_to_utoipa(schema); + ($output_name, schema) + } + fn aliases() -> Vec<(&'__s str, utoipa::openapi::schema::Schema)> { Vec::new() } @@ -89,7 +106,26 @@ fn convert_json_object_to_utoipa( return RefOr::T(Schema::OneOf(builder.build())); } + // Handle the discriminated union pattern from schemars: an object with + // `type`, `properties`, `required` AND `allOf` (e.g. each variant of a + // `#[serde(tag = "type")]` enum). We merge the inline object (which carries + // the discriminator property) with the `allOf` refs into a single `allOf`. if let Some(Value::Array(all_of)) = obj.get("allOf") { + let has_inline_properties = obj.contains_key("properties") || obj.contains_key("type"); + if has_inline_properties { + let mut builder = AllOfBuilder::new(); + // Build an object schema from the inline properties/required + let mut obj_without_allof = obj.clone(); + obj_without_allof.remove("allOf"); + builder = builder.item(convert_json_object_to_utoipa(&obj_without_allof)); + for item in all_of { + if let Ok(schema) = rmcp::schemars::Schema::try_from(item.clone()) { + builder = builder.item(convert_schemars_to_utoipa(schema)); + } + } + return RefOr::T(Schema::AllOf(builder.build())); + } + let mut builder = AllOfBuilder::new(); for item in all_of { if let Ok(schema) = rmcp::schemars::Schema::try_from(item.clone()) { @@ -215,6 +251,22 @@ fn convert_typed_schema( "string" => { let mut object_builder = ObjectBuilder::new().schema_type(SchemaType::String); + if let Some(Value::Array(enum_values)) = obj.get("enum") { + let values: Vec = enum_values + .iter() + .filter_map(|v| { + if let Value::String(s) = v { + Some(Value::String(s.clone())) + } else { + None + } + }) + .collect(); + if !values.is_empty() { + object_builder = object_builder.enum_values(Some(values)); + } + } + if let Some(Value::Number(min_length)) = obj.get("minLength") { if let Some(min) = min_length.as_u64() { object_builder = object_builder.min_length(Some(min as usize)); @@ -310,6 +362,7 @@ fn convert_typed_schema( derive_utoipa!(Role as RoleSchema); derive_utoipa!(Content as ContentSchema); +derive_utoipa!(RawContent as ContentBlockSchema => "ContentBlock"); derive_utoipa!(EmbeddedResource as EmbeddedResourceSchema); derive_utoipa!(ImageContent as ImageContentSchema); derive_utoipa!(TextContent as TextContentSchema); @@ -577,6 +630,7 @@ derive_utoipa!(Icon as IconSchema); super::routes::agent::ReadResourceResponse, super::routes::agent::CallToolRequest, super::routes::agent::CallToolResponse, + ContentBlockSchema, super::routes::agent::ListAppsRequest, super::routes::agent::ListAppsResponse, super::routes::agent::ImportAppRequest, diff --git a/crates/goose-server/src/routes/agent.rs b/crates/goose-server/src/routes/agent.rs index a538cf56f1c2..73e594232563 100644 --- a/crates/goose-server/src/routes/agent.rs +++ b/crates/goose-server/src/routes/agent.rs @@ -27,7 +27,7 @@ use goose::{ agents::{extension::ToolInfo, extension_manager::get_parameter_names}, config::permission::PermissionLevel, }; -use rmcp::model::{CallToolRequestParams, Content}; +use rmcp::model::CallToolRequestParams; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashSet; @@ -134,13 +134,31 @@ pub struct CallToolRequest { arguments: Value, } +/// Ref-only alias so utoipa emits `$ref: "#/components/schemas/ContentBlock"`. +/// The actual schema is registered via `derive_utoipa!(RawContent as ContentBlockSchema => "ContentBlock")`. +#[allow(dead_code)] +pub enum ContentBlock {} + +impl<'s> utoipa::ToSchema<'s> for ContentBlock { + fn schema() -> ( + &'s str, + utoipa::openapi::RefOr, + ) { + // Delegate to the auto-generated schema + crate::openapi::ContentBlockSchema::schema() + } +} + #[derive(Serialize, utoipa::ToSchema)] +#[serde(rename_all = "camelCase")] pub struct CallToolResponse { - content: Vec, + #[schema(value_type = Vec)] + content: Vec, #[serde(skip_serializing_if = "Option::is_none")] structured_content: Option, is_error: bool, #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "_meta")] _meta: Option, } @@ -992,8 +1010,15 @@ async fn call_tool( .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + let content = result + .content + .into_iter() + .map(serde_json::to_value) + .collect::, _>>() + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + Ok(Json(CallToolResponse { - content: result.content, + content, structured_content: result.structured_content, is_error: result.is_error.unwrap_or(false), _meta: result.meta.and_then(|m| serde_json::to_value(m).ok()), diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index 52f79bf09ee2..3f953ea395f8 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -3871,7 +3871,7 @@ "type": "object", "required": [ "content", - "is_error" + "isError" ], "properties": { "_meta": { @@ -3880,13 +3880,13 @@ "content": { "type": "array", "items": { - "$ref": "#/components/schemas/Content" + "$ref": "#/components/schemas/ContentBlock" } }, - "is_error": { + "isError": { "type": "boolean" }, - "structured_content": { + "structuredContent": { "nullable": true } } @@ -4030,6 +4030,20 @@ "oneOf": [ { "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "text" + ] + } + } + }, { "$ref": "#/components/schemas/RawTextContent" } @@ -4037,6 +4051,20 @@ }, { "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "image" + ] + } + } + }, { "$ref": "#/components/schemas/RawImageContent" } @@ -4044,6 +4072,20 @@ }, { "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "resource" + ] + } + } + }, { "$ref": "#/components/schemas/RawEmbeddedResource" } @@ -4051,6 +4093,20 @@ }, { "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "audio" + ] + } + } + }, { "$ref": "#/components/schemas/RawAudioContent" } @@ -4058,6 +4114,129 @@ }, { "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "resource_link" + ] + } + } + }, + { + "$ref": "#/components/schemas/RawResource" + } + ] + } + ] + }, + "ContentBlock": { + "oneOf": [ + { + "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "text" + ] + } + } + }, + { + "$ref": "#/components/schemas/RawTextContent" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "image" + ] + } + } + }, + { + "$ref": "#/components/schemas/RawImageContent" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "resource" + ] + } + } + }, + { + "$ref": "#/components/schemas/RawEmbeddedResource" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "audio" + ] + } + } + }, + { + "$ref": "#/components/schemas/RawAudioContent" + } + ] + }, + { + "allOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "resource_link" + ] + } + } + }, { "$ref": "#/components/schemas/RawResource" } @@ -7029,10 +7208,16 @@ "Role": { "oneOf": [ { - "type": "string" + "type": "string", + "enum": [ + "user" + ] }, { - "type": "string" + "type": "string", + "enum": [ + "assistant" + ] } ] }, @@ -7765,13 +7950,22 @@ "TaskSupport": { "oneOf": [ { - "type": "string" + "type": "string", + "enum": [ + "forbidden" + ] }, { - "type": "string" + "type": "string", + "enum": [ + "optional" + ] }, { - "type": "string" + "type": "string", + "enum": [ + "required" + ] } ] }, diff --git a/ui/desktop/src/api/index.ts b/ui/desktop/src/api/index.ts index adb454d4c712..2a521a90dc32 100644 --- a/ui/desktop/src/api/index.ts +++ b/ui/desktop/src/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts export { addExtension, agentAddExtension, agentRemoveExtension, backupConfig, callTool, cancelDownload, cancelLocalModelDownload, checkProvider, configureProviderOauth, confirmToolAction, createCustomProvider, createRecipe, createSchedule, decodeRecipe, deleteLocalModel, deleteModel, deleteRecipe, deleteSchedule, deleteSession, detectProvider, diagnostics, downloadHfModel, downloadModel, encodeRecipe, exportApp, exportSession, forkSession, getCanonicalModelInfo, getCustomProvider, getDictationConfig, getDownloadProgress, getExtensions, getLocalModelDownloadProgress, getModelSettings, getPrompt, getPrompts, getProviderCatalog, getProviderCatalogTemplate, getProviderModels, getRepoFiles, getSession, getSessionExtensions, getSessionInsights, getSlashCommands, getTools, getTunnelStatus, importApp, importSession, initConfig, inspectRunningJob, killRunningJob, listApps, listLocalModels, listModels, listRecipes, listSchedules, listSessions, mcpUiProxy, type Options, parseRecipe, pauseSchedule, providers, readAllConfig, readConfig, readResource, recipeToYaml, recoverConfig, removeConfig, removeCustomProvider, removeExtension, reply, resetPrompt, restartAgent, resumeAgent, runNowHandler, savePrompt, saveRecipe, scanRecipe, scheduleRecipe, searchHfModels, searchSessions, sendTelemetryEvent, sessionsHandler, setConfigProvider, setRecipeSlashCommand, startAgent, startOpenrouterSetup, startTetrateSetup, startTunnel, status, stopAgent, stopTunnel, systemInfo, transcribeDictation, unpauseSchedule, updateAgentProvider, updateCustomProvider, updateFromSession, updateModelSettings, updateSchedule, updateSessionName, updateSessionUserRecipeValues, updateWorkingDir, upsertConfig, upsertPermissions, validateConfig } from './sdk.gen'; -export type { ActionRequired, ActionRequiredData, AddExtensionData, AddExtensionErrors, AddExtensionRequest, AddExtensionResponse, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponse, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponse, AgentRemoveExtensionResponses, Annotations, Author, AuthorRequest, BackupConfigData, BackupConfigErrors, BackupConfigResponse, BackupConfigResponses, CallToolData, CallToolErrors, CallToolRequest, CallToolResponse, CallToolResponse2, CallToolResponses, CancelDownloadData, CancelDownloadErrors, CancelDownloadResponses, CancelLocalModelDownloadData, CancelLocalModelDownloadErrors, CancelLocalModelDownloadResponses, ChatRequest, CheckProviderData, CheckProviderRequest, ClientOptions, CommandType, ConfigKey, ConfigKeyQuery, ConfigResponse, ConfigureProviderOauthData, ConfigureProviderOauthErrors, ConfigureProviderOauthResponses, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionRequest, ConfirmToolActionResponses, Content, Conversation, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponse, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeRequest, CreateRecipeResponse, CreateRecipeResponse2, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleRequest, CreateScheduleResponse, CreateScheduleResponses, CspMetadata, DeclarativeProviderConfig, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeRequest, DecodeRecipeResponse, DecodeRecipeResponse2, DecodeRecipeResponses, DeleteLocalModelData, DeleteLocalModelErrors, DeleteLocalModelResponses, DeleteModelData, DeleteModelErrors, DeleteModelResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeRequest, DeleteRecipeResponse, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponse, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DetectProviderData, DetectProviderErrors, DetectProviderRequest, DetectProviderResponse, DetectProviderResponse2, DetectProviderResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponse, DiagnosticsResponses, DictationProvider, DictationProviderStatus, DownloadHfModelData, DownloadHfModelErrors, DownloadHfModelResponse, DownloadHfModelResponses, DownloadModelData, DownloadModelErrors, DownloadModelRequest, DownloadModelResponses, DownloadProgress, DownloadStatus, EmbeddedResource, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeRequest, EncodeRecipeResponse, EncodeRecipeResponse2, EncodeRecipeResponses, Envs, EnvVarConfig, ErrorResponse, ExportAppData, ExportAppError, ExportAppErrors, ExportAppResponse, ExportAppResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponse, ExportSessionResponses, ExtensionConfig, ExtensionData, ExtensionEntry, ExtensionLoadResult, ExtensionQuery, ExtensionResponse, ForkRequest, ForkResponse, ForkSessionData, ForkSessionErrors, ForkSessionResponse, ForkSessionResponses, FrontendToolRequest, GetCanonicalModelInfoData, GetCanonicalModelInfoResponse, GetCanonicalModelInfoResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponse, GetCustomProviderResponses, GetDictationConfigData, GetDictationConfigResponse, GetDictationConfigResponses, GetDownloadProgressData, GetDownloadProgressErrors, GetDownloadProgressResponse, GetDownloadProgressResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponse, GetExtensionsResponses, GetLocalModelDownloadProgressData, GetLocalModelDownloadProgressErrors, GetLocalModelDownloadProgressResponse, GetLocalModelDownloadProgressResponses, GetModelSettingsData, GetModelSettingsErrors, GetModelSettingsResponse, GetModelSettingsResponses, GetPromptData, GetPromptErrors, GetPromptResponse, GetPromptResponses, GetPromptsData, GetPromptsResponse, GetPromptsResponses, GetProviderCatalogData, GetProviderCatalogErrors, GetProviderCatalogResponse, GetProviderCatalogResponses, GetProviderCatalogTemplateData, GetProviderCatalogTemplateErrors, GetProviderCatalogTemplateResponse, GetProviderCatalogTemplateResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponse, GetProviderModelsResponses, GetRepoFilesData, GetRepoFilesResponse, GetRepoFilesResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponse, GetSessionExtensionsResponses, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponse, GetSessionInsightsResponses, GetSessionResponse, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponse, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsQuery, GetToolsResponse, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponse, GetTunnelStatusResponses, GooseApp, HfGgufFile, HfModelInfo, HfQuantVariant, Icon, ImageContent, ImportAppData, ImportAppError, ImportAppErrors, ImportAppRequest, ImportAppResponse, ImportAppResponse2, ImportAppResponses, ImportSessionData, ImportSessionErrors, ImportSessionRequest, ImportSessionResponse, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponse, InitConfigResponses, InspectJobResponse, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponse, InspectRunningJobResponses, JsonObject, KillJobResponse, KillRunningJobData, KillRunningJobResponses, ListAppsData, ListAppsError, ListAppsErrors, ListAppsRequest, ListAppsResponse, ListAppsResponse2, ListAppsResponses, ListLocalModelsData, ListLocalModelsResponse, ListLocalModelsResponses, ListModelsData, ListModelsResponse, ListModelsResponses, ListRecipeResponse, ListRecipesData, ListRecipesErrors, ListRecipesResponse, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponse, ListSchedulesResponse2, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponse, ListSessionsResponses, LoadedProvider, LocalModelResponse, McpAppResource, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, Message, MessageContent, MessageEvent, MessageMetadata, ModelCapabilities, ModelConfig, ModelDownloadStatus, ModelInfo, ModelInfoData, ModelInfoQuery, ModelInfoResponse, ModelSettings, ModelTemplate, ParseRecipeData, ParseRecipeError, ParseRecipeErrors, ParseRecipeRequest, ParseRecipeResponse, ParseRecipeResponse2, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponse, PauseScheduleResponses, Permission, PermissionLevel, PermissionsMetadata, PrincipalType, PromptContentResponse, PromptsListResponse, ProviderCatalogEntry, ProviderDetails, ProviderEngine, ProviderMetadata, ProvidersData, ProvidersResponse, ProvidersResponse2, ProvidersResponses, ProviderTemplate, ProviderType, RawAudioContent, RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ReadAllConfigData, ReadAllConfigResponse, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, ReadResourceData, ReadResourceErrors, ReadResourceRequest, ReadResourceResponse, ReadResourceResponse2, ReadResourceResponses, ReasoningContent, Recipe, RecipeManifest, RecipeParameter, RecipeParameterInputType, RecipeParameterRequirement, RecipeToYamlData, RecipeToYamlError, RecipeToYamlErrors, RecipeToYamlRequest, RecipeToYamlResponse, RecipeToYamlResponse2, RecipeToYamlResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponse, RecoverConfigResponses, RedactedThinkingContent, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponse, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponse, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionRequest, RemoveExtensionResponse, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponse, ReplyResponses, RepoVariantsResponse, ResetPromptData, ResetPromptErrors, ResetPromptResponse, ResetPromptResponses, ResourceContents, ResourceMetadata, Response, RestartAgentData, RestartAgentErrors, RestartAgentRequest, RestartAgentResponse, RestartAgentResponse2, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentRequest, ResumeAgentResponse, ResumeAgentResponse2, ResumeAgentResponses, RetryConfig, Role, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponse, RunNowHandlerResponses, RunNowResponse, SamplingConfig, SavePromptData, SavePromptErrors, SavePromptRequest, SavePromptResponse, SavePromptResponses, SaveRecipeData, SaveRecipeError, SaveRecipeErrors, SaveRecipeRequest, SaveRecipeResponse, SaveRecipeResponse2, SaveRecipeResponses, ScanRecipeData, ScanRecipeRequest, ScanRecipeResponse, ScanRecipeResponse2, ScanRecipeResponses, ScheduledJob, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeRequest, ScheduleRecipeResponses, SearchHfModelsData, SearchHfModelsErrors, SearchHfModelsResponse, SearchHfModelsResponses, SearchSessionsData, SearchSessionsErrors, SearchSessionsResponse, SearchSessionsResponses, SendTelemetryEventData, SendTelemetryEventResponses, Session, SessionDisplayInfo, SessionExtensionsResponse, SessionInsights, SessionListResponse, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponse, SessionsHandlerResponses, SessionsQuery, SessionType, SetConfigProviderData, SetProviderRequest, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, SetSlashCommandRequest, Settings, SetupResponse, SlashCommand, SlashCommandsResponse, StartAgentData, StartAgentError, StartAgentErrors, StartAgentRequest, StartAgentResponse, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponse, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponse, StartTetrateSetupResponses, StartTunnelData, StartTunnelError, StartTunnelErrors, StartTunnelResponse, StartTunnelResponses, StatusData, StatusResponse, StatusResponses, StopAgentData, StopAgentErrors, StopAgentRequest, StopAgentResponse, StopAgentResponses, StopTunnelData, StopTunnelError, StopTunnelErrors, StopTunnelResponses, SubRecipe, SuccessCheck, SystemInfo, SystemInfoData, SystemInfoResponse, SystemInfoResponses, SystemNotificationContent, SystemNotificationType, TaskSupport, TelemetryEventRequest, Template, TextContent, ThinkingContent, TokenState, Tool, ToolAnnotations, ToolConfirmationRequest, ToolExecution, ToolInfo, ToolPermission, ToolRequest, ToolResponse, TranscribeDictationData, TranscribeDictationErrors, TranscribeDictationResponse, TranscribeDictationResponses, TranscribeRequest, TranscribeResponse, TunnelInfo, TunnelState, UiMetadata, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponse, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderRequest, UpdateCustomProviderResponse, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionRequest, UpdateFromSessionResponses, UpdateModelSettingsData, UpdateModelSettingsErrors, UpdateModelSettingsResponse, UpdateModelSettingsResponses, UpdateProviderRequest, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleRequest, UpdateScheduleResponse, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameRequest, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesError, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesRequest, UpdateSessionUserRecipeValuesResponse, UpdateSessionUserRecipeValuesResponse2, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirRequest, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigQuery, UpsertConfigResponse, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsQuery, UpsertPermissionsResponse, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponse, ValidateConfigResponses, WhisperModelResponse, WindowProps } from './types.gen'; +export type { ActionRequired, ActionRequiredData, AddExtensionData, AddExtensionErrors, AddExtensionRequest, AddExtensionResponse, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponse, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponse, AgentRemoveExtensionResponses, Annotations, Author, AuthorRequest, BackupConfigData, BackupConfigErrors, BackupConfigResponse, BackupConfigResponses, CallToolData, CallToolErrors, CallToolRequest, CallToolResponse, CallToolResponse2, CallToolResponses, CancelDownloadData, CancelDownloadErrors, CancelDownloadResponses, CancelLocalModelDownloadData, CancelLocalModelDownloadErrors, CancelLocalModelDownloadResponses, ChatRequest, CheckProviderData, CheckProviderRequest, ClientOptions, CommandType, ConfigKey, ConfigKeyQuery, ConfigResponse, ConfigureProviderOauthData, ConfigureProviderOauthErrors, ConfigureProviderOauthResponses, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionRequest, ConfirmToolActionResponses, Content, ContentBlock, Conversation, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponse, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeRequest, CreateRecipeResponse, CreateRecipeResponse2, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleRequest, CreateScheduleResponse, CreateScheduleResponses, CspMetadata, DeclarativeProviderConfig, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeRequest, DecodeRecipeResponse, DecodeRecipeResponse2, DecodeRecipeResponses, DeleteLocalModelData, DeleteLocalModelErrors, DeleteLocalModelResponses, DeleteModelData, DeleteModelErrors, DeleteModelResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeRequest, DeleteRecipeResponse, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponse, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DetectProviderData, DetectProviderErrors, DetectProviderRequest, DetectProviderResponse, DetectProviderResponse2, DetectProviderResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponse, DiagnosticsResponses, DictationProvider, DictationProviderStatus, DownloadHfModelData, DownloadHfModelErrors, DownloadHfModelResponse, DownloadHfModelResponses, DownloadModelData, DownloadModelErrors, DownloadModelRequest, DownloadModelResponses, DownloadProgress, DownloadStatus, EmbeddedResource, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeRequest, EncodeRecipeResponse, EncodeRecipeResponse2, EncodeRecipeResponses, Envs, EnvVarConfig, ErrorResponse, ExportAppData, ExportAppError, ExportAppErrors, ExportAppResponse, ExportAppResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponse, ExportSessionResponses, ExtensionConfig, ExtensionData, ExtensionEntry, ExtensionLoadResult, ExtensionQuery, ExtensionResponse, ForkRequest, ForkResponse, ForkSessionData, ForkSessionErrors, ForkSessionResponse, ForkSessionResponses, FrontendToolRequest, GetCanonicalModelInfoData, GetCanonicalModelInfoResponse, GetCanonicalModelInfoResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponse, GetCustomProviderResponses, GetDictationConfigData, GetDictationConfigResponse, GetDictationConfigResponses, GetDownloadProgressData, GetDownloadProgressErrors, GetDownloadProgressResponse, GetDownloadProgressResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponse, GetExtensionsResponses, GetLocalModelDownloadProgressData, GetLocalModelDownloadProgressErrors, GetLocalModelDownloadProgressResponse, GetLocalModelDownloadProgressResponses, GetModelSettingsData, GetModelSettingsErrors, GetModelSettingsResponse, GetModelSettingsResponses, GetPromptData, GetPromptErrors, GetPromptResponse, GetPromptResponses, GetPromptsData, GetPromptsResponse, GetPromptsResponses, GetProviderCatalogData, GetProviderCatalogErrors, GetProviderCatalogResponse, GetProviderCatalogResponses, GetProviderCatalogTemplateData, GetProviderCatalogTemplateErrors, GetProviderCatalogTemplateResponse, GetProviderCatalogTemplateResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponse, GetProviderModelsResponses, GetRepoFilesData, GetRepoFilesResponse, GetRepoFilesResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponse, GetSessionExtensionsResponses, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponse, GetSessionInsightsResponses, GetSessionResponse, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponse, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsQuery, GetToolsResponse, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponse, GetTunnelStatusResponses, GooseApp, HfGgufFile, HfModelInfo, HfQuantVariant, Icon, ImageContent, ImportAppData, ImportAppError, ImportAppErrors, ImportAppRequest, ImportAppResponse, ImportAppResponse2, ImportAppResponses, ImportSessionData, ImportSessionErrors, ImportSessionRequest, ImportSessionResponse, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponse, InitConfigResponses, InspectJobResponse, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponse, InspectRunningJobResponses, JsonObject, KillJobResponse, KillRunningJobData, KillRunningJobResponses, ListAppsData, ListAppsError, ListAppsErrors, ListAppsRequest, ListAppsResponse, ListAppsResponse2, ListAppsResponses, ListLocalModelsData, ListLocalModelsResponse, ListLocalModelsResponses, ListModelsData, ListModelsResponse, ListModelsResponses, ListRecipeResponse, ListRecipesData, ListRecipesErrors, ListRecipesResponse, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponse, ListSchedulesResponse2, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponse, ListSessionsResponses, LoadedProvider, LocalModelResponse, McpAppResource, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, Message, MessageContent, MessageEvent, MessageMetadata, ModelCapabilities, ModelConfig, ModelDownloadStatus, ModelInfo, ModelInfoData, ModelInfoQuery, ModelInfoResponse, ModelSettings, ModelTemplate, ParseRecipeData, ParseRecipeError, ParseRecipeErrors, ParseRecipeRequest, ParseRecipeResponse, ParseRecipeResponse2, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponse, PauseScheduleResponses, Permission, PermissionLevel, PermissionsMetadata, PrincipalType, PromptContentResponse, PromptsListResponse, ProviderCatalogEntry, ProviderDetails, ProviderEngine, ProviderMetadata, ProvidersData, ProvidersResponse, ProvidersResponse2, ProvidersResponses, ProviderTemplate, ProviderType, RawAudioContent, RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ReadAllConfigData, ReadAllConfigResponse, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, ReadResourceData, ReadResourceErrors, ReadResourceRequest, ReadResourceResponse, ReadResourceResponse2, ReadResourceResponses, ReasoningContent, Recipe, RecipeManifest, RecipeParameter, RecipeParameterInputType, RecipeParameterRequirement, RecipeToYamlData, RecipeToYamlError, RecipeToYamlErrors, RecipeToYamlRequest, RecipeToYamlResponse, RecipeToYamlResponse2, RecipeToYamlResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponse, RecoverConfigResponses, RedactedThinkingContent, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponse, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponse, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionRequest, RemoveExtensionResponse, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponse, ReplyResponses, RepoVariantsResponse, ResetPromptData, ResetPromptErrors, ResetPromptResponse, ResetPromptResponses, ResourceContents, ResourceMetadata, Response, RestartAgentData, RestartAgentErrors, RestartAgentRequest, RestartAgentResponse, RestartAgentResponse2, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentRequest, ResumeAgentResponse, ResumeAgentResponse2, ResumeAgentResponses, RetryConfig, Role, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponse, RunNowHandlerResponses, RunNowResponse, SamplingConfig, SavePromptData, SavePromptErrors, SavePromptRequest, SavePromptResponse, SavePromptResponses, SaveRecipeData, SaveRecipeError, SaveRecipeErrors, SaveRecipeRequest, SaveRecipeResponse, SaveRecipeResponse2, SaveRecipeResponses, ScanRecipeData, ScanRecipeRequest, ScanRecipeResponse, ScanRecipeResponse2, ScanRecipeResponses, ScheduledJob, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeRequest, ScheduleRecipeResponses, SearchHfModelsData, SearchHfModelsErrors, SearchHfModelsResponse, SearchHfModelsResponses, SearchSessionsData, SearchSessionsErrors, SearchSessionsResponse, SearchSessionsResponses, SendTelemetryEventData, SendTelemetryEventResponses, Session, SessionDisplayInfo, SessionExtensionsResponse, SessionInsights, SessionListResponse, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponse, SessionsHandlerResponses, SessionsQuery, SessionType, SetConfigProviderData, SetProviderRequest, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, SetSlashCommandRequest, Settings, SetupResponse, SlashCommand, SlashCommandsResponse, StartAgentData, StartAgentError, StartAgentErrors, StartAgentRequest, StartAgentResponse, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponse, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponse, StartTetrateSetupResponses, StartTunnelData, StartTunnelError, StartTunnelErrors, StartTunnelResponse, StartTunnelResponses, StatusData, StatusResponse, StatusResponses, StopAgentData, StopAgentErrors, StopAgentRequest, StopAgentResponse, StopAgentResponses, StopTunnelData, StopTunnelError, StopTunnelErrors, StopTunnelResponses, SubRecipe, SuccessCheck, SystemInfo, SystemInfoData, SystemInfoResponse, SystemInfoResponses, SystemNotificationContent, SystemNotificationType, TaskSupport, TelemetryEventRequest, Template, TextContent, ThinkingContent, TokenState, Tool, ToolAnnotations, ToolConfirmationRequest, ToolExecution, ToolInfo, ToolPermission, ToolRequest, ToolResponse, TranscribeDictationData, TranscribeDictationErrors, TranscribeDictationResponse, TranscribeDictationResponses, TranscribeRequest, TranscribeResponse, TunnelInfo, TunnelState, UiMetadata, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponse, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderRequest, UpdateCustomProviderResponse, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionRequest, UpdateFromSessionResponses, UpdateModelSettingsData, UpdateModelSettingsErrors, UpdateModelSettingsResponse, UpdateModelSettingsResponses, UpdateProviderRequest, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleRequest, UpdateScheduleResponse, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameRequest, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesError, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesRequest, UpdateSessionUserRecipeValuesResponse, UpdateSessionUserRecipeValuesResponse2, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirRequest, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigQuery, UpsertConfigResponse, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsQuery, UpsertPermissionsResponse, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponse, ValidateConfigResponses, WhisperModelResponse, WindowProps } from './types.gen'; diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index ecc688dad2cf..4fea314c474d 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -54,9 +54,9 @@ export type CallToolRequest = { export type CallToolResponse = { _meta?: unknown; - content: Array; - is_error: boolean; - structured_content?: unknown; + content: Array; + isError: boolean; + structuredContent?: unknown; }; export type ChatRequest = { @@ -128,7 +128,29 @@ export type ConfirmToolActionRequest = { sessionId: string; }; -export type Content = RawTextContent | RawImageContent | RawEmbeddedResource | RawAudioContent | RawResource; +export type Content = ({ + type: 'text'; +} & RawTextContent) | ({ + type: 'image'; +} & RawImageContent) | ({ + type: 'resource'; +} & RawEmbeddedResource) | ({ + type: 'audio'; +} & RawAudioContent) | ({ + type: 'resource_link'; +} & RawResource); + +export type ContentBlock = ({ + type: 'text'; +} & RawTextContent) | ({ + type: 'image'; +} & RawImageContent) | ({ + type: 'resource'; +} & RawEmbeddedResource) | ({ + type: 'audio'; +} & RawAudioContent) | ({ + type: 'resource_link'; +} & RawResource); export type Conversation = Array; @@ -1112,7 +1134,7 @@ export type RetryConfig = { timeout_seconds?: number | null; }; -export type Role = string; +export type Role = 'user' | 'assistant'; export type RunNowResponse = { session_id: string; @@ -1317,7 +1339,7 @@ export type SystemNotificationContent = { export type SystemNotificationType = 'thinkingMessage' | 'inlineMessage' | 'creditsExhausted'; -export type TaskSupport = string; +export type TaskSupport = 'forbidden' | 'optional' | 'required'; export type TelemetryEventRequest = { event_name: string; diff --git a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx index c2142df87f24..a6a3d2380024 100644 --- a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx +++ b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx @@ -39,7 +39,6 @@ import { McpAppToolCancelled, McpAppToolInput, McpAppToolInputPartial, - McpAppToolResult, DimensionLayout, OnDisplayModeChange, SamplingCreateMessageParams, @@ -142,7 +141,7 @@ interface McpAppRendererProps { sessionId?: string | null; toolInput?: McpAppToolInput; toolInputPartial?: McpAppToolInputPartial; - toolResult?: McpAppToolResult; + toolResult?: CallToolResult; toolCancelled?: McpAppToolCancelled; append?: (text: string) => void; displayMode?: GooseDisplayMode; @@ -505,14 +504,13 @@ export default function McpAppRenderer({ }, }); - // rmcp serializes Content with a `type` discriminator via #[serde(tag = "type")]. - // Our generated TS types don't reflect this, but the wire format matches CallToolResult.content. return { content: (response.data?.content || []) as unknown as CallToolResult['content'], - isError: response.data?.is_error || false, - structuredContent: response.data?.structured_content as + isError: response.data?.isError || false, + structuredContent: response.data?.structuredContent as | { [key: string]: unknown } | undefined, + _meta: response.data?._meta as { [key: string]: unknown } | undefined, }; }, [sessionId, extensionName] @@ -685,17 +683,6 @@ export default function McpAppRenderer({ effectiveDisplayModes, ]); - const appToolResult = useMemo((): CallToolResult | undefined => { - if (!toolResult) return undefined; - // rmcp serializes Content with a `type` discriminator via #[serde(tag = "type")]. - // Our generated TS types don't reflect this, but the wire format matches CallToolResult.content. - return { - content: toolResult.content as unknown as CallToolResult['content'], - structuredContent: toolResult.structuredContent as { [key: string]: unknown } | undefined, - _meta: toolResult._meta, - }; - }, [toolResult]); - const isToolCancelled = !!toolCancelled; const isError = state.status === 'error'; const isReady = state.status === 'ready'; @@ -736,7 +723,7 @@ export default function McpAppRenderer({ toolInputPartial={toolInputPartial ? { arguments: toolInputPartial.arguments } : undefined} toolCancelled={isToolCancelled} hostContext={hostContext} - toolResult={appToolResult} + toolResult={toolResult} onOpenLink={handleOpenLink} onMessage={handleMessage} onCallTool={handleCallTool} diff --git a/ui/desktop/src/components/McpApps/types.ts b/ui/desktop/src/components/McpApps/types.ts index 144f25760870..44fdd42a7276 100644 --- a/ui/desktop/src/components/McpApps/types.ts +++ b/ui/desktop/src/components/McpApps/types.ts @@ -4,7 +4,6 @@ import type { McpUiToolCancelledNotification, McpUiDisplayMode, } from '@modelcontextprotocol/ext-apps/app-bridge'; -import type { Content } from '../../api'; /** * Space-separated sandbox tokens for iframe permissions. @@ -37,12 +36,6 @@ export type McpAppToolInputPartial = McpUiToolInputPartialNotification['params'] export type McpAppToolCancelled = McpUiToolCancelledNotification['params']; -export type McpAppToolResult = { - content: Content[]; - structuredContent?: unknown; - _meta?: { [key: string]: unknown }; -}; - /** * Callback fired when the display mode changes, either via user-initiated * host-side controls or app-initiated `ui/request-display-mode` changes. diff --git a/ui/desktop/src/components/ToolCallWithResponse.tsx b/ui/desktop/src/components/ToolCallWithResponse.tsx index b99878f8d972..1cf15fdbd65c 100644 --- a/ui/desktop/src/components/ToolCallWithResponse.tsx +++ b/ui/desktop/src/components/ToolCallWithResponse.tsx @@ -17,7 +17,9 @@ import { ChevronRight, FlaskConical } from 'lucide-react'; import { TooltipWrapper } from './settings/providers/subcomponents/buttons/TooltipWrapper'; import MCPUIResourceRenderer from './MCPUIResourceRenderer'; import { isUIResource } from '@mcp-ui/client'; -import { CallToolResponse, Content, EmbeddedResource } from '../api'; +import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; +import { CallToolResponse, ContentBlock, EmbeddedResource } from '../api'; + import McpAppRenderer from './McpApps/McpAppRenderer'; import ToolApprovalButtons from './ToolApprovalButtons'; @@ -64,7 +66,7 @@ interface ToolCallWithResponseProps { isApprovalClicked?: boolean; } -function getToolResultContent(toolResult: Record): Content[] { +function getToolResultContent(toolResult: Record): ContentBlock[] { if (toolResult.status !== 'success') { return []; } @@ -75,8 +77,11 @@ function getToolResultContent(toolResult: Record): Content[] { }); } -function isEmbeddedResource(content: Content): content is EmbeddedResource { - return 'resource' in content && typeof (content as Record).resource === 'object'; +function isEmbeddedResource( + content: ContentBlock +): content is EmbeddedResource & { type: 'resource' } { + const c = content as Record; + return c.type === 'resource' && typeof c.resource === 'object' && c.resource !== null; } interface McpAppWrapperProps { @@ -120,7 +125,9 @@ function McpAppWrapper({ const resultWithMeta = toolResponse?.toolResult as ToolResultWithMeta | undefined; const toolResult = - resultWithMeta?.status === 'success' && resultWithMeta.value ? resultWithMeta.value : undefined; + resultWithMeta?.status === 'success' && resultWithMeta.value + ? (resultWithMeta.value as unknown as CallToolResult) + : undefined; if (!resourceUri) return null; if (requestWithMeta.toolCall.status !== 'success') return null; @@ -217,13 +224,11 @@ export default function ToolCallWithResponse({ !hasMcpAppResourceURI && toolResponse?.toolResult && getToolResultContent(toolResponse.toolResult).map((content, index) => { - const resourceContent = isEmbeddedResource(content) - ? { ...content, type: 'resource' as const } - : null; - if (resourceContent && isUIResource(resourceContent)) { + if (!isEmbeddedResource(content)) return null; + if (isUIResource(content)) { return (
- +
@@ -857,21 +862,22 @@ interface ToolResultViewProps { name: string; arguments: Record; }; - result: Content; + result: ContentBlock; isStartExpanded: boolean; } function ToolResultView({ toolCall, result, isStartExpanded }: ToolResultViewProps) { - const hasText = (c: Content): c is Content & { text: string } => + const hasText = (c: ContentBlock): c is ContentBlock & { text: string } => 'text' in c && typeof (c as Record).text === 'string'; - const hasImage = (c: Content): c is Content & { data: string; mimeType: string } => { + const hasImage = (c: ContentBlock): c is ContentBlock & { data: string; mimeType: string } => { if (!('data' in c && 'mimeType' in c)) return false; const mimeType = (c as Record).mimeType; return typeof mimeType === 'string' && mimeType.startsWith('image'); }; - const hasResource = (c: Content): c is Content & { resource: unknown } => 'resource' in c; + const hasResource = (c: ContentBlock): c is ContentBlock & { resource: unknown } => + 'resource' in c; const wrapMarkdown = (text: string): string => { if (