diff --git a/project-management/PJ2026-01/specs/PJ2026-01050205-superapi.md b/project-management/PJ2026-01/specs/PJ2026-01050205-superapi.md index 344d31b5..54ad9ca2 100644 --- a/project-management/PJ2026-01/specs/PJ2026-01050205-superapi.md +++ b/project-management/PJ2026-01/specs/PJ2026-01050205-superapi.md @@ -203,6 +203,10 @@ SuperAPI 应提供左侧根导航和多页面管理工作区: - system、developer、user 条目应保留原始顺序,并在卡片表层显示原始 `type`; - `message`、`additional_tools` 等不同类型不得仅因角色相同而被误判为同一种 Prompt; - 条目内容确实为空时保留该条目,摘要保持空白,不显示虚构的“空内容”; + - Tools 同时解析顶层 `tools` 和 `input[].type=additional_tools` 内的工具; + - `type=namespace` 独立投影到 MCP/Namespaces,并展开其嵌套工具; + - reasoning、tool call、tool output、assistant message 等其余 input 条目投影到 Input Items; + - Tools、MCP/Namespaces 和 Input Items 即使为空也保留卡片并显示 `0 项`; - 每个 skill 与 tool 独占一行摘要,并可展开查看完整脱敏字段。 Web 不得实现第二套业务逻辑。管理 API、默认本地 CLI 和显式 `--over-api` CLI diff --git a/scripts/src/web-probe-superapi-smoke.ts b/scripts/src/web-probe-superapi-smoke.ts index 4b326195..273bff69 100644 --- a/scripts/src/web-probe-superapi-smoke.ts +++ b/scripts/src/web-probe-superapi-smoke.ts @@ -452,6 +452,7 @@ export default async function superApiManagementSmoke({ page, goto, wait, screen const readableVisible = await dialog.locator(".readable-columns").isVisible(); const skillNode = requestPanel.locator('[data-section-id="skills"] .readable-node').first(); const toolNode = requestPanel.locator('[data-section-id="tools"] .readable-node').first(); + const namespaceNode = requestPanel.locator('[data-section-id="mcpNamespaces"] .readable-node').first(); const developerNodes = await requestPanel .locator('[data-section-id="developerPrompts"] .readable-node > summary') .evaluateAll((elements) => elements.map((element) => ({ @@ -461,10 +462,14 @@ export default async function superApiManagementSmoke({ page, goto, wait, screen }))); const skillNodeCount = await requestPanel.locator('[data-section-id="skills"] .readable-node').count(); const toolNodeCount = await requestPanel.locator('[data-section-id="tools"] .readable-node').count(); + const namespaceNodeCount = await requestPanel.locator('[data-section-id="mcpNamespaces"] .readable-node').count(); + const inputItemNodeCount = await requestPanel.locator('[data-section-id="inputItems"] .readable-node').count(); if (skillNodeCount > 0) await skillNode.locator("summary").first().click(); if (toolNodeCount > 0) await toolNode.locator("summary").first().click(); + if (namespaceNodeCount > 0) await namespaceNode.locator("summary").first().click(); const skillDetailFields = skillNodeCount > 0 ? await skillNode.locator(".readable-value").count() : 0; const toolDetailFields = toolNodeCount > 0 ? await toolNode.locator(".readable-value").count() : 0; + const namespaceDetailFields = namespaceNodeCount > 0 ? await namespaceNode.locator(".readable-value").count() : 0; const semanticDetailsVisible = (skillNodeCount === 0 || skillDetailFields >= 2) && (toolNodeCount === 0 || toolDetailFields >= 2); await dialog.getByRole("button", { name: "Raw", exact: true }).evaluate((button) => button.click()); @@ -476,7 +481,10 @@ export default async function superApiManagementSmoke({ page, goto, wait, screen await dialog.locator(".readable-columns").waitFor({ state: "visible", timeout: config.navigationTimeoutMs }); const readableRestored = await dialog.locator(".readable-columns").isVisible(); const requestSemantic = requestSections.includes("userPrompts") - && (requestSections.includes("systemPrompt") || requestSections.includes("skills")); + && (requestSections.includes("systemPrompt") || requestSections.includes("skills")) + && requestSections.includes("tools") + && requestSections.includes("mcpNamespaces") + && requestSections.includes("inputItems"); const responseSemantic = responseSections.includes("overview") && responseSections.includes("outputs"); const developerPromptsValid = developerNodes.every((node, index) => @@ -488,6 +496,7 @@ export default async function superApiManagementSmoke({ page, goto, wait, screen && responseSemantic && developerPromptsValid && semanticDetailsVisible + && (namespaceNodeCount === 0 || namespaceDetailFields >= 2) && rawVisible && rawPanelCount === 2 && readableHiddenInRaw @@ -506,8 +515,11 @@ export default async function superApiManagementSmoke({ page, goto, wait, screen developerPromptsValid, skillNodeCount, toolNodeCount, + namespaceNodeCount, + inputItemNodeCount, skillDetailFields, toolDetailFields, + namespaceDetailFields, semanticDetailsVisible, readableVisible, rawVisible,