Skip to content

[Bug] attachSkillSubscriber wired with bgLlm, not bgReflectLlm — skillEvolver dedicated client never invoked #2362

Description

@chiefmojo

Pre-submission checklist

  • I have searched existing issues and this hasn't been mentioned before
  • I have read the project documentation and confirmed this issue doesn't already exist
  • This issue is specific to MemOS and not a general software issue

Bug Description

Summary

In core/pipeline/deps.ts, attachSkillSubscriber is wired with llm: bgLlm (the main model), never bgReflectLlm (the dedicated client built from the skillEvolver config block). As a result the skill subscriber's LLM-backed work (crystallization evaluation, evolution) always runs on the main model regardless of skillEvolver.* config, and skillEvolver.lastOkAt never updates because the dedicated client is never invoked.

Root cause

// deps.ts, attachSkillSubscriber call
const skillHandle = attachSkillSubscriber({
    repos: deps.repos,
    embedder: bgEmbedder,
    llm: bgLlm,          // ← BUG: should be bgReflectLlm
    bus: buses.skill,
    l2Bus: buses.l2,
    rewardBus: buses.reward,
    log: log.child({ channel: "core.skill" }),
    config: algorithm.skill,
    ...
});

bgReflectLlm is constructed earlier in the same file specifically from the skillEvolver config block, but is only read for metadata (health/overview endpoint), never passed into the skill subscriber itself.

Verified via git log -L on this call site: it has never been wired to bgReflectLlm since the v2.0 Reflect2Evolve rewrite (60b97444) — this is not a regression, it's never worked.

Relation to #2148

This is a distinct instance of the same wiring-bug class fixed in #2148 (PR #2151) — that issue was about captureRunner's reflectLlm slot getting the wrong client (skill-evolver client where main llm was needed). This issue is the opposite direction: the skill subscriber never gets the dedicated skillEvolver client it's supposed to have. Different call site, not fixed by #2151.

Impact

  • Operators configuring a distinct skillEvolver.* model (e.g. to isolate skill-evolution cost/quality from the main model) get silently ignored — the main llm handles it instead.
  • skillEvolver.lastOkAt in the overview/health endpoint reads null indefinitely on any install that relies on it as a liveness signal for skill evolution, even when skill evolution is running fine (just on the wrong model).

Suggested Fix

const skillHandle = attachSkillSubscriber({
    ...
    llm: bgReflectLlm ?? bgLlm,
    ...
});

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

ai:pr-readyAI-created PR is ready for review | AI 生成的 PR 已等待评审area:coreMOS 编排层 / 框架底座 / 跨模块问题status:in-progressSomeone or AI is working on it | 人工或 AI 正在处理types:bugSomething isn't working | 功能异常

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions