X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/a606686934b4028c29dca8e9dae6b2e188cee9c5..3cdbd017da9ae7a7045f4272f16d4b262fd01c79:/rebuild.go?ds=inline diff --git a/rebuild.go b/rebuild.go index 8522d70..598371c 100644 --- a/rebuild.go +++ b/rebuild.go @@ -7,7 +7,7 @@ import ( "fmt" "io" "io/fs" - "log" + "log/slog" "os" "path/filepath" "slices" @@ -15,13 +15,20 @@ import ( "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 -// 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 { @@ -38,7 +45,14 @@ func rebuild(ctx context.Context, agent *Agent, added []DatedMessage, client *Mo 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) } @@ -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) } - client.LimitCalls(buildCallLimit) + client.LimitCalls(rebuildCallLimit) + run := BuildRun{ memory: memory, client: client, @@ -104,7 +119,7 @@ func rebuild(ctx context.Context, agent *Agent, added []DatedMessage, client *Mo 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) @@ -136,6 +151,7 @@ func rebuildIdle(root string) error { } var work SubagentWorkFile + 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) + var entries []DatedMessage + 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 = 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 + 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 + data, err = os.ReadFile(path) if err != nil { return fmt.Errorf("read agent file: %w", err)