feat(user-input-fold): 超长用户输入在 transcript 里折叠显示 - #42

Merged
tt-a1i merged 5 commits into
mainfrom
user-input-fold
Aug 22, 2026
Merged

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示#42
tt-a1i merged 5 commits into
mainfrom
user-input-fold

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#40

用户粘贴几百行日志/堆栈/整个文件发送后,pi 把它作为普通用户消息全文渲染,直接刷掉好几屏。而工具输出、子代理结果在本包里都早有折叠,用户消息是唯一没有折叠机制的 transcript 内容——偏偏它可能是最长的。

机制:registerMarkdownTransformer,display-only

pi 的这个 hook 文档明确写了「the original message remains unchanged in the session and model context」。所以:折叠只改 TUI 显示,session 文件和模型上下文里永远是完整原文。这是本 PR 的红线,写进了模块头,并有纯函数测试保证 foldUserMessage 不修改输入。

顺带确认:copy-all 读的是 sessionManager.getBranch()(session 真相源),不受折叠影响,复制出去的仍是完整原文。

折叠规则

  • 触发:> 20 行 或 > 1,200 字符
  • 预览:散文保留 12 行(另有 1,200 字符预算);每个 ``` 代码块保留「开栏 + 语言标记 + 前 4 行 + + 闭栏」——整块折叠,绝不在行中间切,fence 始终闭合
  • 最小收益门槛:只有当折叠能隐藏 ≥ 8 行时才折。少于 8 行就原样渲染
  • marker… folded N lines · full content was sent to the model —— 措辞必须让用户知道模型收到的是完整内容,否则会以为被截断而重复粘贴

那条最小收益门槛是 review 时实测发现的:openpi 自己注入的 /openpi-setup 提示(16 行、因一条极长的 guidance 行而超字符阈值)原本只折掉 4 行,净省 3 行屏幕,代价却是隐藏了 Agent role models / Intercom 这两行用户本来要读的配置摘要。而且字符触发的折叠对「行少但行长」的消息几乎没有屏幕收益——剩下的长行照样换行占多行。折叠必须自己挣回成本。

实测

500 行日志 → 13 行;300 行代码块 → 保留块头 4 行且 fence 闭合(实测 ``` 计数为偶数);setup 提示 → 原样保留

边界与兜底

覆盖并测试:阈值上下各一(19 行隐藏 7 行 → 不折;20 行隐藏 8 行 → 折)、单个巨型代码块、多代码块夹散文、CRLF、结尾换行、阈值下含代码块、空/纯空白、未闭合 fence(保守按文本折)、纯函数性、短消息逐字节一致。transformer 外层有 try/catch——折叠出 bug 也只是退回原文,绝不弄坏渲染。

验证

  • bun run test758 + 29 全绿(基线 739 + 29,新增 19 个测试)
  • bun run check 退出 0(仅剩 file-search/binaries.ts 既存 warning)

Register a display-only markdown transformer that folds finalized user
messages over 20 lines or 1,200 characters into a short preview (12 prose
lines, first 4 content lines per fenced code block) plus a marker stating
how many lines were folded and that the full content was still sent to the
model. The session and model context keep the original message untouched.
Closes#40.
… itself
A char-triggered fold on a message with few but very long lines (e.g. the
/openpi-setup prompt) hid only a handful of lines while saving almost no
screen rows, because the remaining long lines still wrap. Gate folding on
hiding at least 8 lines; below that the message renders byte-identical in
full. Thresholds, preview budgets, marker wording, and the display-only
contract are unchanged.
Refs #40.
@tt-a1i

Copy link
Copy Markdown
CollaboratorAuthor

合并前补充审查:原实现对每个 fenced code block 单独应用预览上限,大量短代码块会绕过折叠预算,极端情况下折叠后反而比原文更长。现已改为所有 prose/code block 共享 20 行全局预览预算,并补充多块与 700 行压力回归。当前分支验证:783 Node tests + 30 Vitest;bun run check 通过。最新 Node 22/24 CI 全绿。

@tt-a1i
tt-a1i merged commit 2b35548 into mainAug 22, 2026
4 checks passed
Sign up for freeto 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.

