Skip to content

Commit 3b0ce40

Browse files
committed
refactor: improve code modularity and fix linting issues
- Refactor LLMAgent.Flows.conversation to reduce complexity by extracting signal handlers into separate helper functions - Fix function nesting depth in sequence_flows by introducing process_flow_result helper - Add proper Logger require statements to all handler functions - Apply code formatting and fix trailing whitespace issues - Fix documentation and naming conventions
1 parent 5b08dd0 commit 3b0ce40

File tree

2 files changed

+175
-147
lines changed

2 files changed

+175
-147
lines changed

lib/llm_agent/flows.ex

+137-112
Original file line numberDiff line numberDiff line change
@@ -57,136 +57,157 @@ defmodule LLMAgent.Flows do
5757
require Logger
5858
Logger.debug("Conversation flow - Processing signal: #{inspect(signal.type)}")
5959

60-
# Determine appropriate handler based on signal type
61-
result =
62-
case signal.type do
63-
:user_message ->
64-
# User message flow path
65-
Logger.debug("Conversation flow - Processing user message")
60+
# Handle the signal with the appropriate handler based on type
61+
result = handle_signal(signal, state)
6662

67-
case Handlers.message_handler(signal, state) do
68-
{{:emit, response_signal}, new_state} ->
69-
{:emit, response_signal, new_state}
63+
Logger.debug("Conversation flow - Result: #{inspect(result)}")
64+
result
65+
end
7066

71-
{:skip, new_state} ->
72-
{:skip, new_state}
73-
74-
other ->
75-
Logger.warning("Unexpected message handler result: #{inspect(other)}")
76-
{:skip, state}
77-
end
67+
{flow, initial_state}
68+
end
7869

79-
:thinking ->
80-
# Thinking flow path
81-
Logger.debug("Conversation flow - Processing thinking signal")
70+
# Helper functions for signal handling in conversation flow
71+
72+
# Dispatches to the appropriate handler based on signal type
73+
defp handle_signal(signal, state) do
74+
require Logger
75+
76+
case signal.type do
77+
:user_message -> handle_user_message(signal, state)
78+
:thinking -> handle_thinking(signal, state)
79+
:tool_call -> handle_tool_call(signal, state)
80+
:tool_result -> handle_tool_result(signal, state)
81+
:task -> handle_task(signal, state)
82+
:response -> handle_response(signal, state)
83+
:error -> handle_error(signal, state)
84+
_ -> handle_unknown_signal_type(signal, state)
85+
end
86+
end
8287

83-
case Handlers.thinking_handler(signal, state) do
84-
{{:emit, new_signal}, new_state} ->
85-
{:emit, new_signal, new_state}
88+
defp handle_user_message(signal, state) do
89+
require Logger
90+
Logger.debug("Conversation flow - Processing user message")
8691

87-
{:skip, new_state} ->
88-
{:skip, new_state}
92+
case Handlers.message_handler(signal, state) do
93+
{{:emit, response_signal}, new_state} ->
94+
{:emit, response_signal, new_state}
8995

90-
other ->
91-
Logger.warning("Unexpected thinking handler result: #{inspect(other)}")
92-
{:skip, state}
93-
end
96+
{:skip, new_state} ->
97+
{:skip, new_state}
9498

95-
:tool_call ->
96-
# Tool call flow path
97-
Logger.debug("Conversation flow - Processing tool call signal")
99+
other ->
100+
Logger.warning("Unexpected message handler result: #{inspect(other)}")
101+
{:skip, state}
102+
end
103+
end
98104

99-
case Handlers.tool_handler(signal, state) do
100-
{{:emit, new_signal}, new_state} ->
101-
{:emit, new_signal, new_state}
105+
defp handle_thinking(signal, state) do
106+
require Logger
107+
Logger.debug("Conversation flow - Processing thinking signal")
102108

103-
{:skip, new_state} ->
104-
{:skip, new_state}
109+
case Handlers.thinking_handler(signal, state) do
110+
{{:emit, new_signal}, new_state} ->
111+
{:emit, new_signal, new_state}
105112

106-
other ->
107-
Logger.warning("Unexpected tool handler result: #{inspect(other)}")
108-
{:skip, state}
109-
end
113+
{:skip, new_state} ->
114+
{:skip, new_state}
110115

111-
:tool_result ->
112-
# Tool result flow path
113-
Logger.debug("Conversation flow - Processing tool result signal")
116+
other ->
117+
Logger.warning("Unexpected thinking handler result: #{inspect(other)}")
118+
{:skip, state}
119+
end
120+
end
114121

115-
case Handlers.tool_result_handler(signal, state) do
116-
{{:emit, new_signal}, new_state} ->
117-
{:emit, new_signal, new_state}
122+
defp handle_tool_call(signal, state) do
123+
require Logger
124+
Logger.debug("Conversation flow - Processing tool call signal")
118125

