Skip to content

Fix #2356: l3.abstraction: misleading "title must be a non-empty string" error — output tru - #2357

Open
Memtensor-AI wants to merge 1 commit into
MemTensor:dev-v2.0.34from
Memtensor-AI:bugfix/autodev-2356-20260910132328679
Open

Fix #2356: l3.abstraction: misleading "title must be a non-empty string" error — output tru#2357
Memtensor-AI wants to merge 1 commit into
MemTensor:dev-v2.0.34from
Memtensor-AI:bugfix/autodev-2356-20260910132328679

Conversation

@Memtensor-AI

Copy link
Copy Markdown
Collaborator

Description

Fixed the misleading "title must be a non-empty string" error in L3 world-model generation caused by two cooperating bugs.

Bug 1 — extractFirstJsonBlock (json-mode.ts): The old loop continued scanning for a nested balanced sub-block when the root opener returned null from walkToClose. A truncated root object like {"title":"...","domain_tags":["network","http"],... left the root { unbalanced, causing the loop to continue and find the inner domain_tags array, which was fully balanced. JSON.parse then succeeded on that array, and the caller's validate() received ["network","http","local-services","cron"] instead of the full object — correctly reporting 'title' must be a non-empty string but pointing blame at the model rather than at token truncation. Fix: stop at the first opener; if walkToClose returns null, return null immediately.

Bug 2 — completeJson (client.ts): finishReason === "length" was already present on LlmCompletion but completeJson passed the truncated text straight to parseLlmJson without inspecting it. Fix: check finishReason === "length" before parsing; throw LLM_OUTPUT_MALFORMED immediately with finishReason: "length" and rawLen in the error details. Also added rawLen to all existing malformed warn log rows for easier token-budget diagnosis.

Tests: 5 new test cases added (2 in json-mode.test.ts, 3 in client.test.ts). All 43 LLM unit tests pass. Pre-existing failures in subscriber.test.ts are unrelated (SQLite native binding absent in this environment).

Related Issue (Required): Fixes #2356

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (does not change functionality, e.g. code style improvements, linting)
  • Documentation update

How Has This Been Tested?

Automated tests are pending.

  • Unit Test
  • Test Script Or Test Steps (please provide)
  • Pipeline Automated API Test (please provide)

Checklist

  • I have performed a self-review of my own code
  • I have commented my code in hard-to-understand areas
  • I have added tests that prove my fix is effective or that my feature works
  • I have created related documentation issue/PR in MemOS-Docs (if applicable)
  • I have linked the issue to this PR (if applicable)
  • I have mentioned the person who will review this PR

@whipser030, @hijzy please review this PR.

Reviewer Checklist

…a error

When an LLM output is truncated at maxTokens, two cooperating bugs caused
a misleading 'title must be a non-empty string' validation error that pointed
blame at the model output rather than the real cause.

Bug 1 — extractFirstJsonBlock (json-mode.ts): the old loop continued scanning
for a nested balanced sub-block when the root opener returned null from
walkToClose. This allowed a fully-balanced inner value (e.g. a domain_tags
array) to pass JSON.parse successfully, after which the caller's validate()
received that nested value and threw a field-level schema error.

Fix: stop at the first opener. If walkToClose returns null (root block is
truncated), return null immediately rather than hunting for a balanced child.

Bug 2 — completeJson (client.ts): finishReason=length was set on LlmCompletion
by providers when the token budget was exhausted, but completeJson passed the
truncated text straight to parseLlmJson without inspecting it.

Fix: check finishReason === 'length' before attempting to parse. Throw
LLM_OUTPUT_MALFORMED immediately with finishReason and rawLen in details so
the log clearly names the cause.

Also adds rawLen to all existing malformed warn rows so token-budget diagnosis
is easier without a separate log query.

Closes MemTensor#2356
@Memtensor-AI

Copy link
Copy Markdown
Collaborator Author

🤖 Open Code Review

Target: PR #2357
Task: 035ad74cb9dcd82a
Base: dev-v2.0.34
Head: bugfix/autodev-2356-20260910132328679
Head SHA: 4ce26cc592ef6c63c9417e6e7a55fb0d38c54baa

🔍 OpenCodeReview found 1 issue(s) in this PR.


1. apps/memos-local-plugin/core/llm/client.ts (L543-L546)

retries is not declared anywhere in the completeJson function scope — only attempt is. Referencing retries++ here will throw a ReferenceError at runtime whenever a truncated response is received, crashing the retry path entirely instead of retrying. The existing parse-error branch below uses attempt (not retries) for its own continue, which is the correct pattern. Either remove retries++ entirely (since attempt already tracks the iteration count and is checked by the while condition), or declare let retries = 0 alongside the other loop variables at the top of the function if a separate counter is intentionally needed.

💡 Suggested Change

Before:

        if (attempt <= maxMalformedRetries) {
          retries++;
          continue;
        }

After:

        if (attempt <= maxMalformedRetries) {
          continue;
        }

Generated by cloud-assistant via Open Code Review.

@Memtensor-AI

Copy link
Copy Markdown
Collaborator Author

🔧 Open Code Review requested Agent fix

Open Code Review found 1 issue(s). I have resumed the development Agent to fix them.

  • Task: 035ad74cb9dcd82a
  • Fix attempt: 1/2
  • Finding delta: 0 repeated / 1 new / 0 likely resolved

The Agent will push a new commit to this PR branch. OCR will recheck after the commit is pushed.

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

Labels

ai:generated Generated or modified by AI | 由 AI 生成或修改 area:plugin OpenClaw & Hermes status:in-progress Someone or AI is working on it | 人工或 AI 正在处理

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants