llm_claude 0.7.0
llm_claude: ^0.7.0 copied to clipboard
Anthropic Claude API backend for LLM interactions. Provides streaming chat and tool calling via the Anthropic Messages API.
Changelog #
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased] #
0.7.0 - 2026-09-22 #
Added #
LLMUsage.cachedTokensand.cacheWriteTokensfromcache_read_input_tokensandcache_creation_input_tokens. The raw values remain onproviderMetadata.- A tool result carrying
LLMToolResult.contentPartsis sent as Anthropic content blocks, so a tool can return an image rather than a description of one.
Fixed #
RetryConfig.retryableStatusCodesnever applied to streaming requests. A non-2xx arrives as a returned response rather than a thrown error, so the retry around the send never saw it and a 429 or 503 from Anthropic failed on the first attempt.- A failure reported in-band —
200, then anerrorevent on the stream — was not retried either, because it arrives after the send has returned. Both are now re-issued while nothing has reached the caller. promptTokensunder-reported every cached request. Anthropic'sinput_tokenscounts only the tokens after the last cache breakpoint —total = cache_read + cache_creation + input_tokens— and the raw value was used as-is, sototalTokenswas wrong too. Cost calculations based onpromptTokenswill see different numbers.- A tool call rejected for undecodable arguments reached Anthropic without
is_error, so the model read the parse error as data. Failure is now read fromLLMToolResult.isError; the old text match remains as a fallback for histories this package did not build. - A successful tool whose output happened to begin
Tool <name> failed:was flagged as an error. - Cancelling a
streamChatsubscription aborts the request.
Changed #
- The tool name is read from
LLMMessage.toolName, falling back tostatus. - All packages bumped to
0.7.0;llm_coreconstraint updated to^0.7.0.
0.6.0 - 2026-09-17 #
Changed #
- A
max_tokensturn now returns its tool calls. Input that doesn't decode is returned ininvalidToolCallsinstead oftoolCalls.
0.5.0 - 2026-09-11 #
Fixed #
- An empty message was rejected by the API with a 400. The converter already substituted a placeholder for a message that produces no content blocks, but used a single space — and the Messages API rejects that too ("text content blocks must contain non-whitespace text"), alongside
'',[]and an empty text block. The placeholder is now non-whitespace. Anthropic is the only backend here with no valid representation of an empty message, so every other backend already accepted one. - Tool calls were emitted only for
stop_reason: "tool_use". A turn mixing text and tool blocks can endend_turn, and its complete calls were dropped. A turn cut short bymax_tokensstill suppresses them: its arguments may stop mid-JSON.
Changed #
- A turn that ends while carrying complete tool calls now reports
LLMFinishReason.toolCalls, whatever the provider spelled. The OpenAI specification definesfinish_reasonastool_calls"if the model called a tool", and providers violate it routinely. Code branching onLLMFinishReason.stopfor a tool-calling turn must move totoolCalls.length,contentFilterandrefusalare never reclassified: a truncated call is not executable, and a declined turn must stay visibly declined.
0.4.0 - 2026-08-30 #
Fixed #
- A truncated tool call no longer runs with no arguments. Accumulated tool input was decoded and re-encoded, and anything unparseable was swallowed into
{}— so a turn cut short bymax_tokens, or the fine-grained tool streaming beta (which emits unvalidated partial JSON by design), produced a tool call that executed with empty arguments instead of failing. The wire text is now passed through verbatim, so truncation surfaces as an error at execution. This also makes the completed call byte-identical to its concatenatedtoolCallDeltas, as on every other backend. - Mid-stream
errorevents now carry astatusCode. Anthropic reports failures bytyperather than a numeric code, and retry classification works off the status code, so a mid-streamoverloaded_errororrate_limit_errorwas never recognized as retryable. Types are mapped to their documented HTTP equivalents (overloaded_error→ 529).
Added #
- Streaming tool calls surface as they arrive on
LLMChunkMessage.toolCallDeltas. Claude names the tool in a dedicatedcontent_block_startevent, so the name is reported before a single argument byte exists. extraHeadersonClaudeChatRepositoryand its builder. This makesanthropic-betareachable for the first time — for examplefine-grained-tool-streaming-2025-05-14, which streams tool parameters without server-side buffering. Protocol headers,x-api-keyandanthropic-versionalways take precedence.
0.3.2 - 2026-08-18 #
Changed #
- Version bumped to
0.3.2in lockstep with the other packages, and thellm_coreconstraint raised to^0.3.2. No other changes to this package.
0.3.1 - 2026-08-18 #
Fixed #
streamChatapplies a timeout to the send operation. It previously opted out, so a request that wedged before response headers arrived never recovered.- The default HTTP client is now
createLLMHttpClient(), which appliesTimeoutConfig.connectionTimeoutand bounds the connection pool.
Changed #
- Dependency floors raised: Dart SDK
^3.12.0(was^3.8.0),http ^1.6.0,lints ^6.1.0,test ^1.31.0.
0.3.0 - 2026-08-17 #
Added #
reasoningEffortsupport: maps tooutput_config.efforton current models (wins over a budget-derived level) and converts tobudget_tokenson legacy models viaclaudeBudgetForEffort.
0.2.0 - 2026-08-12 #
Initial release of the Anthropic Claude backend for the dart-llm ecosystem.
Added #
ClaudeChatRepository— streaming chat via the Anthropic Messages API (POST /v1/messages,x-api-key,anthropic-version: 2023-06-01).- Tool/function calling with automatic tool-loop execution
(
autoExecuteTools: true), plustool_choiceaccepting either the Messages API object form or OpenAI-style shorthands (auto,required,none, or a tool name). Failed tool results are markedis_error: true. - Model-aware thinking. Current models (Opus 4.7+, Sonnet 5, Fable 5,
Mythos 5) use
thinking: {type: 'adaptive', display: 'summarized'}; older models usebudget_tokens, clamped belowmax_tokens.LLMChatOptions.reasoningBudgetmaps to anoutput_config.effortlevel on models that no longer accept token budgets. - Structured output via
LLMChatOptions.responseFormat, using the nativeoutput_config.formatfield where available and falling back to system-prompt injection on older models. Propagated through tool-call loops so the constraint holds across every turn. - Vision support for base64 image content with MIME-type sniffing.
ClaudeRequestShapeand theclaudeSupports*helpers, which resolve the request shape a given model id expects. Unrecognized ids are treated as current models, so newly released models work without a library update.- Cache token counts (
cache_creation_input_tokens,cache_read_input_tokens) and thinking-block signatures are surfaced throughLLMChunk.providerMetadata. ClaudeChatRepository.builder()for fluent configuration, with retry, timeout, rate limiting, response cache, and metrics support.- Unit test suites asserting the exact request body per model family, and key-gated integration suites.
Notes on the Messages API #
Two request shapes were removed rather than deprecated on newer models, so
sending the old form is a hard 400 rather than an ignored field:
| Request shape | Opus 4.7+, Sonnet 5, Fable 5, Mythos 5 | Older models |
|---|---|---|
thinking: {type: 'enabled', budget_tokens: N} |
400 | supported |
temperature / top_p / top_k |
400 | supported |
llm_claude selects the correct shape from the model id, so sampling
parameters are omitted for models that reject them rather than failing the
request. Steer those models through the prompt instead.
thinking.display defaults to omitted on current models, which returns
thinking blocks with empty text; llm_claude requests summarized so
chunk.message.thinking is populated.
Verification status #
The request shapes above are covered by unit tests asserting the serialized JSON body. They have not been exercised against the live Anthropic API — the integration suites are key-gated and were not run for this release.