超长用户输入发送后全文展开刷屏,应折叠显示(display-only)

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示 - #42

Merged
tt-a1i merged 5 commits into
mainfrom
user-input-fold
Aug 22, 2026
Merged

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示#42
tt-a1i merged 5 commits into
mainfrom
user-input-fold

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#40

用户粘贴几百行日志/堆栈/整个文件发送后,pi 把它作为普通用户消息全文渲染,直接刷掉好几屏。而工具输出、子代理结果在本包里都早有折叠,用户消息是唯一没有折叠机制的 transcript 内容——偏偏它可能是最长的。

机制:registerMarkdownTransformer,display-only

pi 的这个 hook 文档明确写了「the original message remains unchanged in the session and model context」。所以:折叠只改 TUI 显示,session 文件和模型上下文里永远是完整原文。这是本 PR 的红线,写进了模块头,并有纯函数测试保证 foldUserMessage 不修改输入。

顺带确认:copy-all 读的是 sessionManager.getBranch()(session 真相源),不受折叠影响,复制出去的仍是完整原文。

折叠规则

  • 触发:> 20 行 或 > 1,200 字符
  • 预览:散文保留 12 行(另有 1,200 字符预算);每个 ``` 代码块保留「开栏 + 语言标记 + 前 4 行 + + 闭栏」——整块折叠,绝不在行中间切,fence 始终闭合
  • 最小收益门槛:只有当折叠能隐藏 ≥ 8 行时才折。少于 8 行就原样渲染
  • marker… folded N lines · full content was sent to the model —— 措辞必须让用户知道模型收到的是完整内容,否则会以为被截断而重复粘贴

那条最小收益门槛是 review 时实测发现的:openpi 自己注入的 /openpi-setup 提示(16 行、因一条极长的 guidance 行而超字符阈值)原本只折掉 4 行,净省 3 行屏幕,代价却是隐藏了 Agent role models / Intercom 这两行用户本来要读的配置摘要。而且字符触发的折叠对「行少但行长」的消息几乎没有屏幕收益——剩下的长行照样换行占多行。折叠必须自己挣回成本。

实测

500 行日志 → 13 行;300 行代码块 → 保留块头 4 行且 fence 闭合(实测 ``` 计数为偶数);setup 提示 → 原样保留

边界与兜底

覆盖并测试:阈值上下各一(19 行隐藏 7 行 → 不折;20 行隐藏 8 行 → 折)、单个巨型代码块、多代码块夹散文、CRLF、结尾换行、阈值下含代码块、空/纯空白、未闭合 fence(保守按文本折)、纯函数性、短消息逐字节一致。transformer 外层有 try/catch——折叠出 bug 也只是退回原文,绝不弄坏渲染。

验证

  • bun run test758 + 29 全绿(基线 739 + 29,新增 19 个测试)
  • bun run check 退出 0(仅剩 file-search/binaries.ts 既存 warning)

Register a display-only markdown transformer that folds finalized user
messages over 20 lines or 1,200 characters into a short preview (12 prose
lines, first 4 content lines per fenced code block) plus a marker stating
how many lines were folded and that the full content was still sent to the
model. The session and model context keep the original message untouched.
Closes#40.
… itself
A char-triggered fold on a message with few but very long lines (e.g. the
/openpi-setup prompt) hid only a handful of lines while saving almost no
screen rows, because the remaining long lines still wrap. Gate folding on
hiding at least 8 lines; below that the message renders byte-identical in
full. Thresholds, preview budgets, marker wording, and the display-only
contract are unchanged.
Refs #40.
@tt-a1i

Copy link
Copy Markdown
CollaboratorAuthor

合并前补充审查:原实现对每个 fenced code block 单独应用预览上限,大量短代码块会绕过折叠预算,极端情况下折叠后反而比原文更长。现已改为所有 prose/code block 共享 20 行全局预览预算,并补充多块与 700 行压力回归。当前分支验证:783 Node tests + 30 Vitest;bun run check 通过。最新 Node 22/24 CI 全绿。

@tt-a1i
tt-a1i merged commit 2b35548 into mainAug 22, 2026
4 checks passed
Sign up for freeto 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.

超长用户输入发送后全文展开刷屏,应折叠显示(display-only)

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示 - #42

