@co0ontty/wand 1.63.1 → 1.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
- "commit": "c173e20f2e7e864991c953a06e6187e84f422e67",
3
- "builtAt": "2026-06-14T06:57:16.056Z",
4
- "version": "1.63.1",
2
+ "commit": "e1e2c0bff9e13be91e47f3bbfc02fec8eca1e1d8",
3
+ "builtAt": "2026-06-14T12:18:11.568Z",
4
+ "version": "1.64.0",
5
5
  "channel": "stable"
6
6
  }
@@ -4,6 +4,25 @@
4
4
  * with a summary, and clients fetch full content on-demand via API.
5
5
  */
6
6
  import type { CardExpandDefaults, ConversationTurn } from "./types.js";
7
+ /**
8
+ * 默认窗口大小:init/resync/快照/REST 默认只下发最近这么多条 turn,更早的由客户端
9
+ * 滚动到顶时按需分页拉取。移动端 WebSocket 单帧上限(iOS 默认 1 MiB)下,长会话一次
10
+ * 全量下发会撑爆帧导致反复断连——窗口化是根治手段,64MB 提帧只是兜底。
11
+ */
12
+ export declare const MESSAGE_WINDOW_SIZE = 40;
13
+ export interface WindowedMessages {
14
+ /** 已截断 + 窗口化后的 turn 列表(最近 windowSize 条)。 */
15
+ messages: ConversationTurn[];
16
+ /** messages[0] 在完整历史里的绝对下标(0 表示已含最早一条)。 */
17
+ messageOffset: number;
18
+ /** 完整历史的 turn 总数(客户端据此判断是否还有更早的可加载)。 */
19
+ messageTotal: number;
20
+ }
21
+ /**
22
+ * 取完整历史的「最近 windowSize 条」并对其做 transport 截断,附带 offset/total 元数据。
23
+ * 客户端持有的永远是一段连续的「后缀」(最近的若干条),更早的按 offset 往前翻页。
24
+ */
25
+ export declare function windowMessagesForTransport(all: ConversationTurn[] | undefined, cardDefaults: CardExpandDefaults, windowSize?: number): WindowedMessages;
7
26
  /**
8
27
  * Truncate messages for WebSocket transport. Tool results for collapsed card
9
28
  * types are replaced with a short summary when they exceed the threshold.
@@ -5,6 +5,26 @@
5
5
  */
6
6
  const TRUNCATION_THRESHOLD = 200;
7
7
  const SUMMARY_LENGTH = 100;
8
+ /**
9
+ * 默认窗口大小:init/resync/快照/REST 默认只下发最近这么多条 turn,更早的由客户端
10
+ * 滚动到顶时按需分页拉取。移动端 WebSocket 单帧上限(iOS 默认 1 MiB)下,长会话一次
11
+ * 全量下发会撑爆帧导致反复断连——窗口化是根治手段,64MB 提帧只是兜底。
12
+ */
13
+ export const MESSAGE_WINDOW_SIZE = 40;
14
+ /**
15
+ * 取完整历史的「最近 windowSize 条」并对其做 transport 截断,附带 offset/total 元数据。
16
+ * 客户端持有的永远是一段连续的「后缀」(最近的若干条),更早的按 offset 往前翻页。
17
+ */
18
+ export function windowMessagesForTransport(all, cardDefaults, windowSize = MESSAGE_WINDOW_SIZE) {
19
+ const total = all?.length ?? 0;
20
+ const offset = Math.max(0, total - windowSize);
21
+ const slice = all ? all.slice(offset) : [];
22
+ return {
23
+ messages: truncateMessagesForTransport(slice, cardDefaults),
24
+ messageOffset: offset,
25
+ messageTotal: total,
26
+ };
27
+ }
8
28
  /** Tool name → cardDefaults field mapping */
9
29
  function isToolDefaultCollapsed(toolName, defaults) {
10
30
  switch (toolName) {
@@ -1,6 +1,7 @@
1
1
  import express from "express";
2
2
  import { SessionInputError } from "./process-manager.js";
3
3
  import { normalizeMode } from "./config.js";
4
+ import { truncateMessagesForTransport, windowMessagesForTransport } from "./message-truncator.js";
4
5
  import { checkSessionWorktreeMergeability, cleanupSessionWorktree, getWorktreeMergeErrorCode, mergeSessionWorktree, WorktreeMergeError } from "./git-worktree.js";
5
6
  import { getGitStatus, QuickCommitError, runQuickCommit, runTagHead, runPush, generateCommitMessageOnly, } from "./git-quick-commit.js";
6
7
  import { getErrorMessage } from "./error-utils.js";
@@ -598,13 +599,38 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
598
599
  ? processes.getPtyTranscript(snapshot.id) ?? snapshot.output
599
600
  : snapshot.output;
600
601
  if (req.query.format === "chat") {
601
- const messages = snapshot.messages ?? [];
602
- res.json({ ...snapshot, output: transcriptOutput, messages });
602
+ // WS init 对齐:只回最近一窗 turn + offset/total,更早的走 /messages 翻页。
603
+ const windowed = windowMessagesForTransport(snapshot.messages ?? [], config.cardDefaults ?? {});
604
+ res.json({
605
+ ...snapshot,
606
+ output: transcriptOutput,
607
+ messages: windowed.messages,
608
+ messageOffset: windowed.messageOffset,
609
+ messageTotal: windowed.messageTotal,
610
+ });
603
611
  }
604
612
  else {
605
613
  res.json({ ...snapshot, output: transcriptOutput });
606
614
  }
607
615
  });
616
+ // 历史消息分页拉取:客户端滚动到顶时按绝对下标往前翻。
617
+ // 返回 messages = 完整历史的 [offset, offset+limit)(已做 transport 截断)+ total。
618
+ app.get("/api/sessions/:id/messages", (req, res) => {
619
+ const snapshot = getSessionById(processes, structured, req.params.id);
620
+ if (!snapshot) {
621
+ res.status(404).json({ error: "未找到该会话,可能已被删除。" });
622
+ return;
623
+ }
624
+ const all = snapshot.messages ?? [];
625
+ const total = all.length;
626
+ const rawLimit = parseInt(String(req.query.limit ?? ""), 10);
627
+ const rawOffset = parseInt(String(req.query.offset ?? ""), 10);
628
+ const limit = Math.min(Math.max(Number.isFinite(rawLimit) ? rawLimit : 40, 1), 200);
629
+ const offset = Math.min(Math.max(Number.isFinite(rawOffset) ? rawOffset : 0, 0), total);
630
+ const end = Math.min(offset + limit, total);
631
+ const slice = truncateMessagesForTransport(all.slice(offset, end), config.cardDefaults ?? {});
632
+ res.json({ messages: slice, offset, total });
633
+ });
608
634
  app.post("/api/sessions/:id/resume", (req, res) => {
609
635
  const sessionId = req.params.id;
610
636
  const body = req.body;