feat: support attachments

Carlos Alexandro Becker created

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

Change summary

cmd/copilot/main.go                     | 31 ++++++++++++++++++++++++++
internal/providers/configs/copilot.json | 32 ++++++++++++++++----------
2 files changed, 50 insertions(+), 13 deletions(-)

Detailed changes

cmd/copilot/main.go 🔗

@@ -157,6 +157,7 @@ func modelsToCatwalk(m []Model) []catwalk.Model {
 
 func modelToCatwalk(m Model) catwalk.Model {
 	canReason, reasoningLevels, defaultReasoning := detectReasoningCapabilities(m)
+	supportsAttachments := detectAttachmentSupport(m)
 
 	return catwalk.Model{
 		ID:                     m.ID,
@@ -166,6 +167,7 @@ func modelToCatwalk(m Model) catwalk.Model {
 		CanReason:              canReason,
 		ReasoningLevels:        reasoningLevels,
 		DefaultReasoningEffort: defaultReasoning,
+		SupportsImages:         supportsAttachments,
 	}
 }
 
@@ -191,6 +193,35 @@ func detectReasoningCapabilities(m Model) (canReason bool, levels []string, defa
 	return false, nil, ""
 }
 
+func detectAttachmentSupport(m Model) bool {
+	// Claude models support attachments (vision/multimodal)
+	if strings.HasPrefix(m.ID, "claude-") {
+		return true
+	}
+
+	// Gemini models support attachments (vision/multimodal)
+	if strings.HasPrefix(m.ID, "gemini-") {
+		return true
+	}
+
+	// GPT-5 models support attachments (based on OpenRouter pattern)
+	if strings.HasPrefix(m.ID, "gpt-5") {
+		return true
+	}
+
+	// Older GPT models do not support attachments
+	if strings.HasPrefix(m.ID, "gpt-4") || strings.HasPrefix(m.ID, "gpt-3.5") {
+		return false
+	}
+
+	// Grok models - only grok-4 supports attachments
+	if m.ID == "grok-4" || strings.HasPrefix(m.ID, "grok-4-") {
+		return true
+	}
+
+	return false
+}
+
 func copilotToken() string {
 	if token := os.Getenv("COPILOT_TOKEN"); token != "" {
 		return token

internal/providers/configs/copilot.json 🔗

@@ -16,7 +16,7 @@
       "context_window": 144000,
       "default_max_tokens": 16000,
       "can_reason": true,
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -29,7 +29,7 @@
       "context_window": 160000,
       "default_max_tokens": 16000,
       "can_reason": true,
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -42,7 +42,7 @@
       "context_window": 216000,
       "default_max_tokens": 16000,
       "can_reason": true,
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -55,7 +55,7 @@
       "context_window": 144000,
       "default_max_tokens": 16000,
       "can_reason": true,
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -68,7 +68,7 @@
       "context_window": 128000,
       "default_max_tokens": 64000,
       "can_reason": true,
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -113,7 +113,7 @@
         "high"
       ],
       "default_reasoning_effort": "medium",
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -132,7 +132,7 @@
         "high"
       ],
       "default_reasoning_effort": "medium",
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -151,7 +151,7 @@
         "high"
       ],
       "default_reasoning_effort": "medium",
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -170,7 +170,7 @@
         "high"
       ],
       "default_reasoning_effort": "medium",
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -189,7 +189,7 @@
         "high"
       ],
       "default_reasoning_effort": "medium",
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -208,7 +208,7 @@
         "high"
       ],
       "default_reasoning_effort": "medium",
-      "supports_attachments": false,
+      "supports_attachments": true,
       "options": {}
     },
     {
@@ -220,8 +220,14 @@
       "cost_per_1m_out_cached": 0,
       "context_window": 400000,
       "default_max_tokens": 128000,
-      "can_reason": false,
-      "supports_attachments": false,
+      "can_reason": true,
+      "reasoning_levels": [
+        "low",
+        "medium",
+        "high"
+      ],
+      "default_reasoning_effort": "medium",
+      "supports_attachments": true,
       "options": {}
     },
     {