Remove post-turn "Cogitated for Xs" inline summary

Caused more trouble than it was worth — even with the context-event
filter stripping the custom message from LLM input, the transcript
entry could still influence the agent in subtle ways (model looking
at it on re-render, extension-interactions, export), and the visual
clutter after every turn wasn't worth the diagnostic value.

Removed:
- pi.registerMessageRenderer("cogitation-summary", ...)
- pi.sendMessage on turn_end
- pi.on("context") filter (no longer needed; nothing to strip)
- Box/Text imports from @mariozechner/pi-tui
- SUMMARY_TYPE constant

Kept:
- Live indicator: ⚙ <quote> · <elapsed> during streaming, with the
  cog pulse and quote rotation and the "Working..." suppression.
- Footer tok/s (lives in mechanicus-footer, not affected).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 23:41:45 +02:00
parent 423c1adc20
commit 19afcd5358
+9 -64
View File
@@ -1,35 +1,25 @@
/**
* dark-mechanicus-indicator — the working indicator AND the post-turn
* duration summary, all in one extension.
* dark-mechanicus-indicator — live working indicator during streaming.
*
* Mechanics:
*
* 1. Live indicator (during streaming):
* "⚙ <quote> · <elapsed>"
* The ⚙ pulses through four shades of gold (dim → normal → bright →
* normal, 250ms each) so a full pulse lasts 1 second. Every second
* the frames array is rebuilt with a freshly-formatted elapsed time
* and (every 10 seconds) a rotated quote. Because 1s of wall time
* equals exactly one pulse cycle, the reset lands at frame 0 and
* the animation looks seamless.
*
* 2. Post-turn summary:
* "✴ Cogitated for <total>"
* Injected as a custom message in the transcript right after the
* last assistant message, via pi.sendMessage + a registered
* message renderer.
* The ⚙ pulses through four shades of gold (dim → normal → bright →
* normal, 250ms each) so a full pulse lasts 1 second. Every second the
* frames array is rebuilt with a freshly-formatted elapsed time and
* (every 10 seconds) a rotated quote. Because 1s of wall time equals
* exactly one pulse cycle, the reset lands at frame 0 and the animation
* looks seamless.
*
* Quote pool (45 lines = 15 heretek / 15 dark / 15 operational). Fresh
* Fisher-Yates shuffle on every turn_start so the order differs per
* assistant response.
*
* Commands:
* /dark-mechanicus-indicator-off Restore pi's default spinner + skip summary
* /dark-mechanicus-indicator-off Restore pi's default spinner
* /dark-mechanicus-indicator-on Re-enable the mechanicum indicator
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { Box, Text } from "@mariozechner/pi-tui";
// ─── Quote pools (15 per category) ───────────────────────────────────────
@@ -104,7 +94,6 @@ const PULSE_SHADES = [GOLD_DIM, GOLD_NORMAL, GOLD_BRIGHT, GOLD_NORMAL];
const FRAME_INTERVAL_MS = 250; // 4 shades × 250ms = 1s pulse
const TICK_MS = 1000; // rebuild frames once per second
const QUOTE_DWELL_MS = 10_000; // switch quote every 10 seconds
const SUMMARY_TYPE = "cogitation-summary";
// ─── Helpers ─────────────────────────────────────────────────────────────
@@ -174,37 +163,6 @@ export default function (pi: ExtensionAPI) {
});
};
// ── Post-turn summary renderer ───────────────────────────────────
pi.registerMessageRenderer(
SUMMARY_TYPE,
(message, _options, theme) => {
const details = message.details as { elapsedMs?: number } | undefined;
const elapsedMs = details?.elapsedMs ?? 0;
const text = `${theme.fg("accent", "✴")} ${theme.fg(
"muted",
`Cogitated for ${formatElapsed(elapsedMs)}`,
)}`;
const box = new Box(1, 0, (t) => theme.bg("customMessageBg", t));
box.addChild(new Text(text, 0, 0));
return box;
},
);
// ── Strip summary messages from LLM context ─────────────────────
// pi's convertToLlm() turns every custom message into a `role: "user"`
// entry before sending to the provider, so without filtering here the
// model sees "Cogitated for 1m 24s" as a user turn and responds to it.
// This hook runs before each provider call and returns a messages array
// with our summaries removed.
pi.on("context", async (event) => {
return {
messages: event.messages.filter(
(m: any) =>
!(m.role === "custom" && m.customType === SUMMARY_TYPE),
),
};
});
// ── Seed at session start so pi's default spinner never appears ──
pi.on("session_start", async (_event, ctx) => {
suppressWorkingMessage(ctx);
@@ -221,22 +179,9 @@ export default function (pi: ExtensionAPI) {
tickerHandle = setInterval(() => applyFrame(ctx), TICK_MS);
});
pi.on("turn_end", async (_event, _ctx) => {
pi.on("turn_end", async () => {
stopTicker();
if (startedAt === null) return;
const elapsedMs = Date.now() - startedAt;
startedAt = null;
if (mode === "off") return;
try {
await pi.sendMessage({
customType: SUMMARY_TYPE,
content: `Cogitated for ${formatElapsed(elapsedMs)}`,
display: true,
details: { elapsedMs },
});
} catch {
// sendMessage may not be available in non-interactive modes; ignore.
}
});
pi.on("session_shutdown", async () => {