refactor: upgrade Anthropic SDK to v1.4.0 and adapt provider code

Kayvan Sylvan created

### CHANGES

- Upgrade Anthropic Go SDK dependency to version 1.4.0.
- Adapt provider code to breaking changes in the SDK.
- Update constructors for tool use and thinking parameters.
- Use new `OfText` field for accessing message content.
- Add Claude 4 Opus and Sonnet to documentation.

Change summary

README.md                          |  2 ++
cmd/schema/README.md               |  2 +-
go.mod                             |  2 +-
go.sum                             |  4 ++--
internal/llm/provider/anthropic.go | 17 ++++++-----------
5 files changed, 12 insertions(+), 15 deletions(-)

Detailed changes

README.md 🔗

@@ -203,6 +203,8 @@ OpenCode supports a variety of AI models from different providers:
 
 ### Anthropic
 
+- Claude 4 Sonnet
+- Claude 4 Opus
 - Claude 3.5 Sonnet
 - Claude 3.5 Haiku
 - Claude 3.7 Sonnet

cmd/schema/README.md 🔗

@@ -61,4 +61,4 @@ Here's an example configuration that conforms to the schema:
     }
   }
 }
-```
+```

go.mod 🔗

@@ -7,7 +7,7 @@ require (
 	github.com/JohannesKaufmann/html-to-markdown v1.6.0
 	github.com/PuerkitoBio/goquery v1.9.2
 	github.com/alecthomas/chroma/v2 v2.15.0
-	github.com/anthropics/anthropic-sdk-go v0.2.0-beta.2
+	github.com/anthropics/anthropic-sdk-go v1.4.0
 	github.com/aymanbagabas/go-udiff v0.2.0
 	github.com/bmatcuk/doublestar/v4 v4.8.1
 	github.com/catppuccin/go v0.3.0

go.sum 🔗

@@ -26,8 +26,8 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc
 github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
 github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
 github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
-github.com/anthropics/anthropic-sdk-go v0.2.0-beta.2 h1:h7qxtumNjKPWFv1QM/HJy60MteeW23iKeEtBoY7bYZk=
-github.com/anthropics/anthropic-sdk-go v0.2.0-beta.2/go.mod h1:AapDW22irxK2PSumZiQXYUFvsdQgkwIWlpESweWZI/c=
+github.com/anthropics/anthropic-sdk-go v1.4.0 h1:fU1jKxYbQdQDiEXCxeW5XZRIOwKevn/PMg8Ay1nnUx0=
+github.com/anthropics/anthropic-sdk-go v1.4.0/go.mod h1:AapDW22irxK2PSumZiQXYUFvsdQgkwIWlpESweWZI/c=
 github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
 github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
 github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=

internal/llm/provider/anthropic.go 🔗

@@ -67,7 +67,7 @@ func (a *anthropicClient) convertMessages(messages []message.Message) (anthropic
 		case message.User:
 			content := anthropic.NewTextBlock(msg.Content().String())
 			if cache && !a.options.disableCache {
-				content.OfRequestTextBlock.CacheControl = anthropic.CacheControlEphemeralParam{
+				content.OfText.CacheControl = anthropic.CacheControlEphemeralParam{
 					Type: "ephemeral",
 				}
 			}
@@ -85,7 +85,7 @@ func (a *anthropicClient) convertMessages(messages []message.Message) (anthropic
 			if msg.Content().String() != "" {
 				content := anthropic.NewTextBlock(msg.Content().String())
 				if cache && !a.options.disableCache {
-					content.OfRequestTextBlock.CacheControl = anthropic.CacheControlEphemeralParam{
+					content.OfText.CacheControl = anthropic.CacheControlEphemeralParam{
 						Type: "ephemeral",
 					}
 				}
@@ -98,7 +98,7 @@ func (a *anthropicClient) convertMessages(messages []message.Message) (anthropic
 				if err != nil {
 					continue
 				}
-				blocks = append(blocks, anthropic.ContentBlockParamOfRequestToolUseBlock(toolCall.ID, inputMap, toolCall.Name))
+				blocks = append(blocks, anthropic.NewToolUseBlock(toolCall.ID, inputMap, toolCall.Name))
 			}
 
 			if len(blocks) == 0 {
@@ -167,17 +167,12 @@ func (a *anthropicClient) preparedMessages(messages []anthropic.MessageParam, to
 	temperature := anthropic.Float(0)
 	if isUser {
 		for _, m := range lastMessage.Content {
-			if m.OfRequestTextBlock != nil && m.OfRequestTextBlock.Text != "" {
-				messageContent = m.OfRequestTextBlock.Text
+			if m.OfText != nil && m.OfText.Text != "" {
+				messageContent = m.OfText.Text
 			}
 		}
 		if messageContent != "" && a.options.shouldThink != nil && a.options.shouldThink(messageContent) {
-			thinkingParam = anthropic.ThinkingConfigParamUnion{
-				OfThinkingConfigEnabled: &anthropic.ThinkingConfigEnabledParam{
-					BudgetTokens: int64(float64(a.providerOptions.maxTokens) * 0.8),
-					Type:         "enabled",
-				},
-			}
+			thinkingParam = anthropic.ThinkingConfigParamOfEnabled(int64(float64(a.providerOptions.maxTokens) * 0.8))
 			temperature = anthropic.Float(1)
 		}
 	}