99
1010 "github.com/docker/docker-agent/pkg/attachment/modelcaps"
1111 "github.com/docker/docker-agent/pkg/chat"
12+ "github.com/docker/docker-agent/pkg/config/latest"
13+ "github.com/docker/docker-agent/pkg/model/provider/base"
14+ "github.com/docker/docker-agent/pkg/modelsdev"
1215)
1316
1417// minJPEG is a minimal JPEG magic-byte header for use in tests.
@@ -51,14 +54,66 @@ func TestConvertDocumentAnthropic_StrategyB64_PDF(t *testing.T) {
5154 assert .Nil (t , blocks [0 ].OfText , "expected no text block for PDF" )
5255}
5356
57+ // TestConvertDocumentAnthropic_QualifiedIDRequired is the regression test for
58+ // the bug where convertUserMultiContent passed only c.ModelConfig.Model (bare
59+ // model name) to convertDocument instead of c.ModelConfig.Provider+"/"+c.ModelConfig.Model.
60+ // When the bare name was used, modelcaps.Load always missed the model and all
61+ // image/PDF attachments were silently dropped.
62+ //
63+ // The test constructs a Client with Provider="anthropic" and Model="claude-sonnet-4-6",
64+ // injects a fake modelsdev.Store, and calls convertUserMultiContent directly.
65+ // The image block must be present in the output — which only happens if the
66+ // fully-qualified "anthropic/claude-sonnet-4-6" was used for the caps lookup.
67+ func TestConvertDocumentAnthropic_QualifiedIDRequired (t * testing.T ) {
68+ store := modelsdev .NewDatabaseStore (& modelsdev.Database {
69+ Providers : map [string ]modelsdev.Provider {
70+ "anthropic" : {
71+ Models : map [string ]modelsdev.Model {
72+ "claude-sonnet-4-6" : {
73+ Modalities : modelsdev.Modalities {
74+ Input : []string {"text" , "image" , "pdf" },
75+ },
76+ },
77+ },
78+ },
79+ },
80+ })
81+
82+ c := & Client {
83+ Config : base.Config {
84+ ModelConfig : latest.ModelConfig {
85+ Provider : "anthropic" ,
86+ Model : "claude-sonnet-4-6" ,
87+ },
88+ },
89+ modelsStore : store ,
90+ }
91+
92+ parts := []chat.MessagePart {
93+ {
94+ Type : chat .MessagePartTypeDocument ,
95+ Document : & chat.Document {
96+ Name : "photo.jpg" ,
97+ MimeType : "image/jpeg" ,
98+ Source : chat.DocumentSource {InlineData : minJPEG },
99+ },
100+ },
101+ }
102+
103+ blocks , err := c .convertUserMultiContent (t .Context (), parts )
104+ require .NoError (t , err )
105+ require .Len (t , blocks , 1 , "image must not be dropped when provider+model ID is used for caps lookup" )
106+ assert .NotNil (t , blocks [0 ].OfImage , "expected native image block" )
107+ }
108+
54109func TestConvertDocumentAnthropic_StrategyTXT (t * testing.T ) {
55110 doc := chat.Document {
56111 Name : "spec.md" ,
57112 MimeType : "text/markdown" ,
58113 Source : chat.DocumentSource {InlineText : "## Specification" },
59114 }
60115
61- blocks , err := convertDocument (t .Context (), doc , "" )
116+ blocks , err := convertDocumentWithCaps (t .Context (), doc , modelcaps. ModelCapabilities {} )
62117 require .NoError (t , err )
63118 require .Len (t , blocks , 1 )
64119 require .NotNil (t , blocks [0 ].OfText )
@@ -74,7 +129,7 @@ func TestConvertDocumentAnthropic_StrategyTXT_Envelope(t *testing.T) {
74129 Source : chat.DocumentSource {InlineText : "some notes" },
75130 }
76131
77- blocks , err := convertDocument (t .Context (), doc , "" )
132+ blocks , err := convertDocumentWithCaps (t .Context (), doc , modelcaps. ModelCapabilities {} )
78133 require .NoError (t , err )
79134 require .Len (t , blocks , 1 )
80135 require .NotNil (t , blocks [0 ].OfText )
@@ -89,7 +144,7 @@ func TestConvertDocumentAnthropic_Drop_NoContent(t *testing.T) {
89144 Source : chat.DocumentSource {},
90145 }
91146
92- blocks , err := convertDocument (t .Context (), doc , "" )
147+ blocks , err := convertDocumentWithCaps (t .Context (), doc , modelcaps. ModelCapabilities {} )
93148 require .NoError (t , err )
94149 assert .Nil (t , blocks , "should be dropped when no inline content" )
95150}
0 commit comments