Current section
9 Versions
Jump to
Current section
9 Versions
Compare versions
12
files changed
+183
additions
-209
deletions
| @@ -1,3 +1,17 @@ | |
| 1 | + ## 0.4.1 - 2024-03-13 |
| 2 | + |
| 3 | + ### Improved |
| 4 | + - Removed GenServer from `Anthropic.Config`. It will be created from `Application.get_env` or from the supplied options. |
| 5 | + - Added Mox to test environment. |
| 6 | + - Increased test coverage. |
| 7 | + |
| 8 | + ### Breaking change |
| 9 | + - Changed the tool field type to MapSet |
| 10 | + |
| 11 | + ### Improved |
| 12 | + - Better system function concatenation with tools description |
| 13 | + - Moved List.reverse from messages to Jason.Encoder implementation. |
| 14 | + |
| 1 15 | ## 0.4.0 - 2024-03-13 |
| 2 16 | |
| 3 17 | ### Improved |
| @@ -10,6 +10,7 @@ This unofficial Elixir wrapper provides a convenient way to interact with the [A | |
| 10 10 | |
| 11 11 | ## To-dos |
| 12 12 | - Add streaming handling |
| 13 | + - Allow for Tool do define different models. |
| 13 14 | |
| 14 15 | ## Installation |
| 15 16 | The package can be installed by adding `anthropic` to your list of dependencies in `mix.exs`: |
| @@ -23,7 +24,7 @@ end | |
| 23 24 | ``` |
| 24 25 | |
| 25 26 | ## Configuration |
| 26 | - Add or create a config file to provide the `api_key` as in the example below. |
| 27 | + Add or create a config file to provide the `api_key` as in the example below. Or pass an `:api_key` as option on `Anthropic.new(api_key: "key")` |
| 27 28 | |
| 28 29 | ```elixir |
| 29 30 | # config/config.exs |
| @@ -103,7 +104,7 @@ end | |
| 103 104 | |
| 104 105 | {:ok, response, request} = |
| 105 106 | Anthropic.new() |
| 106 | - |> Anthropic.register_tool(MyTool) |
| 107 | + |> Anthropic.register_tool(MyApp.WeatherTool) |
| 107 108 | |> Anthropic.add_user_message("Use the MyApp.WeatherTool to perform a task.") |
| 108 109 | |> Anthropic.request_next_message() |
| 109 110 | |> Anthropic.process_invocations() |
| @@ -1,7 +1,7 @@ | |
| 1 1 | {<<"links">>, |
| 2 2 | [{<<"GitHub">>,<<"https://github.com/tubedude/anthropic-community">>}]}. |
| 3 3 | {<<"name">>,<<"anthropic_community">>}. |
| 4 | - {<<"version">>,<<"0.4.0">>}. |
| 4 | + {<<"version">>,<<"0.4.1">>}. |
| 5 5 | {<<"description">>,<<"Unofficial Anthropic API wrapper.">>}. |
| 6 6 | {<<"elixir">>,<<"~> 1.15">>}. |
| 7 7 | {<<"app">>,<<"anthropic">>}. |
| @@ -36,6 +36,7 @@ | |
| 36 36 | <<"lib/anthropic/messages/request.ex">>, |
| 37 37 | <<"lib/anthropic/messages/content">>, |
| 38 38 | <<"lib/anthropic/messages/content/image.ex">>,<<"lib/anthropic/config.ex">>, |
| 39 | - <<"lib/anthropic/application.ex">>,<<"lib/anthropic.ex">>, |
| 40 | - <<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"CHANGELOG.md">>]}. |
| 39 | + <<"lib/anthropic/http_client.ex">>,<<"lib/anthropic/application.ex">>, |
| 40 | + <<"lib/anthropic.ex">>,<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>, |
| 41 | + <<"CHANGELOG.md">>]}. |
| 41 42 | {<<"build_tools">>,[<<"mix">>]}. |
| @@ -64,15 +64,16 @@ defmodule Anthropic do | |
| 64 64 | By attaching to these events, you can monitor the performance and health of your Anthropic API integration, track usage metrics, and handle exceptions as needed. |
| 65 65 | """ |
| 66 66 | |
| 67 | + require Logger |
| 67 68 | alias Anthropic.Messages.Response |
| 68 69 | alias Anthropic.Messages.Request |
| 69 70 | alias Anthropic.Messages.Content.Image |
| 70 71 | alias Anthropic.Config |
| 71 72 | |
| 72 73 | @type role :: :user | :assistant |
| 73 | - @type message :: %{role: role, content: any()} |
| 74 | + @type message :: %{role: role(), content: any()} |
| 74 75 | |
| 75 | - @spec new(Anthropic.Config.config_options() | nil) :: Anthropic.Messages.Request.t() |
| 76 | + @spec new(keyword()) :: struct() |
| 76 77 | @doc """ |
| 77 78 | Initializes a new `Anthropic.Messages.Request` struct with the given options, merging them with the default configuration `Anthropic.Config`. |
| 78 79 | |
| @@ -85,9 +86,17 @@ defmodule Anthropic do | |
| 85 86 | - A new `Anthropic.Messages.Request` struct populated with the merged configuration options. |
| 86 87 | """ |
| 87 88 | def new(opts \\ []) do |
| 88 | - Config.opts() |
| 89 | - |> Map.merge(Enum.into(opts, %{})) |
| 90 | - |> then(fn map -> struct(Anthropic.Config, map) end) |
| 89 | + config = |
| 90 | + case Keyword.get(opts, :config, Config.create(opts)) do |
| 91 | + %Anthropic.Config{} = value -> |
| 92 | + value |
| 93 | + |
| 94 | + error -> |
| 95 | + raise ArgumentError, |
| 96 | + "Config must be a valid %Anthropic.Config{}. Got: #{inspect(error)}" |
| 97 | + end |
| 98 | + |
| 99 | + Keyword.merge(opts, config: config) |
| 91 100 | |> Request.create() |
| 92 101 | end |
| 93 102 | |
| @@ -120,11 +129,6 @@ defmodule Anthropic do | |
| 120 129 | "System message must be type String, got #{inspect(message, limit: 50, structs: false, width: 80)}" |
| 121 130 | ) |
| 122 131 | |
| 123 | - @spec add_message( |
| 124 | - Anthropic.Messages.Request.t(), |
| 125 | - role(), |
| 126 | - String.t() | [String.t()] | Request.content_object() | [Request.content_object()] |
| 127 | - ) :: Anthropic.Messages.Request.t() |
| 128 132 | @doc """ |
| 129 133 | Adds a message to the request with a specified role. |
| 130 134 | |
| @@ -161,6 +165,7 @@ defmodule Anthropic do | |
| 161 165 | %{type: "image", source: %{data: "base64_encoded_data", type: "base64", media_type: "image/png"}} |
| 162 166 | ] |
| 163 167 | request = Anthropic.add_message(request, :user, content_objects) |
| 168 | + ``` |
| 164 169 | """ |
| 165 170 | def add_message(%Request{messages: messages} = request, role, content) when is_list(content) do |
| 166 171 | content_objects = |
| @@ -172,9 +177,7 @@ defmodule Anthropic do | |
| 172 177 | |
| 173 178 | updated_messages = |
| 174 179 | messages |
| 175 | - |> Enum.reverse() |
| 176 | - |> then(fn list -> [%{role: role, content: content_objects} | list] end) |
| 177 | - |> Enum.reverse() |
| 180 | + |> List.insert_at(0, %{role: role, content: content_objects}) |
| 178 181 | |
| 179 182 | %{request | messages: updated_messages} |
| 180 183 | end |
| @@ -206,13 +209,6 @@ defmodule Anthropic do | |
| 206 209 | add_message(%Request{} = request, :user, message) |
| 207 210 | end |
| 208 211 | |
| 209 | - @spec add_assistant_message( |
| 210 | - Anthropic.Messages.Request.t(), |
| 211 | - Anthropic.Messages.Request.message() |
| 212 | - | list(Anthropic.Messages.Request.message()) |
| 213 | - | binary() |
| 214 | - | list(binary()) |
| 215 | - ) :: Anthropic.Messages.Request.t() |
| 216 212 | @doc """ |
| 217 213 | Adds a assistant message to the request. |
| 218 214 | |
| @@ -320,20 +316,31 @@ defmodule Anthropic do | |
| 320 316 | """ |
| 321 317 | @doc since: "0.4.0" |
| 322 318 | def register_tool(%Request{} = request, tool_module) when is_atom(tool_module) do |
| 323 | - case {Code.ensure_loaded?(tool_module), Enum.member?(request.tools, tool_module)} do |
| 324 | - {true, true} -> |
| 325 | - request |
| 326 | - |
| 327 | - {true, false} -> |
| 328 | - %{request | tools: [tool_module | request.tools]} |
| 329 | - |
| 330 | - {false, _} -> |
| 319 | + if Code.ensure_loaded?(tool_module) do |
| 320 | + %{request | tools: MapSet.put(request.tools, tool_module)} |
| 321 | + else |
| 331 322 | raise ArgumentError, |
| 332 323 | "Module #{tool_module} is not loaded. Please use module full name (MyApp.AnthropicTool)" |
| 333 324 | end |
| 325 | + |
| 326 | + # case {Code.ensure_loaded?(tool_module), Enum.member?(request.tools, tool_module)} do |
| 327 | + # {true, true} -> |
| 328 | + # request |
| 329 | + |
| 330 | + # {true, false} -> |
| 331 | + # %{request | tools: [tool_module | request.tools]} |
| 332 | + |
| 333 | + # {false, _} -> |
| 334 | + # raise ArgumentError, |
| 335 | + # "Module #{tool_module} is not loaded. Please use module full name (MyApp.AnthropicTool)" |
| 336 | + # end |
| 334 337 | end |
| 335 338 | |
| 336 | - @spec request_next_message(Anthropic.Messages.Request.t(), any()) :: any() |
| 339 | + def remove_tool(%Request{} = request, tool_module) do |
| 340 | + %{request | tools: MapSet.delete(request.tools, tool_module)} |
| 341 | + end |
| 342 | + |
| 343 | + @spec request_next_message(Anthropic.Messages.Request.t(), keyword() | nil) :: any() |
| 337 344 | @doc """ |
| 338 345 | Sends the current request to the Anthropic API and awaits the next message in the conversation. |
| 339 346 | |
| @@ -365,7 +372,6 @@ defmodule Anthropic do | |
| 365 372 | |> wrap_to_telemetry() |
| 366 373 | end |
| 367 374 | |
| 368 | - # Prepares the response from the API for successful requests, updating the request with the assistant's message. |
| 369 375 | defp prepare_response({:ok, response}, request) do |
| 370 376 | updated_request = |
| 371 377 | request |
| @@ -374,7 +380,6 @@ defmodule Anthropic do | |
| 374 380 | {:ok, response, updated_request} |
| 375 381 | end |
| 376 382 | |
| 377 | - # Handles error responses from the API, passing through the error and the original request for further handling. |
| 378 383 | defp prepare_response({:error, response}, request) do |
| 379 384 | {:error, response, request} |
| 380 385 | end |
| @@ -6,8 +6,7 @@ defmodule Anthropic.Application do | |
| 6 6 | @doc false |
| 7 7 | def start(_type, _args) do |
| 8 8 | children = [ |
| 9 | - Anthropic.Config, |
| 10 | - {Finch, name: Anthropic.HTTPClient} |
| 9 | + {Finch, name: Anthropic.HTTPClient.Engine} |
| 11 10 | ] |
| 12 11 | |
| 13 12 | opts = [strategy: :one_for_one, name: Anthropic.Supervisor] |
Loading more files…