desiru 0.1.0 → 0.1.1
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/.env.example +34 -0
- data/.rubocop.yml +7 -4
- data/.ruby-version +1 -0
- data/CLAUDE.md +4 -0
- data/Gemfile +21 -2
- data/Gemfile.lock +87 -12
- data/README.md +295 -2
- data/Rakefile +1 -0
- data/db/migrations/001_create_initial_tables.rb +96 -0
- data/db/migrations/002_create_job_results.rb +39 -0
- data/desiru.db +0 -0
- data/desiru.gemspec +2 -5
- data/docs/background_processing_roadmap.md +87 -0
- data/docs/job_scheduling.md +167 -0
- data/dspy-analysis-swarm.yml +60 -0
- data/dspy-feature-analysis.md +121 -0
- data/examples/README.md +69 -0
- data/examples/api_with_persistence.rb +122 -0
- data/examples/assertions_example.rb +232 -0
- data/examples/async_processing.rb +2 -0
- data/examples/few_shot_learning.rb +1 -2
- data/examples/graphql_api.rb +4 -2
- data/examples/graphql_integration.rb +3 -3
- data/examples/graphql_optimization_summary.md +143 -0
- data/examples/graphql_performance_benchmark.rb +247 -0
- data/examples/persistence_example.rb +102 -0
- data/examples/react_agent.rb +203 -0
- data/examples/rest_api.rb +173 -0
- data/examples/rest_api_advanced.rb +333 -0
- data/examples/scheduled_job_example.rb +116 -0
- data/examples/simple_qa.rb +1 -2
- data/examples/sinatra_api.rb +109 -0
- data/examples/typed_signatures.rb +1 -2
- data/graphql_optimization_summary.md +53 -0
- data/lib/desiru/api/grape_integration.rb +284 -0
- data/lib/desiru/api/persistence_middleware.rb +148 -0
- data/lib/desiru/api/sinatra_integration.rb +217 -0
- data/lib/desiru/api.rb +42 -0
- data/lib/desiru/assertions.rb +74 -0
- data/lib/desiru/async_status.rb +65 -0
- data/lib/desiru/cache.rb +1 -1
- data/lib/desiru/configuration.rb +2 -1
- data/lib/desiru/errors.rb +160 -0
- data/lib/desiru/field.rb +17 -14
- data/lib/desiru/graphql/batch_loader.rb +85 -0
- data/lib/desiru/graphql/data_loader.rb +242 -75
- data/lib/desiru/graphql/enum_builder.rb +75 -0
- data/lib/desiru/graphql/executor.rb +37 -4
- data/lib/desiru/graphql/schema_generator.rb +62 -158
- data/lib/desiru/graphql/type_builder.rb +138 -0
- data/lib/desiru/graphql/type_cache_warmer.rb +91 -0
- data/lib/desiru/jobs/async_predict.rb +1 -1
- data/lib/desiru/jobs/base.rb +67 -0
- data/lib/desiru/jobs/batch_processor.rb +6 -6
- data/lib/desiru/jobs/retriable.rb +119 -0
- data/lib/desiru/jobs/retry_strategies.rb +169 -0
- data/lib/desiru/jobs/scheduler.rb +219 -0
- data/lib/desiru/jobs/webhook_notifier.rb +242 -0
- data/lib/desiru/models/anthropic.rb +164 -0
- data/lib/desiru/models/base.rb +37 -3
- data/lib/desiru/models/open_ai.rb +151 -0
- data/lib/desiru/models/open_router.rb +161 -0
- data/lib/desiru/module.rb +59 -9
- data/lib/desiru/modules/chain_of_thought.rb +3 -3
- data/lib/desiru/modules/majority.rb +51 -0
- data/lib/desiru/modules/multi_chain_comparison.rb +204 -0
- data/lib/desiru/modules/predict.rb +8 -1
- data/lib/desiru/modules/program_of_thought.rb +139 -0
- data/lib/desiru/modules/react.rb +273 -0
- data/lib/desiru/modules/retrieve.rb +4 -2
- data/lib/desiru/optimizers/base.rb +2 -4
- data/lib/desiru/optimizers/bootstrap_few_shot.rb +2 -2
- data/lib/desiru/optimizers/copro.rb +268 -0
- data/lib/desiru/optimizers/knn_few_shot.rb +185 -0
- data/lib/desiru/persistence/database.rb +71 -0
- data/lib/desiru/persistence/models/api_request.rb +38 -0
- data/lib/desiru/persistence/models/job_result.rb +138 -0
- data/lib/desiru/persistence/models/module_execution.rb +37 -0
- data/lib/desiru/persistence/models/optimization_result.rb +28 -0
- data/lib/desiru/persistence/models/training_example.rb +25 -0
- data/lib/desiru/persistence/models.rb +11 -0
- data/lib/desiru/persistence/repositories/api_request_repository.rb +98 -0
- data/lib/desiru/persistence/repositories/base_repository.rb +77 -0
- data/lib/desiru/persistence/repositories/job_result_repository.rb +116 -0
- data/lib/desiru/persistence/repositories/module_execution_repository.rb +85 -0
- data/lib/desiru/persistence/repositories/optimization_result_repository.rb +67 -0
- data/lib/desiru/persistence/repositories/training_example_repository.rb +102 -0
- data/lib/desiru/persistence/repository.rb +29 -0
- data/lib/desiru/persistence/setup.rb +77 -0
- data/lib/desiru/persistence.rb +49 -0
- data/lib/desiru/registry.rb +3 -5
- data/lib/desiru/signature.rb +91 -24
- data/lib/desiru/version.rb +1 -1
- data/lib/desiru.rb +23 -8
- data/missing-features-analysis.md +192 -0
- metadata +63 -45
- data/lib/desiru/models/raix_adapter.rb +0 -210
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: desiru
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Obie Fernandez
|
@@ -65,48 +65,6 @@ dependencies:
|
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
67
|
version: '0.1'
|
68
|
-
- !ruby/object:Gem::Dependency
|
69
|
-
name: bundler
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '2.0'
|
75
|
-
type: :development
|
76
|
-
prerelease: false
|
77
|
-
version_requirements: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - "~>"
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: '2.0'
|
82
|
-
- !ruby/object:Gem::Dependency
|
83
|
-
name: rake
|
84
|
-
requirement: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - "~>"
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: '13.0'
|
89
|
-
type: :development
|
90
|
-
prerelease: false
|
91
|
-
version_requirements: !ruby/object:Gem::Requirement
|
92
|
-
requirements:
|
93
|
-
- - "~>"
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '13.0'
|
96
|
-
- !ruby/object:Gem::Dependency
|
97
|
-
name: rspec
|
98
|
-
requirement: !ruby/object:Gem::Requirement
|
99
|
-
requirements:
|
100
|
-
- - "~>"
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: '3.0'
|
103
|
-
type: :development
|
104
|
-
prerelease: false
|
105
|
-
version_requirements: !ruby/object:Gem::Requirement
|
106
|
-
requirements:
|
107
|
-
- - "~>"
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '3.0'
|
110
68
|
description: Desiru brings DSPy's declarative programming paradigm for language models
|
111
69
|
to Ruby, enabling reliable, maintainable, and portable AI programming.
|
112
70
|
email:
|
@@ -115,47 +73,107 @@ executables: []
|
|
115
73
|
extensions: []
|
116
74
|
extra_rdoc_files: []
|
117
75
|
files:
|
76
|
+
- ".env.example"
|
118
77
|
- ".rspec"
|
119
78
|
- ".rubocop.yml"
|
79
|
+
- ".ruby-version"
|
120
80
|
- CLAUDE.md
|
121
81
|
- Gemfile
|
122
82
|
- Gemfile.lock
|
123
83
|
- LICENSE
|
124
84
|
- README.md
|
125
85
|
- Rakefile
|
86
|
+
- db/migrations/001_create_initial_tables.rb
|
87
|
+
- db/migrations/002_create_job_results.rb
|
88
|
+
- desiru.db
|
126
89
|
- desiru.gemspec
|
90
|
+
- docs/background_processing_roadmap.md
|
91
|
+
- docs/job_scheduling.md
|
92
|
+
- dspy-analysis-swarm.yml
|
93
|
+
- dspy-feature-analysis.md
|
127
94
|
- examples/README.md
|
95
|
+
- examples/api_with_persistence.rb
|
96
|
+
- examples/assertions_example.rb
|
128
97
|
- examples/async_processing.rb
|
129
98
|
- examples/few_shot_learning.rb
|
130
99
|
- examples/graphql_api.rb
|
131
100
|
- examples/graphql_integration.rb
|
101
|
+
- examples/graphql_optimization_summary.md
|
102
|
+
- examples/graphql_performance_benchmark.rb
|
103
|
+
- examples/persistence_example.rb
|
132
104
|
- examples/rag_retrieval.rb
|
105
|
+
- examples/react_agent.rb
|
106
|
+
- examples/rest_api.rb
|
107
|
+
- examples/rest_api_advanced.rb
|
108
|
+
- examples/scheduled_job_example.rb
|
133
109
|
- examples/simple_qa.rb
|
110
|
+
- examples/sinatra_api.rb
|
134
111
|
- examples/typed_signatures.rb
|
112
|
+
- graphql_optimization_summary.md
|
135
113
|
- lib/desiru.rb
|
114
|
+
- lib/desiru/api.rb
|
115
|
+
- lib/desiru/api/grape_integration.rb
|
116
|
+
- lib/desiru/api/persistence_middleware.rb
|
117
|
+
- lib/desiru/api/sinatra_integration.rb
|
118
|
+
- lib/desiru/assertions.rb
|
136
119
|
- lib/desiru/async_capable.rb
|
120
|
+
- lib/desiru/async_status.rb
|
137
121
|
- lib/desiru/cache.rb
|
138
122
|
- lib/desiru/configuration.rb
|
123
|
+
- lib/desiru/errors.rb
|
139
124
|
- lib/desiru/field.rb
|
125
|
+
- lib/desiru/graphql/batch_loader.rb
|
140
126
|
- lib/desiru/graphql/data_loader.rb
|
127
|
+
- lib/desiru/graphql/enum_builder.rb
|
141
128
|
- lib/desiru/graphql/executor.rb
|
142
129
|
- lib/desiru/graphql/schema_generator.rb
|
130
|
+
- lib/desiru/graphql/type_builder.rb
|
131
|
+
- lib/desiru/graphql/type_cache_warmer.rb
|
143
132
|
- lib/desiru/jobs/async_predict.rb
|
144
133
|
- lib/desiru/jobs/base.rb
|
145
134
|
- lib/desiru/jobs/batch_processor.rb
|
146
135
|
- lib/desiru/jobs/optimizer_job.rb
|
136
|
+
- lib/desiru/jobs/retriable.rb
|
137
|
+
- lib/desiru/jobs/retry_strategies.rb
|
138
|
+
- lib/desiru/jobs/scheduler.rb
|
139
|
+
- lib/desiru/jobs/webhook_notifier.rb
|
140
|
+
- lib/desiru/models/anthropic.rb
|
147
141
|
- lib/desiru/models/base.rb
|
148
|
-
- lib/desiru/models/
|
142
|
+
- lib/desiru/models/open_ai.rb
|
143
|
+
- lib/desiru/models/open_router.rb
|
149
144
|
- lib/desiru/module.rb
|
150
145
|
- lib/desiru/modules/chain_of_thought.rb
|
146
|
+
- lib/desiru/modules/majority.rb
|
147
|
+
- lib/desiru/modules/multi_chain_comparison.rb
|
151
148
|
- lib/desiru/modules/predict.rb
|
149
|
+
- lib/desiru/modules/program_of_thought.rb
|
150
|
+
- lib/desiru/modules/react.rb
|
152
151
|
- lib/desiru/modules/retrieve.rb
|
153
152
|
- lib/desiru/optimizers/base.rb
|
154
153
|
- lib/desiru/optimizers/bootstrap_few_shot.rb
|
154
|
+
- lib/desiru/optimizers/copro.rb
|
155
|
+
- lib/desiru/optimizers/knn_few_shot.rb
|
156
|
+
- lib/desiru/persistence.rb
|
157
|
+
- lib/desiru/persistence/database.rb
|
158
|
+
- lib/desiru/persistence/models.rb
|
159
|
+
- lib/desiru/persistence/models/api_request.rb
|
160
|
+
- lib/desiru/persistence/models/job_result.rb
|
161
|
+
- lib/desiru/persistence/models/module_execution.rb
|
162
|
+
- lib/desiru/persistence/models/optimization_result.rb
|
163
|
+
- lib/desiru/persistence/models/training_example.rb
|
164
|
+
- lib/desiru/persistence/repositories/api_request_repository.rb
|
165
|
+
- lib/desiru/persistence/repositories/base_repository.rb
|
166
|
+
- lib/desiru/persistence/repositories/job_result_repository.rb
|
167
|
+
- lib/desiru/persistence/repositories/module_execution_repository.rb
|
168
|
+
- lib/desiru/persistence/repositories/optimization_result_repository.rb
|
169
|
+
- lib/desiru/persistence/repositories/training_example_repository.rb
|
170
|
+
- lib/desiru/persistence/repository.rb
|
171
|
+
- lib/desiru/persistence/setup.rb
|
155
172
|
- lib/desiru/program.rb
|
156
173
|
- lib/desiru/registry.rb
|
157
174
|
- lib/desiru/signature.rb
|
158
175
|
- lib/desiru/version.rb
|
176
|
+
- missing-features-analysis.md
|
159
177
|
homepage: https://github.com/obie/desiru
|
160
178
|
licenses:
|
161
179
|
- MIT
|
@@ -171,7 +189,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
171
189
|
requirements:
|
172
190
|
- - ">="
|
173
191
|
- !ruby/object:Gem::Version
|
174
|
-
version: 3.
|
192
|
+
version: 3.3.0
|
175
193
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
194
|
requirements:
|
177
195
|
- - ">="
|
@@ -1,210 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'raix'
|
4
|
-
require 'faraday'
|
5
|
-
require 'faraday/retry'
|
6
|
-
require 'openai'
|
7
|
-
|
8
|
-
module Desiru
|
9
|
-
module Models
|
10
|
-
# Adapter for Raix gem integration
|
11
|
-
# Provides unified interface to OpenAI, Anthropic, and OpenRouter via Raix
|
12
|
-
# Uses modern Raix patterns with direct OpenAI::Client configuration
|
13
|
-
class RaixAdapter < Base
|
14
|
-
def initialize(api_key: nil, provider: :openai, uri_base: nil, **config)
|
15
|
-
@api_key = api_key || fetch_api_key(provider)
|
16
|
-
@provider = provider
|
17
|
-
@uri_base = uri_base || fetch_uri_base(provider)
|
18
|
-
|
19
|
-
super(config)
|
20
|
-
configure_raix!
|
21
|
-
end
|
22
|
-
|
23
|
-
def complete(prompt, **options)
|
24
|
-
opts = build_completion_options(prompt, options)
|
25
|
-
|
26
|
-
response = with_retry do
|
27
|
-
client.completions.create(**opts)
|
28
|
-
end
|
29
|
-
|
30
|
-
process_response(response)
|
31
|
-
end
|
32
|
-
|
33
|
-
def stream_complete(prompt, **options)
|
34
|
-
opts = build_completion_options(prompt, options).merge(stream: true)
|
35
|
-
|
36
|
-
with_retry do
|
37
|
-
client.completions.create(**opts) do |chunk|
|
38
|
-
yield process_stream_chunk(chunk)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def models
|
44
|
-
case provider
|
45
|
-
when :openai
|
46
|
-
%w[gpt-4-turbo gpt-4 gpt-3.5-turbo gpt-4o gpt-4o-mini]
|
47
|
-
when :anthropic
|
48
|
-
%w[claude-3-opus-20240229 claude-3-sonnet-20240229 claude-3-haiku-20240307]
|
49
|
-
when :openrouter
|
50
|
-
# OpenRouter supports many models with provider prefixes
|
51
|
-
%w[anthropic/claude-3-opus openai/gpt-4-turbo google/gemini-pro meta-llama/llama-3-70b]
|
52
|
-
else
|
53
|
-
[]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
protected
|
58
|
-
|
59
|
-
def default_config
|
60
|
-
super.merge(
|
61
|
-
model: 'gpt-4-turbo-preview',
|
62
|
-
response_format: nil,
|
63
|
-
tools: nil,
|
64
|
-
tool_choice: nil
|
65
|
-
)
|
66
|
-
end
|
67
|
-
|
68
|
-
def build_client
|
69
|
-
# Modern Raix uses direct configuration, not separate client instances
|
70
|
-
# The client is accessed through Raix after configuration
|
71
|
-
::Raix
|
72
|
-
end
|
73
|
-
|
74
|
-
def configure_raix!
|
75
|
-
::Raix.configure do |raix_config|
|
76
|
-
raix_config.openai_client = build_openai_client
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def build_openai_client
|
81
|
-
::OpenAI::Client.new(
|
82
|
-
access_token: @api_key,
|
83
|
-
uri_base: @uri_base
|
84
|
-
) do |f|
|
85
|
-
# Add retry middleware
|
86
|
-
f.request(:retry, {
|
87
|
-
max: config[:max_retries] || 3,
|
88
|
-
interval: 0.05,
|
89
|
-
interval_randomness: 0.5,
|
90
|
-
backoff_factor: 2
|
91
|
-
})
|
92
|
-
|
93
|
-
# Add logging in debug mode
|
94
|
-
if ENV['DEBUG'] || config[:debug]
|
95
|
-
f.response(:logger, config[:logger] || Logger.new($stdout), {
|
96
|
-
headers: false,
|
97
|
-
bodies: true,
|
98
|
-
errors: true
|
99
|
-
}) do |logger|
|
100
|
-
logger.filter(/(Bearer) (\S+)/, '\1[REDACTED]')
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def fetch_api_key(provider)
|
107
|
-
case provider
|
108
|
-
when :openai
|
109
|
-
ENV.fetch('OPENAI_API_KEY', nil)
|
110
|
-
when :anthropic
|
111
|
-
ENV.fetch('ANTHROPIC_API_KEY', nil)
|
112
|
-
when :openrouter
|
113
|
-
ENV.fetch('OPENROUTER_API_KEY', nil)
|
114
|
-
else
|
115
|
-
ENV.fetch("#{provider.to_s.upcase}_API_KEY", nil)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def fetch_uri_base(provider)
|
120
|
-
case provider
|
121
|
-
when :openai
|
122
|
-
ENV['OPENAI_API_BASE'] || 'https://api.openai.com/v1'
|
123
|
-
when :anthropic
|
124
|
-
ENV['ANTHROPIC_API_BASE'] || 'https://api.anthropic.com/v1'
|
125
|
-
when :openrouter
|
126
|
-
ENV['OPENROUTER_API_BASE'] || 'https://openrouter.ai/api/v1'
|
127
|
-
else
|
128
|
-
ENV.fetch("#{provider.to_s.upcase}_API_BASE", nil)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def validate_config!
|
133
|
-
raise ConfigurationError, 'API key is required' if @api_key.nil? || @api_key.empty?
|
134
|
-
raise ConfigurationError, 'Model must be specified' if config[:model].nil?
|
135
|
-
end
|
136
|
-
|
137
|
-
private
|
138
|
-
|
139
|
-
attr_reader :provider
|
140
|
-
|
141
|
-
def build_completion_options(prompt, options)
|
142
|
-
messages = build_messages(prompt, options[:demos] || [])
|
143
|
-
|
144
|
-
{
|
145
|
-
model: options[:model] || config[:model],
|
146
|
-
messages: messages,
|
147
|
-
temperature: options[:temperature] || config[:temperature],
|
148
|
-
max_tokens: options[:max_tokens] || config[:max_tokens],
|
149
|
-
response_format: options[:response_format] || config[:response_format],
|
150
|
-
tools: options[:tools] || config[:tools],
|
151
|
-
tool_choice: options[:tool_choice] || config[:tool_choice]
|
152
|
-
}.compact
|
153
|
-
end
|
154
|
-
|
155
|
-
def build_messages(prompt, demos)
|
156
|
-
messages = []
|
157
|
-
|
158
|
-
# Add system message if provided
|
159
|
-
messages << { role: 'system', content: prompt[:system] } if prompt[:system]
|
160
|
-
|
161
|
-
# Add demonstrations
|
162
|
-
demos.each do |demo|
|
163
|
-
messages << { role: 'user', content: demo[:input] }
|
164
|
-
messages << { role: 'assistant', content: demo[:output] }
|
165
|
-
end
|
166
|
-
|
167
|
-
# Add current prompt
|
168
|
-
messages << { role: 'user', content: prompt[:user] || prompt[:content] || prompt }
|
169
|
-
|
170
|
-
messages
|
171
|
-
end
|
172
|
-
|
173
|
-
def process_response(response)
|
174
|
-
content = response.dig('choices', 0, 'message', 'content')
|
175
|
-
usage = response['usage']
|
176
|
-
|
177
|
-
increment_stats(usage['total_tokens']) if usage
|
178
|
-
|
179
|
-
{
|
180
|
-
content: content,
|
181
|
-
raw: response,
|
182
|
-
model: response['model'],
|
183
|
-
usage: usage
|
184
|
-
}
|
185
|
-
end
|
186
|
-
|
187
|
-
def process_stream_chunk(chunk)
|
188
|
-
content = chunk.dig('choices', 0, 'delta', 'content')
|
189
|
-
|
190
|
-
{
|
191
|
-
content: content,
|
192
|
-
finished: chunk.dig('choices', 0, 'finish_reason').present?
|
193
|
-
}
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
# Convenience classes for specific providers
|
198
|
-
class OpenAI < RaixAdapter
|
199
|
-
def initialize(api_key: nil, **config)
|
200
|
-
super(api_key: api_key, provider: :openai, **config)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
class OpenRouter < RaixAdapter
|
205
|
-
def initialize(api_key: nil, **config)
|
206
|
-
super(api_key: api_key, provider: :openrouter, **config)
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|