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,251 @@
|
|
1
|
+
# Task Input Handling
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
This document specifies the architecture for handling task inputs within the Agentic framework, addressing how inputs are structured, validated, and utilized. Task inputs serve as the foundation for successful task execution, provide context, and enable effective task chaining.
|
6
|
+
|
7
|
+
## Core Principles
|
8
|
+
|
9
|
+
1. **Consistency**: Task inputs follow standardized formats for interoperability
|
10
|
+
2. **Contextual Awareness**: Inputs include relevant context from the overall plan
|
11
|
+
3. **Validation**: Inputs undergo validation before task execution
|
12
|
+
4. **Transformation**: Outputs from previous tasks can be transformed into inputs for subsequent tasks
|
13
|
+
5. **Dependency Management**: Inputs clearly express dependencies on other tasks
|
14
|
+
|
15
|
+
## Input Structure
|
16
|
+
|
17
|
+
Task inputs should adhere to a consistent structure:
|
18
|
+
|
19
|
+
```
|
20
|
+
{
|
21
|
+
"parameters": {
|
22
|
+
// Domain-specific input parameters
|
23
|
+
},
|
24
|
+
"context": {
|
25
|
+
"plan_id": "uuid",
|
26
|
+
"goal": "Original goal description",
|
27
|
+
"previous_task_outputs": {
|
28
|
+
"task_uuid1": { /* Reference to output */ },
|
29
|
+
"task_uuid2": { /* Reference to output */ }
|
30
|
+
},
|
31
|
+
"user_context": {
|
32
|
+
// User-specific context
|
33
|
+
},
|
34
|
+
"environment": {
|
35
|
+
// Execution environment information
|
36
|
+
}
|
37
|
+
},
|
38
|
+
"constraints": {
|
39
|
+
"time_limit_ms": 60000,
|
40
|
+
"token_limit": 8000,
|
41
|
+
"required_outputs": ["field1", "field2"]
|
42
|
+
},
|
43
|
+
"metadata": {
|
44
|
+
"created_at": "ISO8601",
|
45
|
+
"creator_id": "uuid",
|
46
|
+
"version": "1.0",
|
47
|
+
"priority": "high"
|
48
|
+
}
|
49
|
+
}
|
50
|
+
```
|
51
|
+
|
52
|
+
## Input Sources
|
53
|
+
|
54
|
+
Task inputs can originate from several sources:
|
55
|
+
|
56
|
+
### 1. Plan Generation
|
57
|
+
|
58
|
+
The TaskPlanner generates initial inputs based on:
|
59
|
+
- The original goal
|
60
|
+
- User preferences
|
61
|
+
- Domain-specific requirements
|
62
|
+
- System configuration
|
63
|
+
|
64
|
+
Implementation considerations:
|
65
|
+
- Input schema derivation from goal analysis
|
66
|
+
- Parameter extraction from natural language
|
67
|
+
- Constraint identification from system capabilities
|
68
|
+
- Context gathering from user information
|
69
|
+
|
70
|
+
### 2. Task Chaining
|
71
|
+
|
72
|
+
Subsequent tasks receive inputs derived from previous task outputs:
|
73
|
+
|
74
|
+
```
|
75
|
+
TaskA.output → InputTransformer → TaskB.input
|
76
|
+
```
|
77
|
+
|
78
|
+
Implementation considerations:
|
79
|
+
- Output-to-input mapping definitions
|
80
|
+
- Schema compatibility verification
|
81
|
+
- Selective information transfer
|
82
|
+
- Context accumulation or filtering
|
83
|
+
|
84
|
+
### 3. Human Intervention
|
85
|
+
|
86
|
+
Human feedback can modify or augment task inputs:
|
87
|
+
|
88
|
+
```
|
89
|
+
Task.input → Human Intervention → Modified Task.input
|
90
|
+
```
|
91
|
+
|
92
|
+
Implementation considerations:
|
93
|
+
- User-friendly input editing interface
|
94
|
+
- Validation of human-provided inputs
|
95
|
+
- Clear indication of human modifications
|
96
|
+
- Version tracking of input changes
|
97
|
+
|
98
|
+
### 4. Environmental Sources
|
99
|
+
|
100
|
+
External systems can provide inputs through connectors:
|
101
|
+
|
102
|
+
```
|
103
|
+
External API → Connector → Input Transformation → Task.input
|
104
|
+
```
|
105
|
+
|
106
|
+
Implementation considerations:
|
107
|
+
- Authentication and authorization
|
108
|
+
- Rate limiting and caching
|
109
|
+
- Error handling for external dependencies
|
110
|
+
- Data sanitization and normalization
|
111
|
+
|
112
|
+
## Input Processing Patterns
|
113
|
+
|
114
|
+
### 1. Validation and Normalization
|
115
|
+
|
116
|
+
Inputs undergo validation and normalization before execution:
|
117
|
+
|
118
|
+
```
|
119
|
+
Raw Input → Schema Validation → Type Conversion → Normalization → Validated Input
|
120
|
+
```
|
121
|
+
|
122
|
+
Implementation considerations:
|
123
|
+
- Schema-based validation using StructuredInputs module
|
124
|
+
- Type coercion for compatibility
|
125
|
+
- Default value application
|
126
|
+
- Required field verification
|
127
|
+
|
128
|
+
### 2. Dependency Resolution
|
129
|
+
|
130
|
+
Inputs with dependencies are resolved before task execution:
|
131
|
+
|
132
|
+
```
|
133
|
+
Task.input → DependencyResolver → Resolved Task.input
|
134
|
+
```
|
135
|
+
|
136
|
+
Implementation considerations:
|
137
|
+
- Dependency graph traversal
|
138
|
+
- Circular dependency detection
|
139
|
+
- Parallel resolution of independent dependencies
|
140
|
+
- Caching of resolved dependencies
|
141
|
+
|
142
|
+
### 3. Context Enhancement
|
143
|
+
|
144
|
+
Inputs are enhanced with relevant contextual information:
|
145
|
+
|
146
|
+
```
|
147
|
+
Task.input → ContextEnhancer → Enhanced Task.input
|
148
|
+
```
|
149
|
+
|
150
|
+
Implementation considerations:
|
151
|
+
- Selective context inclusion
|
152
|
+
- Privacy-preserving context filtering
|
153
|
+
- Context source prioritization
|
154
|
+
- Context versioning
|
155
|
+
|
156
|
+
### 4. Input Transformation
|
157
|
+
|
158
|
+
Outputs from previous tasks are transformed into appropriate inputs:
|
159
|
+
|
160
|
+
```
|
161
|
+
Previous Task Output → OutputToInputTransformer → Current Task Input
|
162
|
+
```
|
163
|
+
|
164
|
+
Implementation considerations:
|
165
|
+
- Transformation rule definitions
|
166
|
+
- Field mapping configurations
|
167
|
+
- Type conversion handling
|
168
|
+
- Aggregation of multiple outputs
|
169
|
+
|
170
|
+
## Component Responsibilities
|
171
|
+
|
172
|
+
### Task Class
|
173
|
+
|
174
|
+
- Accept and validate input structure
|
175
|
+
- Provide access to input parameters
|
176
|
+
- Track input provenance
|
177
|
+
- Support input validation
|
178
|
+
|
179
|
+
### InputValidator
|
180
|
+
|
181
|
+
- Verify input against schema
|
182
|
+
- Perform type checking and coercion
|
183
|
+
- Validate required fields
|
184
|
+
- Provide detailed validation errors
|
185
|
+
|
186
|
+
### DependencyResolver
|
187
|
+
|
188
|
+
- Analyze input dependencies
|
189
|
+
- Resolve dependencies before execution
|
190
|
+
- Detect circular or missing dependencies
|
191
|
+
- Handle dependency errors
|
192
|
+
|
193
|
+
### ContextManager
|
194
|
+
|
195
|
+
- Maintain execution context
|
196
|
+
- Provide relevant context to tasks
|
197
|
+
- Filter sensitive context information
|
198
|
+
- Ensure context consistency
|
199
|
+
|
200
|
+
### InputTransformer (New Component)
|
201
|
+
|
202
|
+
- Convert between input/output formats
|
203
|
+
- Apply transformation rules
|
204
|
+
- Handle type conversions
|
205
|
+
- Support custom transformers
|
206
|
+
|
207
|
+
### PlanOrchestrator
|
208
|
+
|
209
|
+
- Coordinate input provision to tasks
|
210
|
+
- Manage input flow between tasks
|
211
|
+
- Handle input errors and retries
|
212
|
+
- Track input state across the plan
|
213
|
+
|
214
|
+
## Implementation Approach
|
215
|
+
|
216
|
+
1. **Start Simple**: Begin with basic parameter support
|
217
|
+
2. **Add Context**: Incorporate contextual information
|
218
|
+
3. **Implement Validation**: Add schema-based validation
|
219
|
+
4. **Enable Transformation**: Create input transformation capabilities
|
220
|
+
5. **Support Dependencies**: Add dependency resolution
|
221
|
+
|
222
|
+
## Development Priorities
|
223
|
+
|
224
|
+
1. Define the input schema interface
|
225
|
+
2. Implement input validation in Task
|
226
|
+
3. Create input transformation utilities
|
227
|
+
4. Develop dependency resolution
|
228
|
+
5. Implement context management
|
229
|
+
6. Add human intervention support
|
230
|
+
|
231
|
+
## Considerations for Future Extensions
|
232
|
+
|
233
|
+
1. **Schema Evolution**: Support versioning of input schemas
|
234
|
+
2. **Smart Defaults**: Intelligent default value generation
|
235
|
+
3. **Input Templates**: Reusable input patterns for common tasks
|
236
|
+
4. **Dynamic Validation**: Context-aware validation rules
|
237
|
+
5. **Input Suggestions**: AI-assisted input completion
|
238
|
+
|
239
|
+
## Integration with Output Handling
|
240
|
+
|
241
|
+
The input and output handling systems are tightly coupled:
|
242
|
+
|
243
|
+
1. **Format Compatibility**: Output schema from one task must be compatible with input schema of dependent tasks
|
244
|
+
2. **Transformation Pipeline**: Clear pipeline for output-to-input transformation
|
245
|
+
3. **Metadata Preservation**: Relevant metadata flows from outputs to inputs
|
246
|
+
4. **Validation Chain**: Output validation should inform input validation
|
247
|
+
5. **Contextual Flow**: Context accumulates through the input/output chain
|
248
|
+
|
249
|
+
## Conclusion
|
250
|
+
|
251
|
+
A well-designed task input handling system is foundational to the Agentic framework. By standardizing input formats, supporting validation, enabling transformation, and managing dependencies, the system can ensure tasks receive the appropriate context and data needed for successful execution while maintaining the integrity of the overall plan.
|
@@ -0,0 +1,391 @@
|
|
1
|
+
# Task Observable Pattern
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
This document outlines the architectural design for implementing the Observable pattern in the Agentic task system. It leverages Ruby's built-in Observable module to enable loose coupling between tasks and components that need to react to task state changes.
|
6
|
+
|
7
|
+
## Design Decision
|
8
|
+
|
9
|
+
### Using Ruby's Standard Observable
|
10
|
+
|
11
|
+
The Agentic framework will use Ruby's built-in Observable module from the standard library rather than implementing a custom solution. The standard library implementation provides:
|
12
|
+
|
13
|
+
1. **Proven Implementation**: Battle-tested code with known behavior
|
14
|
+
2. **Familiarity**: Recognized pattern that Ruby developers understand
|
15
|
+
3. **Lightweight**: Minimal overhead for the functionality provided
|
16
|
+
4. **Maintenance**: Reduces custom code that needs to be maintained
|
17
|
+
|
18
|
+
## Implementation Details
|
19
|
+
|
20
|
+
### Task Integration
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require 'observer'
|
24
|
+
|
25
|
+
module Agentic
|
26
|
+
class Task
|
27
|
+
include Observable
|
28
|
+
|
29
|
+
# ... other attributes and methods ...
|
30
|
+
|
31
|
+
def perform(agent)
|
32
|
+
old_status = @status
|
33
|
+
@status = :in_progress
|
34
|
+
|
35
|
+
# Signal that object state has changed
|
36
|
+
changed
|
37
|
+
# Notify observers with event type and context
|
38
|
+
notify_observers(:status_change, self, old_status, @status)
|
39
|
+
|
40
|
+
# ... execution logic ...
|
41
|
+
|
42
|
+
# Status transitions with notifications
|
43
|
+
end
|
44
|
+
|
45
|
+
def retry(agent)
|
46
|
+
# Similar pattern with status change notifications
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
### Notification Protocol
|
53
|
+
|
54
|
+
The Observable pattern requires a clear protocol for notifications:
|
55
|
+
|
56
|
+
1. **Event Types**: Symbolized event identifiers (e.g., `:status_change`)
|
57
|
+
2. **Event Context**: Relevant objects and data for the event
|
58
|
+
3. **Observer Interface**: Observer must implement `update` method
|
59
|
+
|
60
|
+
Observer's `update` method signature:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
def update(event_type, task, *args)
|
64
|
+
# Handle the event based on type and context
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
Common event types:
|
69
|
+
|
70
|
+
| Event Type | Description | Arguments |
|
71
|
+
|------------|-------------|-----------|
|
72
|
+
| `:status_change` | Task status has changed | `task, old_status, new_status` |
|
73
|
+
| `:output_available` | Task has produced output | `task, output` |
|
74
|
+
| `:failure_occurred` | Task has failed | `task, failure` |
|
75
|
+
| `:verification_complete` | Task verification complete | `task, verification_result` |
|
76
|
+
|
77
|
+
## Practical Usage Patterns
|
78
|
+
|
79
|
+
### 1. Plan Orchestration
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class PlanOrchestrator
|
83
|
+
def initialize(plan_id)
|
84
|
+
@plan_id = plan_id
|
85
|
+
@tasks_in_progress = 0
|
86
|
+
@task_results = {}
|
87
|
+
@dependencies = {}
|
88
|
+
end
|
89
|
+
|
90
|
+
def update(event_type, task, *args)
|
91
|
+
case event_type
|
92
|
+
when :status_change
|
93
|
+
old_status, new_status = args
|
94
|
+
handle_status_change(task, old_status, new_status)
|
95
|
+
when :failure_occurred
|
96
|
+
failure = args.first
|
97
|
+
handle_failure(task, failure)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_task(task, dependencies = [])
|
102
|
+
task.add_observer(self)
|
103
|
+
@dependencies[task.id] = dependencies
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def handle_status_change(task, old_status, new_status)
|
109
|
+
# React to status changes
|
110
|
+
# Track tasks in progress
|
111
|
+
# Execute dependent tasks when appropriate
|
112
|
+
end
|
113
|
+
|
114
|
+
def handle_failure(task, failure)
|
115
|
+
# Apply appropriate failure handling strategy
|
116
|
+
# Retry, fallback, or human intervention
|
117
|
+
end
|
118
|
+
|
119
|
+
def execute_dependent_tasks(completed_task_id)
|
120
|
+
# Find and execute tasks that depend on the completed task
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
### 2. Metrics Collection
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
class MetricsCollector
|
129
|
+
def initialize
|
130
|
+
@task_timings = {}
|
131
|
+
@status_transitions = {}
|
132
|
+
end
|
133
|
+
|
134
|
+
def update(event_type, task, *args)
|
135
|
+
if event_type == :status_change
|
136
|
+
old_status, new_status = args
|
137
|
+
|
138
|
+
# Record timestamp of status change
|
139
|
+
@status_transitions[task.id] ||= []
|
140
|
+
@status_transitions[task.id] << {
|
141
|
+
from: old_status,
|
142
|
+
to: new_status,
|
143
|
+
timestamp: Time.now
|
144
|
+
}
|
145
|
+
|
146
|
+
# Calculate and record timings for completed tasks
|
147
|
+
if new_status == :completed
|
148
|
+
start_time = find_start_time(task.id)
|
149
|
+
@task_timings[task.id] = Time.now - start_time if start_time
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def find_start_time(task_id)
|
157
|
+
transition = @status_transitions[task_id]&.find { |t| t[:to] == :in_progress }
|
158
|
+
transition&.fetch(:timestamp)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
### 3. Human Intervention Portal
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
class HumanInterventionPortal
|
167
|
+
def initialize
|
168
|
+
@intervention_requests = {}
|
169
|
+
end
|
170
|
+
|
171
|
+
def update(event_type, task, *args)
|
172
|
+
if event_type == :status_change
|
173
|
+
old_status, new_status = args
|
174
|
+
|
175
|
+
if new_status == :failed
|
176
|
+
failure = task.failure
|
177
|
+
|
178
|
+
# Check if this failure requires human intervention
|
179
|
+
if requires_human_intervention?(failure)
|
180
|
+
request_intervention(task, failure)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def requires_human_intervention?(failure)
|
189
|
+
# Logic to determine if human should intervene
|
190
|
+
%w[AuthenticationError PermissionDeniedError UnknownDomainError].include?(failure.type)
|
191
|
+
end
|
192
|
+
|
193
|
+
def request_intervention(task, failure)
|
194
|
+
@intervention_requests[task.id] = {
|
195
|
+
task_id: task.id,
|
196
|
+
task_description: task.description,
|
197
|
+
failure: failure.to_h,
|
198
|
+
timestamp: Time.now,
|
199
|
+
status: :pending
|
200
|
+
}
|
201
|
+
|
202
|
+
# Notify human operators
|
203
|
+
notify_operators(task)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
```
|
207
|
+
|
208
|
+
## Benefits of Observable Pattern
|
209
|
+
|
210
|
+
### 1. Loose Coupling
|
211
|
+
|
212
|
+
The Observable pattern decouples tasks from components that need to react to task state:
|
213
|
+
|
214
|
+
```
|
215
|
+
┌─────────────────┐
|
216
|
+
│MetricsCollector │
|
217
|
+
└────────┬────────┘
|
218
|
+
│
|
219
|
+
┌─────┐ notify ┌──────┐ │ update
|
220
|
+
│Agent│───────────▶ │ Task │◀──┘
|
221
|
+
└─────┘ └──────┘
|
222
|
+
│
|
223
|
+
│
|
224
|
+
┌───┴────────────┐
|
225
|
+
│PlanOrchestrator│
|
226
|
+
└────────────────┘
|
227
|
+
```
|
228
|
+
|
229
|
+
This enables:
|
230
|
+
- Independent development of components
|
231
|
+
- Pluggable monitoring and orchestration
|
232
|
+
- Testing in isolation
|
233
|
+
|
234
|
+
### 2. Flexible Execution Models
|
235
|
+
|
236
|
+
The Observer pattern supports both:
|
237
|
+
- **Synchronous Execution**: Direct response to events
|
238
|
+
- **Asynchronous Execution**: Event queues with background processing
|
239
|
+
|
240
|
+
This enables evolution of the execution model without changing the Task interface.
|
241
|
+
|
242
|
+
### 3. Simplified Extensibility
|
243
|
+
|
244
|
+
New functionality can be added by implementing new observers:
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
# Add execution logging without modifying Task
|
248
|
+
class TaskLogger
|
249
|
+
def update(event_type, task, *args)
|
250
|
+
if event_type == :status_change
|
251
|
+
old_status, new_status = args
|
252
|
+
Agentic.logger.info("Task #{task.id} transitioned from #{old_status} to #{new_status}")
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Usage:
|
258
|
+
task = Task.new(...)
|
259
|
+
task.add_observer(TaskLogger.new)
|
260
|
+
```
|
261
|
+
|
262
|
+
### 4. Enhanced Parallelism
|
263
|
+
|
264
|
+
Observable pattern enables:
|
265
|
+
- Multiple observers processing events in parallel
|
266
|
+
- Observer-specific thread pools
|
267
|
+
- Backpressure handling per observer
|
268
|
+
|
269
|
+
## Implementation Considerations
|
270
|
+
|
271
|
+
### 1. Thread Safety
|
272
|
+
|
273
|
+
Ruby's Observable implementation is not thread-safe by default. In multi-threaded environments:
|
274
|
+
|
275
|
+
- Consider using a thread-safe observer collection
|
276
|
+
- Use synchronization when notifying observers
|
277
|
+
- Consider thread-local changed flag
|
278
|
+
|
279
|
+
Example enhancement:
|
280
|
+
|
281
|
+
```ruby
|
282
|
+
module ThreadSafeObservable
|
283
|
+
include Observable
|
284
|
+
|
285
|
+
def notify_observers(*args)
|
286
|
+
observers = @observer_peers.dup
|
287
|
+
observers.each do |observer|
|
288
|
+
observer.update(*args)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
```
|
293
|
+
|
294
|
+
### 2. Memory Management
|
295
|
+
|
296
|
+
Observers create references to the observed objects which may lead to memory leaks:
|
297
|
+
|
298
|
+
- Ensure observers are properly removed when no longer needed
|
299
|
+
- Consider using weak references for long-lived tasks
|
300
|
+
- Implement cleanup methods for completed tasks
|
301
|
+
|
302
|
+
### 3. Error Handling
|
303
|
+
|
304
|
+
Observer errors should not affect the observed object:
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
def notify_observers(*args)
|
308
|
+
observers = @observer_peers.dup
|
309
|
+
observers.each do |observer|
|
310
|
+
begin
|
311
|
+
observer.update(*args)
|
312
|
+
rescue => e
|
313
|
+
Agentic.logger.error("Observer error: #{e.message}")
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
```
|
318
|
+
|
319
|
+
## Integration with Larger Architecture
|
320
|
+
|
321
|
+
### 1. PlanOrchestrator
|
322
|
+
|
323
|
+
The PlanOrchestrator becomes an observer of all tasks it manages:
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
def execute_plan(tasks)
|
327
|
+
tasks.each do |task|
|
328
|
+
task.add_observer(self)
|
329
|
+
# Add other observers as needed
|
330
|
+
task.add_observer(MetricsCollector.instance)
|
331
|
+
task.add_observer(HumanInterventionPortal.instance)
|
332
|
+
end
|
333
|
+
|
334
|
+
# Start eligible tasks
|
335
|
+
start_eligible_tasks(tasks)
|
336
|
+
end
|
337
|
+
```
|
338
|
+
|
339
|
+
### 2. Verification System
|
340
|
+
|
341
|
+
Verification can be triggered by task status changes:
|
342
|
+
|
343
|
+
```ruby
|
344
|
+
class VerificationHub
|
345
|
+
def update(event_type, task, *args)
|
346
|
+
if event_type == :status_change
|
347
|
+
old_status, new_status = args
|
348
|
+
|
349
|
+
if new_status == :completed
|
350
|
+
# Perform verification
|
351
|
+
verification_result = verify(task)
|
352
|
+
|
353
|
+
# Notify observers of verification result
|
354
|
+
task.changed
|
355
|
+
task.notify_observers(:verification_complete, task, verification_result)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
```
|
361
|
+
|
362
|
+
### 3. Learning System
|
363
|
+
|
364
|
+
The learning system can observe tasks to gather training data:
|
365
|
+
|
366
|
+
```ruby
|
367
|
+
class ExecutionHistoryStore
|
368
|
+
def update(event_type, task, *args)
|
369
|
+
case event_type
|
370
|
+
when :status_change
|
371
|
+
record_status_change(task, *args)
|
372
|
+
when :failure_occurred
|
373
|
+
record_failure(task, *args.first)
|
374
|
+
when :verification_complete
|
375
|
+
record_verification(task, *args.first)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
```
|
380
|
+
|
381
|
+
## Conclusion
|
382
|
+
|
383
|
+
The Observable pattern provides a robust, flexible foundation for task state management in the Agentic framework. By leveraging Ruby's built-in Observable module, we achieve loose coupling between tasks and the components that react to them, enabling a more extensible and maintainable architecture.
|
384
|
+
|
385
|
+
This design supports our core architectural goals of:
|
386
|
+
- Separation of concerns
|
387
|
+
- Extensibility
|
388
|
+
- Resilience to failures
|
389
|
+
- Flexible execution models
|
390
|
+
|
391
|
+
The Observable pattern will be particularly valuable as the system grows in complexity, allowing new monitoring, orchestration, and intervention components to be added without modifying the core Task implementation.
|