feat(coding-agent): curate restored state, frame heartbeats, and add violation counters
1144 unmodified linesExpand all11451146114711481149115011511152115311541155115611571158115911601144 unmodified linesExpand all state.search(42) with self.assertRaises(TypeError): state.search("worktree", limit=0)
def test_record_violation_and_overview(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: state = HarnessState(Path(temp_dir) / "harness_state.json") state.create_prompt_note("Test rule", "Follow negative control.", id="rule") self.assertNotIn("violation", state.overview()) entry = state.record_violation("rule", count=1) self.assertEqual(entry.violations, 1) self.assertIn("v1, 1 violation", state.overview()) entry = state.record_violation("rule", count=2) self.assertEqual(entry.violations, 3) self.assertIn("v1, 3 violations", state.overview())
123- Changed restored-state notices and continuation messages to summarize kernel state and carry last verified state instead of dumping variable names.- Changed heartbeat prompts to format as harness heartbeats with instructions and labels instead of plain user messages.- Added violation counters on continual harness notes with escalation to automated checks on repeated violations.590 unmodified linesExpand all591592593594595596595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624576 unmodified linesExpand all1201120212031204118212051206120712081209623 unmodified linesExpand all590 unmodified linesExpand all }); }}
const UPDATE_RESTART_CONTINUATION_PROMPT = "Prime Agent restarted after an update. Continue the interrupted task from the saved transcript and restored tool/kernel state. Inspect current state before retrying commands when needed.";export function buildUpdateRestartContinuationPrompt(session: DaemonUpdateRestartSession): string { const interruptedActivities: string[] = []; if (session.wasStreaming) interruptedActivities.push("streaming a turn"); if (session.wasCompacting) interruptedActivities.push("compacting context"); if (session.wasBashRunning) interruptedActivities.push("running background bash execution"); if (session.hadRunningRlmChildren) interruptedActivities.push("running subagents"); if (session.wasRetrying) interruptedActivities.push("retrying an operation"); if (session.hadAcceptedPromptInFlight) interruptedActivities.push("processing an in-flight prompt");
const activitySummary = interruptedActivities.length > 0 ? `Interrupted activity: ${interruptedActivities.join(", ")}.` : "Interrupted while waiting for next turn.";
const queueDetails = session.queue.actions.actions.length > 0 ? ` Restored queued actions: ${session.queue.actions.actions.length}.` : "";
return [ "Prime Agent restarted after an update.", `Last verified state: working directory is ${session.cwd}. ${activitySummary}${queueDetails}`, "Continue the interrupted task from the saved transcript and verified state instead of starting over.", ].join("\n\n");}
const UPDATE_SESSION_LOSS_COPY: DaemonSessionLossCopy = { busyDetail(count) { const { noun, pronoun } = pluralizeSessions(count); return `Prime Agent has ${count} busy ${noun}. After the update installs, it will stop ${pronoun}, restart its background service, and resume interrupted work.`;576 unmodified linesExpand all const promptResponse = await client.request( { type: "prompt", activeSessionId, message: UPDATE_RESTART_CONTINUATION_PROMPT, message: buildUpdateRestartContinuationPrompt(session), expandPromptTemplates: false, }, 120000, );623 unmodified linesExpand all26 unmodified lines272829303132333435939 unmodified linesExpand all97597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004134 unmodified linesExpand all26 unmodified lines type RefinementAction, type RefinementKind, type RefinementProposal, type RefinementResult, recordHarnessViolation, refineHarness, saveHarnessState, scoreHarnessEntryForQuery, selectOverviewEntries,939 unmodified linesExpand all expect(formatHarnessStateForPrompt(state, { maxEntriesPerKind: 1 })).toContain("[global:aaa]"); expect(() => formatHarnessStateForPrompt(state, { queryTerms: new Map([["worktree", 1]]) })).not.toThrow(); });
it("records violation counts and surfaces them in the harness digest", () => { const state = loadHarnessState(join(makeTempDir(), "h"), "local"); state.entries.prompt.note = makeEntry( "note", "Negative control check", "Verify before claiming pass.", "2026-08-01T00:00:00.000Z", );
const initialOverview = formatHarnessStateForPrompt(state); expect(initialOverview).toContain("[global:note] Negative control check (memory, v1):"); expect(initialOverview).not.toContain("v1,");
recordHarnessViolation(state, "note", 1); const oneViolationOverview = formatHarnessStateForPrompt(state); expect(oneViolationOverview).toContain("[global:note] Negative control check (memory, v1, 1 violation):");
recordHarnessViolation(state, "note", 1); const twoViolationsOverview = formatHarnessStateForPrompt(state); expect(twoViolationsOverview).toContain("[global:note] Negative control check (memory, v1, 2 violations):"); });
it.each<[string, string[]]>([ ["Worktree?", ["worktree"]], ["path/to/skill", ["path", "skill"]], ["harness_search", ["harness", "search"]],134 unmodified linesExpand all31 unmodified lines323334353637383940250 unmodified linesExpand all29129229329429429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034189 unmodified lines31 unmodified linesimport { buildConversationComponents } from "../src/modes/interactive/components/conversation-components.js";import { SlashCommandMessageComponent } from "../src/modes/interactive/components/slash-command-message.js";import { SlashCommandResultMessageComponent } from "../src/modes/interactive/components/slash-command-result-message.js";import { initTheme } from "../src/modes/interactive/theme/theme.js";import { buildUpdateRestartContinuationPrompt } from "../src/package-manager-cli.js";
const componentOptions = { ui: { requestRender: vi.fn() } as unknown as TUI, cwd: "/tmp",250 unmodified linesExpand all createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", runCount: 1, }).content, ).toBe("[heartbeat: every 10 minutes run#1]\n\ncheck in"); ).toBe("[heartbeat: every 10 minutes run#1]\n\nHarness heartbeat.\nInstruction: check in");
expect( createHeartbeatPromptMessage({ id: "hb-labeled", status: "active", source: "heartbeat", label: "periodic check", activeSessionId: "a", sessionId: "s", sessionFile: "/tmp/s.jsonl", cwd: "/tmp", prompt: "check in", schedule: { kind: "interval", expression: "every 5m", intervalMs: 300_000 }, createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z", runCount: 2, }).content, ).toBe("[heartbeat: every 5m run#2]\n\nHarness heartbeat: periodic check.\nInstruction: check in"); });
test("restart continuation prompt carries last verified state instead of generic inspection", () => { const prompt = buildUpdateRestartContinuationPrompt({ activeSessionId: "active-1", sessionId: "session-1", sessionFile: "/tmp/s.jsonl", cwd: "/work/project", config: {} as never, queue: { actions: { formatVersion: 1, actions: [{ payload: { kind: "turn" } } as never] }, nextTurn: [] }, shouldResume: true, wasStreaming: true, wasCompacting: false, wasBashRunning: false, hadRunningRlmChildren: true, wasRetrying: false, hadAcceptedPromptInFlight: false, }); expect(prompt).toContain( "Last verified state: working directory is /work/project. Interrupted activity: streaming a turn, running subagents. Restored queued actions: 1.", ); expect(prompt).not.toContain("Inspect current state"); });
test("every constructor-backed synthetic kind opens with a grammar-conforming bracket line", () => { const goal: GoalState = { active: true, status: "active",89 unmodified lines180 unmodified linesExpand all181182183184185186187188189574 unmodified linesExpand all76476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379474 unmodified lines869870871872873874875876877878850879880881882883106 unmodified linesExpand all180 unmodified linesExpand all source: str = "agent" created_at: str = field(default_factory=_now) updated_at: str = field(default_factory=_now) version: int = 1 violations: int = 0
@dataclassclass RefinementEvent:574 unmodified linesExpand all
def delete_subagent(self, id: str, *, global_: bool = False, **kwargs: Any) -> bool: return self.delete("subagent", id, global_=global_, **kwargs)
def record_violation( self, id: str, count: int = 1, *, global_: bool = False, **kwargs: Any, ) -> HarnessEntry: """Increment the violation counter for a harness note.""" if target := self._global_target(global_, kwargs): return target.record_violation(id, count=count) self._ensure_local_writable() self._sync_from_disk() cleaned_id, global_ = _strip_scope_prefix(id, global_) for kind in _KINDS: if cleaned_id in self.entries[kind]: entry = self.entries[kind][cleaned_id] entry.violations = max(0, entry.violations + count) entry.updated_at = _now() self.save() return entry raise KeyError(f"Harness entry not found: {id}")
def record_refinement( self, trigger: str, changes: list[str] | str,74 unmodified lines reference_text = json.dumps(entry.reference, ensure_ascii=False, sort_keys=True) if len(reference_text) > 120: reference_text = f"{reference_text[:117]}..." reference_summary = f" ref={reference_text}" violation_text = ( f", {entry.violations} violation{'s' if entry.violations != 1 else ''}" if entry.violations > 0 else "" ) lines.append( f" - [{entry.scope}:{entry.id}] {entry.title} ({entry.path}, v{entry.version})" f" - [{entry.scope}:{entry.id}] {entry.title} ({entry.path}, v{entry.version}{violation_text})" f"{reference_summary}{argument_summary}: {summary}" ) overflow = len(self.entries[kind]) - len(records) if overflow > 0:106 unmodified linesExpand all