From 50b146affd9ba5e2779153ca28e87eb447552f86 Mon Sep 17 00:00:00 2001 From: Tai Groot Date: Fri, 27 Feb 2026 01:48:51 -0500 Subject: [PATCH] feat: add Betas support for Anthropic provider options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a Betas field to ProviderOptions that allows specifying beta features to enable via the anthropic-beta header. This is needed for features like the 1M context window on AWS Bedrock (context-1m-2025-08-07). The betas are passed as request options via option.WithHeaderAdd() and the bedrock middleware in the SDK automatically moves these headers into the anthropic_beta JSON body field. 🐊 Generated with Crush Assisted-by: AWS Claude Opus 4.5 via Crush --- providers/anthropic/anthropic.go | 21 +++++++++++++-------- providers/anthropic/provider_options.go | 2 ++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/providers/anthropic/anthropic.go b/providers/anthropic/anthropic.go index 4b593408d..cba30c1c3 100644 --- a/providers/anthropic/anthropic.go +++ b/providers/anthropic/anthropic.go @@ -216,19 +216,24 @@ func (a languageModel) Provider() string { return a.provider } -func (a languageModel) prepareParams(call fantasy.Call) (*anthropic.MessageNewParams, []fantasy.CallWarning, error) { +func (a languageModel) prepareParams(call fantasy.Call) (*anthropic.MessageNewParams, []option.RequestOption, []fantasy.CallWarning, error) { params := &anthropic.MessageNewParams{} + var requestOpts []option.RequestOption providerOptions := &ProviderOptions{} if v, ok := call.ProviderOptions[Name]; ok { providerOptions, ok = v.(*ProviderOptions) if !ok { - return nil, nil, &fantasy.Error{Title: "invalid argument", Message: "anthropic provider options should be *anthropic.ProviderOptions"} + return nil, nil, nil, &fantasy.Error{Title: "invalid argument", Message: "anthropic provider options should be *anthropic.ProviderOptions"} } } sendReasoning := true if providerOptions.SendReasoning != nil { sendReasoning = *providerOptions.SendReasoning } + // Add beta headers for features like 1M context window on Bedrock + for _, beta := range providerOptions.Betas { + requestOpts = append(requestOpts, option.WithHeaderAdd("anthropic-beta", beta)) + } systemBlocks, messages, warnings := toPrompt(call.Prompt, sendReasoning) if call.FrequencyPenalty != nil { @@ -273,7 +278,7 @@ func (a languageModel) prepareParams(call fantasy.Call) (*anthropic.MessageNewPa params.Thinking.OfAdaptive = &adaptive case providerOptions.Thinking != nil: if providerOptions.Thinking.BudgetTokens == 0 { - return nil, nil, &fantasy.Error{Title: "no budget", Message: "thinking requires budget"} + return nil, nil, nil, &fantasy.Error{Title: "no budget", Message: "thinking requires budget"} } params.Thinking = anthropic.ThinkingConfigParamOfEnabled(providerOptions.Thinking.BudgetTokens) if call.Temperature != nil { @@ -315,7 +320,7 @@ func (a languageModel) prepareParams(call fantasy.Call) (*anthropic.MessageNewPa warnings = append(warnings, toolWarnings...) } - return params, warnings, nil + return params, requestOpts, warnings, nil } func (a *provider) Name() string { @@ -767,11 +772,11 @@ func mapFinishReason(finishReason string) fantasy.FinishReason { // Generate implements fantasy.LanguageModel. func (a languageModel) Generate(ctx context.Context, call fantasy.Call) (*fantasy.Response, error) { - params, warnings, err := a.prepareParams(call) + params, requestOpts, warnings, err := a.prepareParams(call) if err != nil { return nil, err } - response, err := a.client.Messages.New(ctx, *params) + response, err := a.client.Messages.New(ctx, *params, requestOpts...) if err != nil { return nil, toProviderErr(err) } @@ -844,12 +849,12 @@ func (a languageModel) Generate(ctx context.Context, call fantasy.Call) (*fantas // Stream implements fantasy.LanguageModel. func (a languageModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.StreamResponse, error) { - params, warnings, err := a.prepareParams(call) + params, requestOpts, warnings, err := a.prepareParams(call) if err != nil { return nil, err } - stream := a.client.Messages.NewStreaming(ctx, *params) + stream := a.client.Messages.NewStreaming(ctx, *params, requestOpts...) acc := anthropic.Message{} return func(yield func(fantasy.StreamPart) bool) { if len(warnings) > 0 { diff --git a/providers/anthropic/provider_options.go b/providers/anthropic/provider_options.go index ad6f6107b..1d2dd92ee 100644 --- a/providers/anthropic/provider_options.go +++ b/providers/anthropic/provider_options.go @@ -61,6 +61,8 @@ type ProviderOptions struct { Thinking *ThinkingProviderOption `json:"thinking"` Effort *Effort `json:"effort"` DisableParallelToolUse *bool `json:"disable_parallel_tool_use"` + // Betas is a list of beta features to enable (e.g., "context-1m-2025-08-07" for 1M context on Bedrock). + Betas []string `json:"betas,omitempty"` } // Options implements the ProviderOptions interface.