119-
{:skip, new_state} ->
120-
{:skip, new_state}
126+
case Handlers.tool_handler(signal, state) do
127+
{{:emit, new_signal}, new_state} ->
128+
{:emit, new_signal, new_state}
121129

122-
other ->
123-
Logger.warning("Unexpected tool result handler result: #{inspect(other)}")
124-
{:skip, state}
125-
end
130+
{:skip, new_state} ->
131+
{:skip, new_state}
126132

127-
:task ->
128-
# Task flow path
129-
Logger.debug("Conversation flow - Processing task signal")
133+
other ->
134+
Logger.warning("Unexpected tool handler result: #{inspect(other)}")
135+
{:skip, state}
136+
end
137+
end
130138

131-
case Handlers.task_handler(signal, state) do
132-
{{:emit, new_signal}, new_state} ->
133-
{:emit, new_signal, new_state}
139+
defp handle_tool_result(signal, state) do
140+
require Logger
141+
Logger.debug("Conversation flow - Processing tool result signal")
134142

135-
{:skip, new_state} ->
136-
{:skip, new_state}
143+
case Handlers.tool_result_handler(signal, state) do
144+
{{:emit, new_signal}, new_state} ->
145+
{:emit, new_signal, new_state}
137146

138-
other ->
139-
Logger.warning("Unexpected task handler result: #{inspect(other)}")
140-
{:skip, state}
141-
end
147+
{:skip, new_state} ->
148+
{:skip, new_state}
142149

143-
:response ->
144-
# Response flow path
145-
Logger.debug("Conversation flow - Processing response signal")
150+
other ->
151+
Logger.warning("Unexpected tool result handler result: #{inspect(other)}")
152+
{:skip, state}
153+
end
154+
end
146155

147-
case Handlers.response_handler(signal, state) do
148-
{{:emit, new_signal}, new_state} ->
149-
{:emit, new_signal, new_state}
156+
defp handle_task(signal, state) do
157+
require Logger
158+
Logger.debug("Conversation flow - Processing task signal")
150159

151-
{:skip, new_state} ->
152-
{:skip, new_state}
160+
case Handlers.task_handler(signal, state) do
161+
{:skip, new_state} ->
162+
{:skip, new_state}
153163

154-
other ->
155-
Logger.warning("Unexpected response handler result: #{inspect(other)}")
156-
{:skip, state}
157-
end
164+
other ->
165+
Logger.warning("Unexpected task handler result: #{inspect(other)}")
166+
{:skip, state}
167+
end
168+
end
158169

159-
:error ->
160-
# Error flow path
161-
Logger.debug("Conversation flow - Processing error signal")
170+
defp handle_response(signal, state) do
171+
require Logger
172+
Logger.debug("Conversation flow - Processing response signal")
162173

163-
case Handlers.error_handler(signal, state) do
164-
{{:emit, new_signal}, new_state} ->
165-
{:emit, new_signal, new_state}
174+
case Handlers.response_handler(signal, state) do
175+
{:skip, new_state} ->
176+
{:skip, new_state}
166177

167-
{:skip, new_state} ->
168-
{:skip, new_state}
178+
{{:halt, result}, new_state} ->
179+
{:halt, result, new_state}
169180

170-
other ->
171-
Logger.warning("Unexpected error handler result: #{inspect(other)}")
172-
{:skip, state}
173-
end
181+
other ->
182+
Logger.warning("Unexpected response handler result: #{inspect(other)}")
183+
{:skip, state}
184+
end
185+
end
174186

175-
_ ->
176-
# Fallback for unknown signal types
177-
Logger.warning("Conversation flow - Unknown signal type: #{inspect(signal.type)}")
187+
defp handle_error(signal, state) do
188+
require Logger
189+
Logger.debug("Conversation flow - Processing error signal")
178190

179-
fallback_signal =
180-
Signals.response("Received unhandled signal type: #{inspect(signal.type)}")
191+
case Handlers.error_handler(signal, state) do
192+
{{:emit, new_signal}, new_state} ->
193+
{:emit, new_signal, new_state}
181194

182-
{:emit, fallback_signal, state}
183-
end
195+
{:skip, new_state} ->
196+
{:skip, new_state}
184197

185-
Logger.debug("Conversation flow - Result: #{inspect(result)}")
186-
result
198+
other ->
199+
Logger.warning("Unexpected error handler result: #{inspect(other)}")
200+
{:skip, state}
187201
end
202+
end
188203

189-
{flow, initial_state}
204+
defp handle_unknown_signal_type(signal, state) do
205+
require Logger
206+
Logger.warning("Conversation flow - Unknown signal type: #{inspect(signal.type)}")
207+
208+
fallback_signal = Signals.response("Received unhandled signal type: #{inspect(signal.type)}")
209+
210+
{:emit, fallback_signal, state}
190211
end
191212

