Skip to content

Commit

Permalink
updated readme. fixes to docs
Browse files Browse the repository at this point in the history
  • Loading branch information
lebrunel committed Mar 13, 2024
1 parent b272197 commit cbd9b42
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 28 deletions.
113 changes: 106 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
![License](https://img.shields.io/github/license/lebrunel/anthropix?color=informational)
![Build Status](https://img.shields.io/github/actions/workflow/status/lebrunel/anthropix/elixir.yml?branch=main)

An up-to-date and fully-featured Elixir client library for [Anthropic's REST API](https://docs.anthropic.com/claude/reference/getting-started-with-the-api).
Anthropix is an open-source Elixir client for the Anthropic API, providing a simple and convenient way to integrate Claude, Anthropic's powerful language model, into your applications.

- ✅ API client fully implementing the Anthropic API
- ✅ API client fully implementing the [Anthropic API](https://docs.anthropic.com/claude/reference/getting-started-with-the-api)
- 🛜 Streaming API requests
- Stream to an Enumerable
- Or stream messages to any Elixir process
- 🔜 Advanced and flexible function calling workflow

This library is currently a WIP. Check back in a week or two, by which point it should be bangin!
- 🕶️ Powerful yet painless function calling with **Agents**

## Installation

Expand All @@ -21,14 +19,115 @@ The package can be installed by adding `anthropix` to your list of dependencies
```elixir
def deps do
[
{:anthropix, "0.0.1"}
{:anthropix, "#{@version}"}
]
end
```

## Quickstart

TODO...
For more examples, refer to the [Anthropix documentation](https://hexdocs.pm/anthropix).

### Initiate a client.

See `Anthropix.init/2`.

```elixir
client = Anthropix.init(api_key)
```

### Chat with Claude

See `Anthropix.chat/2`.

```elixir
messages = [
%{role: "system", content: "You are a helpful assistant."},
%{role: "user", content: "Why is the sky blue?"},
%{role: "assistant", content: "Due to rayleigh scattering."},
%{role: "user", content: "How is that different than mie scattering?"},
]

Anthropix.chat(client, [
model: "claude-3-opus-20240229",
messages: messages,
])
# {:ok, %{"content" => [%{
# "type" => "text",
# "text" => "Mie scattering affects all wavelengths similarly, while Rayleigh favors shorter ones."
# }], ...}}
```

### Streaming

A streaming request can be initiated by setting the `:stream` option.

When `:stream` is true a lazy `t:Enumerable.t/0` is returned which can be used with any `Stream` functions.

```elixir
{:ok, stream} = Anthropix.chat(client, [
model: "claude-3-opus-20240229",
messages: messages,
stream: true,
])
# {:ok, #Function<52.53678557/2 in Stream.resource/3>}

stream
|> Stream.each(&update_ui_with_chunk/1)
|> Stream.run()
# :ok
```

Because the above approach builds the `t:Enumerable.t/0` by calling `receive`, using this approach inside GenServer callbacks may cause the GenServer to misbehave. Setting the `:stream` option to a `t:pid/0` returns a `t:Task.t/0` which will send messages to the specified process.

## Function calling

Chatting with Claude is nice and all, but when it comes to function calling, Anthropix has a trick up its sleeve. Meet `Anthropix.Agent`.

The Agent module abstracts away all the rough bits of implementing [Anthropic style function calling](https://docs.anthropic.com/claude/docs/functions-external-tools), leaving a delightfully simple API that opens the doors to powerful and advanced agent workflows.

```elixir
ticker_tool = %Anthropix.Tool.new([
name: "get_ticker_symbol",
description: "Gets the stock ticker symbol for a company searched by name. Returns str: The ticker symbol for the company stock. Raises TickerNotFound: if no matching ticker symbol is found.",
params: [
%{name: "company_name", description: "The name of the company.", type: "string"}
],
function: &MyStocks.get_ticker/1
])

price_tool = %Anthropix.Tool.new([
name: "get_current_stock_price",
description: "Gets the current stock price for a company. Returns float: The current stock price. Raises ValueError: if the input symbol is invalid/unknown.",
params: [
%{name: "symbol", description: "The stock symbol of the company to get the price for.", type: "string"}
],
function: &MyStocks.get_price/1
])

agent = Anthropix.Agent.init(
Anthropix.init(api_key),
[ticker_tool, price_tool]
)

Anthropix.Agent.chat(agent, [
model: "claude-3-sonnet-20240229",
system: "Answer like Snoop Dogg.",
messages: [
%{role: "user", content: "What is the current stock price of General Motors?"}
]
])
%{
result: %{
"content" => [%{
"type" => "text",
"text" => "*snaps fingers* Damn shawty, General Motors' stock is sittin' pretty at $39.21 per share right now. Dat's a fly price for them big ballers investin' in one of Detroit's finest auto makers, ya heard? *puts hands up like car doors* If ya askin' Snoop, dat stock could be rollin' on some dubs fo' sho'. Just don't get caught slippin' when them prices dippin', ya dig?"
}]
}
}
```

For a more detailed walkthrough, refer to the `Anthropix.Agent` documentation.

# License

Expand Down
123 changes: 115 additions & 8 deletions lib/anthropix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ defmodule Anthropix do
@moduledoc """
![License](https://img.shields.io/github/license/lebrunel/anthropix?color=informational)
An up-to-date and fully-featured Elixir client library for
[Anthropic's REST API](https://docs.anthropic.com/claude/reference/getting-started-with-the-api).
Anthropix is an open-source Elixir client for the Anthropic API, providing a
simple and convenient way to integrate Claude, Anthropic's powerful language
model, into your applications.
- ✅ API client fully implementing the Anthropic API
- ✅ API client fully implementing the [Anthropic API](https://docs.anthropic.com/claude/reference/getting-started-with-the-api)
- 🛜 Streaming API requests
- Stream to an Enumerable
- Or stream messages to any Elixir process
- 🧩 Advanced and flexible function calling workflow
This library is currently a WIP. Check back in a week or two, by which point
it should be bangin!
- 🕶️ Powerful yet painless function calling with **Agents**
## Installation
Expand All @@ -30,7 +28,116 @@ defmodule Anthropix do
## Quickstart
TODO...
For more examples, refer to the [Anthropix documentation](https://hexdocs.pm/anthropix).
### Initiate a client.
See `Anthropix.init/2`.
```elixir
iex> client = Anthropix.init(api_key)
```
### Chat with Claude
See `Anthropix.chat/2`.
```elixir
iex> messages = [
...> %{role: "system", content: "You are a helpful assistant."},
...> %{role: "user", content: "Why is the sky blue?"},
...> %{role: "assistant", content: "Due to rayleigh scattering."},
...> %{role: "user", content: "How is that different than mie scattering?"},
...> ]
iex> Anthropix.chat(client, [
...> model: "claude-3-opus-20240229",
...> messages: messages,
...> ])
{:ok, %{"content" => [%{
"type" => "text",
"text" => "Mie scattering affects all wavelengths similarly, while Rayleigh favors shorter ones."
}], ...}}
```
### Streaming
A streaming request can be initiated by setting the `:stream` option.
When `:stream` is true a lazy `t:Enumerable.t/0` is returned which can be used
with any `Stream` functions.
```elixir
iex> {:ok, stream} = Anthropix.chat(client, [
...> model: "claude-3-opus-20240229",
...> messages: messages,
...> stream: true,
...> ])
{:ok, #Function<52.53678557/2 in Stream.resource/3>}
iex> stream
...> |> Stream.each(&update_ui_with_chunk/1)
...> |> Stream.run()
:ok
```
Because the above approach builds the `t:Enumerable.t/0` by calling `receive`,
using this approach inside GenServer callbacks may cause the GenServer to
misbehave. Setting the `:stream` option to a `t:pid/0` returns a `t:Task.t/0`
which will send messages to the specified process.
## Function calling
Chatting with Claude is nice and all, but when it comes to function calling,
Anthropix has a trick up its sleeve. Meet `Anthropix.Agent`.
The Agent module abstracts away all the rough bits of implementing
[Anthropic style function calling](https://docs.anthropic.com/claude/docs/functions-external-tools),
leaving a delightfully simple API that opens the doors to powerful and
advanced agent workflows.
```elixir
iex> ticker_tool = %Anthropix.Tool.new([
...> name: "get_ticker_symbol",
...> description: "Gets the stock ticker symbol for a company searched by name. Returns str: The ticker symbol for the company stock. Raises TickerNotFound: if no matching ticker symbol is found.",
...> params: [
...> %{name: "company_name", description: "The name of the company.", type: "string"}
...> ],
...> function: &MyStocks.get_ticker/1
...> ])
iex> price_tool = %Anthropix.Tool.new([
...> name: "get_current_stock_price",
...> description: "Gets the current stock price for a company. Returns float: The current stock price. Raises ValueError: if the input symbol is invalid/unknown.",
...> params: [
...> %{name: "symbol", description: "The stock symbol of the company to get the price for.", type: "string"}
...> ],
...> function: &MyStocks.get_price/1
...> ])
iex> agent = Anthropix.Agent.init(
...> Anthropix.init(api_key),
...> [ticker_tool, price_tool]
...> )
iex> Anthropix.Agent.chat(agent, [
...> model: "claude-3-sonnet-20240229",
...> system: "Answer like Snoop Dogg.",
...> messages: [
...> %{role: "user", content: "What is the current stock price of General Motors?"}
...> ]
...> ])
%{
result: %{
"content" => [%{
"type" => "text",
"text" => "*snaps fingers* Damn shawty, General Motors' stock is sittin' pretty at $39.21 per share right now. Dat's a fly price for them big ballers investin' in one of Detroit's finest auto makers, ya heard? *puts hands up like car doors* If ya askin' Snoop, dat stock could be rollin' on some dubs fo' sho'. Just don't get caught slippin' when them prices dippin', ya dig?"
}]
}
}
```
For a more detailed walkthrough, refer to the `Anthropix.Agent` documentation.
"""
use Anthropix.Schemas
alias Anthropix.{APIError, Tool, XML}
Expand Down
4 changes: 2 additions & 2 deletions lib/anthropix/agent.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule Anthropix.Agent do
@moduledoc """
The `Agent` module makes function calling with Claude a breeze!
The `Anthropix.Agent` module makes function calling with Claude a breeze!
Whilst it's possible to manually implement function calling using
`Anthropix.chat/2`, this module provides an interface on top that automates
Expand All @@ -15,7 +15,7 @@ defmodule Anthropix.Agent do
automatically, send the result back to Claude, iterating as many times as is
necessary before ultimately a final result is returned.
`chat/2` returns a `t:t()` struct, which contains a list of all
`chat/2` returns a `t:t/0` struct, which contains a list of all
messages, a sum of all usage statistics, as well as the final response.
## Example
Expand Down
2 changes: 1 addition & 1 deletion lib/anthropix/function_call.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule Anthropix.FunctionCall do
@moduledoc """
The `FunctionCall` module is used to capture function calls from Claud's
The `Anthropix.FunctionCall` module is used to capture function calls from Claud's
responses and, match the function call to an existing `t:Anthropix.Tool.t/0`,
and then invoke the function.
Expand Down
2 changes: 1 addition & 1 deletion lib/anthropix/tool.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule Anthropix.Tool do
@moduledoc """
The `Tool` module allows you to let Claude call functions in your application.
The `Anthropix.Tool` module allows you to let Claude call functions in your application.
The `t:Anthropix.Tool.t/0` struct wraps around any function in your
application - referenced functions, anonymous functions, or MFA style
Expand Down
8 changes: 5 additions & 3 deletions lib/anthropix/xml.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ defmodule Anthropix.XML do
@allowed_roots [:tools, :function_results]

@doc """
Encodes the given data into the specified message type. Supports encoding
a list of `t:Tool.t()` structs into a `:tools` message, or a list of
`t:FunctionCall.t()` structs into a `:function_results` message.
Encodes the given data into the specified message type.
Supports encoding a list of `t:Anthropix.Tool.t/0` structs into a `:tools`
message, or a list of `t:Anthropix.FunctionCall.t/0` structs into a
`:function_results` message.
## Examples
Expand Down
5 changes: 2 additions & 3 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Anthropix.MixProject do
[
app: :anthropix,
name: "Anthropix",
description: "todo",
description: "Anthropix is an open-source Elixir client with interacting with Claude, Anthropic's powerful language model.",
source_url: "https://github.com/lebrunel/anthropix",
version: "0.0.1",
elixir: "~> 1.13",
Expand Down Expand Up @@ -36,11 +36,10 @@ defmodule Anthropix.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:bandit, "~> 1.2", only: :test},
{:ex_doc, "~> 0.31", only: :dev, runtime: false},
{:jason, "~> 1.4"},
{:nimble_options, "~> 1.1"},
{:plug, "~> 1.15"},
{:plug, "~> 1.15", only: :test},
{:req, "~> 0.4"},
{:saxy, "~> 1.5"},
]
Expand Down
3 changes: 0 additions & 3 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
%{
"bandit": {:hex, :bandit, "1.3.0", "6a4e8d7c9ea721edd02c389e2cc867890cd96f83116e71ddf1ccbdd80661550c", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "bda37d6c614d74778a5dc43b8bcdc3245cd30619eab0342f58042f968f2165da"},
"castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"},
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"},
Expand All @@ -20,6 +19,4 @@
"req": {:hex, :req, "0.4.13", "6fde45b78e606e2a46fc3a7e4a74828c220cd0b16951f4321c1214f955402d72", [:mix], [{:aws_signature, "~> 0.3.2", [hex: :aws_signature, repo: "hexpm", optional: true]}, {:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:nimble_ownership, "~> 0.2.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "e01a596b74272de799bc57191883e5d4d3875be63f0480223edc5a0086bfe31b"},
"saxy": {:hex, :saxy, "1.5.0", "0141127f2d042856f135fb2d94e0beecda7a2306f47546dbc6411fc5b07e28bf", [:mix], [], "hexpm", "ea7bb6328fbd1f2aceffa3ec6090bfb18c85aadf0f8e5030905e84235861cf89"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
}

0 comments on commit cbd9b42

Please sign in to comment.