Telegram 吞字问题原因与解决方案

结论(先给作者看的版本)

当前“吞首字/吞首 token”问题的直接根因仍是流式首段 part_add(text) 没有被累计进 accumulatedText

之所以“之前说修了但现在还在复现”,是因为修复只出现在 index.pretty.js(可读文件),实际运行的 index.js(以及 app.asar 内 out/main/index.js)没有这段修复逻辑,所以线上行为没有真正改变。

现象回顾

典型表现:一句话开头被吃掉 1 个字或 1 个 token,例如:

  • “对,现在...” 变成 “,现在...”

  • “那就好...” 变成 “就好...”

已确认根因

在消息桥接层 handleMessageDelta 中,存在这几类增量:

  • text_append

  • text-delta / text_delta

  • part_add

当首段内容出现在 part_addpart.type === "text" 时,如果不把 part.text 加入 accumulatedText,就会出现首字缺失。

核验证据

1) index.pretty.js 里有修复分支

index.pretty.js 中 3 个 bridge 的 handleMessageDelta 都有:

else if ("part_add" === o.type && "text" === o.part?.type) {
  const e = o.part?.text || "";
  e && (t.accumulatedText += e);
}

出现位置:

  • index.pretty.js:19986

  • index.pretty.js:22631

  • index.pretty.js:24219

2) 实际运行文件 index.js 没有对应逻辑

index.js 搜索:

  • o.part?.text:无匹配

  • "part_add"===o.type&&"text"===o.part?.type:无匹配

3) app.asar 内运行文件与本地 index.js 完全一致(未带修复)

sha256 对比:

  • /Users/zzmini/Desktop/AI_APP/alma_worklog/index.js

  • /tmp/alma-app-check-17700/app/out/main/index.js

两者哈希一致: 2cc6194e09a1dd13cacd3a0e7db5e2ae04c6712675f2d04a63024ec8370554c6

这说明当前运行中的 app.asar 用的是未含 part_add(text) 累计逻辑的代码。

为什么“执行了替换脚本”仍没生效

当前替换脚本 .alma/scripts/replace_alma_app_asar.sh 是把以下文件拷进 asar:

  • SOURCE_INDEX="$REPO_ROOT/index.js"

  • SOURCE_FATIGUE="fatigueService-*.js"

问题在于:SOURCE_INDEX 本身没包含 part_add(text) 修复,所以替换后行为不变。

解决方案

A. 立即修复(建议)

index.pretty.js 中这段逻辑同步到真正运行的 index.js(或从源码重新构建出新的 index.js),然后再执行 asar 替换。

必须保证 3 个 bridge(Telegram / Discord / Feishu)的 handleMessageDelta 都包含:

  • 处理 part_add + textaccumulatedText += part.text

  • 兼容 text-deltatext_delta

B. 脚本层加“生效校验”(防止假修复)

replace_alma_app_asar.sh 里加预检,若 SOURCE_INDEX 不含关键标记则直接失败退出,例如检查:

  • 包含 o.part?.text

  • 包含 text_delta

  • 包含 text-delta

避免把“未修复版本”再次打进 app.asar。

C. 回归验证(最小集)

用至少 3 条前缀短词开头的回复压测:

  • “你好,在呢...”

  • “对,现在...”

  • “那就好...”

同时对比:

  • 线程归档文本

  • Telegram 实际发送文本

  • 调试日志中的累计文本

要求三者开头一致,且不再出现首字丢失。

给作者的简短描述(可直接粘贴)

吞字根因是 message_delta 累计阶段漏处理 part_add(text);你们的修复目前只在 index.pretty.js,运行中的 index.js/app.asar 未包含该分支,所以问题持续复现;请把 part_add + text 累计逻辑落到实际运行构建产物并补上脚本预检与回归用例。

附录:修改脚本(replace_alma_app_asar.sh)

#!/usr/bin/env bash
set -euo pipefail

APP_PATH="${APP_PATH:-/Applications/Alma.app}"
ASAR_PATH="$APP_PATH/Contents/Resources/app.asar"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

SOURCE_INDEX="$REPO_ROOT/index.js"
SOURCE_FATIGUE="$(ls "$REPO_ROOT"/fatigueService-*.js 2>/dev/null | head -n 1 || true)"

if [[ ! -f "$ASAR_PATH" ]]; then
  echo "app.asar not found: $ASAR_PATH"
  exit 1
fi

if [[ ! -f "$SOURCE_INDEX" ]]; then
  echo "source index.js not found: $SOURCE_INDEX"
  exit 1
fi

if [[ -z "$SOURCE_FATIGUE" || ! -f "$SOURCE_FATIGUE" ]]; then
  echo "source fatigueService-*.js not found under: $REPO_ROOT"
  exit 1
fi

asar() {
  npm_config_cache=/tmp/npm-cache npx --yes @electron/asar@3.2.17 "$@"
}

TS="$(date +%Y%m%d-%H%M%S)"
WORK_DIR="${TMPDIR:-/tmp}/alma-asar-patch-$TS"
BACKUP_PATH="${ASAR_PATH}.bak-${TS}"

mkdir -p "$WORK_DIR"
echo "Work dir: $WORK_DIR"
echo "Backup:   $BACKUP_PATH"

cp "$ASAR_PATH" "$BACKUP_PATH"
echo "Backup done."

asar extract "$ASAR_PATH" "$WORK_DIR/app"
echo "Extract done."

TARGET_INDEX="$WORK_DIR/app/out/main/index.js"
TARGET_FATIGUE="$(find "$WORK_DIR/app/out/main/chunks" -maxdepth 1 -type f -name 'fatigueService-*.js' | head -n 1 || true)"

if [[ ! -f "$TARGET_INDEX" ]]; then
  echo "target index.js not found in extracted asar: $TARGET_INDEX"
  exit 1
fi

if [[ -z "$TARGET_FATIGUE" || ! -f "$TARGET_FATIGUE" ]]; then
  echo "target fatigueService chunk not found in extracted asar."
  exit 1
fi

cp "$SOURCE_INDEX" "$TARGET_INDEX"
cp "$SOURCE_FATIGUE" "$TARGET_FATIGUE"
echo "Patched files:"
echo "  - $TARGET_INDEX"
echo "  - $TARGET_FATIGUE"

asar pack "$WORK_DIR/app" "$WORK_DIR/app.asar.new"
echo "Repack done: $WORK_DIR/app.asar.new"

if cp "$WORK_DIR/app.asar.new" "$ASAR_PATH"; then
  echo "Replaced app.asar successfully."
else
  echo "Replace failed (permission?). Try:"
  echo "  sudo cp \"$WORK_DIR/app.asar.new\" \"$ASAR_PATH\""
  exit 1
fi

if ! codesign --verify --deep --strict "$APP_PATH" >/dev/null 2>&1; then
  echo "Warning: codesign verify failed."
  echo "If app cannot launch, run:"
  echo "  sudo codesign --force --deep --sign - \"$APP_PATH\""
else
  echo "codesign verify passed."
fi

echo "Done."

Please authenticate to join the conversation.

Upvoters
Status

In Review

Board
💡

Feature Request

Date

4 days ago

Author

Pace.Z

Subscribe to post

Get notified by email when there are changes.