Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
21 changes: 20 additions & 1 deletion lib/req_llm/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,11 @@ defmodule ReqLLM.Schema do
@spec to_google_format(ReqLLM.Tool.t()) :: map()
def to_google_format(%ReqLLM.Tool{} = tool) do
json_schema = to_json(tool.parameter_schema)
parameters = deep_delete_keys(json_schema, @google_forbidden_schema_keys)

parameters =
json_schema
|> deep_delete_keys(@google_forbidden_schema_keys)
|> stringify_enums()

%{
"name" => tool.name,
Expand Down Expand Up @@ -1073,6 +1077,21 @@ defmodule ReqLLM.Schema do

defp deep_delete_keys(value, _keys), do: value

defp stringify_enums(map) when is_map(map) do
Map.new(map, fn
{"enum", values} when is_list(values) ->
{"enum", Enum.map(values, &to_string/1)}

{k, v} ->
{k, stringify_enums(v)}
end)
end

defp stringify_enums(list) when is_list(list),
do: Enum.map(list, &stringify_enums/1)

defp stringify_enums(value), do: value

defp key_variants(keys) when is_list(keys), do: Enum.flat_map(keys, &key_variants/1)
defp key_variants(key) when is_binary(key), do: [key, String.to_atom(key)]
defp key_variants(key) when is_atom(key), do: [key, Atom.to_string(key)]
Expand Down
31 changes: 31 additions & 0 deletions test/req_llm/schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,37 @@ defmodule ReqLLM.SchemaTest do
assert result["parameters"]["required"] == ["tags"]
end

test "to_google_format/1 stringifies non-string enum values" do
tool = %ReqLLM.Tool{
name: "set_level",
description: "Set a level",
parameter_schema: %{
"type" => "object",
"properties" => %{
"level" => %{
"type" => "integer",
"enum" => [1, 2, 3],
"description" => "The level"
},
"mode" => %{
"type" => "string",
"enum" => ["fast", "slow"],
"description" => "The mode"
}
},
"required" => ["level"]
},
callback: fn _ -> {:ok, "ok"} end
}

result = Schema.to_google_format(tool)
level = result["parameters"]["properties"]["level"]
mode = result["parameters"]["properties"]["mode"]

assert level["enum"] == ["1", "2", "3"]
assert mode["enum"] == ["fast", "slow"]
end

test "to_google_format/1 strips atom-keyed forbidden fields recursively" do
atom_keyed_schema = %{
:type => :object,
Expand Down
Loading