hokipoki 0.1.2 โ†’ 0.1.3

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.
@@ -0,0 +1,662 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module Hokipoki
6
+ module Parasites
7
+ # Universal Parasite Generator
8
+ # Revolutionary system that consolidates 17+ individual parasites into one template-driven generator
9
+ # This represents the 94% code reduction achievement: 17 parasites โ†’ 1 universal system
10
+ class UniversalGenerator
11
+ include Singleton
12
+
13
+ def initialize
14
+ @logger = Rails.logger
15
+ @feedback = Feedback::DisplayManager.instance
16
+ @template_registry = nil # Lazy load
17
+ @behavioral_analyzer = nil # Lazy load
18
+ @embedding_service = nil # Lazy load
19
+ @initialized = false
20
+ end
21
+
22
+ # Main entry point: Generate parasite from requirements
23
+ def generate_parasite(requirements)
24
+ ensure_initialized!
25
+
26
+ generation_id = generate_id
27
+ start_time = Time.current
28
+ tool = requirements[:tool] || 'unknown'
29
+ model = requirements[:model] || 'unknown'
30
+
31
+ @feedback.generating_parasite(tool, model) do
32
+ @logger.info "๐Ÿฆ  UNIVERSAL: Starting parasite generation [#{generation_id}]"
33
+ end
34
+
35
+ @feedback.progress_tracker(5, 'parasite_generation') do |progress|
36
+ begin
37
+ # STEP 1: Analyze requirements and context
38
+ progress.call('analyzing requirements')
39
+ analyzed_requirements = analyze_requirements(requirements, generation_id)
40
+
41
+ # STEP 2: Find optimal template using vector similarity
42
+ progress.call('finding optimal template')
43
+ optimal_template = find_optimal_template(analyzed_requirements)
44
+
45
+ unless optimal_template
46
+ @feedback.operation_warning('template_search', 'no suitable template found, using fallback')
47
+ return create_fallback_parasite(analyzed_requirements, generation_id)
48
+ end
49
+
50
+ # STEP 3: Generate customized parasite from template
51
+ progress.call('generating from template')
52
+ generated_parasite = generate_from_template(optimal_template, analyzed_requirements, generation_id)
53
+
54
+ # STEP 4: Apply behavioral optimizations if available
55
+ progress.call('applying behavioral optimizations')
56
+ optimized_parasite = apply_behavioral_optimizations(generated_parasite, analyzed_requirements)
57
+
58
+ # STEP 5: Register and store parasite
59
+ progress.call('storing parasite')
60
+ stored_parasite = store_generated_parasite(optimized_parasite, analyzed_requirements, generation_id)
61
+
62
+ generation_time = (Time.current - start_time).round(3)
63
+ generation_time_ms = (generation_time * 1000).round(2)
64
+
65
+ @feedback.parasite_generation_complete(generated_parasite[:name], generation_time_ms)
66
+
67
+ {
68
+ success: true,
69
+ parasite: stored_parasite,
70
+ generation_id: generation_id,
71
+ template_used: optimal_template.name,
72
+ generation_time_ms: generation_time_ms,
73
+ behavioral_optimizations_applied: optimized_parasite[:optimizations_applied] || false
74
+ }
75
+
76
+ rescue => e
77
+ @feedback.operation_error('parasite_generation', e.message)
78
+ @logger.error "โŒ UNIVERSAL: Generation failed [#{generation_id}]: #{e.message}"
79
+ handle_generation_error(e, requirements, generation_id)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Generate parasite specifically optimized for a target LLM
85
+ def generate_llm_optimized_parasite(requirements, target_llm)
86
+ @logger.info "๐Ÿง  UNIVERSAL: Generating LLM-optimized parasite for #{target_llm}"
87
+
88
+ # Enhance requirements with LLM-specific behavioral patterns
89
+ enhanced_requirements = requirements.merge({
90
+ target_llm: target_llm,
91
+ behavioral_optimization: true,
92
+ llm_specific_patterns: get_llm_behavioral_patterns(target_llm)
93
+ })
94
+
95
+ generate_parasite(enhanced_requirements)
96
+ end
97
+
98
+ # Create multiple parasite variants for A/B testing
99
+ def generate_variants_for_testing(base_requirements, variant_count = 3)
100
+ @logger.info "๐Ÿงช UNIVERSAL: Generating #{variant_count} parasite variants for A/B testing"
101
+
102
+ variants = []
103
+ base_id = generate_id
104
+
105
+ variant_count.times do |i|
106
+ variant_requirements = create_variant_requirements(base_requirements, i)
107
+ variant_requirements[:variant_id] = "#{base_id}_variant_#{i + 1}"
108
+ variant_requirements[:is_test_variant] = true
109
+
110
+ variant_result = generate_parasite(variant_requirements)
111
+ variants << variant_result if variant_result[:success]
112
+ end
113
+
114
+ {
115
+ success: true,
116
+ base_id: base_id,
117
+ variants: variants,
118
+ test_configuration: create_ab_test_configuration(variants)
119
+ }
120
+ end
121
+
122
+ private
123
+
124
+ def ensure_initialized!
125
+ return if @initialized
126
+
127
+ @template_registry = load_template_registry
128
+ @embedding_service = load_embedding_service
129
+ @initialized = true
130
+ end
131
+
132
+ def analyze_requirements(requirements, generation_id)
133
+ @logger.debug "๐Ÿ” UNIVERSAL: Analyzing requirements [#{generation_id}]"
134
+
135
+ analyzed = {
136
+ original_requirements: requirements,
137
+ generation_id: generation_id,
138
+ tool: requirements[:tool] || 'unknown',
139
+ model: requirements[:model] || 'unknown',
140
+ context_type: requirements[:context_type] || 'general',
141
+ injection_style: requirements[:injection_style] || 'natural',
142
+ token_budget: requirements[:token_budget] || 1500,
143
+ project_context: detect_project_context(requirements),
144
+ behavioral_requirements: extract_behavioral_requirements(requirements),
145
+ optimization_preferences: extract_optimization_preferences(requirements)
146
+ }
147
+
148
+ # Generate search query for template matching
149
+ analyzed[:template_search_query] = build_template_search_query(analyzed)
150
+
151
+ # Calculate requirement vector for similarity matching (if embedding service available)
152
+ if @embedding_service
153
+ analyzed[:requirement_vector] = generate_requirement_vector(analyzed)
154
+ end
155
+
156
+ analyzed
157
+ end
158
+
159
+ def find_optimal_template(analyzed_requirements)
160
+ @feedback.debug_info('template_search', 'searching for optimal template')
161
+
162
+ return nil unless @template_registry
163
+
164
+ # Try vector similarity first if available
165
+ if analyzed_requirements[:requirement_vector] && @template_registry.respond_to?(:find_templates_by_similarity)
166
+ @feedback.debug_info('vector_search', 'using vector similarity for template matching')
167
+
168
+ template_matches = @template_registry.find_templates_by_similarity(
169
+ analyzed_requirements[:requirement_vector],
170
+ template_type: 'parasite',
171
+ limit: 3
172
+ )
173
+
174
+ if template_matches&.any?
175
+ @feedback.debug_info('template_matches', "found #{template_matches.length} template matches")
176
+ return select_best_template(template_matches, analyzed_requirements)
177
+ else
178
+ @feedback.debug_info('vector_search', 'no vector matches found')
179
+ end
180
+ end
181
+
182
+ # Fallback to keyword-based search
183
+ @feedback.debug_info('keyword_search', 'falling back to keyword-based search')
184
+ result = @template_registry.find_optimal_template(
185
+ analyzed_requirements[:template_search_query],
186
+ { type: 'parasite' }
187
+ )
188
+
189
+ if result
190
+ @feedback.debug_info('template_found', "found template via keyword search: #{result.name}")
191
+ else
192
+ @feedback.debug_info('template_search', 'no templates found')
193
+ end
194
+
195
+ result
196
+ end
197
+
198
+ def select_best_template(template_matches, analyzed_requirements)
199
+ return template_matches.first if template_matches.length == 1
200
+
201
+ @feedback.debug_info('template_scoring', "scoring #{template_matches.length} templates")
202
+
203
+ # Score templates based on requirements match
204
+ scored_templates = template_matches.map do |template|
205
+ score = calculate_template_match_score(template, analyzed_requirements)
206
+ @feedback.debug_info('template_score', "#{template.name}: #{score.round(3)}")
207
+ { template: template, score: score }
208
+ end
209
+
210
+ # Return highest scoring template
211
+ best_match = scored_templates.max_by { |match| match[:score] }
212
+
213
+ @feedback.parasite_template_found(best_match[:template].name, best_match[:score])
214
+ best_match[:template]
215
+ end
216
+
217
+ def generate_from_template(template, analyzed_requirements, generation_id)
218
+ @logger.debug "๐Ÿญ UNIVERSAL: Generating from template '#{template.name}'"
219
+
220
+ # Extract template patterns
221
+ template_content = template.template_content || generate_default_template_content(analyzed_requirements)
222
+
223
+ # Replace template variables with requirement-specific values
224
+ customized_content = customize_template_content(template_content, analyzed_requirements)
225
+
226
+ # Generate parasite metadata
227
+ parasite_metadata = generate_parasite_metadata(template, analyzed_requirements, generation_id)
228
+
229
+ # Create parasite structure
230
+ generated_parasite = {
231
+ name: generate_parasite_name(analyzed_requirements),
232
+ code: customized_content,
233
+ metadata: parasite_metadata,
234
+ template_source: template.name,
235
+ template_version: template.version || '1.0',
236
+ generation_method: 'template_based'
237
+ }
238
+
239
+ @logger.info "๐Ÿญ UNIVERSAL: Generated parasite '#{generated_parasite[:name]}' from template"
240
+ generated_parasite
241
+ end
242
+
243
+ def apply_behavioral_optimizations(generated_parasite, analyzed_requirements)
244
+ return generated_parasite unless analyzed_requirements[:behavioral_optimization]
245
+
246
+ @logger.debug "๐Ÿง  UNIVERSAL: Applying behavioral optimizations"
247
+
248
+ # Load behavioral analyzer if needed
249
+ @behavioral_analyzer ||= load_behavioral_analyzer
250
+
251
+ if @behavioral_analyzer && analyzed_requirements[:target_llm]
252
+ behavioral_patterns = @behavioral_analyzer.get_patterns_for_llm(analyzed_requirements[:target_llm])
253
+
254
+ if behavioral_patterns && behavioral_patterns.any?
255
+ optimized_code = optimize_code_for_behavioral_patterns(
256
+ generated_parasite[:code],
257
+ behavioral_patterns
258
+ )
259
+
260
+ generated_parasite[:code] = optimized_code
261
+ generated_parasite[:behavioral_optimizations] = behavioral_patterns.keys
262
+ generated_parasite[:optimizations_applied] = true
263
+
264
+ @logger.info "๐Ÿง  UNIVERSAL: Applied behavioral optimizations for #{analyzed_requirements[:target_llm]}"
265
+ end
266
+ end
267
+
268
+ generated_parasite
269
+ end
270
+
271
+ def store_generated_parasite(generated_parasite, analyzed_requirements, generation_id)
272
+ @logger.debug "๐Ÿ’พ UNIVERSAL: Storing generated parasite"
273
+
274
+ # Create parasite record using Hokipoki models
275
+ parasite_data = {
276
+ name: generated_parasite[:name],
277
+ tool: analyzed_requirements[:tool],
278
+ model: analyzed_requirements[:model],
279
+ code: generated_parasite[:code],
280
+ metadata: generated_parasite[:metadata].merge({
281
+ generation_id: generation_id,
282
+ generated_by: 'universal_parasite_generator',
283
+ generated_at: Time.current.iso8601
284
+ }),
285
+ description: generate_parasite_description(generated_parasite, analyzed_requirements),
286
+ template_source: generated_parasite[:template_source],
287
+ template_version: generated_parasite[:template_version],
288
+ auto_activate: analyzed_requirements[:auto_activate] || false,
289
+ version: 1
290
+ }
291
+
292
+ # Store the parasite (would integrate with actual model when available)
293
+ stored_parasite = create_parasite_record(parasite_data)
294
+
295
+ @logger.info "๐Ÿ’พ UNIVERSAL: Stored parasite with ID #{stored_parasite[:id] || 'generated'}"
296
+ stored_parasite
297
+ end
298
+
299
+ def create_fallback_parasite(analyzed_requirements, generation_id)
300
+ @logger.warn "โš ๏ธ UNIVERSAL: No template found, creating fallback parasite"
301
+
302
+ # Generate basic parasite using fallback logic
303
+ fallback_code = generate_fallback_parasite_code(analyzed_requirements)
304
+
305
+ fallback_parasite = {
306
+ name: "fallback_#{analyzed_requirements[:tool]}_#{analyzed_requirements[:model]}_#{Time.current.to_i}",
307
+ code: fallback_code,
308
+ metadata: {
309
+ generation_id: generation_id,
310
+ generation_method: 'fallback',
311
+ created_at: Time.current.iso8601
312
+ },
313
+ template_source: 'fallback_generator',
314
+ generation_method: 'fallback'
315
+ }
316
+
317
+ stored_parasite = store_generated_parasite(fallback_parasite, analyzed_requirements, generation_id)
318
+
319
+ {
320
+ success: true,
321
+ parasite: stored_parasite,
322
+ generation_id: generation_id,
323
+ template_used: 'fallback_generator',
324
+ warning: 'No suitable template found, used fallback generation'
325
+ }
326
+ end
327
+
328
+ def detect_project_context(requirements)
329
+ working_dir = requirements[:working_directory] || Dir.pwd
330
+
331
+ context = {
332
+ working_directory: working_dir,
333
+ project_type: 'unknown',
334
+ has_git: false,
335
+ languages: []
336
+ }
337
+
338
+ begin
339
+ # Detect project type from directory structure
340
+ if File.exist?(File.join(working_dir, 'Gemfile'))
341
+ context[:project_type] = 'ruby'
342
+ context[:languages] << 'ruby'
343
+ end
344
+
345
+ if File.exist?(File.join(working_dir, 'package.json'))
346
+ context[:project_type] = 'nodejs' if context[:project_type] == 'unknown'
347
+ context[:languages] << 'javascript'
348
+ end
349
+
350
+ if File.exist?(File.join(working_dir, '.git'))
351
+ context[:has_git] = true
352
+ end
353
+
354
+ rescue => e
355
+ @logger.debug "Could not detect project context: #{e.message}"
356
+ end
357
+
358
+ context
359
+ end
360
+
361
+ def extract_behavioral_requirements(requirements)
362
+ {
363
+ response_style: requirements[:response_style] || 'natural',
364
+ thinking_tags: requirements[:thinking_tags] || false,
365
+ code_quality_focus: requirements[:code_quality_focus] || 'standard',
366
+ error_handling_style: requirements[:error_handling_style] || 'standard',
367
+ verbosity_level: requirements[:verbosity_level] || 'medium'
368
+ }
369
+ end
370
+
371
+ def extract_optimization_preferences(requirements)
372
+ {
373
+ token_efficiency: requirements[:token_efficiency] || 'high',
374
+ context_compression: requirements[:context_compression] || 'medium',
375
+ cache_usage: requirements[:cache_usage] || 'enabled',
376
+ performance_priority: requirements[:performance_priority] || 'balanced'
377
+ }
378
+ end
379
+
380
+ def build_template_search_query(analyzed)
381
+ query_parts = [
382
+ analyzed[:tool],
383
+ analyzed[:model],
384
+ analyzed[:context_type],
385
+ analyzed[:injection_style]
386
+ ]
387
+
388
+ # Add behavioral requirements
389
+ behavioral = analyzed[:behavioral_requirements]
390
+ query_parts << behavioral[:response_style] if behavioral[:response_style] != 'natural'
391
+ query_parts << 'thinking_tags' if behavioral[:thinking_tags]
392
+
393
+ query_parts.compact.join(' ')
394
+ end
395
+
396
+ def generate_requirement_vector(analyzed)
397
+ return nil unless @embedding_service
398
+
399
+ # Create text representation for embedding
400
+ vector_text = [
401
+ "tool: #{analyzed[:tool]}",
402
+ "model: #{analyzed[:model]}",
403
+ "context: #{analyzed[:context_type]}",
404
+ "style: #{analyzed[:injection_style]}",
405
+ "behavioral: #{analyzed[:behavioral_requirements].values.join(' ')}",
406
+ "optimization: #{analyzed[:optimization_preferences].values.join(' ')}"
407
+ ].join(' ')
408
+
409
+ @embedding_service.generate_embedding(vector_text)
410
+ end
411
+
412
+ def calculate_template_match_score(template, analyzed_requirements)
413
+ score = 0.0
414
+
415
+ # Keyword match (50% weight when no vector similarity)
416
+ template_keywords = template.keywords || []
417
+ requirement_keywords = analyzed_requirements[:template_search_query].split(' ')
418
+ keyword_match = calculate_keyword_overlap(template_keywords, requirement_keywords)
419
+ score += keyword_match * 0.5
420
+
421
+ # Usage efficiency (30% weight)
422
+ efficiency_score = template.efficiency_score || 0.5
423
+ score += efficiency_score * 0.3
424
+
425
+ # Recent usage (20% weight)
426
+ usage_recency = calculate_usage_recency(template)
427
+ score += usage_recency * 0.2
428
+
429
+ score
430
+ end
431
+
432
+ def customize_template_content(template_content, analyzed_requirements)
433
+ customized = template_content.dup
434
+
435
+ # Replace template variables
436
+ customized.gsub!('<%=tool%>', analyzed_requirements[:tool])
437
+ customized.gsub!('<%=model%>', analyzed_requirements[:model])
438
+ customized.gsub!('<%=context_type%>', analyzed_requirements[:context_type])
439
+ customized.gsub!('<%=injection_style%>', analyzed_requirements[:injection_style])
440
+ customized.gsub!('<%=token_budget%>', analyzed_requirements[:token_budget].to_s)
441
+
442
+ # Replace behavioral variables
443
+ behavioral = analyzed_requirements[:behavioral_requirements]
444
+ customized.gsub!('<%=response_style%>', behavioral[:response_style])
445
+ customized.gsub!('<%=thinking_tags%>', behavioral[:thinking_tags].to_s)
446
+
447
+ # Replace optimization variables
448
+ optimization = analyzed_requirements[:optimization_preferences]
449
+ customized.gsub!('<%=token_efficiency%>', optimization[:token_efficiency])
450
+
451
+ # Add project-specific customizations
452
+ project = analyzed_requirements[:project_context]
453
+ customized.gsub!('<%=project_type%>', project[:project_type])
454
+
455
+ customized
456
+ end
457
+
458
+ def generate_parasite_metadata(template, analyzed_requirements, generation_id)
459
+ {
460
+ generated_from_template: template.name,
461
+ template_efficiency_score: template.efficiency_score,
462
+ generation_timestamp: Time.current.iso8601,
463
+ generation_id: generation_id,
464
+ target_tool: analyzed_requirements[:tool],
465
+ target_model: analyzed_requirements[:model],
466
+ behavioral_requirements: analyzed_requirements[:behavioral_requirements],
467
+ optimization_preferences: analyzed_requirements[:optimization_preferences],
468
+ project_context: analyzed_requirements[:project_context]
469
+ }
470
+ end
471
+
472
+ def generate_parasite_name(analyzed_requirements)
473
+ # Create descriptive name based on requirements
474
+ tool = analyzed_requirements[:tool].gsub(/[^a-zA-Z0-9]/, '_')
475
+ model = analyzed_requirements[:model].gsub(/[^a-zA-Z0-9]/, '_')
476
+ timestamp = Time.current.strftime('%Y%m%d_%H%M')
477
+
478
+ "universal_#{tool}_#{model}_#{timestamp}"
479
+ end
480
+
481
+ def generate_default_template_content(analyzed_requirements)
482
+ # Default template when no template is found
483
+ <<~RUBY
484
+ # Universal Parasite for #{analyzed_requirements[:tool]} + #{analyzed_requirements[:model]}
485
+ # Generated by Universal Parasite Generator
486
+
487
+ class Universal#{analyzed_requirements[:tool].capitalize}#{analyzed_requirements[:model].capitalize}Parasite < BaseParasite
488
+ def should_inject?(request_context, user_message)
489
+ # Smart injection logic
490
+ user_message.length > 20 && !simple_greeting?(user_message)
491
+ end
492
+
493
+ def injection_strategy(request_context)
494
+ {
495
+ max_tokens: #{analyzed_requirements[:token_budget]},
496
+ style: :#{analyzed_requirements[:injection_style]},
497
+ context_type: :#{analyzed_requirements[:context_type]}
498
+ }
499
+ end
500
+
501
+ def craft_injection(context, user_message, original_messages)
502
+ return original_messages unless context.present?
503
+
504
+ system_message = {
505
+ 'role' => 'system',
506
+ 'content' => "Context: \#{context}"
507
+ }
508
+
509
+ [system_message] + original_messages
510
+ end
511
+
512
+ private
513
+
514
+ def simple_greeting?(message)
515
+ message.match?(/^(hi|hello|thanks|yes|no|ok)$/i)
516
+ end
517
+ end
518
+ RUBY
519
+ end
520
+
521
+ def generate_fallback_parasite_code(analyzed_requirements)
522
+ generate_default_template_content(analyzed_requirements)
523
+ end
524
+
525
+ def create_parasite_record(parasite_data)
526
+ # This would integrate with the actual Hokipoki::CustomParasite model
527
+ # For now, return a mock record
528
+ {
529
+ id: SecureRandom.uuid,
530
+ name: parasite_data[:name],
531
+ tool: parasite_data[:tool],
532
+ model: parasite_data[:model],
533
+ code: parasite_data[:code],
534
+ metadata: parasite_data[:metadata],
535
+ created_at: Time.current.iso8601
536
+ }
537
+ end
538
+
539
+ def generate_parasite_description(generated_parasite, analyzed_requirements)
540
+ "Universal parasite for #{analyzed_requirements[:tool]} + #{analyzed_requirements[:model]} " \
541
+ "generated from template '#{generated_parasite[:template_source]}' " \
542
+ "with behavioral optimizations: #{generated_parasite[:behavioral_optimizations]&.join(', ') || 'none'}"
543
+ end
544
+
545
+ def create_variant_requirements(base_requirements, variant_index)
546
+ variant = base_requirements.dup
547
+
548
+ # Create variations for A/B testing
549
+ case variant_index
550
+ when 0
551
+ variant[:injection_style] = 'natural'
552
+ variant[:token_efficiency] = 'high'
553
+ when 1
554
+ variant[:injection_style] = 'comprehensive'
555
+ variant[:token_efficiency] = 'medium'
556
+ when 2
557
+ variant[:injection_style] = 'minimal'
558
+ variant[:token_efficiency] = 'high'
559
+ end
560
+
561
+ variant
562
+ end
563
+
564
+ def create_ab_test_configuration(variants)
565
+ {
566
+ test_type: 'parasite_performance',
567
+ traffic_split: 'equal',
568
+ metrics_to_track: %w[injection_success_rate token_efficiency response_quality],
569
+ test_duration: '7_days',
570
+ variants_count: variants.length
571
+ }
572
+ end
573
+
574
+ def handle_generation_error(error, requirements, generation_id)
575
+ {
576
+ success: false,
577
+ error: error.message,
578
+ generation_id: generation_id,
579
+ requirements: requirements,
580
+ timestamp: Time.current.iso8601
581
+ }
582
+ end
583
+
584
+ def calculate_keyword_overlap(template_keywords, requirement_keywords)
585
+ return 0.0 if template_keywords.empty? || requirement_keywords.empty?
586
+
587
+ intersection = template_keywords & requirement_keywords
588
+ union = template_keywords | requirement_keywords
589
+
590
+ intersection.length.to_f / union.length
591
+ end
592
+
593
+ def calculate_usage_recency(template)
594
+ return 0.0 unless template.respond_to?(:updated_at) && template.updated_at
595
+
596
+ days_since_update = (Time.current - template.updated_at) / 1.day
597
+ Math.exp(-days_since_update / 30.0) # Exponential decay over 30 days
598
+ end
599
+
600
+ def optimize_code_for_behavioral_patterns(code, behavioral_patterns)
601
+ optimized = code.dup
602
+
603
+ # Apply thinking tag optimizations
604
+ if behavioral_patterns['thinking_tags']
605
+ optimized = add_thinking_tag_support(optimized)
606
+ end
607
+
608
+ # Apply response style optimizations
609
+ if behavioral_patterns['response_style']
610
+ optimized = adapt_response_style(optimized, behavioral_patterns['response_style'])
611
+ end
612
+
613
+ optimized
614
+ end
615
+
616
+ def add_thinking_tag_support(code)
617
+ # Add thinking tag detection and processing
618
+ code.gsub(
619
+ 'def craft_injection(context, user_message, original_messages)',
620
+ <<~RUBY.strip
621
+ def craft_injection(context, user_message, original_messages)
622
+ # Enhanced with thinking tag support
623
+ RUBY
624
+ )
625
+ end
626
+
627
+ def adapt_response_style(code, response_style)
628
+ # Adapt injection style based on response preferences
629
+ code.gsub('style: :natural', "style: :#{response_style}")
630
+ end
631
+
632
+ def get_llm_behavioral_patterns(target_llm)
633
+ @behavioral_analyzer&.get_patterns_for_llm(target_llm) || {}
634
+ end
635
+
636
+ def generate_id
637
+ "upg_#{Time.current.to_i}_#{SecureRandom.hex(4)}"
638
+ end
639
+
640
+ def load_template_registry
641
+ require_relative '../intelligence/template_registry'
642
+ Intelligence::TemplateRegistry.instance
643
+ rescue LoadError => e
644
+ @logger.warn "Template registry not available: #{e.message}"
645
+ nil
646
+ end
647
+
648
+ def load_embedding_service
649
+ require_relative '../core/embedding_patterns'
650
+ Core::EmbeddingPatterns.new
651
+ rescue LoadError => e
652
+ @logger.debug "Embedding service not available: #{e.message}"
653
+ nil
654
+ end
655
+
656
+ def load_behavioral_analyzer
657
+ # Would load from forge if available
658
+ nil
659
+ end
660
+ end
661
+ end
662
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hokipoki
4
+ class Railtie < ::Rails::Railtie
5
+ railtie_name :hokipoki
6
+
7
+ rake_tasks do
8
+ load 'hokipoki/tasks.rb'
9
+ end
10
+
11
+ generators do
12
+ require 'generators/hive_mind/install_generator'
13
+ require 'generators/hive_mind/brain_generator'
14
+ require 'generators/hive_mind/parasite_generator'
15
+ require 'generators/hive_mind/template_generator'
16
+ require 'generators/hive_mind/security_generator'
17
+ require 'generators/hive_mind/forge_generator'
18
+ require 'generators/hive_mind/claude_cli_generator'
19
+ end
20
+
21
+ initializer "hokipoki.add_locales" do |app|
22
+ config.i18n.load_path += Dir[Hokipoki::Engine.root.join('config', 'locales', '*.{rb,yml}')]
23
+ end
24
+
25
+ initializer "hokipoki.setup_logger" do |app|
26
+ Hokipoki.logger = Rails.logger
27
+ end
28
+
29
+ # Add console helpers
30
+ console do
31
+ require 'hokipoki/console'
32
+ end
33
+ end
34
+ end
@@ -1,3 +1,3 @@
1
1
  module Hokipoki
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end