pi forum: fold long messages in the transcript, whole on expand A message of up to 4000 characters printed in full in both panes; show its first 10 lines, or 1000 characters, and how much more there is, as pi does for tool output. The model still gets the whole text.
Igor Soarez igor@soarez.org
Fri, 06 Nov 2026 13:58:14 +0200
1 files changed,
26 insertions(+),
4 deletions(-)
jump to
M
config/pi/extensions/forum.ts
→
config/pi/extensions/forum.ts
@@ -84,7 +84,7 @@ import net from "node:net";
import { homedir } from "node:os"; import { join } from "node:path"; import { StringEnum } from "@earendil-works/pi-ai"; -import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent"; +import { type ExtensionAPI, type ExtensionContext, keyHint } from "@earendil-works/pi-coding-agent"; import { Box, Text } from "@earendil-works/pi-tui"; import { type Static, Type } from "typebox";@@ -98,6 +98,9 @@ const MAX_PIN = 200;
const READ_DEFAULT = 20; const READ_MAX = 50; const READ_MAX_CHARS = 30_000; +// A message folded in the transcript: at most this many lines, or characters. +const FOLD_LINES = 10; +const FOLD_CHARS = 1000; const TICK_MS = 2000; const LABEL_EVERY_MS = 15_000; const REQUEST_TIMEOUT_MS = 3000;@@ -328,6 +331,20 @@ return one.length > n ? `${one.slice(0, n - 1)}…` : one;
} const who = (s: Sender) => `${s.label} [${s.id}]`; + +// A message for the transcript: whole when expanded, otherwise its first +// FOLD_LINES lines (FOLD_CHARS at most, for one long line) and how much more +// there is. Display only: the model always has the whole text. +function fold(text: string, expanded: boolean): string { + if (expanded) return text; + let shown = text.split("\n").slice(0, FOLD_LINES).join("\n"); + if (shown.length > FOLD_CHARS) shown = shown.slice(0, FOLD_CHARS); + if (shown.length === text.length) return text; + const rest = text.slice(shown.length); + const lines = rest.split("\n").length - (rest.startsWith("\n") ? 1 : 0); + const more = lines > 1 ? `${lines} more lines` : `${rest.length} more characters`; + return `${shown}…\n(${more}, ${keyHint("app.tools.expand", "to expand")})`; +} // --- labels ----------------------------------------------------------------@@ -1050,13 +1067,18 @@ }
return { content: [{ type: "text", text }], details: undefined }; }, - renderCall(args, theme) { + renderCall(args, theme, context) { let head = theme.fg("toolTitle", theme.bold("forum ")) + theme.fg("muted", args.action); if (args.forum) head += ` ${theme.fg("accent", args.forum)}`; if (args.to) head += ` ${theme.fg("accent", `→ ${args.to}`)}`; if (args.mention?.length) head += ` ${theme.fg("accent", args.mention.map((m: string) => `@${m}`).join(" "))}`; if (args.from !== undefined) head += theme.fg("dim", ` from #${args.from}`); - const body = args.text && args.action !== "pin" ? `\n${args.text}` : args.text ? ` ${theme.fg("dim", `"${args.text}"`)}` : ""; + const body = + args.text && args.action !== "pin" + ? `\n${fold(args.text, context.expanded)}` + : args.text + ? ` ${theme.fg("dim", `"${args.text}"`)}` + : ""; return new Text(head + body, 0, 0); }, });@@ -1196,7 +1218,7 @@ ? `Forum · message from ${who(d.from)}`
: `Forum · ${d.forumName} #${d.postNo} · ${d.all ? "@all" : "@you"} from ${who(d.from)}` : "Forum message"; const sub = theme.fg("dim", " another agent, not typed by you"); - const body = expanded || !d ? String(message.content) : d.text; + const body = expanded || !d ? String(message.content) : fold(d.text, false); const box = new Box(outputPad, 1, (t) => theme.bg("customMessageBg", t)); box.addChild(new Text(`${theme.fg("warning", theme.bold(head))}${sub}\n${body}`, 0, 0)); return box;