From 401b263991df252477f2a23140ef8ed5e042ae92 Mon Sep 17 00:00:00 2001 From: HugeFrog24 <62775760+HugeFrog24@users.noreply.github.com> Date: Sun, 25 Oct 2026 13:34:39 +0100 Subject: [PATCH] Upgrade dependencies and toolchain; migrate to Claude API 2026-10-21 Toolchain and CI: - Go 1.27 (go directive 1.27.0, CI 1.27.3) - actions/checkout v7, actions/setup-go v7 - golangci-lint v2.15.0, gosec v2.30.0 - Dockerfile: drop obsolete -a -installsuffix cgo build flags Go modules: - anthropic-sdk-go v1.71.0 -> v2.3.0 (new /v2 module path, API version 2026-10-21); go-telegram/bot v1.27.0; x/sync v0.24.0; indirects to latest - BetaMessageParam is now a per-role union: build assistant turns with OfAssistant and read content through the role in the cache helper - Pass the Anthropic API key only when set: v2 sends an explicitly passed credential as is, so an empty key became an empty bearer token instead of falling back to the SDK's default credential chain as v1 did API 2026-10-21 / deprecations: - Stop sending temperature (rejected on every model); the config key is still parsed and a startup notice flags it - Name refusals in the empty-response error instead of reporting an unexpected response format - ElevenLabs STT: scribe_v1 (deprecated) -> scribe_v2 - Template config: claude-haiku-5-5 with effort low, temperature removed Docs: replace the unsupported `go get -u` install step, document the ignored temperature key, default-on thinking, and per-model effort defaults. --- .github/workflows/go-ci.yaml | 18 ++--- Dockerfile | 2 +- README.md | 12 ++-- anthropic.go | 20 +++--- anthropic_files.go | 2 +- anthropic_test.go | 14 ++-- bot.go | 25 +++++-- config.go | 7 +- config/default.json | 4 +- elevenlabs.go | 2 +- go.mod | 28 +++++--- go.sum | 135 ++++++++++++++++++++++++++++++----- handlers.go | 2 +- prompt_cache_test.go | 20 +++--- 14 files changed, 210 insertions(+), 81 deletions(-) diff --git a/.github/workflows/go-ci.yaml b/.github/workflows/go-ci.yaml index 09883eb..da1482a 100644 --- a/.github/workflows/go-ci.yaml +++ b/.github/workflows/go-ci.yaml @@ -7,28 +7,28 @@ on: branches: [ main ] env: - GO_VERSION: '1.27.1' + GO_VERSION: '1.27.3' jobs: # Lint job lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 with: go-version: ${{ env.GO_VERSION }} - uses: golangci/golangci-lint-action@v9 with: - version: v2.13.2 + version: v2.15.0 args: --timeout 5m # Test job test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 with: go-version: ${{ env.GO_VERSION }} - run: go test ./... -v @@ -37,13 +37,13 @@ jobs: security: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 with: go-version: ${{ env.GO_VERSION }} # gosec is installed rather than run as its container action: the # published image ships its own Go, which lags behind and fails to load # the module ("go.mod requires go >= X"). Installing it here builds gosec # with the toolchain above, so CI's Go version is ours to choose. - - run: go install github.com/securego/gosec/v2/cmd/gosec@v2.29.0 + - run: go install github.com/securego/gosec/v2/cmd/gosec@v2.30.0 - run: gosec ./... diff --git a/Dockerfile b/Dockerfile index 6300eb7..7ce5aac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN go mod download COPY . . # Build the application -RUN CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -o telegram-bot . +RUN CGO_ENABLED=1 GOOS=linux go build -o telegram-bot . # Runtime stage FROM alpine:latest diff --git a/README.md b/README.md index cd7cc93..12cbabc 100644 --- a/README.md +++ b/README.md @@ -40,12 +40,7 @@ A scalable, multi-bot solution for Telegram using Go, GORM, and the Anthropic AP ### Native Deployment -1. Install using `go get`: - - ```bash - go get -u github.com/HugeFrog24/go-telegram-bot - cd go-telegram-bot - ``` +1. Clone the repository as above. Building needs Go 1.27 or later and a C compiler, because the SQLite driver uses cgo. 2. Configure as above, then build: ```bash @@ -73,10 +68,11 @@ Each bot is one JSON file in `config/` (see `config/default.json` for the templa | Key | Type | Default | Description | | ------------------ | ------ | ----------- | ----------- | -| `max_tokens` | number | `1000` | Maximum output tokens per reply. **Thinking tokens count toward this limit** — raise it (e.g. `4000`+) whenever `thinking` is `"adaptive"`, or a turn can spend the whole budget on reasoning and produce no text. | +| `max_tokens` | number | `1000` | Maximum output tokens per reply. **Thinking tokens count toward this limit** — raise it (e.g. `4000`+) whenever `thinking` is `"adaptive"`, or a turn can spend the whole budget on reasoning and produce no text. Claude 5-generation models (Haiku 5.5, Sonnet 5 and later, Opus 5 and later, Fable) think even when `thinking` is omitted; on those, keep `effort` low or raise this limit. | +| `temperature` | number | *(ignored)* | No longer sent: since API version `2026-10-21` the Claude API rejects `temperature`, `top_p` and `top_k` on every model. Old configs still load, and the bot logs a startup notice; remove the key. | | `thinking` | string | *(omitted)* | Reasoning mode: `"adaptive"` (the model decides when and how much to think) or `"disabled"`. Omit the key entirely to use the model's own API default. If the configured model doesn't support the chosen mode, the API rejects the request with a 400 — owners/admins see the raw error, regular users get the generic fallback. Check [Anthropic's model docs](https://platform.claude.com/docs/en/build-with-claude/adaptive-thinking) for per-model support. | | `thinking_display` | string | *(omitted)* | `"summarized"` or `"omitted"`. Only valid together with `"thinking": "adaptive"`. Controls whether the API returns a readable summary of the reasoning (logged, never sent to chat). Thinking is billed the same either way; when omitted, the API's per-model default applies. | -| `effort` | string | *(omitted)* | `"low"`, `"medium"`, `"high"`, `"xhigh"` or `"max"`. Caps how much reasoning and token spend a turn may use; the API default is `high`. For short-reply chat bots `"low"` or `"medium"` cuts cost noticeably. Rejected with a 400 on models older than Claude 4.6 (Haiku 4.5, Sonnet 4.5) — omit it there. | +| `effort` | string | *(omitted)* | `"low"`, `"medium"`, `"high"`, `"xhigh"` or `"max"`. Caps how much reasoning and token spend a turn may use; the API default is `high` on most models and `medium` on Haiku 5.5 and Opus 5.5. For short-reply chat bots `"low"` or `"medium"` cuts cost noticeably. Rejected with a 400 on models older than Claude 4.6 (Haiku 4.5, Sonnet 4.5) — omit it there. | | `debounce_ms` | number | *(omitted)* | Quiet window, in milliseconds, for coalescing rapid follow-up messages into a single turn. Omit or set `0` to disable. See [Coalescing rapid messages](#coalescing-rapid-messages) below. | | `stream_drafts` | bool | `false` | Streams each reply into one Telegram draft that grows in place, with a native Stop button, and sends it as a single message when done. Private chats only. See [Draft streaming and the Stop button](#draft-streaming-and-the-stop-button) below. | | `cache_history` | bool | `true` | Places a prompt-cache breakpoint on the trailing conversation block, so each turn reads the prior history from cache instead of reprocessing it at full price. Set `false` to cache only the system prompt. | diff --git a/anthropic.go b/anthropic.go index 47da324..9263481 100644 --- a/anthropic.go +++ b/anthropic.go @@ -9,8 +9,8 @@ import ( "sync/atomic" "time" - "github.com/anthropics/anthropic-sdk-go" - "github.com/anthropics/anthropic-sdk-go/packages/param" + "github.com/anthropics/anthropic-sdk-go/v2" + "github.com/anthropics/anthropic-sdk-go/v2/packages/param" ) var ErrModelNotFound = errors.New("model not found or deprecated") @@ -58,10 +58,6 @@ func (b *Bot) getAnthropicResponse(ctx context.Context, chatID int64, messages [ params.System = blocks } - if b.config.Temperature != nil { - params.Temperature = param.NewOpt(float64(*b.config.Temperature)) - } - if thinking, ok := thinkingParamFromConfig(b.config.Thinking, b.config.ThinkingDisplay); ok { params.Thinking = thinking } @@ -159,7 +155,7 @@ func (b *Bot) getAnthropicResponse(ctx context.Context, chatID int64, messages [ } if full == "" { - return "", emptyStreamError(string(lastMsg.StopReason), + return "", emptyStreamError(string(lastMsg.StopReason), string(lastMsg.StopDetails.Category), lastMsg.Usage.OutputTokensDetails.ThinkingTokens, params.MaxTokens) } return full, nil @@ -466,10 +462,16 @@ func joinNonEmpty(a, b string) string { } } -func emptyStreamError(stopReason string, thinkingTokens, maxTokens int64) error { - if stopReason == "max_tokens" { +func emptyStreamError(stopReason, refusalCategory string, thinkingTokens, maxTokens int64) error { + switch stopReason { + case "max_tokens": return fmt.Errorf("output budget exhausted before any text (thinking used %d of %d max_tokens) - raise max_tokens", thinkingTokens, maxTokens) + case "refusal": + if refusalCategory == "" { + return fmt.Errorf("the model declined the request (refusal)") + } + return fmt.Errorf("the model declined the request (refusal, category %s)", refusalCategory) } return fmt.Errorf("unexpected response format from Anthropic") } diff --git a/anthropic_files.go b/anthropic_files.go index 79ed408..41ab201 100644 --- a/anthropic_files.go +++ b/anthropic_files.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/anthropics/anthropic-sdk-go" + "github.com/anthropics/anthropic-sdk-go/v2" ) const fileNotFoundPrefix = "File not found: " diff --git a/anthropic_test.go b/anthropic_test.go index 207a967..ec597ba 100644 --- a/anthropic_test.go +++ b/anthropic_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/anthropics/anthropic-sdk-go" + "github.com/anthropics/anthropic-sdk-go/v2" ) func TestTimeContextFor(t *testing.T) { @@ -295,16 +295,22 @@ func TestFetchHosts(t *testing.T) { } func TestEmptyStreamError(t *testing.T) { - err := emptyStreamError("max_tokens", 3900, 4000) + err := emptyStreamError("max_tokens", "", 3900, 4000) for _, want := range []string{"output budget exhausted", "3900", "4000"} { if !strings.Contains(err.Error(), want) { t.Errorf("max_tokens case: %q missing %q", err.Error(), want) } } - if got := emptyStreamError("end_turn", 0, 1000).Error(); got != "unexpected response format from Anthropic" { + if got := emptyStreamError("refusal", "cyber", 0, 1000).Error(); got != "the model declined the request (refusal, category cyber)" { + t.Errorf("refusal case = %q", got) + } + if got := emptyStreamError("refusal", "", 0, 1000).Error(); got != "the model declined the request (refusal)" { + t.Errorf("uncategorized refusal case = %q", got) + } + if got := emptyStreamError("end_turn", "", 0, 1000).Error(); got != "unexpected response format from Anthropic" { t.Errorf("generic case = %q", got) } - if got := emptyStreamError("", 0, 1000).Error(); got != "unexpected response format from Anthropic" { + if got := emptyStreamError("", "", 0, 1000).Error(); got != "unexpected response format from Anthropic" { t.Errorf("no-stop-reason case = %q", got) } } diff --git a/bot.go b/bot.go index 2264930..2754e3e 100644 --- a/bot.go +++ b/bot.go @@ -8,8 +8,8 @@ import ( "sync" "time" - "github.com/anthropics/anthropic-sdk-go" - "github.com/anthropics/anthropic-sdk-go/option" + "github.com/anthropics/anthropic-sdk-go/v2" + "github.com/anthropics/anthropic-sdk-go/v2/option" "github.com/go-telegram/bot" "github.com/go-telegram/bot/models" "gorm.io/gorm" @@ -83,7 +83,13 @@ func NewBot(db *gorm.DB, config BotConfig, clock Clock, tgClient TelegramClient) return nil, err } - anthropicClient := anthropic.NewClient(option.WithAPIKey(config.AnthropicAPIKey)) + // An explicitly passed credential is used as is, so an empty key would go + // out as an empty bearer token; leave it out to use the SDK's default chain. + var anthropicOpts []option.RequestOption + if config.AnthropicAPIKey != "" { + anthropicOpts = append(anthropicOpts, option.WithAPIKey(config.AnthropicAPIKey)) + } + anthropicClient := anthropic.NewClient(anthropicOpts...) b := &Bot{ db: db, @@ -339,10 +345,9 @@ func (b *Bot) buildContextMessages(chatMemory *ChatMemory) []anthropic.BetaMessa if msg.IsUser { param = anthropic.NewBetaUserMessage(blocks...) } else { - param = anthropic.BetaMessageParam{ - Role: anthropic.BetaMessageParamRoleAssistant, + param = anthropic.BetaMessageParam{OfAssistant: &anthropic.BetaAssistantMessageParam{ Content: blocks, - } + }} } contextMessages = append(contextMessages, param) } @@ -366,7 +371,13 @@ func markTrailingCacheBreakpoint(messages []anthropic.BetaMessageParam) { if len(messages) == 0 { return } - blocks := messages[len(messages)-1].Content + var blocks []anthropic.BetaContentBlockParamUnion + switch last := messages[len(messages)-1]; { + case last.OfUser != nil: + blocks = last.OfUser.Content + case last.OfAssistant != nil: + blocks = last.OfAssistant.Content + } if len(blocks) == 0 { return } diff --git a/config.go b/config.go index d396a2f..f48eca5 100644 --- a/config.go +++ b/config.go @@ -76,7 +76,7 @@ type BotConfig struct { MessagePerDay int `json:"messages_per_day"` TempBanDuration string `json:"temp_ban_duration"` Model string `json:"model"` - Temperature *float32 `json:"temperature,omitempty"` + Temperature *float32 `json:"temperature,omitempty"` // never sent (rejected since API 2026-10-21); parsed only to flag stale configs MaxTokens int `json:"max_tokens,omitempty"` Thinking string `json:"thinking,omitempty"` ThinkingDisplay string `json:"thinking_display,omitempty"` @@ -175,6 +175,11 @@ func loadAllConfigs(dir string) ([]BotConfig, error) { // logConfigAdvisories emits non-fatal boot-time notes about settings that are // valid but likely to surprise: silently ineffective, or costlier than intended. func logConfigAdvisories(config *BotConfig) { + if config.Temperature != nil { + InfoLogger.Printf("[%s] temperature=%g is ignored: the Claude API no longer accepts sampling parameters; remove the key", + config.ID, *config.Temperature) + } + if config.Thinking == ThinkingModeAdaptive && config.MaxTokens > 0 && config.MaxTokens < 4000 { InfoLogger.Printf("[%s] thinking=adaptive with max_tokens=%d: thinking tokens count toward max_tokens; consider >= 4000", config.ID, config.MaxTokens) diff --git a/config/default.json b/config/default.json index 2a3c5dc..9a9e62e 100644 --- a/config/default.json +++ b/config/default.json @@ -11,9 +11,9 @@ "messages_per_hour": 20, "messages_per_day": 100, "temp_ban_duration": "24h", - "model": "claude-haiku-4-5", - "temperature": 0.7, + "model": "claude-haiku-5-5", "max_tokens": 1000, + "effort": "low", "debounce_ms": 2500, "debug_screening": false, "system_prompts": { diff --git a/elevenlabs.go b/elevenlabs.go index 705857f..05da21b 100644 --- a/elevenlabs.go +++ b/elevenlabs.go @@ -56,7 +56,7 @@ func (b *Bot) transcribeVoice(ctx context.Context, fileID string) (string, error var buf bytes.Buffer mw := multipart.NewWriter(&buf) - if err := mw.WriteField("model_id", "scribe_v1"); err != nil { + if err := mw.WriteField("model_id", "scribe_v2"); err != nil { return "", fmt.Errorf("multipart write error: %w", err) } part, err := mw.CreateFormFile("file", "audio.ogg") diff --git a/go.mod b/go.mod index 9a82bf6..8b16c51 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,12 @@ module github.com/HugeFrog24/go-telegram-bot -go 1.26.0 +go 1.27.0 require ( - github.com/anthropics/anthropic-sdk-go v1.71.0 - github.com/go-telegram/bot v1.25.0 + github.com/anthropics/anthropic-sdk-go/v2 v2.3.0 + github.com/go-telegram/bot v1.27.0 github.com/stretchr/testify v1.12.1 - golang.org/x/sync v0.23.0 + golang.org/x/sync v0.24.0 golang.org/x/time v0.16.0 gorm.io/driver/sqlite v1.6.0 gorm.io/gorm v1.31.2 @@ -15,18 +15,26 @@ require ( require ( github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.6.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/go-logr/logr v1.4.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/invopop/jsonschema v0.14.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/mattn/go-sqlite3 v1.14.52 // indirect - github.com/pb33f/ordered-map/v2 v2.3.1 // indirect + github.com/pb33f/go-yaml v0.1.1 // indirect + github.com/pb33f/ordered-map/v2 v2.3.2 // indirect github.com/standard-webhooks/standard-webhooks/libraries v0.0.1 // indirect - github.com/stretchr/objx v0.5.3 // indirect - github.com/tidwall/gjson v1.19.0 // indirect + github.com/stretchr/objx v0.8.0 // indirect + github.com/tidwall/gjson v1.20.0 // indirect github.com/tidwall/match v1.2.0 // indirect - github.com/tidwall/pretty v1.2.1 // indirect + github.com/tidwall/pretty v1.2.2 // indirect github.com/tidwall/sjson v1.2.5 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.47.0 // indirect + go.opentelemetry.io/otel/log v1.47.0 // indirect + go.opentelemetry.io/otel/metric v1.47.0 // indirect + go.opentelemetry.io/otel/trace v1.47.0 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect - go.yaml.in/yaml/v4 v4.0.0-rc.6 // indirect - golang.org/x/text v0.42.0 // indirect + golang.org/x/text v0.43.0 // indirect ) diff --git a/go.sum b/go.sum index 88ce414..a7d1aba 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,70 @@ -github.com/anthropics/anthropic-sdk-go v1.71.0 h1:DK9xG3s5t+xUIOp+R+1LIRjkU/wG57YyQO3630+gYOE= -github.com/anthropics/anthropic-sdk-go v1.71.0/go.mod h1:x+lPk/cCl48uRegeP0hlYYBN1b7bEBTveInIMgLicnY= +cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE= +cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs= +cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI= +cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +github.com/anthropics/anthropic-sdk-go/v2 v2.3.0 h1:wEaN13ToNCcjdqP+47ALC78Jt+DkGMmwqL5zzPQTGkQ= +github.com/anthropics/anthropic-sdk-go/v2 v2.3.0/go.mod h1:LAOInMKgn6reTIrPvKXa5weyqzxsJkxSBuzhnxzukpQ= +github.com/aws/aws-sdk-go-v2 v1.38.0 h1:UCRQ5mlqcFk9HJDIqENSLR3wiG1VTWlyUfLDEvY7RxU= +github.com/aws/aws-sdk-go-v2 v1.38.0/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM= +github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= +github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= +github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= +github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/buger/jsonparser v1.6.1 h1:I0phFv0PlbLHnM7TZAVjZ2MJ2/eWRTDyuO7GLR98IEs= github.com/buger/jsonparser v1.6.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/go-telegram/bot v1.25.0 h1:C072msZtr+GjJiQsX/UJLirz+jzSNZVWkckxWufR7Ww= -github.com/go-telegram/bot v1.25.0/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= +github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-telegram/bot v1.27.0 h1:PG9yBDzM8O26oUerE9SZwWlHon4RpH8WcNslZ7CEZmE= +github.com/go-telegram/bot v1.27.0/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= +github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/invopop/jsonschema v0.14.0 h1:MHQqLhvpNUZfw+hM3AZDYK7jxO8FZoQeQM77g8iyZjg= github.com/invopop/jsonschema v0.14.0/go.mod h1:ygm6C2EaVNMBDPpaPlnOA2pFAxBnxGjFlMZABxm9n2I= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -16,35 +73,77 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/mattn/go-sqlite3 v1.14.52 h1:wVbm2Qnf4OXkqhBTSPuCRZDRnxfbVrrmiCEroVdog8U= github.com/mattn/go-sqlite3 v1.14.52/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w= -github.com/pb33f/ordered-map/v2 v2.3.1 h1:5319HDO0aw4DA4gzi+zv4FXU9UlSs3xGZ40wcP1nBjY= -github.com/pb33f/ordered-map/v2 v2.3.1/go.mod h1:qxFQgd0PkVUtOMCkTapqotNgzRhMPL7VvaHKbd1HnmQ= +github.com/modelcontextprotocol/go-sdk v1.3.1 h1:TfqtNKOIWN4Z1oqmPAiWDC2Jq7K9OdJaooe0teoXASI= +github.com/modelcontextprotocol/go-sdk v1.3.1/go.mod h1:DgVX498dMD8UJlseK1S5i1T4tFz2fkBk4xogC3D15nw= +github.com/pb33f/go-yaml v0.1.1 h1:yWGmhVdwzionRnSc/hEJwcfq6PaZL2QdYzyReXBbX7Q= +github.com/pb33f/go-yaml v0.1.1/go.mod h1:QvWdkHP5VjFYAeHMQUkaPQqREaQnBNOXmWzAjNrnSdo= +github.com/pb33f/ordered-map/v2 v2.3.2 h1:wDyaZ2Pv9QLh64X4utCeD5Zoi9nIv2aW3lwv172O5PQ= +github.com/pb33f/ordered-map/v2 v2.3.2/go.mod h1:1OhFrXu3OYw3kM+FXF+Ug3ugmmZ9LE8z0JfQMLvtV0w= +github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= +github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= +github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0= +github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/standard-webhooks/standard-webhooks/libraries v0.0.1 h1:uOfcYT+3QungH6tIGSVCR/Y3KJmgJiHcojJbMTPDZAI= github.com/standard-webhooks/standard-webhooks/libraries v0.0.1/go.mod h1:L1MQhA6x4dn9r007T033lsaZMv9EmBAdXyU/+EF40fo= -github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= -github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= +github.com/stretchr/objx v0.8.0 h1:rm9oMkeprG/wHifkZP4EuDww9S0mvEaQ/p9cXTNT4cw= +github.com/stretchr/objx v0.8.0/go.mod h1:xSzHnPHkdEv7vtgdQej8atlCuU1mdX+ELge8bn0hCsE= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU= -github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= +github.com/tidwall/gjson v1.20.0 h1:+agJ3rEzKcCXKDKo0ml26UROcpcAlnZyjq+TjbY5Fto= +github.com/tidwall/gjson v1.20.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.2 h1:dz1jrRuE7or/74V490B4/GP1pZm5WKlt2bgCP5A83w8= +github.com/tidwall/pretty v1.2.2/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= +github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM= +go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU= +go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI= +go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw= +go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY= +go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU= +go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= +go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM= +go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0= go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= -go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4= -go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= -golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= -golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= -golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= -golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA= +golang.org/x/sync v0.24.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.43.0 h1:1QivrlhwAsnMOcqgOdl9my7s9OyZl8O5/UGUTJVXoWc= +golang.org/x/text v0.43.0/go.mod h1:hbSIYA/amXcRXTFSZqh8tWHEoqRvvbKPJ2uz/KU+a+s= golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE= golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s= +google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI= +google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade h1:oCRSWfwGXQsqlVdErcyTt4A93Y8fo0/9D4b1gnI++qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= diff --git a/handlers.go b/handlers.go index ac71395..8467286 100644 --- a/handlers.go +++ b/handlers.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - "github.com/anthropics/anthropic-sdk-go" + "github.com/anthropics/anthropic-sdk-go/v2" "github.com/go-telegram/bot" "github.com/go-telegram/bot/models" "golang.org/x/sync/errgroup" diff --git a/prompt_cache_test.go b/prompt_cache_test.go index 443e44f..cc9ea9d 100644 --- a/prompt_cache_test.go +++ b/prompt_cache_test.go @@ -3,8 +3,8 @@ package main import ( "testing" - "github.com/anthropics/anthropic-sdk-go" - "github.com/anthropics/anthropic-sdk-go/packages/param" + "github.com/anthropics/anthropic-sdk-go/v2" + "github.com/anthropics/anthropic-sdk-go/v2/packages/param" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -21,14 +21,14 @@ func TestMarkTrailingCacheBreakpoint(t *testing.T) { markTrailingCacheBreakpoint(msgs) - last := msgs[1].Content[1].OfText + last := msgs[1].OfUser.Content[1].OfText require.NotNil(t, last) assert.False(t, param.IsOmitted(last.CacheControl), "the trailing block carries the breakpoint") // Everything earlier stays unmarked: one breakpoint, not one per block. - assert.True(t, param.IsOmitted(msgs[1].Content[0].OfText.CacheControl)) - assert.True(t, param.IsOmitted(msgs[0].Content[0].OfText.CacheControl)) + assert.True(t, param.IsOmitted(msgs[1].OfUser.Content[0].OfText.CacheControl)) + assert.True(t, param.IsOmitted(msgs[0].OfUser.Content[0].OfText.CacheControl)) }) t.Run("marks a trailing image block", func(t *testing.T) { @@ -40,8 +40,8 @@ func TestMarkTrailingCacheBreakpoint(t *testing.T) { markTrailingCacheBreakpoint(msgs) - require.NotNil(t, msgs[0].Content[0].OfImage) - assert.False(t, param.IsOmitted(msgs[0].Content[0].OfImage.CacheControl)) + require.NotNil(t, msgs[0].OfUser.Content[0].OfImage) + assert.False(t, param.IsOmitted(msgs[0].OfUser.Content[0].OfImage.CacheControl)) }) t.Run("tolerates empty input", func(t *testing.T) { @@ -65,7 +65,9 @@ func TestPrepareContextMessages_CacheHistoryToggle(t *testing.T) { //NOSONAR go: t.Run("enabled by default", func(t *testing.T) { msgs := b.prepareContextMessages(memory) require.Len(t, msgs, 2) - assert.False(t, param.IsOmitted(msgs[1].Content[0].OfText.CacheControl)) + require.NotNil(t, msgs[0].OfUser, "user memory becomes a user turn") + require.NotNil(t, msgs[1].OfAssistant, "bot memory becomes an assistant turn") + assert.False(t, param.IsOmitted(msgs[1].OfAssistant.Content[0].OfText.CacheControl)) }) t.Run("opt-out leaves history unmarked", func(t *testing.T) { @@ -75,7 +77,7 @@ func TestPrepareContextMessages_CacheHistoryToggle(t *testing.T) { //NOSONAR go: msgs := b.prepareContextMessages(memory) require.Len(t, msgs, 2) - assert.True(t, param.IsOmitted(msgs[1].Content[0].OfText.CacheControl)) + assert.True(t, param.IsOmitted(msgs[1].OfAssistant.Content[0].OfText.CacheControl)) }) }