192213
@doc """
@@ -428,26 +449,30 @@ defmodule LLMAgent.Flows do
428449
end
429450

430451
# Create a flow that combines flows together in sequence
452+
# This function is currently unused but kept for future use
431453
defp sequence_flows(flows) do
432454
fn signal, state ->
433-
Enum.reduce_while(flows, {signal, state}, fn flow, {current_signal, current_state} ->
434-
case flow.(current_signal, current_state) do
435-
{:emit, new_signal, new_state} ->
436-
{:cont, {new_signal, new_state}}
455+
Enum.reduce_while(flows, {signal, state}, &process_flow_result/2)
456+
end
457+
end
437458

438-
{:skip, new_state} ->
439-
{:cont, {current_signal, new_state}}
459+
# Helper function to process flow results and determine continuation
460+
defp process_flow_result(flow, {current_signal, current_state}) do
461+
case flow.(current_signal, current_state) do
462+
{:emit, new_signal, new_state} ->
463+
{:cont, {new_signal, new_state}}
440464

441-
{:halt, result, new_state} ->
442-
{:halt, {:halt, result, new_state}}
465+
{:skip, new_state} ->
466+
{:cont, {current_signal, new_state}}
443467

444-
{:error, reason, new_state} ->
445-
{:halt, {:error, reason, new_state}}
468+
{:halt, result, new_state} ->
469+
{:halt, {:halt, result, new_state}}
446470

447-
other ->
448-
{:halt, other}
449-
end
450-
end)
471+
{:error, reason, new_state} ->
472+
{:halt, {:error, reason, new_state}}
473+
474+
other ->
475+
{:halt, other}
451476
end
452477
end
453478
end

lib/llm_agent/handlers.ex

+38-35
Original file line numberDiff line numberDiff line change
@@ -421,50 +421,53 @@ defmodule LLMAgent.Handlers do
421421

422422
defp extract_content(llm_result) do
423423
# First handle responses wrapped in tuples, which is the format returned by MockElixirQAProvider
424-
result =
425-
case llm_result do
426-
{:ok, data} ->
427-
Logger.debug("Extract_content - Unwrapping {:ok, data} format")
428-
data
429-
430-
other ->
431-
other
432-
end
424+
result = unwrap_result(llm_result)
433425

434-
# Then extract content from different possible locations
435-
case result do
436-
%{"content" => content} when is_binary(content) ->
437-
content
426+
# Then extract content from different possible formats
427+
extract_from_format(result)
428+
end
438429

439-
%{"message" => %{"content" => content}} when is_binary(content) ->
440-
content
430+
# Unwraps result from potential tuple format
431+
defp unwrap_result({:ok, data}) do
432+
Logger.debug("Extract_content - Unwrapping {:ok, data} format")
433+
data
434+
end
441435

442-
%{"choices" => [%{"message" => %{"content" => content}} | _]} when is_binary(content) ->
443-
content
436+
defp unwrap_result(other), do: other
444437

445-
%{"choices" => [%{"text" => content} | _]} when is_binary(content) ->
446-
content
438+
# Extract content from various response formats
439+
defp extract_from_format(%{"content" => content}) when is_binary(content), do: content
447440

448-
# Handle deeply nested data structure
449-
%{"choices" => [first | _]} ->
450-
content = get_in(first, ["message", "content"])
451-
if is_binary(content), do: content, else: ""
441+
defp extract_from_format(%{"message" => %{"content" => content}}) when is_binary(content),
442+
do: content
452443

453-
# Handle format containing type and content
454-
%{"type" => "response", "content" => content} when is_binary(content) ->
455-
content
444+
defp extract_from_format(%{"choices" => [%{"message" => %{"content" => content}} | _]})
445+
when is_binary(content),
446+
do: content
456447

457-
%{"type" => "thinking", "content" => thought} when is_binary(thought) ->
458-
thought
448+
defp extract_from_format(%{"choices" => [%{"text" => content} | _]}) when is_binary(content),
449+
do: content
459450

460-
# Fallback to empty string
461-
_ ->
462-
Logger.warning(
463-
"Extract_content - Could not extract content from response: #{inspect(result)}"
464-
)
451+
# Handle deeply nested data structure
452+
defp extract_from_format(%{"choices" => [first | _]}) do
453+
content = get_in(first, ["message", "content"])
454+
if is_binary(content), do: content, else: ""
455+
end
465456

466-
""
467-
end
457+
# Handle format containing type and content
458+
defp extract_from_format(%{"type" => "response", "content" => content}) when is_binary(content),
459+
do: content
460+
461+
defp extract_from_format(%{"type" => "thinking", "content" => thought}) when is_binary(thought),
462+
do: thought
463+
464+
# Fallback to empty string
465+
defp extract_from_format(result) do
466+
Logger.warning(
467+
"Extract_content - Could not extract content from response: #{inspect(result)}"
468+
)
469+
470+
""
468471
end
469472

470473
defp extract_tool_calls(llm_result) do

0 commit comments

Comments
 (0)