mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
feat: agent self evolution (#2847)
* feat: add agent self-evolution * fix ci * delete unused doc * fix lint * fix evolution review issues
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package evolution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type coldPathRuntime interface {
|
||||
RunColdPathOnce(ctx context.Context, workspace string) error
|
||||
}
|
||||
|
||||
type ColdPathRunner struct {
|
||||
runtime coldPathRuntime
|
||||
async func(func())
|
||||
onError func(error)
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
mu sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
closeOnce sync.Once
|
||||
closed bool
|
||||
running map[string]workspaceRunState
|
||||
}
|
||||
|
||||
func NewColdPathRunner(runtime coldPathRuntime) *ColdPathRunner {
|
||||
return NewColdPathRunnerWithErrorHandler(runtime, nil)
|
||||
}
|
||||
|
||||
func NewColdPathRunnerWithErrorHandler(runtime coldPathRuntime, onError func(error)) *ColdPathRunner {
|
||||
if onError == nil {
|
||||
onError = func(error) {}
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
return &ColdPathRunner{
|
||||
runtime: runtime,
|
||||
async: func(run func()) {
|
||||
go run()
|
||||
},
|
||||
onError: onError,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
running: make(map[string]workspaceRunState),
|
||||
}
|
||||
}
|
||||
|
||||
type workspaceRunState struct {
|
||||
running bool
|
||||
pending bool
|
||||
}
|
||||
|
||||
func (r *ColdPathRunner) Trigger(workspace string) bool {
|
||||
if r == nil || r.runtime == nil || workspace == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
if r.closed {
|
||||
r.mu.Unlock()
|
||||
return false
|
||||
}
|
||||
state, exists := r.running[workspace]
|
||||
if exists && state.running {
|
||||
state.pending = true
|
||||
r.running[workspace] = state
|
||||
r.mu.Unlock()
|
||||
return true
|
||||
}
|
||||
r.running[workspace] = workspaceRunState{running: true}
|
||||
r.wg.Add(1)
|
||||
r.mu.Unlock()
|
||||
|
||||
r.async(func() {
|
||||
defer r.wg.Done()
|
||||
r.runWorkspace(workspace)
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *ColdPathRunner) runWorkspace(workspace string) {
|
||||
for {
|
||||
if err := r.runtime.RunColdPathOnce(r.ctx, workspace); err != nil && !errors.Is(err, context.Canceled) {
|
||||
r.onError(err)
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
state, exists := r.running[workspace]
|
||||
if !exists || r.closed {
|
||||
delete(r.running, workspace)
|
||||
r.mu.Unlock()
|
||||
return
|
||||
}
|
||||
if state.pending {
|
||||
state.pending = false
|
||||
r.running[workspace] = state
|
||||
r.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
delete(r.running, workspace)
|
||||
r.mu.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ColdPathRunner) Close() error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
r.closeOnce.Do(func() {
|
||||
r.mu.Lock()
|
||||
r.closed = true
|
||||
r.mu.Unlock()
|
||||
r.cancel()
|
||||
})
|
||||
r.wg.Wait()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user