Skip to content

Commit

Permalink
Update to use assistants API v2 and drop org id
Browse files Browse the repository at this point in the history
Regarding org ID, all clients should be using project-specific API keys
now.
  • Loading branch information
jwilger committed Oct 8, 2024
1 parent 29b1a06 commit 3d8b5d6
Show file tree
Hide file tree
Showing 4 changed files with 5 additions and 109 deletions.
2 changes: 0 additions & 2 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,4 @@ config :open_ai_client,
:openai_api_key,
System.get_env("OPENAI_API_KEY") || raise("OPENAI_API_KEY is not set")

config :open_ai_client, :openai_organization_id, System.get_env("OPENAI_ORGANIZATION_ID")

config :open_ai_client, :receive_timeout, System.get_env("OPENAI_RECEIVE_TIMEOUT") || 600_000
20 changes: 3 additions & 17 deletions lib/open_ai_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ defmodule OpenAiClient do
This client supports all options provided by the `Req` library, as well as additional options:
- :breaker - a circuit breaker module (default: `ExBreak`)
- :openai_organization - the OpenAI organization ID
"""

import Req.Request, only: [put_new_header: 3]
Expand Down Expand Up @@ -65,15 +64,12 @@ defmodule OpenAiClient do
end

defp build_request(url, options) do
openai_organization = options[:openai_organization] || default_organization()
options = Keyword.delete(options, :openai_organization)

options
|> Keyword.put(:url, url)
|> validate_options()
|> remove_nil_values()
|> Req.new()
|> set_headers(openai_organization: openai_organization)
|> set_headers()
end

defp validate_options(options) do
Expand Down Expand Up @@ -107,17 +103,7 @@ defmodule OpenAiClient do
Application.get_env(:open_ai_client, :openai_api_key)
end

defp default_organization do
Application.get_env(:open_ai_client, :openai_organization_id)
end

defp set_headers(%Req.Request{} = req, options) when is_list(options) do
req
|> put_new_header("openai-beta", "assistants=v1")
|> then(
&if options[:openai_organization],
do: put_new_header(&1, "openai-organization", options[:openai_organization]),
else: &1
)
defp set_headers(%Req.Request{} = req) do
put_new_header(req, "openai-beta", "assistants=v2")
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule OpenAiClient.MixProject do
[
app: :open_ai_client,
description: "OpenAI API client for Elixir",
version: "2.1.0",
version: "3.0.0",
elixir: "~> 1.15",
start_permanent: Mix.env() == :prod,
aliases: aliases(),
Expand Down
90 changes: 1 addition & 89 deletions test/open_ai_client_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ defmodule OpenAiClientTest do
bypass: bypass
} do
Bypass.expect_once(bypass, "POST", "/foo", fn conn ->
assert {"openai-beta", "assistants=v1"} in conn.req_headers
assert {"openai-beta", "assistants=v2"} in conn.req_headers

Plug.Conn.resp(conn, 201, "")
end)
Expand All @@ -77,62 +77,6 @@ defmodule OpenAiClientTest do
)
end

test "adds the openai_organization_id as a request header when it is a string", %{
bypass: bypass
} do
organization_id = "test_organization_id"

Bypass.expect_once(bypass, "POST", "/foo", fn conn ->
assert {"openai-organization", organization_id} in conn.req_headers

Plug.Conn.resp(conn, 201, "")
end)

{:ok, _response} =
OpenAiClient.post("/foo",
base_url: endpoint_url(bypass),
openai_organization: organization_id,
breaker: MockBreaker
)
end

test "does not include the OpenAI-Organization header when the organization_id is nil", %{
bypass: bypass
} do
Bypass.expect_once(bypass, "POST", "/foo", fn conn ->
refute Enum.any?(conn.req_headers, fn {key, _value} -> key == "openai-organization" end)

Plug.Conn.resp(conn, 201, "")
end)

{:ok, _response} =
OpenAiClient.post("/foo", base_url: endpoint_url(bypass), breaker: MockBreaker)
end

test "retries the request on a 408, 429, 500, 502, 503, or 504 http status response", %{
bypass: bypass
} do
retry_statuses = [408, 429, 500, 502, 503, 504]
{:ok, _pid} = Agent.start_link(fn -> 0 end, name: :retry_counter)

Enum.each(retry_statuses, fn status ->
Bypass.expect(bypass, "POST", "/foo", fn conn ->
Agent.update(:retry_counter, &(&1 + 1))
Plug.Conn.resp(conn, status, "")
end)

assert {:ok, %{status: ^status}} =
OpenAiClient.post("/foo",
base_url: endpoint_url(bypass),
retry_delay: 0,
retry_log_level: false,
breaker: MockBreaker
)

assert Agent.get_and_update(:retry_counter, fn value -> {value, 0} end) == 4
end)
end

test "MockBreaker is called with the expected arguments", %{
bypass: bypass
} do
Expand Down Expand Up @@ -188,38 +132,6 @@ defmodule OpenAiClientTest do
OpenAiClient.get("/foo", base_url: endpoint_url(bypass), breaker: MockBreaker)
end

test "adds the openai_organization_id as a request header when it is a string", %{
bypass: bypass
} do
organization_id = "test_organization_id"

Bypass.expect_once(bypass, "GET", "/foo", fn conn ->
assert {"openai-organization", organization_id} in conn.req_headers

Plug.Conn.resp(conn, 200, "")
end)

{:ok, _response} =
OpenAiClient.get("/foo",
base_url: endpoint_url(bypass),
openai_organization: organization_id,
breaker: MockBreaker
)
end

test "does not include the OpenAI-Organization header when the organization_id is nil", %{
bypass: bypass
} do
Bypass.expect_once(bypass, "GET", "/foo", fn conn ->
refute Enum.any?(conn.req_headers, fn {key, _value} -> key == "openai-organization" end)

Plug.Conn.resp(conn, 200, "")
end)

{:ok, _response} =
OpenAiClient.get("/foo", base_url: endpoint_url(bypass), breaker: MockBreaker)
end

test "retries the request on a 408, 429, 500, 502, 503, or 504 http status response", %{
bypass: bypass
} do
Expand Down

0 comments on commit 3d8b5d6

Please sign in to comment.