Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [0.20.0] - 2026-06-29

### Added
- Added `:sse_middleware` option for streaming responses, allowing consumers to inject a custom SSE middleware instead of the default `Tesla.Middleware.SSE`.
Comment thread
nvelasco marked this conversation as resolved.
- Added `LlmComposer.Agent` — an automatic tool-calling loop that runs the full ask → execute → repeat cycle until the model returns a final answer. Supports sequential and parallel tool execution, configurable iteration limit, and per-tool error recovery.
- Added streaming support to `LlmComposer.Agent` (`stream_response: true`). Returns a lazy stream of `StreamChunk`s with `:text_delta`, `:tool_call` (one per executed tool, result included), and a terminal `:done` chunk carrying cumulative usage and the full `Agent.Result`. Supported providers: `:open_ai`, `:open_router`, `:open_ai_responses`, `:google`, `:bedrock`, `:ollama`.
- Added `:tool_call` chunk type to `LlmComposer.StreamChunk` — emitted by the streaming agent after each tool execution, making the stream self-contained without needing a telemetry handler.
Expand Down Expand Up @@ -297,10 +298,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- **Include Bedrock Support**: Included Bedrock support as provider only with `completion()`s support.

## [0.3.5] - 2024-12-18
- **Fix default api_key setting value**: The default value was en empty string. Now it is nil to be evaluated as false when getting the key from the map later.
- **Fix default api_key setting value**: The default value was en empty string. Now it is nil to be evaluated as false when getting the key from the map later.

## [0.3.4] - 2024-12-17
- **OpenAI API Keys**: Use an API key passed as a parameter when calling chat_completion — overriding the global API key defined in the config. The param is sent inside the settings.
- **OpenAI API Keys**: Use an API key passed as a parameter when calling chat_completion — overriding the global API key defined in the config. The param is sent inside the settings.

## [0.3.3] - 2024-12-04
- **Timeouts**: Configurable OpenAI's timeout. Default set to 50 seconds.
Expand Down
2 changes: 1 addition & 1 deletion lib/llm_composer/http_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ defmodule LlmComposer.HttpClient do

cond do
stream ->
resp ++ [{Tesla.Middleware.SSE, only: :data}]
resp ++ Keyword.get(opts, :sse_middleware, [{Tesla.Middleware.SSE, only: :data}])

retries_disabled?(opts) ->
resp ++
Expand Down
4 changes: 4 additions & 0 deletions lib/llm_composer/providers_runner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,12 @@ defmodule LlmComposer.ProvidersRunner do
|> Keyword.put_new(:stream_response, settings.stream_response)
|> Keyword.put_new(:track_costs, settings.track_costs)
|> Keyword.put_new(:api_key, settings.api_key)
|> maybe_put_sse_middleware(settings)
end

defp maybe_put_sse_middleware(opts, %{sse_middleware: nil}), do: opts
defp maybe_put_sse_middleware(opts, %{sse_middleware: middleware}), do: Keyword.put_new(opts, :sse_middleware, middleware)

defp get_provider_router do
:llm_composer
|> Application.get_env(:provider_router, [])
Expand Down
3 changes: 3 additions & 0 deletions lib/llm_composer/settings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule LlmComposer.Settings do
provider: nil,
provider_opts: nil,
providers: nil,
sse_middleware: nil,
stream_response: false,
system_prompt: nil,
track_costs: false,
Expand All @@ -21,6 +22,7 @@ defmodule LlmComposer.Settings do
- `:provider` — provider module (e.g. `LlmComposer.Providers.OpenAI`). Used with `:provider_opts`.
- `:provider_opts` — keyword list of options forwarded to the single provider.
- `:providers` — list of `{module, opts}` tuples for multi-provider routing via `ProvidersRunner`.
- `:sse_middleware` — custom Tesla SSE middleware list to use instead of the default `Tesla.Middleware.SSE` when `stream_response: true`. Useful when the provider sends incomplete SSE chunks that would crash the default middleware.
- `:stream_response` — when `true`, the provider returns a streaming enumerable.
- `:system_prompt` — system prompt string sent to the model.
- `:track_costs` — when `true`, token usage and cost are computed and attached to the response.
Expand All @@ -31,6 +33,7 @@ defmodule LlmComposer.Settings do
provider: module() | nil,
provider_opts: keyword() | nil,
providers: [{module(), keyword()}] | nil,
sse_middleware: [{module(), keyword()}] | nil,
stream_response: boolean(),
system_prompt: String.t() | nil,
track_costs: boolean(),
Expand Down