convertMCPToolResponse translates a workspace agent MCP tool response into a fantasy.ToolResponse. Text content blocks are collected and joined; binary content (image/media) is returned only when no text is available, matching the mcpclient conversion strategy.
( resp workspacesdk.CallMCPToolResponse, )
| 115 | // only when no text is available, matching the mcpclient |
| 116 | // conversion strategy. |
| 117 | func convertMCPToolResponse( |
| 118 | resp workspacesdk.CallMCPToolResponse, |
| 119 | ) fantasy.ToolResponse { |
| 120 | var ( |
| 121 | textParts []string |
| 122 | binaryResult *fantasy.ToolResponse |
| 123 | ) |
| 124 | |
| 125 | for _, c := range resp.Content { |
| 126 | switch c.Type { |
| 127 | case "text": |
| 128 | textParts = append(textParts, strings.ToValidUTF8(c.Text, "\uFFFD")) |
| 129 | case "image", "audio": |
| 130 | if c.Data == "" { |
| 131 | continue |
| 132 | } |
| 133 | data, err := base64.StdEncoding.DecodeString(c.Data) |
| 134 | if err != nil { |
| 135 | textParts = append(textParts, |
| 136 | "[binary decode error: "+err.Error()+"]", |
| 137 | ) |
| 138 | continue |
| 139 | } |
| 140 | if binaryResult == nil { |
| 141 | r := fantasy.ToolResponse{ |
| 142 | Type: c.Type, |
| 143 | Data: data, |
| 144 | MediaType: c.MediaType, |
| 145 | IsError: resp.IsError, |
| 146 | } |
| 147 | binaryResult = &r |
| 148 | } |
| 149 | default: |
| 150 | textParts = append(textParts, strings.ToValidUTF8(c.Text, "\uFFFD")) |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | // Prefer text content. Only fall back to binary when no |
| 155 | // text was collected. |
| 156 | if len(textParts) > 0 { |
| 157 | r := fantasy.NewTextResponse( |
| 158 | strings.Join(textParts, "\n"), |
| 159 | ) |
| 160 | r.IsError = resp.IsError |
| 161 | return r |
| 162 | } |
| 163 | if binaryResult != nil { |
| 164 | return *binaryResult |
| 165 | } |
| 166 | r := fantasy.NewTextResponse("") |
| 167 | r.IsError = resp.IsError |
| 168 | return r |
| 169 | } |
no test coverage detected