diff --git a/src/mcplocal/tests/smoke/mcp-client.ts b/src/mcplocal/tests/smoke/mcp-client.ts index cb25e74..bbb1d46 100644 --- a/src/mcplocal/tests/smoke/mcp-client.ts +++ b/src/mcplocal/tests/smoke/mcp-client.ts @@ -261,6 +261,21 @@ export async function isMcplocalRunning(): Promise { } } +/** + * Pull the drill-down id out of a paginated result or TOC. + * + * The instruction is written `_resultId="pm-abc"`, while the legacy paginator + * emits it as JSON (`"_resultId": "pm-abc"`). A regex matching only the JSON + * form silently found nothing in the current format, so drill-down checks + * either reported a false failure or skipped themselves as "not large enough + * for section-split" — both invisible in a green run. Accept either spelling + * and return the bare id. + */ +export function extractResultId(text: string): string | null { + const match = /_resultId"?\s*[:=]\s*"?(pm-[a-zA-Z0-9]+)/.exec(text); + return match?.[1] ?? null; +} + /** * Run an mcpctl CLI command and return stdout. */ diff --git a/src/mcplocal/tests/smoke/prompt-drilldown.test.ts b/src/mcplocal/tests/smoke/prompt-drilldown.test.ts index 1925611..74cff82 100644 --- a/src/mcplocal/tests/smoke/prompt-drilldown.test.ts +++ b/src/mcplocal/tests/smoke/prompt-drilldown.test.ts @@ -7,7 +7,7 @@ * Requires: mcplocal running on localhost:3200, mcpd at https://mcpctl.ad.itaz.eu */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; -import { SmokeMcpSession, isMcplocalRunning } from './mcp-client.js'; +import { SmokeMcpSession, isMcplocalRunning, extractResultId } from './mcp-client.js'; const PROJECT_NAME = 'smoke-data'; @@ -90,9 +90,8 @@ describe('Smoke: Prompt section drill-down', () => { console.log(` TOC preview: ${text.slice(0, 200)}...`); // Extract _resultId - const match = /_resultId:\s*(pm-[a-z0-9]+)/.exec(text); - if (match) { - const resultId = match[1]; + const resultId = extractResultId(text); + if (resultId !== null) { // Extract first section id from TOC const sectionMatch = /\[([^\]]+)\]/.exec(text); if (sectionMatch) { diff --git a/src/mcplocal/tests/smoke/proxy-pipeline.test.ts b/src/mcplocal/tests/smoke/proxy-pipeline.test.ts index cb53c0b..e339d17 100644 --- a/src/mcplocal/tests/smoke/proxy-pipeline.test.ts +++ b/src/mcplocal/tests/smoke/proxy-pipeline.test.ts @@ -17,7 +17,7 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { writeFile, mkdir, rm } from 'node:fs/promises'; import { join, resolve } from 'node:path'; -import { SmokeMcpSession, isMcplocalRunning, mcpctl } from './mcp-client.js'; +import { SmokeMcpSession, isMcplocalRunning, mcpctl, extractResultId } from './mcp-client.js'; import { ChatReporter } from './reporter.js'; const PROJECT_NAME = 'smoke-data'; @@ -286,8 +286,7 @@ describe('Smoke: ProxyModel pipeline', () => { chat.check('Response is manageable size', text.length, (v) => v < 20_000); if (text.includes('_resultId')) { - const match = text.match(/_resultId:\s*(\S+)/); - chat.check('_resultId is present', !!match, (v) => v === true); + chat.check('_resultId is present', extractResultId(text) !== null, (v) => v === true); } else { chat.info('Content small enough — no pagination needed'); } @@ -307,14 +306,12 @@ describe('Smoke: ProxyModel pipeline', () => { }); const text = result.content[0]?.text ?? ''; - const match = text.match(/_resultId:\s*(\S+)/); - if (!match) { + const resultId = extractResultId(text); + if (resultId === null) { chat.info('Content not large enough for pagination — skip drill-down'); return; } - const resultId = match[1]!.replace(/[^a-zA-Z0-9-]/g, ''); - const sectionResult = await chat.callTool('smoke-aws-docs_read_documentation', { url: 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html', _resultId: resultId, @@ -401,8 +398,7 @@ describe('Smoke: ProxyModel pipeline', () => { chat.check('Response is manageable size', text.length, (v) => v < 20_000); if (text.includes('_resultId')) { - const match = text.match(/_resultId:\s*(\S+)/); - chat.check('Has _resultId for drill-down', !!match, (v) => v === true); + chat.check('Has _resultId for drill-down', extractResultId(text) !== null, (v) => v === true); } }, 60_000); @@ -420,14 +416,12 @@ describe('Smoke: ProxyModel pipeline', () => { }); const text = result.content[0]?.text ?? ''; - const match = text.match(/_resultId:\s*(\S+)/); - if (!match) { + const resultId = extractResultId(text); + if (resultId === null) { chat.info('Content not large enough for section-split'); return; } - const resultId = match[1]!.replace(/[^a-zA-Z0-9-]/g, ''); - const sectionResult = await chat.callTool('smoke-aws-docs_read_documentation', { url: 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html', _resultId: resultId,