ActorCanvas actor.canvas@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- actor
- Visibility
- public
- Status
- active
- Compatibility
- backward
- Decision
- ADR-059
- Schema
https://openvibe.network/contracts/actor/canvas.v1.json
actor.canvas@1: an agent's live panel beside the conversation (ADR-059) — a board of a trip, a table of prices, a checklist of what is left. It is DATA: a list of blocks drawn by one renderer (OpenVibe.Shared ov-canvas.js) wherever it is shown (Chat, Surf, the Dock, Actor). There is no HTML, no style, no script and no frame: text is plain and the renderer escapes it; an image is only a picture on openvibe.media; a link opens in a new tab with its host shown. A canvas acts only through the person: a button sends its label to the agent as the person's own message (action ask), and ticking a checklist item tells the agent which item changed; the agent's next steps go through its level and approvals like any other. VERSION only grows: a viewer ignores an older one, and the agent replaces the whole document, never part of it.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
canvas | const | yes |
| |
id | string | yes |
| |
title | string | yes |
| |
version | integer | yes | Grows with every update; a viewer ignores an older version. |
|
agent_id | string | The agent that draws it. |
| |
thread | string | The conversation it sits beside (Actor's task or chat id). |
| |
updated_at | string | yes |
| |
blocks | array of one of | yes |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: minimal
{
"canvas": "actor.canvas@1",
"id": "cnv_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"title": "Notes",
"version": 1,
"updated_at": "2026-11-08T01:00:00.000Z",
"blocks": []
}Valid: trip
{
"canvas": "actor.canvas@1",
"id": "cnv_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"title": "Lisbon, 14–17 November",
"version": 3,
"agent_id": "agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"thread": "tsk_42",
"updated_at": "2026-11-08T01:00:00.000Z",
"blocks": [
{
"type": "heading",
"text": "Lisbon, 14–17 November",
"level": 1
},
{
"type": "metric",
"label": "Flights and hotel",
"value": "€612",
"note": "two people, booked nothing yet"
},
{
"type": "checklist",
"id": "todo",
"items": [
{
"id": "flights",
"text": "Pick the flights",
"done": true
},
{
"id": "hotel",
"text": "Choose a hotel near Alfama",
"done": false
}
]
},
{
"type": "table",
"id": "hotels",
"columns": [
"Hotel",
"Night",
"Walk to the river"
],
"rows": [
[
"Casa A",
118,
"6 min"
],
[
"Hotel B",
96,
"14 min"
]
]
},
{
"type": "chart",
"id": "prices",
"kind": "line",
"unit": "€",
"series": [
{
"name": "Flights",
"points": [
{
"x": "Mon",
"y": 240
},
{
"x": "Tue",
"y": 212
},
{
"x": "Wed",
"y": 199
}
]
}
]
},
{
"type": "image",
"src": "https://openvibe.media/t/lisbon.jpg",
"alt": "The river at dusk"
},
{
"type": "link",
"href": "https://openvibe.video/watch?v=AbCdEfGhIjK",
"text": "The walking tour video"
},
{
"type": "text",
"text": "Casa A is closer to the river; Hotel B is cheaper.\nBoth have free cancellation until Friday."
},
{
"type": "button",
"label": "Book Casa A",
"action": "ask"
}
]
}Rejected: button-runs
{
"canvas": "actor.canvas@1",
"id": "cnv_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"title": "Lisbon, 14–17 November",
"version": 3,
"agent_id": "agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"thread": "tsk_42",
"updated_at": "2026-11-08T01:00:00.000Z",
"blocks": [
{
"type": "button",
"label": "Delete everything",
"action": "run"
}
]
}Rejected: foreign-image
{
"canvas": "actor.canvas@1",
"id": "cnv_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"title": "Lisbon, 14–17 November",
"version": 3,
"agent_id": "agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"thread": "tsk_42",
"updated_at": "2026-11-08T01:00:00.000Z",
"blocks": [
{
"type": "image",
"src": "https://tracker.example/p.png",
"alt": "x"
}
]
}Rejected: html-block
{
"canvas": "actor.canvas@1",
"id": "cnv_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"title": "Lisbon, 14–17 November",
"version": 3,
"agent_id": "agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"thread": "tsk_42",
"updated_at": "2026-11-08T01:00:00.000Z",
"blocks": [
{
"type": "html",
"html": "<script>alert(1)</script>"
}
]
}Rejected: http-link
{
"canvas": "actor.canvas@1",
"id": "cnv_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"title": "Lisbon, 14–17 November",
"version": 3,
"agent_id": "agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"thread": "tsk_42",
"updated_at": "2026-11-08T01:00:00.000Z",
"blocks": [
{
"type": "link",
"href": "javascript:alert(1)",
"text": "x"
}
]
}Rejected: too-many-blocks
{
"canvas": "actor.canvas@1",
"id": "cnv_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"title": "Lisbon, 14–17 November",
"version": 3,
"agent_id": "agt_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"thread": "tsk_42",
"updated_at": "2026-11-08T01:00:00.000Z",
"blocks": [
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
},
{
"type": "text",
"text": "x"
}
]
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('actor.canvas@1', value); // { valid, errors: [{ path, message }] }