-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathloop.go
More file actions
86 lines (72 loc) · 2.28 KB
/
Copy pathloop.go
File metadata and controls
86 lines (72 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package reference
import (
"context"
"errors"
"fmt"
"time"
)
// AgentLoopConfig configures the execution parameters for an Agentic Loop.
type AgentLoopConfig struct {
MaxSteps int
EnergyBudget int
StepTimeout time.Duration
ExitOnGoalPass bool
}
// ToolCall represents a structured tool invocation request from the model.
type ToolCall struct {
Name string `json:"name"`
Action string `json:"action"`
Arguments map[string]interface{} `json:"arguments"`
EnergyCost int `json:"energy_cost"`
}
// StepResult represents the observation outcome returned to the model.
type StepResult struct {
StepIndex int `json:"step_index"`
Output string `json:"output"`
Err error `json:"err,omitempty"`
GoalPassed bool `json:"goal_passed"`
}
// AgenticLoopKernel manages energy-metered, step-bounded execution loops.
type AgenticLoopKernel struct {
config AgentLoopConfig
energySpent int
currentStep int
}
// NewAgenticLoopKernel initializes a new Agentic Loop instance.
func NewAgenticLoopKernel(cfg AgentLoopConfig) *AgenticLoopKernel {
if cfg.MaxSteps <= 0 {
cfg.MaxSteps = 20
}
if cfg.EnergyBudget <= 0 {
cfg.EnergyBudget = 1000
}
if cfg.StepTimeout == 0 {
cfg.StepTimeout = 30 * time.Second
}
return &AgenticLoopKernel{config: cfg}
}
// ExecuteStep runs a single perception-action cycle within energy & step boundaries.
func (k *AgenticLoopKernel) ExecuteStep(ctx context.Context, call ToolCall, executor func(context.Context, ToolCall) (string, bool, error)) (*StepResult, error) {
if k.currentStep >= k.config.MaxSteps {
return nil, fmt.Errorf("agentic loop error: step limit reached (%d/%d)", k.currentStep, k.config.MaxSteps)
}
cost := call.EnergyCost
if cost <= 0 {
cost = 10
}
if k.energySpent+cost > k.config.EnergyBudget {
return nil, fmt.Errorf("agentic loop error: energy budget depleted (%d/%d spent)", k.energySpent, k.config.EnergyBudget)
}
k.currentStep++
k.energySpent += cost
stepCtx, cancel := context.WithTimeout(ctx, k.config.StepTimeout)
defer cancel()
output, goalPassed, err := executor(stepCtx, call)
res := &StepResult{
StepIndex: k.currentStep,
Output: output,
Err: err,
GoalPassed: goalPassed,
}
return res, nil
}