Description
The defaultDraftValidator in crystallize.ts throws skill.crystallize.invalid: missing summary when the LLM returns valid JSON but omits the required summary key. This is a separate failure mode from the empty-response case addressed by PR #2064.
Reproduction
The LLM (e.g. DeepSeek V4 Flash) occasionally returns valid JSON skill drafts without a summary key. The validator at line ~303 checks if (!draft.summary) and throws immediately. This happens every 5-10 seconds in a busy bridge, flooding logs and blocking the crystallizer queue.
Proposed Fix
Instead of throwing, auto-generate a fallback summary from available fields in priority order:
retrievalBlurb (first)
- First step body or title
- Skill name
- Static placeholder "skill procedure"
The autoSummary fallback should never be empty so the function never throws for missing summary.
if (!draft.summary) {
const autoSummary = draft.retrievalBlurb
|| (draft.steps?.[0]?.body || draft.steps?.[0]?.title)
|| draft.name
|| "skill procedure";
draft.summary = autoSummary.slice(0, 200);
}
Impact
Without this fix, bridge logs fill with 10+ ERROR skill.crystallize.failed messages per minute. The crystallizer accumulates a backlog and other RPC requests (like memory.search) can time out waiting for the queue to drain.
Environment
- MemOS version: v2.0.19 (plugin install from dev branch)
- LLM: DeepSeek V4 Flash via openai_compatible provider
- Embedding: local ONNX (Xenova/all-MiniLM-L6-v2, 384-dim)
- Hermes Agent with memos-local-plugin
Description
The
defaultDraftValidatorincrystallize.tsthrowsskill.crystallize.invalid: missing summarywhen the LLM returns valid JSON but omits the requiredsummarykey. This is a separate failure mode from the empty-response case addressed by PR #2064.Reproduction
The LLM (e.g. DeepSeek V4 Flash) occasionally returns valid JSON skill drafts without a
summarykey. The validator at line ~303 checksif (!draft.summary)and throws immediately. This happens every 5-10 seconds in a busy bridge, flooding logs and blocking the crystallizer queue.Proposed Fix
Instead of throwing, auto-generate a fallback summary from available fields in priority order:
retrievalBlurb(first)The
autoSummaryfallback should never be empty so the function never throws for missing summary.Impact
Without this fix, bridge logs fill with 10+
ERROR skill.crystallize.failedmessages per minute. The crystallizer accumulates a backlog and other RPC requests (likememory.search) can time out waiting for the queue to drain.Environment