Merged
tt-a1i merged 5 commits into
mainfrom
user-input-fold
Aug 22, 2026
Merged

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示#42
tt-a1i merged 5 commits into
mainfrom
user-input-fold

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#40

用户粘贴几百行日志/堆栈/整个文件发送后,pi 把它作为普通用户消息全文渲染,直接刷掉好几屏。而工具输出、子代理结果在本包里都早有折叠,用户消息是唯一没有折叠机制的 transcript 内容——偏偏它可能是最长的。

机制:registerMarkdownTransformer,display-only

pi 的这个 hook 文档明确写了「the original message remains unchanged in the session and model context」。所以:折叠只改 TUI 显示,session 文件和模型上下文里永远是完整原文。这是本 PR 的红线,写进了模块头,并有纯函数测试保证 foldUserMessage 不修改输入。

顺带确认:copy-all 读的是 sessionManager.getBranch()(session 真相源),不受折叠影响,复制出去的仍是完整原文。

折叠规则

  • 触发:> 20 行 或 > 1,200 字符
  • 预览:散文保留 12 行(另有 1,200 字符预算);每个 ``` 代码块保留「开栏 + 语言标记 + 前 4 行 + + 闭栏」——整块折叠,绝不在行中间切,fence 始终闭合
  • 最小收益门槛:只有当折叠能隐藏 ≥ 8 行时才折。少于 8 行就原样渲染
  • marker… folded N lines · full content was sent to the model —— 措辞必须让用户知道模型收到的是完整内容,否则会以为被截断而重复粘贴

那条最小收益门槛是 review 时实测发现的:openpi 自己注入的 /openpi-setup 提示(16 行、因一条极长的 guidance 行而超字符阈值)原本只折掉 4 行,净省 3 行屏幕,代价却是隐藏了 Agent role models / Intercom 这两行用户本来要读的配置摘要。而且字符触发的折叠对「行少但行长」的消息几乎没有屏幕收益——剩下的长行照样换行占多行。折叠必须自己挣回成本。

实测

500 行日志 → 13 行;300 行代码块 → 保留块头 4 行且 fence 闭合(实测 ``` 计数为偶数);setup 提示 → 原样保留

边界与兜底

覆盖并测试:阈值上下各一(19 行隐藏 7 行 → 不折;20 行隐藏 8 行 → 折)、单个巨型代码块、多代码块夹散文、CRLF、结尾换行、阈值下含代码块、空/纯空白、未闭合 fence(保守按文本折)、纯函数性、短消息逐字节一致。transformer 外层有 try/catch——折叠出 bug 也只是退回原文,绝不弄坏渲染。

验证

  • bun run test758 + 29 全绿(基线 739 + 29,新增 19 个测试)
  • bun run check 退出 0(仅剩 file-search/binaries.ts 既存 warning)

Register a display-only markdown transformer that folds finalized user
messages over 20 lines or 1,200 characters into a short preview (12 prose
lines, first 4 content lines per fenced code block) plus a marker stating
how many lines were folded and that the full content was still sent to the
model. The session and model context keep the original message untouched.
Closes#40.
… itself
A char-triggered fold on a message with few but very long lines (e.g. the
/openpi-setup prompt) hid only a handful of lines while saving almost no
screen rows, because the remaining long lines still wrap. Gate folding on
hiding at least 8 lines; below that the message renders byte-identical in
full. Thresholds, preview budgets, marker wording, and the display-only
contract are unchanged.
Refs #40.
@tt-a1i

Copy link
Copy Markdown
CollaboratorAuthor

合并前补充审查:原实现对每个 fenced code block 单独应用预览上限,大量短代码块会绕过折叠预算,极端情况下折叠后反而比原文更长。现已改为所有 prose/code block 共享 20 行全局预览预算,并补充多块与 700 行压力回归。当前分支验证:783 Node tests + 30 Vitest;bun run check 通过。最新 Node 22/24 CI 全绿。

@tt-a1i
tt-a1i merged commit 2b35548 into mainAug 22, 2026
4 checks passed
Sign up for freeto 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.

超长用户输入发送后全文展开刷屏,应折叠显示(display-only)

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示 - #42

