Skip to content

fix(memos-local-plugin): add maxTokens to LlmSchema & SkillEvolverSchema#1896

Open
chouti wants to merge 1 commit into
MemTensor:mainfrom
chouti:fix/llm-schema-add-max-tokens
Open

fix(memos-local-plugin): add maxTokens to LlmSchema & SkillEvolverSchema#1896
chouti wants to merge 1 commit into
MemTensor:mainfrom
chouti:fix/llm-schema-add-max-tokens

Conversation

@chouti

@chouti chouti commented Jun 8, 2026

Copy link
Copy Markdown

Problem

Reasoning models (e.g. deepseek-reasoner, o1*, gpt-5-thinking) consume hundreds of tokens on chain-of-thought before emitting JSON content. When llm.json reflection / skillEvolver.crystallize is called with the legacy hard-coded max_tokens: 1024, the response is truncated mid-JSON and the bridge logs llm.json malformed 73+ times in a single reflection cycle.

Result: episodes never close, recoveryReason: "dirty_reward_rescore" piles up, and the MemOS viewer reports bridge.status: disconnected even though the daemon is alive.

Reproduction

llm:
  provider: openai_compatible
  endpoint: https://api.deepseek.com/v1
  model: deepseek-reasoner       # or any reasoning model
  apiKey: sk-...
algorithm:
  lightweightMemory:
    enabled: false               # full self-evolution ON

Start bridge with no override of max_tokens. After ~1 episode:

[bridge] llm.json malformed at 2026-06-08T...Z (attempt 1)
[bridge] llm.json malformed at 2026-06-08T...Z (attempt 2)
... × 73

Direct curl confirms root cause: API returns finish_reason: "length" with truncated content.

Fix

Add maxTokens (default 4_000) to LlmSchema and SkillEvolverSchema. Reasonable budget for reasoning models while still clamping below OpenAI's 32k ceiling.

  • LlmSchema.maxTokens: NumberInRange(4000, 1024, 32768)
  • SkillEvolverSchema.maxTokens: NumberInRange(4000, 1024, 32768)
  • Corresponding defaults in defaults.ts for old configs

TypeBox's Value.Default already preserves user-supplied fields, so the change is backward compatible — old configs without maxTokens get the 4_000 default; new configs can override.

Verification

Before patch:

  • 73 malformed per reflection cycle
  • bridge.status: disconnected

After patch (config unchanged, schema updated):

Files changed

  • apps/memos-local-plugin/core/config/schema.ts (+15 lines, 2 field defs)
  • apps/memos-local-plugin/core/config/defaults.ts (+2 lines, 2 default values)
 apps/memos-local-plugin/core/config/defaults.ts |  2 ++
 apps/memos-local-plugin/core/config/schema.ts   | 15 +++++++++++++++
 2 files changed, 17 insertions(+)

Reasoning models (deepseek-reasoner, o1*, gpt-5-thinking) consume
hundreds of tokens on chain-of-thought. The hard-coded 1024 cap on
LLM JSON reflection caused 73+ 'llm.json malformed' errors per
episode, blocking episode closure and disconnecting the bridge.

- Add maxTokens: NumberInRange(4000, 1024, 32768) to LlmSchema
- Add maxTokens: NumberInRange(4000, 1024, 32768) to SkillEvolverSchema
- Add corresponding defaults in defaults.ts (backward compat)

TypeBox's Value.Default preserves user-supplied fields, so old
configs without maxTokens get the 4000 default; new configs can
override.
@Memtensor-AI Memtensor-AI changed the base branch from main to dev-20260604-v2.0.19 June 10, 2026 15:42
@Memtensor-AI Memtensor-AI changed the base branch from dev-20260604-v2.0.19 to dev-v2.0.22 July 1, 2026 13:15
@Memtensor-AI

Copy link
Copy Markdown
Collaborator

Automated Test Results: FAILED

Cloud test-engine rerun against dev-v2.0.22 failed.

  • Run: tr-7d12f792-72f on cloud test-engine 10010

  • Verdict: fail_code_bug

  • Summary: Tests failed. Failed cases: test

  • memos_local_plugin/unit: 0 passed, 1 failed, 0 skipped

  • memos_local_plugin/smoke: 0 passed, 0 failed, 0 skipped

  • memos_local_plugin/contract: 0 passed, 0 failed, 0 skipped

Failed cases:

  • test: e}
    11:26:01.223 WARN [core.memory.l2.events] listener_threw kind="l2.candidate.added" err={name,message}
    11:26:05.033 WARN [core.skill.events] listener_threw kind="skill.archived" err={name,message}
    11:26:05.033 WARN [core.skill.events] listener_threw kind="skill.archived" err={name,message}
    11:26:06.675 WARN [core.retrieval.events] listener_threw kind="retrieval.started" err="bad listener"
    11:26:06.675 WARN [core.retrieval.events] listener_threw kind="retrieval.started" err="bad listener"

Do not merge until this is fixed and cloud tests pass.

@CarltonXiang CarltonXiang deleted the branch MemTensor:main July 3, 2026 07:25
@syzsunshine219 syzsunshine219 reopened this Jul 3, 2026
@syzsunshine219 syzsunshine219 added the needs-audit Requires manual audit before merge label Jul 3, 2026
@syzsunshine219 syzsunshine219 changed the base branch from dev-v2.0.22 to main July 3, 2026 08:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-audit Requires manual audit before merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants