47 lines
1.3 KiB
Go
47 lines
1.3 KiB
Go
package loop
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/persist"
|
|
)
|
|
|
|
// checkpointState is the durable snapshot persisted at every step. Carrying the
|
|
// message window and the step index lets a long-running task be resumed from the
|
|
// latest checkpoint without losing context (design §1 durable execution).
|
|
type checkpointState struct {
|
|
Step int `json:"step"`
|
|
Messages []model.Message `json:"messages"`
|
|
StopReason string `json:"stop_reason,omitempty"`
|
|
}
|
|
|
|
// saveCheckpoint persists a snapshot at step. It never fails the run: a nil store
|
|
// is a no-op and a marshal/save error is logged.
|
|
func (l *Loop) saveCheckpoint(ctx context.Context, sessionID string, step int, messages []model.Message, stopReason string) {
|
|
if l.checkpoint == nil {
|
|
return
|
|
}
|
|
state := checkpointState{
|
|
Step: step,
|
|
Messages: messages,
|
|
StopReason: stopReason,
|
|
}
|
|
buf, err := json.Marshal(state)
|
|
if err != nil {
|
|
l.log.Warn("checkpoint marshal", "step", step, "error", err)
|
|
return
|
|
}
|
|
cp := &persist.Checkpoint{
|
|
ID: fmt.Sprintf("%s:%d", sessionID, step),
|
|
AgentID: sessionID,
|
|
Step: step,
|
|
State: buf,
|
|
}
|
|
if err := l.checkpoint.Save(ctx, cp); err != nil {
|
|
l.log.Warn("checkpoint save", "step", step, "error", err)
|
|
}
|
|
}
|