beeos-claw 0.6.63-cloud.12 → 0.6.63-cloud.13
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/dist/canvas/tools.js +1 -1
- package/package.json +2 -2
package/dist/canvas/tools.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{extractBeeosConversationIdFromSessionKey}from"../runtime/openclaw-session-key-resolution.js";const A2UI_TYPE_NAMES=new Set(["Text","Image","Icon","Video","AudioPlayer","Row","Column","List","Card","Tabs","Divider","Modal","Button","CheckBox","TextField","DateTimeInput","MultipleChoice","Slider","Chart","WebEmbed","FilePreview","MapView"]);function normalizeComponents(e){return e.map(e=>{if(!e||"object"!=typeof e)return e;const t=e;if(t.component&&"object"==typeof t.component)return t;for(const e of Object.keys(t))if(A2UI_TYPE_NAMES.has(e)&&"object"==typeof t[e])return{id:t.id,component:{[e]:t[e]}};return t})}export const RENDER_UI_TOOL_NAME="render_ui";export const CLOSE_UI_TOOL_NAME="close_ui";export const RENDER_UI_TOOL_DESCRIPTION="Render A2UI v0.8 components to the Canvas panel. Prefer this over the built-in canvas tool.";export const RENDER_UI_TOOL_SCHEMA={type:"object",required:["id","root","components"],properties:{id:{type:"string",description:"Surface id. Reuse to update."},root:{type:"string",description:"Root component id."},components:{type:"array",description:"Flat ComponentInstance list. Each item has id plus one component type.",items:{type:"object",required:["id"],properties:{id:{type:"string",description:"Component id."},component:{type:"object",description:"One type key: Text, Image, Icon, Video, AudioPlayer, Row, Column, List, Card, Tabs, Divider, Modal, Button, CheckBox, TextField, DateTimeInput, MultipleChoice, Slider, Chart."}}}},data:{type:"object",description:"Optional binding model, path keys like /name."}}};export const CLOSE_UI_TOOL_DESCRIPTION="Close and remove a UI surface that was previously rendered.";export const CLOSE_UI_TOOL_SCHEMA={type:"object",required:["id"],properties:{id:{type:"string",description:"The UI identifier to close"}}};const SESSION_READY_POLL_ATTEMPTS=3,SESSION_READY_POLL_INTERVAL_MS=400,delay=e=>new Promise(t=>setTimeout(t,e));async function ensureRelayConnected(e,t,n,a){const{stateManager:o,logger:i}=e,r=a??e.getGatewaySessionKey?.(n),s=r??t,l=o.resolveCanvasForSession(s);if(l&&o.isCanvasJoined(l))return l;let c=o.getRelayClient();if(c||(c=await o.waitForRelayClient(),c))try{e.waitForAgentSync&&await e.waitForAgentSync();const a=e.getPlatformAgentId?.(n),l=r??t,d=(r?extractBeeosConversationIdFromSessionKey(r):void 0)??(r&&r!==t?t:void 0),u=await c.ensureCanvas(l,{agentId:a,linkSessionId:d});return await o.joinCanvas(u,s),i.info?.(`[canvas] Joined canvas=${u} session=${t} gatewayKey=${r??"none"} agentId=${a??"none"}`),u}catch(e){return void i.warn?.(`[canvas] Failed to join canvas relay: ${e}`)}}export function createRenderUiHandler(e){const{stateManager:t,logger:n,writeObs:a,getGatewaySessionKey:o}=e;let i=0;return async(o,r)=>{const s=r,l=s.id,c=s.root,d="panel";let u=s.components;if("string"==typeof u)try{u=JSON.parse(u)}catch{}if(!(l&&c&&Array.isArray(u)&&u.length))return{success:!1,error:"id, root, and components (array) are required"};const p=normalizeComponents(u);if(!t.validateComponentCount(p))return{success:!1,error:"Too many components (max 500)"};if(!t.checkRateLimit(l))return n.warn?.(`[canvas] Rate limited surfaceId=${l}`),a({component:"canvas",domain:"canvas",name:"canvas.rate_limited",severity:"warn",payload:{surfaceId:l}}),{success:!1,error:"Rate limited — too many updates per second"};const m=s.data;let h=e.getActiveSessionId?.(o);for(let t=0;!h&&t<3;t++)await delay(400),h=e.getActiveSessionId?.(o);if(!h&&e.waitForAgentSync){try{await e.waitForAgentSync()}catch{}h=e.getActiveSessionId?.(o)}if(!h)return n.warn?.(`[canvas] No active session for toolCallId=${o} after 3 polls, render_ui not ready`),{success:!1,retryable:!0,error:"Canvas session not ready yet (agent just connected) — retry render_ui shortly; do NOT fall back to plain text."};const y=e.getGatewaySessionKey?.(o),f=await ensureRelayConnected(e,h,o,y),g=t.has(l,f??void 0),v=Date.now(),C=t.getRelayClient();f&&C&&v-i>6e4&&C.createSnapshot(f,"Pre-agent edit").then(()=>{i=Date.now(),n.debug?.("[canvas] Pre-edit checkpoint created")}).catch(e=>n.warn?.(`[canvas] Pre-edit checkpoint failed: ${e}`)),g?t.update(l,p,f,c,m):t.create(f??`_fallback_${Date.now()}`,l,d,p,{origin:{kind:"agent"},rootComponentId:c,dataModel:m});const b=p.map(e=>e.component&&"object"==typeof e.component?Object.keys(e.component)[0]??"unknown":"unknown");a({component:"canvas",domain:"canvas",name:g?"canvas.update_sent":"canvas.surface_created",severity:"info",payload:{surfaceId:l,presentation:d,componentCount:p.length,componentTypes:b}}),n.debug?.(`[canvas] ${g?"Updated":"Created"} surface=${l} components=${p.length}`);const w={success:!0,surfaceId:l,presentation:d,isUpdate:g,activeSurfaces:f?t.getAllActive(f).map(e=>e.surfaceId):[l]};return m&&(w.dataModel=m),w}}export function createCloseUiHandler(e){const{stateManager:t,logger:n,writeObs:a}=e;return async(o,i)=>{const r=i.id;if(!r)return{success:!1,error:"id is required"};const s=t.get(r),l=s?Date.now()-s.createdAt:0,c=e.getGatewaySessionKey?.(o),d=c?t.resolveCanvasForSession(c):void 0;return t.delete(r,d),a({component:"canvas",domain:"canvas",name:"canvas.surface_closed",severity:"info",payload:{surfaceId:r,lifetime_ms:l}}),n.debug?.(`[canvas] Closed surface=${r}`),{success:!0,surfaceId:r,message:"UI closed"}}}export const CANVAS_PRESENTATION_GATE="## BeeOS Canvas presentation gate\n\nCanvas presentation is available in the background for this BeeOS conversation. The Canvas resource tab does not need to be open and no Web subscriber is required before a Canvas tool is called. Describe successful rendering as content created or updated on the canvas; do not claim that a user is currently viewing it.\n\nDo not read `beeos-canvas/SKILL.md` or any canvas skill file. Call `render_ui` directly. The A2UI schema is in this prompt and the `render_ui` tool.\n\nAfter any skill or data tool returns, apply this gate before writing the final reply:\n1. Count the related records, items, rows, time points, options, or repeated field groups in the completed result.\n2. If there are two or more, you MUST call `render_ui` before the final reply.\n3. Do not replace `render_ui` with a Markdown table, bullets, JSON, or a prose summary.\n4. If there is only one fact or value, or the answer is a prose explanation, reply in chat without `render_ui`.\n\nDomain skills control how data is obtained and interpreted. This gate controls how the completed result is presented and overrides a domain skill's default text-summary format. When `render_ui` succeeds, keep the chat reply to one short confirmation sentence.";export const CANVAS_SYSTEM_PROMPT='## Canvas UI — Google A2UI v0.8\n\n**IMPORTANT: Always use `render_ui` (not the built-in `canvas` tool) to display visual/structured content.**\n\n### How render_ui works\n\nYou output a **flat array of components** with unique IDs. Components reference each other by ID.\n\nParameters:\n- `id`: Surface ID (e.g. "sales-report"). Reuse same id to update.\n- `root`: The ID of the top-level component (usually a Column).\n- `components`: Flat array of objects. **Each object MUST have `id` and `component`**:\n `{"id": "myId", "component": {"Text": {"text": {"literalString": "Hello"}, "usageHint": "body"}}}`\n The `component` key wraps exactly ONE type key (Text, Card, Row, etc.) and its properties.\n- `data` (optional): Data model object for form two-way binding.\n\n### Rules\n- Keep chat reply to ONE short sentence when using render_ui. Do NOT repeat data shown in canvas.\n- Use render_ui for structured data, visualizations, forms, dashboards. Use plain text for explanations.\n- Canvas renders in a narrow sidebar (~400px).\n- Prefer fewer, larger components. One table is better than many small cards.\n- Use descriptive surface IDs (e.g. "sales-report", not "ui1").\n- Same `id` updates existing surface; different `id` creates new one.\n- When asked to modify existing content, reuse the original surface id from [Canvas State].\n\n### StringValue\n\nText properties use StringValue — an object with exactly one key:\n- Static text: `{"literalString": "Hello"}`\n- Data binding: `{"path": "/fieldName"}` (reads from the `data` model)\n\nShorthand: `sv("text")` means `{"literalString": "text"}` in examples below.\n\n### Component Reference\n\n**Text** — Display text with semantic sizing.\n`{Text: {text: sv("Title"), usageHint: "h2"}}`\nusageHint: "h1" | "h2" | "h3" | "h4" | "h5" | "caption" | "body"\ntext also renders Markdown (bold, italic, lists, code blocks, links).\n\n**Image** — Display an image.\n`{Image: {url: sv("https://..."), usageHint: "mediumFeature"}}`\nImage.url may be `beeos-file://<fileId>`; the renderer resolves it. Do not convert it to a signed URL.\nusageHint: "icon" | "avatar" | "smallFeature" | "mediumFeature" | "largeFeature" | "header"\nfit (optional): "contain" | "cover" | "fill" | "none" | "scale-down"\n\n**Icon** — Material icon.\n`{Icon: {name: sv("check")}}`\n\n**Video** — Embed a video.\n`{Video: {url: sv("https://youtube.com/...")}}`\n\n**AudioPlayer** — Audio playback.\n`{AudioPlayer: {url: sv("https://..."), description: sv("Episode 1")}}`\n\n**Row** — Horizontal layout. Children referenced by ID.\n`{Row: {children: {explicitList: ["child1", "child2"]}, distribution: "spaceBetween"}}`\ndistribution: "start" | "center" | "end" | "spaceBetween" | "spaceAround" | "spaceEvenly"\nalignment: "start" | "center" | "end" | "stretch"\n\n**Column** — Vertical layout. Children referenced by ID.\n`{Column: {children: {explicitList: ["child1", "child2"]}}}`\nSame distribution/alignment options as Row.\n\n**List** — Vertical or horizontal list.\n`{List: {children: {explicitList: ["item1", "item2"]}, direction: "vertical"}}`\n\n**Card** — Container with a single child.\n`{Card: {child: "contentColumnId"}}`\n\n**Tabs** — Tabbed container.\n`{Tabs: {tabItems: [{title: sv("Tab 1"), child: "panel1"}, {title: sv("Tab 2"), child: "panel2"}]}}`\n\n**Divider** — Horizontal or vertical separator.\n`{Divider: {axis: "horizontal"}}`\n\n**Modal** — Dialog with trigger.\n`{Modal: {entryPointChild: "triggerBtnId", contentChild: "dialogContentId"}}`\n\n**Button** — Clickable with action.\n`{Button: {child: "labelTextId", action: {name: "onClick", context: [{key: "id", value: {literalString: "item-1"}}]}}}`\n\n**TextField** — Text input with data binding.\n`{TextField: {label: sv("Name"), text: {path: "/name"}, type: "shortText"}}`\ntype: "shortText" | "number" | "date" | "longText"\n\n**CheckBox** — Boolean toggle.\n`{CheckBox: {label: sv("Agree"), value: {path: "/agree"}}}`\n\n**DateTimeInput** — Date/time picker.\n`{DateTimeInput: {value: {path: "/date"}, enableDate: true, enableTime: false}}`\n\n**MultipleChoice** — Selection from options.\n`{MultipleChoice: {selections: {path: "/country"}, options: [{label: sv("US"), value: "US"}, {label: sv("CN"), value: "CN"}]}}`\n\n**Slider** — Numeric range input.\n`{Slider: {value: {path: "/volume"}, minValue: 0, maxValue: 100}}`\n\n**Chart** (BeeOS extension) — Data visualization.\n`{Chart: {chartType: sv("bar"), title: sv("Sales"), labels: ["Q1","Q2","Q3"], datasets: [{label: "Revenue", data: [100,200,150]}]}}`\nchartType: bar, horizontal_bar, line, area, scatter, pie, doughnut, radar, gauge, candlestick, funnel, sparkline\ngauge uses value + max instead of labels/datasets.\ncandlestick data: [{open,high,low,close}] (full field names, NOT o/h/l/c).\n\n### Composition\n\nNest by id: Column/Row `children.explicitList`, Card `child`. Example:\n`{"id":"s1","root":"r","components":[{"id":"t","component":{"Text":{"text":{"literalString":"Hello"},"usageHint":"h2"}}},{"id":"r","component":{"Column":{"children":{"explicitList":["t"]}}}}]}`\nTables: Card > Column > Row > Text. Forms: TextField/CheckBox + Button `action.context` paths.\n\n### render_form\nUse `render_form` for schema-driven forms when a domain schema exists.\nParameters: `domain`, `operation`, `data`, `entityId`.\n\n### close_ui\nCloses a UI surface. Use when user moves to a new topic or explicitly dismisses.\n';export const CANVAS_TERM_MAPPING='[System Note] Always use `render_ui` (not the canvas tool) for visual/structured content. Each component in the array MUST be: {"id":"x","component":{"TypeName":{props}}} — the "component" wrapper key is required. render_ui uses Google A2UI v0.8 format: flat component array with id references. Components: Text (usageHint: h1-h5/caption/body), Image, Icon, Video, AudioPlayer, Row (horizontal layout, children.explicitList), Column (vertical layout, children.explicitList), List, Card (single child), Tabs (tabItems), Divider, Modal, Button (child + action), TextField, CheckBox, MultipleChoice, Slider, DateTimeInput, Chart (BeeOS extension: chartType, labels, datasets). StringValue: {"literalString":"text"} or {"path":"/binding"}. root param = top-level component ID. Tables: Card > Column > Row > Text. Forms: TextField/CheckBox/Slider + Button with action.context paths. Chart: chartType(bar/line/pie/area/scatter/doughnut/radar/funnel/gauge/candlestick/sparkline), labels, datasets:[{label,data,color?}]. Candlestick: [{open,high,low,close}]. Gauge: value+max. Keep chat brief when canvas is used. Use `close_ui` to dismiss. Reuse same id to update; new id for new content.';export const CANVAS_UPDATE_HINT="[Canvas Rule] Same id in render_ui = update existing surface. Different id = new surface. When a surface is referenced for editing, you MUST reuse its exact id and provide the full updated component tree.";const MAX_CONTEXT_SURFACES=8,MAX_CONTEXT_CHARS=500;export function buildActiveSurfacesContext(e,t){let n;if(!t)return null;if(n=e.getAllActive(t),0===n.length)return null;const a=[...n].sort((e,t)=>t.updatedAt-e.updatedAt).slice(0,8),o=n.length-a.length;let i=`[Canvas State] Active surfaces: ${a.map(t=>{const n=e.summarize(t.surfaceId);if(!n)return`"${t.surfaceId}"`;const a=n.types.slice(0,3).join(", "),o=n.title?`: "${n.title}"`:"";return`"${t.surfaceId}" (${a}${o})`}).join("; ")}.`;return o>0&&(i+=` ...and ${o} more.`),i+=" To modify existing content, reuse its id in render_ui.",i.length>500&&(i=i.slice(0,497)+"..."),i}
|
|
1
|
+
import{extractBeeosConversationIdFromSessionKey}from"../runtime/openclaw-session-key-resolution.js";const A2UI_TYPE_NAMES=new Set(["Text","Image","Icon","Video","AudioPlayer","Row","Column","List","Card","Tabs","Divider","Modal","Button","CheckBox","TextField","DateTimeInput","MultipleChoice","Slider","Chart","WebEmbed","FilePreview","MapView"]);function normalizeComponents(e){return e.map(e=>{if(!e||"object"!=typeof e)return e;const t=e;if(t.component&&"object"==typeof t.component)return t;for(const e of Object.keys(t))if(A2UI_TYPE_NAMES.has(e)&&"object"==typeof t[e])return{id:t.id,component:{[e]:t[e]}};return t})}export const RENDER_UI_TOOL_NAME="render_ui";export const CLOSE_UI_TOOL_NAME="close_ui";export const CANVAS_COMPONENT_ID_GUIDANCE="Component IDs must differ from non-reference scalar values (usageHint, literalString, and action.name). Use type-qualified IDs such as text_heading, text_body, and column_root; do not use scalar values such as body, h1, or center as IDs. A2UI v0.8 resolves strings matching component IDs as references. Keep root, child, explicitList, and template.componentId references matching their target IDs. Reuse the same component IDs when updating a surface.";export const RENDER_UI_TOOL_DESCRIPTION="Render A2UI v0.8 components to the Canvas panel. Prefer this over the built-in canvas tool.";export const RENDER_UI_TOOL_SCHEMA={type:"object",required:["id","root","components"],properties:{id:{type:"string",description:"Surface id. Reuse to update."},root:{type:"string",description:"Root component id."},components:{type:"array",description:"Flat ComponentInstance list. Each item has id plus one component type.",items:{type:"object",required:["id"],properties:{id:{type:"string",description:CANVAS_COMPONENT_ID_GUIDANCE},component:{type:"object",description:"One type key: Text, Image, Icon, Video, AudioPlayer, Row, Column, List, Card, Tabs, Divider, Modal, Button, CheckBox, TextField, DateTimeInput, MultipleChoice, Slider, Chart."}}}},data:{type:"object",description:"Optional binding model, path keys like /name."}}};export const CLOSE_UI_TOOL_DESCRIPTION="Close and remove a UI surface that was previously rendered.";export const CLOSE_UI_TOOL_SCHEMA={type:"object",required:["id"],properties:{id:{type:"string",description:"The UI identifier to close"}}};const SESSION_READY_POLL_ATTEMPTS=3,SESSION_READY_POLL_INTERVAL_MS=400,delay=e=>new Promise(t=>setTimeout(t,e));async function ensureRelayConnected(e,t,n,a){const{stateManager:o,logger:i}=e,r=a??e.getGatewaySessionKey?.(n),s=r??t,l=o.resolveCanvasForSession(s);if(l&&o.isCanvasJoined(l))return l;let c=o.getRelayClient();if(c||(c=await o.waitForRelayClient(),c))try{e.waitForAgentSync&&await e.waitForAgentSync();const a=e.getPlatformAgentId?.(n),l=r??t,d=(r?extractBeeosConversationIdFromSessionKey(r):void 0)??(r&&r!==t?t:void 0),u=await c.ensureCanvas(l,{agentId:a,linkSessionId:d});return await o.joinCanvas(u,s),i.info?.(`[canvas] Joined canvas=${u} session=${t} gatewayKey=${r??"none"} agentId=${a??"none"}`),u}catch(e){return void i.warn?.(`[canvas] Failed to join canvas relay: ${e}`)}}export function createRenderUiHandler(e){const{stateManager:t,logger:n,writeObs:a,getGatewaySessionKey:o}=e;let i=0;return async(o,r)=>{const s=r,l=s.id,c=s.root,d="panel";let u=s.components;if("string"==typeof u)try{u=JSON.parse(u)}catch{}if(!(l&&c&&Array.isArray(u)&&u.length))return{success:!1,error:"id, root, and components (array) are required"};const p=normalizeComponents(u);if(!t.validateComponentCount(p))return{success:!1,error:"Too many components (max 500)"};if(!t.checkRateLimit(l))return n.warn?.(`[canvas] Rate limited surfaceId=${l}`),a({component:"canvas",domain:"canvas",name:"canvas.rate_limited",severity:"warn",payload:{surfaceId:l}}),{success:!1,error:"Rate limited — too many updates per second"};const m=s.data;let h=e.getActiveSessionId?.(o);for(let t=0;!h&&t<3;t++)await delay(400),h=e.getActiveSessionId?.(o);if(!h&&e.waitForAgentSync){try{await e.waitForAgentSync()}catch{}h=e.getActiveSessionId?.(o)}if(!h)return n.warn?.(`[canvas] No active session for toolCallId=${o} after 3 polls, render_ui not ready`),{success:!1,retryable:!0,error:"Canvas session not ready yet (agent just connected) — retry render_ui shortly; do NOT fall back to plain text."};const y=e.getGatewaySessionKey?.(o),f=await ensureRelayConnected(e,h,o,y),g=t.has(l,f??void 0),v=Date.now(),C=t.getRelayClient();f&&C&&v-i>6e4&&C.createSnapshot(f,"Pre-agent edit").then(()=>{i=Date.now(),n.debug?.("[canvas] Pre-edit checkpoint created")}).catch(e=>n.warn?.(`[canvas] Pre-edit checkpoint failed: ${e}`)),g?t.update(l,p,f,c,m):t.create(f??`_fallback_${Date.now()}`,l,d,p,{origin:{kind:"agent"},rootComponentId:c,dataModel:m});const b=p.map(e=>e.component&&"object"==typeof e.component?Object.keys(e.component)[0]??"unknown":"unknown");a({component:"canvas",domain:"canvas",name:g?"canvas.update_sent":"canvas.surface_created",severity:"info",payload:{surfaceId:l,presentation:d,componentCount:p.length,componentTypes:b}}),n.debug?.(`[canvas] ${g?"Updated":"Created"} surface=${l} components=${p.length}`);const I={success:!0,surfaceId:l,presentation:d,isUpdate:g,activeSurfaces:f?t.getAllActive(f).map(e=>e.surfaceId):[l]};return m&&(I.dataModel=m),I}}export function createCloseUiHandler(e){const{stateManager:t,logger:n,writeObs:a}=e;return async(o,i)=>{const r=i.id;if(!r)return{success:!1,error:"id is required"};const s=t.get(r),l=s?Date.now()-s.createdAt:0,c=e.getGatewaySessionKey?.(o),d=c?t.resolveCanvasForSession(c):void 0;return t.delete(r,d),a({component:"canvas",domain:"canvas",name:"canvas.surface_closed",severity:"info",payload:{surfaceId:r,lifetime_ms:l}}),n.debug?.(`[canvas] Closed surface=${r}`),{success:!0,surfaceId:r,message:"UI closed"}}}export const CANVAS_PRESENTATION_GATE="## BeeOS Canvas presentation gate\n\nCanvas presentation is available in the background for this BeeOS conversation. The Canvas resource tab does not need to be open and no Web subscriber is required before a Canvas tool is called. Describe successful rendering as content created or updated on the canvas; do not claim that a user is currently viewing it.\n\nDo not read `beeos-canvas/SKILL.md` or any canvas skill file. Call `render_ui` directly. The A2UI schema is in this prompt and the `render_ui` tool.\n\nAfter any skill or data tool returns, apply this gate before writing the final reply:\n1. Count the related records, items, rows, time points, options, or repeated field groups in the completed result.\n2. If there are two or more, you MUST call `render_ui` before the final reply.\n3. Do not replace `render_ui` with a Markdown table, bullets, JSON, or a prose summary.\n4. If there is only one fact or value, or the answer is a prose explanation, reply in chat without `render_ui`.\n\nDomain skills control how data is obtained and interpreted. This gate controls how the completed result is presented and overrides a domain skill's default text-summary format. When `render_ui` succeeds, keep the chat reply to one short confirmation sentence.";export const CANVAS_SYSTEM_PROMPT=`## Canvas UI — Google A2UI v0.8\n\n**IMPORTANT: Always use \`render_ui\` (not the built-in \`canvas\` tool) to display visual/structured content.**\n\n### How render_ui works\n\nYou output a **flat array of components** with unique IDs. Components reference each other by ID.\n${CANVAS_COMPONENT_ID_GUIDANCE}\n\nParameters:\n- \`id\`: Surface ID (e.g. "sales-report"). Reuse same id to update.\n- \`root\`: The ID of the top-level component (usually a Column).\n- \`components\`: Flat array of objects. **Each object MUST have \`id\` and \`component\`**:\n \`{"id": "myId", "component": {"Text": {"text": {"literalString": "Hello"}, "usageHint": "body"}}}\`\n The \`component\` key wraps exactly ONE type key (Text, Card, Row, etc.) and its properties.\n- \`data\` (optional): Data model object for form two-way binding.\n\n### Rules\n- Keep chat reply to ONE short sentence when using render_ui. Do NOT repeat data shown in canvas.\n- Use render_ui for structured data, visualizations, forms, dashboards. Use plain text for explanations.\n- Canvas renders in a narrow sidebar (~400px).\n- Prefer fewer, larger components. One table is better than many small cards.\n- Use descriptive surface IDs (e.g. "sales-report", not "ui1").\n- Same \`id\` updates existing surface; different \`id\` creates new one.\n- When asked to modify existing content, reuse the original surface id from [Canvas State].\n\n### StringValue\n\nText properties use StringValue — an object with exactly one key:\n- Static text: \`{"literalString": "Hello"}\`\n- Data binding: \`{"path": "/fieldName"}\` (reads from the \`data\` model)\n\nShorthand: \`sv("text")\` means \`{"literalString": "text"}\` in examples below.\n\n### Component Reference\n\n**Text** — Display text with semantic sizing.\n\`{Text: {text: sv("Title"), usageHint: "h2"}}\`\nusageHint: "h1" | "h2" | "h3" | "h4" | "h5" | "caption" | "body"\ntext also renders Markdown (bold, italic, lists, code blocks, links).\n\n**Image** — Display an image.\n\`{Image: {url: sv("https://..."), usageHint: "mediumFeature"}}\`\nImage.url may be \`beeos-file://<fileId>\`; the renderer resolves it. Do not convert it to a signed URL.\nusageHint: "icon" | "avatar" | "smallFeature" | "mediumFeature" | "largeFeature" | "header"\nfit (optional): "contain" | "cover" | "fill" | "none" | "scale-down"\n\n**Icon** — Material icon.\n\`{Icon: {name: sv("check")}}\`\n\n**Video** — Embed a video.\n\`{Video: {url: sv("https://youtube.com/...")}}\`\n\n**AudioPlayer** — Audio playback.\n\`{AudioPlayer: {url: sv("https://..."), description: sv("Episode 1")}}\`\n\n**Row** — Horizontal layout. Children referenced by ID.\n\`{Row: {children: {explicitList: ["child1", "child2"]}, distribution: "spaceBetween"}}\`\ndistribution: "start" | "center" | "end" | "spaceBetween" | "spaceAround" | "spaceEvenly"\nalignment: "start" | "center" | "end" | "stretch"\n\n**Column** — Vertical layout. Children referenced by ID.\n\`{Column: {children: {explicitList: ["child1", "child2"]}}}\`\nSame distribution/alignment options as Row.\n\n**List** — Vertical or horizontal list.\n\`{List: {children: {explicitList: ["item1", "item2"]}, direction: "vertical"}}\`\n\n**Card** — Container with a single child.\n\`{Card: {child: "contentColumnId"}}\`\n\n**Tabs** — Tabbed container.\n\`{Tabs: {tabItems: [{title: sv("Tab 1"), child: "panel1"}, {title: sv("Tab 2"), child: "panel2"}]}}\`\n\n**Divider** — Horizontal or vertical separator.\n\`{Divider: {axis: "horizontal"}}\`\n\n**Modal** — Dialog with trigger.\n\`{Modal: {entryPointChild: "triggerBtnId", contentChild: "dialogContentId"}}\`\n\n**Button** — Clickable with action.\n\`{Button: {child: "labelTextId", action: {name: "onClick", context: [{key: "id", value: {literalString: "item-1"}}]}}}\`\n\n**TextField** — Text input with data binding.\n\`{TextField: {label: sv("Name"), text: {path: "/name"}, type: "shortText"}}\`\ntype: "shortText" | "number" | "date" | "longText"\n\n**CheckBox** — Boolean toggle.\n\`{CheckBox: {label: sv("Agree"), value: {path: "/agree"}}}\`\n\n**DateTimeInput** — Date/time picker.\n\`{DateTimeInput: {value: {path: "/date"}, enableDate: true, enableTime: false}}\`\n\n**MultipleChoice** — Selection from options.\n\`{MultipleChoice: {selections: {path: "/country"}, options: [{label: sv("US"), value: "US"}, {label: sv("CN"), value: "CN"}]}}\`\n\n**Slider** — Numeric range input.\n\`{Slider: {value: {path: "/volume"}, minValue: 0, maxValue: 100}}\`\n\n**Chart** (BeeOS extension) — Data visualization.\n\`{Chart: {chartType: sv("bar"), title: sv("Sales"), labels: ["Q1","Q2","Q3"], datasets: [{label: "Revenue", data: [100,200,150]}]}}\`\nchartType: bar, horizontal_bar, line, area, scatter, pie, doughnut, radar, gauge, candlestick, funnel, sparkline\ngauge uses value + max instead of labels/datasets.\ncandlestick data: [{open,high,low,close}] (full field names, NOT o/h/l/c).\n\n### Composition\n\nNest by id: Column/Row \`children.explicitList\`, Card \`child\`. Example:\n\`{"id":"s1","root":"column_root","components":[{"id":"text_body","component":{"Text":{"text":{"literalString":"Hello"},"usageHint":"body"}}},{"id":"column_root","component":{"Column":{"children":{"explicitList":["text_body"]}}}}]}\`\nTables: Card > Column > Row > Text. Forms: TextField/CheckBox + Button \`action.context\` paths.\n\n### render_form\nUse \`render_form\` for schema-driven forms when a domain schema exists.\nParameters: \`domain\`, \`operation\`, \`data\`, \`entityId\`.\n\n### close_ui\nCloses a UI surface. Use when user moves to a new topic or explicitly dismisses.\n`;export const CANVAS_TERM_MAPPING=`[System Note] Always use \`render_ui\` (not the canvas tool) for visual/structured content. Each component in the array MUST be: {"id":"x","component":{"TypeName":{props}}} — the "component" wrapper key is required. render_ui uses Google A2UI v0.8 format: flat component array with id references. ${CANVAS_COMPONENT_ID_GUIDANCE} Components: Text (usageHint: h1-h5/caption/body), Image, Icon, Video, AudioPlayer, Row (horizontal layout, children.explicitList), Column (vertical layout, children.explicitList), List, Card (single child), Tabs (tabItems), Divider, Modal, Button (child + action), TextField, CheckBox, MultipleChoice, Slider, DateTimeInput, Chart (BeeOS extension: chartType, labels, datasets). StringValue: {"literalString":"text"} or {"path":"/binding"}. root param = top-level component ID. Tables: Card > Column > Row > Text. Forms: TextField/CheckBox/Slider + Button with action.context paths. Chart: chartType(bar/line/pie/area/scatter/doughnut/radar/funnel/gauge/candlestick/sparkline), labels, datasets:[{label,data,color?}]. Candlestick: [{open,high,low,close}]. Gauge: value+max. Keep chat brief when canvas is used. Use \`close_ui\` to dismiss. Reuse same id to update; new id for new content.`;export const CANVAS_UPDATE_HINT="[Canvas Rule] Same id in render_ui = update existing surface. Different id = new surface. When a surface is referenced for editing, you MUST reuse its exact id and provide the full updated component tree.";const MAX_CONTEXT_SURFACES=8,MAX_CONTEXT_CHARS=500;export function buildActiveSurfacesContext(e,t){let n;if(!t)return null;if(n=e.getAllActive(t),0===n.length)return null;const a=[...n].sort((e,t)=>t.updatedAt-e.updatedAt).slice(0,8),o=n.length-a.length;let i=`[Canvas State] Active surfaces: ${a.map(t=>{const n=e.summarize(t.surfaceId);if(!n)return`"${t.surfaceId}"`;const a=n.types.slice(0,3).join(", "),o=n.title?`: "${n.title}"`:"";return`"${t.surfaceId}" (${a}${o})`}).join("; ")}.`;return o>0&&(i+=` ...and ${o} more.`),i+=" To modify existing content, reuse its id in render_ui.",i.length>500&&(i=i.slice(0,497)+"..."),i}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beeos-claw",
|
|
3
|
-
"version": "0.6.63-cloud.
|
|
3
|
+
"version": "0.6.63-cloud.13",
|
|
4
4
|
"description": "OpenClaw plugin that bridges the BeeOS platform with the local OpenClaw Gateway, providing file transfer, ACP bridge, and observability.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "BeeOS <dev@beeos.ai>",
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"fast-uri": ">=3.1.4",
|
|
89
89
|
"brace-expansion": ">=5.0.9"
|
|
90
90
|
},
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "be153a0b4e848144e212e10b6cd09f8fbc010abe"
|
|
92
92
|
}
|