@@ -831,7 +831,6 @@ func toPrompt(prompt fantasy.Prompt, sendReasoningData bool) ([]anthropic.TextBl
if !ok {
continue
}
- // TODO: handle other file types
switch {
case strings.HasPrefix(file.MediaType, "image/"):
base64Encoded := base64.StdEncoding.EncodeToString(file.Data)
@@ -840,10 +839,22 @@ func toPrompt(prompt fantasy.Prompt, sendReasoningData bool) ([]anthropic.TextBl
imageBlock.OfImage.CacheControl = anthropic.NewCacheControlEphemeralParam()
}
anthropicContent = append(anthropicContent, imageBlock)
+ case file.MediaType == "application/pdf":
+ base64Encoded := base64.StdEncoding.EncodeToString(file.Data)
+ docBlock := anthropic.NewDocumentBlock(anthropic.Base64PDFSourceParam{
+ Data: base64Encoded,
+ })
+ if cacheControl != nil {
+ docBlock.OfDocument.CacheControl = anthropic.NewCacheControlEphemeralParam()
+ }
+ anthropicContent = append(anthropicContent, docBlock)
case strings.HasPrefix(file.MediaType, "text/"):
documentBlock := anthropic.NewDocumentBlock(anthropic.PlainTextSourceParam{
Data: string(file.Data),
})
+ if cacheControl != nil {
+ documentBlock.OfDocument.CacheControl = anthropic.NewCacheControlEphemeralParam()
+ }
anthropicContent = append(anthropicContent, documentBlock)
}
}
@@ -1050,7 +1061,7 @@ func toPrompt(prompt fantasy.Prompt, sendReasoningData bool) ([]anthropic.TextBl
func hasVisibleUserContent(content []anthropic.ContentBlockParamUnion) bool {
for _, block := range content {
- if block.OfText != nil || block.OfImage != nil || block.OfToolResult != nil {
+ if block.OfText != nil || block.OfImage != nil || block.OfDocument != nil || block.OfToolResult != nil {
return true
}
}
@@ -262,6 +262,50 @@ func TestToPrompt_DropsEmptyMessages(t *testing.T) {
require.Empty(t, warnings)
})
+ t.Run("should keep user messages with PDF content", func(t *testing.T) {
+ t.Parallel()
+
+ prompt := fantasy.Prompt{
+ {
+ Role: fantasy.MessageRoleUser,
+ Content: []fantasy.MessagePart{
+ fantasy.FilePart{
+ Data: []byte("fake pdf data"),
+ MediaType: "application/pdf",
+ },
+ },
+ },
+ }
+
+ systemBlocks, messages, warnings := toPrompt(prompt, true)
+
+ require.Empty(t, systemBlocks)
+ require.Len(t, messages, 1)
+ require.Empty(t, warnings)
+ })
+
+ t.Run("should keep user messages with text document content", func(t *testing.T) {
+ t.Parallel()
+
+ prompt := fantasy.Prompt{
+ {
+ Role: fantasy.MessageRoleUser,
+ Content: []fantasy.MessagePart{
+ fantasy.FilePart{
+ Data: []byte("# Hello World\nSome markdown content"),
+ MediaType: "text/markdown",
+ },
+ },
+ },
+ }
+
+ systemBlocks, messages, warnings := toPrompt(prompt, true)
+
+ require.Empty(t, systemBlocks)
+ require.Len(t, messages, 1)
+ require.Empty(t, warnings)
+ })
+
t.Run("should drop user messages without visible content", func(t *testing.T) {
t.Parallel()
@@ -271,7 +315,7 @@ func TestToPrompt_DropsEmptyMessages(t *testing.T) {
Content: []fantasy.MessagePart{
fantasy.FilePart{
Data: []byte("not supported"),
- MediaType: "application/pdf",
+ MediaType: "application/zip",
},
},
},