agentic 0.1.0 → 0.2.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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.agentic.yml +2 -0
  3. data/.architecture/decisions/ArchitecturalFeatureBuilder.md +136 -0
  4. data/.architecture/decisions/ArchitectureConsiderations.md +200 -0
  5. data/.architecture/decisions/adr_001_observer_pattern_implementation.md +196 -0
  6. data/.architecture/decisions/adr_002_plan_orchestrator.md +320 -0
  7. data/.architecture/decisions/adr_003_plan_orchestrator_interface.md +179 -0
  8. data/.architecture/decisions/adrs/ADR-001-dependency-management.md +147 -0
  9. data/.architecture/decisions/adrs/ADR-002-system-boundaries.md +162 -0
  10. data/.architecture/decisions/adrs/ADR-003-content-safety.md +158 -0
  11. data/.architecture/decisions/adrs/ADR-004-agent-permissions.md +161 -0
  12. data/.architecture/decisions/adrs/ADR-005-adaptation-engine.md +127 -0
  13. data/.architecture/decisions/adrs/ADR-006-extension-system.md +273 -0
  14. data/.architecture/decisions/adrs/ADR-007-learning-system.md +156 -0
  15. data/.architecture/decisions/adrs/ADR-008-prompt-generation.md +325 -0
  16. data/.architecture/decisions/adrs/ADR-009-task-failure-handling.md +353 -0
  17. data/.architecture/decisions/adrs/ADR-010-task-input-handling.md +251 -0
  18. data/.architecture/decisions/adrs/ADR-011-task-observable-pattern.md +391 -0
  19. data/.architecture/decisions/adrs/ADR-012-task-output-handling.md +205 -0
  20. data/.architecture/decisions/adrs/ADR-013-architecture-alignment.md +211 -0
  21. data/.architecture/decisions/adrs/ADR-014-agent-capability-registry.md +80 -0
  22. data/.architecture/decisions/adrs/ADR-015-persistent-agent-store.md +100 -0
  23. data/.architecture/decisions/adrs/ADR-016-agent-assembly-engine.md +117 -0
  24. data/.architecture/decisions/adrs/ADR-017-streaming-observability.md +171 -0
  25. data/.architecture/decisions/capability_tools_distinction.md +150 -0
  26. data/.architecture/decisions/cli_command_structure.md +61 -0
  27. data/.architecture/implementation/agent_self_assembly_implementation.md +267 -0
  28. data/.architecture/implementation/agent_self_assembly_summary.md +138 -0
  29. data/.architecture/members.yml +187 -0
  30. data/.architecture/planning/self_implementation_exercise.md +295 -0
  31. data/.architecture/planning/session_compaction_rule.md +43 -0
  32. data/.architecture/planning/streaming_observability_feature.md +223 -0
  33. data/.architecture/principles.md +151 -0
  34. data/.architecture/recalibration/0-2-0.md +92 -0
  35. data/.architecture/recalibration/agent_self_assembly.md +238 -0
  36. data/.architecture/recalibration/cli_command_structure.md +91 -0
  37. data/.architecture/recalibration/implementation_roadmap_0-2-0.md +301 -0
  38. data/.architecture/recalibration/progress_tracking_0-2-0.md +114 -0
  39. data/.architecture/recalibration_process.md +127 -0
  40. data/.architecture/reviews/0-2-0.md +181 -0
  41. data/.architecture/reviews/cli_command_duplication.md +98 -0
  42. data/.architecture/templates/adr.md +105 -0
  43. data/.architecture/templates/implementation_roadmap.md +125 -0
  44. data/.architecture/templates/progress_tracking.md +89 -0
  45. data/.architecture/templates/recalibration_plan.md +70 -0
  46. data/.architecture/templates/version_comparison.md +124 -0
  47. data/.claude/settings.local.json +13 -0
  48. data/.claude-sessions/001-task-class-architecture-implementation.md +129 -0
  49. data/.claude-sessions/002-plan-orchestrator-interface-review.md +105 -0
  50. data/.claude-sessions/architecture-governance-implementation.md +37 -0
  51. data/.claude-sessions/architecture-review-session.md +27 -0
  52. data/ArchitecturalFeatureBuilder.md +136 -0
  53. data/ArchitectureConsiderations.md +229 -0
  54. data/CHANGELOG.md +57 -2
  55. data/CLAUDE.md +111 -0
  56. data/CONTRIBUTING.md +286 -0
  57. data/MAINTAINING.md +301 -0
  58. data/README.md +582 -28
  59. data/docs/agent_capabilities_api.md +259 -0
  60. data/docs/artifact_extension_points.md +757 -0
  61. data/docs/artifact_generation_architecture.md +323 -0
  62. data/docs/artifact_implementation_plan.md +596 -0
  63. data/docs/artifact_integration_points.md +345 -0
  64. data/docs/artifact_verification_strategies.md +581 -0
  65. data/docs/streaming_observability_architecture.md +510 -0
  66. data/exe/agentic +6 -1
  67. data/lefthook.yml +5 -0
  68. data/lib/agentic/adaptation_engine.rb +124 -0
  69. data/lib/agentic/agent.rb +181 -4
  70. data/lib/agentic/agent_assembly_engine.rb +442 -0
  71. data/lib/agentic/agent_capability_registry.rb +260 -0
  72. data/lib/agentic/agent_config.rb +63 -0
  73. data/lib/agentic/agent_specification.rb +46 -0
  74. data/lib/agentic/capabilities/examples.rb +530 -0
  75. data/lib/agentic/capabilities.rb +14 -0
  76. data/lib/agentic/capability_provider.rb +146 -0
  77. data/lib/agentic/capability_specification.rb +118 -0
  78. data/lib/agentic/cli/agent.rb +31 -0
  79. data/lib/agentic/cli/capabilities.rb +191 -0
  80. data/lib/agentic/cli/config.rb +134 -0
  81. data/lib/agentic/cli/execution_observer.rb +796 -0
  82. data/lib/agentic/cli.rb +1068 -0
  83. data/lib/agentic/default_agent_provider.rb +35 -0
  84. data/lib/agentic/errors/llm_error.rb +184 -0
  85. data/lib/agentic/execution_plan.rb +53 -0
  86. data/lib/agentic/execution_result.rb +91 -0
  87. data/lib/agentic/expected_answer_format.rb +46 -0
  88. data/lib/agentic/extension/domain_adapter.rb +109 -0
  89. data/lib/agentic/extension/plugin_manager.rb +163 -0
  90. data/lib/agentic/extension/protocol_handler.rb +116 -0
  91. data/lib/agentic/extension.rb +45 -0
  92. data/lib/agentic/factory_methods.rb +9 -1
  93. data/lib/agentic/generation_stats.rb +61 -0
  94. data/lib/agentic/learning/README.md +84 -0
  95. data/lib/agentic/learning/capability_optimizer.rb +613 -0
  96. data/lib/agentic/learning/execution_history_store.rb +251 -0
  97. data/lib/agentic/learning/pattern_recognizer.rb +500 -0
  98. data/lib/agentic/learning/strategy_optimizer.rb +706 -0
  99. data/lib/agentic/learning.rb +131 -0
  100. data/lib/agentic/llm_assisted_composition_strategy.rb +188 -0
  101. data/lib/agentic/llm_client.rb +215 -15
  102. data/lib/agentic/llm_config.rb +65 -1
  103. data/lib/agentic/llm_response.rb +163 -0
  104. data/lib/agentic/logger.rb +1 -1
  105. data/lib/agentic/observable.rb +51 -0
  106. data/lib/agentic/persistent_agent_store.rb +385 -0
  107. data/lib/agentic/plan_execution_result.rb +129 -0
  108. data/lib/agentic/plan_orchestrator.rb +464 -0
  109. data/lib/agentic/plan_orchestrator_config.rb +57 -0
  110. data/lib/agentic/retry_config.rb +63 -0
  111. data/lib/agentic/retry_handler.rb +125 -0
  112. data/lib/agentic/structured_outputs.rb +1 -1
  113. data/lib/agentic/task.rb +193 -0
  114. data/lib/agentic/task_definition.rb +39 -0
  115. data/lib/agentic/task_execution_result.rb +92 -0
  116. data/lib/agentic/task_failure.rb +66 -0
  117. data/lib/agentic/task_output_schemas.rb +112 -0
  118. data/lib/agentic/task_planner.rb +54 -19
  119. data/lib/agentic/task_result.rb +48 -0
  120. data/lib/agentic/ui.rb +244 -0
  121. data/lib/agentic/verification/critic_framework.rb +116 -0
  122. data/lib/agentic/verification/llm_verification_strategy.rb +60 -0
  123. data/lib/agentic/verification/schema_verification_strategy.rb +47 -0
  124. data/lib/agentic/verification/verification_hub.rb +62 -0
  125. data/lib/agentic/verification/verification_result.rb +50 -0
  126. data/lib/agentic/verification/verification_strategy.rb +26 -0
  127. data/lib/agentic/version.rb +1 -1
  128. data/lib/agentic.rb +74 -2
  129. data/plugins/README.md +41 -0
  130. metadata +245 -6
