last_llm 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +246 -0
- data/lib/last_llm/client.rb +100 -0
- data/lib/last_llm/completion.rb +19 -0
- data/lib/last_llm/configuration.rb +115 -0
- data/lib/last_llm/extensions/dry_schema_extensions.rb +76 -0
- data/lib/last_llm/provider.rb +152 -0
- data/lib/last_llm/providers/anthropic.rb +124 -0
- data/lib/last_llm/providers/constants.rb +33 -0
- data/lib/last_llm/providers/deepseek.rb +121 -0
- data/lib/last_llm/providers/google_gemini.rb +175 -0
- data/lib/last_llm/providers/ollama.rb +124 -0
- data/lib/last_llm/providers/openai.rb +184 -0
- data/lib/last_llm/providers/test_provider.rb +38 -0
- data/lib/last_llm/railtie.rb +38 -0
- data/lib/last_llm/schema.rb +241 -0
- data/lib/last_llm/structured_output.rb +58 -0
- data/lib/last_llm/tool.rb +110 -0
- data/lib/last_llm/version.rb +5 -0
- data/lib/last_llm.rb +88 -0
- metadata +144 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LastLLM
|
4
|
+
# Error raised when tool parameter validation fails
|
5
|
+
class ToolValidationError < ValidationError; end
|
6
|
+
|
7
|
+
# Tool class for defining callable functions that can be used with LLM providers
|
8
|
+
class Tool
|
9
|
+
attr_reader :name, :description, :parameters, :function
|
10
|
+
|
11
|
+
# Initialize a new tool
|
12
|
+
# @param name [String] The name of the tool
|
13
|
+
# @param description [String] A description of what the tool does
|
14
|
+
# @param parameters [Hash] JSON Schema for the tool parameters
|
15
|
+
# @param function [Proc] The function to execute when the tool is called
|
16
|
+
def initialize(name:, description:, parameters:, function:)
|
17
|
+
validate_initialization_params(name, description, parameters, function)
|
18
|
+
|
19
|
+
@name = name
|
20
|
+
@description = description
|
21
|
+
@parameters = parameters
|
22
|
+
@function = function
|
23
|
+
end
|
24
|
+
|
25
|
+
# Call the tool with the provided parameters
|
26
|
+
# @param params [Hash] Parameters to pass to the tool function
|
27
|
+
# @return [Hash] The result of the function call
|
28
|
+
def call(params)
|
29
|
+
# Convert string keys to symbols
|
30
|
+
params = symbolize_keys(params)
|
31
|
+
|
32
|
+
# Validate parameters against the schema
|
33
|
+
validate_parameters(params)
|
34
|
+
|
35
|
+
# Convert parameter types if needed
|
36
|
+
converted_params = convert_parameter_types(params)
|
37
|
+
|
38
|
+
# Execute the function
|
39
|
+
function.call(converted_params)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def validate_initialization_params(name, description, parameters, function)
|
45
|
+
missing_params = []
|
46
|
+
missing_params << 'name' unless name.is_a?(String) && !name.empty?
|
47
|
+
missing_params << 'description' unless description.is_a?(String) && !description.empty?
|
48
|
+
missing_params << 'parameters' unless parameters.is_a?(Hash) && !parameters.empty?
|
49
|
+
missing_params << 'function' unless function.respond_to?(:call)
|
50
|
+
|
51
|
+
return if missing_params.empty?
|
52
|
+
|
53
|
+
raise ArgumentError, "Missing or invalid required attributes: #{missing_params.join(', ')}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_parameters(params)
|
57
|
+
# Basic validation for required parameters
|
58
|
+
if parameters[:required].is_a?(Array)
|
59
|
+
parameters[:required].each do |required_param|
|
60
|
+
unless params.key?(required_param.to_sym)
|
61
|
+
raise ToolValidationError, "Missing required parameter: #{required_param}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Validate enum values if present
|
67
|
+
return unless parameters[:properties].is_a?(Hash)
|
68
|
+
|
69
|
+
parameters[:properties].each do |prop_name, prop_schema|
|
70
|
+
next unless params.key?(prop_name.to_sym) && prop_schema[:enum].is_a?(Array)
|
71
|
+
|
72
|
+
param_value = params[prop_name.to_sym]
|
73
|
+
unless prop_schema[:enum].include?(param_value)
|
74
|
+
raise ToolValidationError, "Invalid value for #{prop_name}: #{param_value}. " \
|
75
|
+
"Allowed values: #{prop_schema[:enum].join(', ')}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def convert_parameter_types(params)
|
81
|
+
converted_params = params.dup
|
82
|
+
|
83
|
+
parameters[:properties].each do |prop_name, prop_schema|
|
84
|
+
next unless params.key?(prop_name.to_sym)
|
85
|
+
|
86
|
+
param_value = params[prop_name.to_sym]
|
87
|
+
prop_name_sym = prop_name.to_sym
|
88
|
+
|
89
|
+
case prop_schema[:type]
|
90
|
+
when 'number', 'integer'
|
91
|
+
converted_params[prop_name_sym] = param_value.to_f if param_value.is_a?(String)
|
92
|
+
if prop_schema[:type] == 'integer' && param_value.is_a?(Float)
|
93
|
+
converted_params[prop_name_sym] =
|
94
|
+
param_value.to_i
|
95
|
+
end
|
96
|
+
when 'boolean'
|
97
|
+
converted_params[prop_name_sym] = (param_value.downcase == 'true') if param_value.is_a?(String)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
converted_params
|
102
|
+
end
|
103
|
+
|
104
|
+
def symbolize_keys(hash)
|
105
|
+
return hash unless hash.is_a?(Hash)
|
106
|
+
|
107
|
+
hash.transform_keys(&:to_sym)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/last_llm.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry-schema'
|
4
|
+
require 'faraday'
|
5
|
+
require 'json'
|
6
|
+
require 'last_llm/extensions/dry_schema_extensions'
|
7
|
+
|
8
|
+
# Main module for LastLLM
|
9
|
+
module LastLLM
|
10
|
+
# Base error class for all LastLLM errors
|
11
|
+
class Error < StandardError; end
|
12
|
+
|
13
|
+
# Error raised when configuration is invalid
|
14
|
+
class ConfigurationError < Error; end
|
15
|
+
|
16
|
+
# Error raised when validation fails
|
17
|
+
class ValidationError < Error; end
|
18
|
+
|
19
|
+
# Error raised when API request fails
|
20
|
+
class ApiError < Error
|
21
|
+
attr_reader :status
|
22
|
+
|
23
|
+
def initialize(message, status = nil)
|
24
|
+
@status = status
|
25
|
+
super(message)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Autoload all required components
|
30
|
+
autoload :Configuration, 'last_llm/configuration'
|
31
|
+
autoload :Client, 'last_llm/client'
|
32
|
+
autoload :Provider, 'last_llm/provider'
|
33
|
+
autoload :Schema, 'last_llm/schema'
|
34
|
+
autoload :StructuredOutput, 'last_llm/structured_output'
|
35
|
+
autoload :Tool, 'last_llm/tool'
|
36
|
+
autoload :Railtie, 'last_llm/railtie'
|
37
|
+
autoload :Completion, 'last_llm/completion'
|
38
|
+
autoload :VERSION, 'last_llm/version'
|
39
|
+
|
40
|
+
# Provider implementations
|
41
|
+
module Providers
|
42
|
+
autoload :OpenAI, 'last_llm/providers/openai'
|
43
|
+
autoload :Anthropic, 'last_llm/providers/anthropic'
|
44
|
+
autoload :GoogleGemini, 'last_llm/providers/google_gemini'
|
45
|
+
autoload :Deepseek, 'last_llm/providers/deepseek'
|
46
|
+
autoload :Ollama, 'last_llm/providers/ollama'
|
47
|
+
end
|
48
|
+
|
49
|
+
class << self
|
50
|
+
# Configure the LastLLM client
|
51
|
+
# @yield [config] Configuration instance
|
52
|
+
# @return [Configuration] The updated configuration
|
53
|
+
def configure
|
54
|
+
self.configuration ||= Configuration.new
|
55
|
+
yield(configuration) if block_given?
|
56
|
+
configuration
|
57
|
+
end
|
58
|
+
|
59
|
+
# Get the current configuration or create a new one
|
60
|
+
# @return [Configuration] The current configuration
|
61
|
+
def configuration
|
62
|
+
@configuration ||= Configuration.new
|
63
|
+
end
|
64
|
+
|
65
|
+
# Create a new client with the current configuration
|
66
|
+
# @param options [Hash] Additional options for the client
|
67
|
+
# @return [Client] A new client instance
|
68
|
+
def client(options = {})
|
69
|
+
Client.new(configuration, options)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Reset the configuration to defaults
|
73
|
+
# @return [Configuration] A new default configuration
|
74
|
+
def reset_configuration!
|
75
|
+
@configuration = Configuration.new
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add Rails integration helper
|
79
|
+
def setup_rails!
|
80
|
+
return unless defined?(Rails)
|
81
|
+
|
82
|
+
require 'last_llm/railtie'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Rails integration
|
88
|
+
LastLLM.setup_rails! if defined?(Rails)
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: last_llm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Obukwelu
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-03-04 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: dry-schema
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.6'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '1.6'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: faraday
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: json
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '2.0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rspec
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.12'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.12'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: vcr
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '6.0'
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '6.0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: webmock
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '3.18'
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '3.18'
|
96
|
+
description: A unified client for interacting with various LLM providers
|
97
|
+
email:
|
98
|
+
- sam@obukwelu.com
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- README.md
|
104
|
+
- lib/last_llm.rb
|
105
|
+
- lib/last_llm/client.rb
|
106
|
+
- lib/last_llm/completion.rb
|
107
|
+
- lib/last_llm/configuration.rb
|
108
|
+
- lib/last_llm/extensions/dry_schema_extensions.rb
|
109
|
+
- lib/last_llm/provider.rb
|
110
|
+
- lib/last_llm/providers/anthropic.rb
|
111
|
+
- lib/last_llm/providers/constants.rb
|
112
|
+
- lib/last_llm/providers/deepseek.rb
|
113
|
+
- lib/last_llm/providers/google_gemini.rb
|
114
|
+
- lib/last_llm/providers/ollama.rb
|
115
|
+
- lib/last_llm/providers/openai.rb
|
116
|
+
- lib/last_llm/providers/test_provider.rb
|
117
|
+
- lib/last_llm/railtie.rb
|
118
|
+
- lib/last_llm/schema.rb
|
119
|
+
- lib/last_llm/structured_output.rb
|
120
|
+
- lib/last_llm/tool.rb
|
121
|
+
- lib/last_llm/version.rb
|
122
|
+
homepage: https://github.com/joemocha/last_llm
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
metadata:
|
126
|
+
rubygems_mfa_required: 'true'
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '3.0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubygems_version: 3.6.3
|
142
|
+
specification_version: 4
|
143
|
+
summary: Last LLM
|
144
|
+
test_files: []
|