ag-cortex 0.1.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/.agent/commands/test-browser.md +339 -0
- package/.agent/rules/00-constitution.md +46 -0
- package/.agent/rules/project-rules.md +49 -0
- package/.agent/skills/agent-browser/SKILL.md +223 -0
- package/.agent/skills/agent-native-architecture/SKILL.md +435 -0
- package/.agent/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
- package/.agent/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
- package/.agent/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
- package/.agent/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
- package/.agent/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
- package/.agent/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
- package/.agent/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
- package/.agent/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
- package/.agent/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
- package/.agent/skills/agent-native-architecture/references/product-implications.md +443 -0
- package/.agent/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
- package/.agent/skills/agent-native-architecture/references/self-modification.md +269 -0
- package/.agent/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
- package/.agent/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
- package/.agent/skills/agent-native-reviewer/SKILL.md +246 -0
- package/.agent/skills/andrew-kane-gem-writer/SKILL.md +184 -0
- package/.agent/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
- package/.agent/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
- package/.agent/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
- package/.agent/skills/andrew-kane-gem-writer/references/resources.md +119 -0
- package/.agent/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
- package/.agent/skills/ankane-readme-writer/SKILL.md +50 -0
- package/.agent/skills/architecture-strategist/SKILL.md +52 -0
- package/.agent/skills/best-practices-researcher/SKILL.md +100 -0
- package/.agent/skills/bug-reproduction-validator/SKILL.md +67 -0
- package/.agent/skills/code-simplicity-reviewer/SKILL.md +85 -0
- package/.agent/skills/coding-tutor/.claude-plugin/plugin.json +9 -0
- package/.agent/skills/coding-tutor/README.md +37 -0
- package/.agent/skills/coding-tutor/commands/quiz-me.md +1 -0
- package/.agent/skills/coding-tutor/commands/sync-tutorials.md +25 -0
- package/.agent/skills/coding-tutor/commands/teach-me.md +1 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/SKILL.md +214 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py +202 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py +203 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/scripts/quiz_priority.py +190 -0
- package/.agent/skills/coding-tutor/skills/coding-tutor/scripts/setup_tutorials.py +132 -0
- package/.agent/skills/compound-docs/SKILL.md +510 -0
- package/.agent/skills/compound-docs/assets/critical-pattern-template.md +34 -0
- package/.agent/skills/compound-docs/assets/resolution-template.md +93 -0
- package/.agent/skills/compound-docs/references/yaml-schema.md +65 -0
- package/.agent/skills/compound-docs/schema.yaml +176 -0
- package/.agent/skills/create-agent-skills/SKILL.md +299 -0
- package/.agent/skills/create-agent-skills/references/api-security.md +226 -0
- package/.agent/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
- package/.agent/skills/create-agent-skills/references/best-practices.md +404 -0
- package/.agent/skills/create-agent-skills/references/common-patterns.md +595 -0
- package/.agent/skills/create-agent-skills/references/core-principles.md +437 -0
- package/.agent/skills/create-agent-skills/references/executable-code.md +175 -0
- package/.agent/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
- package/.agent/skills/create-agent-skills/references/official-spec.md +185 -0
- package/.agent/skills/create-agent-skills/references/recommended-structure.md +168 -0
- package/.agent/skills/create-agent-skills/references/skill-structure.md +372 -0
- package/.agent/skills/create-agent-skills/references/using-scripts.md +113 -0
- package/.agent/skills/create-agent-skills/references/using-templates.md +112 -0
- package/.agent/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
- package/.agent/skills/create-agent-skills/templates/router-skill.md +73 -0
- package/.agent/skills/create-agent-skills/templates/simple-skill.md +33 -0
- package/.agent/skills/create-agent-skills/workflows/add-reference.md +96 -0
- package/.agent/skills/create-agent-skills/workflows/add-script.md +93 -0
- package/.agent/skills/create-agent-skills/workflows/add-template.md +74 -0
- package/.agent/skills/create-agent-skills/workflows/add-workflow.md +120 -0
- package/.agent/skills/create-agent-skills/workflows/audit-skill.md +138 -0
- package/.agent/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
- package/.agent/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
- package/.agent/skills/create-agent-skills/workflows/get-guidance.md +121 -0
- package/.agent/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
- package/.agent/skills/create-agent-skills/workflows/verify-skill.md +204 -0
- package/.agent/skills/data-integrity-guardian/SKILL.md +70 -0
- package/.agent/skills/data-migration-expert/SKILL.md +97 -0
- package/.agent/skills/deployment-verification-agent/SKILL.md +159 -0
- package/.agent/skills/design-implementation-reviewer/SKILL.md +85 -0
- package/.agent/skills/design-iterator/SKILL.md +197 -0
- package/.agent/skills/dhh-rails-reviewer/SKILL.md +45 -0
- package/.agent/skills/dhh-rails-style/SKILL.md +184 -0
- package/.agent/skills/dhh-rails-style/references/architecture.md +653 -0
- package/.agent/skills/dhh-rails-style/references/controllers.md +303 -0
- package/.agent/skills/dhh-rails-style/references/frontend.md +510 -0
- package/.agent/skills/dhh-rails-style/references/gems.md +266 -0
- package/.agent/skills/dhh-rails-style/references/models.md +359 -0
- package/.agent/skills/dhh-rails-style/references/testing.md +338 -0
- package/.agent/skills/dspy-ruby/SKILL.md +594 -0
- package/.agent/skills/dspy-ruby/assets/config-template.rb +359 -0
- package/.agent/skills/dspy-ruby/assets/module-template.rb +326 -0
- package/.agent/skills/dspy-ruby/assets/signature-template.rb +143 -0
- package/.agent/skills/dspy-ruby/references/core-concepts.md +265 -0
- package/.agent/skills/dspy-ruby/references/optimization.md +623 -0
- package/.agent/skills/dspy-ruby/references/providers.md +305 -0
- package/.agent/skills/every-style-editor/SKILL.md +134 -0
- package/.agent/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
- package/.agent/skills/figma-design-sync/SKILL.md +166 -0
- package/.agent/skills/file-todos/SKILL.md +251 -0
- package/.agent/skills/file-todos/assets/todo-template.md +155 -0
- package/.agent/skills/framework-docs-researcher/SKILL.md +83 -0
- package/.agent/skills/frontend-design/SKILL.md +42 -0
- package/.agent/skills/gemini-imagegen/SKILL.md +237 -0
- package/.agent/skills/gemini-imagegen/requirements.txt +2 -0
- package/.agent/skills/gemini-imagegen/scripts/compose_images.py +168 -0
- package/.agent/skills/gemini-imagegen/scripts/edit_image.py +157 -0
- package/.agent/skills/gemini-imagegen/scripts/gemini_images.py +265 -0
- package/.agent/skills/gemini-imagegen/scripts/generate_image.py +147 -0
- package/.agent/skills/gemini-imagegen/scripts/multi_turn_chat.py +215 -0
- package/.agent/skills/git-history-analyzer/SKILL.md +42 -0
- package/.agent/skills/git-worktree/SKILL.md +302 -0
- package/.agent/skills/git-worktree/scripts/worktree-manager.sh +345 -0
- package/.agent/skills/julik-frontend-races-reviewer/SKILL.md +222 -0
- package/.agent/skills/kieran-python-reviewer/SKILL.md +104 -0
- package/.agent/skills/kieran-rails-reviewer/SKILL.md +86 -0
- package/.agent/skills/kieran-typescript-reviewer/SKILL.md +95 -0
- package/.agent/skills/lint/SKILL.md +16 -0
- package/.agent/skills/pattern-recognition-specialist/SKILL.md +57 -0
- package/.agent/skills/performance-oracle/SKILL.md +110 -0
- package/.agent/skills/pr-comment-resolver/SKILL.md +69 -0
- package/.agent/skills/rclone/SKILL.md +150 -0
- package/.agent/skills/rclone/scripts/check_setup.sh +60 -0
- package/.agent/skills/repo-research-analyst/SKILL.md +113 -0
- package/.agent/skills/security-sentinel/SKILL.md +93 -0
- package/.agent/skills/skill-creator/SKILL.md +209 -0
- package/.agent/skills/skill-creator/scripts/init_skill.py +304 -0
- package/.agent/skills/skill-creator/scripts/package_skill.py +112 -0
- package/.agent/skills/skill-creator/scripts/quick_validate.py +72 -0
- package/.agent/skills/spec-flow-analyzer/SKILL.md +113 -0
- package/.agent/skills/test-agent/SKILL.md +4 -0
- package/.agent/workflows/agent-native-audit.md +277 -0
- package/.agent/workflows/ask-user-question.md +21 -0
- package/.agent/workflows/changelog.md +137 -0
- package/.agent/workflows/compound.md +202 -0
- package/.agent/workflows/create-agent-skill.md +8 -0
- package/.agent/workflows/deepen-plan-research.md +334 -0
- package/.agent/workflows/deepen-plan-synthesis.md +182 -0
- package/.agent/workflows/deepen-plan.md +79 -0
- package/.agent/workflows/feature-video.md +342 -0
- package/.agent/workflows/generate-command.md +162 -0
- package/.agent/workflows/heal-skill.md +142 -0
- package/.agent/workflows/lfg.md +20 -0
- package/.agent/workflows/plan-analysis.md +67 -0
- package/.agent/workflows/plan-next-steps.md +63 -0
- package/.agent/workflows/plan-review.md +33 -0
- package/.agent/workflows/plan-synthesis.md +106 -0
- package/.agent/workflows/plan.md +49 -0
- package/.agent/workflows/report-bug.md +150 -0
- package/.agent/workflows/reproduce-bug.md +99 -0
- package/.agent/workflows/resolve-parallel.md +34 -0
- package/.agent/workflows/resolve-pr-parallel.md +49 -0
- package/.agent/workflows/resolve-todo-parallel.md +35 -0
- package/.agent/workflows/review-analysis.md +145 -0
- package/.agent/workflows/review-synthesis.md +262 -0
- package/.agent/workflows/review.md +64 -0
- package/.agent/workflows/ship.md +90 -0
- package/.agent/workflows/test-command.md +3 -0
- package/.agent/workflows/triage.md +310 -0
- package/.agent/workflows/work.md +157 -0
- package/.agent/workflows/xcode-test.md +332 -0
- package/LICENSE +22 -0
- package/README.md +49 -0
- package/bin/ag-cortex.js +54 -0
- package/lib/core.js +165 -0
- package/package.json +31 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# DSPy.rb Configuration Examples
|
|
4
|
+
# This file demonstrates various configuration patterns for different use cases
|
|
5
|
+
|
|
6
|
+
require 'dspy'
|
|
7
|
+
|
|
8
|
+
# ============================================================================
|
|
9
|
+
# Basic Configuration
|
|
10
|
+
# ============================================================================
|
|
11
|
+
|
|
12
|
+
# Simple OpenAI configuration
|
|
13
|
+
DSPy.configure do |c|
|
|
14
|
+
c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
15
|
+
api_key: ENV['OPENAI_API_KEY'])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# ============================================================================
|
|
19
|
+
# Multi-Provider Configuration
|
|
20
|
+
# ============================================================================
|
|
21
|
+
|
|
22
|
+
# Google Gemini (Advanced)
|
|
23
|
+
DSPy.configure do |c|
|
|
24
|
+
c.lm = DSPy::LM.new('google/gemini-1.5-pro-latest',
|
|
25
|
+
api_key: ENV['GOOGLE_API_KEY'])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Google Gemini
|
|
29
|
+
DSPy.configure do |c|
|
|
30
|
+
c.lm = DSPy::LM.new('gemini/gemini-1.5-pro',
|
|
31
|
+
api_key: ENV['GOOGLE_API_KEY'])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Local Ollama
|
|
35
|
+
DSPy.configure do |c|
|
|
36
|
+
c.lm = DSPy::LM.new('ollama/llama3.1',
|
|
37
|
+
base_url: 'http://localhost:11434')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# OpenRouter (access to 200+ models)
|
|
41
|
+
DSPy.configure do |c|
|
|
42
|
+
c.lm = DSPy::LM.new('openrouter/google/gemini-1.5-pro',
|
|
43
|
+
api_key: ENV['OPENROUTER_API_KEY'],
|
|
44
|
+
base_url: 'https://openrouter.ai/api/v1')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# ============================================================================
|
|
48
|
+
# Environment-Based Configuration
|
|
49
|
+
# ============================================================================
|
|
50
|
+
|
|
51
|
+
# Different models for different environments
|
|
52
|
+
if Rails.env.development?
|
|
53
|
+
# Use local Ollama for development (free, private)
|
|
54
|
+
DSPy.configure do |c|
|
|
55
|
+
c.lm = DSPy::LM.new('ollama/llama3.1')
|
|
56
|
+
end
|
|
57
|
+
elsif Rails.env.test?
|
|
58
|
+
# Use cheap model for testing
|
|
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('google/gemini-1.5-pro',
|
|
67
|
+
api_key: ENV['GOOGLE_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('google/gemini-1.5-pro',
|
|
100
|
+
api_key: ENV['GOOGLE_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
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def self.create_lm_with_retry
|
|
183
|
+
lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
184
|
+
api_key: ENV['OPENAI_API_KEY'])
|
|
185
|
+
|
|
186
|
+
# Wrap with retry logic
|
|
187
|
+
lm.extend(RetryBehavior)
|
|
188
|
+
lm
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
module RetryBehavior
|
|
192
|
+
def forward(input, retry_count: 0)
|
|
193
|
+
super(input)
|
|
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
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
RetryableConfig.configure
|
|
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('google/gemini-1.5-pro',
|
|
220
|
+
api_key: ENV['GOOGLE_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
|
|
227
|
+
|
|
228
|
+
class FallbackLM
|
|
229
|
+
def initialize(primary, fallback)
|
|
230
|
+
@primary = primary
|
|
231
|
+
@fallback = fallback
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def forward(input)
|
|
235
|
+
@primary.forward(input)
|
|
236
|
+
rescue => e
|
|
237
|
+
puts "Primary model failed: #{e.message}. Falling back..."
|
|
238
|
+
@fallback.forward(input)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
FallbackConfig.configure
|
|
244
|
+
|
|
245
|
+
# ============================================================================
|
|
246
|
+
# Configuration with Budget Tracking
|
|
247
|
+
# ============================================================================
|
|
248
|
+
|
|
249
|
+
class BudgetTrackedConfig
|
|
250
|
+
def self.configure(monthly_budget_usd:)
|
|
251
|
+
DSPy.configure do |c|
|
|
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
|
|
259
|
+
|
|
260
|
+
class BudgetTracker
|
|
261
|
+
def initialize(lm, monthly_budget_usd:)
|
|
262
|
+
@lm = lm
|
|
263
|
+
@monthly_budget_usd = monthly_budget_usd
|
|
264
|
+
@monthly_cost = 0.0
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def forward(input)
|
|
268
|
+
result = @lm.forward(input)
|
|
269
|
+
|
|
270
|
+
# Track cost (simplified - actual costs vary by model)
|
|
271
|
+
tokens = result.metadata[:usage][:total_tokens]
|
|
272
|
+
cost = estimate_cost(tokens)
|
|
273
|
+
@monthly_cost += cost
|
|
274
|
+
|
|
275
|
+
if @monthly_cost > @monthly_budget_usd
|
|
276
|
+
raise "Monthly budget of $#{@monthly_budget_usd} exceeded!"
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
result
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
private
|
|
283
|
+
|
|
284
|
+
def estimate_cost(tokens)
|
|
285
|
+
# Simplified cost estimation (check provider pricing)
|
|
286
|
+
(tokens / 1_000_000.0) * 5.0 # $5 per 1M tokens
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
BudgetTrackedConfig.configure(monthly_budget_usd: 100)
|
|
292
|
+
|
|
293
|
+
# ============================================================================
|
|
294
|
+
# Configuration Initializer for Rails
|
|
295
|
+
# ============================================================================
|
|
296
|
+
|
|
297
|
+
# Save this as config/initializers/dspy.rb
|
|
298
|
+
#
|
|
299
|
+
# require 'dspy'
|
|
300
|
+
#
|
|
301
|
+
# DSPy.configure do |c|
|
|
302
|
+
# # Environment-specific configuration
|
|
303
|
+
# model_config = case Rails.env.to_sym
|
|
304
|
+
# when :development
|
|
305
|
+
# { provider: 'ollama', model: 'llama3.1' }
|
|
306
|
+
# when :test
|
|
307
|
+
# { provider: 'openai', model: 'gpt-4o-mini', temperature: 0.0 }
|
|
308
|
+
# when :production
|
|
309
|
+
# { provider: 'google', model: 'gemini-1.5-pro' }
|
|
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)
|
|
317
|
+
# )
|
|
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
|
+
# end
|
|
327
|
+
|
|
328
|
+
# ============================================================================
|
|
329
|
+
# Testing Configuration
|
|
330
|
+
# ============================================================================
|
|
331
|
+
|
|
332
|
+
# In spec/spec_helper.rb or test/test_helper.rb
|
|
333
|
+
#
|
|
334
|
+
# RSpec.configure do |config|
|
|
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
|
|
343
|
+
# end
|
|
344
|
+
|
|
345
|
+
# ============================================================================
|
|
346
|
+
# Configuration Best Practices
|
|
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
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Example DSPy Module Template
|
|
4
|
+
# This template demonstrates best practices for creating composable modules
|
|
5
|
+
|
|
6
|
+
# Basic module with single predictor
|
|
7
|
+
class BasicModule < DSPy::Module
|
|
8
|
+
def initialize
|
|
9
|
+
super
|
|
10
|
+
# Initialize predictor with signature
|
|
11
|
+
@predictor = DSPy::Predict.new(ExampleSignature)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def forward(input_hash)
|
|
15
|
+
# Forward pass through the predictor
|
|
16
|
+
@predictor.forward(input_hash)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Module with Chain of Thought reasoning
|
|
21
|
+
class ChainOfThoughtModule < DSPy::Module
|
|
22
|
+
def initialize
|
|
23
|
+
super
|
|
24
|
+
# ChainOfThought automatically adds reasoning to output
|
|
25
|
+
@predictor = DSPy::ChainOfThought.new(EmailClassificationSignature)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def forward(email_subject:, email_body:)
|
|
29
|
+
result = @predictor.forward(
|
|
30
|
+
email_subject: email_subject,
|
|
31
|
+
email_body: email_body
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Result includes :reasoning field automatically
|
|
35
|
+
{
|
|
36
|
+
category: result[:category],
|
|
37
|
+
priority: result[:priority],
|
|
38
|
+
reasoning: result[:reasoning],
|
|
39
|
+
confidence: calculate_confidence(result)
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def calculate_confidence(result)
|
|
46
|
+
# Add custom logic to calculate confidence
|
|
47
|
+
# For example, based on reasoning length or specificity
|
|
48
|
+
result[:confidence] || 0.8
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Composable module that chains multiple steps
|
|
53
|
+
class MultiStepPipeline < DSPy::Module
|
|
54
|
+
def initialize
|
|
55
|
+
super
|
|
56
|
+
# Initialize multiple predictors for different steps
|
|
57
|
+
@step1 = DSPy::Predict.new(Step1Signature)
|
|
58
|
+
@step2 = DSPy::ChainOfThought.new(Step2Signature)
|
|
59
|
+
@step3 = DSPy::Predict.new(Step3Signature)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def forward(input)
|
|
63
|
+
# Chain predictors together
|
|
64
|
+
result1 = @step1.forward(input)
|
|
65
|
+
result2 = @step2.forward(result1)
|
|
66
|
+
result3 = @step3.forward(result2)
|
|
67
|
+
|
|
68
|
+
# Combine results as needed
|
|
69
|
+
{
|
|
70
|
+
step1_output: result1,
|
|
71
|
+
step2_output: result2,
|
|
72
|
+
final_result: result3
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Module with conditional logic
|
|
78
|
+
class ConditionalModule < DSPy::Module
|
|
79
|
+
def initialize
|
|
80
|
+
super
|
|
81
|
+
@simple_classifier = DSPy::Predict.new(SimpleClassificationSignature)
|
|
82
|
+
@complex_analyzer = DSPy::ChainOfThought.new(ComplexAnalysisSignature)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def forward(text:, complexity_threshold: 100)
|
|
86
|
+
# Use different predictors based on input characteristics
|
|
87
|
+
if text.length < complexity_threshold
|
|
88
|
+
@simple_classifier.forward(text: text)
|
|
89
|
+
else
|
|
90
|
+
@complex_analyzer.forward(text: text)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Module with error handling and retry logic
|
|
96
|
+
class RobustModule < DSPy::Module
|
|
97
|
+
MAX_RETRIES = 3
|
|
98
|
+
|
|
99
|
+
def initialize
|
|
100
|
+
super
|
|
101
|
+
@predictor = DSPy::Predict.new(RobustSignature)
|
|
102
|
+
@logger = Logger.new(STDOUT)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def forward(input, retry_count: 0)
|
|
106
|
+
@logger.info "Processing input: #{input.inspect}"
|
|
107
|
+
|
|
108
|
+
begin
|
|
109
|
+
result = @predictor.forward(input)
|
|
110
|
+
validate_result!(result)
|
|
111
|
+
result
|
|
112
|
+
rescue DSPy::ValidationError => e
|
|
113
|
+
@logger.error "Validation error: #{e.message}"
|
|
114
|
+
|
|
115
|
+
if retry_count < MAX_RETRIES
|
|
116
|
+
@logger.info "Retrying (#{retry_count + 1}/#{MAX_RETRIES})..."
|
|
117
|
+
sleep(2 ** retry_count) # Exponential backoff
|
|
118
|
+
forward(input, retry_count: retry_count + 1)
|
|
119
|
+
else
|
|
120
|
+
@logger.error "Max retries exceeded"
|
|
121
|
+
raise
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
def validate_result!(result)
|
|
129
|
+
# Add custom validation logic
|
|
130
|
+
raise DSPy::ValidationError, "Invalid result" unless result[:category]
|
|
131
|
+
raise DSPy::ValidationError, "Low confidence" if result[:confidence] && result[:confidence] < 0.5
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Module with ReAct agent and tools
|
|
136
|
+
class AgentModule < DSPy::Module
|
|
137
|
+
def initialize
|
|
138
|
+
super
|
|
139
|
+
|
|
140
|
+
# Define tools for the agent
|
|
141
|
+
tools = [
|
|
142
|
+
SearchTool.new,
|
|
143
|
+
CalculatorTool.new,
|
|
144
|
+
DatabaseQueryTool.new
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
# ReAct provides iterative reasoning and tool usage
|
|
148
|
+
@agent = DSPy::ReAct.new(
|
|
149
|
+
AgentSignature,
|
|
150
|
+
tools: tools,
|
|
151
|
+
max_iterations: 5
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def forward(task:)
|
|
156
|
+
# Agent will autonomously use tools to complete the task
|
|
157
|
+
@agent.forward(task: task)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Tool definition example
|
|
162
|
+
class SearchTool < DSPy::Tool
|
|
163
|
+
def call(query:)
|
|
164
|
+
# Implement search functionality
|
|
165
|
+
results = perform_search(query)
|
|
166
|
+
{ results: results }
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
private
|
|
170
|
+
|
|
171
|
+
def perform_search(query)
|
|
172
|
+
# Actual search implementation
|
|
173
|
+
# Could call external API, database, etc.
|
|
174
|
+
["result1", "result2", "result3"]
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Module with state management
|
|
179
|
+
class StatefulModule < DSPy::Module
|
|
180
|
+
attr_reader :history
|
|
181
|
+
|
|
182
|
+
def initialize
|
|
183
|
+
super
|
|
184
|
+
@predictor = DSPy::ChainOfThought.new(StatefulSignature)
|
|
185
|
+
@history = []
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def forward(input)
|
|
189
|
+
# Process with context from history
|
|
190
|
+
context = build_context_from_history
|
|
191
|
+
result = @predictor.forward(
|
|
192
|
+
input: input,
|
|
193
|
+
context: context
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# Store in history
|
|
197
|
+
@history << {
|
|
198
|
+
input: input,
|
|
199
|
+
result: result,
|
|
200
|
+
timestamp: Time.now
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
result
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def reset!
|
|
207
|
+
@history.clear
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
private
|
|
211
|
+
|
|
212
|
+
def build_context_from_history
|
|
213
|
+
@history.last(5).map { |h| h[:result][:summary] }.join("\n")
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Module that uses different LLMs for different tasks
|
|
218
|
+
class MultiModelModule < DSPy::Module
|
|
219
|
+
def initialize
|
|
220
|
+
super
|
|
221
|
+
|
|
222
|
+
# Fast, cheap model for simple classification
|
|
223
|
+
@fast_predictor = create_predictor(
|
|
224
|
+
'openai/gpt-4o-mini',
|
|
225
|
+
SimpleClassificationSignature
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# Powerful model for complex analysis
|
|
229
|
+
@powerful_predictor = create_predictor(
|
|
230
|
+
'google/gemini-1.5-pro-20241022',
|
|
231
|
+
ComplexAnalysisSignature
|
|
232
|
+
)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def forward(input, use_complex: false)
|
|
236
|
+
if use_complex
|
|
237
|
+
@powerful_predictor.forward(input)
|
|
238
|
+
else
|
|
239
|
+
@fast_predictor.forward(input)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
private
|
|
244
|
+
|
|
245
|
+
def create_predictor(model, signature)
|
|
246
|
+
lm = DSPy::LM.new(model, api_key: ENV["#{model.split('/').first.upcase}_API_KEY"])
|
|
247
|
+
DSPy::Predict.new(signature, lm: lm)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Module with caching
|
|
252
|
+
class CachedModule < DSPy::Module
|
|
253
|
+
def initialize
|
|
254
|
+
super
|
|
255
|
+
@predictor = DSPy::Predict.new(CachedSignature)
|
|
256
|
+
@cache = {}
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def forward(input)
|
|
260
|
+
# Create cache key from input
|
|
261
|
+
cache_key = create_cache_key(input)
|
|
262
|
+
|
|
263
|
+
# Return cached result if available
|
|
264
|
+
if @cache.key?(cache_key)
|
|
265
|
+
puts "Cache hit for #{cache_key}"
|
|
266
|
+
return @cache[cache_key]
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Compute and cache result
|
|
270
|
+
result = @predictor.forward(input)
|
|
271
|
+
@cache[cache_key] = result
|
|
272
|
+
result
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def clear_cache!
|
|
276
|
+
@cache.clear
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
private
|
|
280
|
+
|
|
281
|
+
def create_cache_key(input)
|
|
282
|
+
# Create deterministic hash from input
|
|
283
|
+
Digest::MD5.hexdigest(input.to_s)
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Usage Examples:
|
|
288
|
+
#
|
|
289
|
+
# Basic usage:
|
|
290
|
+
# module = BasicModule.new
|
|
291
|
+
# result = module.forward(field_name: "value")
|
|
292
|
+
#
|
|
293
|
+
# Chain of Thought:
|
|
294
|
+
# module = ChainOfThoughtModule.new
|
|
295
|
+
# result = module.forward(
|
|
296
|
+
# email_subject: "Can't log in",
|
|
297
|
+
# email_body: "I'm unable to access my account"
|
|
298
|
+
# )
|
|
299
|
+
# puts result[:reasoning]
|
|
300
|
+
#
|
|
301
|
+
# Multi-step pipeline:
|
|
302
|
+
# pipeline = MultiStepPipeline.new
|
|
303
|
+
# result = pipeline.forward(input_data)
|
|
304
|
+
#
|
|
305
|
+
# With error handling:
|
|
306
|
+
# module = RobustModule.new
|
|
307
|
+
# begin
|
|
308
|
+
# result = module.forward(input_data)
|
|
309
|
+
# rescue DSPy::ValidationError => e
|
|
310
|
+
# puts "Failed after retries: #{e.message}"
|
|
311
|
+
# end
|
|
312
|
+
#
|
|
313
|
+
# Agent with tools:
|
|
314
|
+
# agent = AgentModule.new
|
|
315
|
+
# result = agent.forward(task: "Find the population of Tokyo")
|
|
316
|
+
#
|
|
317
|
+
# Stateful processing:
|
|
318
|
+
# module = StatefulModule.new
|
|
319
|
+
# result1 = module.forward("First input")
|
|
320
|
+
# result2 = module.forward("Second input") # Has context from first
|
|
321
|
+
# module.reset! # Clear history
|
|
322
|
+
#
|
|
323
|
+
# With caching:
|
|
324
|
+
# module = CachedModule.new
|
|
325
|
+
# result1 = module.forward(input) # Computes result
|
|
326
|
+
# result2 = module.forward(input) # Returns cached result
|