]> git.giacomolli.uk - onechat/blobdiff - rebuild.go
Receive images in WhatsApp batches
[onechat] / rebuild.go
index 8522d70b60a7130458441d16f19ef3677cbc5572..598371caa5343965f4e27cd481cd5a289132ae1c 100644 (file)
@@ -7,7 +7,7 @@ import (
        "fmt"
        "io"
        "io/fs"
        "fmt"
        "io"
        "io/fs"
-       "log"
+       "log/slog"
        "os"
        "path/filepath"
        "slices"
        "os"
        "path/filepath"
        "slices"
@@ -15,13 +15,20 @@ import (
        "time"
 )
 
        "time"
 )
 
+// rebuildCallLimit is the most model calls of a rebuild. A rebuild summarizes
+// the whole merged log, which can need more calls than a probe sample, and the
+// quota stop of the build run still guards the account.
+const rebuildCallLimit = 1500
+
 // rebuild merges added messages with the log of agent, in date order, and
 // builds a new memory beside it. The caller holds the token lock. The model
 // uses the original agent prompt and cache key. A failed or stopped build
 // removes the new directory and leaves the original directory unchanged.
 // Success copies the other agent files, adds this run's usage, and swaps the
 // directories, with the original kept as a timestamped backup. Message IDs are
 // rebuild merges added messages with the log of agent, in date order, and
 // builds a new memory beside it. The caller holds the token lock. The model
 // uses the original agent prompt and cache key. A failed or stopped build
 // removes the new directory and leaves the original directory unchanged.
 // Success copies the other agent files, adds this run's usage, and swaps the
 // directories, with the original kept as a timestamped backup. Message IDs are
-// new positions in the merged log, but kind, text, and date stay exact.
+// new positions in the merged log, but kind, text, and date stay exact. A child
+// keeps its staging directory and backup outside children so that neither is
+// read as a configured child.
 func rebuild(ctx context.Context, agent *Agent, added []DatedMessage, client *ModelClient, summarizer Summarizer, out io.Writer) (backup string, err error) {
        err = rebuildIdle(agent.dir)
        if err != nil {
 func rebuild(ctx context.Context, agent *Agent, added []DatedMessage, client *ModelClient, summarizer Summarizer, out io.Writer) (backup string, err error) {
        err = rebuildIdle(agent.dir)
        if err != nil {
@@ -38,7 +45,14 @@ func rebuild(ctx context.Context, agent *Agent, added []DatedMessage, client *Mo
                return "", fmt.Errorf("merge rebuild messages: %w", err)
        }
 
                return "", fmt.Errorf("merge rebuild messages: %w", err)
        }
 
-       root, err := os.MkdirTemp(filepath.Dir(agent.dir), ".agent-rebuild-")
+       parent := filepath.Dir(agent.dir)
+       backupDir := agent.dir
+       if agent.config.Parent != "" {
+               parent = filepath.Dir(parent)
+               backupDir = filepath.Join(parent, agent.config.Name)
+       }
+
+       root, err := os.MkdirTemp(parent, ".agent-rebuild-")
        if err != nil {
                return "", fmt.Errorf("create rebuild directory: %w", err)
        }
        if err != nil {
                return "", fmt.Errorf("create rebuild directory: %w", err)
        }
@@ -50,12 +64,13 @@ func rebuild(ctx context.Context, agent *Agent, added []DatedMessage, client *Mo
                }
        }()
 
                }
        }()
 
-       memory, err := openMemory(ctx, root, time.Now, summarizer, log.New(io.Discard, "", 0))
+       memory, err := openMemory(ctx, root, time.Now, summarizer, slog.New(slog.DiscardHandler))
        if err != nil {
                return "", fmt.Errorf("open rebuilt memory: %w", err)
        }
 
        if err != nil {
                return "", fmt.Errorf("open rebuilt memory: %w", err)
        }
 
-       client.LimitCalls(buildCallLimit)
+       client.LimitCalls(rebuildCallLimit)
+
        run := BuildRun{
                memory:    memory,
                client:    client,
        run := BuildRun{
                memory:    memory,
                client:    client,
@@ -104,7 +119,7 @@ func rebuild(ctx context.Context, agent *Agent, added []DatedMessage, client *Mo
                return "", ctx.Err()
        }
 
                return "", ctx.Err()
        }
 
-       backup = agent.dir + "-backup-" + time.Now().Format("20060102-150405.000000000")
+       backup = backupDir + "-backup-" + time.Now().Format("20060102-150405.000000000")
        err = os.Rename(agent.dir, backup)
        if err != nil {
                return "", fmt.Errorf("back up agent: %w", err)
        err = os.Rename(agent.dir, backup)
        if err != nil {
                return "", fmt.Errorf("back up agent: %w", err)
@@ -136,6 +151,7 @@ func rebuildIdle(root string) error {
        }
 
        var work SubagentWorkFile
        }
 
        var work SubagentWorkFile
+
        err = json.Unmarshal(data, &work)
        if err != nil {
                return fmt.Errorf("decode running subagents: %w", err)
        err = json.Unmarshal(data, &work)
        if err != nil {
                return fmt.Errorf("decode running subagents: %w", err)
@@ -157,7 +173,9 @@ func rebuildReadLog(ctx context.Context, root string) ([]DatedMessage, error) {
        }
 
        slices.Sort(paths)
        }
 
        slices.Sort(paths)
+
        var entries []DatedMessage
        var entries []DatedMessage
+
        for _, path := range paths {
                var day uint32
 
        for _, path := range paths {
                var day uint32
 
@@ -168,6 +186,7 @@ func rebuildReadLog(ctx context.Context, root string) ([]DatedMessage, error) {
 
                err = journalScanFile(ctx, path, day, 0, false, func(line []byte, _ Position) error {
                        var message Message
 
                err = journalScanFile(ctx, path, day, 0, false, func(line []byte, _ Position) error {
                        var message Message
+
                        err = json.Unmarshal(line, &message)
                        if err != nil {
                                return fmt.Errorf("decode message: %w", err)
                        err = json.Unmarshal(line, &message)
                        if err != nil {
                                return fmt.Errorf("decode message: %w", err)
@@ -215,6 +234,7 @@ func rebuildMerge(old, added []DatedMessage) ([]DatedMessage, error) {
                }
 
                var date time.Time
                }
 
                var date time.Time
+
                date, err = time.Parse(time.RFC3339Nano, entry.Date)
                if err != nil {
                        return nil, fmt.Errorf("parse merge date: %w", err)
                date, err = time.Parse(time.RFC3339Nano, entry.Date)
                if err != nil {
                        return nil, fmt.Errorf("parse merge date: %w", err)
@@ -263,6 +283,7 @@ func rebuildCopy(source, target string) error {
                        }
                case entry.Type().IsRegular():
                        var data []byte
                        }
                case entry.Type().IsRegular():
                        var data []byte
+
                        data, err = os.ReadFile(path)
                        if err != nil {
                                return fmt.Errorf("read agent file: %w", err)
                        data, err = os.ReadFile(path)
                        if err != nil {
                                return fmt.Errorf("read agent file: %w", err)