@@ -0,0 +1,613 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Agentic
4
+ module Learning
5
+ # CapabilityOptimizer improves capability implementations and composition
6
+ # based on execution history and performance metrics.
7
+ #
8
+ # @example Optimizing a capability implementation
9
+ # history_store = Agentic::Learning::ExecutionHistoryStore.new
10
+ # recognizer = Agentic::Learning::PatternRecognizer.new(history_store: history_store)
11
+ # optimizer = Agentic::Learning::CapabilityOptimizer.new(
12
+ # pattern_recognizer: recognizer,
13
+ # history_store: history_store,
14
+ # registry: Agentic.agent_capability_registry
15
+ # )
16
+ #
17
+ # # Get optimization suggestions for a capability
18
+ # suggestions = optimizer.get_optimization_suggestions("text_generation")
19
+ #
20
+ class CapabilityOptimizer
21
+ # Initialize a new CapabilityOptimizer
22
+ #
23
+ # @param options [Hash] Configuration options
24
+ # @option options [Logger] :logger Custom logger (defaults to Agentic.logger)
25
+ # @option options [PatternRecognizer] :pattern_recognizer Pattern recognizer for insights
26
+ # @option options [ExecutionHistoryStore] :history_store History store for performance data
27
+ # @option options [AgentCapabilityRegistry] :registry The capability registry
28
+ # @option options [LlmClient] :llm_client LLM client for generating optimizations (optional)
29
+ # @option options [Boolean] :auto_apply_optimizations Whether to automatically apply optimizations
30
+ def initialize(options = {})
31
+ @logger = options[:logger] || Agentic.logger
32
+ @pattern_recognizer = options[:pattern_recognizer] || raise(ArgumentError, "pattern_recognizer is required")
33
+ @history_store = options[:history_store] || raise(ArgumentError, "history_store is required")
34
+ @registry = options[:registry] || Agentic.agent_capability_registry
35
+ @llm_client = options[:llm_client]
36
+ @auto_apply_optimizations = options.fetch(:auto_apply_optimizations, false)
37
+ @optimization_cache = {}
38
+ @last_optimization = {}
39
+ end
40
+
41
+ # Get optimization suggestions for a capability
42
+ #
43
+ # @param capability_name [String] The name of the capability
44
+ # @param version [String, nil] The version of the capability (latest if nil)
45
+ # @param options [Hash] Additional options
46
+ # @option options [Boolean] :force Force new suggestions even if recently generated
47
+ # @return [Hash] Optimization suggestions
48
+ def get_optimization_suggestions(capability_name, version = nil, options = {})
49
+ # Get the capability from the registry
50
+ capability = @registry.get(capability_name, version)
51
+ return {success: false, reason: "Capability not found"} unless capability
52
+
53
+ version = capability.version
54
+ cache_key = "#{capability_name}:#{version}"
55
+
56
+ # Check cache
57
+ unless options[:force]
58
+ if @optimization_cache[cache_key] && @last_optimization[cache_key] &&
59
+ @last_optimization[cache_key] > Time.now - 24 * 60 * 60
60
+ return @optimization_cache[cache_key]
61
+ end
62
+ end
63
+
64
+ # Get capability execution history
65
+ history = get_capability_history(capability_name, version)
66
+
67
+ # Check if we have enough data
68
+ if history.size < 10
69
+ result = {
70
+ success: false,
71
+ reason: "Insufficient execution data",
72
+ capability: capability_name,
73
+ version: version,
74
+ suggestions: []
75
+ }
76
+
77
+ @optimization_cache[cache_key] = result
78
+ @last_optimization[cache_key] = Time.now
79
+
80
+ return result
81
+ end
82
+
83
+ # Analyze performance
84
+ performance = analyze_capability_performance(history)
85
+
86
+ # Generate suggestions
87
+ suggestions = generate_optimization_suggestions(capability, performance)
88
+
89
+ result = {
90
+ success: true,
91
+ capability: capability_name,
92
+ version: version,
93
+ performance: performance,
94
+ suggestions: suggestions
95
+ }
96
+
97
+ @optimization_cache[cache_key] = result
98
+ @last_optimization[cache_key] = Time.now
99
+
100
+ result
101
+ end
102
+
103
+ # Optimize capability composition for a task
104
+ #
105
+ # @param task [Task] The task to optimize capabilities for
106
+ # @param options [Hash] Additional options
107
+ # @return [Hash] Optimized capability composition
108
+ def optimize_capability_composition(task, options = {})
109
+ # Get task description
110
+ description = task.description
111
+
112
+ # Get currently used capabilities
113
+ if task.input && task.input[:capabilities]
114
+ current_capabilities = task.input[:capabilities]
115
+ else
116
+ # If no capabilities specified, use default inference
117
+ requirements = {}
118
+ if task.agent_spec
119
+ engine = Agentic::AgentAssemblyEngine.new(@registry)
120
+ requirements = engine.analyze_requirements(task)
121
+ end
122
+
123
+ current_capabilities = requirements.keys
124
+ end
125
+
126
+ # No need to optimize if no capabilities
127
+ if current_capabilities.empty?
128
+ return {
129
+ success: false,
130
+ reason: "No capabilities to optimize",
131
+ original_capabilities: [],
132
+ optimized_capabilities: []
133
+ }
134
+ end
135
+
136
+ # Get capability performance data
137
+ capability_performance = {}
138
+ current_capabilities.each do |capability|
139
+ suggestions = get_optimization_suggestions(capability.to_s)
140
+ capability_performance[capability.to_s] = suggestions[:performance] if suggestions[:success]
141
+ end
142
+
143
+ # Generate optimized composition
144
+ if @llm_client
145
+ generate_optimized_composition_with_llm(
146
+ description,
147
+ current_capabilities,
148
+ capability_performance,
149
+ options
150
+ )
151
+ else
152
+ generate_optimized_composition_heuristic(
153
+ description,
154
+ current_capabilities,
155
+ capability_performance,
156
+ options
157
+ )
158
+ end
159
+ end
160
+
161
+ # Apply optimization to a capability
162
+ #
163
+ # @param capability_name [String] The name of the capability
164
+ # @param optimization [Hash] The optimization to apply
165
+ # @param options [Hash] Additional options
166
+ # @return [Boolean] Whether the optimization was applied successfully
167
+ def apply_optimization(capability_name, optimization, options = {})
168
+ # Get the capability and provider
169
+ capability = @registry.get(capability_name)
170
+ return false unless capability
171
+
172
+ provider = @registry.get_provider(capability_name)
173
+ return false unless provider
174
+
175
+ # Check optimization type
176
+ case optimization[:type]
177
+ when :implementation
178
+ # For implementation optimizations, we would need to create a new provider
179
+ # This is a simplified example - in a real implementation, we would need to
180
+ # handle different implementation types (Proc, Class, etc.)
181
+ if provider.implementation.is_a?(Proc) && optimization[:new_implementation].is_a?(Proc)
182
+ # Create a new provider with the optimized implementation
183
+ new_provider = Agentic::CapabilityProvider.new(
184
+ capability: capability,
185
+ implementation: optimization[:new_implementation]
186
+ )
187
+
188
+ # Register the new provider
189
+ @registry.register(capability, new_provider)
190
+
191
+ return true
192
+ end
193
+ when :parameters
194
+ # For parameter optimizations, we would update the capability's parameters
195
+ # This is a simplified example - in a real implementation, we would need to
196
+ # handle different parameter types
197
+ if optimization[:parameters].is_a?(Hash)
198
+ # Update parameters (this would depend on the actual capability implementation)
199
+ # For this example, we just log that we would update the parameters
200
+ @logger.info("Would update parameters for #{capability_name}: #{optimization[:parameters]}")
201
+
202
+ return true
203
+ end
204
+ end
205
+
206
+ false
207
+ end
208
+
209
+ # Record capability execution metrics
210
+ #
211
+ # @param capability_name [String] The name of the capability
212
+ # @param version [String] The version of the capability
213
+ # @param metrics [Hash] The execution metrics
214
+ # @param result [Hash] The execution result
215
+ # @return [Boolean] Whether the metrics were recorded successfully
216
+ def record_execution(capability_name, version, metrics, result)
217
+ success = result && !result.key?(:error)
218
+
219
+ @history_store.record_execution(
220
+ capability_name: capability_name,
221
+ capability_version: version,
222
+ duration_ms: metrics[:duration_ms],
223
+ success: success,
224
+ metrics: metrics,
225
+ context: {
226
+ result_summary: summarize_result(result),
227
+ error: (result && result[:error]) ? result[:error] : nil
228
+ }
229
+ )
230
+
231
+ true
232
+ end
233
+
234
+ private
235
+
236
+ # Get execution history for a capability
237
+ def get_capability_history(capability_name, version)
238
+ # Get execution history for this capability
239
+ end_time = Time.now
240
+ start_time = end_time - (30 * 24 * 60 * 60) # 30 days
241
+
242
+ @history_store.get_history(
243
+ capability_name: capability_name,
244
+ capability_version: version,
245
+ start_time: start_time,
246
+ end_time: end_time
247
+ )
248
+ end
249
+
250
+ # Analyze capability performance based on history
251
+ def analyze_capability_performance(history)
252
+ # Calculate success rate
253
+ total = history.size
254
+ successful = history.count { |h| h[:success] }
255
+ success_rate = successful.to_f / total
256
+
257
+ # Calculate average duration
258
+ durations = history.map { |h| h[:duration_ms] }.compact
259
+ avg_duration = durations.empty? ? nil : durations.sum / durations.size.to_f
260
+
261
+ # Calculate trend
262
+ if history.size >= 10
263
+ recent = history.first(5)
264
+ older = history.last(5)
265
+
266
+ recent_success = recent.count { |h| h[:success] }.to_f / recent.size
267
+ older_success = older.count { |h| h[:success] }.to_f / older.size
268
+
269
+ trend = if (recent_success - older_success).abs < 0.1
270
+ :stable
271
+ elsif recent_success > older_success
272
+ :improving
273
+ else
274
+ :declining
275
+ end
276
+ else
277
+ trend = :unknown
278
+ end
279
+
280
+ # Calculate error patterns
281
+ errors = history.select { |h| !h[:success] && h[:context] && h[:context][:error] }
282
+ error_patterns = {}
283
+
284
+ errors.each do |error|
285
+ message = error[:context][:error].to_s
286
+ error_patterns[message] ||= 0
287
+ error_patterns[message] += 1
288
+ end
289
+
290
+ top_errors = error_patterns.sort_by { |_, count| -count }.first(3).map do |message, count|
291
+ {message: message, count: count}
292
+ end
293
+
294
+ {
295
+ success_rate: success_rate,
296
+ avg_duration_ms: avg_duration,
297
+ total_executions: total,
298
+ trend: trend,
299
+ top_errors: top_errors
300
+ }
301
+ end
302
+
303
+ # Generate optimization suggestions for a capability
304
+ def generate_optimization_suggestions(capability, performance)
305
+ suggestions = []
306
+
307
+ # Check success rate
308
+ if performance[:success_rate] < 0.8
309
+ suggestions << {
310
+ type: :reliability,
311
+ importance: :high,
312
+ message: "Improve reliability to address the #{performance[:success_rate] * 100}% success rate"
313
+ }
314
+
315
+ # Add specific suggestions based on error patterns
316
+ performance[:top_errors].each do |error|
317
+ suggestions << {
318
+ type: :error_handling,
319
+ importance: :high,
320
+ message: "Address common error: #{error[:message]} (#{error[:count]} occurrences)"
321
+ }
322
+ end
323
+ end
324
+
325
+ # Check performance
326
+ if performance[:avg_duration_ms] && performance[:avg_duration_ms] > 1000
327
+ suggestions << {
328
+ type: :performance,
329
+ importance: :medium,
330
+ message: "Improve performance to reduce average duration (#{performance[:avg_duration_ms].round}ms)"
331
+ }
332
+ end
333
+
334
+ # Check trend
335
+ if performance[:trend] == :declining
336
+ suggestions << {
337
+ type: :trend,
338
+ importance: :high,
339
+ message: "Address declining success rate trend"
340
+ }
341
+ end
342
+
343
+ # Add dependency suggestions
344
+ if capability.dependencies&.any?
345
+ dependency_names = capability.dependencies.map { |d| d[:name] }
346
+
347
+ dependency_names.each do |dep_name|
348
+ dep_suggestions = get_optimization_suggestions(dep_name)
349
+
350
+ if dep_suggestions[:success] && dep_suggestions[:performance][:success_rate] < 0.9
351
+ suggestions << {
352
+ type: :dependency,
353
+ importance: :medium,
354
+ message: "Improve or replace dependency: #{dep_name} (#{dep_suggestions[:performance][:success_rate] * 100}% success rate)"
355
+ }
356
+ end
357
+ end
358
+ end
359
+
360
+ # Use LLM for advanced suggestions if available
361
+ if @llm_client && performance[:total_executions] >= 20
362
+ llm_suggestions = generate_llm_suggestions(capability, performance)
363
+ suggestions.concat(llm_suggestions) if llm_suggestions.any?
364
+ end
365
+
366
+ suggestions
367
+ end
368
+
369
+ # Generate suggestions using LLM
370
+ def generate_llm_suggestions(capability, performance)
371
+ # Format the capability details
372
+ capability_details = <<~DETAILS
373
+ Capability: #{capability.name} v#{capability.version}
374
+ Description: #{capability.description}
375
+ Inputs: #{capability.inputs.map { |name, spec| "#{name} (#{spec[:type] || "any"})" }.join(", ")}
376
+ Outputs: #{capability.outputs.map { |name, spec| "#{name} (#{spec[:type] || "any"})" }.join(", ")}
377
+ Dependencies: #{capability.dependencies.map { |d| "#{d[:name]} v#{d[:version]}" }.join(", ")}
378
+ DETAILS
379
+
380
+ # Format the performance details
381
+ performance_details = <<~DETAILS
382
+ Success Rate: #{(performance[:success_rate] * 100).round(1)}%
383
+ Average Duration: #{performance[:avg_duration_ms] ? "#{performance[:avg_duration_ms].round}ms" : "Unknown"}
384
+ Total Executions: #{performance[:total_executions]}
385
+ Trend: #{performance[:trend]}
386
+ Top Errors: #{performance[:top_errors].map { |e| "#{e[:message]} (#{e[:count]} occurrences)" }.join(", ")}
387
+ DETAILS
388
+
389
+ # Create the prompt
390
+ prompt = <<~PROMPT
391
+ As an AI specialized in optimizing AI agent capabilities, please analyze this capability and its performance metrics.
392
+
393
+ Capability Details:
394
+ #{capability_details}
395
+
396
+ Performance Metrics:
397
+ #{performance_details}
398
+
399
+ Based on this information, provide 2-3 specific optimization suggestions that could improve this capability's
400
+ performance, reliability, or effectiveness. Focus on practical, implementable changes rather than general advice.
401
+
402
+ Format your response as a JSON array of suggestion objects, each with:
403
+ - type: The type of suggestion (implementation, parameters, error_handling, etc.)
404
+ - importance: The importance level (high, medium, low)
405
+ - message: A clear, specific suggestion message
406
+ - details: Optional implementation details or examples
407
+ PROMPT
408
+
409
+ # Get suggestions from the LLM
410
+ response = @llm_client.complete(
411
+ prompt: prompt,
412
+ response_format: {type: "json"}
413
+ )
414
+
415
+ # Parse the response
416
+ begin
417
+ suggestions = JSON.parse(response.to_s, symbolize_names: true)
418
+
419
+ if suggestions.is_a?(Array)
420
+ suggestions
421
+ elsif suggestions.is_a?(Hash) && suggestions[:suggestions].is_a?(Array)
422
+ suggestions[:suggestions]
423
+ else
424
+ @logger.warn("Unexpected LLM response format for capability suggestions")
425
+ []
426
+ end
427
+ rescue => e
428
+ @logger.error("Failed to parse LLM capability suggestions: #{e.message}")
429
+ []
430
+ end
431
+ end
432
+
433
+ # Generate optimized capability composition using LLM
434
+ def generate_optimized_composition_with_llm(description, current_capabilities, capability_performance, options)
435
+ # Format current capabilities
436
+ capabilities_text = current_capabilities.map do |capability|
437
+ perf = capability_performance[capability.to_s]
438
+ if perf
439
+ "- #{capability} (Success rate: #{(perf[:success_rate] * 100).round(1)}%, " \
440
+ "Avg duration: #{perf[:avg_duration_ms] ? "#{perf[:avg_duration_ms].round}ms" : "Unknown"})"
441
+ else
442
+ "- #{capability} (No performance data available)"
443
+ end
444
+ end.join("\n")
445
+
446
+ # Get all available capabilities
447
+ available_capabilities = @registry.list.keys - current_capabilities.map(&:to_s)
448
+ available_text = available_capabilities.map { |c| "- #{c}" }.join("\n")
449
+
450
+ # Create the prompt
451
+ prompt = <<~PROMPT
452
+ As an AI specialized in composing capabilities for AI agents, please analyze this task and the currently used capabilities.
453
+
454
+ Task Description:
455
+ #{description}
456
+
457
+ Currently Used Capabilities:
458
+ #{capabilities_text}
459
+
460
+ Other Available Capabilities:
461
+ #{available_text}
462
+
463
+ Based on this information, suggest an optimized set of capabilities for this task. You can:
464
+ 1. Keep capabilities that are well-suited for the task
465
+ 2. Remove capabilities that are unnecessary or underperforming
466
+ 3. Add new capabilities from the available list that would enhance task performance
467
+ 4. Suggest a different composition or sequence of capabilities
468
+
469
+ Format your response as a JSON object with:
470
+ {
471
+ "optimized_capabilities": ["capability1", "capability2", ...],
472
+ "additions": ["new_capability1", ...],
473
+ "removals": ["removed_capability1", ...],
474
+ "rationale": "Explanation of your changes"
475
+ }
476
+ PROMPT
477
+
478
+ # Get suggestions from the LLM
479
+ response = @llm_client.complete(
480
+ prompt: prompt,
481
+ response_format: {type: "json"}
482
+ )
483
+
484
+ # Parse the response
485
+ begin
486
+ result = JSON.parse(response.to_s, symbolize_names: true)
487
+
488
+ if result[:optimized_capabilities].is_a?(Array)
489
+ {
490
+ success: true,
491
+ original_capabilities: current_capabilities,
492
+ optimized_capabilities: result[:optimized_capabilities],
493
+ additions: result[:additions] || [],
494
+ removals: result[:removals] || [],
495
+ rationale: result[:rationale] || "No rationale provided"
496
+ }
497
+ else
498
+ @logger.warn("Unexpected LLM response format for capability composition")
499
+ {
500
+ success: false,
501
+ reason: "Failed to generate optimized composition",
502
+ original_capabilities: current_capabilities,
503
+ optimized_capabilities: current_capabilities
504
+ }
505
+ end
506
+ rescue => e
507
+ @logger.error("Failed to parse LLM capability composition: #{e.message}")
508
+ {
509
+ success: false,
510
+ reason: "Failed to parse optimization response",
511
+ original_capabilities: current_capabilities,
512
+ optimized_capabilities: current_capabilities
513
+ }
514
+ end
515
+ end
516
+
517
+ # Generate optimized capability composition using heuristics
518
+ def generate_optimized_composition_heuristic(description, current_capabilities, capability_performance, options)
519
+ optimized = current_capabilities.dup
520
+ additions = []
521
+ removals = []
522
+ changes = []
523
+
524
+ # Remove low-performing capabilities
525
+ current_capabilities.each do |capability|
526
+ capability_name = capability.to_s
527
+ perf = capability_performance[capability_name]
528
+
529
+ if perf && perf[:success_rate] < 0.5 && perf[:total_executions] > 10
530
+ # Only remove if it's not a critical capability
531
+ # This is a simplified check - in a real implementation, we would need
532
+ # to determine if a capability is critical based on the task
533
+ unless description.downcase.include?(capability_name.downcase)
534
+ optimized.delete(capability)
535
+ removals << capability_name
536
+ changes << "Removed low-performing capability: #{capability_name} (#{(perf[:success_rate] * 100).round}% success rate)"
537
+ end
538
+ end
539
+ end
540
+
541
+ # Add capabilities based on task description
542
+ available_capabilities = @registry.list.keys - current_capabilities.map(&:to_s)
543
+
544
+ available_capabilities.each do |capability|
545
+ # Check if the capability is relevant to the task
546
+ # This is a simplified check - in a real implementation, we would need
547
+ # a more sophisticated relevance determination
548
+ if description.downcase.include?(capability.downcase)
549
+ optimized << capability
550
+ additions << capability
551
+ changes << "Added potentially relevant capability: #{capability}"
552
+ end
553
+ end
554
+
555
+ # Handle common combinations
556
+ if optimized.include?("data_analysis") && !optimized.include?("text_generation")
557
+ optimized << "text_generation"
558
+ additions << "text_generation"
559
+ changes << "Added text_generation to support data_analysis"
560
+ end
561
+
562
+ if optimized.include?("web_search") && !optimized.include?("summarization")
563
+ optimized << "summarization"
564
+ additions << "summarization"
565
+ changes << "Added summarization to process web_search results"
566
+ end
567
+
568
+ if changes.empty?
569
+ {
570
+ success: false,
571
+ reason: "No composition improvements identified",
572
+ original_capabilities: current_capabilities,
573
+ optimized_capabilities: current_capabilities
574
+ }
575
+ else
576
+ {
577
+ success: true,
578
+ original_capabilities: current_capabilities,
579
+ optimized_capabilities: optimized,
580
+ additions: additions,
581
+ removals: removals,
582
+ rationale: "Applied composition optimizations: #{changes.join(", ")}"
583
+ }
584
+ end
585
+ end
586
+
587
+ # Summarize a result for storage
588
+ def summarize_result(result)
589
+ return "No result" unless result
590
+
591
+ if result[:error]
592
+ "Error: #{result[:error]}"
593
+ else
594
+ summary = []
595
+
596
+ result.each do |key, value|
597
+ summary << if value.is_a?(String)
598
+ "#{key}: #{value.length} chars"
599
+ elsif value.is_a?(Array)
600
+ "#{key}: #{value.length} items"
601
+ elsif value.is_a?(Hash)
602
+ "#{key}: #{value.keys.join(", ")}"
603
+ else
604
+ "#{key}: #{value}"
605
+ end
606
+ end
607
+
608
+ summary.join(", ")
609
+ end
610
+ end
611
+ end
612
+ end
613
+ end