feat: support `text/*` files (#100)

Carlos Alexandro Becker created

Change summary

providers/anthropic/anthropic.go               | 22 +++++++++++--------
providers/openai/language_model_hooks.go       |  7 ++++++
providers/openaicompat/language_model_hooks.go |  7 ++++++
3 files changed, 27 insertions(+), 9 deletions(-)

Detailed changes

providers/anthropic/anthropic.go 🔗

@@ -726,16 +726,20 @@ func toPrompt(prompt fantasy.Prompt, sendReasoningData bool) ([]anthropic.TextBl
 								continue
 							}
 							// TODO: handle other file types
-							if !strings.HasPrefix(file.MediaType, "image/") {
-								continue
-							}
-
-							base64Encoded := base64.StdEncoding.EncodeToString(file.Data)
-							imageBlock := anthropic.NewImageBlockBase64(file.MediaType, base64Encoded)
-							if cacheControl != nil {
-								imageBlock.OfImage.CacheControl = anthropic.NewCacheControlEphemeralParam()
+							switch {
+							case strings.HasPrefix(file.MediaType, "image/"):
+								base64Encoded := base64.StdEncoding.EncodeToString(file.Data)
+								imageBlock := anthropic.NewImageBlockBase64(file.MediaType, base64Encoded)
+								if cacheControl != nil {
+									imageBlock.OfImage.CacheControl = anthropic.NewCacheControlEphemeralParam()
+								}
+								anthropicContent = append(anthropicContent, imageBlock)
+							case strings.HasPrefix(file.MediaType, "text/"):
+								documentBlock := anthropic.NewDocumentBlock(anthropic.PlainTextSourceParam{
+									Data: string(file.Data),
+								})
+								anthropicContent = append(anthropicContent, documentBlock)
 							}
-							anthropicContent = append(anthropicContent, imageBlock)
 						}
 					}
 				} else if msg.Role == fantasy.MessageRoleTool {

providers/openai/language_model_hooks.go 🔗

@@ -363,6 +363,13 @@ func DefaultToPrompt(prompt fantasy.Prompt, _, _ string) ([]openai.ChatCompletio
 					}
 
 					switch {
+					case strings.HasPrefix(filePart.MediaType, "text/"):
+						base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
+						documentBlock := openai.ChatCompletionContentPartFileFileParam{
+							FileData: param.NewOpt(base64Encoded),
+						}
+						content = append(content, openai.FileContentPart(documentBlock))
+
 					case strings.HasPrefix(filePart.MediaType, "image/"):
 						// Handle image files
 						base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)

providers/openaicompat/language_model_hooks.go 🔗

@@ -209,6 +209,13 @@ func ToPromptFunc(prompt fantasy.Prompt, _, _ string) ([]openaisdk.ChatCompletio
 					}
 
 					switch {
+					case strings.HasPrefix(filePart.MediaType, "text/"):
+						base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
+						documentBlock := openaisdk.ChatCompletionContentPartFileFileParam{
+							FileData: param.NewOpt(base64Encoded),
+						}
+						content = append(content, openaisdk.FileContentPart(documentBlock))
+
 					case strings.HasPrefix(filePart.MediaType, "image/"):
 						// Handle image files
 						base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)