yao/agent/robot/executor/standard/run.go
Max 0c9bdb8000 Implement P3 Run Phase with Enhanced Validation and Execution Logic
- Completed the implementation of the P3 Run phase, integrating task execution and validation mechanisms.
- Introduced a new `RunConfig` struct to manage execution parameters such as retries and validation thresholds.
- Developed a two-layer validation system using the new `yao/assert` package, supporting both natural language and structured JSON rules.
- Enhanced the `RunExecution` method to execute tasks sequentially with progress tracking and a retry mechanism for validation failures.
- Updated task structures to include comprehensive validation rules and expected outputs, ensuring robust task management.
- Added unit tests for the new execution and validation features, achieving high test coverage across the implementation.
- Revised documentation to reflect changes in the architecture and functionality of the P3 phase.
2026-01-17 12:22:23 +08:00

122 lines
3.3 KiB
Go

package standard
import (
"fmt"
"time"
robottypes "github.com/yaoapp/yao/agent/robot/types"
)
// RunConfig configures P3 execution behavior
type RunConfig struct {
// MaxRetries is the maximum number of retry attempts per task (default: 3)
MaxRetries int
// RetryOnValidationFailure enables retry when validation fails (default: true)
RetryOnValidationFailure bool
// ContinueOnFailure continues to next task even if current task fails (default: false)
ContinueOnFailure bool
// ValidationThreshold is the minimum score to pass validation (default: 0.6)
ValidationThreshold float64
// MaxTurnsPerTask is the maximum conversation turns for multi-turn agents (default: 10)
MaxTurnsPerTask int
}
// DefaultRunConfig returns the default P3 configuration
func DefaultRunConfig() *RunConfig {
return &RunConfig{
MaxRetries: 3,
RetryOnValidationFailure: true,
ContinueOnFailure: false,
ValidationThreshold: 0.6,
MaxTurnsPerTask: 10,
}
}
// RunExecution executes P3: Run phase
// Executes each task using the appropriate executor (Assistant, MCP, Process)
// with validation and retry mechanism
//
// Input:
// - Tasks (from P2)
//
// Output:
// - TaskResult for each task with output and validation
//
// Features:
// 1. Sequential task execution with progress tracking
// 2. Validation after each task using Validation Agent
// 3. Retry mechanism with feedback loop to expert agent
// 4. Multi-turn conversation support for complex tasks
// 5. Previous task results passed as context to next task
func (e *Executor) RunExecution(ctx *robottypes.Context, exec *robottypes.Execution, _ interface{}) error {
robot := exec.GetRobot()
if robot == nil {
return fmt.Errorf("robot not found in execution")
}
if len(exec.Tasks) == 0 {
return fmt.Errorf("no tasks to execute")
}
// Get run configuration
config := DefaultRunConfig()
// Initialize results slice
exec.Results = make([]robottypes.TaskResult, 0, len(exec.Tasks))
// Create task runner
runner := NewRunner(ctx, robot, config)
// Execute tasks sequentially
for i := range exec.Tasks {
task := &exec.Tasks[i]
// Update current state for tracking
exec.Current = &robottypes.CurrentState{
Task: task,
TaskIndex: i,
Progress: fmt.Sprintf("%d/%d tasks", i+1, len(exec.Tasks)),
}
// Mark task as running
task.Status = robottypes.TaskRunning
now := time.Now()
task.StartTime = &now
// Build task context with previous results
taskCtx := runner.BuildTaskContext(exec, i)
// Execute task with retry
result := runner.ExecuteWithRetry(task, taskCtx)
// Update task status based on result
endTime := time.Now()
task.EndTime = &endTime
if result.Success && (result.Validation == nil || result.Validation.Passed) {
task.Status = robottypes.TaskCompleted
} else {
task.Status = robottypes.TaskFailed
}
// Store result
exec.Results = append(exec.Results, *result)
// Check if we should continue on failure
if !result.Success && !config.ContinueOnFailure {
// Mark remaining tasks as skipped
for j := i + 1; j < len(exec.Tasks); j++ {
exec.Tasks[j].Status = robottypes.TaskSkipped
}
return fmt.Errorf("task %s failed: %s", task.ID, result.Error)
}
}
// Clear current state
exec.Current = nil
return nil
}