Merged
tt-a1i merged 5 commits into
mainfrom
user-input-fold
Aug 22, 2026
Merged

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示#42
tt-a1i merged 5 commits into
mainfrom
user-input-fold

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#40

用户粘贴几百行日志/堆栈/整个文件发送后,pi 把它作为普通用户消息全文渲染,直接刷掉好几屏。而工具输出、子代理结果在本包里都早有折叠,用户消息是唯一没有折叠机制的 transcript 内容——偏偏它可能是最长的。

机制:registerMarkdownTransformer,display-only

pi 的这个 hook 文档明确写了「the original message remains unchanged in the session and model context」。所以:折叠只改 TUI 显示,session 文件和模型上下文里永远是完整原文。这是本 PR 的红线,写进了模块头,并有纯函数测试保证 foldUserMessage 不修改输入。

顺带确认:copy-all 读的是 sessionManager.getBranch()(session 真相源),不受折叠影响,复制出去的仍是完整原文。

折叠规则

  • 触发:> 20 行 或 > 1,200 字符
  • 预览:散文保留 12 行(另有 1,200 字符预算);每个 ``` 代码块保留「开栏 + 语言标记 + 前 4 行 + + 闭栏」——整块折叠,绝不在行中间切,fence 始终闭合
  • 最小收益门槛:只有当折叠能隐藏 ≥ 8 行时才折。少于 8 行就原样渲染
  • marker… folded N lines · full content was sent to the model —— 措辞必须让用户知道模型收到的是完整内容,否则会以为被截断而重复粘贴

那条最小收益门槛是 review 时实测发现的:openpi 自己注入的 /openpi-setup 提示(16 行、因一条极长的 guidance 行而超字符阈值)原本只折掉 4 行,净省 3 行屏幕,代价却是隐藏了 Agent role models / Intercom 这两行用户本来要读的配置摘要。而且字符触发的折叠对「行少但行长」的消息几乎没有屏幕收益——剩下的长行照样换行占多行。折叠必须自己挣回成本。

实测

500 行日志 → 13 行;300 行代码块 → 保留块头 4 行且 fence 闭合(实测 ``` 计数为偶数);setup 提示 → 原样保留

边界与兜底

覆盖并测试:阈值上下各一(19 行隐藏 7 行 → 不折;20 行隐藏 8 行 → 折)、单个巨型代码块、多代码块夹散文、CRLF、结尾换行、阈值下含代码块、空/纯空白、未闭合 fence(保守按文本折)、纯函数性、短消息逐字节一致。transformer 外层有 try/catch——折叠出 bug 也只是退回原文,绝不弄坏渲染。

验证

  • bun run test758 + 29 全绿(基线 739 + 29,新增 19 个测试)
  • bun run check 退出 0(仅剩 file-search/binaries.ts 既存 warning)

Register a display-only markdown transformer that folds finalized user
messages over 20 lines or 1,200 characters into a short preview (12 prose
lines, first 4 content lines per fenced code block) plus a marker stating
how many lines were folded and that the full content was still sent to the
model. The session and model context keep the original message untouched.
Closes#40.
… itself
A char-triggered fold on a message with few but very long lines (e.g. the
/openpi-setup prompt) hid only a handful of lines while saving almost no
screen rows, because the remaining long lines still wrap. Gate folding on
hiding at least 8 lines; below that the message renders byte-identical in
full. Thresholds, preview budgets, marker wording, and the display-only
contract are unchanged.
Refs #40.
@tt-a1i

Copy link
Copy Markdown
CollaboratorAuthor

合并前补充审查:原实现对每个 fenced code block 单独应用预览上限,大量短代码块会绕过折叠预算,极端情况下折叠后反而比原文更长。现已改为所有 prose/code block 共享 20 行全局预览预算,并补充多块与 700 行压力回归。当前分支验证:783 Node tests + 30 Vitest;bun run check 通过。最新 Node 22/24 CI 全绿。

@tt-a1i
tt-a1i merged commit 2b35548 into mainAug 22, 2026
4 checks passed
Sign up for freeto 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.

超长用户输入发送后全文展开刷屏,应折叠显示(display-only)

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示 - #42

