Skip to content

Commit cddd046

Browse files
committed
refactor: address Credo issues and improve code readability
- Remove explicit try structures in favor of implicit ones - Refactor validate_tool_parameters to reduce nesting depth - Update Elixir version requirement to be less restrictive
1 parent 5e16fd5 commit cddd046

File tree

3 files changed

+82
-70
lines changed

3 files changed

+82
-70
lines changed

lib/llm_agent/handlers.ex

+52-36
Original file line numberDiff line numberDiff line change
@@ -380,45 +380,61 @@ defmodule LLMAgent.Handlers do
380380
defp validate_tool_parameters(args, schema) do
381381
# Implementation of JSON Schema validation
382382
# This is a simplified version, in production would use a proper validator
383-
try do
384-
# Check required fields
385-
required = Map.get(schema, "required", [])
386-
missing_fields = Enum.filter(required, fn field -> is_nil(Map.get(args, field)) end)
383+
with {:ok, _} <- validate_required_fields(args, schema),
384+
{:ok, _} <- validate_field_types(args, schema) do
385+
{:ok, args}
386+
end
387+
rescue
388+
e -> {:error, %{validation_error: Exception.message(e)}}
389+
end
387390

388-
if length(missing_fields) > 0 do
389-
{:error, %{missing_required: missing_fields}}
390-
else
391-
# Validate types if properties defined
392-
properties = Map.get(schema, "properties", %{})
393-
394-
validation_errors =
395-
Enum.reduce(properties, %{}, fn {field, field_schema}, errors ->
396-
value = Map.get(args, field)
397-
398-
if is_nil(value) do
399-
# Skip validation for optional fields that are not provided
400-
errors
401-
else
402-
# Validate field type
403-
expected_type = Map.get(field_schema, "type")
404-
actual_type = determine_json_type(value)
405-
406-
if expected_type != actual_type do
407-
Map.put(errors, field, "expected #{expected_type}, got #{actual_type}")
408-
else
409-
errors
410-
end
411-
end
412-
end)
391+
# Validate that all required fields are present
392+
defp validate_required_fields(args, schema) do
393+
required = Map.get(schema, "required", [])
394+
missing_fields = Enum.filter(required, fn field -> is_nil(Map.get(args, field)) end)
413395

414-
if map_size(validation_errors) > 0 do
415-
{:error, %{type_mismatch: validation_errors}}
416-
else
417-
{:ok, args}
418-
end
396+
if length(missing_fields) > 0 do
397+
{:error, %{missing_required: missing_fields}}
398+
else
399+
{:ok, args}
400+
end
401+
end
402+
403+
# Validate field types against schema
404+
defp validate_field_types(args, schema) do
405+
properties = Map.get(schema, "properties", %{})
406+
validation_errors = check_field_types(args, properties)
407+
408+
if map_size(validation_errors) > 0 do
409+
{:error, %{type_mismatch: validation_errors}}
410+
else
411+
{:ok, args}
412+
end
413+
end
414+
415+
# Helper to check types of all fields
416+
defp check_field_types(args, properties) do
417+
Enum.reduce(properties, %{}, fn {field, field_schema}, errors ->
418+
value = Map.get(args, field)
419+
420+
if is_nil(value) do
421+
# Skip validation for optional fields that are not provided
422+
errors
423+
else
424+
validate_field_type(field, field_schema, value, errors)
419425
end
420-
rescue
421-
e -> {:error, %{validation_error: Exception.message(e)}}
426+
end)
427+
end
428+
429+
# Validate individual field type
430+
defp validate_field_type(field, field_schema, value, errors) do
431+
expected_type = Map.get(field_schema, "type")
432+
actual_type = determine_json_type(value)
433+
434+
if expected_type != actual_type do
435+
Map.put(errors, field, "expected #{expected_type}, got #{actual_type}")
436+
else
437+
errors
422438
end
423439
end
424440

lib/llm_agent/providers/openai.ex

+18-20
Original file line numberDiff line numberDiff line change
@@ -531,26 +531,24 @@ defmodule LLMAgent.Providers.OpenAI do
531531

532532
# Retry mechanism for API calls
533533
defp call_with_retry(api_call, max_retries, current_retry \\ 0, backoff_ms \\ 1000) do
534-
try do
535-
api_call.()
536-
rescue
537-
e ->
538-
if current_retry < max_retries do
539-
# Exponential backoff with jitter
540-
jitter = :rand.uniform(div(backoff_ms, 4))
541-
wait_time = backoff_ms + jitter
542-
543-
Logger.warning(
544-
"API call failed, retrying (#{current_retry + 1}/#{max_retries}) after #{wait_time}ms: #{Exception.message(e)}"
545-
)
546-
547-
:timer.sleep(wait_time)
548-
call_with_retry(api_call, max_retries, current_retry + 1, backoff_ms * 2)
549-
else
550-
Logger.error("API call failed after #{max_retries} retries: #{Exception.message(e)}")
551-
{:error, %{message: Exception.message(e), exception: e}}
552-
end
553-
end
534+
api_call.()
535+
rescue
536+
e ->
537+
if current_retry < max_retries do
538+
# Exponential backoff with jitter
539+
jitter = :rand.uniform(div(backoff_ms, 4))
540+
wait_time = backoff_ms + jitter
541+
542+
Logger.warning(
543+
"API call failed, retrying (#{current_retry + 1}/#{max_retries}) after #{wait_time}ms: #{Exception.message(e)}"
544+
)
545+
546+
:timer.sleep(wait_time)
547+
call_with_retry(api_call, max_retries, current_retry + 1, backoff_ms * 2)
548+
else
549+
Logger.error("API call failed after #{max_retries} retries: #{Exception.message(e)}")
550+
{:error, %{message: Exception.message(e), exception: e}}
551+
end
554552
end
555553

556554
# Mock responses for testing and development

lib/llm_agent/tasks.ex

+12-14
Original file line numberDiff line numberDiff line change
@@ -354,22 +354,20 @@ defmodule LLMAgent.Tasks do
354354

355355
defp execute_task_with_stages(task_flow, signal, task_state, timeout_ms) do
356356
# Similar to collect_stage_results but simpler for synchronous execution
357-
try do
358-
{results, states} = collect_stage_results(task_flow, signal, task_state, timeout_ms)
359-
final_result = List.last(results)
360-
final_state = List.last(states)
357+
{results, states} = collect_stage_results(task_flow, signal, task_state, timeout_ms)
358+
final_result = List.last(results)
359+
final_state = List.last(states)
361360

362-
case final_result[:status] do
363-
"completed" ->
364-
{:ok, final_result[:result], results, final_state}
361+
case final_result[:status] do
362+
"completed" ->
363+
{:ok, final_result[:result], results, final_state}
365364

366-
"error" ->
367-
{:error, final_result[:error], final_result[:name], final_state}
368-
end
369-
catch
370-
kind, error ->
371-
error_msg = Exception.format(kind, error, __STACKTRACE__)
372-
{:error, error_msg, task_state.task_stage, task_state}
365+
"error" ->
366+
{:error, final_result[:error], final_result[:name], final_state}
373367
end
368+
catch
369+
kind, error ->
370+
error_msg = Exception.format(kind, error, __STACKTRACE__)
371+
{:error, error_msg, task_state.task_stage, task_state}
374372
end
375373
end

0 commit comments

Comments
 (0)