Resolve Bedrock model IDs using AWS region-group prefixes with
AWS_DEFAULT_REGION fallback, preserve already-prefixed IDs, and default
to global for unmapped regions. Add tests to lock in mapping and
prefixing behavior.
💘 Generated with Crush
Assisted-by: GPT-5.3 Codex via Crush <crush@charm.land>
d13521a
chore(openai): add missing constants and checks for some thinking effort levels (#186)
Click to expand commit body
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>
4620329
fix(providers/openai): emit source parts for Responses API streaming annotations (#187)
Click to expand commit body
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.
aa7e82f
fix(bedrock): don't default baseURL to anthropic API when using bedrock
Click to expand commit body
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>
Aleks Clark
created
8924b01
fix(bedrock): apply base URL override after bedrock.WithConfig
Click to expand commit body
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>
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>
43df1e4
chore: revert change to skip user-agent for openrouter
Andrey Nering
created
dff62fa
fix(openai): skip reasoning items in Responses API replay (#181)
Click to expand commit body
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).
6bb474f
fix: migrate the openai sdk to our internal fork
Click to expand commit body
The OpenAI SDK has a bug on dealing with SSE events. This was affected
OpenRouter, but we made a workaround for it. See:
* https://github.com/charmbracelet/fantasy/pull/166
* https://github.com/charmbracelet/fantasy/pull/169
We made a fix for the SDK, but it wasn't merged yet:
* https://github.com/openai/openai-go/pull/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
f910b4c
feat(agent): allow empty prompt when messages exist (#179)
Click to expand commit body
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 #54
Closes #59
Closes #103
Co-authored-by: Arun Barua <arun.barua@onit.com>
Co-authored-by: Ruslan Mayer <r.stupa@ya.ru>
Andrey Nering
,
Arun Barua
, and
Ruslan Mayer
created
d749d13
fix(anthropic): ToolChoiceNone should send tool_choice:{type:"none"} to API (#178)
Click to expand commit body
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 #177
💘 Generated with Crush
Assisted-by: Kimi K2.5 via Crush <crush@charm.land>
Andrey Nering
created
1568c97
fix(anthropic): anthropic with vertex works with service account json keys (#157)
22c3e9a
fix(openai): subtract cached tokens from input tokens to avoid double counting (#176)
Click to expand commit body
OpenAI's API reports prompt_tokens/input_tokens INCLUDING cached tokens,
while also separately reporting cached_tokens in prompt_tokens_details.
This caused double-counting when users summed InputTokens + CacheReadTokens.
For example, if OpenAI reports:
- prompt_tokens: 1000 (includes 900 cached)
- cached_tokens: 900
Before this fix, fantasy reported:
- InputTokens: 1000
- CacheReadTokens: 900
After this fix, fantasy reports:
- InputTokens: 100 (non-cached only)
- CacheReadTokens: 900
This matches the behavior of Vercel AI SDK and prevents billing
miscalculations when pricing input tokens and cache read tokens separately.
See: https://platform.openai.com/docs/guides/prompt-caching#requirements
💘 Generated with Crush
Assisted-by: Kimi K2.5 via Crush <crush@charm.land>
Andrey Nering
created
0c8663f
feat(openai): add responses api `store`, `previous_response_id`, and `response.id` support (#175)
Click to expand commit body
Co-authored-by: Christian Rocha <christian@rocha.is>
This is currently already covered by `web-search` example.
Andrey Nering
created
6462ab9
feat(openai): add web search tool support for Responses API (#173)
Click to expand commit body
Add OpenAI web search as a provider-defined tool, mirroring the
Anthropic web search implementation pattern.
New files:
- providers/openai/web_search.go: WebSearchTool() helper with
SearchContextSize, AllowedDomains, and UserLocation options.
- examples/openai-web-search/main.go: Example using the agent
pattern with web search.
Changes to existing files:
- responses_options.go: WebSearchCallMetadata, WebSearchAction,
and WebSearchSource types registered for JSON round-tripping.
- responses_language_model.go:
- toResponsesTools(): Route ProviderDefinedTool web_search to
the OpenAI SDK WebSearchToolParam.
- Generate(): Emit ToolCallContent + ToolResultContent pair for
web_search_call output items. Source citations come from
url_citation annotations on message text.
- Stream(): Emit ToolInputStart/ToolInputEnd/ToolCall/ToolResult
lifecycle events for web_search_call items.
- toResponsesPrompt(): Round-trip provider-executed tool calls
via item_reference; skip SourceContent and provider-executed
ToolResultPart (already handled by the reference).
- providertests/provider_registry_test.go: Add metadata test case.
df8bcd9
chore(deps): bump the all group with 4 updates (#171)
Click to expand commit body
Bumps the all group with 4 updates: [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2), [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2), [github.com/openai/openai-go/v3](https://github.com/openai/openai-go) and [google.golang.org/genai](https://github.com/googleapis/go-genai).
Updates `github.com/aws/aws-sdk-go-v2` from 1.41.3 to 1.41.4
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.41.3...v1.41.4)
Updates `github.com/aws/aws-sdk-go-v2/config` from 1.32.11 to 1.32.12
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.32.11...config/v1.32.12)
Updates `github.com/openai/openai-go/v3` from 3.26.0 to 3.28.0
- [Release notes](https://github.com/openai/openai-go/releases)
- [Changelog](https://github.com/openai/openai-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/openai/openai-go/compare/v3.26.0...v3.28.0)
Updates `google.golang.org/genai` from 1.49.0 to 1.50.0
- [Release notes](https://github.com/googleapis/go-genai/releases)
- [Changelog](https://github.com/googleapis/go-genai/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/go-genai/compare/v1.49.0...v1.50.0)
---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
dependency-version: 1.41.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: all
- dependency-name: github.com/aws/aws-sdk-go-v2/config
dependency-version: 1.32.12
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: all
- dependency-name: github.com/openai/openai-go/v3
dependency-version: 3.28.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: all
- dependency-name: google.golang.org/genai
dependency-version: 1.50.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>
dependabot[bot]
and
dependabot[bot]
created
eaa111e
chore(anthroipic): harden web_search coercion for json round-trips
Click to expand commit body
This guards against cases when web_search options could be silently
dropped when tool args pass through generic/JSON-shaped data, so domain
filters, max uses, and user location reliably reach Anthropic.