@theprototype/agent 1.53.1 → 1.54.0
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/catalog.json +90 -4
- package/package.json +1 -1
- package/src/browserEngine.js +4 -3
- package/src/mcpServer.js +3 -1
- package/src/mcpTools.js +22 -2
package/catalog.json
CHANGED
|
@@ -538,7 +538,7 @@
|
|
|
538
538
|
{
|
|
539
539
|
"name": "create_flow_nodes",
|
|
540
540
|
"title": "Add behaviour (flow) nodes",
|
|
541
|
-
"description": "Add behavior (flow) nodes to a node graph — this is how objects get MOTION and interactivity: spin, bounce, patrol a path, pulse, blink, react to clicks. graph is \"scene\" or an object uuid (ONE graph per call). KEY RULE: a behavior node placed in an OBJECT's graph with no edges automatically drives that object — most behaviors are one node, zero edges, so usually OMIT edges. A script node runs every frame FROM THE BASE POSE, so object.rotation.y += 0.02 lands at base + 0.02 and stays: write object.rotation.y = base.rot[1] +
|
|
541
|
+
"description": "Add behavior (flow) nodes to a node graph — this is how objects get MOTION and interactivity: spin, bounce, patrol a path, pulse, blink, react to clicks. graph is \"scene\" or an object uuid (ONE graph per call). KEY RULE: a behavior node placed in an OBJECT's graph with no edges automatically drives that object — most behaviors are one node, zero edges, so usually OMIT edges. A script node runs every frame FROM THE BASE POSE, so object.rotation.y += 0.02 lands at base + 0.02 and stays: write object.rotation.y = base.rot[1] + elapsed * speed (base has pos, rot, scale as arrays; elapsed = seconds since Play started, time = the shared clock, seconds of the day, a large number). Particle gravity is the acceleration along world Y: negative falls, positive rises. Describe nodes EITHER as text (graph lines, see the system prompt) OR as nodes/edges arrays. A call with some bad nodes still creates the good ones and returns partial:true + errors[] — resend only what errors[] names.\nMotion and interaction are flow nodes (create_flow_nodes); call describe_node_types before wiring edges.\nTake a screenshot after each change to check your work.",
|
|
542
542
|
"inputSchema": {
|
|
543
543
|
"type": "object",
|
|
544
544
|
"properties": {
|
|
@@ -613,7 +613,7 @@
|
|
|
613
613
|
{
|
|
614
614
|
"name": "update_flow_nodes",
|
|
615
615
|
"title": "Change or remove flow nodes",
|
|
616
|
-
"description": "Tune or remove existing behavior nodes in one graph. Node ids and current data are in the scene summary under each object's \"flow\" (and \"sceneFlow\"). Script code runs every frame from the base pose: use object.rotation.y = base.rot[1] +
|
|
616
|
+
"description": "Tune or remove existing behavior nodes in one graph. Node ids and current data are in the scene summary under each object's \"flow\" (and \"sceneFlow\"). Script code runs every frame from the base pose: use object.rotation.y = base.rot[1] + elapsed * speed, not += (elapsed = seconds since Play started, time = the shared clock, seconds of the day).\nTake a screenshot after each change to check your work.",
|
|
617
617
|
"inputSchema": {
|
|
618
618
|
"type": "object",
|
|
619
619
|
"properties": {
|
|
@@ -1330,7 +1330,7 @@
|
|
|
1330
1330
|
{
|
|
1331
1331
|
"name": "screenshot",
|
|
1332
1332
|
"title": "Take a picture of the scene",
|
|
1333
|
-
"description": "See the scene: a PNG of a clean frame (no gizmos) from a temporary camera, never moving anyone's view. view: current | top | front | iso | focus (focus needs uuid).",
|
|
1333
|
+
"description": "See the scene: a PNG of a clean frame (no gizmos) from a temporary camera, never moving anyone's view. view: current | top | front | iso | focus (focus needs uuid or uuids); from = an angle or {yaw, pitch}; camera = a free {position, target}. 4:3 unless aspect says otherwise (current follows the person's window). Answers with the camera it used.",
|
|
1334
1334
|
"inputSchema": {
|
|
1335
1335
|
"type": "object",
|
|
1336
1336
|
"properties": {
|
|
@@ -1346,7 +1346,93 @@
|
|
|
1346
1346
|
},
|
|
1347
1347
|
"uuid": {
|
|
1348
1348
|
"type": "string",
|
|
1349
|
-
"description": "object to frame
|
|
1349
|
+
"description": "object to frame"
|
|
1350
|
+
},
|
|
1351
|
+
"uuids": {
|
|
1352
|
+
"type": "array",
|
|
1353
|
+
"items": {
|
|
1354
|
+
"type": "string"
|
|
1355
|
+
},
|
|
1356
|
+
"description": "objects to frame together"
|
|
1357
|
+
},
|
|
1358
|
+
"from": {
|
|
1359
|
+
"description": "the angle around the subject, instead of view: front, back, left, right, top, below, iso, or {yaw, pitch} in degrees (yaw 0 = front, 90 = right; pitch 90 = from above)",
|
|
1360
|
+
"anyOf": [
|
|
1361
|
+
{
|
|
1362
|
+
"type": "string",
|
|
1363
|
+
"enum": [
|
|
1364
|
+
"front",
|
|
1365
|
+
"back",
|
|
1366
|
+
"left",
|
|
1367
|
+
"right",
|
|
1368
|
+
"top",
|
|
1369
|
+
"below",
|
|
1370
|
+
"iso"
|
|
1371
|
+
]
|
|
1372
|
+
},
|
|
1373
|
+
{
|
|
1374
|
+
"type": "object",
|
|
1375
|
+
"properties": {
|
|
1376
|
+
"yaw": {
|
|
1377
|
+
"type": "number"
|
|
1378
|
+
},
|
|
1379
|
+
"pitch": {
|
|
1380
|
+
"type": "number"
|
|
1381
|
+
}
|
|
1382
|
+
},
|
|
1383
|
+
"required": [
|
|
1384
|
+
"yaw",
|
|
1385
|
+
"pitch"
|
|
1386
|
+
]
|
|
1387
|
+
}
|
|
1388
|
+
]
|
|
1389
|
+
},
|
|
1390
|
+
"camera": {
|
|
1391
|
+
"type": "object",
|
|
1392
|
+
"description": "a free camera, instead of view and from",
|
|
1393
|
+
"properties": {
|
|
1394
|
+
"position": {
|
|
1395
|
+
"type": "array",
|
|
1396
|
+
"items": {
|
|
1397
|
+
"type": "number"
|
|
1398
|
+
},
|
|
1399
|
+
"minItems": 3,
|
|
1400
|
+
"maxItems": 3,
|
|
1401
|
+
"description": "[x,y,z]"
|
|
1402
|
+
},
|
|
1403
|
+
"target": {
|
|
1404
|
+
"type": "array",
|
|
1405
|
+
"items": {
|
|
1406
|
+
"type": "number"
|
|
1407
|
+
},
|
|
1408
|
+
"minItems": 3,
|
|
1409
|
+
"maxItems": 3,
|
|
1410
|
+
"description": "[x,y,z]"
|
|
1411
|
+
}
|
|
1412
|
+
},
|
|
1413
|
+
"required": [
|
|
1414
|
+
"position",
|
|
1415
|
+
"target"
|
|
1416
|
+
]
|
|
1417
|
+
},
|
|
1418
|
+
"aspect": {
|
|
1419
|
+
"description": "width to height: \"4:3\" (default), \"1:1\", \"16:9\" or a number. view current defaults to the person's window",
|
|
1420
|
+
"anyOf": [
|
|
1421
|
+
{
|
|
1422
|
+
"type": "string"
|
|
1423
|
+
},
|
|
1424
|
+
{
|
|
1425
|
+
"type": "number"
|
|
1426
|
+
}
|
|
1427
|
+
]
|
|
1428
|
+
},
|
|
1429
|
+
"zoom": {
|
|
1430
|
+
"type": "number",
|
|
1431
|
+
"description": "above 1 is closer, 0.1 to 10"
|
|
1432
|
+
},
|
|
1433
|
+
"margin": {
|
|
1434
|
+
"type": "number",
|
|
1435
|
+
"description": "room around the subject: 1 touches the frame, default 1.15"
|
|
1350
1436
|
},
|
|
1351
1437
|
"size": {
|
|
1352
1438
|
"type": "number",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theprototype/agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.54.0",
|
|
4
4
|
"description": "Let an AI agent (Claude Code, Claude Desktop, any MCP host) join a theprototype.app session from its link and build the 3D scene with you.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/browserEngine.js
CHANGED
|
@@ -357,13 +357,14 @@ export class BrowserEngine extends EventEmitter {
|
|
|
357
357
|
fr.readAsDataURL(/** @type {Blob} */ (r));
|
|
358
358
|
});
|
|
359
359
|
}
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
const camera = typeof api.lastShot === 'function' ? api.lastShot() : null;
|
|
361
|
+
if (r && typeof r === 'object' && typeof r.data === 'string') return { data: r.data, mimeType: r.mimeType || 'image/png', camera };
|
|
362
|
+
return typeof r === 'string' ? { data: r, mimeType: 'image/png', camera } : null;
|
|
362
363
|
}, opts)
|
|
363
364
|
.catch((/** @type {any} */ e) => ({ error: firstLine(e) }));
|
|
364
365
|
if (viaApi && typeof viaApi.data === 'string') {
|
|
365
366
|
const m = /^data:([^;,]+)(;base64)?,/.exec(viaApi.data);
|
|
366
|
-
return m ? { data: viaApi.data.slice(m[0].length), mimeType: m[1] } : viaApi;
|
|
367
|
+
return m ? { data: viaApi.data.slice(m[0].length), mimeType: m[1], camera: viaApi.camera } : viaApi;
|
|
367
368
|
}
|
|
368
369
|
const canvas = await this.page.evaluateHandle(() => {
|
|
369
370
|
const all = [...document.querySelectorAll('canvas')].filter((c) => c.width > 0 && c.height > 0 && c.offsetParent !== null);
|
package/src/mcpServer.js
CHANGED
|
@@ -222,10 +222,12 @@ export function createBridgeServer(opts) {
|
|
|
222
222
|
if (!engine) return textResult({ error: 'not connected — join first', note: 'call connect with the session link first' }, true);
|
|
223
223
|
if (name === 'screenshot' && reserved.includes('screenshot')) {
|
|
224
224
|
if (!engineReady()) return textResult({ error: 'the agent page is not up yet (' + engine.state + ')' }, true);
|
|
225
|
-
const
|
|
225
|
+
const { view, uuid, uuids, from, camera, aspect, zoom, margin, size } = a;
|
|
226
|
+
const shot = await engine.screenshot({ view, uuid, uuids, from, camera, aspect, zoom, margin, size });
|
|
226
227
|
/** @type {any[]} */
|
|
227
228
|
const content = [{ type: 'image', data: shot.data, mimeType: shot.mimeType || 'image/png' }];
|
|
228
229
|
if (shot.note) content.push({ type: 'text', text: shot.note });
|
|
230
|
+
if (shot.camera) content.push({ type: 'text', text: JSON.stringify({ camera: shot.camera }) });
|
|
229
231
|
return { content };
|
|
230
232
|
}
|
|
231
233
|
if (name === 'wait_for_edit' && reserved.includes('wait_for_edit')) {
|
package/src/mcpTools.js
CHANGED
|
@@ -86,12 +86,32 @@ export function bridgeTools(engine = 'browser') {
|
|
|
86
86
|
{
|
|
87
87
|
name: 'screenshot',
|
|
88
88
|
description:
|
|
89
|
-
'See the scene: a PNG of a clean frame (no gizmos) from a temporary camera, never moving anyone\'s view. view: current | top | front | iso | focus (focus needs uuid).',
|
|
89
|
+
'See the scene: a PNG of a clean frame (no gizmos) from a temporary camera, never moving anyone\'s view. view: current | top | front | iso | focus (focus needs uuid or uuids); from = an angle or {yaw, pitch}; camera = a free {position, target}. 4:3 unless aspect says otherwise (current follows the person\'s window). Answers with the camera it used.',
|
|
90
90
|
inputSchema: {
|
|
91
91
|
type: 'object',
|
|
92
92
|
properties: {
|
|
93
93
|
view: { type: 'string', enum: ['current', 'top', 'front', 'iso', 'focus'] },
|
|
94
|
-
uuid: { type: 'string', description: 'object to frame
|
|
94
|
+
uuid: { type: 'string', description: 'object to frame' },
|
|
95
|
+
uuids: { type: 'array', items: { type: 'string' }, description: 'objects to frame together' },
|
|
96
|
+
from: {
|
|
97
|
+
description: 'the angle around the subject, instead of view: front, back, left, right, top, below, iso, or {yaw, pitch} in degrees (yaw 0 = front, 90 = right; pitch 90 = from above)',
|
|
98
|
+
anyOf: [
|
|
99
|
+
{ type: 'string', enum: ['front', 'back', 'left', 'right', 'top', 'below', 'iso'] },
|
|
100
|
+
{ type: 'object', properties: { yaw: { type: 'number' }, pitch: { type: 'number' } }, required: ['yaw', 'pitch'] }
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
camera: {
|
|
104
|
+
type: 'object',
|
|
105
|
+
description: 'a free camera, instead of view and from',
|
|
106
|
+
properties: {
|
|
107
|
+
position: { type: 'array', items: { type: 'number' }, minItems: 3, maxItems: 3, description: '[x,y,z]' },
|
|
108
|
+
target: { type: 'array', items: { type: 'number' }, minItems: 3, maxItems: 3, description: '[x,y,z]' }
|
|
109
|
+
},
|
|
110
|
+
required: ['position', 'target']
|
|
111
|
+
},
|
|
112
|
+
aspect: { description: 'width to height: "4:3" (default), "1:1", "16:9" or a number. view current defaults to the person\'s window', anyOf: [{ type: 'string' }, { type: 'number' }] },
|
|
113
|
+
zoom: { type: 'number', description: 'above 1 is closer, 0.1 to 10' },
|
|
114
|
+
margin: { type: 'number', description: 'room around the subject: 1 touches the frame, default 1.15' },
|
|
95
115
|
size: { type: 'number', description: 'longest side in pixels' }
|
|
96
116
|
}
|
|
97
117
|
}
|