Merged
tt-a1i merged 5 commits into
mainfrom
user-input-fold
Aug 22, 2026
Merged

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示#42
tt-a1i merged 5 commits into
mainfrom
user-input-fold

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#40

用户粘贴几百行日志/堆栈/整个文件发送后,pi 把它作为普通用户消息全文渲染,直接刷掉好几屏。而工具输出、子代理结果在本包里都早有折叠,用户消息是唯一没有折叠机制的 transcript 内容——偏偏它可能是最长的。

机制:registerMarkdownTransformer,display-only

pi 的这个 hook 文档明确写了「the original message remains unchanged in the session and model context」。所以:折叠只改 TUI 显示,session 文件和模型上下文里永远是完整原文。这是本 PR 的红线,写进了模块头,并有纯函数测试保证 foldUserMessage 不修改输入。

顺带确认:copy-all 读的是 sessionManager.getBranch()(session 真相源),不受折叠影响,复制出去的仍是完整原文。

折叠规则

  • 触发:> 20 行 或 > 1,200 字符
  • 预览:散文保留 12 行(另有 1,200 字符预算);每个 ``` 代码块保留「开栏 + 语言标记 + 前 4 行 + + 闭栏」——整块折叠,绝不在行中间切,fence 始终闭合
  • 最小收益门槛:只有当折叠能隐藏 ≥ 8 行时才折。少于 8 行就原样渲染
  • marker… folded N lines · full content was sent to the model —— 措辞必须让用户知道模型收到的是完整内容,否则会以为被截断而重复粘贴

那条最小收益门槛是 review 时实测发现的:openpi 自己注入的 /openpi-setup 提示(16 行、因一条极长的 guidance 行而超字符阈值)原本只折掉 4 行,净省 3 行屏幕,代价却是隐藏了 Agent role models / Intercom 这两行用户本来要读的配置摘要。而且字符触发的折叠对「行少但行长」的消息几乎没有屏幕收益——剩下的长行照样换行占多行。折叠必须自己挣回成本。

实测

500 行日志 → 13 行;300 行代码块 → 保留块头 4 行且 fence 闭合(实测 ``` 计数为偶数);setup 提示 → 原样保留

边界与兜底

覆盖并测试:阈值上下各一(19 行隐藏 7 行 → 不折;20 行隐藏 8 行 → 折)、单个巨型代码块、多代码块夹散文、CRLF、结尾换行、阈值下含代码块、空/纯空白、未闭合 fence(保守按文本折)、纯函数性、短消息逐字节一致。transformer 外层有 try/catch——折叠出 bug 也只是退回原文,绝不弄坏渲染。

验证

  • bun run test758 + 29 全绿(基线 739 + 29,新增 19 个测试)
  • bun run check 退出 0(仅剩 file-search/binaries.ts 既存 warning)

Register a display-only markdown transformer that folds finalized user
messages over 20 lines or 1,200 characters into a short preview (12 prose
lines, first 4 content lines per fenced code block) plus a marker stating
how many lines were folded and that the full content was still sent to the
model. The session and model context keep the original message untouched.
Closes#40.
… itself
A char-triggered fold on a message with few but very long lines (e.g. the
/openpi-setup prompt) hid only a handful of lines while saving almost no
screen rows, because the remaining long lines still wrap. Gate folding on
hiding at least 8 lines; below that the message renders byte-identical in
full. Thresholds, preview budgets, marker wording, and the display-only
contract are unchanged.
Refs #40.
@tt-a1i

Copy link
Copy Markdown
CollaboratorAuthor

合并前补充审查:原实现对每个 fenced code block 单独应用预览上限,大量短代码块会绕过折叠预算,极端情况下折叠后反而比原文更长。现已改为所有 prose/code block 共享 20 行全局预览预算,并补充多块与 700 行压力回归。当前分支验证:783 Node tests + 30 Vitest;bun run check 通过。最新 Node 22/24 CI 全绿。

@tt-a1i
tt-a1i merged commit 2b35548 into mainAug 22, 2026
4 checks passed
Sign up for freeto 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.

超长用户输入发送后全文展开刷屏,应折叠显示(display-only)

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示 - #42

Merged
tt-a1i merged 5 commits into
mainfrom
user-input-fold
Aug 22, 2026
Merged

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示#42
tt-a1i merged 5 commits into
mainfrom
user-input-fold

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#40

用户粘贴几百行日志/堆栈/整个文件发送后,pi 把它作为普通用户消息全文渲染,直接刷掉好几屏。而工具输出、子代理结果在本包里都早有折叠,用户消息是唯一没有折叠机制的 transcript 内容——偏偏它可能是最长的。

机制:registerMarkdownTransformer,display-only

pi 的这个 hook 文档明确写了「the original message remains unchanged in the session and model context」。所以:折叠只改 TUI 显示,session 文件和模型上下文里永远是完整原文。这是本 PR 的红线,写进了模块头,并有纯函数测试保证 foldUserMessage 不修改输入。

顺带确认:copy-all 读的是 sessionManager.getBranch()(session 真相源),不受折叠影响,复制出去的仍是完整原文。

折叠规则

  • 触发:> 20 行 或 > 1,200 字符
  • 预览:散文保留 12 行(另有 1,200 字符预算);每个 ``` 代码块保留「开栏 + 语言标记 + 前 4 行 + + 闭栏」——整块折叠,绝不在行中间切,fence 始终闭合
  • 最小收益门槛:只有当折叠能隐藏 ≥ 8 行时才折。少于 8 行就原样渲染
  • marker… folded N lines · full content was sent to the model —— 措辞必须让用户知道模型收到的是完整内容,否则会以为被截断而重复粘贴

那条最小收益门槛是 review 时实测发现的:openpi 自己注入的 /openpi-setup 提示(16 行、因一条极长的 guidance 行而超字符阈值)原本只折掉 4 行,净省 3 行屏幕,代价却是隐藏了 Agent role models / Intercom 这两行用户本来要读的配置摘要。而且字符触发的折叠对「行少但行长」的消息几乎没有屏幕收益——剩下的长行照样换行占多行。折叠必须自己挣回成本。

实测

500 行日志 → 13 行;300 行代码块 → 保留块头 4 行且 fence 闭合(实测 ``` 计数为偶数);setup 提示 → 原样保留

边界与兜底

覆盖并测试:阈值上下各一(19 行隐藏 7 行 → 不折;20 行隐藏 8 行 → 折)、单个巨型代码块、多代码块夹散文、CRLF、结尾换行、阈值下含代码块、空/纯空白、未闭合 fence(保守按文本折)、纯函数性、短消息逐字节一致。transformer 外层有 try/catch——折叠出 bug 也只是退回原文,绝不弄坏渲染。

验证

  • bun run test758 + 29 全绿(基线 739 + 29,新增 19 个测试)
  • bun run check 退出 0(仅剩 file-search/binaries.ts 既存 warning)

Register a display-only markdown transformer that folds finalized user
messages over 20 lines or 1,200 characters into a short preview (12 prose
lines, first 4 content lines per fenced code block) plus a marker stating
how many lines were folded and that the full content was still sent to the
model. The session and model context keep the original message untouched.
Closes#40.
… itself
A char-triggered fold on a message with few but very long lines (e.g. the
/openpi-setup prompt) hid only a handful of lines while saving almost no
screen rows, because the remaining long lines still wrap. Gate folding on
hiding at least 8 lines; below that the message renders byte-identical in
full. Thresholds, preview budgets, marker wording, and the display-only
contract are unchanged.
Refs #40.
@tt-a1i

Copy link
Copy Markdown
CollaboratorAuthor

合并前补充审查:原实现对每个 fenced code block 单独应用预览上限,大量短代码块会绕过折叠预算,极端情况下折叠后反而比原文更长。现已改为所有 prose/code block 共享 20 行全局预览预算,并补充多块与 700 行压力回归。当前分支验证:783 Node tests + 30 Vitest;bun run check 通过。最新 Node 22/24 CI 全绿。

@tt-a1i
tt-a1i merged commit 2b35548 into mainAug 22, 2026
4 checks passed
Sign up for freeto 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.

超长用户输入发送后全文展开刷屏,应折叠显示(display-only)

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示 - #42

Merged
tt-a1i merged 5 commits into
mainfrom
user-input-fold
Aug 22, 2026
Merged

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示#42
tt-a1i merged 5 commits into
mainfrom
user-input-fold

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#40

