dspy-gemini 1.0.3 → 1.0.5
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/README.md +23 -170
- data/lib/dspy/gemini/README.md +38 -23
- data/lib/dspy/gemini/lm/adapters/gemini_adapter.rb +3 -4
- data/lib/dspy/gemini/lm/schema_converter.rb +21 -74
- data/lib/dspy/gemini/version.rb +1 -1
- data/lib/dspy/gemini.rb +0 -3
- metadata +17 -6
- data/lib/dspy/gemini/guardrails.rb +0 -25
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f74542eb4beab2b4b2c3c3931b496c4a0ef8d7e6925fb63dd7bf1b71d770a9c0
|
|
4
|
+
data.tar.gz: 6d8cdd3ffcadbbea59ebc03c0b199fa79e07aac79a07ba9dc29aba1aa39169fa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f30d06f707b26c85d0497feb334664f553f7f02f5c5fccfd5ecfd9a4ef32d668f6cb1f567a22a772e8f48a5a7cc7ccc462a96abc8ec354161e722717758574d8
|
|
7
|
+
data.tar.gz: aa30c0732139dc720652735bc5f850a5ba1f39cd2e32082dc0d592a7a61a344143f72160737583cb3e15300a958a87084b7f5612b1029e60dc5559b8cb72b53a
|
data/README.md
CHANGED
|
@@ -6,95 +6,16 @@
|
|
|
6
6
|
[](https://oss.vicente.services/dspy.rb/)
|
|
7
7
|
[](https://discord.gg/zWBhrMqn)
|
|
8
8
|
|
|
9
|
-
**Build
|
|
9
|
+
**Build typed agents and model-backed programs in Ruby.**
|
|
10
10
|
|
|
11
|
-
DSPy.rb
|
|
11
|
+
DSPy.rb brings [DSPy](https://dspy.ai)'s signature, module, agent, and optimizer model to Ruby, with Sorbet types and Ruby-native integrations. A signature declares a task as typed inputs and outputs. A module chooses how to execute it. Ruby composes modules into programs, while `ReAct` adds a bounded loop when the model should choose the next action. DSPy.rb builds the provider request and validates the returned shape.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
require 'dspy'
|
|
15
|
-
|
|
16
|
-
DSPy.configure do |c|
|
|
17
|
-
c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY'])
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
class Summarize < DSPy::Signature
|
|
21
|
-
description "Summarize the given text in one sentence."
|
|
22
|
-
|
|
23
|
-
input do
|
|
24
|
-
const :text, String
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
output do
|
|
28
|
-
const :summary, String
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
summarizer = DSPy::Predict.new(Summarize)
|
|
33
|
-
result = summarizer.call(text: "DSPy.rb brings structured LLM programming to Ruby...")
|
|
34
|
-
puts result.summary
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
That's it. No prompt templates. No JSON parsing. No prayer-based error handling.
|
|
38
|
-
|
|
39
|
-
## Installation
|
|
40
|
-
|
|
41
|
-
```ruby
|
|
42
|
-
# Gemfile
|
|
43
|
-
gem 'dspy'
|
|
44
|
-
gem 'dspy-openai' # For OpenAI, OpenRouter, or Ollama
|
|
45
|
-
# gem 'dspy-anthropic' # For Claude
|
|
46
|
-
# gem 'dspy-gemini' # For Gemini
|
|
47
|
-
# gem 'dspy-ruby_llm' # For 12+ providers via RubyLLM
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
bundle install
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Quick Start
|
|
55
|
-
|
|
56
|
-
### Configure Your LLM
|
|
57
|
-
|
|
58
|
-
```ruby
|
|
59
|
-
# OpenAI
|
|
60
|
-
DSPy.configure do |c|
|
|
61
|
-
c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
62
|
-
api_key: ENV['OPENAI_API_KEY'],
|
|
63
|
-
structured_outputs: true)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Anthropic Claude
|
|
67
|
-
DSPy.configure do |c|
|
|
68
|
-
c.lm = DSPy::LM.new('anthropic/claude-sonnet-4-20250514',
|
|
69
|
-
api_key: ENV['ANTHROPIC_API_KEY'])
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Google Gemini
|
|
73
|
-
DSPy.configure do |c|
|
|
74
|
-
c.lm = DSPy::LM.new('gemini/gemini-2.5-flash',
|
|
75
|
-
api_key: ENV['GEMINI_API_KEY'])
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Ollama (local, free)
|
|
79
|
-
DSPy.configure do |c|
|
|
80
|
-
c.lm = DSPy::LM.new('ollama/llama3.2')
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# OpenRouter (200+ models)
|
|
84
|
-
DSPy.configure do |c|
|
|
85
|
-
c.lm = DSPy::LM.new('openrouter/deepseek/deepseek-chat-v3.1:free',
|
|
86
|
-
api_key: ENV['OPENROUTER_API_KEY'])
|
|
87
|
-
end
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### Define a Signature
|
|
13
|
+
The `1.x` series is the current stable release line.
|
|
91
14
|
|
|
92
|
-
|
|
15
|
+
In a configured application, the task contract and call look like this:
|
|
93
16
|
|
|
94
17
|
```ruby
|
|
95
18
|
class Classify < DSPy::Signature
|
|
96
|
-
description "Classify sentiment of a given sentence."
|
|
97
|
-
|
|
98
19
|
class Sentiment < T::Enum
|
|
99
20
|
enums do
|
|
100
21
|
Positive = new('positive')
|
|
@@ -104,7 +25,7 @@ class Classify < DSPy::Signature
|
|
|
104
25
|
end
|
|
105
26
|
|
|
106
27
|
input do
|
|
107
|
-
const :sentence, String
|
|
28
|
+
const :sentence, String
|
|
108
29
|
end
|
|
109
30
|
|
|
110
31
|
output do
|
|
@@ -114,107 +35,39 @@ class Classify < DSPy::Signature
|
|
|
114
35
|
end
|
|
115
36
|
|
|
116
37
|
classifier = DSPy::Predict.new(Classify)
|
|
117
|
-
result = classifier.call(sentence: "This book was
|
|
118
|
-
|
|
119
|
-
result.sentiment # => #<Sentiment::Positive>
|
|
120
|
-
result.confidence # => 0.92
|
|
38
|
+
result = classifier.call(sentence: "This book was fun to read!")
|
|
121
39
|
```
|
|
122
40
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
For complex reasoning, use `ChainOfThought` to get step-by-step explanations:
|
|
126
|
-
|
|
127
|
-
```ruby
|
|
128
|
-
solver = DSPy::ChainOfThought.new(MathProblem)
|
|
129
|
-
result = solver.call(problem: "If a train travels 120km in 2 hours, what's its speed?")
|
|
130
|
-
|
|
131
|
-
result.reasoning # => "Speed = Distance / Time = 120km / 2h = 60km/h"
|
|
132
|
-
result.answer # => "60 km/h"
|
|
133
|
-
```
|
|
41
|
+
Define a typed task contract instead of maintaining an output template. Receive validated Ruby values instead of parsing provider JSON. Handle configuration, transport, and validation errors explicitly.
|
|
134
42
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
Build agents that use tools to accomplish tasks:
|
|
138
|
-
|
|
139
|
-
```ruby
|
|
140
|
-
class SearchTool < DSPy::Tools::Base
|
|
141
|
-
tool_name "search"
|
|
142
|
-
tool_description "Search for information"
|
|
143
|
-
|
|
144
|
-
sig { params(query: String).returns(String) }
|
|
145
|
-
def call(query:)
|
|
146
|
-
# Your search implementation
|
|
147
|
-
"Result 1, Result 2"
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
agent = DSPy::ReAct.new(ResearchTask, tools: [SearchTool.new], max_iterations: 5)
|
|
152
|
-
result = agent.call(question: "What's the latest on Ruby 3.4?")
|
|
153
|
-
```
|
|
43
|
+
## Start Here
|
|
154
44
|
|
|
155
|
-
|
|
45
|
+
The [Quick Start](https://oss.vicente.services/dspy.rb/getting-started/quick-start/) is the complete supported path: install the core and provider gems, configure a key, save a program, and run it.
|
|
156
46
|
|
|
157
|
-
|
|
47
|
+
Use [Installation](https://oss.vicente.services/dspy.rb/getting-started/installation/) to choose a provider. The [package and capability matrix](https://oss.vicente.services/dspy.rb/getting-started/packages/) records exact gem names, require behavior, support labels, and model or SDK boundaries.
|
|
158
48
|
|
|
159
|
-
|
|
49
|
+
## Mental Model
|
|
160
50
|
|
|
161
|
-
|
|
51
|
+
- A `DSPy::Signature` defines the task contract.
|
|
52
|
+
- `DSPy::Predict` and other modules choose an execution strategy.
|
|
53
|
+
- Ordinary Ruby owns fixed sequencing, branching, persistence, permissions, and failure policy.
|
|
54
|
+
- Results cross a runtime validation boundary; validation establishes shape, not factual correctness.
|
|
162
55
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
**Optimization**: MIPROv2 (Bayesian optimization) and GEPA (genetic evolution) for prompt tuning.
|
|
166
|
-
|
|
167
|
-
**Provider Support**: OpenAI, Anthropic, Gemini, Ollama, and OpenRouter via official SDKs.
|
|
168
|
-
|
|
169
|
-
## Documentation
|
|
170
|
-
|
|
171
|
-
**[Full Documentation](https://oss.vicente.services/dspy.rb/)** — Getting started, core concepts, advanced patterns.
|
|
172
|
-
|
|
173
|
-
**[llms.txt](https://oss.vicente.services/dspy.rb/llms.txt)** — LLM-friendly reference for AI assistants.
|
|
174
|
-
|
|
175
|
-
### Claude Skill
|
|
176
|
-
|
|
177
|
-
A [Claude Skill](https://github.com/vicentereig/dspy-rb-skill) is available to help you build DSPy.rb applications:
|
|
178
|
-
|
|
179
|
-
```bash
|
|
180
|
-
# Claude Code — install from the vicentereig/engineering marketplace
|
|
181
|
-
claude install-skill vicentereig/engineering --skill dspy-rb
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
For Claude.ai Pro/Max, download the [skill ZIP](https://github.com/vicentereig/dspy-rb-skill/archive/refs/heads/main.zip) and upload via Settings > Skills.
|
|
185
|
-
|
|
186
|
-
## Examples
|
|
187
|
-
|
|
188
|
-
The [examples/](examples/) directory has runnable code for common patterns:
|
|
189
|
-
|
|
190
|
-
- Sentiment classification
|
|
191
|
-
- ReAct agents with tools
|
|
192
|
-
- Image analysis
|
|
193
|
-
- Prompt optimization
|
|
194
|
-
|
|
195
|
-
```bash
|
|
196
|
-
bundle exec ruby examples/basic_search_agent.rb
|
|
197
|
-
```
|
|
56
|
+
### ReAct Agents
|
|
198
57
|
|
|
199
|
-
|
|
58
|
+
Use `ReAct` when the model needs to choose among typed Ruby tools inside an iteration bound. The application still owns tool authorization, side effects, budgets, and errors. See [Predictors](https://oss.vicente.services/dspy.rb/core-concepts/predictors/) and [Toolsets](https://oss.vicente.services/dspy.rb/core-concepts/toolsets/).
|
|
200
59
|
|
|
201
|
-
|
|
60
|
+
## Explore
|
|
202
61
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
| `dspy-evals` | Evaluation harness with metrics and callbacks |
|
|
207
|
-
| `dspy-miprov2` | Bayesian optimization for prompt tuning |
|
|
208
|
-
| `dspy-gepa` | Genetic-Pareto prompt evolution |
|
|
209
|
-
| `dspy-o11y-langfuse` | Auto-configure Langfuse tracing |
|
|
210
|
-
| `dspy-code_act` | Think-Code-Observe agents |
|
|
211
|
-
| `dspy-deep_search` | Production DeepSearch with Exa |
|
|
62
|
+
- [Documentation](https://oss.vicente.services/dspy.rb/) — task-oriented guides and reference
|
|
63
|
+
- [Examples](examples/) — repository demos indexed by capability and prerequisites
|
|
64
|
+
- [llms.txt](https://oss.vicente.services/dspy.rb/llms.txt) — generated reference for AI assistants
|
|
212
65
|
|
|
213
|
-
|
|
66
|
+
Provider adapters, optimizers, observability exporters, datasets, and code-executing agents are separate packages when they add dependencies. Check the package matrix before selecting one; package availability does not guarantee uniform provider or model behavior.
|
|
214
67
|
|
|
215
68
|
## Contributing
|
|
216
69
|
|
|
217
|
-
|
|
70
|
+
For bugs, [open an issue](https://github.com/vicentereig/dspy.rb/issues). For suggestions, [start a discussion](https://github.com/vicentereig/dspy.rb/discussions).
|
|
218
71
|
|
|
219
72
|
Want to contribute code? Reach out: hey at vicente.services
|
|
220
73
|
|
data/lib/dspy/gemini/README.md
CHANGED
|
@@ -1,37 +1,52 @@
|
|
|
1
|
-
# DSPy Gemini
|
|
1
|
+
# DSPy Gemini Adapter
|
|
2
2
|
|
|
3
|
-
`dspy-gemini`
|
|
3
|
+
`dspy-gemini` lets `DSPy::LM` call model IDs with the `gemini/` prefix. The package is a supported provider adapter; model and SDK capabilities still vary.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- You call `DSPy::LM.new` with a provider of `gemini`.
|
|
7
|
-
- You want structured outputs, multimodal prompts, or streaming responses backed by Gemini's Generative Language API.
|
|
5
|
+
See the [package and capability matrix](https://oss.vicente.services/dspy.rb/getting-started/packages/) for canonical status and model/SDK boundaries.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
## Prerequisites
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
- Ruby 3.3 or newer and Bundler
|
|
10
|
+
- a Gemini API key
|
|
11
|
+
- a Gemini model ID available to your account
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
# Gemfile
|
|
16
|
-
gem 'dspy'
|
|
17
|
-
gem 'dspy-gemini'
|
|
18
|
-
```
|
|
13
|
+
## Install and Run
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
Add both gems to your `Gemfile`:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem "dspy"
|
|
19
|
+
gem "dspy-gemini"
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
Save this as `gemini_smoke.rb`:
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
```ruby
|
|
25
|
+
require "dspy"
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
lm = DSPy::LM.new(
|
|
28
|
+
ENV.fetch("GEMINI_MODEL"),
|
|
29
|
+
api_key: ENV.fetch("GEMINI_API_KEY")
|
|
30
|
+
)
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
response = lm.raw_chat([{ role: "user", content: "Reply with: adapter ready" }])
|
|
33
|
+
puts response.content
|
|
34
|
+
```
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
Then install and run it:
|
|
36
37
|
|
|
38
|
+
```bash
|
|
39
|
+
bundle install
|
|
40
|
+
export GEMINI_API_KEY="your-key"
|
|
41
|
+
export GEMINI_MODEL="gemini/your-model-id"
|
|
42
|
+
bundle exec ruby gemini_smoke.rb
|
|
37
43
|
```
|
|
44
|
+
|
|
45
|
+
The command prints the model response. Requiring `dspy` loads the installed adapter for a `gemini/` model; explicit `require "dspy/gemini"` is also supported.
|
|
46
|
+
|
|
47
|
+
## Failure Conditions
|
|
48
|
+
|
|
49
|
+
- A missing key raises from `ENV.fetch` before the request.
|
|
50
|
+
- A missing or incompatible `gemini-ai` dependency prevents the adapter from loading.
|
|
51
|
+
- An unavailable model, safety rejection, or invalid request raises an adapter/provider error.
|
|
52
|
+
- Schema, image, safety, and streaming behavior depend on the selected Gemini model and SDK/API version. Verify the exact request; installing the gem does not guarantee every capability.
|
|
@@ -5,9 +5,6 @@ require 'json'
|
|
|
5
5
|
require 'dspy/lm/vision_models'
|
|
6
6
|
require 'dspy/lm/adapter'
|
|
7
7
|
|
|
8
|
-
require 'dspy/gemini/guardrails'
|
|
9
|
-
DSPy::Gemini::Guardrails.ensure_gemini_installed!
|
|
10
|
-
|
|
11
8
|
module DSPy
|
|
12
9
|
module Gemini
|
|
13
10
|
module LM
|
|
@@ -52,7 +49,9 @@ module DSPy
|
|
|
52
49
|
# Validate vision support if images are present
|
|
53
50
|
if contains_images?(normalized_messages)
|
|
54
51
|
DSPy::LM::VisionModels.validate_vision_support!('gemini', model)
|
|
55
|
-
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if contains_media?(normalized_messages)
|
|
56
55
|
normalized_messages = format_multimodal_messages(normalized_messages, 'gemini')
|
|
57
56
|
end
|
|
58
57
|
|
|
@@ -45,8 +45,8 @@ module DSPy
|
|
|
45
45
|
# Get the output JSON schema from the signature class
|
|
46
46
|
output_schema = signature_class.output_json_schema
|
|
47
47
|
|
|
48
|
-
#
|
|
49
|
-
|
|
48
|
+
# response_json_schema accepts JSON Schema, including nullable type arrays.
|
|
49
|
+
convert_property_to_gemini(output_schema)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
sig { params(model: String).returns(T::Boolean) }
|
|
@@ -73,87 +73,34 @@ module DSPy
|
|
|
73
73
|
|
|
74
74
|
private
|
|
75
75
|
|
|
76
|
-
sig { params(dspy_schema: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
|
|
77
|
-
def self.convert_dspy_schema_to_gemini(dspy_schema)
|
|
78
|
-
# For Gemini's responseJsonSchema, we need pure JSON Schema format
|
|
79
|
-
# Remove OpenAPI-specific fields like "$schema"
|
|
80
|
-
result = {
|
|
81
|
-
type: "object",
|
|
82
|
-
properties: {},
|
|
83
|
-
required: []
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
# Convert properties
|
|
87
|
-
properties = dspy_schema[:properties] || {}
|
|
88
|
-
properties.each do |prop_name, prop_schema|
|
|
89
|
-
result[:properties][prop_name] = convert_property_to_gemini(prop_schema)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Set required fields
|
|
93
|
-
result[:required] = (dspy_schema[:required] || []).map(&:to_s)
|
|
94
|
-
|
|
95
|
-
result
|
|
96
|
-
end
|
|
97
|
-
|
|
98
76
|
sig { params(property_schema: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
|
|
99
77
|
def self.convert_property_to_gemini(property_schema)
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
oneOf: property_schema[:oneOf].map { |schema| convert_property_to_gemini(schema) },
|
|
104
|
-
description: property_schema[:description]
|
|
105
|
-
}.compact
|
|
106
|
-
end
|
|
78
|
+
# Preserve types and constraints instead of rebuilding nodes from scalar
|
|
79
|
+
# type names: Sorbet represents nilable fields as type: [type, "null"].
|
|
80
|
+
result = property_schema.reject { |key, _| key == :"$schema" || key == :const }
|
|
107
81
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
anyOf: property_schema[:anyOf].map { |schema| convert_property_to_gemini(schema) },
|
|
111
|
-
description: property_schema[:description]
|
|
112
|
-
}.compact
|
|
113
|
-
end
|
|
82
|
+
# Keep the existing const-to-enum conversion, including false/null values.
|
|
83
|
+
result[:enum] = [property_schema[:const]] if property_schema.key?(:const)
|
|
114
84
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
# Gemini responseJsonSchema doesn't support const, so convert to single-value enum
|
|
119
|
-
# See: https://ai.google.dev/api/generate-content#FIELDS.response_json_schema
|
|
120
|
-
if property_schema[:const]
|
|
121
|
-
result[:enum] = [property_schema[:const]]
|
|
122
|
-
elsif property_schema[:enum]
|
|
123
|
-
result[:enum] = property_schema[:enum]
|
|
85
|
+
[:properties, :"$defs", :definitions].each do |key|
|
|
86
|
+
if property_schema[key].is_a?(Hash)
|
|
87
|
+
result[key] = property_schema[key].transform_values { |schema| convert_property_to_gemini(schema) }
|
|
124
88
|
end
|
|
125
|
-
|
|
126
|
-
when "integer"
|
|
127
|
-
{ type: "integer" }
|
|
128
|
-
when "number"
|
|
129
|
-
{ type: "number" }
|
|
130
|
-
when "boolean"
|
|
131
|
-
{ type: "boolean" }
|
|
132
|
-
when "array"
|
|
133
|
-
{
|
|
134
|
-
type: "array",
|
|
135
|
-
items: convert_property_to_gemini(property_schema[:items] || { type: "string" })
|
|
136
|
-
}
|
|
137
|
-
when "object"
|
|
138
|
-
result = { type: "object" }
|
|
139
|
-
|
|
140
|
-
if property_schema[:properties]
|
|
141
|
-
result[:properties] = {}
|
|
142
|
-
property_schema[:properties].each do |nested_prop, nested_schema|
|
|
143
|
-
result[:properties][nested_prop] = convert_property_to_gemini(nested_schema)
|
|
144
|
-
end
|
|
89
|
+
end
|
|
145
90
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
end
|
|
91
|
+
[:items, :additionalProperties].each do |key|
|
|
92
|
+
if property_schema[key].is_a?(Hash)
|
|
93
|
+
result[key] = convert_property_to_gemini(property_schema[key])
|
|
150
94
|
end
|
|
95
|
+
end
|
|
151
96
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
97
|
+
[:oneOf, :anyOf, :allOf, :prefixItems].each do |key|
|
|
98
|
+
if property_schema[key].is_a?(Array)
|
|
99
|
+
result[key] = property_schema[key].map { |schema| convert_property_to_gemini(schema) }
|
|
100
|
+
end
|
|
156
101
|
end
|
|
102
|
+
|
|
103
|
+
result
|
|
157
104
|
end
|
|
158
105
|
|
|
159
106
|
sig { params(schema: T::Hash[Symbol, T.untyped], current_depth: Integer).returns(Integer) }
|
data/lib/dspy/gemini/version.rb
CHANGED
data/lib/dspy/gemini.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dspy-gemini
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vicente Reig Rincón de Arellano
|
|
@@ -15,28 +15,40 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 0.30.1
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '2.0'
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
25
|
requirements:
|
|
23
26
|
- - ">="
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
28
|
+
version: 0.30.1
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '2.0'
|
|
26
32
|
- !ruby/object:Gem::Dependency
|
|
27
33
|
name: gemini-ai
|
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
|
29
35
|
requirements:
|
|
30
36
|
- - ">="
|
|
31
37
|
- !ruby/object:Gem::Version
|
|
32
|
-
version:
|
|
38
|
+
version: 4.3.0
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '5.0'
|
|
33
42
|
type: :runtime
|
|
34
43
|
prerelease: false
|
|
35
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
45
|
requirements:
|
|
37
46
|
- - ">="
|
|
38
47
|
- !ruby/object:Gem::Version
|
|
39
|
-
version:
|
|
48
|
+
version: 4.3.0
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '5.0'
|
|
40
52
|
description: Provides the GeminiAdapter so Gemini-compatible providers can be added
|
|
41
53
|
to DSPy.rb projects independently of the core gem.
|
|
42
54
|
email:
|
|
@@ -49,7 +61,6 @@ files:
|
|
|
49
61
|
- README.md
|
|
50
62
|
- lib/dspy/gemini.rb
|
|
51
63
|
- lib/dspy/gemini/README.md
|
|
52
|
-
- lib/dspy/gemini/guardrails.rb
|
|
53
64
|
- lib/dspy/gemini/lm/adapters/gemini_adapter.rb
|
|
54
65
|
- lib/dspy/gemini/lm/schema_converter.rb
|
|
55
66
|
- lib/dspy/gemini/version.rb
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'dspy/lm/errors'
|
|
4
|
-
|
|
5
|
-
module DSPy
|
|
6
|
-
module Gemini
|
|
7
|
-
class Guardrails
|
|
8
|
-
SUPPORTED_GEMINI_VERSIONS = "~> 4.3".freeze
|
|
9
|
-
|
|
10
|
-
def self.ensure_gemini_installed!
|
|
11
|
-
require 'gemini-ai'
|
|
12
|
-
|
|
13
|
-
spec = Gem.loaded_specs["gemini-ai"]
|
|
14
|
-
unless spec && Gem::Requirement.new(SUPPORTED_GEMINI_VERSIONS).satisfied_by?(spec.version)
|
|
15
|
-
msg = <<~MSG
|
|
16
|
-
DSPY requires `gemini-ai` gem #{SUPPORTED_GEMINI_VERSIONS}.
|
|
17
|
-
Please Install or upgrade it with `bundle add gemini-ai --version "#{SUPPORTED_GEMINI_VERSIONS}"`.
|
|
18
|
-
MSG
|
|
19
|
-
raise DSPy::LM::UnsupportedVersionError, msg
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|