From cf390cc6fd62c5e007b2cb31ab9f3dd695716938 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:44:06 +0800 Subject: [PATCH] fix(skill): recognize empty catalog tombstones --- packages/skill/tool-skill/src/index.ts | 6 ++++-- packages/skill/tool-skill/tests/tool-skill.spec.ts | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/skill/tool-skill/src/index.ts b/packages/skill/tool-skill/src/index.ts index bd635c9893..f6f45b0316 100644 --- a/packages/skill/tool-skill/src/index.ts +++ b/packages/skill/tool-skill/src/index.ts @@ -18,7 +18,7 @@ export const inject = ['agents', 'tools', 'skills'] const DEFAULT_CATALOG_DESCRIPTION_MAX_LENGTH = 500 const CATALOG_ENTRIES_START = '\n' -const CATALOG_ENTRIES_END = '\n' +const CATALOG_ENTRIES_END = '' const PLUGIN_SOURCE = { kind: 'plugin', plugin: 'dsh-tool-skill' } as const /** Model-facing skill catalog configuration. */ @@ -275,7 +275,9 @@ function catalogContentDigest(content: UserMessage['content']): string | undefin const entriesStart = start + CATALOG_ENTRIES_START.length const end = text.indexOf(CATALOG_ENTRIES_END, entriesStart) if (end === -1) return undefined - return digestCatalogEntries(text.slice(entriesStart, end)) + const renderedEntries = text.slice(entriesStart, end) + const entries = renderedEntries.endsWith('\n') ? renderedEntries.slice(0, -1) : renderedEntries + return digestCatalogEntries(entries) } function catalogDescription(value: string, maxLength: number): string { diff --git a/packages/skill/tool-skill/tests/tool-skill.spec.ts b/packages/skill/tool-skill/tests/tool-skill.spec.ts index 0390504565..3962b98f28 100644 --- a/packages/skill/tool-skill/tests/tool-skill.spec.ts +++ b/packages/skill/tool-skill/tests/tool-skill.spec.ts @@ -320,6 +320,9 @@ describe('dsh-tool-skill', () => { expect(JSON.stringify(removal.data.content)).toContain('No skills are currently available') expect(JSON.stringify(removal.data.content)).not.toContain('first-skill') expect(JSON.stringify(removal.data.content)).not.toContain('second-skill') + + await fireStep(ctx, agent, 1, 4) + expect(catalogMessages(session)).toHaveLength(3) }) it('resumes from the latest valid visible catalog content', async () => {