Phase C -- Pursuit continuity¶
Status: Done
Goal¶
Give multi-heartbeat goal pursuit memory of its own ReAct transcript so agents resume work across daemon cycles instead of restarting from a single-shot user message each time.
Why (problems addressed -- bullet list with severity)¶
- P0: No cross-cycle pursuit transcript -- each heartbeat builds a fresh runtime
Agent, runs onerun()call, discardsConversationMemory(src/hive/daemon/agent_cycle.py,src/hive/runtime/agent.py). - P0: Profile
max_stepscaps per cycle, not per goal lifetime (exacerbated until Phase B wires limits -- then still needs continuation semantics). - P1:
CheckpointManagersaves suffering/identity/goals on completion (src/hive/checkpoint.py) but not in-progress conversation state. - P1: Session JSONL logs exist (
src/hive/logging/writer.py) but are not replayed into the runtime conversation on resume. - P2:
run_onceCLI/API path vs daemon pursuit semantics diverge (docs/guide/system-overview.md).
Related issues bundled¶
| ID | Finding |
|---|---|
| LOOP-PURSUIT-01 | Fresh Agent + empty conversation every cycle |
| LOOP-PURSUIT-02 | No checkpoint / session resume for active goals |
| LOOP-PURSUIT-03 | Step budget semantics across cycles unclear |
Current state (files)¶
| Area | Location | Behavior today |
|---|---|---|
| Pursuit | src/hive/daemon/agent_cycle.py |
adapter.pursue_goal(objective, context=pursuit_context) once per cycle |
| Bridge | src/hive/runtime/bridge.py |
Single Task --> Agent.run() |
| Conversation | src/hive/runtime/memory.py ConversationMemory |
In-memory only for task lifetime |
| Logs | src/hive/logging/writer.py |
Decision/tool JSONL keyed by agent/session/goal |
| Checkpoint | src/hive/checkpoint.py |
No conversation blob |
| Store | src/hive/memory/store.py sessions table |
Session metadata; not full message replay |
| Docs | docs/guide/prompt-assembly.md |
Describes single pursuit invocation |
Proposed changes (numbered)¶
Design choice (pick one primary approach)¶
| Option | Summary | Pros | Cons |
|---|---|---|---|
| C1 -- Session transcript store | Persist serialized messages per (agent_id, goal_id) in SQLite or JSONL slice; hydrate ConversationMemory at pursuit start |
Clear audit trail; works with existing logs | Schema + size limits |
| C2 -- Checkpoint conversation field | Extend CheckpointManager.save() with optional conversation_snapshot; save each cycle end while goal active |
Reuses checkpoint UX | Checkpoints currently on milestones only |
| C3 -- Long-lived runtime Agent | Cache Agent instance in AgentContextCache keyed by (agent_id, goal_id) |
Minimal serialization | Memory growth; toolkits stale on config change |
Recommendation: C1 as primary (store-backed transcript), with incremental flush from ConversationMemory after each pursuit slice. Keep checkpoint optional for operator snapshots.
-
Stable pursuit session id: Derive
pursuit_session_idfromgoal_id(or store column) reused across cycles. -
Transcript persistence API (new module e.g.
src/hive/memory/pursuit_transcript.pyor extendstore.py): append_messages(goal_id, messages)load_messages(goal_id, limit=N)-
Truncate policy: cap messages or tokens (config
daemon.pursuit_transcript_max_messages). -
Bridge / Agent changes:
DaemonAgentAdapter.pursue_goal(..., resume: bool = True)loads transcript before_prepare_conversation.-
After
run(), append new messages; ifMAX_STEPS/ cycle timeout partial, persist state without completing goal (pairs with Phase B continue policy). -
Cycle integration in
agent_cycle.py: - On active goal: load transcript --> run bounded step slice (
min(remaining, profile.max_steps)). -
On goal complete/abandon: delete transcript archive.
-
Timeout behavior: Align with Phase D -- on cycle timeout, persist transcript before parking agent (do not abandon goal by default; today timeout abandons -- consider changing in Phase B/G).
-
Docs: New section in
docs/guide/daemon-mode.md+ updatedocs/guide/prompt-assembly.mdpursuit diagram.
Non-goals¶
- Full semantic summarization of old transcript (optional later).
- Cross-agent shared transcripts.
- Changing ReAct algorithm.
Risks / rollback¶
| Risk | Mitigation |
|---|---|
| Unbounded transcript size | Hard cap + drop-oldest or summarize |
| SQLite write amplification | Batch append once per cycle |
| Stale tool definitions in old messages | Inject system note on toolkit version change |
Rollback: config daemon.pursuit_resume: false restores single-shot behavior.
Acceptance criteria (testable)¶
- [x] Mock agent with
max_steps=2per cycle completes a 4-step goal across two heartbeat cycles with monotonic step counter in logs. - [x] Transcript replay: second cycle's provider receives prior assistant/tool messages (assert on mock message list).
- [x] Goal completion deletes transcript rows/files for that
goal_id. - [x] Restart daemon mid-goal: reload transcript from disk and continue (integration test with temp hive dir).
Suggested implementation order¶
- Design doc section + config keys.
- Store module + unit tests.
- Bridge hydrate/persist hooks.
agent_cycle.pyintegration + Phase B outcome flags.- Integration test + docs.
Estimate¶
L (4--6 days): persistence design, migration, integration tests.
Dependencies (prior phases)¶
- Phase B --
MAX_STEPScontinue policy and wiredmax_stepsmust be defined first. - Phase D (soft) -- timeout should persist spend + transcript, not abandon blindly.