2026-10-14 22:52:02 -07:00
package store
import (
"context"
"database/sql"
"errors"
2026-10-18 15:32:07 -07:00
"g.fc.run/ai/byre/internal/api"
2026-10-14 22:52:02 -07:00
)
const snapshotColumns = `id, task_id, agent_session_id, n, commit_sha, tree_sha, event_seq, trigger, created_at`
func ( s * Store ) CreateSnapshot ( ctx context . Context , snap api . Snapshot , projectID string ) error {
return s . write ( ctx , func ( tx * sql . Tx , emit emitFunc ) error {
_ , err := tx . ExecContext ( ctx , `INSERT INTO snapshots (` + snapshotColumns + `) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)` ,
snap . Id , snap . TaskId , snap . AgentSessionId , snap . N , snap . CommitSha , snap . TreeSha , snap . EventSeq , string ( snap . Trigger ), formatTime ( snap . CreatedAt ))
if err != nil {
return err
}
2026-10-19 17:53:54 -07:00
if snap . Trigger != api . SnapshotTriggerAnswer {
_ , err = tx . ExecContext ( ctx , `UPDATE tasks SET ready = '' WHERE id = ?` , snap . TaskId )
if err != nil {
return err
}
}
2026-10-14 22:52:02 -07:00
return emit ( api . Event {
Kind : "snapshot.created" ,
ProjectId : & projectID ,
TaskId : & snap . TaskId ,
AgentSessionId : & snap . AgentSessionId ,
Actor : "byre" ,
Payload : ToPayload ( snap ),
})
})
}
func ( s * Store ) ListSnapshots ( ctx context . Context , taskID string ) ([] api . Snapshot , error ) {
rows , err := s . db . QueryContext ( ctx , `SELECT ` + snapshotColumns + ` FROM snapshots WHERE task_id = ? ORDER BY n` , taskID )
if err != nil {
return nil , err
}
defer rows . Close ()
snaps := [] api . Snapshot {}
for rows . Next () {
snap , err := scanSnapshot ( rows )
if err != nil {
return nil , err
}
snaps = append ( snaps , snap )
}
return snaps , rows . Err ()
}
2026-10-15 00:08:32 -07:00
func ( s * Store ) GetSnapshot ( ctx context . Context , taskID string , n int ) ( api . Snapshot , error ) {
snap , err := scanSnapshot ( s . db . QueryRowContext ( ctx , `SELECT ` + snapshotColumns + ` FROM snapshots WHERE task_id = ? AND n = ?` , taskID , n ))
if errors . Is ( err , sql . ErrNoRows ) {
return snap , ErrNotFound
}
return snap , err
}
2026-10-14 22:52:02 -07:00
func ( s * Store ) LastSnapshot ( ctx context . Context , taskID string ) ( api . Snapshot , error ) {
snap , err := scanSnapshot ( s . db . QueryRowContext ( ctx , `SELECT ` + snapshotColumns + ` FROM snapshots WHERE task_id = ? ORDER BY n DESC LIMIT 1` , taskID ))
if errors . Is ( err , sql . ErrNoRows ) {
return snap , ErrNotFound
}
return snap , err
}
2026-10-18 15:06:06 -07:00
func ( s * Store ) LastSnapshotNot ( ctx context . Context , taskID string , trigger api . SnapshotTrigger ) ( api . Snapshot , error ) {
snap , err := scanSnapshot ( s . db . QueryRowContext ( ctx , `SELECT ` + snapshotColumns + ` FROM snapshots WHERE task_id = ? AND trigger != ? ORDER BY n DESC LIMIT 1` , taskID , string ( trigger )))
if errors . Is ( err , sql . ErrNoRows ) {
return snap , ErrNotFound
}
return snap , err
}
2026-10-14 22:52:02 -07:00
func ( s * Store ) LastTaskSeq ( ctx context . Context , taskID string ) ( int64 , error ) {
seq := int64 ( 0 )
err := s . db . QueryRowContext ( ctx , `SELECT COALESCE(MAX(seq), 0) FROM events WHERE task_id = ?` , taskID ). Scan ( & seq )
return seq , err
}
func scanSnapshot ( row scanner ) ( api . Snapshot , error ) {
snap := api . Snapshot {}
trigger := ""
createdAt := ""
err := row . Scan ( & snap . Id , & snap . TaskId , & snap . AgentSessionId , & snap . N , & snap . CommitSha , & snap . TreeSha , & snap . EventSeq , & trigger , & createdAt )
if err != nil {
return snap , err
}
snap . Trigger = api . SnapshotTrigger ( trigger )
snap . CreatedAt , err = parseTime ( createdAt )
return snap , err
}