Current section

50 Versions

Jump to

Compare versions

5 files changed
+99 additions
-60 deletions
  @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 6
7 7 ## [Unreleased]
8 8
9 + ## [0.19.5] - 2026-06-01
10 +
11 + ### Added
12 + - Bedrock HTTP receive timeout is now configurable via `config :llm_composer, :bedrock, receive_timeout: <ms>`. Falls back to the global `config :llm_composer, :timeout` and then to the previous hardcoded default of 30 000 ms. Applies to all Mint-based paths (streaming and non-streaming) as well as the shared `handle_stream_response` helpers used by Finch streaming.
13 +
14 + ## [0.19.4] - 2026-05-05
15 +
16 + ### Fixed
17 + - Fixed Google cached token tracking: `cachedContentTokenCount` from `usageMetadata` is now extracted and populated in both `LlmResponse.cached_tokens` (non-streaming) and `StreamChunk.usage.cached_tokens` (streaming) instead of always being `nil`.
18 +
9 19 ## [0.19.3] - 2026-04-30
10 20
11 21 ### Fixed
  @@ -306,7 +316,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
306 316 - Initial release with support for basic message handling, interaction with OpenAI and Ollama models, and a foundational structure for model settings and function execution.
307 317
308 318 ---
309 - [Unreleased]: https://github.com/doofinder/llm_composer/compare/0.19.3...HEAD
319 + [Unreleased]: https://github.com/doofinder/llm_composer/compare/0.19.5...HEAD
320 + [0.19.5]: https://github.com/doofinder/llm_composer/compare/0.19.4...0.19.5
321 + [0.19.4]: https://github.com/doofinder/llm_composer/compare/0.19.3...0.19.4
310 322 [0.19.3]: https://github.com/doofinder/llm_composer/compare/0.19.2...0.19.3
311 323 [0.19.2]: https://github.com/doofinder/llm_composer/compare/0.19.1...0.19.2
312 324 [0.19.1]: https://github.com/doofinder/llm_composer/compare/0.19.0...0.19.1
  @@ -1,6 +1,6 @@
1 1 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/doofinder/llm_composer">>}]}.
2 2 {<<"name">>,<<"llm_composer">>}.
3 - {<<"version">>,<<"0.19.4">>}.
3 + {<<"version">>,<<"0.19.5">>}.
4 4 {<<"description">>,
5 5 <<"LlmComposer is an Elixir library that facilitates chat interactions with language models, providing tools to handle user messages, generate responses, and execute functions automatically based on model outputs.">>}.
6 6 {<<"elixir">>,<<"~> 1.18">>}.
  @@ -49,68 +49,69 @@
