Skip to content

feat(nudge): persist nudge injections as display-only session entries + single-line acp.log (closes #326) - #329

Open
ranxianglei wants to merge 1 commit into
masterfrom
2026-09-08_persist-nudge-records
Open

feat(nudge): persist nudge injections as display-only session entries + single-line acp.log (closes #326)#329
ranxianglei wants to merge 1 commit into
masterfrom
2026-09-08_persist-nudge-records

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Closes #326.

Triage / verification

Changes

  • Persistence (src/index.ts): on nudge injection, append a compact one-line record (e.g. [ACP nudge] EMERGENCY 95% · T1 · top range m00120–m00168) via pi.appendEntry("acp-nudge", {text}). Deduped per user turn — emergency nudges re-inject on every LLM call until retry-capped and must not flood the session file. markNudgeRecorded runs only after a successful append (a failed append retries on the next fire). Recorded-state cleared at session start alongside nudge-shown tracking.
  • Renderer (src/index.ts): registerEntryRenderer("acp-nudge", ...) renders the record as a dim boxed line (pi-tui Box/Text, customMessageBg background). @earendil-works/pi-tui added as devDependency pinned exactly 0.83.0 (matching the host) and bundled inline by tsup — dist stays zero-runtime-deps (verified: no bare pi-tui import remains in the bundle).
  • Single-line log (src/log.ts): \r/\n in string fields (including Error.stack) are escaped to literals, so every acp.log entry occupies exactly one physical line — grep nudge-injected now returns the full nudge body instead of just the headline.
  • Docs: README Logging section (nudge audit trail + one-entry-per-line guarantee), CHANGELOG.

Tests (4 new; full suite green)

  • formatNudgeRecord unit — exact-string assertions matching the issue example (emergency/non-emergency, tier, missing ranges).
  • Integration — emergency overflow recipe (180K window vs ~270K sent view): renderer registered at factory time; exactly one persisted record per user turn across three context fires (emergency re-injection still reaches the model but must not duplicate the record); a new user message yields the next record.
  • Renderer unit — well-formed record → box with one text child; empty data → undefined (invisible but persisted).
  • log.test.ts — multi-line field values (nudge text + stack trace) stay on one tagged physical line.

Verification

  • npm run typecheck
  • npm test ✅ — 466 pass / 3 skipped / 0 fail (469 total)
  • npm run build ✅ — dist 627 KB, pi-tui fully inlined
  • Smoke-loaded the built dist/index.js in plain node ✅

… + single-line acp.log (closes #326)

- pi.appendEntry("acp-nudge", {text}) on injection: compact one-line record
  ([ACP nudge] EMERGENCY 95% · T1 · top range m00120–m00168), deduped per user
  turn; survives restarts (session JSONL), visible in TUI scrollback via a
  registered entry renderer (pi-tui Box/Text, bundled inline), never sent to
  the model (type:"custom" entries are not projected into the sent view)
- log.ts: escape \r/\n in string fields (incl. stacks) so every acp.log entry
  occupies one physical line -> nudge-injected entries self-contained for grep
- devDep @earendil-works/pi-tui pinned exactly 0.83.0 (matches host); dist
  stays zero-runtime-deps
- tests: formatNudgeRecord unit, persistence/dedup integration (emergency
  re-injection must not duplicate records), renderer unit, log single-line
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] Persist nudge echoes as session entries (survive restarts, grep-able log)

1 participant