用户粘贴几百行日志/堆栈/整个文件发送后,pi 把它作为普通用户消息全文渲染,直接刷掉好几屏。而工具输出、子代理结果在本包里都早有折叠,用户消息是唯一没有折叠机制的 transcript 内容——偏偏它可能是最长的。

机制:registerMarkdownTransformer,display-only

pi 的这个 hook 文档明确写了「the original message remains unchanged in the session and model context」。所以:折叠只改 TUI 显示,session 文件和模型上下文里永远是完整原文。这是本 PR 的红线,写进了模块头,并有纯函数测试保证 foldUserMessage 不修改输入。

顺带确认:copy-all 读的是 sessionManager.getBranch()(session 真相源),不受折叠影响,复制出去的仍是完整原文。

折叠规则

  • 触发:> 20 行 或 > 1,200 字符
  • 预览:散文保留 12 行(另有 1,200 字符预算);每个 ``` 代码块保留「开栏 + 语言标记 + 前 4 行 + + 闭栏」——整块折叠,绝不在行中间切,fence 始终闭合
  • 最小收益门槛:只有当折叠能隐藏 ≥ 8 行时才折。少于 8 行就原样渲染
  • marker… folded N lines · full content was sent to the model —— 措辞必须让用户知道模型收到的是完整内容,否则会以为被截断而重复粘贴

那条最小收益门槛是 review 时实测发现的:openpi 自己注入的 /openpi-setup 提示(16 行、因一条极长的 guidance 行而超字符阈值)原本只折掉 4 行,净省 3 行屏幕,代价却是隐藏了 Agent role models / Intercom 这两行用户本来要读的配置摘要。而且字符触发的折叠对「行少但行长」的消息几乎没有屏幕收益——剩下的长行照样换行占多行。折叠必须自己挣回成本。

实测

500 行日志 → 13 行;300 行代码块 → 保留块头 4 行且 fence 闭合(实测 ``` 计数为偶数);setup 提示 → 原样保留

边界与兜底

覆盖并测试:阈值上下各一(19 行隐藏 7 行 → 不折;20 行隐藏 8 行 → 折)、单个巨型代码块、多代码块夹散文、CRLF、结尾换行、阈值下含代码块、空/纯空白、未闭合 fence(保守按文本折)、纯函数性、短消息逐字节一致。transformer 外层有 try/catch——折叠出 bug 也只是退回原文,绝不弄坏渲染。

验证

  • bun run test758 + 29 全绿(基线 739 + 29,新增 19 个测试)
  • bun run check 退出 0(仅剩 file-search/binaries.ts 既存 warning)

Register a display-only markdown transformer that folds finalized user
messages over 20 lines or 1,200 characters into a short preview (12 prose
lines, first 4 content lines per fenced code block) plus a marker stating
how many lines were folded and that the full content was still sent to the
model. The session and model context keep the original message untouched.
Closes#40.
… itself
A char-triggered fold on a message with few but very long lines (e.g. the
/openpi-setup prompt) hid only a handful of lines while saving almost no
screen rows, because the remaining long lines still wrap. Gate folding on
hiding at least 8 lines; below that the message renders byte-identical in
full. Thresholds, preview budgets, marker wording, and the display-only
contract are unchanged.
Refs #40.
@tt-a1i

Copy link
Copy Markdown
CollaboratorAuthor

合并前补充审查:原实现对每个 fenced code block 单独应用预览上限,大量短代码块会绕过折叠预算,极端情况下折叠后反而比原文更长。现已改为所有 prose/code block 共享 20 行全局预览预算,并补充多块与 700 行压力回归。当前分支验证:783 Node tests + 30 Vitest;bun run check 通过。最新 Node 22/24 CI 全绿。

@tt-a1i
tt-a1i merged commit 2b35548 into mainAug 22, 2026
4 checks passed
Sign up for freeto 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.

超长用户输入发送后全文展开刷屏,应折叠显示(display-only)

1 participant

@tt-a1i
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示 - #42

Merged
tt-a1i merged 5 commits into
mainfrom
user-input-fold
Aug 22, 2026
Merged

