diff --git a/internal/agent/tools.go b/internal/agent/tools.go index 0dae664..43571dc 100644 --- a/internal/agent/tools.go +++ b/internal/agent/tools.go @@ -2,7 +2,6 @@ package agent import ( "context" - "time" "gitea.stevedudenhoeffer.com/steve/majordomo/llm" @@ -218,8 +217,9 @@ func (a *adapter) readJournal(ctx context.Context, args struct { ObjectID *int64 `json:"objectId" description:"optional bed to narrow to; omit for the whole garden"` From string `json:"from" description:"optional earliest observed date, YYYY-MM-DD"` To string `json:"to" description:"optional latest observed date, YYYY-MM-DD"` + Offset int `json:"offset" description:"how many entries to skip; pass the count you've already seen to page when hasMore is true"` }) (any, error) { - q := service.JournalQuery{ObjectID: args.ObjectID, Limit: 50} + q := service.JournalQuery{ObjectID: args.ObjectID, Limit: 50, Offset: args.Offset} if args.From != "" { q.From = &args.From } @@ -230,6 +230,7 @@ func (a *adapter) readJournal(ctx context.Context, args struct { if err != nil { return nil, err } + // hasMore is actionable now: re-call with offset += len(entries) to page. return map[string]any{"entries": entries, "hasMore": hasMore}, nil } @@ -261,11 +262,9 @@ func (a *adapter) removePlanting(ctx context.Context, args struct { PlantingID int64 `json:"plantingId" description:"plop to remove (its id from describe_garden)"` Version int64 `json:"version" description:"the plop's current version (from describe_garden)"` }) (any, error) { - // Soft-remove: set removed_at to today, mirroring clear_object, so the plop - // stays in the planting history and the change is undoable. - today := time.Now().UTC().Format("2006-01-02") - return a.svc.UpdatePlanting(ctx, a.actor, args.PlantingID, - service.PlantingPatch{SetRemovedAt: true, RemovedAt: &today}, args.Version) + // Soft-remove via the service, so removed_at is stamped from the same + // (injectable) clock clear_object uses rather than the adapter's wall clock. + return a.svc.RemovePlanting(ctx, a.actor, args.PlantingID, args.Version) } func (a *adapter) listSeedLots(ctx context.Context, args struct { diff --git a/internal/service/plantings.go b/internal/service/plantings.go index 246f749..879feff 100644 --- a/internal/service/plantings.go +++ b/internal/service/plantings.go @@ -178,6 +178,17 @@ func (s *Service) UpdatePlanting(ctx context.Context, actorID, plantingID int64, return updated, nil } +// RemovePlanting soft-removes a single plop — the one-plop counterpart to +// ClearObject, used by the agent's remove_planting tool. It stamps removed_at +// from the service clock (s.now()), same as ClearObject and the fill path, so the +// removal date can't diverge by which caller set it; then delegates to +// UpdatePlanting for the editor-role check, version guard and history record. +func (s *Service) RemovePlanting(ctx context.Context, actorID, plantingID, version int64) (*domain.Planting, error) { + today := s.now().UTC().Format(dateLayout) + return s.UpdatePlanting(ctx, actorID, plantingID, + PlantingPatch{SetRemovedAt: true, RemovedAt: &today}, version) +} + // plantingEditSummary describes a plop edit for the history list. Soft-removal // ("clear bed", harvested) is the one edit worth naming specifically — it reads // as a removal to the person who did it, not as an edit.