dsh-motion-ui 0.5.3 → 0.5.4
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 +9 -0
- package/README.md +6 -0
- package/VERIFICATION.md +18 -0
- package/client.js +386 -249
- package/index.js +16 -3
- package/lib/author-expression.js +3 -2
- package/lib/authoring-guide.js +9 -0
- package/lib/build-info.js +1 -1
- package/lib/canvas-preview.js +1 -1
- package/lib/canvas-system.js +3 -2
- package/lib/catalog.js +5 -4
- package/lib/components.js +2 -2
- package/lib/export-runtime-bundle.js +1 -1
- package/lib/freeform.js +3 -2
- package/lib/identifiers.js +4 -0
- package/lib/protocol.js +20 -11
- package/lib/stream.js +2 -1
- package/lib/tool-json.js +21 -2
- package/lib/tool-schema.js +29 -0
- package/package.json +1 -1
package/lib/stream.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LIMITS, validateDocument } from './protocol.js';
|
|
2
|
+
import { toolJson } from './tool-json.js';
|
|
2
3
|
|
|
3
4
|
// Parse complete JSON tokens only. Never finish a string, number or model expression.
|
|
4
5
|
// Partial containers retain completed members, but only the document wrapper and
|
|
@@ -62,7 +63,7 @@ export function previewDocument(raw) {
|
|
|
62
63
|
try {
|
|
63
64
|
const root=parseToolArguments(raw);if(!root)return null;
|
|
64
65
|
const document = root.members?.get('document');
|
|
65
|
-
if(document?.complete&&typeof document.value==='string'&&root.members.size===1)return validateDocument(
|
|
66
|
+
if(document?.complete&&typeof document.value==='string'&&root.members.size===1)return validateDocument(toolJson(document.value,'document'));
|
|
66
67
|
if (!document?.members) return null;
|
|
67
68
|
if ([...root.members.keys()].some(k => k !== 'document')) return null;
|
|
68
69
|
const doc = { ...document.value }, nodes = document.members.get('nodes');
|
package/lib/tool-json.js
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
// DSH adapters may represent `type: json` fields as JSON strings.
|
|
2
2
|
// Decode only the tool field, once; strict protocol validation still applies.
|
|
3
|
+
function clean(source) {
|
|
4
|
+
let input=source.trim().replace(/^\uFEFF/, '');
|
|
5
|
+
const fence=input.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/i);
|
|
6
|
+
if(fence)input=fence[1];
|
|
7
|
+
let output='',quoted=false,escaped=false;
|
|
8
|
+
for(let i=0;i<input.length;i++){
|
|
9
|
+
const c=input[i];
|
|
10
|
+
if(quoted){output+=c;if(escaped)escaped=false;else if(c==='\\')escaped=true;else if(c==='"')quoted=false;continue;}
|
|
11
|
+
if(c==='"')quoted=true;
|
|
12
|
+
if(c===',' && /^\s*[}\]]/.test(input.slice(i+1)))continue;
|
|
13
|
+
output+=c;
|
|
14
|
+
}
|
|
15
|
+
return output;
|
|
16
|
+
}
|
|
3
17
|
export function toolJson(value, field, maxBytes=131072){
|
|
4
18
|
if(typeof value!=='string')return value;
|
|
5
|
-
if(
|
|
6
|
-
|
|
19
|
+
if(new TextEncoder().encode(value).length>maxBytes)throw new Error(`DSH UI: ${field} JSON exceeds size limit`);
|
|
20
|
+
const source=clean(value);
|
|
21
|
+
try{return JSON.parse(source)}catch(error){
|
|
22
|
+
const position=error.message.match(/position (\d+)/)?.[1];
|
|
23
|
+
const location=position===undefined?'':` at line ${source.slice(0,Number(position)).split('\n').length}, column ${Number(position)-source.lastIndexOf('\n',Number(position)-1)}`;
|
|
24
|
+
throw new Error(`DSH UI: ${field} must contain valid JSON${location}. Pass an object directly, not a manually escaped JSON string. Do not use single-quoted keys or raw newlines inside strings. For HTML/SVG use render_canvas with separate html/css/script fields. No partial document was saved.`);
|
|
25
|
+
}
|
|
7
26
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {COMPONENTS} from './components.js';
|
|
2
|
+
// Expose the document skeleton to native function calling, not just prose.
|
|
3
|
+
// Per-component and expression checks remain in the shared runtime validator.
|
|
4
|
+
const dictionary=description=>({type:'object',additionalProperties:true,description});
|
|
5
|
+
export const DOCUMENT_PARAMETER={
|
|
6
|
+
required:true,
|
|
7
|
+
description:'Pass the document as an OBJECT. Do not manually escape/serialize it. For HTML/SVG source prefer render_canvas.',
|
|
8
|
+
type:'object',additionalProperties:false,
|
|
9
|
+
properties:{
|
|
10
|
+
version:{type:'number',const:1,required:true},
|
|
11
|
+
title:{type:'string',required:true},
|
|
12
|
+
fallback:{type:'string',required:true,description:'Useful plain-text explanation if the UI is unavailable.'},
|
|
13
|
+
nodes:{type:'array',required:true,items:{type:'object',additionalProperties:true,properties:{
|
|
14
|
+
id:{type:'string',required:true,description:'Unique letter/underscore identifier; Chinese supported, max64.'},
|
|
15
|
+
type:{type:'string',required:true,enum:Object.keys(COMPONENTS)},
|
|
16
|
+
label:{type:'string'},title:{type:'string'},
|
|
17
|
+
text:{type:'json',description:'Literal scalar or {ref}/{expr}.'},
|
|
18
|
+
value:{type:'json',description:'metric: number or display string/boolean, or {ref}/{expr}. progress: numeric.'},
|
|
19
|
+
rows:{type:'json',description:'table/chart: inline array of objects, {ref:"data.rows"}/{ref:"derived.rows"}, or scoped reference string.'},
|
|
20
|
+
columns:{type:'array',items:{type:'object',additionalProperties:false,properties:{key:{type:'string',required:true},label:{type:'string',required:true},unit:{type:'string'}}}},
|
|
21
|
+
bind:{type:'string',description:'Controls bind state.key.'},children:{type:'array',items:{type:'json'}}
|
|
22
|
+
}}},
|
|
23
|
+
state:dictionary('key -> {type:number/string/boolean/json,default,...}. Numeric state needs min,max,step. json is bounded array/object state for canvas controls.'),
|
|
24
|
+
data:dictionary('Static data; Chinese identifier keys supported. Omit if rows are inline.'),
|
|
25
|
+
derived:dictionary('Local expressions or maps. Omit when unused.'),
|
|
26
|
+
actions:dictionary('Declared agent.followup actions. Omit when unused.'),
|
|
27
|
+
presentation:dictionary('Optional layout/accent/density from registered tokens.')
|
|
28
|
+
}
|
|
29
|
+
};
|
package/package.json
CHANGED