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.
- checksums.yaml +4 -4
- data/.agentic.yml +2 -0
- data/.architecture/decisions/ArchitecturalFeatureBuilder.md +136 -0
- data/.architecture/decisions/ArchitectureConsiderations.md +200 -0
- data/.architecture/decisions/adr_001_observer_pattern_implementation.md +196 -0
- data/.architecture/decisions/adr_002_plan_orchestrator.md +320 -0
- data/.architecture/decisions/adr_003_plan_orchestrator_interface.md +179 -0
- data/.architecture/decisions/adrs/ADR-001-dependency-management.md +147 -0
- data/.architecture/decisions/adrs/ADR-002-system-boundaries.md +162 -0
- data/.architecture/decisions/adrs/ADR-003-content-safety.md +158 -0
- data/.architecture/decisions/adrs/ADR-004-agent-permissions.md +161 -0
- data/.architecture/decisions/adrs/ADR-005-adaptation-engine.md +127 -0
- data/.architecture/decisions/adrs/ADR-006-extension-system.md +273 -0
- data/.architecture/decisions/adrs/ADR-007-learning-system.md +156 -0
- data/.architecture/decisions/adrs/ADR-008-prompt-generation.md +325 -0
- data/.architecture/decisions/adrs/ADR-009-task-failure-handling.md +353 -0
- data/.architecture/decisions/adrs/ADR-010-task-input-handling.md +251 -0
- data/.architecture/decisions/adrs/ADR-011-task-observable-pattern.md +391 -0
- data/.architecture/decisions/adrs/ADR-012-task-output-handling.md +205 -0
- data/.architecture/decisions/adrs/ADR-013-architecture-alignment.md +211 -0
- data/.architecture/decisions/adrs/ADR-014-agent-capability-registry.md +80 -0
- data/.architecture/decisions/adrs/ADR-015-persistent-agent-store.md +100 -0
- data/.architecture/decisions/adrs/ADR-016-agent-assembly-engine.md +117 -0
- data/.architecture/decisions/adrs/ADR-017-streaming-observability.md +171 -0
- data/.architecture/decisions/capability_tools_distinction.md +150 -0
- data/.architecture/decisions/cli_command_structure.md +61 -0
- data/.architecture/implementation/agent_self_assembly_implementation.md +267 -0
- data/.architecture/implementation/agent_self_assembly_summary.md +138 -0
- data/.architecture/members.yml +187 -0
- data/.architecture/planning/self_implementation_exercise.md +295 -0
- data/.architecture/planning/session_compaction_rule.md +43 -0
- data/.architecture/planning/streaming_observability_feature.md +223 -0
- data/.architecture/principles.md +151 -0
- data/.architecture/recalibration/0-2-0.md +92 -0
- data/.architecture/recalibration/agent_self_assembly.md +238 -0
- data/.architecture/recalibration/cli_command_structure.md +91 -0
- data/.architecture/recalibration/implementation_roadmap_0-2-0.md +301 -0
- data/.architecture/recalibration/progress_tracking_0-2-0.md +114 -0
- data/.architecture/recalibration_process.md +127 -0
- data/.architecture/reviews/0-2-0.md +181 -0
- data/.architecture/reviews/cli_command_duplication.md +98 -0
- data/.architecture/templates/adr.md +105 -0
- data/.architecture/templates/implementation_roadmap.md +125 -0
- data/.architecture/templates/progress_tracking.md +89 -0
- data/.architecture/templates/recalibration_plan.md +70 -0
- data/.architecture/templates/version_comparison.md +124 -0
- data/.claude/settings.local.json +13 -0
- data/.claude-sessions/001-task-class-architecture-implementation.md +129 -0
- data/.claude-sessions/002-plan-orchestrator-interface-review.md +105 -0
- data/.claude-sessions/architecture-governance-implementation.md +37 -0
- data/.claude-sessions/architecture-review-session.md +27 -0
- data/ArchitecturalFeatureBuilder.md +136 -0
- data/ArchitectureConsiderations.md +229 -0
- data/CHANGELOG.md +57 -2
- data/CLAUDE.md +111 -0
- data/CONTRIBUTING.md +286 -0
- data/MAINTAINING.md +301 -0
- data/README.md +582 -28
- data/docs/agent_capabilities_api.md +259 -0
- data/docs/artifact_extension_points.md +757 -0
- data/docs/artifact_generation_architecture.md +323 -0
- data/docs/artifact_implementation_plan.md +596 -0
- data/docs/artifact_integration_points.md +345 -0
- data/docs/artifact_verification_strategies.md +581 -0
- data/docs/streaming_observability_architecture.md +510 -0
- data/exe/agentic +6 -1
- data/lefthook.yml +5 -0
- data/lib/agentic/adaptation_engine.rb +124 -0
- data/lib/agentic/agent.rb +181 -4
- data/lib/agentic/agent_assembly_engine.rb +442 -0
- data/lib/agentic/agent_capability_registry.rb +260 -0
- data/lib/agentic/agent_config.rb +63 -0
- data/lib/agentic/agent_specification.rb +46 -0
- data/lib/agentic/capabilities/examples.rb +530 -0
- data/lib/agentic/capabilities.rb +14 -0
- data/lib/agentic/capability_provider.rb +146 -0
- data/lib/agentic/capability_specification.rb +118 -0
- data/lib/agentic/cli/agent.rb +31 -0
- data/lib/agentic/cli/capabilities.rb +191 -0
- data/lib/agentic/cli/config.rb +134 -0
- data/lib/agentic/cli/execution_observer.rb +796 -0
- data/lib/agentic/cli.rb +1068 -0
- data/lib/agentic/default_agent_provider.rb +35 -0
- data/lib/agentic/errors/llm_error.rb +184 -0
- data/lib/agentic/execution_plan.rb +53 -0
- data/lib/agentic/execution_result.rb +91 -0
- data/lib/agentic/expected_answer_format.rb +46 -0
- data/lib/agentic/extension/domain_adapter.rb +109 -0
- data/lib/agentic/extension/plugin_manager.rb +163 -0
- data/lib/agentic/extension/protocol_handler.rb +116 -0
- data/lib/agentic/extension.rb +45 -0
- data/lib/agentic/factory_methods.rb +9 -1
- data/lib/agentic/generation_stats.rb +61 -0
- data/lib/agentic/learning/README.md +84 -0
- data/lib/agentic/learning/capability_optimizer.rb +613 -0
- data/lib/agentic/learning/execution_history_store.rb +251 -0
- data/lib/agentic/learning/pattern_recognizer.rb +500 -0
- data/lib/agentic/learning/strategy_optimizer.rb +706 -0
- data/lib/agentic/learning.rb +131 -0
- data/lib/agentic/llm_assisted_composition_strategy.rb +188 -0
- data/lib/agentic/llm_client.rb +215 -15
- data/lib/agentic/llm_config.rb +65 -1
- data/lib/agentic/llm_response.rb +163 -0
- data/lib/agentic/logger.rb +1 -1
- data/lib/agentic/observable.rb +51 -0
- data/lib/agentic/persistent_agent_store.rb +385 -0
- data/lib/agentic/plan_execution_result.rb +129 -0
- data/lib/agentic/plan_orchestrator.rb +464 -0
- data/lib/agentic/plan_orchestrator_config.rb +57 -0
- data/lib/agentic/retry_config.rb +63 -0
- data/lib/agentic/retry_handler.rb +125 -0
- data/lib/agentic/structured_outputs.rb +1 -1
- data/lib/agentic/task.rb +193 -0
- data/lib/agentic/task_definition.rb +39 -0
- data/lib/agentic/task_execution_result.rb +92 -0
- data/lib/agentic/task_failure.rb +66 -0
- data/lib/agentic/task_output_schemas.rb +112 -0
- data/lib/agentic/task_planner.rb +54 -19
- data/lib/agentic/task_result.rb +48 -0
- data/lib/agentic/ui.rb +244 -0
- data/lib/agentic/verification/critic_framework.rb +116 -0
- data/lib/agentic/verification/llm_verification_strategy.rb +60 -0
- data/lib/agentic/verification/schema_verification_strategy.rb +47 -0
- data/lib/agentic/verification/verification_hub.rb +62 -0
- data/lib/agentic/verification/verification_result.rb +50 -0
- data/lib/agentic/verification/verification_strategy.rb +26 -0
- data/lib/agentic/version.rb +1 -1
- data/lib/agentic.rb +74 -2
- data/plugins/README.md +41 -0
- metadata +245 -6
@@ -0,0 +1,260 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module Agentic
|
6
|
+
# Central registry for agent capabilities
|
7
|
+
# @attr_reader [Hash] capabilities The registered capabilities by name and version
|
8
|
+
# @attr_reader [Hash] providers The registered capability providers by name and version
|
9
|
+
class AgentCapabilityRegistry
|
10
|
+
include Singleton
|
11
|
+
|
12
|
+
attr_reader :capabilities, :providers
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@capabilities = {}
|
16
|
+
@providers = {}
|
17
|
+
@capability_versions = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Register a capability with the registry
|
21
|
+
# @param capability [CapabilitySpecification] The capability to register
|
22
|
+
# @param provider [CapabilityProvider] The provider of the capability
|
23
|
+
# @return [CapabilitySpecification] The registered capability
|
24
|
+
def register(capability, provider)
|
25
|
+
validate_capability!(capability)
|
26
|
+
|
27
|
+
# Store by name and version
|
28
|
+
@capabilities[capability.name] ||= {}
|
29
|
+
@capabilities[capability.name][capability.version] = capability
|
30
|
+
|
31
|
+
# Track the provider
|
32
|
+
@providers[capability.name] ||= {}
|
33
|
+
@providers[capability.name][capability.version] = provider
|
34
|
+
|
35
|
+
# Update version tracking
|
36
|
+
update_version_tracking(capability)
|
37
|
+
|
38
|
+
# Log the registration
|
39
|
+
Agentic.logger.info("Registered capability: #{capability.name} v#{capability.version}")
|
40
|
+
|
41
|
+
capability
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get a capability by name and version
|
45
|
+
# @param name [String] The name of the capability
|
46
|
+
# @param version [String, nil] The version of the capability, or nil for latest
|
47
|
+
# @return [CapabilitySpecification, nil] The capability or nil if not found
|
48
|
+
def get(name, version = nil)
|
49
|
+
return nil unless @capabilities[name]
|
50
|
+
|
51
|
+
if version.nil?
|
52
|
+
# Get the latest version
|
53
|
+
version = get_latest_version(name)
|
54
|
+
return nil unless version
|
55
|
+
end
|
56
|
+
|
57
|
+
@capabilities[name][version]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get the provider for a capability
|
61
|
+
# @param name [String] The name of the capability
|
62
|
+
# @param version [String, nil] The version of the capability, or nil for latest
|
63
|
+
# @return [CapabilityProvider, nil] The provider or nil if not found
|
64
|
+
def get_provider(name, version = nil)
|
65
|
+
return nil unless @providers[name]
|
66
|
+
|
67
|
+
if version.nil?
|
68
|
+
# Get the latest version
|
69
|
+
version = get_latest_version(name)
|
70
|
+
return nil unless version
|
71
|
+
end
|
72
|
+
|
73
|
+
@providers[name][version]
|
74
|
+
end
|
75
|
+
|
76
|
+
# Find capabilities matching criteria
|
77
|
+
# @param criteria [Hash] The search criteria
|
78
|
+
# @return [Array<CapabilitySpecification>] Matching capabilities
|
79
|
+
def find(criteria = {})
|
80
|
+
# Filter capabilities based on criteria
|
81
|
+
results = []
|
82
|
+
|
83
|
+
@capabilities.each do |name, versions|
|
84
|
+
versions.each do |version, capability|
|
85
|
+
if matches_criteria?(capability, criteria)
|
86
|
+
results << capability
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
results
|
92
|
+
end
|
93
|
+
|
94
|
+
# List all registered capabilities
|
95
|
+
# @param include_providers [Boolean] Whether to include providers in the output
|
96
|
+
# @return [Hash] Map of capability names to arrays of version strings
|
97
|
+
def list(include_providers: false)
|
98
|
+
result = {}
|
99
|
+
|
100
|
+
@capabilities.each do |name, versions|
|
101
|
+
result[name] = {
|
102
|
+
versions: versions.keys,
|
103
|
+
latest: get_latest_version(name)
|
104
|
+
}
|
105
|
+
|
106
|
+
if include_providers
|
107
|
+
result[name][:providers] = {}
|
108
|
+
versions.each do |version, _|
|
109
|
+
result[name][:providers][version] = @providers[name][version] if @providers[name][version]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
result
|
115
|
+
end
|
116
|
+
|
117
|
+
# Compose capabilities into a new capability
|
118
|
+
# @param name [String] The name of the composed capability
|
119
|
+
# @param description [String] Description of the composed capability
|
120
|
+
# @param version [String] The version of the composed capability
|
121
|
+
# @param capabilities [Array<Hash>] The capabilities to compose
|
122
|
+
# @param compose_fn [Proc] The function to use for composition
|
123
|
+
# @return [CapabilitySpecification] The composed capability
|
124
|
+
def compose(name, description, version, capabilities, compose_fn)
|
125
|
+
# Get the individual capabilities
|
126
|
+
capability_instances = []
|
127
|
+
capability_providers = []
|
128
|
+
|
129
|
+
capabilities.each do |cap_spec|
|
130
|
+
cap_name = cap_spec[:name]
|
131
|
+
cap_version = cap_spec[:version]
|
132
|
+
|
133
|
+
capability = get(cap_name, cap_version)
|
134
|
+
raise "Capability not found: #{cap_name} v#{cap_version}" unless capability
|
135
|
+
|
136
|
+
provider = get_provider(cap_name, cap_version)
|
137
|
+
raise "Provider not found for capability: #{cap_name} v#{cap_version}" unless provider
|
138
|
+
|
139
|
+
capability_instances << capability
|
140
|
+
capability_providers << provider
|
141
|
+
end
|
142
|
+
|
143
|
+
# Create the composed capability
|
144
|
+
dependencies = capabilities.map do |cap_spec|
|
145
|
+
{
|
146
|
+
name: cap_spec[:name],
|
147
|
+
version: cap_spec[:version] || get_latest_version(cap_spec[:name])
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
composed_capability = CapabilitySpecification.new(
|
152
|
+
name: name,
|
153
|
+
description: description,
|
154
|
+
version: version,
|
155
|
+
dependencies: dependencies
|
156
|
+
)
|
157
|
+
|
158
|
+
# Create the composed provider
|
159
|
+
composed_provider = CapabilityProvider.new(
|
160
|
+
capability: composed_capability,
|
161
|
+
implementation: lambda do |inputs|
|
162
|
+
# Call the composition function with the individual providers and inputs
|
163
|
+
compose_fn.call(capability_providers, inputs)
|
164
|
+
end
|
165
|
+
)
|
166
|
+
|
167
|
+
# Register the composed capability
|
168
|
+
register(composed_capability, composed_provider)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Clear all registered capabilities
|
172
|
+
# @return [void]
|
173
|
+
def clear
|
174
|
+
@capabilities = {}
|
175
|
+
@providers = {}
|
176
|
+
@capability_versions = {}
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
def validate_capability!(capability)
|
182
|
+
# Validate the capability specification
|
183
|
+
raise "Capability must be a CapabilitySpecification" unless capability.is_a?(CapabilitySpecification)
|
184
|
+
raise "Capability name cannot be empty" if capability.name.nil? || capability.name.empty?
|
185
|
+
raise "Capability version cannot be empty" if capability.version.nil? || capability.version.empty?
|
186
|
+
end
|
187
|
+
|
188
|
+
def update_version_tracking(capability)
|
189
|
+
# Update version tracking for the capability
|
190
|
+
@capability_versions[capability.name] ||= []
|
191
|
+
@capability_versions[capability.name] << capability.version
|
192
|
+
@capability_versions[capability.name].uniq!
|
193
|
+
end
|
194
|
+
|
195
|
+
def get_latest_version(name)
|
196
|
+
# Get the latest version of a capability
|
197
|
+
return nil unless @capability_versions[name] && !@capability_versions[name].empty?
|
198
|
+
|
199
|
+
# Sort versions semantically
|
200
|
+
# For now, just sort by splitting into parts and comparing numerically
|
201
|
+
@capability_versions[name].max do |a, b|
|
202
|
+
a_parts = a.split(".").map(&:to_i)
|
203
|
+
b_parts = b.split(".").map(&:to_i)
|
204
|
+
|
205
|
+
# Compare major version
|
206
|
+
major_comparison = a_parts[0] <=> b_parts[0]
|
207
|
+
next major_comparison unless major_comparison == 0
|
208
|
+
|
209
|
+
# Compare minor version
|
210
|
+
minor_comparison = a_parts[1] <=> b_parts[1]
|
211
|
+
next minor_comparison unless minor_comparison == 0
|
212
|
+
|
213
|
+
# Compare patch version
|
214
|
+
a_parts[2] <=> b_parts[2]
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def matches_criteria?(capability, criteria)
|
219
|
+
# Check if a capability matches the given criteria
|
220
|
+
criteria.all? do |key, value|
|
221
|
+
case key
|
222
|
+
when :name, "name"
|
223
|
+
capability.name == value
|
224
|
+
when :version, "version"
|
225
|
+
capability.version == value
|
226
|
+
when :min_version, "min_version"
|
227
|
+
compare_versions(capability.version, value) >= 0
|
228
|
+
when :max_version, "max_version"
|
229
|
+
compare_versions(capability.version, value) <= 0
|
230
|
+
when :has_input, "has_input"
|
231
|
+
capability.inputs.key?(value.to_sym) || capability.inputs.key?(value.to_s)
|
232
|
+
when :has_output, "has_output"
|
233
|
+
capability.outputs.key?(value.to_sym) || capability.outputs.key?(value.to_s)
|
234
|
+
when :has_dependency, "has_dependency"
|
235
|
+
capability.dependencies.any? { |dep| dep[:name] == value || dep["name"] == value }
|
236
|
+
else
|
237
|
+
# For other criteria, check if the capability responds to the method
|
238
|
+
capability.respond_to?(key) && capability.send(key) == value
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def compare_versions(version_a, version_b)
|
244
|
+
# Compare two version strings
|
245
|
+
a_parts = version_a.split(".").map(&:to_i)
|
246
|
+
b_parts = version_b.split(".").map(&:to_i)
|
247
|
+
|
248
|
+
# Compare major version
|
249
|
+
major_comparison = a_parts[0] <=> b_parts[0]
|
250
|
+
return major_comparison unless major_comparison == 0
|
251
|
+
|
252
|
+
# Compare minor version
|
253
|
+
minor_comparison = a_parts[1] <=> b_parts[1]
|
254
|
+
return minor_comparison unless minor_comparison == 0
|
255
|
+
|
256
|
+
# Compare patch version
|
257
|
+
a_parts[2] <=> b_parts[2]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Agentic
|
4
|
+
# Configuration object for an Agent
|
5
|
+
class AgentConfig
|
6
|
+
# @return [String] The name of the agent
|
7
|
+
attr_accessor :name
|
8
|
+
|
9
|
+
# @return [String] The role of the agent
|
10
|
+
attr_accessor :role
|
11
|
+
|
12
|
+
# @return [String] The backstory or additional context for the agent
|
13
|
+
attr_accessor :backstory
|
14
|
+
|
15
|
+
# @return [Array<String>] The tools available to the agent
|
16
|
+
attr_accessor :tools
|
17
|
+
|
18
|
+
# @return [LlmConfig] The LLM configuration for the agent
|
19
|
+
attr_accessor :llm_config
|
20
|
+
|
21
|
+
# @return [Hash] Additional options for the agent
|
22
|
+
attr_accessor :options
|
23
|
+
|
24
|
+
# Initializes a new agent configuration
|
25
|
+
# @param name [String] The name of the agent
|
26
|
+
# @param role [String] The role of the agent
|
27
|
+
# @param backstory [String, nil] The backstory or additional context for the agent
|
28
|
+
# @param tools [Array<String>] The tools available to the agent
|
29
|
+
# @param llm_config [LlmConfig, nil] The LLM configuration for the agent
|
30
|
+
# @param options [Hash] Additional options for the agent
|
31
|
+
def initialize(
|
32
|
+
name:,
|
33
|
+
role:,
|
34
|
+
backstory: nil,
|
35
|
+
tools: [],
|
36
|
+
llm_config: nil,
|
37
|
+
options: {}
|
38
|
+
)
|
39
|
+
@name = name
|
40
|
+
@role = role
|
41
|
+
@backstory = backstory
|
42
|
+
@tools = tools
|
43
|
+
@llm_config = llm_config || LlmConfig.new
|
44
|
+
@options = options
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns a hash representation of the agent configuration
|
48
|
+
# @return [Hash] The agent configuration as a hash
|
49
|
+
def to_h
|
50
|
+
{
|
51
|
+
name: @name,
|
52
|
+
role: @role,
|
53
|
+
backstory: @backstory,
|
54
|
+
tools: @tools,
|
55
|
+
llm_config: {
|
56
|
+
model: @llm_config.model,
|
57
|
+
temperature: @llm_config.temperature
|
58
|
+
},
|
59
|
+
options: @options
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Agentic
|
4
|
+
# Value object representing requirements for an agent
|
5
|
+
class AgentSpecification
|
6
|
+
# @return [String] The name of the agent
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
# @return [String] A description of the agent
|
10
|
+
attr_reader :description
|
11
|
+
|
12
|
+
# @return [String] Instructions for the agent
|
13
|
+
attr_reader :instructions
|
14
|
+
|
15
|
+
# Initializes a new agent specification
|
16
|
+
# @param name [String] The name of the agent
|
17
|
+
# @param description [String] A description of the agent
|
18
|
+
# @param instructions [String] Instructions for the agent
|
19
|
+
def initialize(name:, description:, instructions:)
|
20
|
+
@name = name
|
21
|
+
@description = description
|
22
|
+
@instructions = instructions
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns a serializable representation of the agent specification
|
26
|
+
# @return [Hash] The agent specification as a hash
|
27
|
+
def to_h
|
28
|
+
{
|
29
|
+
"name" => @name,
|
30
|
+
"description" => @description,
|
31
|
+
"instructions" => @instructions
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates an AgentSpecification from a hash
|
36
|
+
# @param hash [Hash] The hash representation
|
37
|
+
# @return [AgentSpecification] A new agent specification
|
38
|
+
def self.from_hash(hash)
|
39
|
+
new(
|
40
|
+
name: hash["name"],
|
41
|
+
description: hash["description"],
|
42
|
+
instructions: hash["instructions"]
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|