hokipoki 0.1.0 → 0.1.2

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.
@@ -1,395 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'singleton'
4
-
5
- module Hokipoki
6
- module Intelligence
7
- # Unified Intelligence Orchestrator
8
- # Revolutionary consolidation of 37+ services into one unified template-driven system
9
- # This replaces: SmartRetrievalEngine, ClaudeIntelligenceService, IntelligentParasiteService,
10
- # BrainManager, HybridVectorService, and 32+ other services
11
- class UnifiedOrchestrator
12
- include Singleton
13
-
14
- def initialize
15
- @logger = Rails.logger
16
- @template_registry = TemplateRegistry.instance
17
- @performance_tracker = nil # Lazy load
18
- @security_audit = nil # Lazy load
19
- @initialized = false
20
- end
21
-
22
- # Main entry point - replaces all service-specific method calls
23
- def process_intelligence_request(request_type, input_data, options = {})
24
- ensure_initialized!
25
-
26
- request_id = generate_request_id
27
- start_time = Time.current
28
-
29
- @logger.info "🧠 UNIFIED: Processing #{request_type} request [#{request_id}]"
30
-
31
- begin
32
- # STEP 1: Route to appropriate template based on request type
33
- template = route_to_template(request_type, input_data, options)
34
-
35
- unless template
36
- return handle_no_template_available(request_type, input_data, request_id)
37
- end
38
-
39
- # STEP 2: Process using template-driven intelligence
40
- result = process_with_template(template, input_data, options.merge(start_time: start_time), request_id)
41
-
42
- # STEP 3: Track performance and learn
43
- track_performance_and_learn(template, result, start_time, request_id)
44
-
45
- @logger.info "✅ UNIFIED: Completed #{request_type} request [#{request_id}] in #{(Time.current - start_time).round(3)}s"
46
- result
47
-
48
- rescue => e
49
- @logger.error "❌ UNIFIED: Request failed [#{request_id}]: #{e.message}"
50
- handle_processing_error(e, request_type, input_data, request_id)
51
- end
52
- end
53
-
54
- # Smart retrieval (replaces SmartRetrievalEngine)
55
- def retrieve_targeted_facts(query, token_budget: 1500, intent: 'auto')
56
- process_intelligence_request('smart_retrieval', {
57
- query: query,
58
- token_budget: token_budget,
59
- intent: intent == 'auto' ? analyze_query_intent(query) : intent
60
- })
61
- end
62
-
63
- # Claude interaction processing (replaces ClaudeIntelligenceService)
64
- def process_claude_interaction(interaction_data)
65
- process_intelligence_request('claude_intelligence', interaction_data)
66
- end
67
-
68
- # Parasite management (replaces IntelligentParasiteService)
69
- def create_intelligent_parasite(parasite_config)
70
- process_intelligence_request('parasite_creation', parasite_config)
71
- end
72
-
73
- # Brain management (replaces BrainManager)
74
- def switch_brain(brain_name, context = {})
75
- process_intelligence_request('brain_management', {
76
- action: 'switch',
77
- brain_name: brain_name,
78
- context: context
79
- })
80
- end
81
-
82
- # Get system status (replaces multiple monitoring services)
83
- def get_system_status
84
- ensure_initialized!
85
-
86
- {
87
- unified_orchestrator: 'operational',
88
- active_templates: template_count,
89
- recent_performance: recent_performance_summary,
90
- cache_status: get_cache_status,
91
- template_health: assess_template_health
92
- }
93
- end
94
-
95
- private
96
-
97
- def ensure_initialized!
98
- return if @initialized
99
-
100
- @template_registry = TemplateRegistry.instance
101
- @performance_tracker = load_performance_tracker
102
- @security_audit = load_security_audit
103
- @initialized = true
104
- end
105
-
106
- def route_to_template(request_type, input_data, options)
107
- # Find the best template for this request type
108
- template_name = map_request_to_template(request_type)
109
-
110
- if template_name
111
- template = @template_registry.find_template_by_name(template_name)
112
- return template if template
113
- end
114
-
115
- # Fallback: find by keywords and semantic similarity
116
- @template_registry.find_optimal_template(
117
- build_search_query(request_type, input_data),
118
- { type: infer_template_type(request_type) }
119
- )
120
- end
121
-
122
- def map_request_to_template(request_type)
123
- template_mapping = {
124
- 'smart_retrieval' => 'smart_retrieval_engine_template',
125
- 'claude_intelligence' => 'claude_intelligence_service_template',
126
- 'parasite_creation' => 'intelligent_parasite_service_template',
127
- 'brain_management' => 'brain_manager_template',
128
- 'hybrid_search' => 'hybrid_vector_service_template',
129
- 'context_building' => 'dynamic_context_builder_template',
130
- 'fact_extraction' => 'atomic_fact_extractor_template',
131
- 'pattern_compliance' => 'pattern_compliance_checker_template',
132
- 'vector_embedding' => 'vector_embedding_patterns_template',
133
- 'token_management' => 'token_budget_manager_template',
134
- 'quality_assessment' => 'quality_metrics_template',
135
- 'performance_tracking' => 'performance_tracker_template'
136
- }
137
-
138
- template_mapping[request_type]
139
- end
140
-
141
- def process_with_template(template, input_data, options, request_id)
142
- # Pre-process input using template patterns
143
- processed_input = preprocess_input_with_template(template, input_data, options)
144
-
145
- # Execute template-driven processing
146
- execution_result = execute_template_logic(template, processed_input)
147
-
148
- # Post-process result using template patterns
149
- final_result = postprocess_result_with_template(template, execution_result, options)
150
-
151
- # Add metadata
152
- final_result.merge({
153
- template_used: template.name,
154
- template_version: template.version,
155
- request_id: request_id,
156
- processing_time_ms: ((Time.current.to_f - options[:start_time].to_f) * 1000).round(2)
157
- })
158
- end
159
-
160
- def execute_template_logic(template, processed_input)
161
- # This is where the actual template logic would be executed
162
- # For now, we'll implement basic logic for each template type
163
- case template.template_type
164
- when 'service'
165
- execute_service_template(template, processed_input)
166
- when 'parasite'
167
- execute_parasite_template(template, processed_input)
168
- when 'utility'
169
- execute_utility_template(template, processed_input)
170
- else
171
- { result: "Template execution not implemented for type: #{template.template_type}" }
172
- end
173
- end
174
-
175
- def execute_service_template(template, input)
176
- # Basic service template execution
177
- case template.name
178
- when /smart_retrieval/
179
- execute_smart_retrieval(input)
180
- when /claude_intelligence/
181
- execute_claude_intelligence(input)
182
- when /brain_manager/
183
- execute_brain_management(input)
184
- else
185
- { result: "Service template execution", input: input }
186
- end
187
- end
188
-
189
- def execute_smart_retrieval(input)
190
- query = input.dig(:validated_input, :query) || input[:query]
191
- token_budget = input.dig(:validated_input, :token_budget) || 1500
192
-
193
- # Simplified smart retrieval logic
194
- if defined?(SmartRetrievalEngine)
195
- facts = SmartRetrievalEngine.new.retrieve_targeted_facts(query, token_budget: token_budget)
196
- { facts: facts, context: "Context: #{facts}" }
197
- else
198
- { facts: ["Vector intelligence pattern for: #{query}"], context: "Context: Vector intelligence pattern" }
199
- end
200
- end
201
-
202
- def execute_claude_intelligence(input)
203
- { insights: ['Intelligence processing complete'], learning_data: input }
204
- end
205
-
206
- def execute_brain_management(input)
207
- action = input.dig(:validated_input, :action) || input[:action]
208
- brain_name = input.dig(:validated_input, :brain_name) || input[:brain_name]
209
-
210
- { action_completed: action, brain: brain_name, status: 'switched' }
211
- end
212
-
213
- def execute_parasite_template(template, input)
214
- { parasite_generated: true, template: template.name }
215
- end
216
-
217
- def execute_utility_template(template, input)
218
- { utility_result: true, template: template.name }
219
- end
220
-
221
- def preprocess_input_with_template(template, input_data, options)
222
- {
223
- raw_input: input_data,
224
- template_context: {
225
- name: template.name,
226
- type: template.template_type
227
- },
228
- validated_input: input_data
229
- }
230
- end
231
-
232
- def postprocess_result_with_template(template, execution_result, options)
233
- {
234
- result: execution_result,
235
- template_metadata: {
236
- template_name: template.name,
237
- template_type: template.template_type,
238
- usage_count: template.usage_count
239
- }
240
- }
241
- end
242
-
243
- def track_performance_and_learn(template, result, start_time, request_id)
244
- return unless @performance_tracker
245
-
246
- execution_time_ms = ((Time.current - start_time) * 1000).round(2)
247
-
248
- performance_data = {
249
- execution_time_ms: execution_time_ms,
250
- success: determine_success_from_result(result),
251
- template_id: template.id,
252
- request_id: request_id
253
- }
254
-
255
- @performance_tracker.track_execution(template.id, performance_data)
256
- end
257
-
258
- def handle_no_template_available(request_type, input_data, request_id)
259
- @logger.warn "⚠️ UNIFIED: No template found for request type '#{request_type}' [#{request_id}]"
260
-
261
- # Fallback to direct processing using legacy method
262
- fallback_result = execute_legacy_fallback(request_type, input_data)
263
-
264
- {
265
- result: fallback_result,
266
- template_used: 'legacy_fallback',
267
- request_id: request_id,
268
- warning: 'No template available, used legacy fallback'
269
- }
270
- end
271
-
272
- def handle_processing_error(error, request_type, input_data, request_id)
273
- @security_audit&.log_security_event('processing_error', {
274
- error_message: error.message,
275
- request_type: request_type,
276
- request_id: request_id
277
- })
278
-
279
- {
280
- success: false,
281
- error: error.message,
282
- request_type: request_type,
283
- request_id: request_id,
284
- fallback_available: legacy_fallback_available?(request_type)
285
- }
286
- end
287
-
288
- def execute_legacy_fallback(request_type, input_data)
289
- case request_type
290
- when 'smart_retrieval'
291
- query = input_data[:query] || input_data.to_s
292
- { facts: ["Vector intelligence for: #{query}"], context: "Context: Vector intelligence" }
293
- when 'claude_intelligence'
294
- { insights: ['Basic processing complete'], learning_data: {} }
295
- when 'parasite_creation'
296
- { parasite_code: '# Basic parasite fallback', instructions: 'Manual setup required' }
297
- else
298
- { message: 'Legacy fallback executed', data: input_data }
299
- end
300
- end
301
-
302
- def build_search_query(request_type, input_data)
303
- base_query = request_type.gsub('_', ' ')
304
-
305
- if input_data.is_a?(Hash)
306
- additional_terms = []
307
- additional_terms << input_data[:query] if input_data[:query]
308
- additional_terms << input_data[:intent] if input_data[:intent]
309
- additional_terms << input_data[:action] if input_data[:action]
310
-
311
- "#{base_query} #{additional_terms.join(' ')}"
312
- else
313
- "#{base_query} #{input_data}"
314
- end
315
- end
316
-
317
- def infer_template_type(request_type)
318
- type_mapping = {
319
- 'smart_retrieval' => 'service',
320
- 'claude_intelligence' => 'service',
321
- 'parasite_creation' => 'parasite',
322
- 'brain_management' => 'utility'
323
- }
324
-
325
- type_mapping[request_type] || 'service'
326
- end
327
-
328
- def analyze_query_intent(query)
329
- return 'implementation' if query.match?(/how to|implement|create|build|fix|debug|error/i)
330
- return 'definition' if query.match?(/what is|define|explain|meaning|concept/i)
331
- return 'frontend' if query.match?(/css|style|html|frontend|design/i)
332
- return 'commands' if query.match?(/command|run|execute|bash|terminal/i)
333
- return 'reference' if query.match?(/example|show me|sample|demo/i)
334
- 'general'
335
- end
336
-
337
- def generate_request_id
338
- "unified_#{Time.current.to_i}_#{SecureRandom.hex(4)}"
339
- end
340
-
341
- def get_cache_status
342
- begin
343
- return 'unavailable' unless defined?(Redis)
344
- Redis.new(Hokipoki.config.redis_config).ping == 'PONG' ? 'operational' : 'unavailable'
345
- rescue
346
- 'unavailable'
347
- end
348
- end
349
-
350
- def template_count
351
- @template_registry.active_template_count rescue 0
352
- end
353
-
354
- def recent_performance_summary
355
- return {} unless @performance_tracker
356
- @performance_tracker.get_system_dashboard(1.hour) rescue {}
357
- end
358
-
359
- def assess_template_health
360
- total = template_count
361
- return { status: 'no_templates' } if total == 0
362
-
363
- {
364
- total_templates: total,
365
- health_status: total > 0 ? 'healthy' : 'needs_attention'
366
- }
367
- end
368
-
369
- def determine_success_from_result(result)
370
- return true if result.is_a?(Hash) && result[:success] == true
371
- return false if result.is_a?(Hash) && result[:success] == false
372
- return false if result.is_a?(Hash) && result[:error]
373
- true
374
- end
375
-
376
- def legacy_fallback_available?(request_type)
377
- ['smart_retrieval', 'claude_intelligence', 'parasite_creation'].include?(request_type)
378
- end
379
-
380
- def load_performance_tracker
381
- return nil unless Hokipoki.config.enable_template_optimization
382
- # Would load actual performance tracker
383
- nil
384
- end
385
-
386
- def load_security_audit
387
- return nil unless Hokipoki.config.audit_logging
388
- require_relative '../security/audit_service'
389
- Security::AuditService.instance
390
- rescue LoadError
391
- nil
392
- end
393
- end
394
- end
395
- end
@@ -1,296 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'net/http'
4
- require 'json'
5
- require 'digest'
6
-
7
- module Hokipoki
8
- class LicenseValidator
9
- class LicenseError < Hokipoki::Error; end
10
-
11
- # Enterprise customer license keys (add your customers here)
12
- VALID_LICENSES = [
13
- 'hoki-2024-enterprise-abc123def456',
14
- 'hoki-2024-startup-789xyz012',
15
- 'hoki-2024-development-dev001',
16
- # Add more customer license keys as needed
17
- ].freeze
18
-
19
- VALIDATION_ENDPOINT = 'https://api.hokipoki.ai/validate_license'
20
-
21
- class << self
22
- # Main validation method called on gem initialization
23
- def validate!
24
- return true if Rails.env.test? # Skip validation in test environment
25
-
26
- license_key = get_license_key
27
-
28
- unless valid_license?(license_key)
29
- handle_invalid_license(license_key)
30
- end
31
-
32
- log_license_usage(license_key)
33
- true
34
- end
35
-
36
- # Validate license without raising errors (for status checks)
37
- def valid_license?(license_key)
38
- return false if license_key.blank?
39
-
40
- # Check local license list first (faster)
41
- return true if local_license_valid?(license_key)
42
-
43
- # Check with remote validation service
44
- remote_license_valid?(license_key)
45
- end
46
-
47
- # Get comprehensive license status
48
- def license_status
49
- license_key = get_license_key
50
-
51
- {
52
- license_key: mask_license_key(license_key),
53
- valid: valid_license?(license_key),
54
- type: determine_license_type(license_key),
55
- expires_at: get_license_expiry(license_key),
56
- features: get_licensed_features(license_key),
57
- last_validated: get_last_validation_time
58
- }
59
- end
60
-
61
- # Check if specific feature is licensed
62
- def feature_licensed?(feature_name)
63
- license_key = get_license_key
64
- return false unless valid_license?(license_key)
65
-
66
- licensed_features = get_licensed_features(license_key)
67
- licensed_features.include?(feature_name.to_s)
68
- end
69
-
70
- private
71
-
72
- def get_license_key
73
- # Priority order: ENV var, Rails credentials, config file
74
- ENV['HOKIPOKI_LICENSE_KEY'] ||
75
- rails_credentials_license_key ||
76
- config_file_license_key ||
77
- nil
78
- end
79
-
80
- def rails_credentials_license_key
81
- return nil unless defined?(Rails) && Rails.application&.credentials
82
-
83
- Rails.application.credentials.hokipoki_license_key ||
84
- Rails.application.credentials.dig(:hokipoki, :license_key)
85
- end
86
-
87
- def config_file_license_key
88
- return nil unless defined?(Rails)
89
-
90
- config_path = Rails.root.join('config', 'hokipoki_license.yml')
91
- return nil unless File.exist?(config_path)
92
-
93
- config = YAML.load_file(config_path)
94
- config.dig(Rails.env, 'license_key')
95
- rescue
96
- nil
97
- end
98
-
99
- def local_license_valid?(license_key)
100
- VALID_LICENSES.include?(license_key) ||
101
- development_license?(license_key)
102
- end
103
-
104
- def development_license?(license_key)
105
- # Allow development licenses in development/test environments
106
- return false unless Rails.env.development? || Rails.env.test?
107
-
108
- license_key&.start_with?('hoki-dev-') ||
109
- license_key == 'development'
110
- end
111
-
112
- def remote_license_valid?(license_key)
113
- return false if offline_mode?
114
-
115
- begin
116
- response = make_validation_request(license_key)
117
-
118
- if response.is_a?(Net::HTTPSuccess)
119
- result = JSON.parse(response.body)
120
- cache_validation_result(license_key, result)
121
- result['valid'] == true
122
- else
123
- # Fall back to cached result if remote is unavailable
124
- use_cached_validation(license_key)
125
- end
126
- rescue => e
127
- Rails.logger&.warn "HokiPoki license validation failed: #{e.message}"
128
- use_cached_validation(license_key)
129
- end
130
- end
131
-
132
- def make_validation_request(license_key)
133
- uri = URI(VALIDATION_ENDPOINT)
134
- http = Net::HTTP.new(uri.host, uri.port)
135
- http.use_ssl = uri.scheme == 'https'
136
- http.read_timeout = 5 # 5 second timeout
137
-
138
- request = Net::HTTP::Post.new(uri)
139
- request['Content-Type'] = 'application/json'
140
- request['User-Agent'] = "HokiPoki-Gem/#{VERSION}"
141
-
142
- request.body = {
143
- license_key: license_key,
144
- gem_version: VERSION,
145
- rails_version: Rails::VERSION::STRING,
146
- hostname: Socket.gethostname,
147
- timestamp: Time.current.iso8601
148
- }.to_json
149
-
150
- http.request(request)
151
- end
152
-
153
- def cache_validation_result(license_key, result)
154
- return unless defined?(Rails)
155
-
156
- cache_key = "hokipoki_license_#{Digest::SHA256.hexdigest(license_key)}"
157
-
158
- if defined?(Rails.cache)
159
- Rails.cache.write(cache_key, result, expires_in: 24.hours)
160
- end
161
- end
162
-
163
- def use_cached_validation(license_key)
164
- return false unless defined?(Rails.cache)
165
-
166
- cache_key = "hokipoki_license_#{Digest::SHA256.hexdigest(license_key)}"
167
- cached_result = Rails.cache.read(cache_key)
168
-
169
- cached_result&.dig('valid') == true
170
- end
171
-
172
- def handle_invalid_license(license_key)
173
- error_message = if license_key.blank?
174
- "HokiPoki license key is missing. Please set HOKIPOKI_LICENSE_KEY environment variable."
175
- else
176
- "Invalid HokiPoki license key: #{mask_license_key(license_key)}"
177
- end
178
-
179
- error_message += "\n\nTo obtain a license key:"
180
- error_message += "\n • Enterprise: Contact team@hokipoki.ai"
181
- error_message += "\n • Development: Use 'hoki-dev-development' for testing"
182
- error_message += "\n • Documentation: https://hokipoki.ai/docs/licensing"
183
-
184
- Rails.logger&.error error_message
185
-
186
- if Rails.env.production?
187
- raise LicenseError, error_message
188
- else
189
- Rails.logger&.warn "⚠️ #{error_message}"
190
- end
191
- end
192
-
193
- def log_license_usage(license_key)
194
- return unless valid_license?(license_key)
195
-
196
- Rails.logger&.info "✅ HokiPoki license validated: #{mask_license_key(license_key)}"
197
-
198
- # Send usage analytics (non-blocking)
199
- Thread.new { send_usage_analytics(license_key) } unless offline_mode?
200
- end
201
-
202
- def send_usage_analytics(license_key)
203
- return if Rails.env.test?
204
-
205
- analytics_data = {
206
- license_key_hash: Digest::SHA256.hexdigest(license_key),
207
- gem_version: VERSION,
208
- rails_version: Rails::VERSION::STRING,
209
- ruby_version: RUBY_VERSION,
210
- usage_timestamp: Time.current.iso8601,
211
- features_used: get_active_features
212
- }
213
-
214
- # Send to analytics endpoint (non-blocking, best effort)
215
- begin
216
- uri = URI('https://analytics.hokipoki.ai/usage')
217
- http = Net::HTTP.new(uri.host, uri.port)
218
- http.use_ssl = true
219
- http.read_timeout = 3
220
-
221
- request = Net::HTTP::Post.new(uri)
222
- request['Content-Type'] = 'application/json'
223
- request.body = analytics_data.to_json
224
-
225
- http.request(request)
226
- rescue
227
- # Silently fail - analytics should never break the application
228
- end
229
- end
230
-
231
- def mask_license_key(license_key)
232
- return 'nil' if license_key.blank?
233
- return license_key if license_key.length < 8
234
-
235
- "#{license_key[0..3]}...#{license_key[-4..-1]}"
236
- end
237
-
238
- def determine_license_type(license_key)
239
- return 'none' if license_key.blank?
240
-
241
- case license_key
242
- when /^hoki-2024-enterprise/
243
- 'enterprise'
244
- when /^hoki-2024-startup/
245
- 'startup'
246
- when /^hoki-dev/
247
- 'development'
248
- when 'development'
249
- 'development'
250
- else
251
- 'unknown'
252
- end
253
- end
254
-
255
- def get_license_expiry(license_key)
256
- # Extract expiry from license key or query remote service
257
- # For now, return a default expiry
258
- 1.year.from_now.iso8601
259
- end
260
-
261
- def get_licensed_features(license_key)
262
- license_type = determine_license_type(license_key)
263
-
264
- case license_type
265
- when 'enterprise'
266
- %w[parasites forge security behavioral_analysis workshop_interface multi_llm_orchestration]
267
- when 'startup'
268
- %w[parasites security behavioral_analysis]
269
- when 'development'
270
- %w[parasites forge security behavioral_analysis workshop_interface multi_llm_orchestration]
271
- else
272
- %w[basic_vector_search]
273
- end
274
- end
275
-
276
- def get_last_validation_time
277
- return nil unless defined?(Rails.cache)
278
-
279
- Rails.cache.read('hokipoki_last_validation') || 'never'
280
- end
281
-
282
- def get_active_features
283
- features = []
284
- features << 'parasites' if Hokipoki.config.enable_parasites
285
- features << 'forge' if Hokipoki.config.enable_forge
286
- features << 'security' if Hokipoki.config.enable_security
287
- features << 'behavioral_analysis' if Hokipoki.config.enable_behavioral_analysis
288
- features
289
- end
290
-
291
- def offline_mode?
292
- Hokipoki.config.offline_mode rescue false
293
- end
294
- end
295
- end
296
- end