49 49 {<<"repository">>,<<"hexpm">>}]]}.
50 50 {<<"files">>,
51 51 [<<"lib">>,<<"lib/llm_composer.ex">>,<<"lib/llm_composer">>,
52 - <<"lib/llm_composer/cache">>,<<"lib/llm_composer/cache/behaviour.ex">>,
53 - <<"lib/llm_composer/cache/ets.ex">>,<<"lib/llm_composer/cost">>,
52 + <<"lib/llm_composer/function_call_extractors.ex">>,
53 + <<"lib/llm_composer/function_call_helpers.ex">>,
54 + <<"lib/llm_composer/provider_router.ex">>,
55 + <<"lib/llm_composer/provider_stream_chunk">>,
56 + <<"lib/llm_composer/provider_stream_chunk/parser">>,
57 + <<"lib/llm_composer/provider_stream_chunk/parser/open_ai.ex">>,
58 + <<"lib/llm_composer/provider_stream_chunk/parser/open_ai_responses.ex">>,
59 + <<"lib/llm_composer/provider_stream_chunk/parser/bedrock.ex">>,
60 + <<"lib/llm_composer/provider_stream_chunk/parser/google.ex">>,
61 + <<"lib/llm_composer/provider_stream_chunk/parser/ollama.ex">>,
62 + <<"lib/llm_composer/provider_stream_chunk/open_ai.ex">>,
63 + <<"lib/llm_composer/provider_stream_chunk/open_ai_responses.ex">>,
64 + <<"lib/llm_composer/provider_stream_chunk/bedrock.ex">>,
65 + <<"lib/llm_composer/provider_stream_chunk/struct.ex">>,
66 + <<"lib/llm_composer/provider_stream_chunk/google.ex">>,
67 + <<"lib/llm_composer/provider_stream_chunk/open_router.ex">>,
68 + <<"lib/llm_composer/provider_stream_chunk/ollama.ex">>,
69 + <<"lib/llm_composer/errors.ex">>,<<"lib/llm_composer/helpers.ex">>,
70 + <<"lib/llm_composer/cost">>,<<"lib/llm_composer/cost/pricing.ex">>,
54 71 <<"lib/llm_composer/cost/fetchers">>,
55 72 <<"lib/llm_composer/cost/fetchers/models_dev.ex">>,
56 73 <<"lib/llm_composer/cost/fetchers/open_router.ex">>,
57 - <<"lib/llm_composer/cost/pricing.ex">>,
58 74 <<"lib/llm_composer/cost/cost_assembler.ex">>,
59 - <<"lib/llm_composer/cost_info.ex">>,<<"lib/llm_composer/errors.ex">>,
60 - <<"lib/llm_composer/function.ex">>,<<"lib/llm_composer/function_call.ex">>,
61 - <<"lib/llm_composer/function_call_extractors.ex">>,
62 - <<"lib/llm_composer/function_call_helpers.ex">>,
75 + <<"lib/llm_composer/cost_info.ex">>,
63 76 <<"lib/llm_composer/function_executor.ex">>,
64 - <<"lib/llm_composer/helpers.ex">>,<<"lib/llm_composer/http_client.ex">>,
65 - <<"lib/llm_composer/provider_response.ex">>,
66 - <<"lib/llm_composer/provider_response">>,
67 - <<"lib/llm_composer/provider_response/bedrock.ex">>,
68 - <<"lib/llm_composer/provider_response/google.ex">>,
69 - <<"lib/llm_composer/provider_response/ollama.ex">>,
70 - <<"lib/llm_composer/provider_response/open_ai.ex">>,
71 - <<"lib/llm_composer/provider_response/open_ai_responses.ex">>,
72 - <<"lib/llm_composer/provider_response/open_router.ex">>,
73 - <<"lib/llm_composer/provider_response/parser">>,
74 - <<"lib/llm_composer/provider_response/parser/bedrock.ex">>,
75 - <<"lib/llm_composer/provider_response/parser/ollama.ex">>,
76 - <<"lib/llm_composer/provider_response/parser/open_ai.ex">>,
77 - <<"lib/llm_composer/provider_response/parser/google.ex">>,
78 - <<"lib/llm_composer/provider_response/struct.ex">>,
79 - <<"lib/llm_composer/provider_router.ex">>,
80 77 <<"lib/llm_composer/provider_router">>,
81 78 <<"lib/llm_composer/provider_router/simple.ex">>,
79 + <<"lib/llm_composer/cache">>,<<"lib/llm_composer/cache/ets.ex">>,
80 + <<"lib/llm_composer/cache/behaviour.ex">>,
81 + <<"lib/llm_composer/provider_response.ex">>,
82 + <<"lib/llm_composer/llm_response.ex">>,
83 + <<"lib/llm_composer/providers_runner.ex">>,
84 + <<"lib/llm_composer/provider.ex">>,
82 85 <<"lib/llm_composer/provider_stream_chunk.ex">>,
83 - <<"lib/llm_composer/provider_stream_chunk">>,
84 - <<"lib/llm_composer/provider_stream_chunk/bedrock.ex">>,
85 - <<"lib/llm_composer/provider_stream_chunk/google.ex">>,
86 - <<"lib/llm_composer/provider_stream_chunk/ollama.ex">>,
87 - <<"lib/llm_composer/provider_stream_chunk/open_ai.ex">>,
88 - <<"lib/llm_composer/provider_stream_chunk/open_ai_responses.ex">>,
89 - <<"lib/llm_composer/provider_stream_chunk/open_router.ex">>,
90 - <<"lib/llm_composer/provider_stream_chunk/parser">>,
91 - <<"lib/llm_composer/provider_stream_chunk/parser/bedrock.ex">>,
92 - <<"lib/llm_composer/provider_stream_chunk/parser/ollama.ex">>,
93 - <<"lib/llm_composer/provider_stream_chunk/parser/open_ai.ex">>,
94 - <<"lib/llm_composer/provider_stream_chunk/parser/open_ai_responses.ex">>,
95 - <<"lib/llm_composer/provider_stream_chunk/parser/google.ex">>,
96 - <<"lib/llm_composer/provider_stream_chunk/struct.ex">>,
86 + <<"lib/llm_composer/settings.ex">>,<<"lib/llm_composer/function.ex">>,
87 + <<"lib/llm_composer/stream_chunk.ex">>,
88 + <<"lib/llm_composer/provider_response">>,
89 + <<"lib/llm_composer/provider_response/parser">>,
90 + <<"lib/llm_composer/provider_response/parser/open_ai.ex">>,
91 + <<"lib/llm_composer/provider_response/parser/bedrock.ex">>,
92 + <<"lib/llm_composer/provider_response/parser/google.ex">>,
93 + <<"lib/llm_composer/provider_response/parser/ollama.ex">>,
94 + <<"lib/llm_composer/provider_response/open_ai.ex">>,
95 + <<"lib/llm_composer/provider_response/open_ai_responses.ex">>,
96 + <<"lib/llm_composer/provider_response/bedrock.ex">>,
97 + <<"lib/llm_composer/provider_response/struct.ex">>,
98 + <<"lib/llm_composer/provider_response/google.ex">>,
99 + <<"lib/llm_composer/provider_response/open_router.ex">>,
100 + <<"lib/llm_composer/provider_response/ollama.ex">>,
97 101 <<"lib/llm_composer/providers">>,
98 - <<"lib/llm_composer/providers/bedrock.ex">>,
99 - <<"lib/llm_composer/providers/bedrock">>,
100 - <<"lib/llm_composer/providers/bedrock/http_client.ex">>,
101 - <<"lib/llm_composer/providers/bedrock/stream_operation.ex">>,
102 - <<"lib/llm_composer/providers/google.ex">>,
103 - <<"lib/llm_composer/providers/ollama.ex">>,
104 102 <<"lib/llm_composer/providers/open_ai.ex">>,
103 + <<"lib/llm_composer/providers/utils.ex">>,
105 104 <<"lib/llm_composer/providers/open_ai_responses.ex">>,
106 105 <<"lib/llm_composer/providers/open_ai_responses">>,
107 106 <<"lib/llm_composer/providers/open_ai_responses/reasoning.ex">>,
107 + <<"lib/llm_composer/providers/bedrock.ex">>,
108 + <<"lib/llm_composer/providers/bedrock">>,
109 + <<"lib/llm_composer/providers/bedrock/stream_operation.ex">>,
110 + <<"lib/llm_composer/providers/bedrock/http_client.ex">>,
111 + <<"lib/llm_composer/providers/google.ex">>,
108 112 <<"lib/llm_composer/providers/open_router.ex">>,
109 - <<"lib/llm_composer/providers/utils.ex">>,
110 - <<"lib/llm_composer/providers_runner.ex">>,
111 - <<"lib/llm_composer/stream_chunk.ex">>,
112 - <<"lib/llm_composer/llm_response.ex">>,<<"lib/llm_composer/message.ex">>,
113 - <<"lib/llm_composer/provider.ex">>,<<"lib/llm_composer/settings.ex">>,
114 - <<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>,
115 - <<"CHANGELOG.md">>]}.
113 + <<"lib/llm_composer/providers/ollama.ex">>,
114 + <<"lib/llm_composer/message.ex">>,<<"lib/llm_composer/function_call.ex">>,
115 + <<"lib/llm_composer/http_client.ex">>,<<".formatter.exs">>,<<"mix.exs">>,
116 + <<"README.md">>,<<"LICENSE">>,<<"CHANGELOG.md">>]}.
116 117 {<<"build_tools">>,[<<"mix">>]}.
  @@ -7,6 +7,22 @@ if Code.ensure_loaded?(ExAws) do
