picoclaw/pkg/agent/session_recorder.go
dj-oyu 18f484165f feat(session): add Fork/Report turn recording for session DAG (TASKS-3 Phase 1)
Introduce SessionRecorder interface to bridge pkg/tools → pkg/session
without circular imports. SubagentManager now records Fork, Turn, and
Completion events in SQLite. processSystemMessage writes TurnReport
directly to the store with AdvanceStored to prevent double-writes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:15:32 +09:00

58 lines
1.6 KiB
Go

package agent
import (
"github.com/sipeed/picoclaw/pkg/providers"
"github.com/sipeed/picoclaw/pkg/session"
"github.com/sipeed/picoclaw/pkg/tools"
)
// sessionRecorderImpl bridges tools.SessionRecorder → session.SessionStore.
type sessionRecorderImpl struct {
adapter *session.LegacyAdapter
}
var _ tools.SessionRecorder = (*sessionRecorderImpl)(nil)
func newSessionRecorder(adapter *session.LegacyAdapter) *sessionRecorderImpl {
return &sessionRecorderImpl{adapter: adapter}
}
func (r *sessionRecorderImpl) RecordFork(conductorKey, subagentKey, taskID, label string) error {
store := r.adapter.Store()
return store.Fork(conductorKey, subagentKey, &session.CreateOpts{
ForkTurnID: taskID,
Label: label,
})
}
func (r *sessionRecorderImpl) RecordSubagentTurn(subagentKey string, messages []providers.Message) error {
store := r.adapter.Store()
turn := &session.Turn{
Kind: session.TurnNormal,
Messages: messages,
}
return store.Append(subagentKey, turn)
}
func (r *sessionRecorderImpl) RecordCompletion(subagentKey, status, result string) error {
store := r.adapter.Store()
return store.SetStatus(subagentKey, status)
}
func (r *sessionRecorderImpl) RecordReport(conductorKey, subagentKey, senderID, content string) error {
store := r.adapter.Store()
turn := &session.Turn{
Kind: session.TurnReport,
OriginKey: subagentKey,
Author: senderID,
Messages: []providers.Message{
{Role: "user", Content: content},
},
}
if err := store.Append(conductorKey, turn); err != nil {
return err
}
// Advance LegacyAdapter's stored counter so flush loop doesn't double-write.
r.adapter.AdvanceStored(conductorKey, 1)
return nil
}