chore(ai): generalize element-tool name regex to accept _v\d+
Five regex sites across pen-ai-skills + pen-mcp + apps/web were
anchored at `_v0$`, blocking the _v1 family from being recognized
as element tools:
- packages/pen-ai-skills/src/corpus/output-parser.ts
ELEMENT_TOOL_NAME_RE (filters tool_call outputs in A/B
scorer)
- apps/web/src/services/ai/design-parser.ts:106 (embedded
orchestrator dispatch)
- packages/pen-mcp/src/__tests__/design-prompt-elements.test.ts
(×2 — stale-integration guard for elements.md)
- packages/pen-mcp/src/__tests__/element-tool-registry-parity.test.ts
("every tool name matches convention" — renamed to _vN)
- apps/web/src/services/ai/__tests__/element-tools-dispatcher.test.ts
(drift guard for SUPPORTED_EMBEDDED_ELEMENT_TOOLS)
All now accept /^add_[a-z_]+_v\d+$/. Registry-parity test's
expectedBuilder mapping already handled both v0 (strip suffix →
buildModalShell) and v1+ (preserve → buildModalShellV1) via the
existing `.replace(/_v0$/, '')` — no change there.
Prerequisite for landing add_modal_shell_v1 as a first-class MCP
tool in the next commit.
This commit is contained in:
parent
b07b970daa
commit
315ded51ad
|
|
@ -153,8 +153,8 @@ describe('dispatchElementToolCalls (multi-tag batch)', () => {
|
|||
* advertised-but-not-executable output).
|
||||
*/
|
||||
describe('SUPPORTED_EMBEDDED_ELEMENT_TOOLS drift guard', () => {
|
||||
it('covers every add_*_v0 name pen-mcp exposes', () => {
|
||||
const penMcpAddNames = [...ELEMENT_TOOL_NAMES].filter((n) => /^add_.+_v0$/.test(n));
|
||||
it('covers every add_*_vN name pen-mcp exposes', () => {
|
||||
const penMcpAddNames = [...ELEMENT_TOOL_NAMES].filter((n) => /^add_.+_v\d+$/.test(n));
|
||||
const shimSet = new Set(SUPPORTED_EMBEDDED_ELEMENT_TOOLS);
|
||||
const missing = penMcpAddNames.filter((n) => !shimSet.has(n));
|
||||
expect(
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ export function tryParseAllElementToolOutputs(raw: string): DesignOutputShape[]
|
|||
parsed.arguments && typeof parsed.arguments === 'object'
|
||||
? (parsed.arguments as Record<string, unknown>)
|
||||
: {};
|
||||
if (/^add_[a-z_]+_v0$/.test(parsed.name)) {
|
||||
if (/^add_[a-z_]+_v\d+$/.test(parsed.name)) {
|
||||
shapes.push({ kind: 'element-tool', name: parsed.name, arguments: args, raw: match[0] });
|
||||
} else if (parsed.name === 'batch_design') {
|
||||
const dsl = typeof args.operations === 'string' ? args.operations : '';
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ import type { ParsedOutput } from './types';
|
|||
*/
|
||||
const OP_TOOL_RE_G = /<op_tool>\s*([\s\S]*?)\s*<\/op_tool>/g;
|
||||
|
||||
const ELEMENT_TOOL_NAME_RE = /^add_[a-z_]+_v0$/;
|
||||
// Accepts any numeric version suffix (_v0, _v1, …). The family
|
||||
// currently ships v0 (byte-parity, hex literals) and v1 (theme-
|
||||
// aware with $color-* refs). Future _v2+ lands here automatically.
|
||||
const ELEMENT_TOOL_NAME_RE = /^add_[a-z_]+_v\d+$/;
|
||||
|
||||
/**
|
||||
* Reasoning-model chain-of-thought wrapper. MiniMax M-series,
|
||||
|
|
|
|||
|
|
@ -37,10 +37,10 @@ describe('get_design_prompt — elements section', () => {
|
|||
const def = DESIGN_TOOL_DEFINITIONS.find((t) => t.name === 'get_design_prompt');
|
||||
const description = def?.description ?? '';
|
||||
const elementTools = DESIGN_TOOL_DEFINITIONS.map((t) => t.name).filter((n) =>
|
||||
/^add_.*_v0$/.test(n),
|
||||
/^add_.*_v\d+$/.test(n),
|
||||
);
|
||||
// (1) any element-tool name that DOES appear must be in the registry
|
||||
const namedInDescription = description.match(/add_[a-z_]+_v0/g) ?? [];
|
||||
const namedInDescription = description.match(/add_[a-z_]+_v\d+/g) ?? [];
|
||||
for (const named of namedInDescription) {
|
||||
expect(elementTools, `description references ${named} which is not in registry`).toContain(
|
||||
named,
|
||||
|
|
@ -76,7 +76,7 @@ describe('get_design_prompt — elements section', () => {
|
|||
// such tool MUST be mentioned in the elements skill content.
|
||||
const content = buildDesignPrompt('elements');
|
||||
const elementTools = DESIGN_TOOL_DEFINITIONS.map((t) => t.name).filter((n) =>
|
||||
/^add_.*_v0$/.test(n),
|
||||
/^add_.*_v\d+$/.test(n),
|
||||
);
|
||||
expect(elementTools.length).toBeGreaterThan(0);
|
||||
for (const n of elementTools) {
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ describe('pen-mcp element-tool registry parity', () => {
|
|||
expect(ELEMENT_TOOL_DEFINITIONS.length).toBeGreaterThanOrEqual(42);
|
||||
});
|
||||
|
||||
it('Every tool name matches the add_X_v0 convention', () => {
|
||||
it('Every tool name matches the add_X_vN convention (accepts _v0, _v1, …)', () => {
|
||||
for (const def of ELEMENT_TOOL_DEFINITIONS) {
|
||||
expect(def.name, `tool definition: ${def.name}`).toMatch(/^add_[a-z_]+_v0$/);
|
||||
expect(def.name, `tool definition: ${def.name}`).toMatch(/^add_[a-z_]+_v\d+$/);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue