Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions betafile.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"net/http"
"net/url"
"slices"
"strings"
"time"

"github.com/anthropics/anthropic-sdk-go/internal/apiform"
Expand Down Expand Up @@ -47,8 +48,12 @@ func NewBetaFileService(opts ...option.RequestOption) (r BetaFileService) {
// List Files
func (r *BetaFileService) List(ctx context.Context, params BetaFileListParams, opts ...option.RequestOption) (res *pagination.Page[FileMetadata], err error) {
var raw *http.Response
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(params.Betas) > 0 {
betaStrs := make([]string, len(params.Betas))
for i, v := range params.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14"), option.WithResponseInto(&raw)}, opts...)
Expand All @@ -72,8 +77,12 @@ func (r *BetaFileService) ListAutoPaging(ctx context.Context, params BetaFileLis

// Delete File
func (r *BetaFileService) Delete(ctx context.Context, fileID string, body BetaFileDeleteParams, opts ...option.RequestOption) (res *DeletedFile, err error) {
for _, v := range body.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(body.Betas) > 0 {
betaStrs := make([]string, len(body.Betas))
for i, v := range body.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14")}, opts...)
Expand All @@ -88,8 +97,12 @@ func (r *BetaFileService) Delete(ctx context.Context, fileID string, body BetaFi

// Download File
func (r *BetaFileService) Download(ctx context.Context, fileID string, query BetaFileDownloadParams, opts ...option.RequestOption) (res *http.Response, err error) {
for _, v := range query.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(query.Betas) > 0 {
betaStrs := make([]string, len(query.Betas))
for i, v := range query.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14"), option.WithHeader("Accept", "application/binary")}, opts...)
Expand All @@ -104,8 +117,12 @@ func (r *BetaFileService) Download(ctx context.Context, fileID string, query Bet

// Get File Metadata
func (r *BetaFileService) GetMetadata(ctx context.Context, fileID string, query BetaFileGetMetadataParams, opts ...option.RequestOption) (res *FileMetadata, err error) {
for _, v := range query.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(query.Betas) > 0 {
betaStrs := make([]string, len(query.Betas))
for i, v := range query.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14")}, opts...)
Expand All @@ -120,8 +137,12 @@ func (r *BetaFileService) GetMetadata(ctx context.Context, fileID string, query

// Upload File
func (r *BetaFileService) Upload(ctx context.Context, params BetaFileUploadParams, opts ...option.RequestOption) (res *FileMetadata, err error) {
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(params.Betas) > 0 {
betaStrs := make([]string, len(params.Betas))
for i, v := range params.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14")}, opts...)
Expand Down
25 changes: 19 additions & 6 deletions betamessage.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"net/http"
"slices"
"strings"
"time"

"github.com/anthropics/anthropic-sdk-go/internal/apijson"
Expand Down Expand Up @@ -52,8 +53,12 @@ func NewBetaMessageService(opts ...option.RequestOption) (r BetaMessageService)
//
// Note: If you choose to set a timeout for this request, we recommend 10 minutes.
func (r *BetaMessageService) New(ctx context.Context, params BetaMessageNewParams, opts ...option.RequestOption) (res *BetaMessage, err error) {
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(params.Betas) > 0 {
betaStrs := make([]string, len(params.Betas))
for i, v := range params.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)

Expand Down Expand Up @@ -85,8 +90,12 @@ func (r *BetaMessageService) NewStreaming(ctx context.Context, params BetaMessag
raw *http.Response
err error
)
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(params.Betas) > 0 {
betaStrs := make([]string, len(params.Betas))
for i, v := range params.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append(opts, option.WithJSONSet("stream", true))
Expand All @@ -103,8 +112,12 @@ func (r *BetaMessageService) NewStreaming(ctx context.Context, params BetaMessag
// Learn more about token counting in our
// [user guide](https://docs.claude.com/en/docs/build-with-claude/token-counting)
func (r *BetaMessageService) CountTokens(ctx context.Context, params BetaMessageCountTokensParams, opts ...option.RequestOption) (res *BetaMessageTokensCount, err error) {
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(params.Betas) > 0 {
betaStrs := make([]string, len(params.Betas))
for i, v := range params.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
path := "v1/messages/count_tokens?beta=true"
Expand Down
50 changes: 50 additions & 0 deletions betamessage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"context"
"encoding/json"
"errors"
"net/http"
"os"
"strings"
"testing"

"github.com/anthropics/anthropic-sdk-go"
Expand Down Expand Up @@ -496,3 +498,51 @@ Therefore, the answer is..."}}`,
})
}
}

func TestMultipleBetaHeadersJoinedWithCommas(t *testing.T) {
var capturedHeaders http.Header
middleware := option.WithMiddleware(func(req *http.Request, next option.MiddlewareNext) (*http.Response, error) {
capturedHeaders = req.Header.Clone()
return &http.Response{StatusCode: 200, Body: http.NoBody}, nil
})
client := anthropic.NewClient(
option.WithAPIKey("test-key"),
middleware,
)

_, _ = client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
MaxTokens: 1024,
Messages: []anthropic.BetaMessageParam{{
Content: []anthropic.BetaContentBlockParamUnion{{
OfText: &anthropic.BetaTextBlockParam{Text: "hello"},
}},
Role: anthropic.BetaMessageParamRoleUser,
}},
Model: anthropic.ModelClaudeOpus4_6,
Betas: []anthropic.AnthropicBeta{
anthropic.AnthropicBetaMessageBatches2024_09_24,
anthropic.AnthropicBetaPromptCaching2024_07_31,
},
})

if capturedHeaders == nil {
t.Fatal("Expected middleware to capture headers")
}

betaValues := capturedHeaders.Values("Anthropic-Beta")
// The user-specified betas should be joined with commas in a single header entry
// (not sent as multiple separate header entries)
joined := false
for _, v := range betaValues {
if strings.Contains(v, ",") {
joined = true
parts := strings.Split(v, ",")
if len(parts) < 2 {
t.Fatalf("Expected at least 2 comma-separated values, got: %s", v)
}
}
}
if !joined {
t.Fatalf("Expected beta headers to be comma-separated, but got separate entries: %v", betaValues)
}
}
49 changes: 37 additions & 12 deletions betamessagebatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"slices"
"strings"
"time"

"github.com/anthropics/anthropic-sdk-go/internal/apijson"
Expand Down Expand Up @@ -51,8 +52,12 @@ func NewBetaMessageBatchService(opts ...option.RequestOption) (r BetaMessageBatc
// Learn more about the Message Batches API in our
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
func (r *BetaMessageBatchService) New(ctx context.Context, params BetaMessageBatchNewParams, opts ...option.RequestOption) (res *BetaMessageBatch, err error) {
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(params.Betas) > 0 {
betaStrs := make([]string, len(params.Betas))
for i, v := range params.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24")}, opts...)
Expand All @@ -68,8 +73,12 @@ func (r *BetaMessageBatchService) New(ctx context.Context, params BetaMessageBat
// Learn more about the Message Batches API in our
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
func (r *BetaMessageBatchService) Get(ctx context.Context, messageBatchID string, query BetaMessageBatchGetParams, opts ...option.RequestOption) (res *BetaMessageBatch, err error) {
for _, v := range query.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(query.Betas) > 0 {
betaStrs := make([]string, len(query.Betas))
for i, v := range query.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24")}, opts...)
Expand All @@ -89,8 +98,12 @@ func (r *BetaMessageBatchService) Get(ctx context.Context, messageBatchID string
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
func (r *BetaMessageBatchService) List(ctx context.Context, params BetaMessageBatchListParams, opts ...option.RequestOption) (res *pagination.Page[BetaMessageBatch], err error) {
var raw *http.Response
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(params.Betas) > 0 {
betaStrs := make([]string, len(params.Betas))
for i, v := range params.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24"), option.WithResponseInto(&raw)}, opts...)
Expand Down Expand Up @@ -124,8 +137,12 @@ func (r *BetaMessageBatchService) ListAutoPaging(ctx context.Context, params Bet
// Learn more about the Message Batches API in our
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
func (r *BetaMessageBatchService) Delete(ctx context.Context, messageBatchID string, body BetaMessageBatchDeleteParams, opts ...option.RequestOption) (res *BetaDeletedMessageBatch, err error) {
for _, v := range body.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(body.Betas) > 0 {
betaStrs := make([]string, len(body.Betas))
for i, v := range body.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24")}, opts...)
Expand All @@ -151,8 +168,12 @@ func (r *BetaMessageBatchService) Delete(ctx context.Context, messageBatchID str
// Learn more about the Message Batches API in our
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
func (r *BetaMessageBatchService) Cancel(ctx context.Context, messageBatchID string, body BetaMessageBatchCancelParams, opts ...option.RequestOption) (res *BetaMessageBatch, err error) {
for _, v := range body.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(body.Betas) > 0 {
betaStrs := make([]string, len(body.Betas))
for i, v := range body.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24")}, opts...)
Expand All @@ -178,8 +199,12 @@ func (r *BetaMessageBatchService) ResultsStreaming(ctx context.Context, messageB
raw *http.Response
err error
)
for _, v := range query.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(query.Betas) > 0 {
betaStrs := make([]string, len(query.Betas))
for i, v := range query.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24"), option.WithHeader("Accept", "application/x-jsonl")}, opts...)
Expand Down
17 changes: 13 additions & 4 deletions betamodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"slices"
"strings"
"time"

"github.com/anthropics/anthropic-sdk-go/internal/apijson"
Expand Down Expand Up @@ -45,8 +46,12 @@ func NewBetaModelService(opts ...option.RequestOption) (r BetaModelService) {
// The Models API response can be used to determine information about a specific
// model or resolve a model alias to a model ID.
func (r *BetaModelService) Get(ctx context.Context, modelID string, query BetaModelGetParams, opts ...option.RequestOption) (res *BetaModelInfo, err error) {
for _, v := range query.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(query.Betas) > 0 {
betaStrs := make([]string, len(query.Betas))
for i, v := range query.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
if modelID == "" {
Expand All @@ -64,8 +69,12 @@ func (r *BetaModelService) Get(ctx context.Context, modelID string, query BetaMo
// use in the API. More recently released models are listed first.
func (r *BetaModelService) List(ctx context.Context, params BetaModelListParams, opts ...option.RequestOption) (res *pagination.Page[BetaModelInfo], err error) {
var raw *http.Response
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
if len(params.Betas) > 0 {
betaStrs := make([]string, len(params.Betas))
for i, v := range params.Betas {
betaStrs[i] = fmt.Sprintf("%v", v)
}
opts = append(opts, option.WithHeaderAdd("anthropic-beta", strings.Join(betaStrs, ",")))
}
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
Expand Down
Loading