Class: Ace::LLM::Molecules::ProviderModelParser

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/llm/molecules/provider_model_parser.rb

Overview

ProviderModelParser handles parsing and validation of provider:model syntax for the unified LLM query interface.

Defined Under Namespace

Classes: ParseResult

Constant Summary collapse

THINKING_LEVELS =
%w[low medium high xhigh].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(alias_resolver: nil, registry: nil) ⇒ ProviderModelParser

Returns a new instance of ProviderModelParser.



33
34
35
36
# File 'lib/ace/llm/molecules/provider_model_parser.rb', line 33

def initialize(alias_resolver: nil, registry: nil)
  @alias_resolver = alias_resolver || LlmAliasResolver.new
  @registry = registry || ClientRegistry.new
end

Instance Attribute Details

#alias_resolverObject (readonly)

Returns the value of attribute alias_resolver.



31
32
33
# File 'lib/ace/llm/molecules/provider_model_parser.rb', line 31

def alias_resolver
  @alias_resolver
end

#registryObject (readonly)

Returns the value of attribute registry.



31
32
33
# File 'lib/ace/llm/molecules/provider_model_parser.rb', line 31

def registry
  @registry
end

Instance Method Details

#default_model_for(provider) ⇒ Object



90
91
92
93
# File 'lib/ace/llm/molecules/provider_model_parser.rb', line 90

def default_model_for(provider)
  models = @registry.models_for_provider(provider)
  models&.first
end

#dynamic_aliasesObject



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ace/llm/molecules/provider_model_parser.rb', line 95

def dynamic_aliases
  return {} unless @alias_resolver

  global = @alias_resolver.available_aliases[:global] || {}
  providers = @alias_resolver.available_aliases[:providers] || {}

  flattened = {}
  providers.each do |provider, aliases|
    aliases.each do |alias_name, model|
      flattened["#{provider}:#{alias_name}"] = "#{provider}:#{model}"
    end
  end

  global.merge(flattened)
end

#parse(input) ⇒ Object

Parse a provider:model string or alias.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/ace/llm/molecules/provider_model_parser.rb', line 39

def parse(input)
  return create_error_result(input, "Input cannot be nil or empty") if input.nil? || input.strip.empty?

  original_input = input.strip
  provider_target, preset_name, preset_error = split_preset_suffix(original_input)
  return create_error_result(original_input, preset_error) if preset_error

  provider_target = @alias_resolver.resolve(provider_target).to_s.strip
  return create_error_result(original_input, "Invalid target: provider/model portion cannot be empty") if provider_target.empty?

  parts = provider_target.split(":", 2)

  if parts.length == 1
    provider = normalize_provider(parts[0])
    unless supported_providers.include?(provider)
      return create_error_result(original_input, provider_validation_error(provider, supported_providers))
    end

    model = default_model_for(provider)
    return ParseResult.new(provider, model, preset_name, nil, true, nil, original_input)
  end

  provider = normalize_provider(parts[0])
  model_with_suffix = parts[1].to_s.strip
  unless supported_providers.include?(provider)
    return create_error_result(original_input, provider_validation_error(provider, supported_providers))
  end

  model_alias, thinking_level, thinking_error = split_thinking_suffix(model_with_suffix)
  return create_error_result(original_input, thinking_error) if thinking_error
  return create_error_result(original_input, "Invalid target: model cannot be empty") if model_alias.to_s.strip.empty?

  resolved_model_input = @alias_resolver.resolve("#{parts[0]}:#{model_alias}")
  resolved_parts = resolved_model_input.split(":", 2)

  return create_error_result(original_input, "Invalid target: provider/model resolution produced invalid model format: #{resolved_model_input}") if resolved_parts.length != 2

  resolved_provider = normalize_provider(resolved_parts[0])
  model = resolved_parts[1].to_s

  unless model && !model.empty?
    return create_error_result(original_input, "Invalid target: resolved model cannot be empty")
  end

  ParseResult.new(resolved_provider, model, preset_name, thinking_level, true, nil, original_input)
end

#supported_providersObject



86
87
88
# File 'lib/ace/llm/molecules/provider_model_parser.rb', line 86

def supported_providers
  @registry.available_providers
end