geminize 1.1.0 → 1.3.0
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 +4 -4
- data/.memory_bank/activeContext.md +35 -1
- data/.memory_bank/progress.md +27 -13
- data/.memory_bank/projectbrief.md +16 -0
- data/.memory_bank/tasks.md +59 -13
- data/CHANGELOG.md +36 -0
- data/README.md +225 -0
- data/examples/code_execution.rb +126 -0
- data/examples/function_calling.rb +218 -0
- data/examples/safety_settings.rb +82 -0
- data/lib/geminize/models/code_execution/code_execution_result.rb +72 -0
- data/lib/geminize/models/code_execution/executable_code.rb +72 -0
- data/lib/geminize/models/content_request_extensions.rb +227 -0
- data/lib/geminize/models/content_request_safety.rb +123 -0
- data/lib/geminize/models/content_response_extensions.rb +129 -0
- data/lib/geminize/models/function_declaration.rb +112 -0
- data/lib/geminize/models/function_response.rb +70 -0
- data/lib/geminize/models/safety_setting.rb +102 -0
- data/lib/geminize/models/tool.rb +65 -0
- data/lib/geminize/models/tool_config.rb +52 -0
- data/lib/geminize/module_extensions.rb +283 -0
- data/lib/geminize/module_safety.rb +135 -0
- data/lib/geminize/version.rb +1 -1
- data/lib/geminize.rb +14 -0
- metadata +16 -1
@@ -0,0 +1,126 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "geminize"
|
6
|
+
|
7
|
+
# Configure the API key
|
8
|
+
Geminize.configure do |config|
|
9
|
+
config.api_key = ENV["GEMINI_API_KEY"] # Make sure to set your API key in the environment
|
10
|
+
config.default_model = "gemini-2.0-flash" # Use a model that supports code execution
|
11
|
+
end
|
12
|
+
|
13
|
+
puts "==========================================="
|
14
|
+
puts "= GEMINIZE CODE EXECUTION EXAMPLES ="
|
15
|
+
puts "==========================================="
|
16
|
+
|
17
|
+
puts "\n=== BASIC CODE EXECUTION EXAMPLE ==="
|
18
|
+
puts "Asking Gemini to calculate the sum of the first 50 prime numbers..."
|
19
|
+
|
20
|
+
begin
|
21
|
+
# Generate a response with code execution enabled
|
22
|
+
response = Geminize.generate_with_code_execution(
|
23
|
+
"What is the sum of the first 50 prime numbers? Generate and run code for the calculation, and make sure you get all 50.",
|
24
|
+
nil,
|
25
|
+
{temperature: 0.2}
|
26
|
+
)
|
27
|
+
|
28
|
+
# Display the generated text
|
29
|
+
puts "\nGemini's response:"
|
30
|
+
puts response.text
|
31
|
+
|
32
|
+
# Display the executable code if present
|
33
|
+
if response.has_executable_code?
|
34
|
+
puts "\nGenerated code:"
|
35
|
+
puts "```#{response.executable_code.language.downcase}"
|
36
|
+
puts response.executable_code.code
|
37
|
+
puts "```"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Display the code execution result if present
|
41
|
+
if response.has_code_execution_result?
|
42
|
+
puts "\nCode execution result:"
|
43
|
+
puts "Outcome: #{response.code_execution_result.outcome}"
|
44
|
+
puts "Output: #{response.code_execution_result.output}"
|
45
|
+
end
|
46
|
+
rescue => e
|
47
|
+
puts "Error during code execution: #{e.message}"
|
48
|
+
end
|
49
|
+
|
50
|
+
puts "\n\n=== PRACTICAL CODE EXECUTION EXAMPLE ==="
|
51
|
+
puts "Asking Gemini to analyze some text data..."
|
52
|
+
|
53
|
+
begin
|
54
|
+
# Generate a response with code execution for data analysis
|
55
|
+
response = Geminize.generate_with_code_execution(
|
56
|
+
"I have a list of temperatures: 32, 25, 30, 22, 28, 27, 35, 31, 29, 26. " \
|
57
|
+
"Please write code to calculate the mean, median, and standard deviation. " \
|
58
|
+
"Also, create a simple histogram visualization using matplotlib.",
|
59
|
+
nil,
|
60
|
+
{temperature: 0.2}
|
61
|
+
)
|
62
|
+
|
63
|
+
# Display the generated text
|
64
|
+
puts "\nGemini's response:"
|
65
|
+
puts response.text
|
66
|
+
|
67
|
+
# Display the executable code if present
|
68
|
+
if response.has_executable_code?
|
69
|
+
puts "\nGenerated code:"
|
70
|
+
puts "```#{response.executable_code.language.downcase}"
|
71
|
+
puts response.executable_code.code
|
72
|
+
puts "```"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Display the code execution result if present
|
76
|
+
if response.has_code_execution_result?
|
77
|
+
puts "\nCode execution result:"
|
78
|
+
puts "Outcome: #{response.code_execution_result.outcome}"
|
79
|
+
puts "Output: #{response.code_execution_result.output}"
|
80
|
+
end
|
81
|
+
rescue => e
|
82
|
+
puts "Error during code execution: #{e.message}"
|
83
|
+
end
|
84
|
+
|
85
|
+
puts "\n\n=== ITERATIVE PROBLEM SOLVING EXAMPLE ==="
|
86
|
+
puts "Asking Gemini to solve a complex problem using code execution..."
|
87
|
+
|
88
|
+
begin
|
89
|
+
# Generate a response for a more complex problem
|
90
|
+
response = Geminize.generate_with_code_execution(
|
91
|
+
"Write a Python function to find the nth Fibonacci number where n is a positive integer. " \
|
92
|
+
"Then use this function to calculate the 50th Fibonacci number. " \
|
93
|
+
"Implement it efficiently using memoization to avoid redundant calculations.",
|
94
|
+
nil,
|
95
|
+
{temperature: 0.2}
|
96
|
+
)
|
97
|
+
|
98
|
+
# Display the generated text
|
99
|
+
puts "\nGemini's response:"
|
100
|
+
puts response.text
|
101
|
+
|
102
|
+
# Display the executable code if present
|
103
|
+
if response.has_executable_code?
|
104
|
+
puts "\nGenerated code:"
|
105
|
+
puts "```#{response.executable_code.language.downcase}"
|
106
|
+
puts response.executable_code.code
|
107
|
+
puts "```"
|
108
|
+
end
|
109
|
+
|
110
|
+
# Display the code execution result if present
|
111
|
+
if response.has_code_execution_result?
|
112
|
+
puts "\nCode execution result:"
|
113
|
+
puts "Outcome: #{response.code_execution_result.outcome}"
|
114
|
+
puts "Output: #{response.code_execution_result.output}"
|
115
|
+
end
|
116
|
+
rescue => e
|
117
|
+
puts "Error during code execution: #{e.message}"
|
118
|
+
puts "\nNOTE: If you hit a quota limit, try:"
|
119
|
+
puts "1. Using a paid API key with higher quotas"
|
120
|
+
puts "2. Reducing the number of examples you run"
|
121
|
+
puts "3. Adding delays between API calls"
|
122
|
+
end
|
123
|
+
|
124
|
+
puts "\n==========================================="
|
125
|
+
puts "= END OF EXAMPLES ="
|
126
|
+
puts "==========================================="
|
@@ -0,0 +1,218 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "geminize"
|
6
|
+
require "json"
|
7
|
+
|
8
|
+
# Configure the API key
|
9
|
+
Geminize.configure do |config|
|
10
|
+
config.api_key = ENV["GEMINI_API_KEY"] # Make sure to set your API key in the environment
|
11
|
+
config.default_model = "gemini-1.5-pro-latest" # Use the latest model that supports function calling
|
12
|
+
end
|
13
|
+
|
14
|
+
# Define a weather function that can handle a location and unit
|
15
|
+
def get_weather(location, unit = "celsius")
|
16
|
+
puts "Getting weather for #{location} in #{unit}..."
|
17
|
+
|
18
|
+
# In a real implementation, this would call a weather API
|
19
|
+
# For this example, we'll return mock data
|
20
|
+
case location.downcase
|
21
|
+
when /new york/
|
22
|
+
{temperature: (unit == "celsius") ? 22 : 72, conditions: "Sunny", humidity: 45}
|
23
|
+
when /london/
|
24
|
+
{temperature: (unit == "celsius") ? 15 : 59, conditions: "Rainy", humidity: 80}
|
25
|
+
when /tokyo/
|
26
|
+
{temperature: (unit == "celsius") ? 26 : 79, conditions: "Partly Cloudy", humidity: 65}
|
27
|
+
else
|
28
|
+
{temperature: (unit == "celsius") ? 20 : 68, conditions: "Unknown", humidity: 50}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Enhanced weather function that can handle a batch of locations
|
33
|
+
def get_weather_batch(locations, unit = "celsius")
|
34
|
+
if locations.is_a?(Array)
|
35
|
+
results = {}
|
36
|
+
locations.each do |location|
|
37
|
+
results[location] = get_weather(location, unit)
|
38
|
+
end
|
39
|
+
results
|
40
|
+
else
|
41
|
+
{locations => get_weather(locations, unit)}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Define a function schema for get_weather
|
46
|
+
weather_function = {
|
47
|
+
name: "get_weather",
|
48
|
+
description: "Get the current weather in a location",
|
49
|
+
parameters: {
|
50
|
+
type: "object",
|
51
|
+
properties: {
|
52
|
+
location: {
|
53
|
+
type: "string",
|
54
|
+
description: "The city and state or country, e.g., 'New York, NY' or 'London, UK'"
|
55
|
+
},
|
56
|
+
unit: {
|
57
|
+
type: "string",
|
58
|
+
enum: ["celsius", "fahrenheit"],
|
59
|
+
description: "The unit of temperature"
|
60
|
+
}
|
61
|
+
},
|
62
|
+
required: ["location"]
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
# Define a batch weather function schema that can handle multiple locations
|
67
|
+
batch_weather_function = {
|
68
|
+
name: "get_weather_batch",
|
69
|
+
description: "Get the current weather for multiple locations at once",
|
70
|
+
parameters: {
|
71
|
+
type: "object",
|
72
|
+
properties: {
|
73
|
+
locations: {
|
74
|
+
type: "array",
|
75
|
+
items: {
|
76
|
+
type: "string"
|
77
|
+
},
|
78
|
+
description: "List of cities, e.g., ['New York, NY', 'London, UK', 'Tokyo, Japan']"
|
79
|
+
},
|
80
|
+
unit: {
|
81
|
+
type: "string",
|
82
|
+
enum: ["celsius", "fahrenheit"],
|
83
|
+
description: "The unit of temperature"
|
84
|
+
}
|
85
|
+
},
|
86
|
+
required: ["locations"]
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
puts "==========================================="
|
91
|
+
puts "= GEMINIZE FUNCTION CALLING & JSON EXAMPLES ="
|
92
|
+
puts "==========================================="
|
93
|
+
|
94
|
+
puts "\n=== FUNCTION CALLING EXAMPLE ==="
|
95
|
+
puts "Asking Gemini about the weather in New York..."
|
96
|
+
|
97
|
+
begin
|
98
|
+
# Generate a response with the function definition
|
99
|
+
response = Geminize.generate_with_functions(
|
100
|
+
"What's the weather like in New York?",
|
101
|
+
[weather_function],
|
102
|
+
nil,
|
103
|
+
{temperature: 0.2}
|
104
|
+
)
|
105
|
+
|
106
|
+
# Check if the model wants to call a function
|
107
|
+
if response.has_function_call?
|
108
|
+
function_call = response.function_call
|
109
|
+
puts "Model wants to call function: #{function_call.name}"
|
110
|
+
puts "With arguments: #{function_call.response.inspect}"
|
111
|
+
|
112
|
+
function_name = function_call.name
|
113
|
+
args = function_call.response
|
114
|
+
|
115
|
+
if function_name == "get_weather"
|
116
|
+
location = args["location"]
|
117
|
+
unit = args["unit"] || "celsius"
|
118
|
+
|
119
|
+
# Call our weather function
|
120
|
+
weather_data = get_weather(location, unit)
|
121
|
+
puts "Weather data for #{location}: #{weather_data.inspect}"
|
122
|
+
|
123
|
+
# Process the function result
|
124
|
+
final_response = Geminize.process_function_call(response) do |name, arguments|
|
125
|
+
get_weather(arguments["location"], arguments["unit"])
|
126
|
+
end
|
127
|
+
|
128
|
+
puts "\nFinal response from Gemini:"
|
129
|
+
puts final_response.text
|
130
|
+
else
|
131
|
+
puts "Unexpected function call: #{function_name}"
|
132
|
+
end
|
133
|
+
else
|
134
|
+
puts "Model did not request to call a function."
|
135
|
+
puts "Response: #{response.text}"
|
136
|
+
end
|
137
|
+
rescue => e
|
138
|
+
puts "Error during function calling: #{e.message}"
|
139
|
+
end
|
140
|
+
|
141
|
+
# Example of using JSON mode
|
142
|
+
puts "\n\n=== JSON MODE EXAMPLE ==="
|
143
|
+
puts "Using JSON mode to get weather data in structured format..."
|
144
|
+
|
145
|
+
begin
|
146
|
+
json_response = Geminize.generate_json(
|
147
|
+
"Get the current temperature and weather conditions for New York.",
|
148
|
+
nil,
|
149
|
+
{
|
150
|
+
system_instruction: "Return a JSON object with temperature in celsius and conditions."
|
151
|
+
}
|
152
|
+
)
|
153
|
+
|
154
|
+
if json_response.has_json_response?
|
155
|
+
puts "Structured JSON response:"
|
156
|
+
puts JSON.pretty_generate(json_response.json_response)
|
157
|
+
else
|
158
|
+
puts "Raw text response (not valid JSON):"
|
159
|
+
puts json_response.text
|
160
|
+
end
|
161
|
+
rescue => e
|
162
|
+
puts "Error during JSON mode: #{e.message}"
|
163
|
+
end
|
164
|
+
|
165
|
+
puts "\n\n=== BATCH FUNCTION CALL EXAMPLE ==="
|
166
|
+
puts "Using batch function to efficiently get weather for multiple cities at once..."
|
167
|
+
|
168
|
+
begin
|
169
|
+
# Use a batch function to get all cities at once (more efficient)
|
170
|
+
response = Geminize.generate_with_functions(
|
171
|
+
"I need weather information for New York, Tokyo, and London. Please get all this information in a single function call.",
|
172
|
+
[batch_weather_function],
|
173
|
+
nil,
|
174
|
+
{temperature: 0.2}
|
175
|
+
)
|
176
|
+
|
177
|
+
# Check if the model wants to call the batch function
|
178
|
+
if response.has_function_call?
|
179
|
+
function_call = response.function_call
|
180
|
+
puts "Model wants to call function: #{function_call.name}"
|
181
|
+
puts "With arguments: #{function_call.response.inspect}"
|
182
|
+
|
183
|
+
function_name = function_call.name
|
184
|
+
args = function_call.response
|
185
|
+
|
186
|
+
if function_name == "get_weather_batch"
|
187
|
+
locations = args["locations"]
|
188
|
+
unit = args["unit"] || "celsius"
|
189
|
+
|
190
|
+
# Get weather for all locations at once
|
191
|
+
weather_data = get_weather_batch(locations, unit)
|
192
|
+
puts "Weather data for multiple locations: #{weather_data.inspect}"
|
193
|
+
|
194
|
+
# Process the function result with a single API call
|
195
|
+
final_response = Geminize.process_function_call(response) do |name, arguments|
|
196
|
+
get_weather_batch(arguments["locations"], arguments["unit"])
|
197
|
+
end
|
198
|
+
|
199
|
+
puts "\nFinal response from Gemini:"
|
200
|
+
puts final_response.text
|
201
|
+
else
|
202
|
+
puts "Unexpected function call: #{function_name}"
|
203
|
+
end
|
204
|
+
else
|
205
|
+
puts "Model did not request to call a function."
|
206
|
+
puts "Response: #{response.text}"
|
207
|
+
end
|
208
|
+
rescue => e
|
209
|
+
puts "Error during batch function calling: #{e.message}"
|
210
|
+
puts "\nNOTE: If you hit a quota limit, try:"
|
211
|
+
puts "1. Using a paid API key with higher quotas"
|
212
|
+
puts "2. Reducing the number of examples you run"
|
213
|
+
puts "3. Adding delays between API calls"
|
214
|
+
end
|
215
|
+
|
216
|
+
puts "\n==========================================="
|
217
|
+
puts "= END OF EXAMPLES ="
|
218
|
+
puts "==========================================="
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "geminize"
|
6
|
+
|
7
|
+
# Configure the API key
|
8
|
+
Geminize.configure do |config|
|
9
|
+
config.api_key = ENV["GEMINI_API_KEY"] # Make sure to set your API key in the environment
|
10
|
+
config.default_model = "gemini-1.5-pro-latest" # Use the latest model
|
11
|
+
end
|
12
|
+
|
13
|
+
# A prompt that might trigger safety filters
|
14
|
+
POTENTIALLY_SENSITIVE_PROMPT = "Describe a violent conflict scene from a movie"
|
15
|
+
|
16
|
+
puts "1. Generating with default safety settings:"
|
17
|
+
begin
|
18
|
+
response = Geminize.generate_text(POTENTIALLY_SENSITIVE_PROMPT, nil, temperature: 0.2)
|
19
|
+
puts "Default response:\n#{response.text}\n\n"
|
20
|
+
rescue Geminize::GeminizeError => e
|
21
|
+
puts "Error with default settings: #{e.message}\n\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
puts "2. Generating with maximum safety (blocking most potentially harmful content):"
|
25
|
+
begin
|
26
|
+
response = Geminize.generate_text_safe(POTENTIALLY_SENSITIVE_PROMPT, nil, temperature: 0.2)
|
27
|
+
puts "Maximum safety response:\n#{response.text}\n\n"
|
28
|
+
rescue Geminize::GeminizeError => e
|
29
|
+
puts "Error with maximum safety: #{e.message}\n\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
puts "3. Generating with minimum safety (blocking only high-risk content):"
|
33
|
+
begin
|
34
|
+
response = Geminize.generate_text_permissive(POTENTIALLY_SENSITIVE_PROMPT, nil, temperature: 0.2)
|
35
|
+
puts "Minimum safety response:\n#{response.text}\n\n"
|
36
|
+
rescue Geminize::GeminizeError => e
|
37
|
+
puts "Error with minimum safety: #{e.message}\n\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
puts "4. Generating with custom safety settings:"
|
41
|
+
begin
|
42
|
+
# Custom safety settings:
|
43
|
+
# - Block medium and above for dangerous content
|
44
|
+
# - Block low and above for hate speech
|
45
|
+
# - Block only high for sexually explicit content
|
46
|
+
# - No blocks for harassment
|
47
|
+
custom_safety_settings = [
|
48
|
+
{category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_MEDIUM_AND_ABOVE"},
|
49
|
+
{category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_LOW_AND_ABOVE"},
|
50
|
+
{category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_ONLY_HIGH"},
|
51
|
+
{category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_NONE"}
|
52
|
+
]
|
53
|
+
|
54
|
+
response = Geminize.generate_with_safety_settings(
|
55
|
+
POTENTIALLY_SENSITIVE_PROMPT,
|
56
|
+
custom_safety_settings,
|
57
|
+
nil,
|
58
|
+
temperature: 0.2
|
59
|
+
)
|
60
|
+
puts "Custom safety response:\n#{response.text}\n\n"
|
61
|
+
rescue Geminize::GeminizeError => e
|
62
|
+
puts "Error with custom safety: #{e.message}\n\n"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Demonstrate direct usage of safety settings in a ContentRequest
|
66
|
+
puts "5. Using safety settings directly in a ContentRequest:"
|
67
|
+
begin
|
68
|
+
generator = Geminize::TextGeneration.new
|
69
|
+
content_request = Geminize::Models::ContentRequest.new(
|
70
|
+
POTENTIALLY_SENSITIVE_PROMPT,
|
71
|
+
nil,
|
72
|
+
temperature: 0.2
|
73
|
+
)
|
74
|
+
|
75
|
+
# Add specific safety settings
|
76
|
+
content_request.add_safety_setting("HARM_CATEGORY_DANGEROUS_CONTENT", "BLOCK_MEDIUM_AND_ABOVE")
|
77
|
+
|
78
|
+
response = generator.generate(content_request)
|
79
|
+
puts "ContentRequest safety response:\n#{response.text}\n\n"
|
80
|
+
rescue Geminize::GeminizeError => e
|
81
|
+
puts "Error with ContentRequest safety: #{e.message}\n\n"
|
82
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Geminize
|
4
|
+
module Models
|
5
|
+
module CodeExecution
|
6
|
+
# Represents the result of executed code
|
7
|
+
class CodeExecutionResult
|
8
|
+
# Valid outcome values for code execution
|
9
|
+
VALID_OUTCOMES = ["OUTCOME_OK", "OUTCOME_ERROR"].freeze
|
10
|
+
|
11
|
+
# @return [String] The outcome of the code execution (e.g., "OUTCOME_OK", "OUTCOME_ERROR")
|
12
|
+
attr_reader :outcome
|
13
|
+
|
14
|
+
# @return [String] The output from the code execution
|
15
|
+
attr_reader :output
|
16
|
+
|
17
|
+
# Initialize a new code execution result
|
18
|
+
# @param outcome [String] The outcome of the code execution
|
19
|
+
# @param output [String] The output from the code execution
|
20
|
+
# @raise [Geminize::ValidationError] If the code execution result is invalid
|
21
|
+
def initialize(outcome, output)
|
22
|
+
@outcome = outcome
|
23
|
+
@output = output
|
24
|
+
validate!
|
25
|
+
end
|
26
|
+
|
27
|
+
# Validate the code execution result
|
28
|
+
# @raise [Geminize::ValidationError] If the code execution result is invalid
|
29
|
+
# @return [Boolean] true if validation passes
|
30
|
+
def validate!
|
31
|
+
unless @outcome.is_a?(String)
|
32
|
+
raise Geminize::ValidationError.new(
|
33
|
+
"Outcome must be a string, got #{@outcome.class}",
|
34
|
+
"INVALID_ARGUMENT"
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
unless VALID_OUTCOMES.include?(@outcome)
|
39
|
+
raise Geminize::ValidationError.new(
|
40
|
+
"Invalid outcome: #{@outcome}. Must be one of: #{VALID_OUTCOMES.join(", ")}",
|
41
|
+
"INVALID_ARGUMENT"
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
unless @output.is_a?(String)
|
46
|
+
raise Geminize::ValidationError.new(
|
47
|
+
"Output must be a string, got #{@output.class}",
|
48
|
+
"INVALID_ARGUMENT"
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
# Convert the code execution result to a hash
|
56
|
+
# @return [Hash] The code execution result as a hash
|
57
|
+
def to_hash
|
58
|
+
{
|
59
|
+
outcome: @outcome,
|
60
|
+
output: @output
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Alias for to_hash
|
65
|
+
# @return [Hash] The code execution result as a hash
|
66
|
+
def to_h
|
67
|
+
to_hash
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Geminize
|
4
|
+
module Models
|
5
|
+
module CodeExecution
|
6
|
+
# Represents executable code generated by the model
|
7
|
+
class ExecutableCode
|
8
|
+
# Valid language options for executable code
|
9
|
+
VALID_LANGUAGES = ["PYTHON"].freeze
|
10
|
+
|
11
|
+
# @return [String] The language of the code (e.g., "PYTHON")
|
12
|
+
attr_reader :language
|
13
|
+
|
14
|
+
# @return [String] The code content
|
15
|
+
attr_reader :code
|
16
|
+
|
17
|
+
# Initialize a new executable code object
|
18
|
+
# @param language [String] The programming language of the code (e.g., "PYTHON")
|
19
|
+
# @param code [String] The code content
|
20
|
+
# @raise [Geminize::ValidationError] If the executable code is invalid
|
21
|
+
def initialize(language, code)
|
22
|
+
@language = language
|
23
|
+
@code = code
|
24
|
+
validate!
|
25
|
+
end
|
26
|
+
|
27
|
+
# Validate the executable code
|
28
|
+
# @raise [Geminize::ValidationError] If the executable code is invalid
|
29
|
+
# @return [Boolean] true if validation passes
|
30
|
+
def validate!
|
31
|
+
unless @language.is_a?(String)
|
32
|
+
raise Geminize::ValidationError.new(
|
33
|
+
"Language must be a string, got #{@language.class}",
|
34
|
+
"INVALID_ARGUMENT"
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
unless VALID_LANGUAGES.include?(@language)
|
39
|
+
raise Geminize::ValidationError.new(
|
40
|
+
"Invalid language: #{@language}. Must be one of: #{VALID_LANGUAGES.join(", ")}",
|
41
|
+
"INVALID_ARGUMENT"
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
unless @code.is_a?(String)
|
46
|
+
raise Geminize::ValidationError.new(
|
47
|
+
"Code must be a string, got #{@code.class}",
|
48
|
+
"INVALID_ARGUMENT"
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
# Convert the executable code to a hash
|
56
|
+
# @return [Hash] The executable code as a hash
|
57
|
+
def to_hash
|
58
|
+
{
|
59
|
+
language: @language,
|
60
|
+
code: @code
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Alias for to_hash
|
65
|
+
# @return [Hash] The executable code as a hash
|
66
|
+
def to_h
|
67
|
+
to_hash
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|