Skip to content

refactor(opencode-plugin): migrate auto recall from chat.messages.transform to chat.message hook#1977

Merged
yangxinxin-7 merged 1 commit into
volcengine:mainfrom
A0nameless0man:fix/recall-chat-message-hook
May 12, 2026
Merged

refactor(opencode-plugin): migrate auto recall from chat.messages.transform to chat.message hook#1977
yangxinxin-7 merged 1 commit into
volcengine:mainfrom
A0nameless0man:fix/recall-chat-message-hook

Conversation

@A0nameless0man
Copy link
Copy Markdown
Contributor

Description

将记忆召回(auto recall)钩子从 experimental.chat.messages.transform 迁移到 chat.message,使用 synthetic: true 持久化注入,解决上下文漂移与重复搜索问题。

Related Issue

N/A

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test update

Changes Made

  • 移除 experimental.chat.messages.transform 钩子
  • 移除死代码:RecallMessagePartRecallWithParts 接口、extractLatestUserTextappendToLastTextPart 函数
  • 新增 chat.message 钩子,使用 synthetic: true 持久化注入 <relevant-memories>
  • 新增 runAutoRecall() 共享函数
  • 新增 extractMessageText() 替代 extractLatestUserText(),适配 chat.messageinput.parts 签名
  • 净减少 28 行(-82/+54)

Testing

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have tested this on the following platforms:
    • Linux
    • macOS
    • Windows

Checklist

  • My code follows the project's coding style
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

Additional Notes

问题根因

experimental.chat.messages.transform 是无状态钩子——修改仅作用于内存中的消息拷贝,不写回会话存储。每次 LLM API 调用(含工具调用续接)都会重新触发,导致:

  1. 上下文不一致 — 每次工具调用回来,模型看到的记忆集合不同
  2. 前序记忆丢失 — 上次注入的记忆在下一次调用时消失
  3. KV-cache 命中差 — 消息内容持续变化,服务端缓存无效
  4. 冗余 API 调用 — 同一轮对话反复调用 OpenViking search

方案

chat.message 钩子在用户消息创建时触发一次,output.parts 的修改持久化到会话历史。synthetic: true 的 part 在 TUI 中不可见,但对 LLM 作为 synthetic context 发送。

效果对比

# 旧方案
用户输入 → API#1: 搜索→A,B,C → 工具调用 → API#2: 重新搜索→A,D,E → ...

# 新方案
用户输入 → chat.message: 搜索→插入synthetic part(持久化)
         → API#1: 含A,B,C → 工具调用 → API#2: 仍含A,B,C ✓

关键约束

  • Part ID 前缀prt-ov-recall-{ts}-{random},必须 prt- 开头(OpenCode schema 校验)
  • 幂等性:保留 <relevant-memories> 标记检测,防止重加载会话后重复注入
  • 兼容性:旧会话不含 synthetic part,chat.message 仅对新消息触发

…nsform to chat.message hook

Replace experimental.chat.messages.transform (stateless, non-persistent) with chat.message + synthetic:true parts for persistent injection. Eliminates context drift, redundant searches, and poor KV-cache hit rate across tool call continuations. Removes dead code: RecallMessagePart, RecallWithParts, extractLatestUserText, appendToLastTextPart. Adds runAutoRecall() shared function. Net -28 lines (-82/+54).
@github-actions
Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🏅 Score: 60
🧪 No relevant tests
⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

NameError in load_latest_conversation due to missing time_str capture

The load_latest_conversation function removed the line that captures time_str from the regex match when processing a new message section, but still uses time_str when parsing timestamps for previous messages, leading to a NameError.

    match = re.match(r"^## \[([0-9:]+)\] (.+)$", line)
    if match:
        # Save previous message
        if current_speaker and current_content:
            # Try to parse timestamp, or use current time
            try:
                # We don't have the date, just use current time
                ts = time.time()
            except ValueError:
                ts = time.time()

            messages.append(
                ChatMessage(
                    channel_id=current_speaker,
                    content="\n".join(current_content).strip(),
                    is_user=(current_speaker == "admin"),
                    timestamp=ts,
                )
            )

        # Start new message
        current_speaker = match.group(2)
        current_content = []
    elif line and not line.startswith("# "):
        # Content line
        if current_speaker is not None:
            current_content.append(line)

# Save the last message
if current_speaker and current_content:
    try:
        ts = time.time()
    except ValueError:
        ts = time.time()

    messages.append(
        ChatMessage(
            channel_id=current_speaker,
            content="\n".join(current_content).strip(),
            is_user=(current_speaker == "admin"),
            timestamp=ts,
        )
    )

logger.info(
    f"Loaded {len(messages)} messages from latest conversation, session_id={session_id}"
)
Mismatched command line argument for werewolf server

The start script changed from passing --bot-url to --bot-port, but the werewolf server still expects --vikingbot-url as a command line argument, causing a startup failure.

args.server_host,
"--port",
str(args.server_port),
"--with-bot",
"--bot-port",
str(urlparse(args.vikingbot_url).port or 18790),

@A0nameless0man A0nameless0man force-pushed the fix/recall-chat-message-hook branch from fdca3dc to e509129 Compare May 12, 2026 01:59
@github-actions
Copy link
Copy Markdown

PR Code Suggestions ✨

No code suggestions found for the PR.

Copy link
Copy Markdown
Collaborator

@yangxinxin-7 yangxinxin-7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!这是一个很棒的重构:

  1. 解决了无状态钩子导致的上下文漂移和重复搜索问题
  2. 代码更简洁,删除了不必要的死代码
  3. 幂等性处理得当
  4. CI 全部通过

@yangxinxin-7 yangxinxin-7 merged commit 32d9aa1 into volcengine:main May 12, 2026
5 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in OpenViking project May 12, 2026
r266-tech added a commit to r266-tech/OpenViking that referenced this pull request May 12, 2026
ZaynJarvis pushed a commit that referenced this pull request May 13, 2026
…nsform to chat.message hook (#1977)

Replace experimental.chat.messages.transform (stateless, non-persistent) with chat.message + synthetic:true parts for persistent injection. Eliminates context drift, redundant searches, and poor KV-cache hit rate across tool call continuations. Removes dead code: RecallMessagePart, RecallWithParts, extractLatestUserText, appendToLastTextPart. Adds runAutoRecall() shared function. Net -28 lines (-82/+54).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants