Files
editor/packages/mcp/src/prompts/from-brief.ts
T
Adrian PerezandClaude Opus 4.7 570c605446 feat(mcp): add resources and prompts
Resources: pascal://scene/current (JSON), /scene/current/summary
(markdown with per-level counts, floor areas, bbox), /catalog/items
(returns catalog_unavailable in headless mode), and the templated
pascal://constraints/{levelId} which exposes slabs + wall footprints
via @pascal-app/core/wall helpers.

Prompts: from_brief (generate scene from a natural-language brief),
iterate_on_feedback (minimal-diff patch proposals), and
renovation_from_photos (orchestrates the vision tools).

17 tests, all passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:51:15 +02:00

62 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { z } from 'zod'
import type { SceneBridge } from '../bridge/scene-bridge'
const PREAMBLE = [
'You are a Pascal 3D scene designer.',
'You have access to the `apply_patch` tool for all scene mutations. Prefer it over individual create_* tools so that your changes land as a single undoable step.',
'Build incrementally. Starting from an empty scene, first create a Site, then a Building, then one or more Levels; only after that do you create walls, zones, slabs, items, and openings.',
'Respect these invariants:',
' - Levels live under a Building.',
' - Walls, fences, zones, slabs, ceilings, roofs, stairs live under a Level.',
' - Doors and windows live under a Wall (parentId = wallId).',
' - Items live under a Wall, Ceiling, or Site.',
'Use realistic dimensions in meters. Keep wall thickness small (0.10.3 m) and ceiling height 2.43.0 m unless the brief dictates otherwise.',
'Respond ONLY with tool calls. Do not produce verbose narrative or prose; keep any explanations in short tool-call arguments.',
].join('\n')
/**
* Build the user-facing prompt text for `from_brief`. Pure function for testability.
*/
export function buildFromBriefPrompt(args: {
brief: string
constraints?: string | undefined
}): string {
const parts: string[] = [PREAMBLE, '', '## Brief', args.brief.trim()]
if (args.constraints && args.constraints.trim().length > 0) {
parts.push('', '## Constraints', args.constraints.trim())
}
parts.push(
'',
'## Task',
'Produce a plan of `apply_patch` calls that realises the brief within the stated constraints. Start from an empty site. Call the vision / query tools only if you need extra context.',
)
return parts.join('\n')
}
export function registerFromBrief(server: McpServer, _bridge: SceneBridge): void {
server.registerPrompt(
'from_brief',
{
title: 'Generate a Pascal scene from a brief',
description:
'Produces a plan of apply_patch calls to create a scene from a natural-language brief.',
argsSchema: {
brief: z.string(),
constraints: z.string().optional(),
},
},
async ({ brief, constraints }) => ({
messages: [
{
role: 'user',
content: {
type: 'text',
text: buildFromBriefPrompt({ brief, constraints }),
},
},
],
}),
)
}