@pascal-app/mcp 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/README.md +166 -62
- package/dist/bin/pascal-mcp.js +1 -1
- package/dist/bridge/agent-session.d.ts +18 -0
- package/dist/bridge/agent-session.d.ts.map +1 -0
- package/dist/bridge/agent-session.js +15 -0
- package/dist/bridge/index.d.ts +1 -1
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.d.ts +3 -0
- package/dist/bridge/scene-bridge.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.js +7 -0
- package/dist/lib/safe-fetch.d.ts +22 -4
- package/dist/lib/safe-fetch.d.ts.map +1 -1
- package/dist/lib/safe-fetch.js +233 -134
- package/dist/operations/scene-operations.d.ts +18 -0
- package/dist/operations/scene-operations.d.ts.map +1 -1
- package/dist/operations/scene-operations.js +11 -0
- package/dist/prompts/from-brief.d.ts +1 -1
- package/dist/prompts/from-brief.d.ts.map +1 -1
- package/dist/prompts/from-brief.js +3 -3
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/iterate-on-feedback.d.ts +1 -1
- package/dist/prompts/iterate-on-feedback.d.ts.map +1 -1
- package/dist/prompts/iterate-on-feedback.js +2 -2
- package/dist/prompts/renovation-from-photos.d.ts +1 -1
- package/dist/prompts/renovation-from-photos.d.ts.map +1 -1
- package/dist/prompts/renovation-from-photos.js +2 -2
- package/dist/prompts/scene-guidance.d.ts.map +1 -1
- package/dist/prompts/scene-guidance.js +10 -3
- package/dist/resources/agent-guide.d.ts +1 -1
- package/dist/resources/agent-guide.d.ts.map +1 -1
- package/dist/resources/agent-guide.js +52 -44
- package/dist/resources/catalog-items.d.ts +1 -1
- package/dist/resources/catalog-items.d.ts.map +1 -1
- package/dist/resources/constraints.d.ts +1 -1
- package/dist/resources/constraints.d.ts.map +1 -1
- package/dist/resources/constraints.js +1 -1
- package/dist/resources/design-schema.d.ts +1 -1
- package/dist/resources/design-schema.d.ts.map +1 -1
- package/dist/resources/index.d.ts +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/scene-current.d.ts +1 -1
- package/dist/resources/scene-current.d.ts.map +1 -1
- package/dist/resources/scene-summary.d.ts +1 -1
- package/dist/resources/scene-summary.d.ts.map +1 -1
- package/dist/server.d.ts +7 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +59 -21
- package/dist/storage/disk-artifact-store.d.ts.map +1 -1
- package/dist/storage/sqlite-scene-store.d.ts +1 -1
- package/dist/storage/sqlite-scene-store.d.ts.map +1 -1
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/templates/empty-studio.d.ts +3 -3
- package/dist/templates/empty-studio.d.ts.map +1 -1
- package/dist/templates/garden-house.d.ts +3 -3
- package/dist/templates/garden-house.d.ts.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/two-bedroom.d.ts +3 -3
- package/dist/templates/two-bedroom.d.ts.map +1 -1
- package/dist/tools/add-column.d.ts +1 -1
- package/dist/tools/add-column.d.ts.map +1 -1
- package/dist/tools/add-column.js +3 -2
- package/dist/tools/add-object.d.ts +19 -3
- package/dist/tools/add-object.d.ts.map +1 -1
- package/dist/tools/add-object.js +66 -35
- package/dist/tools/annotations.d.ts.map +1 -1
- package/dist/tools/apply-patch.d.ts +6 -2
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +13 -8
- package/dist/tools/asset-catalog.d.ts.map +1 -1
- package/dist/tools/asset-catalog.js +23 -0
- package/dist/tools/author-scene.d.ts +10 -0
- package/dist/tools/author-scene.d.ts.map +1 -0
- package/dist/tools/author-scene.js +140 -0
- package/dist/tools/check-collisions.d.ts +6 -6
- package/dist/tools/check-collisions.d.ts.map +1 -1
- package/dist/tools/check-collisions.js +6 -6
- package/dist/tools/clear-scene.d.ts +1 -1
- package/dist/tools/clear-scene.d.ts.map +1 -1
- package/dist/tools/clear-scene.js +3 -3
- package/dist/tools/collections.d.ts +1 -1
- package/dist/tools/collections.d.ts.map +1 -1
- package/dist/tools/collections.js +3 -2
- package/dist/tools/construction-tools.d.ts +6 -49
- package/dist/tools/construction-tools.d.ts.map +1 -1
- package/dist/tools/construction-tools.js +9 -158
- package/dist/tools/create-unit.d.ts +3 -3
- package/dist/tools/create-unit.d.ts.map +1 -1
- package/dist/tools/create-unit.js +2 -2
- package/dist/tools/errors.d.ts +5 -5
- package/dist/tools/errors.d.ts.map +1 -1
- package/dist/tools/errors.js +4 -4
- package/dist/tools/export-glb.d.ts +1 -1
- package/dist/tools/export-glb.d.ts.map +1 -1
- package/dist/tools/export-glb.js +2 -2
- package/dist/tools/export-json.d.ts +1 -1
- package/dist/tools/export-json.d.ts.map +1 -1
- package/dist/tools/export-json.js +2 -2
- package/dist/tools/get-scene.d.ts +1 -1
- package/dist/tools/get-scene.d.ts.map +1 -1
- package/dist/tools/get-scene.js +2 -2
- package/dist/tools/hosted-services.d.ts +1 -1
- package/dist/tools/hosted-services.d.ts.map +1 -1
- package/dist/tools/hosted-services.js +13 -3
- package/dist/tools/index.d.ts +4 -3
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +8 -13
- package/dist/tools/level-height-guard.d.ts +2 -0
- package/dist/tools/level-height-guard.d.ts.map +1 -0
- package/dist/tools/level-height-guard.js +11 -0
- package/dist/tools/list-units.d.ts +2 -2
- package/dist/tools/list-units.d.ts.map +1 -1
- package/dist/tools/list-units.js +2 -2
- package/dist/tools/live-sync.d.ts +1 -1
- package/dist/tools/live-sync.d.ts.map +1 -1
- package/dist/tools/live-sync.js +4 -4
- package/dist/tools/measure.d.ts +1 -1
- package/dist/tools/measure.d.ts.map +1 -1
- package/dist/tools/measure.js +7 -7
- package/dist/tools/node-world-point.d.ts +1 -1
- package/dist/tools/node-world-point.d.ts.map +1 -1
- package/dist/tools/normalize-schema-dialect.d.ts +1 -1
- package/dist/tools/normalize-schema-dialect.d.ts.map +1 -1
- package/dist/tools/normalize-schema-dialect.js +2 -3
- package/dist/tools/patch-guards.d.ts +6 -4
- package/dist/tools/patch-guards.d.ts.map +1 -1
- package/dist/tools/patch-guards.js +5 -2
- package/dist/tools/photo-to-scene/index.d.ts +1 -1
- package/dist/tools/photo-to-scene/index.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts +3 -3
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.js +7 -7
- package/dist/tools/project-files.d.ts +4 -0
- package/dist/tools/project-files.d.ts.map +1 -0
- package/dist/tools/project-files.js +30 -0
- package/dist/tools/redo.d.ts +2 -2
- package/dist/tools/redo.d.ts.map +1 -1
- package/dist/tools/redo.js +2 -2
- package/dist/tools/retired-tools.d.ts +10 -0
- package/dist/tools/retired-tools.d.ts.map +1 -0
- package/dist/tools/retired-tools.js +22 -0
- package/dist/tools/roof-level-guard.d.ts +2 -0
- package/dist/tools/roof-level-guard.d.ts.map +1 -0
- package/dist/tools/roof-level-guard.js +22 -0
- package/dist/tools/room-tools.d.ts +47 -46
- package/dist/tools/room-tools.d.ts.map +1 -1
- package/dist/tools/room-tools.js +6 -5
- package/dist/tools/scene-lifecycle/create-project.d.ts +1 -1
- package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/create-project.js +5 -5
- package/dist/tools/scene-lifecycle/delete-scene.d.ts +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.js +6 -6
- package/dist/tools/scene-lifecycle/get-project-status.d.ts +1 -1
- package/dist/tools/scene-lifecycle/get-project-status.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/get-project-status.js +6 -6
- package/dist/tools/scene-lifecycle/index.d.ts +1 -1
- package/dist/tools/scene-lifecycle/index.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.d.ts +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.js +4 -4
- package/dist/tools/scene-lifecycle/load-scene.d.ts +2 -2
- package/dist/tools/scene-lifecycle/load-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/load-scene.js +5 -5
- package/dist/tools/scene-lifecycle/metadata.d.ts +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.d.ts +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.js +6 -6
- package/dist/tools/scene-lifecycle/save-scene.d.ts +5 -3
- package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/save-scene.js +80 -12
- package/dist/tools/scene-lifecycle/test-utils.d.ts +1 -1
- package/dist/tools/scene-lifecycle/test-utils.d.ts.map +1 -1
- package/dist/tools/set-unit-members.d.ts +2 -2
- package/dist/tools/set-unit-members.d.ts.map +1 -1
- package/dist/tools/set-unit-members.js +6 -6
- package/dist/tools/set-zone.d.ts +2 -2
- package/dist/tools/set-zone.d.ts.map +1 -1
- package/dist/tools/set-zone.js +30 -18
- package/dist/tools/shared-tools.d.ts +15 -5
- package/dist/tools/shared-tools.d.ts.map +1 -1
- package/dist/tools/shared-tools.js +242 -29
- package/dist/tools/structure-tools.d.ts +3 -3
- package/dist/tools/templates/create-from-template.d.ts +2 -2
- package/dist/tools/templates/create-from-template.d.ts.map +1 -1
- package/dist/tools/templates/create-from-template.js +6 -6
- package/dist/tools/templates/create-house-from-brief.d.ts +1 -1
- package/dist/tools/templates/create-house-from-brief.d.ts.map +1 -1
- package/dist/tools/templates/create-house-from-brief.js +6 -6
- package/dist/tools/templates/index.d.ts +1 -1
- package/dist/tools/templates/index.d.ts.map +1 -1
- package/dist/tools/templates/list-templates.d.ts +1 -1
- package/dist/tools/templates/list-templates.d.ts.map +1 -1
- package/dist/tools/templates/list-templates.js +2 -2
- package/dist/tools/undo.d.ts +2 -2
- package/dist/tools/undo.d.ts.map +1 -1
- package/dist/tools/undo.js +2 -2
- package/dist/tools/unit-members.d.ts.map +1 -1
- package/dist/tools/unit-members.js +6 -6
- package/dist/tools/variants/generate-variants.d.ts +6 -6
- package/dist/tools/variants/generate-variants.d.ts.map +1 -1
- package/dist/tools/variants/generate-variants.js +6 -6
- package/dist/tools/variants/index.d.ts +1 -1
- package/dist/tools/variants/index.d.ts.map +1 -1
- package/dist/tools/view-scene.d.ts +8 -2
- package/dist/tools/view-scene.d.ts.map +1 -1
- package/dist/tools/view-scene.js +17 -5
- package/dist/tools/vision/analyze-floorplan-image.d.ts +1 -1
- package/dist/tools/vision/analyze-floorplan-image.d.ts.map +1 -1
- package/dist/tools/vision/analyze-floorplan-image.js +7 -7
- package/dist/tools/vision/analyze-room-photo.d.ts +1 -1
- package/dist/tools/vision/analyze-room-photo.d.ts.map +1 -1
- package/dist/tools/vision/analyze-room-photo.js +7 -7
- package/dist/tools/vision/index.d.ts +1 -1
- package/dist/tools/vision/index.d.ts.map +1 -1
- package/dist/transports/http.d.ts +8 -2
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +9 -3
- package/dist/transports/stdio.d.ts +15 -9
- package/dist/transports/stdio.d.ts.map +1 -1
- package/dist/transports/stdio.js +18 -11
- package/examples/coordinate-conventions-demo.md +12 -13
- package/examples/embed-in-agent.ts +5 -6
- package/examples/generate-apartment.md +4 -4
- package/examples/photo-to-scene.md +2 -3
- package/examples/renovate-from-photos.md +3 -5
- package/package.json +13 -9
- package/dist/tools/describe-node.d.ts +0 -17
- package/dist/tools/describe-node.d.ts.map +0 -1
- package/dist/tools/describe-node.js +0 -99
- package/dist/tools/find-nodes.d.ts +0 -16
- package/dist/tools/find-nodes.d.ts.map +0 -1
- package/dist/tools/find-nodes.js +0 -204
- package/dist/tools/place-design.d.ts +0 -34
- package/dist/tools/place-design.d.ts.map +0 -1
- package/dist/tools/place-design.js +0 -91
- package/dist/tools/validate-design.d.ts +0 -136
- package/dist/tools/validate-design.d.ts.map +0 -1
- package/dist/tools/validate-design.js +0 -28
- package/dist/tools/validate-scene.d.ts +0 -19
- package/dist/tools/validate-scene.d.ts.map +0 -1
- package/dist/tools/validate-scene.js +0 -28
package/dist/tools/set-zone.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { newZone } from '@pascal-app/core';
|
|
1
|
+
import { isAllocatedRoomName, newZone, walledRoomAt } from '@pascal-app/core';
|
|
2
|
+
import { roofLevelRefusal } from '@pascal-app/core/agent-operations';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { ADDITIVE_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
|
-
import {
|
|
5
|
+
import { ProtocolErrorCode, refusalResult, throwMcpError } from './errors.js';
|
|
5
6
|
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
6
7
|
import { NodeIdSchema, Vec2Schema } from './schemas.js';
|
|
7
8
|
export const setZoneInput = {
|
|
@@ -17,30 +18,41 @@ export const setZoneOutput = {
|
|
|
17
18
|
export function registerSetZone(server, bridge) {
|
|
18
19
|
server.registerTool('set_zone', {
|
|
19
20
|
title: 'Set zone',
|
|
20
|
-
description: 'Create a polygonal zone on the given level. label is stored as the zone name and properties are merged into metadata.',
|
|
21
|
-
inputSchema: setZoneInput,
|
|
22
|
-
outputSchema: setZoneOutput,
|
|
21
|
+
description: 'Create a polygonal zone on the given level. label is stored as the zone name and properties are merged into metadata. A polygon along walls that already enclose a room is that room, never a second zone: a room still named "Room N", or already named label, takes the label and properties; a room a person named otherwise is refused (rename it with update_node only when the person asked).',
|
|
22
|
+
inputSchema: z.object(setZoneInput),
|
|
23
|
+
outputSchema: z.object(setZoneOutput),
|
|
23
24
|
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
24
25
|
}, async ({ levelId, polygon, label, properties }) => {
|
|
25
26
|
const parent = bridge.getNode(levelId);
|
|
26
27
|
if (!parent) {
|
|
27
|
-
throwMcpError(
|
|
28
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Level not found: ${levelId}`);
|
|
28
29
|
}
|
|
29
30
|
if (parent.type !== 'level') {
|
|
30
|
-
throwMcpError(
|
|
31
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Node ${levelId} is a ${parent.type}, expected level`);
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const onRoofLevel = roofLevelRefusal(bridge.getNodes(), levelId, 'a zone');
|
|
34
|
+
if (onRoofLevel)
|
|
35
|
+
return refusalResult(onRoofLevel);
|
|
36
|
+
const walled = walledRoomAt(bridge.getNodes(), levelId, polygon);
|
|
37
|
+
if (walled && !isAllocatedRoomName(walled.name) && walled.name !== label) {
|
|
38
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `The walls here already enclose the room "${walled.name}" (${walled.id}), which a person named; a zone "${label}" would stack a second room on it. Rename it with update_node only if the person asked; otherwise leave it.`);
|
|
39
|
+
}
|
|
40
|
+
let id;
|
|
41
|
+
if (walled) {
|
|
42
|
+
id = walled.id;
|
|
43
|
+
bridge.updateNode(id, {
|
|
44
|
+
name: label,
|
|
45
|
+
metadata: { ...walled.metadata, ...properties },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const zone = newZone({
|
|
50
|
+
name: label,
|
|
51
|
+
polygon: polygon,
|
|
52
|
+
metadata: properties ?? {},
|
|
53
|
+
});
|
|
54
|
+
id = bridge.createNode(zone, levelId);
|
|
37
55
|
}
|
|
38
|
-
const zone = newZone({
|
|
39
|
-
name: label,
|
|
40
|
-
polygon: polygon,
|
|
41
|
-
metadata: properties ?? {},
|
|
42
|
-
});
|
|
43
|
-
const id = bridge.createNode(zone, levelId);
|
|
44
56
|
const persistence = await publishLiveSceneSnapshot(bridge, 'set_zone');
|
|
45
57
|
const payload = { zoneId: id, ...persistencePayload(persistence) };
|
|
46
58
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
2
|
-
import { type AgentOperation, type SceneChanges } from '@pascal-app/core/agent-operations';
|
|
3
|
-
import { type AgentToolAnnotations, type AgentToolContract } from '@pascal-app/core/agent-tools';
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
+
import { type AddObjectInput, type AgentHostRuntime, type AgentOperation, type AssetViewLoader, type SceneChanges } from '@pascal-app/core/agent-operations';
|
|
3
|
+
import { type AgentToolAnnotations, type AgentToolContract, type DesignBrief } from '@pascal-app/core/agent-tools';
|
|
4
|
+
import { type CompiledGeometryScript } from '@pascal-app/core/schema';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import type { Patch } from '../bridge/scene-bridge.js';
|
|
6
7
|
import type { SceneOperations } from '../operations/index.js';
|
|
@@ -20,11 +21,20 @@ export type OperationTool = {
|
|
|
20
21
|
/** Reads the host's item library: only these calls wait for it (the hosted one is a query). */
|
|
21
22
|
catalog?: true;
|
|
22
23
|
};
|
|
24
|
+
export type PlanReadingHosts = {
|
|
25
|
+
/** Reads catalog pictures and surfaces before view_assets and paint. */
|
|
26
|
+
assetViews?: AssetViewLoader;
|
|
27
|
+
/** Compiles one add_object module for a batch before the synchronous operations run. */
|
|
28
|
+
buildObject?: (input: Omit<AddObjectInput, 'compiled'>) => Promise<CompiledGeometryScript>;
|
|
29
|
+
};
|
|
23
30
|
export declare function toPatches(changes: SceneChanges): Patch[];
|
|
24
|
-
|
|
31
|
+
/** How an outcome reaches this bridge: its patches, its derived construction, its session record. */
|
|
32
|
+
export declare function agentRuntime(bridge: SceneOperations): AgentHostRuntime;
|
|
33
|
+
export declare function briefInForce(bridge: SceneOperations): DesignBrief | null | undefined;
|
|
34
|
+
export declare function registerSharedTools(server: McpServer, bridge: SceneOperations, catalog?: AssetCatalog, hosts?: PlanReadingHosts): void;
|
|
25
35
|
/**
|
|
26
36
|
* Registers one operation tool, as the shared tools are: a host adds a plugin's `'operation'`
|
|
27
37
|
* tools with it, from the plugin's `./agent-tools` contract and `./agent-operations` operation.
|
|
28
38
|
*/
|
|
29
|
-
export declare function registerOperationTool(server: McpServer, bridge: SceneOperations, tool: OperationTool, catalog?: AssetCatalog): void;
|
|
39
|
+
export declare function registerOperationTool(server: McpServer, bridge: SceneOperations, tool: OperationTool, catalog?: AssetCatalog, hosts?: PlanReadingHosts): void;
|
|
30
40
|
//# sourceMappingURL=shared-tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-tools.d.ts","sourceRoot":"","sources":["../../src/tools/shared-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"shared-tools.d.ts","sourceRoot":"","sources":["../../src/tools/shared-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,EAUpB,KAAK,YAAY,EAGlB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EAStB,KAAK,WAAW,EA+BjB,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAGL,KAAK,sBAAsB,EAG5B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAMpD,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,iBAAiB,CAAA;AASnE;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,SAAS,EAAE,cAAc,CAAA;IACzB,WAAW,EAAE,oBAAoB,CAAA;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAA;IACxC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/D,+FAA+F;IAC/F,OAAO,CAAC,EAAE,IAAI,CAAA;CACf,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wEAAwE;IACxE,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,wFAAwF;IACxF,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAA;CAC3F,CAAA;AAmaD,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,KAAK,EAAE,CAmBxD;AAED,qGAAqG;AACrG,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,gBAAgB,CAsBtE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,WAAW,GAAG,IAAI,GAAG,SAAS,CAIpF;AAUD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,YAA6B,EACtC,KAAK,GAAE,gBAAqB,GAC3B,IAAI,CAGN;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,YAA6B,EACtC,KAAK,GAAE,gBAAqB,GAC3B,IAAI,CAuHN"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { AGENT_OPERATIONS, achievedChanges, applyAgentOutcome, writeCollections, } from '@pascal-app/core/agent-operations';
|
|
2
|
-
import { addLevelTool, addWallTool, createRoomTool, createStairTool, deleteNodeTool, duplicateLevelTool, findByTypeTool, fitStairTool, furnishRoomTool, getLevelSummaryTool, getNodeTool, getWallsTool, getZonesTool, listLevelsTool, measureStairTool, paintTool, placeItemsTool, ROOM_TOOL_CONTRACTS, searchAssetsTool, searchMaterialsTool, verifySceneTool, } from '@pascal-app/core/agent-tools';
|
|
1
|
+
import { AGENT_OPERATIONS, achievedChanges, applyAgentOutcome, assetViewNeeds, assetViewsReadCatalog, briefReadsCatalog, buildBatchObjects, createAssetViewLoader, createFetchAssetViewIO, furnishingRefusal, startOfSession, writeCollections, } from '@pascal-app/core/agent-operations';
|
|
2
|
+
import { addCornerWindowTool, addFenceTool, addLevelTool, addObjectTool, addWallTool, createRoofTool, createRoomTool, createStairTool, deleteNodeTool, designBriefTool, duplicateLevelTool, findByTypeTool, fitStairTool, furnishRoomTool, getLevelSummaryTool, getNodeTool, getSiteTool, getWallsTool, getZonesTool, listLevelsTool, measureStairTool, mergeWindowsTool, moveRoofsToRoofLevelTool, paintTool, placeBuildingTool, placeDesignTool, placeInRoomTool, placeItemsTool, ROOM_TOOL_CONTRACTS, refuse, runBatchTool, searchAssetsTool, searchMaterialsTool, setCheckpointTool, setGroundLevelTool, validateDesignTool, verifySceneTool, viewAssetsTool, } from '@pascal-app/core/agent-tools';
|
|
3
|
+
import { DesignValidationSchema } from '@pascal-app/core/procedural-items';
|
|
3
4
|
import { MaterialSchema, SceneMaterial, } from '@pascal-app/core/schema';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import { ADDITIVE_TOOL_ANNOTATIONS, DESTRUCTIVE_TOOL_ANNOTATIONS, READ_ONLY_TOOL_ANNOTATIONS, } from './annotations.js';
|
|
@@ -8,7 +9,11 @@ import { registerCollectionTools } from './collections.js';
|
|
|
8
9
|
import { refusalResult } from './errors.js';
|
|
9
10
|
import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
|
|
10
11
|
import { ROOM_TOOL_ANNOTATIONS, structureOutput } from './structure-tools.js';
|
|
12
|
+
const defaultAssetViews = createAssetViewLoader(createFetchAssetViewIO());
|
|
11
13
|
const jsonObject = z.record(z.string(), z.unknown());
|
|
14
|
+
function refuseScripts() {
|
|
15
|
+
refuse('scripts_unavailable', 'This Pascal server cannot run geometry scripts.');
|
|
16
|
+
}
|
|
12
17
|
/** What the scene holds after a mutating call (core achievedChanges). */
|
|
13
18
|
const achievedOutput = {
|
|
14
19
|
achieved: z
|
|
@@ -31,6 +36,23 @@ const levelRoleOutput = {
|
|
|
31
36
|
referenceLevelId: z.string().nullable(),
|
|
32
37
|
};
|
|
33
38
|
const SHARED_TOOLS = [
|
|
39
|
+
{
|
|
40
|
+
contract: validateDesignTool,
|
|
41
|
+
operation: AGENT_OPERATIONS.validate_design,
|
|
42
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
43
|
+
outputSchema: DesignValidationSchema.shape,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
contract: placeDesignTool,
|
|
47
|
+
operation: AGENT_OPERATIONS.place_design,
|
|
48
|
+
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
49
|
+
outputSchema: {
|
|
50
|
+
designId: z.string(),
|
|
51
|
+
parentId: z.string(),
|
|
52
|
+
surfaceId: z.string().nullable(),
|
|
53
|
+
...liveSyncOutput,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
34
56
|
{
|
|
35
57
|
contract: measureStairTool,
|
|
36
58
|
operation: AGENT_OPERATIONS.measure_stair,
|
|
@@ -67,7 +89,12 @@ const SHARED_TOOLS = [
|
|
|
67
89
|
contract: getNodeTool,
|
|
68
90
|
operation: AGENT_OPERATIONS.get_node,
|
|
69
91
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
70
|
-
outputSchema: {
|
|
92
|
+
outputSchema: {
|
|
93
|
+
node: jsonObject,
|
|
94
|
+
ancestorIds: z.array(z.string()),
|
|
95
|
+
missingChildIds: z.array(z.string()).optional(),
|
|
96
|
+
materials: z.record(z.string(), SceneMaterial).optional(),
|
|
97
|
+
},
|
|
71
98
|
},
|
|
72
99
|
{
|
|
73
100
|
contract: getLevelSummaryTool,
|
|
@@ -117,6 +144,24 @@ const SHARED_TOOLS = [
|
|
|
117
144
|
...liveSyncOutput,
|
|
118
145
|
},
|
|
119
146
|
},
|
|
147
|
+
{
|
|
148
|
+
contract: setGroundLevelTool,
|
|
149
|
+
operation: AGENT_OPERATIONS.set_ground_level,
|
|
150
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
151
|
+
outputSchema: {
|
|
152
|
+
ok: z.boolean(),
|
|
153
|
+
levelId: z.string(),
|
|
154
|
+
buildingId: z.string(),
|
|
155
|
+
floorElevation: z.number(),
|
|
156
|
+
gradeElevation: z.number().optional(),
|
|
157
|
+
movedBuildingBy: z.number().optional(),
|
|
158
|
+
renumbered: z.boolean().optional(),
|
|
159
|
+
unchanged: z.boolean().optional(),
|
|
160
|
+
message: z.string(),
|
|
161
|
+
...achievedOutput,
|
|
162
|
+
...liveSyncOutput,
|
|
163
|
+
},
|
|
164
|
+
},
|
|
120
165
|
{
|
|
121
166
|
contract: verifySceneTool,
|
|
122
167
|
operation: AGENT_OPERATIONS.verify_scene,
|
|
@@ -132,17 +177,33 @@ const SHARED_TOOLS = [
|
|
|
132
177
|
activeLevelId: z.string().nullable(),
|
|
133
178
|
levels: z.array(jsonObject),
|
|
134
179
|
emptyLevelIds: z.array(z.string()),
|
|
135
|
-
|
|
180
|
+
// Typed by `type`; a check registered with verify_scene may add fields of its own.
|
|
181
|
+
issues: z.array(z.looseObject({
|
|
136
182
|
type: z.string(),
|
|
137
183
|
message: z.string(),
|
|
138
184
|
severity: z.literal('info').optional(),
|
|
185
|
+
nodeId: z.string().optional(),
|
|
186
|
+
path: z.string().optional(),
|
|
187
|
+
zoneId: z.string().optional(),
|
|
188
|
+
wallIds: z.array(z.string()).optional(),
|
|
189
|
+
area: z.number().optional(),
|
|
190
|
+
at: z.tuple([z.number(), z.number()]).optional(),
|
|
139
191
|
wallId: z.string().optional(),
|
|
192
|
+
slabId: z.string().optional(),
|
|
193
|
+
levelId: z.string().optional(),
|
|
194
|
+
wallTop: z.number().optional(),
|
|
195
|
+
slabUnderside: z.number().optional(),
|
|
196
|
+
slabTop: z.number().optional(),
|
|
197
|
+
penetration: z.number().optional(),
|
|
198
|
+
coplanar: z.boolean().optional(),
|
|
140
199
|
end: z.enum(['start', 'end']).optional(),
|
|
141
200
|
reason: z.enum(['gap', 'crosses', 'parallel', 'rejected']).optional(),
|
|
142
201
|
gap: z.number().optional(),
|
|
143
202
|
nearestWallId: z.string().optional(),
|
|
144
203
|
})),
|
|
145
204
|
hasIssues: z.boolean(),
|
|
205
|
+
checkpoints: z.array(z.string()).optional(),
|
|
206
|
+
since: jsonObject.optional(),
|
|
146
207
|
authoredObjects: z
|
|
147
208
|
.array(z.object({
|
|
148
209
|
id: z.string(),
|
|
@@ -154,11 +215,36 @@ const SHARED_TOOLS = [
|
|
|
154
215
|
},
|
|
155
216
|
envelope: (bridge) => ({ activeSceneId: bridge.getActiveScene()?.id ?? null }),
|
|
156
217
|
},
|
|
218
|
+
{
|
|
219
|
+
contract: setCheckpointTool,
|
|
220
|
+
operation: AGENT_OPERATIONS.set_checkpoint,
|
|
221
|
+
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
contract: designBriefTool,
|
|
225
|
+
operation: AGENT_OPERATIONS.design_brief,
|
|
226
|
+
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
227
|
+
},
|
|
157
228
|
{
|
|
158
229
|
contract: addWallTool,
|
|
159
230
|
operation: AGENT_OPERATIONS.add_wall,
|
|
160
231
|
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
161
232
|
},
|
|
233
|
+
{
|
|
234
|
+
contract: addFenceTool,
|
|
235
|
+
operation: AGENT_OPERATIONS.add_fence,
|
|
236
|
+
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
contract: addCornerWindowTool,
|
|
240
|
+
operation: AGENT_OPERATIONS.add_corner_window,
|
|
241
|
+
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
contract: mergeWindowsTool,
|
|
245
|
+
operation: AGENT_OPERATIONS.merge_windows,
|
|
246
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
247
|
+
},
|
|
162
248
|
{
|
|
163
249
|
contract: addLevelTool,
|
|
164
250
|
operation: AGENT_OPERATIONS.add_level,
|
|
@@ -169,6 +255,16 @@ const SHARED_TOOLS = [
|
|
|
169
255
|
operation: AGENT_OPERATIONS.create_stair,
|
|
170
256
|
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
171
257
|
},
|
|
258
|
+
{
|
|
259
|
+
contract: createRoofTool,
|
|
260
|
+
operation: AGENT_OPERATIONS.create_roof,
|
|
261
|
+
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
contract: moveRoofsToRoofLevelTool,
|
|
265
|
+
operation: AGENT_OPERATIONS.move_roofs_to_roof_level,
|
|
266
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
267
|
+
},
|
|
172
268
|
{
|
|
173
269
|
contract: placeItemsTool,
|
|
174
270
|
operation: AGENT_OPERATIONS.place_items,
|
|
@@ -227,12 +323,6 @@ const SHARED_TOOLS = [
|
|
|
227
323
|
...liveSyncOutput,
|
|
228
324
|
},
|
|
229
325
|
},
|
|
230
|
-
{
|
|
231
|
-
contract: searchAssetsTool,
|
|
232
|
-
operation: AGENT_OPERATIONS.search_assets,
|
|
233
|
-
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
234
|
-
catalog: true,
|
|
235
|
-
},
|
|
236
326
|
{
|
|
237
327
|
contract: paintTool,
|
|
238
328
|
operation: AGENT_OPERATIONS.paint,
|
|
@@ -249,6 +339,54 @@ const SHARED_TOOLS = [
|
|
|
249
339
|
...liveSyncOutput,
|
|
250
340
|
},
|
|
251
341
|
},
|
|
342
|
+
{
|
|
343
|
+
contract: placeInRoomTool,
|
|
344
|
+
operation: AGENT_OPERATIONS.place_in_room,
|
|
345
|
+
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
346
|
+
catalog: true,
|
|
347
|
+
outputSchema: {
|
|
348
|
+
ok: z.literal(true),
|
|
349
|
+
itemId: z.string(),
|
|
350
|
+
kind: z.string(),
|
|
351
|
+
placed: z.object({ position: z.array(z.number()), rotationDeg: z.number() }),
|
|
352
|
+
against: z.object({ edge: z.number(), wall: z.string() }).optional(),
|
|
353
|
+
around: z.string().optional(),
|
|
354
|
+
facing: z.string().optional(),
|
|
355
|
+
message: z.string(),
|
|
356
|
+
...achievedOutput,
|
|
357
|
+
...liveSyncOutput,
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
contract: getSiteTool,
|
|
362
|
+
operation: AGENT_OPERATIONS.get_site,
|
|
363
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
contract: placeBuildingTool,
|
|
367
|
+
operation: AGENT_OPERATIONS.place_building,
|
|
368
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
369
|
+
outputSchema: {
|
|
370
|
+
buildingId: z.string(),
|
|
371
|
+
moved: z.boolean(),
|
|
372
|
+
fit: z.enum(['buildable', 'lot', 'outside']),
|
|
373
|
+
message: z.string(),
|
|
374
|
+
...achievedOutput,
|
|
375
|
+
...liveSyncOutput,
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
contract: searchAssetsTool,
|
|
380
|
+
operation: AGENT_OPERATIONS.search_assets,
|
|
381
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
382
|
+
catalog: true,
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
contract: viewAssetsTool,
|
|
386
|
+
operation: AGENT_OPERATIONS.view_assets,
|
|
387
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
388
|
+
catalog: true,
|
|
389
|
+
},
|
|
252
390
|
{
|
|
253
391
|
contract: searchMaterialsTool,
|
|
254
392
|
operation: AGENT_OPERATIONS.search_materials,
|
|
@@ -263,6 +401,11 @@ const SHARED_TOOLS = [
|
|
|
263
401
|
outputSchema: { ...structureOutput, ...achievedOutput },
|
|
264
402
|
};
|
|
265
403
|
}),
|
|
404
|
+
{
|
|
405
|
+
contract: runBatchTool,
|
|
406
|
+
operation: AGENT_OPERATIONS.run_batch,
|
|
407
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
408
|
+
},
|
|
266
409
|
];
|
|
267
410
|
export function toPatches(changes) {
|
|
268
411
|
return [
|
|
@@ -284,25 +427,51 @@ export function toPatches(changes) {
|
|
|
284
427
|
})),
|
|
285
428
|
];
|
|
286
429
|
}
|
|
430
|
+
/** How an outcome reaches this bridge: its patches, its derived construction, its session record. */
|
|
431
|
+
export function agentRuntime(bridge) {
|
|
432
|
+
return {
|
|
433
|
+
getNodes: () => bridge.getNodes(),
|
|
434
|
+
applyChanges: (changes) => {
|
|
435
|
+
if (changes.materials?.length &&
|
|
436
|
+
(bridge.supportsMaterialUpserts !== true || bridge.getMaterials?.() === undefined))
|
|
437
|
+
refuse('materials_unavailable', 'This host cannot atomically persist native materials; nothing was painted.');
|
|
438
|
+
const next = toPatches(changes);
|
|
439
|
+
if (next.length)
|
|
440
|
+
bridge.applyPatch(next);
|
|
441
|
+
if (changes.collections && Object.keys(changes.collections).length)
|
|
442
|
+
bridge.setCollections(writeCollections(bridge.getCollections(), changes.collections));
|
|
443
|
+
},
|
|
444
|
+
reconcile: () => {
|
|
445
|
+
bridge.deriveStructure();
|
|
446
|
+
},
|
|
447
|
+
keep: (keep) => bridge.agentSession?.keep(keep),
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
export function briefInForce(bridge) {
|
|
451
|
+
if (bridge.designBriefRequired === false)
|
|
452
|
+
return undefined;
|
|
453
|
+
const session = bridge.agentSession;
|
|
454
|
+
return session ? (session.read().designBrief ?? null) : undefined;
|
|
455
|
+
}
|
|
287
456
|
function writesScene(changes) {
|
|
288
457
|
return Boolean(changes &&
|
|
289
458
|
(toPatches(changes).length ||
|
|
290
459
|
(changes.collections && Object.keys(changes.collections).length)));
|
|
291
460
|
}
|
|
292
|
-
export function registerSharedTools(server, bridge, catalog = builtInCatalog) {
|
|
461
|
+
export function registerSharedTools(server, bridge, catalog = builtInCatalog, hosts = {}) {
|
|
293
462
|
for (const tool of SHARED_TOOLS)
|
|
294
|
-
registerOperationTool(server, bridge, tool, catalog);
|
|
463
|
+
registerOperationTool(server, bridge, tool, catalog, hosts);
|
|
295
464
|
registerCollectionTools(server, bridge);
|
|
296
465
|
}
|
|
297
466
|
/**
|
|
298
467
|
* Registers one operation tool, as the shared tools are: a host adds a plugin's `'operation'`
|
|
299
468
|
* tools with it, from the plugin's `./agent-tools` contract and `./agent-operations` operation.
|
|
300
469
|
*/
|
|
301
|
-
export function registerOperationTool(server, bridge, tool, catalog = builtInCatalog) {
|
|
470
|
+
export function registerOperationTool(server, bridge, tool, catalog = builtInCatalog, hosts = {}) {
|
|
302
471
|
server.registerTool(tool.contract.name, {
|
|
303
472
|
title: tool.contract.title,
|
|
304
473
|
description: tool.contract.description,
|
|
305
|
-
inputSchema: tool.contract.input,
|
|
474
|
+
inputSchema: z.object(tool.contract.input),
|
|
306
475
|
// Loose: a client that listed the tools rejects any field the schema leaves out, and the
|
|
307
476
|
// operations in core grow fields (verify_scene's guesses) that this list would miss.
|
|
308
477
|
...(tool.outputSchema ? { outputSchema: z.looseObject(tool.outputSchema) } : {}),
|
|
@@ -312,13 +481,50 @@ export function registerOperationTool(server, bridge, tool, catalog = builtInCat
|
|
|
312
481
|
// A copy of the map: a host may write its own in place (the hosted bridge does), and a
|
|
313
482
|
// "before" that grows with the call reads every creation as unchanged.
|
|
314
483
|
const before = { ...bridge.getNodes() };
|
|
484
|
+
// The agent's session begins with its first call, before anything is written.
|
|
485
|
+
const first = bridge.agentSession && startOfSession(bridge.agentSession.read(), before);
|
|
486
|
+
if (first)
|
|
487
|
+
bridge.agentSession?.keep(first);
|
|
488
|
+
// Gate before catalog I/O or module compilation.
|
|
489
|
+
const designBrief = briefInForce(bridge);
|
|
490
|
+
if (designBrief !== undefined) {
|
|
491
|
+
const refusal = furnishingRefusal(tool.contract.name, input, designBrief);
|
|
492
|
+
if (refusal)
|
|
493
|
+
return refusalResult(refusal);
|
|
494
|
+
}
|
|
495
|
+
const batchPlacesInRoom = tool.contract.name === runBatchTool.name &&
|
|
496
|
+
Array.isArray(input.calls) &&
|
|
497
|
+
input.calls.some((call) => typeof call === 'object' &&
|
|
498
|
+
call !== null &&
|
|
499
|
+
'tool' in call &&
|
|
500
|
+
call.tool === placeInRoomTool.name);
|
|
501
|
+
const batchesObjects = tool.contract.name === runBatchTool.name &&
|
|
502
|
+
Array.isArray(input.calls) &&
|
|
503
|
+
input.calls.some((call) => typeof call === 'object' &&
|
|
504
|
+
call !== null &&
|
|
505
|
+
'tool' in call &&
|
|
506
|
+
call.tool === addObjectTool.name);
|
|
315
507
|
const context = {
|
|
316
|
-
activeLevelId: null,
|
|
317
|
-
...(tool.catalog && { catalog: await catalog() }),
|
|
508
|
+
activeLevelId: bridge.activeLevelId?.() ?? null,
|
|
318
509
|
...(bridge.supportsMaterialUpserts && bridge.getMaterials
|
|
319
510
|
? { materials: bridge.getMaterials() }
|
|
320
511
|
: {}),
|
|
512
|
+
...(bridge.nodeSchema && { nodeSchema: (kind) => bridge.nodeSchema(kind) }),
|
|
513
|
+
session: bridge.agentSession?.read(),
|
|
514
|
+
...(designBrief !== undefined && { designBrief }),
|
|
515
|
+
...((tool.catalog ||
|
|
516
|
+
batchPlacesInRoom ||
|
|
517
|
+
assetViewsReadCatalog(tool.contract.name, input) ||
|
|
518
|
+
briefReadsCatalog(tool.contract.name, input)) && { catalog: await catalog() }),
|
|
519
|
+
...(batchesObjects && {
|
|
520
|
+
batchObjects: await buildBatchObjects(input.calls, hosts.buildObject ?? refuseScripts),
|
|
521
|
+
}),
|
|
321
522
|
};
|
|
523
|
+
const needs = assetViewNeeds(before, tool.contract.name, input, context);
|
|
524
|
+
if (needs.subjects.length)
|
|
525
|
+
context.assetViews = await (hosts.assetViews ?? defaultAssetViews)(needs.subjects, {
|
|
526
|
+
pictures: needs.pictures,
|
|
527
|
+
});
|
|
322
528
|
try {
|
|
323
529
|
outcome = tool.operation(before, input, context);
|
|
324
530
|
}
|
|
@@ -330,21 +536,13 @@ export function registerOperationTool(server, bridge, tool, catalog = builtInCat
|
|
|
330
536
|
// An outcome edits the scene through its node changes, its collection writes, or the
|
|
331
537
|
// follow-up it plans once the host has reconciled; any of them is one history step.
|
|
332
538
|
if (writesScene(outcome.changes) || outcome.afterReconcile) {
|
|
333
|
-
result = bridge.runAsSingleHistoryStep(() => applyAgentOutcome(outcome,
|
|
334
|
-
getNodes: () => bridge.getNodes(),
|
|
335
|
-
applyChanges: (changes) => {
|
|
336
|
-
const next = toPatches(changes);
|
|
337
|
-
if (next.length)
|
|
338
|
-
bridge.applyPatch(next);
|
|
339
|
-
if (changes.collections && Object.keys(changes.collections).length)
|
|
340
|
-
bridge.setCollections(writeCollections(bridge.getCollections(), changes.collections));
|
|
341
|
-
},
|
|
342
|
-
reconcile: () => {
|
|
343
|
-
bridge.deriveStructure();
|
|
344
|
-
},
|
|
345
|
-
}));
|
|
539
|
+
result = bridge.runAsSingleHistoryStep(() => applyAgentOutcome(outcome, agentRuntime(bridge)));
|
|
346
540
|
persistence = persistencePayload(await publishLiveSceneSnapshot(bridge, tool.contract.name));
|
|
347
541
|
}
|
|
542
|
+
else if (outcome.keep) {
|
|
543
|
+
// A checkpoint: kept with the session, nothing in the scene to save.
|
|
544
|
+
result = applyAgentOutcome(outcome, agentRuntime(bridge));
|
|
545
|
+
}
|
|
348
546
|
// What the scene holds after the call, not only what the call says it built.
|
|
349
547
|
const achieved = outcome.changes ? achievedChanges(before, outcome.changes) : null;
|
|
350
548
|
const payload = {
|
|
@@ -353,6 +551,21 @@ export function registerOperationTool(server, bridge, tool, catalog = builtInCat
|
|
|
353
551
|
...(tool.envelope?.(bridge) ?? {}),
|
|
354
552
|
...persistence,
|
|
355
553
|
};
|
|
554
|
+
const { previews, ...shown } = payload;
|
|
555
|
+
const pictures = (Array.isArray(previews) ? previews : []).flatMap(({ label, image }) => {
|
|
556
|
+
const [, mimeType, data] = /^data:(image\/[\w.+-]+);base64,(.+)$/.exec(image) ?? [];
|
|
557
|
+
return mimeType && data
|
|
558
|
+
? [
|
|
559
|
+
{ type: 'text', text: label },
|
|
560
|
+
{ type: 'image', data, mimeType },
|
|
561
|
+
]
|
|
562
|
+
: [];
|
|
563
|
+
});
|
|
564
|
+
if (pictures.length)
|
|
565
|
+
return {
|
|
566
|
+
content: [{ type: 'text', text: JSON.stringify(shown) }, ...pictures],
|
|
567
|
+
structuredContent: shown,
|
|
568
|
+
};
|
|
356
569
|
return {
|
|
357
570
|
content: [{ type: 'text', text: JSON.stringify(payload) }],
|
|
358
571
|
structuredContent: payload,
|
|
@@ -8,8 +8,8 @@ export declare const structureOutput: {
|
|
|
8
8
|
unsaved: z.ZodOptional<z.ZodString>;
|
|
9
9
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
10
10
|
status: z.ZodEnum<{
|
|
11
|
-
unbound: "unbound";
|
|
12
11
|
events_unsupported: "events_unsupported";
|
|
12
|
+
unbound: "unbound";
|
|
13
13
|
}>;
|
|
14
14
|
warning: z.ZodString;
|
|
15
15
|
}, z.core.$strip>>;
|
|
@@ -31,9 +31,9 @@ export declare const structureOutput: {
|
|
|
31
31
|
zoneId: z.ZodString;
|
|
32
32
|
name: z.ZodString;
|
|
33
33
|
mode: z.ZodEnum<{
|
|
34
|
-
merge: "merge";
|
|
35
|
-
delete: "delete";
|
|
36
34
|
blocked: "blocked";
|
|
35
|
+
delete: "delete";
|
|
36
|
+
merge: "merge";
|
|
37
37
|
}>;
|
|
38
38
|
mergedIntoZoneId: z.ZodOptional<z.ZodString>;
|
|
39
39
|
contents: z.ZodEnum<{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../../operations/index.js';
|
|
4
4
|
export declare const createFromTemplateInput: {
|
|
@@ -36,8 +36,8 @@ export declare const createFromTemplateOutput: {
|
|
|
36
36
|
published: z.ZodBoolean;
|
|
37
37
|
isDraft: z.ZodBoolean;
|
|
38
38
|
saveMode: z.ZodEnum<{
|
|
39
|
-
draft: "draft";
|
|
40
39
|
checkpoint: "checkpoint";
|
|
40
|
+
draft: "draft";
|
|
41
41
|
}>;
|
|
42
42
|
graphHash: z.ZodOptional<z.ZodString>;
|
|
43
43
|
levelIds: z.ZodArray<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-from-template.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/create-from-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"create-from-template.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/create-from-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAG7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAOvD,eAAO,MAAM,uBAAuB;IAClC,EAAE;IAKF,IAAI;IAMJ;;;;;OAKG;IACH,IAAI;IACJ,SAAS;CACV,CAAA;AAED,eAAO,MAAM,wBAAwB;IACnC,UAAU;IACV,WAAW;IACX,SAAS;IACT,yEAAyE;IACzE,WAAW;IACX,6DAA6D;IAC7D,KAAK;;;;;;;;;;;;;;;;;;;;;;;CAsBN,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA+F3F"}
|
|
@@ -3,7 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { rehydrateSiteChildren } from '../../lib/rehydrate-site-children.js';
|
|
4
4
|
import { isTemplateId, TEMPLATES } from '../../templates/index.js';
|
|
5
5
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
6
|
-
import {
|
|
6
|
+
import { ProtocolErrorCode, throwMcpError } from '../errors.js';
|
|
7
7
|
import { appendLiveSceneEvent } from '../live-sync.js';
|
|
8
8
|
import { currentLevelContext, sceneMetaPayload } from '../scene-lifecycle/metadata.js';
|
|
9
9
|
export const createFromTemplateInput = {
|
|
@@ -67,12 +67,12 @@ export function registerCreateFromTemplate(server, bridge) {
|
|
|
67
67
|
server.registerTool('create_from_template', {
|
|
68
68
|
title: 'Create scene from template',
|
|
69
69
|
description: 'Instantiate a seed Pascal scene template into the bridge. Regenerates all ids before applying. When `save: true` and a SceneStore is wired, also persists the new scene and returns the SceneMeta.',
|
|
70
|
-
inputSchema: createFromTemplateInput,
|
|
71
|
-
outputSchema: createFromTemplateOutput,
|
|
70
|
+
inputSchema: z.object(createFromTemplateInput),
|
|
71
|
+
outputSchema: z.object(createFromTemplateOutput),
|
|
72
72
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
73
73
|
}, async ({ id, name, save, projectId }) => {
|
|
74
74
|
if (!isTemplateId(id)) {
|
|
75
|
-
throwMcpError(
|
|
75
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `unknown_template: ${id}. Call list_templates for the set of valid ids.`);
|
|
76
76
|
}
|
|
77
77
|
const entry = TEMPLATES[id];
|
|
78
78
|
// Clone: regenerate ids so each instantiation is independent.
|
|
@@ -87,7 +87,7 @@ export function registerCreateFromTemplate(server, bridge) {
|
|
|
87
87
|
}
|
|
88
88
|
catch (err) {
|
|
89
89
|
const msg = err instanceof Error ? err.message : String(err);
|
|
90
|
-
throwMcpError(
|
|
90
|
+
throwMcpError(ProtocolErrorCode.InternalError, `apply_failed: ${msg}`);
|
|
91
91
|
}
|
|
92
92
|
const basePayload = {
|
|
93
93
|
templateId: entry.id,
|
|
@@ -143,7 +143,7 @@ export function registerCreateFromTemplate(server, bridge) {
|
|
|
143
143
|
}
|
|
144
144
|
catch (err) {
|
|
145
145
|
const msg = err instanceof Error ? err.message : String(err);
|
|
146
|
-
throwMcpError(
|
|
146
|
+
throwMcpError(ProtocolErrorCode.InternalError, `save_failed: ${msg}`);
|
|
147
147
|
}
|
|
148
148
|
});
|
|
149
149
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import type { SceneOperations } from '../../operations/index.js';
|
|
4
4
|
export declare const createHouseFromBriefInput: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-house-from-brief.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/create-house-from-brief.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"create-house-from-brief.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/create-house-from-brief.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAG7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAOvD,eAAO,MAAM,yBAAyB;IACpC,KAAK;IACL,SAAS;IACT,WAAW;IACX,YAAY;IACZ,KAAK;IACL,KAAK;IACL,WAAW;IACX,WAAW;CACZ,CAAA;AAED,eAAO,MAAM,0BAA0B;IACrC,SAAS;IACT,SAAS;IACT,GAAG;IACH,OAAO;IACP,SAAS;IACT,OAAO;IACP,UAAU;IACV,SAAS;IACT,SAAS;IACT,QAAQ;IACR,cAAc;IACd,UAAU;;;;IAIV,OAAO;IACP,WAAW;IACX,QAAQ;CACT,CAAA;AAmCD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAsI7F"}
|