@every-env/compound-plugin 0.2.0 → 0.5.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/deploy-docs.yml +3 -3
- package/.github/workflows/publish.yml +37 -0
- package/README.md +12 -3
- package/docs/index.html +13 -13
- package/docs/pages/changelog.html +39 -0
- package/docs/plans/2026-02-08-feat-convert-local-md-settings-for-opencode-codex-plan.md +143 -0
- package/docs/plans/2026-02-08-feat-simplify-plugin-settings-plan.md +195 -0
- package/docs/plans/2026-02-08-refactor-reduce-plugin-context-token-usage-plan.md +212 -0
- package/docs/plans/2026-02-09-refactor-dspy-ruby-skill-update-plan.md +104 -0
- package/docs/plans/2026-02-12-feat-add-cursor-cli-target-provider-plan.md +306 -0
- package/docs/specs/cursor.md +85 -0
- package/package.json +1 -1
- package/plugins/compound-engineering/.claude-plugin/plugin.json +2 -2
- package/plugins/compound-engineering/CHANGELOG.md +64 -0
- package/plugins/compound-engineering/README.md +5 -3
- package/plugins/compound-engineering/agents/design/design-implementation-reviewer.md +16 -1
- package/plugins/compound-engineering/agents/design/design-iterator.md +28 -1
- package/plugins/compound-engineering/agents/design/figma-design-sync.md +19 -1
- package/plugins/compound-engineering/agents/docs/ankane-readme-writer.md +16 -1
- package/plugins/compound-engineering/agents/research/best-practices-researcher.md +16 -1
- package/plugins/compound-engineering/agents/research/framework-docs-researcher.md +16 -1
- package/plugins/compound-engineering/agents/research/git-history-analyzer.md +16 -1
- package/plugins/compound-engineering/agents/research/learnings-researcher.md +22 -1
- package/plugins/compound-engineering/agents/research/repo-research-analyst.md +22 -1
- package/plugins/compound-engineering/agents/review/agent-native-reviewer.md +16 -1
- package/plugins/compound-engineering/agents/review/architecture-strategist.md +16 -1
- package/plugins/compound-engineering/agents/review/code-simplicity-reviewer.md +16 -1
- package/plugins/compound-engineering/agents/review/data-integrity-guardian.md +16 -1
- package/plugins/compound-engineering/agents/review/data-migration-expert.md +16 -1
- package/plugins/compound-engineering/agents/review/deployment-verification-agent.md +16 -1
- package/plugins/compound-engineering/agents/review/dhh-rails-reviewer.md +22 -1
- package/plugins/compound-engineering/agents/review/julik-frontend-races-reviewer.md +20 -21
- package/plugins/compound-engineering/agents/review/kieran-python-reviewer.md +30 -1
- package/plugins/compound-engineering/agents/review/kieran-rails-reviewer.md +30 -1
- package/plugins/compound-engineering/agents/review/kieran-typescript-reviewer.md +30 -1
- package/plugins/compound-engineering/agents/review/pattern-recognition-specialist.md +16 -1
- package/plugins/compound-engineering/agents/review/performance-oracle.md +28 -1
- package/plugins/compound-engineering/agents/review/schema-drift-detector.md +16 -1
- package/plugins/compound-engineering/agents/review/security-sentinel.md +22 -1
- package/plugins/compound-engineering/agents/workflow/bug-reproduction-validator.md +16 -1
- package/plugins/compound-engineering/agents/workflow/every-style-editor.md +1 -1
- package/plugins/compound-engineering/agents/workflow/pr-comment-resolver.md +16 -1
- package/plugins/compound-engineering/agents/workflow/spec-flow-analyzer.md +22 -1
- package/plugins/compound-engineering/commands/agent-native-audit.md +1 -0
- package/plugins/compound-engineering/commands/changelog.md +1 -0
- package/plugins/compound-engineering/commands/create-agent-skill.md +1 -0
- package/plugins/compound-engineering/commands/deploy-docs.md +1 -0
- package/plugins/compound-engineering/commands/generate_command.md +1 -0
- package/plugins/compound-engineering/commands/heal-skill.md +1 -0
- package/plugins/compound-engineering/commands/lfg.md +1 -0
- package/plugins/compound-engineering/commands/report-bug.md +1 -0
- package/plugins/compound-engineering/commands/reproduce-bug.md +1 -0
- package/plugins/compound-engineering/commands/resolve_parallel.md +1 -0
- package/plugins/compound-engineering/commands/slfg.md +1 -0
- package/plugins/compound-engineering/commands/{xcode-test.md → test-xcode.md} +2 -1
- package/plugins/compound-engineering/commands/triage.md +1 -0
- package/plugins/compound-engineering/commands/workflows/brainstorm.md +6 -1
- package/plugins/compound-engineering/commands/workflows/compound.md +1 -0
- package/plugins/compound-engineering/commands/workflows/review.md +23 -21
- package/plugins/compound-engineering/commands/workflows/work.md +29 -15
- package/plugins/compound-engineering/skills/compound-docs/SKILL.md +1 -0
- package/plugins/compound-engineering/skills/dspy-ruby/SKILL.md +539 -396
- package/plugins/compound-engineering/skills/dspy-ruby/assets/config-template.rb +159 -331
- package/plugins/compound-engineering/skills/dspy-ruby/assets/module-template.rb +210 -236
- package/plugins/compound-engineering/skills/dspy-ruby/assets/signature-template.rb +173 -95
- package/plugins/compound-engineering/skills/dspy-ruby/references/core-concepts.md +552 -143
- package/plugins/compound-engineering/skills/dspy-ruby/references/observability.md +366 -0
- package/plugins/compound-engineering/skills/dspy-ruby/references/optimization.md +440 -460
- package/plugins/compound-engineering/skills/dspy-ruby/references/providers.md +305 -225
- package/plugins/compound-engineering/skills/dspy-ruby/references/toolsets.md +502 -0
- package/plugins/compound-engineering/skills/file-todos/SKILL.md +1 -0
- package/plugins/compound-engineering/skills/orchestrating-swarms/SKILL.md +1 -0
- package/plugins/compound-engineering/skills/setup/SKILL.md +168 -0
- package/plugins/compound-engineering/skills/skill-creator/SKILL.md +1 -0
- package/src/commands/convert.ts +10 -5
- package/src/commands/install.ts +10 -5
- package/src/converters/claude-to-codex.ts +9 -3
- package/src/converters/claude-to-cursor.ts +166 -0
- package/src/converters/claude-to-droid.ts +174 -0
- package/src/converters/claude-to-opencode.ts +9 -2
- package/src/parsers/claude.ts +4 -0
- package/src/targets/cursor.ts +48 -0
- package/src/targets/droid.ts +50 -0
- package/src/targets/index.ts +18 -0
- package/src/types/claude.ts +2 -0
- package/src/types/cursor.ts +29 -0
- package/src/types/droid.ts +20 -0
- package/tests/claude-parser.test.ts +24 -2
- package/tests/codex-converter.test.ts +100 -0
- package/tests/converter.test.ts +76 -0
- package/tests/cursor-converter.test.ts +347 -0
- package/tests/cursor-writer.test.ts +137 -0
- package/tests/droid-converter.test.ts +277 -0
- package/tests/droid-writer.test.ts +100 -0
- package/tests/fixtures/sample-plugin/commands/disabled-command.md +7 -0
- package/tests/fixtures/sample-plugin/skills/disabled-skill/SKILL.md +7 -0
- package/plugins/compound-engineering/commands/technical_review.md +0 -7
- /package/{plugins/compound-engineering → .claude}/commands/release-docs.md +0 -0
|
@@ -1,359 +1,187 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
if Rails.env.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
DSPy.configure do |c|
|
|
60
|
-
c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
61
|
-
api_key: ENV['OPENAI_API_KEY'])
|
|
62
|
-
end
|
|
63
|
-
else
|
|
64
|
-
# Use powerful model for production
|
|
65
|
-
DSPy.configure do |c|
|
|
66
|
-
c.lm = DSPy::LM.new('anthropic/claude-3-5-sonnet-20241022',
|
|
67
|
-
api_key: ENV['ANTHROPIC_API_KEY'])
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# ============================================================================
|
|
72
|
-
# Configuration with Custom Parameters
|
|
73
|
-
# ============================================================================
|
|
74
|
-
|
|
75
|
-
DSPy.configure do |c|
|
|
76
|
-
c.lm = DSPy::LM.new('openai/gpt-4o',
|
|
77
|
-
api_key: ENV['OPENAI_API_KEY'],
|
|
78
|
-
temperature: 0.7, # Creativity (0.0-2.0, default: 1.0)
|
|
79
|
-
max_tokens: 2000, # Maximum response length
|
|
80
|
-
top_p: 0.9, # Nucleus sampling
|
|
81
|
-
frequency_penalty: 0.0, # Reduce repetition (-2.0 to 2.0)
|
|
82
|
-
presence_penalty: 0.0 # Encourage new topics (-2.0 to 2.0)
|
|
83
|
-
)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# ============================================================================
|
|
87
|
-
# Multiple Model Configuration (Task-Specific)
|
|
88
|
-
# ============================================================================
|
|
89
|
-
|
|
90
|
-
# Create different language models for different tasks
|
|
91
|
-
module MyApp
|
|
92
|
-
# Fast model for simple tasks
|
|
93
|
-
FAST_LM = DSPy::LM.new('openai/gpt-4o-mini',
|
|
94
|
-
api_key: ENV['OPENAI_API_KEY'],
|
|
95
|
-
temperature: 0.3 # More deterministic
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
# Powerful model for complex tasks
|
|
99
|
-
POWERFUL_LM = DSPy::LM.new('anthropic/claude-3-5-sonnet-20241022',
|
|
100
|
-
api_key: ENV['ANTHROPIC_API_KEY'],
|
|
101
|
-
temperature: 0.7
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
# Creative model for content generation
|
|
105
|
-
CREATIVE_LM = DSPy::LM.new('openai/gpt-4o',
|
|
106
|
-
api_key: ENV['OPENAI_API_KEY'],
|
|
107
|
-
temperature: 1.2, # More creative
|
|
108
|
-
top_p: 0.95
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
# Vision-capable model
|
|
112
|
-
VISION_LM = DSPy::LM.new('openai/gpt-4o',
|
|
113
|
-
api_key: ENV['OPENAI_API_KEY'])
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# Use in modules
|
|
117
|
-
class SimpleClassifier < DSPy::Module
|
|
118
|
-
def initialize
|
|
119
|
-
super
|
|
120
|
-
DSPy.configure { |c| c.lm = MyApp::FAST_LM }
|
|
121
|
-
@predictor = DSPy::Predict.new(SimpleSignature)
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
class ComplexAnalyzer < DSPy::Module
|
|
126
|
-
def initialize
|
|
127
|
-
super
|
|
128
|
-
DSPy.configure { |c| c.lm = MyApp::POWERFUL_LM }
|
|
129
|
-
@predictor = DSPy::ChainOfThought.new(ComplexSignature)
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# ============================================================================
|
|
134
|
-
# Configuration with Observability (OpenTelemetry)
|
|
135
|
-
# ============================================================================
|
|
136
|
-
|
|
137
|
-
require 'opentelemetry/sdk'
|
|
138
|
-
|
|
139
|
-
# Configure OpenTelemetry
|
|
140
|
-
OpenTelemetry::SDK.configure do |c|
|
|
141
|
-
c.service_name = 'my-dspy-app'
|
|
142
|
-
c.use_all
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# Configure DSPy (automatically integrates with OpenTelemetry)
|
|
146
|
-
DSPy.configure do |c|
|
|
147
|
-
c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
148
|
-
api_key: ENV['OPENAI_API_KEY'])
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
# ============================================================================
|
|
152
|
-
# Configuration with Langfuse Tracing
|
|
153
|
-
# ============================================================================
|
|
154
|
-
|
|
155
|
-
require 'dspy/langfuse'
|
|
156
|
-
|
|
157
|
-
DSPy.configure do |c|
|
|
158
|
-
c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
159
|
-
api_key: ENV['OPENAI_API_KEY'])
|
|
160
|
-
|
|
161
|
-
# Enable Langfuse tracing
|
|
162
|
-
c.langfuse = {
|
|
163
|
-
public_key: ENV['LANGFUSE_PUBLIC_KEY'],
|
|
164
|
-
secret_key: ENV['LANGFUSE_SECRET_KEY'],
|
|
165
|
-
host: ENV['LANGFUSE_HOST'] || 'https://cloud.langfuse.com'
|
|
166
|
-
}
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# ============================================================================
|
|
170
|
-
# Configuration with Retry Logic
|
|
171
|
-
# ============================================================================
|
|
172
|
-
|
|
173
|
-
class RetryableConfig
|
|
174
|
-
MAX_RETRIES = 3
|
|
175
|
-
|
|
176
|
-
def self.configure
|
|
177
|
-
DSPy.configure do |c|
|
|
178
|
-
c.lm = create_lm_with_retry
|
|
179
|
-
end
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# DSPy.rb Configuration Template — v0.34.3 API
|
|
5
|
+
#
|
|
6
|
+
# Rails initializer patterns for DSPy.rb with RubyLLM, observability,
|
|
7
|
+
# and feature-flagged model selection.
|
|
8
|
+
#
|
|
9
|
+
# Key patterns:
|
|
10
|
+
# - Use after_initialize for Rails setup
|
|
11
|
+
# - Use dspy-ruby_llm for multi-provider routing
|
|
12
|
+
# - Use structured_outputs: true for reliable parsing
|
|
13
|
+
# - Use dspy-o11y + dspy-o11y-langfuse for observability
|
|
14
|
+
# - Use ENV-based feature flags for model selection
|
|
15
|
+
# =============================================================================
|
|
16
|
+
|
|
17
|
+
# =============================================================================
|
|
18
|
+
# Gemfile Dependencies
|
|
19
|
+
# =============================================================================
|
|
20
|
+
#
|
|
21
|
+
# # Core
|
|
22
|
+
# gem 'dspy'
|
|
23
|
+
#
|
|
24
|
+
# # Provider adapter (choose one strategy):
|
|
25
|
+
#
|
|
26
|
+
# # Strategy A: Unified adapter via RubyLLM (recommended)
|
|
27
|
+
# gem 'dspy-ruby_llm'
|
|
28
|
+
# gem 'ruby_llm'
|
|
29
|
+
#
|
|
30
|
+
# # Strategy B: Per-provider adapters (direct SDK access)
|
|
31
|
+
# gem 'dspy-openai' # OpenAI, OpenRouter, Ollama
|
|
32
|
+
# gem 'dspy-anthropic' # Claude
|
|
33
|
+
# gem 'dspy-gemini' # Gemini
|
|
34
|
+
#
|
|
35
|
+
# # Observability (optional)
|
|
36
|
+
# gem 'dspy-o11y'
|
|
37
|
+
# gem 'dspy-o11y-langfuse'
|
|
38
|
+
#
|
|
39
|
+
# # Optimization (optional)
|
|
40
|
+
# gem 'dspy-miprov2' # MIPROv2 optimizer
|
|
41
|
+
# gem 'dspy-gepa' # GEPA optimizer
|
|
42
|
+
#
|
|
43
|
+
# # Schema formats (optional)
|
|
44
|
+
# gem 'sorbet-baml' # BAML schema format (84% token reduction)
|
|
45
|
+
|
|
46
|
+
# =============================================================================
|
|
47
|
+
# Rails Initializer — config/initializers/dspy.rb
|
|
48
|
+
# =============================================================================
|
|
49
|
+
|
|
50
|
+
Rails.application.config.after_initialize do
|
|
51
|
+
# Skip in test unless explicitly enabled
|
|
52
|
+
next if Rails.env.test? && ENV["DSPY_ENABLE_IN_TEST"].blank?
|
|
53
|
+
|
|
54
|
+
# Configure RubyLLM provider credentials
|
|
55
|
+
RubyLLM.configure do |config|
|
|
56
|
+
config.gemini_api_key = ENV["GEMINI_API_KEY"] if ENV["GEMINI_API_KEY"].present?
|
|
57
|
+
config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"] if ENV["ANTHROPIC_API_KEY"].present?
|
|
58
|
+
config.openai_api_key = ENV["OPENAI_API_KEY"] if ENV["OPENAI_API_KEY"].present?
|
|
180
59
|
end
|
|
181
60
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
lm.extend(RetryBehavior)
|
|
188
|
-
lm
|
|
61
|
+
# Configure DSPy with unified RubyLLM adapter
|
|
62
|
+
model = ENV.fetch("DSPY_MODEL", "ruby_llm/gemini-2.5-flash")
|
|
63
|
+
DSPy.configure do |config|
|
|
64
|
+
config.lm = DSPy::LM.new(model, structured_outputs: true)
|
|
65
|
+
config.logger = Rails.logger
|
|
189
66
|
end
|
|
190
67
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
rescue RateLimitError, TimeoutError => e
|
|
195
|
-
if retry_count < MAX_RETRIES
|
|
196
|
-
sleep(2 ** retry_count) # Exponential backoff
|
|
197
|
-
forward(input, retry_count: retry_count + 1)
|
|
198
|
-
else
|
|
199
|
-
raise
|
|
200
|
-
end
|
|
201
|
-
end
|
|
68
|
+
# Enable Langfuse observability (optional)
|
|
69
|
+
if ENV["LANGFUSE_PUBLIC_KEY"].present? && ENV["LANGFUSE_SECRET_KEY"].present?
|
|
70
|
+
DSPy::Observability.configure!
|
|
202
71
|
end
|
|
203
72
|
end
|
|
204
73
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
#
|
|
208
|
-
# Configuration with Fallback Models
|
|
209
|
-
# ============================================================================
|
|
210
|
-
|
|
211
|
-
class FallbackConfig
|
|
212
|
-
def self.configure
|
|
213
|
-
DSPy.configure do |c|
|
|
214
|
-
c.lm = create_lm_with_fallback
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def self.create_lm_with_fallback
|
|
219
|
-
primary = DSPy::LM.new('anthropic/claude-3-5-sonnet-20241022',
|
|
220
|
-
api_key: ENV['ANTHROPIC_API_KEY'])
|
|
221
|
-
|
|
222
|
-
fallback = DSPy::LM.new('openai/gpt-4o',
|
|
223
|
-
api_key: ENV['OPENAI_API_KEY'])
|
|
224
|
-
|
|
225
|
-
FallbackLM.new(primary, fallback)
|
|
226
|
-
end
|
|
74
|
+
# =============================================================================
|
|
75
|
+
# Feature Flags — config/initializers/feature_flags.rb
|
|
76
|
+
# =============================================================================
|
|
227
77
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
@fallback = fallback
|
|
232
|
-
end
|
|
78
|
+
# Use different models for different roles:
|
|
79
|
+
# - Fast/cheap for classification, routing, simple tasks
|
|
80
|
+
# - Powerful for synthesis, reasoning, complex analysis
|
|
233
81
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
@fallback.forward(input)
|
|
239
|
-
end
|
|
240
|
-
end
|
|
82
|
+
module FeatureFlags
|
|
83
|
+
SELECTOR_MODEL = ENV.fetch("DSPY_SELECTOR_MODEL", "ruby_llm/gemini-2.5-flash-lite")
|
|
84
|
+
SYNTHESIZER_MODEL = ENV.fetch("DSPY_SYNTHESIZER_MODEL", "ruby_llm/gemini-2.5-flash")
|
|
85
|
+
REASONING_MODEL = ENV.fetch("DSPY_REASONING_MODEL", "ruby_llm/claude-sonnet-4-20250514")
|
|
241
86
|
end
|
|
242
87
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
#
|
|
246
|
-
#
|
|
247
|
-
#
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
c.lm = BudgetTracker.new(
|
|
253
|
-
DSPy::LM.new('openai/gpt-4o',
|
|
254
|
-
api_key: ENV['OPENAI_API_KEY']),
|
|
255
|
-
monthly_budget_usd: monthly_budget_usd
|
|
256
|
-
)
|
|
257
|
-
end
|
|
258
|
-
end
|
|
88
|
+
# Usage in tools/modules:
|
|
89
|
+
#
|
|
90
|
+
# class ClassifyTool < DSPy::Tools::Base
|
|
91
|
+
# def call(query:)
|
|
92
|
+
# predictor = DSPy::Predict.new(ClassifySignature)
|
|
93
|
+
# predictor.configure { |c| c.lm = DSPy::LM.new(FeatureFlags::SELECTOR_MODEL, structured_outputs: true) }
|
|
94
|
+
# predictor.call(query: query)
|
|
95
|
+
# end
|
|
96
|
+
# end
|
|
259
97
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
98
|
+
# =============================================================================
|
|
99
|
+
# Environment Variables — .env
|
|
100
|
+
# =============================================================================
|
|
101
|
+
#
|
|
102
|
+
# # Provider API keys (set the ones you need)
|
|
103
|
+
# GEMINI_API_KEY=...
|
|
104
|
+
# ANTHROPIC_API_KEY=...
|
|
105
|
+
# OPENAI_API_KEY=...
|
|
106
|
+
#
|
|
107
|
+
# # DSPy model configuration
|
|
108
|
+
# DSPY_MODEL=ruby_llm/gemini-2.5-flash
|
|
109
|
+
# DSPY_SELECTOR_MODEL=ruby_llm/gemini-2.5-flash-lite
|
|
110
|
+
# DSPY_SYNTHESIZER_MODEL=ruby_llm/gemini-2.5-flash
|
|
111
|
+
# DSPY_REASONING_MODEL=ruby_llm/claude-sonnet-4-20250514
|
|
112
|
+
#
|
|
113
|
+
# # Langfuse observability (optional)
|
|
114
|
+
# LANGFUSE_PUBLIC_KEY=pk-...
|
|
115
|
+
# LANGFUSE_SECRET_KEY=sk-...
|
|
116
|
+
# DSPY_TELEMETRY_BATCH_SIZE=5
|
|
117
|
+
#
|
|
118
|
+
# # Test environment
|
|
119
|
+
# DSPY_ENABLE_IN_TEST=1 # Set to enable DSPy in test env
|
|
266
120
|
|
|
267
|
-
|
|
268
|
-
|
|
121
|
+
# =============================================================================
|
|
122
|
+
# Per-Provider Configuration (without RubyLLM)
|
|
123
|
+
# =============================================================================
|
|
269
124
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
125
|
+
# OpenAI (dspy-openai gem)
|
|
126
|
+
# DSPy.configure do |c|
|
|
127
|
+
# c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY'])
|
|
128
|
+
# end
|
|
274
129
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
130
|
+
# Anthropic (dspy-anthropic gem)
|
|
131
|
+
# DSPy.configure do |c|
|
|
132
|
+
# c.lm = DSPy::LM.new('anthropic/claude-sonnet-4-20250514', api_key: ENV['ANTHROPIC_API_KEY'])
|
|
133
|
+
# end
|
|
278
134
|
|
|
279
|
-
|
|
280
|
-
|
|
135
|
+
# Gemini (dspy-gemini gem)
|
|
136
|
+
# DSPy.configure do |c|
|
|
137
|
+
# c.lm = DSPy::LM.new('gemini/gemini-2.5-flash', api_key: ENV['GEMINI_API_KEY'])
|
|
138
|
+
# end
|
|
281
139
|
|
|
282
|
-
|
|
140
|
+
# Ollama (dspy-openai gem, local models)
|
|
141
|
+
# DSPy.configure do |c|
|
|
142
|
+
# c.lm = DSPy::LM.new('ollama/llama3.2', base_url: 'http://localhost:11434')
|
|
143
|
+
# end
|
|
283
144
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
end
|
|
145
|
+
# OpenRouter (dspy-openai gem, 200+ models)
|
|
146
|
+
# DSPy.configure do |c|
|
|
147
|
+
# c.lm = DSPy::LM.new('openrouter/anthropic/claude-3.5-sonnet',
|
|
148
|
+
# api_key: ENV['OPENROUTER_API_KEY'],
|
|
149
|
+
# base_url: 'https://openrouter.ai/api/v1')
|
|
150
|
+
# end
|
|
290
151
|
|
|
291
|
-
|
|
152
|
+
# =============================================================================
|
|
153
|
+
# VCR Test Configuration — spec/support/dspy.rb
|
|
154
|
+
# =============================================================================
|
|
155
|
+
|
|
156
|
+
# VCR.configure do |config|
|
|
157
|
+
# config.cassette_library_dir = "spec/vcr_cassettes"
|
|
158
|
+
# config.hook_into :webmock
|
|
159
|
+
# config.configure_rspec_metadata!
|
|
160
|
+
# config.filter_sensitive_data('<GEMINI_API_KEY>') { ENV['GEMINI_API_KEY'] }
|
|
161
|
+
# config.filter_sensitive_data('<OPENAI_API_KEY>') { ENV['OPENAI_API_KEY'] }
|
|
162
|
+
# config.filter_sensitive_data('<ANTHROPIC_API_KEY>') { ENV['ANTHROPIC_API_KEY'] }
|
|
163
|
+
# end
|
|
292
164
|
|
|
293
|
-
#
|
|
294
|
-
#
|
|
295
|
-
#
|
|
165
|
+
# =============================================================================
|
|
166
|
+
# Schema Format Configuration (optional)
|
|
167
|
+
# =============================================================================
|
|
296
168
|
|
|
297
|
-
#
|
|
298
|
-
#
|
|
299
|
-
# require 'dspy'
|
|
300
|
-
#
|
|
169
|
+
# BAML schema format — 84% token reduction for Enhanced Prompting mode
|
|
301
170
|
# DSPy.configure do |c|
|
|
302
|
-
#
|
|
303
|
-
#
|
|
304
|
-
#
|
|
305
|
-
# { provider: 'ollama', model: 'llama3.1' }
|
|
306
|
-
# when :test
|
|
307
|
-
# { provider: 'openai', model: 'gpt-4o-mini', temperature: 0.0 }
|
|
308
|
-
# when :production
|
|
309
|
-
# { provider: 'anthropic', model: 'claude-3-5-sonnet-20241022' }
|
|
310
|
-
# end
|
|
311
|
-
#
|
|
312
|
-
# # Configure language model
|
|
313
|
-
# c.lm = DSPy::LM.new(
|
|
314
|
-
# "#{model_config[:provider]}/#{model_config[:model]}",
|
|
315
|
-
# api_key: ENV["#{model_config[:provider].upcase}_API_KEY"],
|
|
316
|
-
# **model_config.except(:provider, :model)
|
|
171
|
+
# c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
172
|
+
# api_key: ENV['OPENAI_API_KEY'],
|
|
173
|
+
# schema_format: :baml # Requires sorbet-baml gem
|
|
317
174
|
# )
|
|
318
|
-
#
|
|
319
|
-
# # Optional: Add observability
|
|
320
|
-
# if Rails.env.production?
|
|
321
|
-
# c.langfuse = {
|
|
322
|
-
# public_key: ENV['LANGFUSE_PUBLIC_KEY'],
|
|
323
|
-
# secret_key: ENV['LANGFUSE_SECRET_KEY']
|
|
324
|
-
# }
|
|
325
|
-
# end
|
|
326
175
|
# end
|
|
327
176
|
|
|
328
|
-
#
|
|
329
|
-
#
|
|
330
|
-
#
|
|
331
|
-
|
|
332
|
-
#
|
|
333
|
-
#
|
|
334
|
-
#
|
|
335
|
-
# config.before(:suite) do
|
|
336
|
-
# DSPy.configure do |c|
|
|
337
|
-
# c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
338
|
-
# api_key: ENV['OPENAI_API_KEY'],
|
|
339
|
-
# temperature: 0.0 # Deterministic for testing
|
|
340
|
-
# )
|
|
341
|
-
# end
|
|
342
|
-
# end
|
|
177
|
+
# TOON schema + data format — table-oriented format
|
|
178
|
+
# DSPy.configure do |c|
|
|
179
|
+
# c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
180
|
+
# api_key: ENV['OPENAI_API_KEY'],
|
|
181
|
+
# schema_format: :toon, # How DSPy describes the signature
|
|
182
|
+
# data_format: :toon # How inputs/outputs are rendered in prompts
|
|
183
|
+
# )
|
|
343
184
|
# end
|
|
344
|
-
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
# ============================================================================
|
|
348
|
-
|
|
349
|
-
# 1. Use environment variables for API keys (never hardcode)
|
|
350
|
-
# 2. Use different models for different environments
|
|
351
|
-
# 3. Use cheaper/faster models for development and testing
|
|
352
|
-
# 4. Configure temperature based on use case:
|
|
353
|
-
# - 0.0-0.3: Deterministic, factual tasks
|
|
354
|
-
# - 0.7-1.0: Balanced creativity
|
|
355
|
-
# - 1.0-2.0: High creativity, content generation
|
|
356
|
-
# 5. Add observability in production (OpenTelemetry, Langfuse)
|
|
357
|
-
# 6. Implement retry logic and fallbacks for reliability
|
|
358
|
-
# 7. Track costs and set budgets for production
|
|
359
|
-
# 8. Use max_tokens to control response length and costs
|
|
185
|
+
#
|
|
186
|
+
# Note: BAML and TOON apply only when structured_outputs: false.
|
|
187
|
+
# With structured_outputs: true, the provider receives JSON Schema directly.
|