7 7 Bedrock compatible model can be used. To specify any model-specific options for
8 8 the request, you can pass them in the `request_params` option and they will
9 9 be merged into the base request that is prepared.
10 +
11 + ## Timeout configuration
12 +
13 + The HTTP receive timeout (how long to wait for data from Bedrock before giving
14 + up) can be tuned via application config. The lookup order is:
15 +
16 + 1. `config :llm_composer, :bedrock, receive_timeout: <ms>` — Bedrock-specific override
17 + 2. `config :llm_composer, :timeout, <ms>` — global llm_composer timeout
18 + 3. Default: `30_000` ms (30 s)
19 +
20 + Example:
21 +
22 + config :llm_composer, :bedrock, receive_timeout: 60_000
23 +
24 + The timeout applies to all Mint-based requests (streaming and non-streaming).
25 + Finch regular (non-streaming) requests use Finch's own timeout configuration.
10 26 """
11 27 @behaviour LlmComposer.Provider
  @@ -31,7 +31,7 @@ if Code.ensure_loaded?(ExAws) do
31 31
32 32 require Logger
33 33
34 - @stream_timeout 30_000
34 + @default_receive_timeout 30_000
35 35
36 36 @impl ExAws.Request.HttpClient
37 37 @spec request(
  @@ -159,7 +159,7 @@ if Code.ensure_loaded?(ExAws) do
159 159 stream_mint_loop(conn, ref, caller)
160 160 end
161 161 after
162 - @stream_timeout ->
162 + receive_timeout() ->
163 163 send(caller, {:bedrock_stream, :done})
164 164 end
165 165 end
  @@ -232,7 +232,7 @@ if Code.ensure_loaded?(ExAws) do
232 232 collect_mint_response(conn, ref, acc)
233 233 end
234 234 after
235 - @stream_timeout -> {:error, %{reason: :timeout}}
235 + receive_timeout() -> {:error, %{reason: :timeout}}
236 236 end
237 237 end
238 238
  @@ -290,7 +290,7 @@ if Code.ensure_loaded?(ExAws) do
290 290 {:DOWN, ^ref, :process, _pid, reason} ->
291 291 {:error, {:task_crashed, reason}}
292 292 after
293 - @stream_timeout -> {:error, :timeout_waiting_for_headers}
293 + receive_timeout() -> {:error, :timeout_waiting_for_headers}
294 294 end
295 295
296 296 {:bedrock_stream, {:error, reason}} ->
  @@ -299,7 +299,7 @@ if Code.ensure_loaded?(ExAws) do
299 299 {:DOWN, ^ref, :process, _pid, reason} ->
300 300 {:error, {:task_crashed, reason}}
301 301 after
302 - @stream_timeout -> {:error, :timeout_waiting_for_status}
302 + receive_timeout() -> {:error, :timeout_waiting_for_status}
303 303 end
304 304 end
305 305
  @@ -311,7 +311,7 @@ if Code.ensure_loaded?(ExAws) do
311 311 {:bedrock_stream, {:error, _reason}} -> acc
312 312 {:DOWN, ^ref, :process, _pid, _reason} -> acc
313 313 after
314 - @stream_timeout -> acc
314 + receive_timeout() -> acc
315 315 end
316 316 end
317 317
  @@ -326,13 +326,23 @@ if Code.ensure_loaded?(ExAws) do
326 326 {:bedrock_stream, {:error, _reason}} -> {:halt, state}
327 327 {:DOWN, ^ref, :process, _pid, _reason} -> {:halt, state}
328 328 after
329 - @stream_timeout -> {:halt, state}
329 + receive_timeout() -> {:halt, state}
330 330 end
331 331 end,
332 332 fn _state -> :ok end
333 333 )
334 334 end
335 335
336 + @spec receive_timeout() :: non_neg_integer()
337 + defp receive_timeout do
338 + bedrock_timeout =
339 + :llm_composer
340 + |> Application.get_env(:bedrock, [])
341 + |> Keyword.get(:receive_timeout)
342 +
343 + bedrock_timeout || Application.get_env(:llm_composer, :timeout, @default_receive_timeout)
344 + end
345 +
336 346 @spec finch_name() :: {:ok, atom()} | :error
337 347 defp finch_name do
338 348 case Application.get_env(:llm_composer, :tesla_adapter) do
  @@ -4,7 +4,7 @@ defmodule LlmComposer.MixProject do
4 4 def project do
5 5 [
6 6 app: :llm_composer,
7 - version: "0.19.4",
7 + version: "0.19.5",
8 8 elixir: "~> 1.18",
9 9 start_permanent: Mix.env() == :prod,
10 10 deps: deps(),