feat(user-input-fold): 超长用户输入在 transcript 里折叠显示#42
tt-a1i merged 5 commits into
mainfrom
user-input-fold

Conversation

@tt-a1i

Copy link
Copy Markdown
Collaborator

Closes#40

用户粘贴几百行日志/堆栈/整个文件发送后,pi 把它作为普通用户消息全文渲染,直接刷掉好几屏。而工具输出、子代理结果在本包里都早有折叠,用户消息是唯一没有折叠机制的 transcript 内容——偏偏它可能是最长的。

机制:registerMarkdownTransformer,display-only

pi 的这个 hook 文档明确写了「the original message remains unchanged in the session and model context」。所以:折叠只改 TUI 显示,session 文件和模型上下文里永远是完整原文。这是本 PR 的红线,写进了模块头,并有纯函数测试保证 foldUserMessage 不修改输入。

顺带确认:copy-all 读的是 sessionManager.getBranch()(session 真相源),不受折叠影响,复制出去的仍是完整原文。

折叠规则

  • 触发:> 20 行 或 > 1,200 字符
  • 预览:散文保留 12 行(另有 1,200 字符预算);每个 ``` 代码块保留「开栏 + 语言标记 + 前 4 行 + + 闭栏」——整块折叠,绝不在行中间切,fence 始终闭合
  • 最小收益门槛:只有当折叠能隐藏 ≥ 8 行时才折。少于 8 行就原样渲染
  • marker… folded N lines · full content was sent to the model —— 措辞必须让用户知道模型收到的是完整内容,否则会以为被截断而重复粘贴

那条最小收益门槛是 review 时实测发现的:openpi 自己注入的 /openpi-setup 提示(16 行、因一条极长的 guidance 行而超字符阈值)原本只折掉 4 行,净省 3 行屏幕,代价却是隐藏了 Agent role models / Intercom 这两行用户本来要读的配置摘要。而且字符触发的折叠对「行少但行长」的消息几乎没有屏幕收益——剩下的长行照样换行占多行。折叠必须自己挣回成本。

实测

500 行日志 → 13 行;300 行代码块 → 保留块头 4 行且 fence 闭合(实测 ``` 计数为偶数);setup 提示 → 原样保留

边界与兜底

覆盖并测试:阈值上下各一(19 行隐藏 7 行 → 不折;20 行隐藏 8 行 → 折)、单个巨型代码块、多代码块夹散文、CRLF、结尾换行、阈值下含代码块、空/纯空白、未闭合 fence(保守按文本折)、纯函数性、短消息逐字节一致。transformer 外层有 try/catch——折叠出 bug 也只是退回原文,绝不弄坏渲染。

验证

  • bun run test758 + 29 全绿(基线 739 + 29,新增 19 个测试)
  • bun run check 退出 0(仅剩 file-search/binaries.ts 既存 warning)

Register a display-only markdown transformer that folds finalized user
messages over 20 lines or 1,200 characters into a short preview (12 prose
lines, first 4 content lines per fenced code block) plus a marker stating
how many lines were folded and that the full content was still sent to the
model. The session and model context keep the original message untouched.
Closes#40.
… itself
A char-triggered fold on a message with few but very long lines (e.g. the
/openpi-setup prompt) hid only a handful of lines while saving almost no
screen rows, because the remaining long lines still wrap. Gate folding on
hiding at least 8 lines; below that the message renders byte-identical in
full. Thresholds, preview budgets, marker wording, and the display-only
contract are unchanged.
Refs #40.
@tt-a1i

Copy link
Copy Markdown
CollaboratorAuthor

合并前补充审查:原实现对每个 fenced code block 单独应用预览上限,大量短代码块会绕过折叠预算,极端情况下折叠后反而比原文更长。现已改为所有 prose/code block 共享 20 行全局预览预算,并补充多块与 700 行压力回归。当前分支验证:783 Node tests + 30 Vitest;bun run check 通过。最新 Node 22/24 CI 全绿。

@tt-a1i
tt-a1i merged commit 2b35548 into mainAug 22, 2026
4 checks passed
Sign up for freeto 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.

超长用户输入发送后全文展开刷屏,应折叠显示(display-only)

1 participant

@tt-a1i