Skip to content

fix(anthropic): extract usage-mapping helper, add streaming usage tests#13

Draft
ibetitsmike wants to merge 32 commits intocj/go1.25-Mar-25-2026from
mike/fix-anthropic-streaming-usage
Draft

fix(anthropic): extract usage-mapping helper, add streaming usage tests#13
ibetitsmike wants to merge 32 commits intocj/go1.25-Mar-25-2026from
mike/fix-anthropic-streaming-usage

Conversation

@ibetitsmike
Copy link
Copy Markdown

This PR was authored by Mux on behalf of Mike.

The Anthropic provider duplicated the SDK-to-fantasy usage mapping inline in both Generate() and Stream().

This patch:

  • Extracts a private mapAnthropicUsage() helper used by both paths.
  • Documents TotalTokens semantics: InputTokens + OutputTokens (cache tokens tracked separately).
  • Adds TestMapAnthropicUsage unit test and TestStream_MapsUsage integration test verifying the finish event carries correct cache token values.

Cali0707 and others added 30 commits March 18, 2026 14:45
… keys (charmbracelet#157)

Signed-off-by: Calum Murray <cmurray@redhat.com>
…to API (charmbracelet#178)

The Anthropic provider's toTools function was returning nil for
anthropicToolChoice when ToolChoiceNone was set, which meant
tool_choice was never included in the API request. The API defaults
to "auto", so the model could still make tool calls.

Now properly constructs ToolChoiceUnionParam with OfNone set using
anthropic.NewToolChoiceNoneParam().

Also adds test coverage for ToolChoiceNone.

* Closes charmbracelet#177

💘 Generated with Crush

Assisted-by: Kimi K2.5 via Crush <crush@charm.land>
Allow empty prompts when there are messages and no files to attach.
The last message must be a user or tool message - this ensures the
conversation state is valid for the LLM to respond.

This addresses use cases where:
- Generating from an existing conversation
- Tool results were just returned and we want the LLM to respond

Validation:
- Error if empty prompt with no messages
- Error if empty prompt with files (files need a user message)
- Error if last message is assistant (nothing to respond to)
- Allow if last message is user or tool

Closes charmbracelet#54
Closes charmbracelet#59
Closes charmbracelet#103

Co-authored-by: Arun Barua <arun.barua@onit.com>
Co-authored-by: Ruslan Mayer <r.stupa@ya.ru>
The OpenAI SDK has a bug on dealing with SSE events. This was affected
OpenRouter, but we made a workaround for it. See:

* charmbracelet#166
* charmbracelet#169

We made a fix for the SDK, but it wasn't merged yet:

* openai/openai-go#621

In the meantime, an user reported that Avian has the same issue, but it's
impossible for us to workaround it. Because of this, we had to fork the
SDK. We're pinning the `fantasy` branch from our fork:

* https://github.com/charmbracelet/openai-go/tree/fantasy
…let#181)

When Store is enabled, replaying reasoning items (OfReasoning) in
the Responses API input causes a validation error:

  Item 'rs_xxx' of type 'reasoning' was provided without its
  required following item.

The API stores reasoning server-side and cannot pair a reconstructed
reasoning item with the output item that originally followed it.
The fix skips reasoning parts during replay, letting the conversation
continue with visible assistant content (text / tool calls).
Make it shorter (one per major provider) and favor smaller models.
Allows overriding the default Bedrock endpoint URL, enabling use with
custom or proxy endpoints.

🐙 Generated with Crush

Assisted-by: AWS Claude Opus 4.6 via Crush <crush@charm.land>
bedrock.WithConfig internally calls option.WithBaseURL with the default
regional endpoint, clobbering any user-provided base_url. Move the
custom base URL append to after the bedrock config block so last-write
wins.

🐨 Generated with Crush

Assisted-by: AWS Claude Opus 4.6 via Crush <crush@charm.land>
When useBedrock is true, the DefaultURL ("https://api.anthropic.com") was
being set on providerOptions.baseURL in New(). This caused LanguageModel()
to append option.WithBaseURL("https://api.anthropic.com") after
bedrock.WithConfig had already set the correct bedrock-runtime URL,
overwriting it.

Only set the default base URL for non-bedrock providers. Bedrock gets its
URL from bedrock.WithConfig() in the SDK.

🐙 Generated with Crush

Assisted-by: AWS Claude Opus 4.6 via Crush <crush@charm.land>
…t#156)

Co-authored-by: Andrey Nering <andreynering@users.noreply.github.com>
…rmbracelet#113)

Co-authored-by: Andrey Nering <andreynering@users.noreply.github.com>
Bumps the all group with 2 updates: [github.com/kaptinlin/jsonschema](https://github.com/kaptinlin/jsonschema) and [google.golang.org/genai](https://github.com/googleapis/go-genai).


Updates `github.com/kaptinlin/jsonschema` from 0.7.5 to 0.7.6
- [Commits](kaptinlin/jsonschema@v0.7.5...v0.7.6)

Updates `google.golang.org/genai` from 1.50.0 to 1.51.0
- [Release notes](https://github.com/googleapis/go-genai/releases)
- [Changelog](https://github.com/googleapis/go-genai/blob/main/CHANGELOG.md)
- [Commits](googleapis/go-genai@v1.50.0...v1.51.0)

---
updated-dependencies:
- dependency-name: github.com/kaptinlin/jsonschema
  dependency-version: 0.7.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all
- dependency-name: google.golang.org/genai
  dependency-version: 1.51.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…mbracelet#184)

Bumps the kronk group with 1 update: [github.com/ardanlabs/kronk](https://github.com/ardanlabs/kronk).


Updates `github.com/ardanlabs/kronk` from 1.21.3 to 1.21.4
- [Release notes](https://github.com/ardanlabs/kronk/releases)
- [Commits](ardanlabs/kronk@v1.21.3...v1.21.4)

---
updated-dependencies:
- dependency-name: github.com/ardanlabs/kronk
  dependency-version: 1.21.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: kronk
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…annotations (charmbracelet#187)

The Responses API streaming path was missing a handler for
"response.output_text.annotation.added" events. This meant that
url_citation and file_citation annotations—which carry source
URLs and titles for web search results—were silently dropped
during streaming.

The non-streaming Generate path and the Chat Completions API
streaming path both handled annotations correctly; only the
Responses API Stream path was affected.

Add a case for "response.output_text.annotation.added" that
parses the annotation map and yields StreamPartTypeSource parts
for url_citation and file_citation types, matching the behavior
of the existing Generate path and the Anthropic provider.

Update TestResponsesStream_WebSearchResponse to include
annotation.added events in the mock stream and assert that
source parts are emitted with the correct URL, title, and type.
…ort levels (charmbracelet#186)

We were missing some "none", "minimal" and "xhigh" constants, for the `openai`, `openaicompat` and `openrouter` packages.

Added the missing checks to ensure they work as well.

Co-authored-by: Andrey Nering <andreynering@users.noreply.github.com>
kylecarbs and others added 2 commits March 25, 2026 14:57
Remove kronk provider and examples (every published version requires
go 1.26). Downgrade kaptinlin deps to Go 1.25-compatible versions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants