Skip to content

Commit 08be33c

Browse files
fix: project credo and dialyzer issues
1 parent b90cba0 commit 08be33c

25 files changed

Lines changed: 294 additions & 223 deletions

.dialyzer_ignore.exs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,11 @@
2929
{"lib/mcpixir/agents/mcpagent.ex", :pattern_match_cov},
3030
{"lib/mcpixir.ex", :call},
3131
{"lib/mcpixir/agents/mcpagent.ex", :invalid_contract},
32-
{"lib/mcpixir/agents/mcpagent.ex", :pattern_match}
32+
{"lib/mcpixir/agents/mcpagent.ex", :pattern_match},
33+
34+
# Ignore guard_fail warnings for LangChain checks
35+
{"lib/mcpixir/application.ex", :guard_fail},
36+
{"lib/mcpixir/llm_client/anthropic.ex", :guard_fail},
37+
{"lib/mcpixir/llm_client/langchain.ex", :guard_fail},
38+
{"lib/mcpixir/llm_client/openai.ex", :guard_fail}
3339
]

config/config.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import Config
33
config :mcpixir,
44
log_level: :info,
55
default_servers: [],
6-
environment: config_env() # Add this line to capture the environment
6+
# Add this line to capture the environment
7+
environment: config_env()
78

89
# Import environment specific config
910
import_config "#{config_env()}.exs"

lib/mcpixir.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ defmodule Mcpixir do
8282
{:ok, prepared_agent} -> {:ok, prepared_agent}
8383
{:error, _} -> {:error, "Failed to prepare agent"}
8484
end
85-
_ -> {:error, "Failed to create agent"}
85+
86+
_ ->
87+
{:error, "Failed to create agent"}
8688
end
8789
end
8890

lib/mcpixir/agents/mcpagent.ex

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -153,37 +153,43 @@ defmodule Mcpixir.Agents.MCPAgent do
153153
defp process_tool_calls(agent, tool_calls, content) do
154154
{updated_agent, tool_results} =
155155
Enum.reduce(tool_calls, {agent, []}, fn tool_call, {current_agent, results} ->
156-
tool_name = tool_call["name"] || tool_call["function"]["name"]
157-
arguments = tool_call["arguments"] || tool_call["function"]["arguments"]
158-
tool_call_id = tool_call["id"]
159-
160-
args =
161-
case arguments do
162-
args when is_binary(args) ->
163-
case Jason.decode(args) do
164-
{:ok, parsed} -> parsed
165-
_ -> %{}
166-
end
167-
168-
args when is_map(args) ->
169-
args
170-
171-
_ ->
172-
%{}
173-
end
174-
175-
case run_tool(current_agent, tool_name, args) do
176-
{:ok, result} ->
177-
handle_successful_tool_call(current_agent, tool_call_id, tool_name, result, results)
178-
179-
{:error, reason} ->
180-
handle_failed_tool_call(current_agent, tool_call_id, tool_name, reason, results)
181-
end
156+
process_single_tool_call(current_agent, tool_call, results)
182157
end)
183158

184159
handle_tool_results(updated_agent, tool_results, content)
185160
end
186161

162+
defp process_single_tool_call(agent, tool_call, results) do
163+
tool_name = tool_call["name"] || tool_call["function"]["name"]
164+
arguments = tool_call["arguments"] || tool_call["function"]["arguments"]
165+
tool_call_id = tool_call["id"]
166+
args = parse_arguments(arguments)
167+
168+
case run_tool(agent, tool_name, args) do
169+
{:ok, result} ->
170+
handle_successful_tool_call(agent, tool_call_id, tool_name, result, results)
171+
172+
{:error, reason} ->
173+
handle_failed_tool_call(agent, tool_call_id, tool_name, reason, results)
174+
end
175+
end
176+
177+
defp parse_arguments(arguments) do
178+
case arguments do
179+
args when is_binary(args) ->
180+
case Jason.decode(args) do
181+
{:ok, parsed} -> parsed
182+
_ -> %{}
183+
end
184+
185+
args when is_map(args) ->
186+
args
187+
188+
_ ->
189+
%{}
190+
end
191+
end
192+
187193
defp handle_successful_tool_call(agent, tool_call_id, tool_name, result, results) do
188194
tool_result = %{
189195
"tool_call_id" => tool_call_id,

lib/mcpixir/application.ex

Lines changed: 65 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ defmodule Mcpixir.Application do
99
def start(_type, _args) do
1010
# Get the current environment
1111
env = Application.get_env(:mcpixir, :environment, :dev)
12-
12+
1313
# Start supervision tree with proper children
1414
opts = [strategy: :one_for_one, name: Mcpixir.Supervisor]
15-
15+
1616
# Start supervision tree
1717
children(env)
1818
|> Supervisor.start_link(opts)
1919
end
20-
20+
2121
# Define children for each environment
2222
defp children(env) do
2323
[
@@ -26,7 +26,7 @@ defmodule Mcpixir.Application do
2626
{Registry, keys: :unique, name: Mcpixir.SessionRegistry}
2727
] ++ maybe_add_langchain(env)
2828
end
29-
29+
3030
# Conditionally start LangChain in development and production
3131
defp maybe_add_langchain(env) when env in [:dev, :prod] do
3232
# Try to load LangChain and start any required services
@@ -37,46 +37,44 @@ defmodule Mcpixir.Application do
3737
_ = Code.ensure_loaded?(LangChain.ChatModels)
3838
_ = Code.ensure_loaded?(LangChain.ChatModels.OpenAI)
3939
_ = Code.ensure_loaded?(LangChain.ChatModels.Anthropic)
40-
40+
4141
# We don't need to actually start any processes, just ensure modules are loaded
4242
[]
43-
43+
4444
false ->
4545
# LangChain not available, which is fine as it's optional
4646
[]
4747
end
4848
end
49-
49+
5050
# Don't load LangChain in test
5151
defp maybe_add_langchain(:test), do: []
5252

5353
@doc """
5454
Load optional dependencies like LangChain
55-
55+
5656
Returns a boolean indicating whether LangChain is available.
5757
"""
5858
def load_optional_dependencies do
59-
try do
60-
# Try to load LangChain module itself
61-
Code.ensure_loaded?(LangChain) and
62-
# Also verify some key modules are available
63-
Code.ensure_loaded?(LangChain.Message) and
64-
Code.ensure_loaded?(LangChain.ChatModels)
65-
rescue
66-
# Handle any loading errors gracefully
67-
_ -> false
68-
catch
69-
# Handle any unexpected issues
70-
_, _ -> false
71-
end
59+
# Try to load LangChain module itself
60+
# Also verify some key modules are available
61+
Code.ensure_loaded?(LangChain) and
62+
Code.ensure_loaded?(LangChain.Message) and
63+
Code.ensure_loaded?(LangChain.ChatModels)
64+
rescue
65+
# Handle any loading errors gracefully
66+
_ -> false
67+
catch
68+
# Handle any unexpected issues
69+
_, _ -> false
7270
end
7371

7472
@doc """
7573
Checks if LangChain integration is available.
7674
Always use this function instead of directly checking Code.ensure_loaded.
7775
"""
7876
def langchain_available? do
79-
# This is a hardcoded true because we've removed the optional flag
77+
# This is a hardcoded true because we've removed the optional flag
8078
# from the dependency in mix.exs and are forcing it to be loaded in all mix tasks
8179
true
8280
end
@@ -85,76 +83,79 @@ defmodule Mcpixir.Application do
8583
Gets the OpenAI module if available.
8684
"""
8785
def openai_module do
88-
try do
89-
if langchain_available?() && Code.ensure_loaded?(LangChain.ChatModels.OpenAI) do
86+
cond do
87+
langchain_available?() && Code.ensure_loaded?(LangChain.ChatModels.OpenAI) ->
9088
LangChain.ChatModels.OpenAI
91-
else
89+
90+
true ->
9291
nil
93-
end
94-
rescue
95-
_ -> nil
9692
end
93+
rescue
94+
_ -> nil
9795
end
9896

9997
@doc """
10098
Gets the Anthropic module if available.
10199
"""
102100
def anthropic_module do
103-
try do
104-
if langchain_available?() && Code.ensure_loaded?(LangChain.ChatModels.Anthropic) do
101+
cond do
102+
langchain_available?() && Code.ensure_loaded?(LangChain.ChatModels.Anthropic) ->
105103
LangChain.ChatModels.Anthropic
106-
else
104+
105+
true ->
107106
nil
108-
end
109-
rescue
110-
_ -> nil
111107
end
108+
rescue
109+
_ -> nil
112110
end
113111

114112
@doc """
115113
Gets the LangChain models module if available.
116114
"""
117115
def langchain_models_module do
118-
try do
119-
if langchain_available?() do
116+
cond do
117+
langchain_available?() ->
120118
LangChain.ChatModels
121-
else
119+
120+
true ->
122121
nil
123-
end
124-
rescue
125-
_ -> nil
126122
end
123+
rescue
124+
_ -> nil
127125
end
128126

129127
@doc """
130128
Formats messages for LangChain integration.
131129
Safely handles the conversion, falling back to the original messages if LangChain is unavailable.
132130
"""
133131
def format_messages_for_langchain(messages) do
134-
try do
135-
if langchain_available?() do
136-
Enum.map(messages, fn message ->
137-
role = Map.get(message, :role) || Map.get(message, "role", "user")
138-
content = Map.get(message, :content) || Map.get(message, "content", "")
139-
140-
role_atom =
141-
case role do
142-
role when is_atom(role) -> role
143-
role when is_binary(role) -> String.to_atom(role)
144-
_ -> :user
145-
end
146-
147-
# Create the struct dynamically to avoid compile-time errors when LangChain is missing
148-
struct(LangChain.Message, role: role_atom, content: content)
149-
end)
150-
else
132+
cond do
133+
langchain_available?() ->
134+
convert_messages_to_langchain(messages)
135+
136+
true ->
151137
messages
152-
end
153-
rescue
154-
# Return original messages if any conversion fails
155-
_ -> messages
156-
catch
157-
_, _ -> messages
158138
end
139+
rescue
140+
# Return original messages if any conversion fails
141+
_ -> messages
142+
catch
143+
_, _ -> messages
159144
end
160-
end
145+
146+
defp convert_messages_to_langchain(messages) do
147+
Enum.map(messages, fn message ->
148+
role = Map.get(message, :role) || Map.get(message, "role", "user")
149+
content = Map.get(message, :content) || Map.get(message, "content", "")
150+
151+
role_atom = convert_role_to_atom(role)
152+
153+
# Create the struct dynamically to avoid compile-time errors when LangChain is missing
154+
struct(LangChain.Message, role: role_atom, content: content)
155+
end)
156+
end
157+
158+
defp convert_role_to_atom(role) when is_atom(role), do: role
159+
defp convert_role_to_atom(role) when is_binary(role), do: String.to_atom(role)
160+
defp convert_role_to_atom(_), do: :user
161+
end

lib/mcpixir/config.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ defmodule Mcpixir.Config do
5656
read_config_file(path)
5757
end)
5858
end
59+
5960
defp read_config_file(path) do
6061
with {:ok, content} <- File.read(path),
6162
{:ok, config} <- Jason.decode(content) do

lib/mcpixir/connectors/http.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ defmodule Mcpixir.Connectors.HttpConnector do
4444
end
4545

4646
@impl Mcpixir.Connectors.Base
47-
@spec initialize(Mcpixir.Connectors.Base.connector()) :: {:ok, Mcpixir.Connectors.Base.connector()} | {:error, any()}
47+
@spec initialize(Mcpixir.Connectors.Base.connector()) ::
48+
{:ok, Mcpixir.Connectors.Base.connector()} | {:error, any()}
4849
def initialize(connector) do
4950
Base.initialize(connector)
5051
end
@@ -56,7 +57,8 @@ defmodule Mcpixir.Connectors.HttpConnector do
5657
end
5758

5859
@impl Mcpixir.Connectors.Base
59-
@spec execute_tool(Mcpixir.Connectors.Base.connector(), String.t(), map()) :: {:ok, any()} | {:error, any()}
60+
@spec execute_tool(Mcpixir.Connectors.Base.connector(), String.t(), map()) ::
61+
{:ok, any()} | {:error, any()}
6062
def execute_tool(connector, tool_name, args) do
6163
Base.execute_tool(connector, tool_name, args)
6264
end

lib/mcpixir/connectors/stdio.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ defmodule Mcpixir.Connectors.StdioConnector do
4646
end
4747

4848
@impl Mcpixir.Connectors.Base
49-
@spec initialize(Mcpixir.Connectors.Base.connector()) :: {:ok, Mcpixir.Connectors.Base.connector()} | {:error, any()}
49+
@spec initialize(Mcpixir.Connectors.Base.connector()) ::
50+
{:ok, Mcpixir.Connectors.Base.connector()} | {:error, any()}
5051
def initialize(connector) do
5152
Base.initialize(connector)
5253
end
@@ -58,7 +59,8 @@ defmodule Mcpixir.Connectors.StdioConnector do
5859
end
5960

6061
@impl Mcpixir.Connectors.Base
61-
@spec execute_tool(Mcpixir.Connectors.Base.connector(), String.t(), map()) :: {:ok, any()} | {:error, any()}
62+
@spec execute_tool(Mcpixir.Connectors.Base.connector(), String.t(), map()) ::
63+
{:ok, any()} | {:error, any()}
6264
def execute_tool(connector, tool_name, args) do
6365
Base.execute_tool(connector, tool_name, args)
6466
end
@@ -70,6 +72,7 @@ defmodule Mcpixir.Connectors.StdioConnector do
7072
%{port: port} when is_port(port) -> Port.close(port)
7173
_ -> nil
7274
end
75+
7376
:ok
7477
end
7578

0 commit comments

Comments
 (0)