dsh-motion-ui 0.7.0 → 0.8.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/CHANGELOG.md +59 -0
- package/README.md +63 -3
- package/VERIFICATION.md +26 -0
- package/client.js +876 -272
- package/index.js +43 -20
- package/lib/assets/mermaid.js +382 -382
- package/lib/assets/standalone-runtime.js +1 -1
- package/lib/assets/visual.js +13 -13
- package/lib/author-expression.js +7 -7
- package/lib/authoring-guide.js +3 -17
- package/lib/build-info.js +1 -1
- package/lib/canvas-design.js +2 -2
- package/lib/canvas-export.js +3 -3
- package/lib/canvas-system.js +1 -1
- package/lib/catalog.js +1 -2
- package/lib/delivery.js +1 -1
- package/lib/export-runtime-bundle.js +1 -1
- package/lib/fence-feedback.js +8 -2
- package/lib/freeform.js +4 -10
- package/lib/inspection.js +19 -6
- package/lib/motion-craft.js +31 -0
- package/lib/motion-design-skill.js +23 -0
- package/lib/motion-library.js +5 -4
- package/lib/normalize-authoring.js +9 -0
- package/lib/project-archive.js +16 -0
- package/lib/prompt-contract.js +22 -0
- package/lib/protocol.js +3 -3
- package/lib/refinement.js +36 -3
- package/lib/sandbox.js +4 -1
- package/lib/scene-entry.js +41 -0
- package/lib/style-system.js +2 -2
- package/lib/text-guide.js +9 -13
- package/lib/third-party/taste-skill-NOTICE.md +10 -0
- package/lib/timeline.js +29 -0
- package/lib/tool-json.js +5 -0
- package/lib/tool-schema.js +7 -7
- package/lib/ui-intent.js +4 -15
- package/lib/ui-skill.js +19 -26
- package/lib/video-tools.js +21 -0
- package/lib/video.js +296 -0
- package/lib/visual-audit.js +15 -4
- package/lib/visual-styles.js +1 -1
- package/lib/voice.js +72 -0
- package/package.json +17 -9
- package/skills/intelligent-ui/SKILL.md +14 -107
- package/skills/motion-design/ADAPTER.md +35 -0
- package/skills/motion-design/LICENSE +201 -0
- package/skills/motion-design/NOTICE.md +9 -0
- package/skills/motion-design/SKILL.md +388 -0
- package/skills/motion-design/SOURCES.md +16 -0
- package/skills/motion-design/upstream.json +8 -0
package/index.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {sceneDocument,SCENE_PARAMETERS,sceneReference} from './lib/scene-entry.js';
|
|
2
|
+
import {registerVideoTools} from './lib/video-tools.js';
|
|
3
|
+
import {VIDEO_GUIDE,PROMO_GUIDE} from './lib/motion-craft.js';
|
|
4
|
+
import {loadMotionDesignSkill,MOTION_DESIGN_REFERENCE} from './lib/motion-design-skill.js';
|
|
5
|
+
import {normalizeNodeEdits} from './lib/refinement.js';
|
|
6
|
+
import {TEXT_GUIDE} from './lib/text-guide.js';
|
|
7
|
+
import {CANVAS_CONTRACT,TOOL_DIRECTORY} from './lib/prompt-contract.js';
|
|
1
8
|
import {mechanismDocument} from './lib/mechanism-entry.js';
|
|
2
9
|
import {mechanismCatalog} from './lib/mechanism-catalog.js';
|
|
3
10
|
import {motionCatalog} from './lib/motion-library.js';
|
|
@@ -7,25 +14,26 @@ import { validateDocument, fallbackText } from './lib/protocol.js';
|
|
|
7
14
|
import { UiStore, stateRoute, documentRoute, historyRoute } from './lib/store.js';
|
|
8
15
|
import { evaluate } from './lib/protocol.js';
|
|
9
16
|
import { componentCatalog } from './lib/components.js';
|
|
17
|
+
import {CANVAS_SYSTEM_GUIDE} from './lib/canvas-system.js';
|
|
10
18
|
import { CANVAS_DESIGN_GUIDE } from './lib/canvas-design.js';
|
|
11
19
|
import { architectureExample, scatterExample } from './lib/visual-examples.js';
|
|
12
20
|
import { BUILD_INFO } from './lib/build-info.js';
|
|
13
21
|
import { UI_SKILL_SECTIONS, promptSections } from './lib/ui-skill.js';
|
|
14
|
-
import {DEFAULT_VISUAL_STYLE,VISUAL_STYLE_IDS} from './lib/visual-styles.js';
|
|
22
|
+
import {stylePrompt,styleExamples,DEFAULT_VISUAL_STYLE,VISUAL_STYLE_IDS} from './lib/visual-styles.js';
|
|
15
23
|
import { canvasDocument } from './lib/freeform.js';
|
|
16
24
|
import z from '@deepseek-ai/schemastery';
|
|
17
25
|
import { toolJson } from './lib/tool-json.js';
|
|
18
26
|
import { DOCUMENT_PARAMETER,TEXT_BLOCKS_PARAMETER } from './lib/tool-schema.js';
|
|
19
27
|
import {textDocument} from './lib/text-document.js';
|
|
20
28
|
import {TEXT_PRESETS} from './lib/typography.js';
|
|
21
|
-
import { inspectRecord } from './lib/inspection.js';
|
|
29
|
+
import { inspectRecord,normalizeNodeIds } from './lib/inspection.js';
|
|
22
30
|
import {QUICK_EXAMPLES,QUICK_GUIDE} from './lib/quick-examples.js';
|
|
23
31
|
import { PROTOCOL_GUIDE, calculatorExample, comparisonExample, budgetExample, curveExample, sceneExamples, bicycleExample, oscillatorExample } from './lib/catalog.js';
|
|
24
32
|
import {VISUAL_GUIDE,VISUAL_EXAMPLES,visualCatalog} from './lib/visual.js';
|
|
25
33
|
import {registerVisualAssets} from './lib/visual-assets.js';
|
|
26
34
|
import {diagnosticsRoute} from './lib/diagnostics-route.js';
|
|
27
35
|
import {fenceRoute} from './lib/fence-route.js';
|
|
28
|
-
import {sceneCatalog
|
|
36
|
+
import {sceneCatalog} from './lib/scene-library.js';
|
|
29
37
|
import {registerFenceFeedback} from './lib/fence-feedback.js';
|
|
30
38
|
import {diagnoseDelivery,deliveryDiagnostics} from './lib/delivery.js';
|
|
31
39
|
|
|
@@ -38,25 +46,26 @@ function defineRenderTool(options) {
|
|
|
38
46
|
// string branch that encourages models to manually escape whole documents.
|
|
39
47
|
// Canonicalize adapter quirks before native schema checks, so a lossless
|
|
40
48
|
// items:{item:[...]} wrapper receives the same treatment as stored/replayed UI.
|
|
41
|
-
const normalized=args&&Object.hasOwn(args,'document')?{...args,document:validateDocument(toolJson(args.document,'document'))}:args&&Object.hasOwn(args,'blocks')?{...args,blocks:textDocument({...args,blocks:toolJson(args.blocks,'blocks')}).nodes}:args;
|
|
49
|
+
const normalized=args&&Object.hasOwn(args,'document')?{...args,document:validateDocument(toolJson(args.document,'document'))}:args&&Object.hasOwn(args,'blocks')?{...args,blocks:textDocument({...args,blocks:toolJson(args.blocks,'blocks')}).nodes}:args&&Object.hasOwn(args,'changes')?{...args,changes:normalizeNodeEdits(args.changes)}:args&&Object.hasOwn(args,'nodeIds')?{...args,nodeIds:normalizeNodeIds(args.nodeIds)}:args;
|
|
42
50
|
return execute(normalized,exec);
|
|
43
51
|
}};
|
|
44
52
|
}
|
|
45
53
|
export const Config=z.object({autoRepair:z.boolean().default(true).description('自动反馈无法交付的 UI 围栏、渲染失败及仅思考没有正文或工具的空交付,最多两次去重提醒;不限制模型思考。'),visualStyle:z.union(VISUAL_STYLE_IDS).default(DEFAULT_VISUAL_STYLE).description('引导模式的视觉风格;同步原生组件外观、风格提示词与案例,自由模式不应用。'),defaultPreset:z.union(TEXT_PRESETS).default('reading').description('兼容旧配置的保留字段,已停用;排版由模型按内容选择。'),designMode:z.union(['guided','free']).default('guided').description('guided:设计技能与示例引导;free:只注入画布接口与交互约束,由模型自主设计。'),displayMode:z.union(['tail','inline','sidebar']).default('inline').description('兼容旧配置的保留字段,已停用;统一使用正文标记,侧栏随时可打开。'),showDetails:z.boolean().default(false).description('显示参数状态、原始说明、视觉诊断和版本历史。默认关闭,保持界面简洁。')}).volatile();
|
|
46
54
|
export function apply(ctx,config={}) {
|
|
47
55
|
const store = new UiStore(dshHomePath('plugins', 'dsh-generative-ui'));
|
|
56
|
+
|
|
48
57
|
const settings=()=>typeof config.get==='function'?config.get():config;
|
|
49
58
|
const feedback=registerFenceFeedback(ctx,()=>settings().autoRepair!==false);
|
|
50
59
|
const placement=value=>`\nPlace this exact fenced marker in your answer at the intended UI position:\n\`\`\`dsh-ui\n${value.documentId}\n\`\`\``;
|
|
51
60
|
ctx.effect(()=>ctx.tools.register(defineRenderTool({
|
|
52
|
-
name:'render_text',description:
|
|
61
|
+
name:'render_text',description:"Format native text, comparisons, steps, copyable text/code and link buttons without HTML. blocks is a direct array of strings/native nodes with optional IDs. State/formulas require render_ui; custom graphics require render_canvas. Several calls create independent documents.",
|
|
53
62
|
parameters:{title:{type:'string'},preset:{type:'string',enum:TEXT_PRESETS},accent:{type:'string',enum:['blue','teal','violet','amber','rose']},blocks:TEXT_BLOCKS_PARAMETER},
|
|
54
63
|
output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:v.document.fallback+`\nUI documentId=${v.documentId}; documentRevision=${v.documentRevision??0}.`+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},
|
|
55
64
|
async execute(args,exec){exec.signal.throwIfAborted();for(const key of Object.keys(args))if(!['title','preset','accent','blocks'].includes(key))throw Error(`DSH UI: unknown render_text argument ${key}; put all content/styling inside blocks or children`);const document=textDocument({...args,blocks:toolJson(args.blocks,'blocks'),preset:args.preset??'reading'});fallbackText(document);const record=await store.create(document,{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}
|
|
56
65
|
})));
|
|
57
66
|
ctx.effect(() => ctx.tools.register(defineRenderTool({
|
|
58
67
|
name: 'render_ui',
|
|
59
|
-
description:
|
|
68
|
+
description: "Render one complete native v1 {version:1,title,fallback,nodes,state?,derived?} OR extended {title,items:[components]} document. Do not mix root languages. Use for useful static/interactive explanations; native formulas stay local. Direct call only. ui_catalog supplies optional fields/examples.",
|
|
60
69
|
parameters: { document: DOCUMENT_PARAMETER },
|
|
61
70
|
output: {
|
|
62
71
|
schema: { type: 'json' },
|
|
@@ -71,49 +80,63 @@ export function apply(ctx,config={}) {
|
|
|
71
80
|
}
|
|
72
81
|
})));
|
|
73
82
|
ctx.effect(()=>ctx.tools.register(defineTool({
|
|
74
|
-
name:'render_canvas',description:
|
|
83
|
+
name:'render_canvas',description:"Render custom HTML/SVG/CSS/JS in an isolated canvas, with optional persisted state. Separate html/css/script fields; no external resources or host APIs. Use the injected canvas contract; libraries:[\"mechanism\"] enables the optional local helper.",
|
|
75
84
|
parameters:{title:{type:'string',required:true},fallback:{type:'string',required:true},state:{type:'json'},data:{type:'json'},derived:{type:'json'},libraries:{type:'array',items:{type:'string',enum:['mechanism']}},height:{type:'number'},css:{type:'string',description:'Canvas CSS; use an empty string when no custom styles are needed. Styled static previews appear progressively; interaction activates after the assistant turn ends.'},html:{type:'string',required:true},script:{type:'string'}},
|
|
76
85
|
output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:fallbackText(v.document)+`\nUI documentId=${v.documentId}; documentRevision=${v.documentRevision??0}; canvas nodeId=canvas.`+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},
|
|
77
86
|
async execute(args,exec){exec.signal.throwIfAborted();const record=await store.create(canvasDocument(args),{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}
|
|
78
87
|
})));
|
|
88
|
+
ctx.effect(()=>ctx.tools.register(defineTool({name:'render_scene',description:'Deliver a complete flow/comparison/allocation/budget UI from short task data; Host creates nodes, controls and formulas. No source or catalog needed. values/items must be complete; never invent prices. Custom UI remains render_ui/render_canvas.',parameters:SCENE_PARAMETERS,output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:fallbackText(v.document)+'\nUI documentId='+v.documentId+'; documentRevision='+v.documentRevision+'. To revise this saved scene, use inspect_ui then patch_ui/update_ui with this documentId; calling render_scene again creates an extra UI.'+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},async execute(args,exec){exec.signal.throwIfAborted();const parsed={...args};for(const key of['items','values'])if(parsed[key]!==undefined)parsed[key]=toolJson(parsed[key],key);const record=await store.create(sceneDocument(parsed),{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}})));
|
|
79
89
|
ctx.effect(()=>ctx.tools.register(defineTool({
|
|
80
|
-
name:'render_mechanism',description:
|
|
90
|
+
name:'render_mechanism',description:"Create an adjustable assembly/gears/crank diagram from parameters, no source or catalog needed. Gear driver16 teeth; crank rod70. Educational geometry/kinematics. For other structures use render_canvas libraries:[\"mechanism\"] and ui_catalog topic=mechanism.",
|
|
81
91
|
parameters:{scene:{type:'string',required:true,enum:['assembly','gears','crank']},title:{type:'string'},rpm:{type:'number',description:'gears/crank: 0..90, default20'},teeth:{type:'number',description:'gears only: driven integer16..48, default32'},radius:{type:'number',description:'crank only: integer10..28, default20'},running:{type:'boolean',description:'gears/crank: defaultfalse'},angle:{type:'number',description:'gears/crank: integer0..360 degrees, default0'},explode:{type:'number',description:'0..1 in steps0.01; assembly default0.45, others0'}},
|
|
82
92
|
output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:fallbackText(v.document)+'\nUI documentId='+v.documentId+'; documentRevision='+v.documentRevision+'.'+placement(v)}],presentationMeta:(_a,v)=>({dshGenerativeUi:v})},
|
|
83
93
|
async execute(args,exec){exec.signal.throwIfAborted();const record=await store.create(mechanismDocument(args),{sessionId:exec.agent?.id??'unscoped',callId:exec.callId});exec.signal.throwIfAborted();return record;}
|
|
84
94
|
})));
|
|
85
95
|
ctx.effect(() => ctx.tools.register(defineTool({
|
|
86
|
-
name: 'ui_catalog', description:
|
|
87
|
-
parameters: { topic: { type: 'string', enum: ['overview',
|
|
96
|
+
name: 'ui_catalog', description: "Read one optional reference topic or scene. text=native typography; native=v1 fields/formulas; visual=extended components; canvas=API/construction/examples; style=selected guided style/examples; templates/motion/mechanism=targeted recipes. overview/quick/data/scenes/all remain available; avoid all unless needed.",
|
|
97
|
+
parameters: { topic: { type: 'string', enum: ['overview','quick','text','native','style','visual','motion','video','mechanism','templates','canvas','data','scenes','all'], description:'Optional topic; default overview.' },scene:{type:'string',description:'Scene for canvas/templates/motion/mechanism, or explicit style ID for style. Omit to get summaries/current guided style.'} }, output: { schema: { type: 'json' }, render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }] },
|
|
88
98
|
isConcurrencySafe: () => true,
|
|
89
99
|
async execute({ topic = 'overview',scene } = {}) {
|
|
100
|
+
if((topic==='motion'||topic==='video')&&scene==='motion-design')return {topic,designSkill:await loadMotionDesignSkill()};
|
|
101
|
+
if(topic==='video')return{topic,guide:VIDEO_GUIDE,designReference:MOTION_DESIGN_REFERENCE,...(scene==='promo'?{production:PROMO_GUIDE,designSkill:await loadMotionDesignSkill()}:{}),capabilities:await video.capabilities(),workflow:'Author render_canvas with exactly one DSHUI.timeline({id:"main",duration,draw}) and #stage. Then render_video({documentId,duration,...}). For input videos inspect_video then view sampled frames, process_video clips/audio/captions. No unrequested video export. Output URLs are authenticated same-host downloads; HTML sources are attachments, never executed in the Host origin.'};
|
|
102
|
+
if(topic==='text')return {topic,guide:TEXT_GUIDE};
|
|
103
|
+
if(topic==='native')return {topic,protocol:PROTOCOL_GUIDE,components:componentCatalog(),example:calculatorExample};
|
|
104
|
+
if(topic==='style'){if(settings().designMode==='free'&&!scene)return{topic,mode:'free',note:'No style is selected in free mode. An explicit scene equal to a style ID requests reference guidance only.',styles:VISUAL_STYLE_IDS};const id=scene??settings().visualStyle??DEFAULT_VISUAL_STYLE;return{topic,style:id,guide:stylePrompt(id),examples:styleExamples(id)}}
|
|
105
|
+
if(topic==='canvas'){
|
|
106
|
+
const docs={bicycle:bicycleExample,oscillator:oscillatorExample,architecture:architectureExample,scatter:scatterExample};
|
|
107
|
+
if(scene&&!Object.hasOwn(docs,scene))throw Error('Unknown canvas scene; use bicycle, oscillator, architecture or scatter');
|
|
108
|
+
return {topic,interface:CANVAS_CONTRACT,construction:CANVAS_SYSTEM_GUIDE,...(settings().designMode==='free'?{}:{design:CANVAS_DESIGN_GUIDE}),examples:scene?[docs[scene]]:Object.entries(docs).map(([scene,d])=>({scene,title:d.title,fallback:d.fallback})),usage:'Add scene to retrieve one complete example, not all four sources.'};
|
|
109
|
+
}
|
|
110
|
+
if(topic==='overview')return{topic,guide:TOOL_DIRECTORY,examples:QUICK_EXAMPLES.slice(0,2)};
|
|
111
|
+
if(topic==='quick')return{...sceneReference(),design:QUICK_GUIDE,fullDocuments:QUICK_EXAMPLES};
|
|
90
112
|
if(topic==='templates')return sceneCatalog(scene);
|
|
91
113
|
if(topic==='mechanism')return mechanismCatalog(scene);
|
|
92
|
-
if(topic==='motion')return motionCatalog(scene);
|
|
114
|
+
if(topic==='motion')return {...motionCatalog(scene),...(!scene?{designReferences:[MOTION_DESIGN_REFERENCE]}:{})};
|
|
93
115
|
const groups = { overview: [calculatorExample, oscillatorExample], canvas: [bicycleExample, oscillatorExample, architectureExample, scatterExample], data: [calculatorExample, comparisonExample, budgetExample, curveExample, scatterExample], scenes: sceneExamples, all: [calculatorExample, comparisonExample, budgetExample, curveExample, ...sceneExamples, bicycleExample, oscillatorExample, architectureExample, scatterExample] };
|
|
94
116
|
groups.quick=QUICK_EXAMPLES;groups.overview=QUICK_EXAMPLES.slice(0,2);
|
|
95
117
|
groups.visual=VISUAL_EXAMPLES;
|
|
96
|
-
if (!Object.hasOwn(groups, topic)) throw new Error('Unknown ui_catalog topic; use templates, overview, quick, visual, canvas, data, scenes or all');
|
|
118
|
+
if (!Object.hasOwn(groups, topic)) throw new Error('Unknown ui_catalog topic; use text, native, style, templates, overview, quick, visual, canvas, data, scenes, motion, mechanism or all');
|
|
97
119
|
if(topic==='visual')return{build:BUILD_INFO,topic,protocol:VISUAL_GUIDE,components:visualCatalog(),examples:VISUAL_EXAMPLES};
|
|
98
120
|
return { build: BUILD_INFO, topic, protocol: PROTOCOL_GUIDE, components: componentCatalog(), design: topic === 'quick' ? QUICK_GUIDE : topic === 'canvas' || topic === 'all' ? CANVAS_DESIGN_GUIDE : 'Choose composition by the question: editorial reading, technical relationships, analytical data, exploratory objects, aligned comparisons or ordered instruction. Keep theme, accessible labels and readable Chinese. Use topic=canvas for the full visual design guide.', examples: groups[topic] };
|
|
99
121
|
}
|
|
100
122
|
})));
|
|
101
123
|
ctx.effect(() => ctx.connection.fetch.register({ path: '/api/plugins/dsh-generative-ui/state', methods: ['GET', 'POST'], requestBody: 'buffered', fetch: stateRoute(store) }));
|
|
124
|
+
const video=registerVideoTools(ctx,store);
|
|
102
125
|
ctx.effect(() => ctx.connection.fetch.register({ path: '/api/plugins/dsh-generative-ui/document', methods: ['GET', 'POST'], requestBody: 'buffered', fetch: documentRoute(store) }));
|
|
103
126
|
ctx.effect(() => ctx.connection.fetch.register({ path: '/api/plugins/dsh-generative-ui/history', methods: ['GET', 'POST'], requestBody: 'buffered', fetch: historyRoute(store) }));
|
|
104
127
|
registerVisualAssets(ctx);
|
|
105
128
|
ctx.effect(()=>ctx.connection.fetch.register({path:'/api/plugins/dsh-generative-ui/diagnostics',methods:['GET'],requestBody:'buffered',fetch:diagnosticsRoute(feedback)}));
|
|
106
129
|
ctx.effect(()=>ctx.connection.fetch.register({path:'/api/plugins/dsh-generative-ui/fence',methods:['POST'],requestBody:'buffered',fetch:fenceRoute(store)}));
|
|
107
|
-
ctx.effect(()=>ctx.tools.register(defineTool({name:'validate_ui',description:
|
|
108
|
-
ctx.effect(()=>ctx.tools.register(
|
|
109
|
-
name:'inspect_ui',description:
|
|
110
|
-
parameters:{documentId:{type:'string',required:true},detail:{type:'string',enum:['summary','nodes','full']},nodeIds:{type:'
|
|
130
|
+
ctx.effect(()=>ctx.tools.register(defineTool({name:'validate_ui',description:"Validate native or extended UI without saving/displaying. valid with complete=false means rejected components. Returns canonical document/diagnostics; a rendering tool still delivers the UI.",parameters:{document:{type:'json',required:true}},output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:JSON.stringify(v)}]},isConcurrencySafe:()=>true,async execute({document}){try{const report=diagnoseDelivery(toolJson(document,'document'));return {...report,...(report.valid?{fallback:fallbackText(report.document)}:{error:report.diagnostics[0].message})}}catch(e){return{valid:false,complete:false,error:e.message}}}})));
|
|
131
|
+
ctx.effect(()=>ctx.tools.register(defineRenderTool({
|
|
132
|
+
name:'inspect_ui',description:"Read current revision/state/derived and heuristic observations. Summary includes node paths/positions/editable fields. query finds text/labels/types (max200 chars); detail=nodes with query OR nodeIds reads matching source. Full only when needed. Missing observations mean unobserved; do not poll. Inspect before editing.",
|
|
133
|
+
parameters:{documentId:{type:'string',required:true},detail:{type:'string',enum:['summary','nodes','full']},query:{type:'string',description:'Find by text/label/title/type; mutually exclusive with nodeIds. Up to16 matches; blank means all.'},nodeIds:{type:'array',items:{type:'string'},description:'For nodes detail: direct array of up to16 existing node IDs, e.g. ["canvas"], not HTML DOM IDs.'}},
|
|
111
134
|
output:{schema:{type:'json'},render:(_args,value)=>[{type:'text',text:JSON.stringify(value)}]},isConcurrencySafe:()=>true,
|
|
112
|
-
async execute({documentId,detail='summary',nodeIds=[]},exec){const record=await store.owned(documentId,exec.agent?.id);const saved=await store.readState(documentId,record.sessionId);return inspectRecord(record,saved.state,evaluate(record.document,saved.state).derived,await store.audits(documentId),{detail,nodeIds:toolJson(nodeIds,'nodeIds')});}
|
|
135
|
+
async execute({documentId,detail='summary',nodeIds=[],query=''},exec){const record=await store.owned(documentId,exec.agent?.id);const saved=await store.readState(documentId,record.sessionId);return inspectRecord(record,saved.state,evaluate(record.document,saved.state).derived,await store.audits(documentId),{detail,nodeIds:toolJson(nodeIds,'nodeIds'),query});}
|
|
113
136
|
})));
|
|
114
|
-
ctx.effect(()=>ctx.tools.register(
|
|
115
|
-
ctx.effect(()=>ctx.tools.register(defineTool({name:'update_ui',description:
|
|
116
|
-
for
|
|
137
|
+
ctx.effect(()=>ctx.tools.register(defineRenderTool({name:'patch_ui',description:"Edit existing scalar/source properties using the inspected documentRevision. changes:[{id,props}]. IDs/structure/bindings/actions stay unchanged; canvas source replacement restarts that frame. Saved parameters persist. Use update_ui for structure changes.",parameters:{documentId:{type:'string',required:true},documentRevision:{type:'number',required:true},changes:{type:'array',required:true,description:'Direct array [{id,props}]; combine changed properties for one node in props.',items:{type:'object',additionalProperties:false,properties:{id:{type:'string',required:true},props:{type:'json',required:true}}}}},output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:`Updated ${v.document.title}; documentId=${v.documentId}; documentRevision=${v.documentRevision}. Saved parameters retained.`}],presentationMeta:(_a,v)=>({dshGenerativeUiPatch:v})},async execute({documentId,documentRevision,changes},exec){exec.signal.throwIfAborted();return store.refine(documentId,exec.agent?.id,documentRevision,toolJson(changes,'changes'));}})));
|
|
138
|
+
ctx.effect(()=>ctx.tools.register(defineTool({name:'update_ui',description:"Append/replace existing content at the inspected revision, keeping documentId and compatible state. targetId selects a node; an extended fragment appends to the sole visual when unambiguous. Supply a stable operationId; reuse only for an identical retry (latest64 replay IDs). Preserve state/derived definitions; new inputs get defaults.",parameters:{documentId:{type:'string',required:true},documentRevision:{type:'number',required:true},operationId:{type:'string',required:true},mode:{type:'string',enum:['append','replace'],required:true},targetId:{type:'string'},document:{type:'json',required:true}},output:{schema:{type:'json'},render:(_a,v)=>[{type:'text',text:'Updated existing UI '+v.documentId+'; documentRevision='+v.documentRevision+'. Keep its existing inline marker; do not duplicate it.'}],presentationMeta:(_a,v)=>({dshGenerativeUiPatch:v})},async execute({documentId,documentRevision,operationId,mode,targetId,document},exec){exec.signal.throwIfAborted();return store.update(documentId,exec.agent?.id,documentRevision,operationId,{mode,...(targetId?{targetId}:{}),document:toolJson(document,'document')})}})));
|
|
139
|
+
for(const[i,section]of UI_SKILL_SECTIONS.entries())ctx.effect(()=>ctx.systemPrompt.section({...section,text:()=>promptSections(settings().designMode??'guided',settings().visualStyle??DEFAULT_VISUAL_STYLE)[i].text}));
|
|
117
140
|
}
|
|
118
141
|
|
|
119
142
|
|